2 Copyright (C) 2006 The AROS Development Team. All rights reserved.
5 Desc: ELF32 loader extracted from our internal_load_seg_elf in dos.library.
9 #include "elfloader32.h"
16 #define kprintf printf
19 * This two pointers are used by the ELF loader to claim for memory ranges for both
20 * the RW sections (.data, .bss and such) and RO sections (.text, .rodata....) of executable.
21 * Keeping both areas of memory separate reduces the memory waste when more modules are
22 * loaded. Moreover, the whole RO range may be marked for MMU as read-only at once.
38 void *kernel_highest()
43 void set_base_address(void *ptr
, void *tracker
, void ** sysbaseaddr
)
45 printf("[ELF Loader] set_base_address %p %p %p\n",ptr
,tracker
,sysbaseaddr
);
46 ptr_ro
= ptr_rw
= ptr
;
47 bss_tracker
= (struct _bss_tracker
*)tracker
;
48 SysBaseAddr
= sysbaseaddr
;
52 * read_block interface. we want to read from files here
54 static int read_block(void *file
, long offset
, void *dest
, long length
)
56 fseek(file
, offset
, SEEK_SET
);
57 fread(dest
,(size_t)length
, 1, file
);
62 * load_block also allocates teh memory
64 static void *load_block(void *file
, long offset
, long length
)
66 void * dest
= malloc(length
);
67 fseek(file
, offset
, SEEK_SET
);
68 fread(dest
, (size_t)length
, 1, file
);
72 static void free_block(void * block
)
79 * Test for correct ELF header here
81 static int check_header(struct elfheader
*eh
)
85 eh
->ident
[0] != 0x7f ||
86 eh
->ident
[1] != 'E' ||
87 eh
->ident
[2] != 'L' ||
91 D(kprintf("[ELF Loader] Not an ELF object\n"));
95 if (eh
->type
!= ET_REL
|| eh
->machine
!= EM_386
)
97 D(kprintf("[ELF Loader] Wrong object type or wrong architecture\n"));
104 * Get the memory for chunk and load it
106 static int load_hunk(void *file
, struct sheader
*sh
)
110 /* empty chunk? Who cares :) */
116 /* Allocate a chunk with write access - take aligned memory beneath the RO kernel */
117 if (sh
->flags
& SHF_WRITE
)
119 D(kprintf("[ELF Loader] RW chunk (%d bytes, align=%d) @ ", (unsigned int)sh
->size
, (unsigned int)sh
->addralign
));
121 ptr
= (void*)(((unsigned long)ptr_rw
- (unsigned long)sh
->size
- (unsigned long)sh
->addralign
+ 1) & ~((unsigned long)sh
->addralign
-1));
124 ptr
= malloc(sh
->size
+ sh
->addralign
);
129 /* Read-Only mode? Get the memory from the kernel space, align it accorting to the demand */
131 D(kprintf("[ELF Loader] RO chunk (%d bytes, align=%d) @ ", (unsigned int)sh
->size
, (unsigned int)sh
->addralign
));
132 ptr_ro
= (char *)(((unsigned long)ptr_ro
+ (unsigned long)sh
->addralign
- 1) & ~((unsigned long)sh
->addralign
-1));
134 ptr_ro
= ptr_ro
+ sh
->size
;
136 ptr
= malloc(sh
->size
+ sh
->addralign
);
139 D(kprintf("%p\n", (unsigned int)ptr
));
143 /* copy block of memory from ELF file if it exists */
144 if (sh
->type
!= SHT_NOBITS
)
145 return read_block(file
, sh
->offset
, (void *)((unsigned long)sh
->addr
), sh
->size
);
148 memset(ptr
, 0, sh
->size
);
149 bss_tracker
->addr
= ptr
;
150 bss_tracker
->len
= sh
->size
;
157 /* Perform relocations of given section */
158 static int relocate(struct elfheader
*eh
, struct sheader
*sh
, long shrel_idx
, unsigned long long virt
)
160 struct sheader
*shrel
= &sh
[shrel_idx
];
161 struct sheader
*shsymtab
= &sh
[shrel
->link
];
162 struct sheader
*toreloc
= &sh
[shrel
->info
];
164 struct symbol
*symtab
= (struct symbol
*)((unsigned long)shsymtab
->addr
);
165 struct relo
*rel
= (struct relo
*)((unsigned long)shrel
->addr
);
166 char *section
= (char *)((unsigned long)toreloc
->addr
);
168 unsigned int numrel
= (unsigned long)shrel
->size
/ (unsigned long)shrel
->entsize
;
171 struct symbol
*SysBase_sym
= (void*)0;
173 D(kprintf("[ELF Loader] performing %d relocations, target address %p%p\n",
174 numrel
, (unsigned long)(virt
>> 32), (unsigned long)virt
));
176 for (i
=0; i
<numrel
; i
++, rel
++)
178 struct symbol
*sym
= &symtab
[ELF32_R_SYM(rel
->info
)];
179 unsigned long *p
= (unsigned long *)§ion
[rel
->offset
];
180 unsigned long long s
;
181 const char * name
= (char *)((unsigned long)sh
[shsymtab
->link
].addr
) + sym
->name
;
182 switch (sym
->shindex
)
185 D(kprintf("[ELF Loader] Undefined symbol '%s' while relocating the section '%s'\n",
186 (char *)((unsigned long)sh
[shsymtab
->link
].addr
) + sym
->name
,
187 (char *)((unsigned long)sh
[eh
->shstrndx
].addr
) + toreloc
->name
));
191 D(kprintf("[ELF Loader] COMMON symbol '%s' while relocating the section '%s'\n",
192 (char *)((unsigned long)sh
[shsymtab
->link
].addr
) + sym
->name
,
193 (char *)((unsigned long)sh
[eh
->shstrndx
].addr
) + toreloc
->name
));
198 if (SysBase_sym
== (void*)0)
200 if (strncmp(name
, "SysBase", 8) == 0)
202 D(kprintf("[ELF Loader] got SysBase\n"));
210 if (SysBase_sym
== sym
)
212 SysBase_yes
: s
= SysBaseAddr
;
215 SysBase_no
: s
= sym
->value
;
219 s
= (unsigned long)sh
[sym
->shindex
].addr
+ virt
+ sym
->value
;
224 switch (ELF32_R_TYPE(rel
->info
))
226 case R_386_32
: /* 32bit absolute */
230 case R_386_PC32
: /* 32bit PC relative */
231 *p
+= s
- (unsigned int)p
;
238 kprintf("[ELF Loader] Unrecognized relocation type %d %d\n", i
, (unsigned int)ELF32_R_TYPE(rel
->info
));
242 D(kprintf("[ELF Loader] relocated symbol: %s->0x%x\n",name
,*p
));
247 void load_elf_file(void *file
, unsigned long long virt
)
252 int addr_displayed
= 0;
254 D(kprintf("[ELF Loader] Loading ELF module from address %p\n", (unsigned int)file
));
256 /* Check the header of ELF file */
259 !read_block(file
, 0, &eh
, sizeof(eh
)) ||
260 !check_header(&eh
) ||
261 !(sh
= load_block(file
, eh
.shoff
, eh
.shnum
* eh
.shentsize
))
264 kprintf("[ELF Loader] Wrong module header, aborting.\n");
268 /* Iterate over the section header in order to prepare memory and eventually load some hunks */
269 for (i
=0; i
< eh
.shnum
; i
++)
271 /* Load the symbol and string tables */
272 if (sh
[i
].type
== SHT_SYMTAB
|| sh
[i
].type
== SHT_STRTAB
)
274 sh
[i
].addr
= load_block(file
, sh
[i
].offset
, sh
[i
].size
);
276 /* Does the section require memoy allcation? */
277 else if (sh
[i
].flags
& SHF_ALLOC
)
279 /* Yup, it does. Load the hunk */
280 if (!load_hunk(file
, &sh
[i
]))
282 kprintf("[ELF Loader] Error at loading of the hunk!\n");
284 else if (!addr_displayed
)
286 kprintf("[ELF Loader] shared mem@0x%x\n", sh
[i
].addr
);
292 /* For every loaded section perform the relocations */
293 for (i
=0; i
< eh
.shnum
; i
++)
295 if ((sh
[i
].type
== SHT_RELA
|| sh
[i
].type
== SHT_REL
) && sh
[sh
[i
].info
].addr
)
297 sh
[i
].addr
= load_block(file
, sh
[i
].offset
, sh
[i
].size
);
298 if (!sh
[i
].addr
|| !relocate(&eh
, sh
, i
, virt
))
300 kprintf("[ELF Loader] Relocation error!\n");
302 free_block(sh
[i
].addr
);
304 else if (sh
[i
].type
== SHT_SYMTAB
|| sh
[i
].type
== SHT_STRTAB
)
305 free_block(sh
[i
].addr
);