2 Copyright © 2013, The AROS Development Team. All rights reserved.
19 uint32_t int_shstrndx
;
21 int checkHeader(struct elfheader
*eh
)
23 if (eh
->ident
[0] != 0x7f || eh
->ident
[1] != 'E' ||
24 eh
->ident
[2] != 'L' || eh
->ident
[3] != 'F')
29 int_shnum
= eh
->shnum
;
30 int_shstrndx
= eh
->shstrndx
;
32 /* the ELF header only uses 16 bits to store the count of section headers,
33 * so it can't handle more than 65535 headers. if the count is 0, and an
34 * offset is defined, then the real count can be found in the first
35 * section header (which always exists).
37 * similarly, if the string table index is SHN_XINDEX, then the actual
38 * index is found in the first section header also.
40 * see the System V ABI 2001-04-24 draft for more details.
42 if (int_shnum
== 0 || int_shstrndx
== SHN_XINDEX
)
49 /* Get section header. I hope it's there, in memory already. */
50 struct sheader
*sh
= (struct sheader
*)((intptr_t)eh
+ eh
->shoff
);
52 /* wider section header count is in the size field */
56 /* wider string table index is in the link field */
57 if (int_shstrndx
== SHN_XINDEX
)
58 int_shstrndx
= sh
->link
;
60 /* sanity, if they're still invalid then this isn't elf */
61 if (int_shnum
== 0 || int_shstrndx
== SHN_XINDEX
)
69 eh
->ident
[EI_CLASS
] != ELFCLASS32
||
70 eh
->ident
[EI_VERSION
] != EV_CURRENT
||
72 eh
->ident
[EI_DATA
] != ELFDATA2LSB
||
82 int getElfSize(void *elf_file
, uint32_t *size_rw
, uint32_t *size_ro
)
84 struct elfheader
*eh
= (struct elfheader
*)elf_file
;
88 DELF(kprintf("[BOOT:ELF] getElfSize(%p)", eh
));
92 struct sheader
*sh
= (struct sheader
*)((intptr_t)elf_file
+ eh
->shoff
);
95 for (i
= 0; i
< int_shnum
; i
++)
97 /* Does the section require memoy allcation? */
98 if (sh
[i
].flags
& SHF_ALLOC
)
100 uint32_t size
= (sh
[i
].size
+ sh
[i
].addralign
- 1) & ~(sh
[i
].addralign
- 1);
103 * I extend the section size according to the alignment requirement. However, also the already
104 * measured size has to be aligned poperly. It is so, because the loader has to align the load address later on.
106 if (sh
[i
].flags
& SHF_WRITE
)
108 s_rw
= (s_rw
+ sh
[i
].addralign
- 1) & ~(sh
[i
].addralign
- 1);
113 s_ro
= (s_ro
+ sh
[i
].addralign
- 1) & ~(sh
[i
].addralign
- 1);
119 DELF(kprintf(": ro=%p, rw=%p\n", s_ro
, s_rw
));
129 static uintptr_t ptr_ro
;
130 static uintptr_t ptr_rw
;
131 static uintptr_t virtoffset
;
133 void initAllocator(uintptr_t addr_ro
, uintptr_t addr_rw
, uintptr_t virtoff
)
137 virtoffset
= virtoff
;
140 struct bss_tracker tracker
[MAX_BSS_SECTIONS
];
141 static struct bss_tracker
*bss_tracker
= &tracker
[0];
144 * read_block function copies the range of memory within ELF file to any specified location.
146 static inline void read_block(void *file
, long offset
, void *dest
, long length
)
148 memcpy(dest
, (void *)((unsigned long)file
+ offset
), length
);
152 * Get the memory for chunk and load it
154 static int load_hunk(void *file
, struct sheader
*sh
)
156 void *ptr
= (void *)0;
158 /* empty chunk? Who cares :) */
162 /* Allocate a chunk with write access */
163 if (sh
->flags
& SHF_WRITE
)
165 ptr_rw
= (char *)(((unsigned long)ptr_rw
166 + (unsigned long)sh
->addralign
- 1)
167 & ~((unsigned long)sh
->addralign
- 1));
169 ptr_rw
= ptr_rw
+ sh
->size
;
173 /* Read-Only mode? Get the memory from the kernel space, align it accorting to the demand */
174 ptr_ro
= (char *)(((unsigned long)ptr_ro
175 + (unsigned long)sh
->addralign
- 1)
176 & ~((unsigned long)sh
->addralign
- 1));
178 ptr_ro
= ptr_ro
+ sh
->size
;
183 /* copy block of memory from ELF file if it exists */
184 if (sh
->type
!= SHT_NOBITS
)
186 read_block(file
, sh
->offset
, (void *)((unsigned long)sh
->addr
),
191 bzero(ptr
, sh
->size
);
193 (void *)((unsigned long)ptr
+ virtoffset
);
194 bss_tracker
->length
= sh
->size
;
197 * empty the subsequent tracker in case it's the last one. We did that in case a buggy firmare
198 * forgot to clear our .bss section
200 bss_tracker
->addr
= (void*)0;
201 bss_tracker
->length
= 0;
207 /* Perform relocations of given section */
208 static int relocate(struct elfheader
*eh
, struct sheader
*sh
, long shrel_idx
,
211 struct sheader
*shrel
= &sh
[shrel_idx
];
212 struct sheader
*shsymtab
= &sh
[shrel
->link
];
213 struct sheader
*toreloc
= &sh
[shrel
->info
];
215 struct symbol
*symtab
=
216 (struct symbol
*)((unsigned long)shsymtab
->addr
);
217 struct relo
*rel
= (struct relo
*)((unsigned long)shrel
->addr
);
218 char *section
= (char *)((unsigned long)toreloc
->addr
);
220 unsigned int numrel
= (unsigned long)shrel
->size
221 / (unsigned long)shrel
->entsize
;
226 struct symbol
*SysBase_sym
= (void *)0;
228 for (i
= 0; i
< numrel
; i
++, rel
++)
230 struct symbol
*sym
= &symtab
[ELF32_R_SYM(rel
->info
)];
231 uint32_t *p
= (uint32_t *) & section
[rel
->offset
];
236 * R_ARM_V4BX are actually special marks for the linker.
237 * They even never have a target (shindex == SHN_UNDEF),
238 * so we simply ignore them before doing any checks.
240 if (ELF_R_TYPE(rel
->info
) == R_ARM_V4BX
)
243 switch (sym
->shindex
)
247 ("[BOOT:ELF] Undefined symbol '%s' in section '%s'\n",
248 (char *)((uint32_t) sh
[shsymtab
->link
].addr
) +
250 (char *)((uint32_t) sh
[eh
->shstrndx
].addr
) +
256 ("[BOOT:ELF] COMMON symbol '%s' in section '%s'\n",
257 (char *)((uint32_t) sh
[shsymtab
->link
].addr
) +
259 (char *)((uint32_t) sh
[eh
->shstrndx
].addr
) +
265 if (SysBase_sym
== (void *)0) {
267 ((char *)((uint32_t) sh
[shsymtab
->link
].
268 addr
) + sym
->name
, "SysBase",
274 } else if (SysBase_sym
== sym
) {
275 SysBase_yes
: s
= (uint32_t) 4UL;
278 SysBase_no
: s
= sym
->value
;
281 s
= (uint32_t) sh
[sym
->shindex
].addr
+ sym
->value
;
283 switch (ELF32_R_TYPE(rel
->info
)) {
285 // case R_386_32: /* 32bit direct/absolute */
286 // *p += s + virtoffset;
293 /* On ARM the 24 bit offset is shifted by 2 to the right */
294 signed long offset
= (*p
& 0x00ffffff) << 2;
295 /* If highest bit set, make offset negative */
296 if (offset
& 0x02000000)
297 offset
-= 0x04000000;
299 offset
+= s
- (ULONG
)p
;
303 *p
|= offset
& 0x00ffffff;
308 case R_ARM_MOVW_ABS_NC
:
311 signed long offset
= *p
;
312 offset
= ((offset
& 0xf0000) >> 4) | (offset
& 0xfff);
313 offset
= (offset
^ 0x8000) - 0x8000;
315 offset
+= s
+ virtoffset
;
317 if (ELF_R_TYPE(rel
->info
) == R_ARM_MOVT_ABS
)
321 *p
|= ((offset
& 0xf000) << 4) | (offset
& 0x0fff);
325 case R_ARM_ABS32
: /* PC relative 32 bit signed */
326 *p
+= s
+ virtoffset
;
329 case R_ARM_NONE
: /* No reloc */
333 kprintf("[BOOT:ELF] Unknown relocation %d in ELF file\n",
334 ELF32_R_TYPE(rel
->info
));
342 int loadElf(void *elf_file
)
344 struct elfheader
*eh
= (struct elfheader
*)elf_file
;
348 DELF(kprintf("[BOOT] loadElf(%p)\n", eh
));
352 struct sheader
*sh
= (struct sheader
*)((intptr_t)elf_file
+ eh
->shoff
);
355 for (i
= 0; i
< int_shnum
; i
++)
357 /* Load the symbol and string tables */
358 if (sh
[i
].type
== SHT_SYMTAB
|| sh
[i
].type
== SHT_STRTAB
)
360 sh
[i
].addr
= (unsigned long)elf_file
+ sh
[i
].offset
;
362 /* Does the section require memoy allcation? */
363 else if (sh
[i
].flags
& SHF_ALLOC
)
365 /* Yup, it does. Load the hunk */
366 if (!load_hunk(elf_file
, &sh
[i
]))
374 DELF(kprintf("[BOOT:ELF] %s section loaded at %p (Virtual addr: %p)\n",
375 sh
[i
].flags
& SHF_WRITE
? "RW":"RO",
377 sh
[i
].addr
+ virtoffset
));
383 /* For every loaded section perform the relocations */
384 for (i
= 0; i
< int_shnum
; i
++)
386 if (sh
[i
].type
== SHT_REL
&& sh
[sh
[i
].info
].addr
)
388 sh
[i
].addr
= (uint32_t) elf_file
+ sh
[i
].offset
;
389 if (!sh
[i
].addr
|| !relocate(eh
, sh
, i
, virtoffset
))