2 Copyright © 1995-2010, The AROS Development Team. All rights reserved.
17 uint32_t int_shstrndx
;
19 int checkHeader(struct elfheader
*eh
)
21 if (eh
->ident
[0] != 0x7f || eh
->ident
[1] != 'E' ||
22 eh
->ident
[2] != 'L' || eh
->ident
[3] != 'F')
27 int_shnum
= eh
->shnum
;
28 int_shstrndx
= eh
->shstrndx
;
30 /* the ELF header only uses 16 bits to store the count of section headers,
31 * so it can't handle more than 65535 headers. if the count is 0, and an
32 * offset is defined, then the real count can be found in the first
33 * section header (which always exists).
35 * similarly, if the string table index is SHN_XINDEX, then the actual
36 * index is found in the first section header also.
38 * see the System V ABI 2001-04-24 draft for more details.
40 if (int_shnum
== 0 || int_shstrndx
== SHN_XINDEX
)
47 /* Get section header. I hope it's there, in memory already. */
48 struct sheader
*sh
= (struct sheader
*)((intptr_t)eh
+ eh
->shoff
);
50 /* wider section header count is in the size field */
54 /* wider string table index is in the link field */
55 if (int_shstrndx
== SHN_XINDEX
)
56 int_shstrndx
= sh
->link
;
58 /* sanity, if they're still invalid then this isn't elf */
59 if (int_shnum
== 0 || int_shstrndx
== SHN_XINDEX
)
67 eh
->ident
[EI_CLASS
] != ELFCLASS32
||
68 eh
->ident
[EI_VERSION
] != EV_CURRENT
||
70 eh
->ident
[EI_DATA
] != ELFDATA2LSB
||
80 int getElfSize(void *elf_file
, uint32_t *size_rw
, uint32_t *size_ro
)
82 struct elfheader
*eh
= (struct elfheader
*)elf_file
;
88 struct sheader
*sh
= (struct sheader
*)((intptr_t)elf_file
+ eh
->shoff
);
91 for (i
= 0; i
< int_shnum
; i
++)
93 /* Does the section require memoy allcation? */
94 if (sh
[i
].flags
& SHF_ALLOC
)
96 uint32_t size
= (sh
[i
].size
+ sh
[i
].addralign
- 1) & ~(sh
[i
].addralign
- 1);
99 * I extend the section size according to the alignment requirement. However, also the already
100 * measured size has to be aligned poperly. It is so, because the loader has to align the load address later on.
102 if (sh
[i
].flags
& SHF_WRITE
)
104 s_rw
= (s_rw
+ sh
[i
].addralign
- 1) & ~(sh
[i
].addralign
- 1);
109 s_ro
= (s_ro
+ sh
[i
].addralign
- 1) & ~(sh
[i
].addralign
- 1);
124 static uintptr_t ptr_ro
;
125 static uintptr_t ptr_rw
;
126 static uintptr_t virtoffset
;
128 void initAllocator(uintptr_t addr_ro
, uintptr_t addr_rw
, uintptr_t virtoff
)
132 virtoffset
= virtoff
;
135 struct bss_tracker tracker
[MAX_BSS_SECTIONS
];
136 static struct bss_tracker
*bss_tracker
= &tracker
[0];
139 * read_block function copies the range of memory within ELF file to any specified location.
141 static inline void read_block(void *file
, long offset
, void *dest
, long length
)
143 memcpy(dest
, (void *)((unsigned long)file
+ offset
), length
);
147 * Get the memory for chunk and load it
149 static int load_hunk(void *file
, struct sheader
*sh
)
151 void *ptr
= (void *)0;
153 /* empty chunk? Who cares :) */
157 /* Allocate a chunk with write access */
158 if (sh
->flags
& SHF_WRITE
)
160 ptr_rw
= (char *)(((unsigned long)ptr_rw
161 + (unsigned long)sh
->addralign
- 1)
162 & ~((unsigned long)sh
->addralign
- 1));
164 ptr_rw
= ptr_rw
+ sh
->size
;
168 /* Read-Only mode? Get the memory from the kernel space, align it accorting to the demand */
169 ptr_ro
= (char *)(((unsigned long)ptr_ro
170 + (unsigned long)sh
->addralign
- 1)
171 & ~((unsigned long)sh
->addralign
- 1));
173 ptr_ro
= ptr_ro
+ sh
->size
;
178 /* copy block of memory from ELF file if it exists */
179 if (sh
->type
!= SHT_NOBITS
)
181 read_block(file
, sh
->offset
, (void *)((unsigned long)sh
->addr
),
186 bzero(ptr
, sh
->size
);
188 (void *)((unsigned long)ptr
+ virtoffset
);
189 bss_tracker
->length
= sh
->size
;
192 * empty the subsequent tracker in case it's the last one. We did that in case a buggy firmare
193 * forgot to clear our .bss section
195 bss_tracker
->addr
= (void*)0;
196 bss_tracker
->length
= 0;
202 /* Perform relocations of given section */
203 static int relocate(struct elfheader
*eh
, struct sheader
*sh
, long shrel_idx
,
206 struct sheader
*shrel
= &sh
[shrel_idx
];
207 struct sheader
*shsymtab
= &sh
[shrel
->link
];
208 struct sheader
*toreloc
= &sh
[shrel
->info
];
210 struct symbol
*symtab
=
211 (struct symbol
*)((unsigned long)shsymtab
->addr
);
212 struct relo
*rel
= (struct relo
*)((unsigned long)shrel
->addr
);
213 char *section
= (char *)((unsigned long)toreloc
->addr
);
215 unsigned int numrel
= (unsigned long)shrel
->size
216 / (unsigned long)shrel
->entsize
;
221 struct symbol
*SysBase_sym
= (void *)0;
223 for (i
= 0; i
< numrel
; i
++, rel
++)
225 struct symbol
*sym
= &symtab
[ELF32_R_SYM(rel
->info
)];
226 uint32_t *p
= (uint32_t *) & section
[rel
->offset
];
231 * R_ARM_V4BX are actually special marks for the linker.
232 * They even never have a target (shindex == SHN_UNDEF),
233 * so we simply ignore them before doing any checks.
235 if (ELF_R_TYPE(rel
->info
) == R_ARM_V4BX
)
238 switch (sym
->shindex
)
242 ("[ELF Loader] Undefined symbol '%s' in section '%s'\n",
243 (char *)((uint32_t) sh
[shsymtab
->link
].addr
) +
245 (char *)((uint32_t) sh
[eh
->shstrndx
].addr
) +
251 ("[ELF Loader] COMMON symbol '%s' in section '%s'\n",
252 (char *)((uint32_t) sh
[shsymtab
->link
].addr
) +
254 (char *)((uint32_t) sh
[eh
->shstrndx
].addr
) +
260 if (SysBase_sym
== (void *)0) {
262 ((char *)((uint32_t) sh
[shsymtab
->link
].
263 addr
) + sym
->name
, "SysBase",
269 } else if (SysBase_sym
== sym
) {
270 SysBase_yes
: s
= (uint32_t) 4UL;
273 SysBase_no
: s
= sym
->value
;
276 s
= (uint32_t) sh
[sym
->shindex
].addr
+ sym
->value
;
278 switch (ELF32_R_TYPE(rel
->info
)) {
280 // case R_386_32: /* 32bit direct/absolute */
281 // *p += s + virtoffset;
288 /* On ARM the 24 bit offset is shifted by 2 to the right */
289 signed long offset
= (*p
& 0x00ffffff) << 2;
290 /* If highest bit set, make offset negative */
291 if (offset
& 0x02000000)
292 offset
-= 0x04000000;
294 offset
+= s
- (ULONG
)p
;
298 *p
|= offset
& 0x00ffffff;
303 case R_ARM_MOVW_ABS_NC
:
306 signed long offset
= *p
;
307 offset
= ((offset
& 0xf0000) >> 4) | (offset
& 0xfff);
308 offset
= (offset
^ 0x8000) - 0x8000;
310 offset
+= s
+ virtoffset
;
312 if (ELF_R_TYPE(rel
->info
) == R_ARM_MOVT_ABS
)
316 *p
|= ((offset
& 0xf000) << 4) | (offset
& 0x0fff);
320 case R_ARM_ABS32
: /* PC relative 32 bit signed */
321 *p
+= s
+ virtoffset
;
324 case R_ARM_NONE
: /* No reloc */
328 kprintf("[BOOT] Unknown relocation %d in ELF file\n",
329 ELF32_R_TYPE(rel
->info
));
337 int loadElf(void *elf_file
)
339 struct elfheader
*eh
= (struct elfheader
*)elf_file
;
343 kprintf("[BOOT] loadElf(%p)\n", eh
);
347 struct sheader
*sh
= (struct sheader
*)((intptr_t)elf_file
+ eh
->shoff
);
350 for (i
= 0; i
< int_shnum
; i
++)
352 /* Load the symbol and string tables */
353 if (sh
[i
].type
== SHT_SYMTAB
|| sh
[i
].type
== SHT_STRTAB
)
355 sh
[i
].addr
= (unsigned long)elf_file
+ sh
[i
].offset
;
357 /* Does the section require memoy allcation? */
358 else if (sh
[i
].flags
& SHF_ALLOC
)
360 /* Yup, it does. Load the hunk */
361 if (!load_hunk(elf_file
, &sh
[i
]))
369 kprintf("[BOOT] ELF: %s section loaded at %p (Virtual addr: %p)\n",
370 sh
[i
].flags
& SHF_WRITE
? "RW":"RO",
372 sh
[i
].addr
+ virtoffset
);
378 /* For every loaded section perform the relocations */
379 for (i
= 0; i
< int_shnum
; i
++)
381 if (sh
[i
].type
== SHT_REL
&& sh
[sh
[i
].info
].addr
)
383 sh
[i
].addr
= (uint32_t) elf_file
+ sh
[i
].offset
;
384 if (!sh
[i
].addr
|| !relocate(eh
, sh
, i
, virtoffset
))