2 Copyright © 2013-2019, 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
||
71 !(eh
->type
== ET_REL
|| eh
->type
== ET_EXEC
) ||
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
,
213 uint32_t virt
, uintptr_t *deltas
)
215 struct sheader
*shrel
= &sh
[shrel_idx
];
216 struct sheader
*shsymtab
= &sh
[shrel
->link
];
217 struct sheader
*toreloc
= &sh
[shrel
->info
];
218 uintptr_t orig_addr
= deltas
[shrel
->info
];
219 int is_exec
= (eh
->type
== ET_EXEC
);
221 struct symbol
*symtab
=
222 (struct symbol
*)((unsigned long)shsymtab
->addr
);
223 struct relo
*rel
= (struct relo
*)((unsigned long)shrel
->addr
);
224 char *section
= (char *)((unsigned long)toreloc
->addr
);
226 unsigned int numrel
= (unsigned long)shrel
->size
227 / (unsigned long)shrel
->entsize
;
232 struct symbol
*SysBase_sym
= (void *)0;
234 for (i
= 0; i
< numrel
; i
++, rel
++)
236 struct symbol
*sym
= &symtab
[ELF32_R_SYM(rel
->info
)];
237 uint32_t *p
= (uint32_t *) & section
[rel
->offset
- orig_addr
];
242 * R_ARM_V4BX are actually special marks for the linker.
243 * They even never have a target (shindex == SHN_UNDEF),
244 * so we simply ignore them before doing any checks.
246 if (ELF_R_TYPE(rel
->info
) == R_ARM_V4BX
)
249 switch (sym
->shindex
)
253 ("[BOOT:ELF] Undefined symbol '%s' in section '%s'\n",
254 (char *)((uint32_t) sh
[shsymtab
->link
].addr
) +
256 (char *)((uint32_t) sh
[eh
->shstrndx
].addr
) +
262 ("[BOOT:ELF] COMMON symbol '%s' in section '%s'\n",
263 (char *)((uint32_t) sh
[shsymtab
->link
].addr
) +
265 (char *)((uint32_t) sh
[eh
->shstrndx
].addr
) +
271 if (SysBase_sym
== (void *)0) {
273 ((char *)((uint32_t) sh
[shsymtab
->link
].
274 addr
) + sym
->name
, "SysBase",
280 } else if (SysBase_sym
== sym
) {
281 SysBase_yes
: s
= (uint32_t) 4UL;
284 SysBase_no
: s
= sym
->value
;
287 s
= (uint32_t) sh
[sym
->shindex
].addr
+ sym
->value
- deltas
[sym
->shindex
];
289 switch (ELF32_R_TYPE(rel
->info
)) {
297 Real executables are already properly relocated. Here, adjustment is
298 necessary *only* if the jump is across sections and *only* if offset
299 between both sections differs from the one in executable.
301 if shrel->info == sym->shindex don't do anything!
303 if (shrel
->info
!= sym
->shindex
)
305 intptr_t expected_delta
= deltas
[sym
->shindex
] - deltas
[shrel
->info
];
306 intptr_t actual_delta
= sh
[sym
->shindex
].addr
- sh
[shrel
->info
].addr
;
308 /* On ARM the 24 bit offset is shifted by 2 to the right */
309 intptr_t offset
= (AROS_LE2LONG(*p
) & 0x00ffffff) << 2;
310 /* If highest bit set, make offset negative */
311 if (offset
& 0x02000000)
312 offset
-= 0x04000000;
315 offset
+= actual_delta
- expected_delta
;
319 *p
&= AROS_LONG2LE(0xff000000);
320 *p
|= AROS_LONG2LE(offset
& 0x00ffffff);
325 /* On ARM the 24 bit offset is shifted by 2 to the right */
326 signed long offset
= (AROS_LE2LONG(*p
) & 0x00ffffff) << 2;
327 /* If highest bit set, make offset negative */
328 if (offset
& 0x02000000)
329 offset
-= 0x04000000;
331 offset
+= s
- (ULONG
)p
;
334 *p
&= AROS_LONG2LE(0xff000000);
335 *p
|= AROS_LONG2LE(offset
& 0x00ffffff);
341 case R_ARM_MOVW_ABS_NC
:
344 intptr_t offset
= AROS_LE2LONG(*p
);
345 offset
= ((offset
& 0xf0000) >> 4) | (offset
& 0xfff);
346 //offset = (offset ^ 0x8000) - 0x8000;
348 /* If MOVT relocation shift the offset 16 bits left */
349 if (ELF_R_TYPE(rel
->info
) == R_ARM_MOVT_ABS
)
352 kprintf("movw/movt: offset=%08x, s=%08x, sym->value=%08x, section_orig_addr=%08x, section_addr=%08x\n", offset
, s
, sym
->value
,
353 deltas
[sym
->shindex
], sh
[sym
->shindex
].addr
+ virtoffset
);
357 /* Fix address by difference between actual address and expected address */
358 offset
+= (intptr_t)sh
[sym
->shindex
].addr
- (intptr_t)deltas
[sym
->shindex
] + (intptr_t)virtoffset
;
362 offset
+= (intptr_t)(s
+ virtoffset
);
365 /* If MOVT shift the offset back */
366 if (ELF_R_TYPE(rel
->info
) == R_ARM_MOVT_ABS
)
369 *p
&= AROS_LONG2LE(0xfff0f000);
370 *p
|= AROS_LONG2LE(((offset
& 0xf000) << 4) | (offset
& 0x0fff));
374 case R_ARM_ABS32
: /* PC relative 32 bit signed */
377 *p
+= (uintptr_t)sh
[sym
->shindex
].addr
- (uintptr_t)deltas
[sym
->shindex
] + (uintptr_t)virtoffset
;
381 *p
+= s
+ virtoffset
;
385 case R_ARM_NONE
: /* No reloc */
389 kprintf("[BOOT:ELF] Unknown relocation %d in ELF file\n",
390 ELF32_R_TYPE(rel
->info
));
398 int loadElf(void *elf_file
)
400 struct elfheader
*eh
= (struct elfheader
*)elf_file
;
401 uintptr_t deltas
[int_shnum
];
405 DELF(kprintf("[BOOT] loadElf(%p)\n", eh
));
409 struct sheader
*sh
= (struct sheader
*)((intptr_t)elf_file
+ eh
->shoff
);
412 for (i
= 0; i
< int_shnum
; i
++)
414 /* Load the symbol and string tables */
415 if (sh
[i
].type
== SHT_SYMTAB
|| sh
[i
].type
== SHT_STRTAB
)
417 sh
[i
].addr
= (APTR
)((unsigned long)elf_file
+ sh
[i
].offset
);
419 /* Does the section require memoy allcation? */
420 else if (sh
[i
].flags
& SHF_ALLOC
)
422 deltas
[i
] = (uintptr_t)sh
[i
].addr
;
423 /* Yup, it does. Load the hunk */
424 if (!load_hunk(elf_file
, &sh
[i
]))
432 DELF(kprintf("[BOOT:ELF] %s section loaded at %p (Virtual addr: %p, requestet addr: %p)\n",
433 sh
[i
].flags
& SHF_WRITE
? "RW":"RO",
435 sh
[i
].addr
+ virtoffset
,
442 /* For every loaded section perform the relocations */
443 for (i
= 0; i
< int_shnum
; i
++)
445 if (sh
[i
].type
== SHT_REL
&& sh
[sh
[i
].info
].addr
)
447 sh
[i
].addr
= (APTR
)((uint32_t) elf_file
+ sh
[i
].offset
);
448 if (!sh
[i
].addr
|| !relocate(eh
, sh
, i
, virtoffset
, deltas
))