2 Copyright � 2013, The AROS Development Team. All rights reserved.
16 #define DELF(x) /* x */
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
||
73 eh
->ident
[EI_DATA
] != ELFDATA2MSB
||
75 eh
->ident
[EI_DATA
] != ELFDATA2LSB
||
86 int getElfSize(void *elf_file
, uint32_t *size_rw
, uint32_t *size_ro
)
88 struct elfheader
*eh
= (struct elfheader
*)elf_file
;
92 DELF(kprintf("[BOOT:ELF] getElfSize(%p)", eh
));
96 struct sheader
*sh
= (struct sheader
*)((intptr_t)elf_file
+ eh
->shoff
);
99 for (i
= 0; i
< int_shnum
; i
++)
101 /* Does the section require memoy allcation? */
102 if (sh
[i
].flags
& SHF_ALLOC
)
104 uint32_t size
= (sh
[i
].size
+ sh
[i
].addralign
- 1) & ~(sh
[i
].addralign
- 1);
107 * I extend the section size according to the alignment requirement. However, also the already
108 * measured size has to be aligned poperly. It is so, because the loader has to align the load address later on.
110 if (sh
[i
].flags
& SHF_WRITE
)
112 s_rw
= (s_rw
+ sh
[i
].addralign
- 1) & ~(sh
[i
].addralign
- 1);
117 s_ro
= (s_ro
+ sh
[i
].addralign
- 1) & ~(sh
[i
].addralign
- 1);
123 DELF(kprintf(": ro=%p, rw=%p\n", s_ro
, s_rw
));
133 static uintptr_t ptr_ro
;
134 static uintptr_t ptr_rw
;
135 static uintptr_t virtoffset
;
137 void initAllocator(uintptr_t addr_ro
, uintptr_t addr_rw
, uintptr_t virtoff
)
141 virtoffset
= virtoff
;
144 struct bss_tracker tracker
[MAX_BSS_SECTIONS
];
145 static struct bss_tracker
*bss_tracker
= &tracker
[0];
148 * read_block function copies the range of memory within ELF file to any specified location.
150 static inline void read_block(void *file
, long offset
, void *dest
, long length
)
152 memcpy(dest
, (void *)((unsigned long)file
+ offset
), length
);
156 * Get the memory for chunk and load it
158 static int load_hunk(void *file
, struct sheader
*sh
)
160 void *ptr
= (void *)0;
162 /* empty chunk? Who cares :) */
166 /* Allocate a chunk with write access */
167 if (sh
->flags
& SHF_WRITE
)
169 ptr_rw
= (((unsigned long)ptr_rw
170 + (unsigned long)sh
->addralign
- 1)
171 & ~((unsigned long)sh
->addralign
- 1));
173 ptr_rw
= ptr_rw
+ sh
->size
;
177 /* Read-Only mode? Get the memory from the kernel space, align it accorting to the demand */
178 ptr_ro
= (((unsigned long)ptr_ro
179 + (unsigned long)sh
->addralign
- 1)
180 & ~((unsigned long)sh
->addralign
- 1));
182 ptr_ro
= ptr_ro
+ sh
->size
;
187 /* copy block of memory from ELF file if it exists */
188 if (sh
->type
!= SHT_NOBITS
)
190 read_block(file
, sh
->offset
, (void *)((unsigned long)sh
->addr
),
195 bzero(ptr
, sh
->size
);
197 (void *)((unsigned long)ptr
+ virtoffset
);
198 bss_tracker
->length
= sh
->size
;
201 * empty the subsequent tracker in case it's the last one. We did that in case a buggy firmare
202 * forgot to clear our .bss section
204 bss_tracker
->addr
= (void*)0;
205 bss_tracker
->length
= 0;
211 /* Perform relocations of given section */
212 static int relocate(struct elfheader
*eh
, struct sheader
*sh
, long shrel_idx
,
215 struct sheader
*shrel
= &sh
[shrel_idx
];
216 struct sheader
*shsymtab
= &sh
[shrel
->link
];
217 struct sheader
*toreloc
= &sh
[shrel
->info
];
219 struct symbol
*symtab
=
220 (struct symbol
*)((unsigned long)shsymtab
->addr
);
221 struct relo
*rel
= (struct relo
*)((unsigned long)shrel
->addr
);
222 char *section
= (char *)((unsigned long)toreloc
->addr
);
224 unsigned int numrel
= (unsigned long)shrel
->size
225 / (unsigned long)shrel
->entsize
;
230 struct symbol
*SysBase_sym
= (void *)0;
232 for (i
= 0; i
< numrel
; i
++, rel
++)
234 struct symbol
*sym
= &symtab
[ELF32_R_SYM(rel
->info
)];
235 uint32_t *p
= (uint32_t *) & section
[rel
->offset
];
240 * R_ARM_V4BX are actually special marks for the linker.
241 * They even never have a target (shindex == SHN_UNDEF),
242 * so we simply ignore them before doing any checks.
244 if (ELF_R_TYPE(rel
->info
) == R_ARM_V4BX
)
247 switch (sym
->shindex
)
251 ("[BOOT:ELF] Undefined symbol '%s' in section '%s'\n",
252 (char *)((uint32_t) sh
[shsymtab
->link
].addr
) +
254 (char *)((uint32_t) sh
[eh
->shstrndx
].addr
) +
260 ("[BOOT:ELF] COMMON symbol '%s' in section '%s'\n",
261 (char *)((uint32_t) sh
[shsymtab
->link
].addr
) +
263 (char *)((uint32_t) sh
[eh
->shstrndx
].addr
) +
269 if (SysBase_sym
== (void *)0) {
271 ((char *)((uint32_t) sh
[shsymtab
->link
].
272 addr
) + sym
->name
, "SysBase",
278 } else if (SysBase_sym
== sym
) {
279 SysBase_yes
: s
= (uint32_t) 4UL;
282 SysBase_no
: s
= sym
->value
;
285 s
= (uint32_t) sh
[sym
->shindex
].addr
+ sym
->value
;
287 switch (ELF32_R_TYPE(rel
->info
)) {
289 // case R_386_32: /* 32bit direct/absolute */
290 // *p += s + virtoffset;
297 /* On ARM the 24 bit offset is shifted by 2 to the right */
298 signed long offset
= (AROS_LE2LONG(*p
) & 0x00ffffff) << 2;
299 /* If highest bit set, make offset negative */
300 if (offset
& 0x02000000)
301 offset
-= 0x04000000;
303 offset
+= s
- (ULONG
)p
;
306 *p
&= AROS_LONG2LE(0xff000000);
307 *p
|= AROS_LONG2LE(offset
& 0x00ffffff);
312 case R_ARM_MOVW_ABS_NC
:
315 signed long offset
= AROS_LE2LONG(*p
);
316 offset
= ((offset
& 0xf0000) >> 4) | (offset
& 0xfff);
317 offset
= (offset
^ 0x8000) - 0x8000;
319 offset
+= s
+ virtoffset
;
321 if (ELF_R_TYPE(rel
->info
) == R_ARM_MOVT_ABS
)
324 *p
&= AROS_LONG2LE(0xfff0f000);
325 *p
|= AROS_LONG2LE(((offset
& 0xf000) << 4) | (offset
& 0x0fff));
329 case R_ARM_ABS32
: /* PC relative 32 bit signed */
330 *p
+= s
+ virtoffset
;
333 case R_ARM_NONE
: /* No reloc */
337 kprintf("[BOOT:ELF] Unknown relocation %d in ELF file\n",
338 ELF32_R_TYPE(rel
->info
));
346 int loadElf(void *elf_file
)
348 struct elfheader
*eh
= (struct elfheader
*)elf_file
;
352 DELF(kprintf("[BOOT] loadElf(%p)\n", eh
));
356 struct sheader
*sh
= (struct sheader
*)((intptr_t)elf_file
+ eh
->shoff
);
359 for (i
= 0; i
< int_shnum
; i
++)
361 /* Load the symbol and string tables */
362 if (sh
[i
].type
== SHT_SYMTAB
|| sh
[i
].type
== SHT_STRTAB
)
364 sh
[i
].addr
= (APTR
)((unsigned long)elf_file
+ sh
[i
].offset
);
366 /* Does the section require memoy allcation? */
367 else if (sh
[i
].flags
& SHF_ALLOC
)
369 /* Yup, it does. Load the hunk */
370 if (!load_hunk(elf_file
, &sh
[i
]))
378 DELF(kprintf("[BOOT:ELF] %s section loaded at %p (Virtual addr: %p)\n",
379 sh
[i
].flags
& SHF_WRITE
? "RW":"RO",
381 sh
[i
].addr
+ virtoffset
));
387 /* For every loaded section perform the relocations */
388 for (i
= 0; i
< int_shnum
; i
++)
390 if (sh
[i
].type
== SHT_REL
&& sh
[sh
[i
].info
].addr
)
392 sh
[i
].addr
= (APTR
)((uint32_t) elf_file
+ sh
[i
].offset
);
393 if (!sh
[i
].addr
|| !relocate(eh
, sh
, i
, virtoffset
))