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.
12 #include "../include/aros/kernel.h"
13 #include "elfloader32.h"
18 //#include "bootstrap.h"
19 //#include "support.h"
26 #define kprintf printf
29 * This two pointers are used by the ELF loader to claim for memory ranges for both
30 * the RW sections (.data, .bss and such) and RO sections (.text, .rodata....) of executable.
31 * Keeping both areas of memory separate reduces the memory waste when more modules are
32 * loaded. Moreover, the whole RO range may be marked for MMU as read-only at once.
39 unsigned long long addr
;
40 unsigned long long len
;
48 void *kernel_highest()
53 void set_base_address(void *ptr
, void *tracker
, void ** sysbaseaddr
)
55 printf("[ELF Loader] set_base_address %p %p %p\n",ptr
,tracker
,sysbaseaddr
);
56 ptr_ro
= ptr_rw
= ptr
;
57 bss_tracker
= (struct _bss_tracker
*)tracker
;
58 SysBaseAddr
= sysbaseaddr
;
62 * read_block interface. we want to read from files here
64 static int read_block(void *file
, long offset
, void *dest
, long length
)
66 fseek(file
, offset
, SEEK_SET
);
67 fread(dest
,(size_t)length
, 1, file
);
72 * load_block also allocates teh memory
74 static void *load_block(void *file
, long offset
, long length
)
76 void * dest
= malloc(length
);
77 fseek(file
, offset
, SEEK_SET
);
78 fread(dest
, (size_t)length
, 1, file
);
82 static void free_block(void * block
)
89 * Test for correct ELF header here
91 static int check_header(struct elfheader
*eh
)
95 eh
->ident
[0] != 0x7f ||
96 eh
->ident
[1] != 'E' ||
97 eh
->ident
[2] != 'L' ||
101 D(kprintf("[ELF Loader] Not an ELF object\n"));
105 if (eh
->type
!= ET_REL
|| eh
->machine
!= EM_386
)
107 D(kprintf("[ELF Loader] Wrong object type or wrong architecture\n"));
114 * Get the memory for chunk and load it
116 static int load_hunk(void *file
, struct sheader
*sh
)
120 /* empty chunk? Who cares :) */
126 /* Allocate a chunk with write access - take aligned memory beneath the RO kernel */
127 if (sh
->flags
& SHF_WRITE
)
129 D(kprintf("[ELF Loader] RW chunk (%d bytes, align=%d) @ ", (unsigned int)sh
->size
, (unsigned int)sh
->addralign
));
131 ptr
= (void*)(((unsigned long)ptr_rw
- (unsigned long)sh
->size
- (unsigned long)sh
->addralign
+ 1) & ~((unsigned long)sh
->addralign
-1));
134 ptr
= malloc(sh
->size
+ sh
->addralign
);
139 /* Read-Only mode? Get the memory from the kernel space, align it accorting to the demand */
141 D(kprintf("[ELF Loader] RO chunk (%d bytes, align=%d) @ ", (unsigned int)sh
->size
, (unsigned int)sh
->addralign
));
142 ptr_ro
= (char *)(((unsigned long)ptr_ro
+ (unsigned long)sh
->addralign
- 1) & ~((unsigned long)sh
->addralign
-1));
144 ptr_ro
= ptr_ro
+ sh
->size
;
146 ptr
= malloc(sh
->size
+ sh
->addralign
);
149 D(kprintf("%p\n", (unsigned int)ptr
));
153 /* copy block of memory from ELF file if it exists */
154 if (sh
->type
!= SHT_NOBITS
)
155 return read_block(file
, sh
->offset
, (void *)((unsigned long)sh
->addr
), sh
->size
);
158 bzero(ptr
, sh
->size
);
159 bss_tracker
->addr
= (unsigned long)ptr
;
160 bss_tracker
->len
= sh
->size
;
167 /* Perform relocations of given section */
168 static int relocate(struct elfheader
*eh
, struct sheader
*sh
, long shrel_idx
, unsigned long long virt
)
170 struct sheader
*shrel
= &sh
[shrel_idx
];
171 struct sheader
*shsymtab
= &sh
[shrel
->link
];
172 struct sheader
*toreloc
= &sh
[shrel
->info
];
174 struct symbol
*symtab
= (struct symbol
*)((unsigned long)shsymtab
->addr
);
175 struct relo
*rel
= (struct relo
*)((unsigned long)shrel
->addr
);
176 char *section
= (char *)((unsigned long)toreloc
->addr
);
178 unsigned int numrel
= (unsigned long)shrel
->size
/ (unsigned long)shrel
->entsize
;
181 struct symbol
*SysBase_sym
= (void*)0;
183 D(kprintf("[ELF Loader] performing %d relocations, target address %p%p\n",
184 numrel
, (unsigned long)(virt
>> 32), (unsigned long)virt
));
186 for (i
=0; i
<numrel
; i
++, rel
++)
188 struct symbol
*sym
= &symtab
[ELF32_R_SYM(rel
->info
)];
189 unsigned long *p
= (unsigned long *)§ion
[rel
->offset
];
190 unsigned long long s
;
191 const char * name
= (char *)((unsigned long)sh
[shsymtab
->link
].addr
) + sym
->name
;
192 switch (sym
->shindex
)
195 D(kprintf("[ELF Loader] Undefined symbol '%s' while relocating the section '%s'\n",
196 (char *)((unsigned long)sh
[shsymtab
->link
].addr
) + sym
->name
,
197 (char *)((unsigned long)sh
[eh
->shstrndx
].addr
) + toreloc
->name
));
201 D(kprintf("[ELF Loader] COMMON symbol '%s' while relocating the section '%s'\n",
202 (char *)((unsigned long)sh
[shsymtab
->link
].addr
) + sym
->name
,
203 (char *)((unsigned long)sh
[eh
->shstrndx
].addr
) + toreloc
->name
));
208 if (SysBase_sym
== (void*)0)
210 if (strncmp(name
, "SysBase", 8) == 0)
212 D(kprintf("[ELF Loader] got SysBase\n"));
220 if (SysBase_sym
== sym
)
222 SysBase_yes
: s
= SysBaseAddr
;
225 SysBase_no
: s
= sym
->value
;
229 s
= (unsigned long)sh
[sym
->shindex
].addr
+ virt
+ sym
->value
;
234 switch (ELF32_R_TYPE(rel
->info
))
236 case R_386_32
: /* 32bit absolute */
240 case R_386_PC32
: /* 32bit PC relative */
241 *p
+= s
- (unsigned int)p
;
248 kprintf("[ELF Loader] Unrecognized relocation type %d %d\n", i
, (unsigned int)ELF32_R_TYPE(rel
->info
));
252 D(kprintf("[ELF Loader] relocated symbol: %s->0x%x\n",name
,*p
));
257 void load_elf_file(void *file
, unsigned long long virt
)
262 int addr_displayed
= 0;
264 D(kprintf("[ELF Loader] Loading ELF module from address %p\n", (unsigned int)file
));
266 /* Check the header of ELF file */
269 !read_block(file
, 0, &eh
, sizeof(eh
)) ||
270 !check_header(&eh
) ||
271 !(sh
= load_block(file
, eh
.shoff
, eh
.shnum
* eh
.shentsize
))
274 kprintf("[ELF Loader] Wrong module header, aborting.\n");
278 /* Iterate over the section header in order to prepare memory and eventually load some hunks */
279 for (i
=0; i
< eh
.shnum
; i
++)
281 /* Load the symbol and string tables */
282 if (sh
[i
].type
== SHT_SYMTAB
|| sh
[i
].type
== SHT_STRTAB
)
284 sh
[i
].addr
= load_block(file
, sh
[i
].offset
, sh
[i
].size
);
286 /* Does the section require memoy allcation? */
287 else if (sh
[i
].flags
& SHF_ALLOC
)
289 /* Yup, it does. Load the hunk */
290 if (!load_hunk(file
, &sh
[i
]))
292 kprintf("[ELF Loader] Error at loading of the hunk!\n");
294 else if (!addr_displayed
)
296 kprintf("[ELF Loader] shared mem@0x%x\n", sh
[i
].addr
);
302 /* For every loaded section perform the relocations */
303 for (i
=0; i
< eh
.shnum
; i
++)
305 if ((sh
[i
].type
== SHT_RELA
|| sh
[i
].type
== SHT_REL
) && sh
[sh
[i
].info
].addr
)
307 sh
[i
].addr
= load_block(file
, sh
[i
].offset
, sh
[i
].size
);
308 if (!sh
[i
].addr
|| !relocate(&eh
, sh
, i
, virt
))
310 kprintf("[ELF Loader] Relocation error!\n");
312 free_block(sh
[i
].addr
);
314 else if (sh
[i
].type
== SHT_SYMTAB
|| sh
[i
].type
== SHT_STRTAB
)
315 free_block(sh
[i
].addr
);