Changeset View
Changeset View
Standalone View
Standalone View
stand/common/load_elf.c
Show First 20 Lines • Show All 456 Lines • ▼ Show 20 Lines | #endif | ||||
if (ef.kernel == 1 && multiboot == 0) | if (ef.kernel == 1 && multiboot == 0) | ||||
setenv("kernelname", filename, 1); | setenv("kernelname", filename, 1); | ||||
fp->f_name = strdup(filename); | fp->f_name = strdup(filename); | ||||
if (multiboot == 0) | if (multiboot == 0) | ||||
fp->f_type = strdup(ef.kernel ? | fp->f_type = strdup(ef.kernel ? | ||||
__elfN(kerneltype) : __elfN(moduletype)); | __elfN(kerneltype) : __elfN(moduletype)); | ||||
else | else | ||||
fp->f_type = strdup("elf multiboot kernel"); | fp->f_type = strdup("elf multiboot kernel"); | ||||
#ifdef ELF_VERBOSE | if (module_verbose >= MODULE_VERBOSE_FULL) { | ||||
imp: I'd be tempted to print the ELF_VERBOSE stuff at level 3 and adjust the documented range. | |||||
if (ef.kernel) | if (ef.kernel) | ||||
printf("%s entry at 0x%jx\n", filename, | printf("%s entry at 0x%jx\n", filename, | ||||
Not Done Inline ActionsIt appears the intention is to not twiddle if the verbosity is decreased below the default value module_verbose. In that case, shouldn't this 2 actually be MODULE_VERBOSE? rpokala: It appears the intention is to not twiddle if the verbosity is decreased below the default… | |||||
Done Inline ActionsNo, because again the purpose of the #define is to control the default. sjg: No, because again the purpose of the `#define` is to control the default.
| |||||
(uintmax_t)ehdr->e_entry); | (uintmax_t)ehdr->e_entry); | ||||
#else | } else if (module_verbose > MODULE_VERBOSE_SILENT) | ||||
Not Done Inline Actions
imp: > MODULE_VERBOSE_SILENT | |||||
printf("%s ", filename); | printf("%s ", filename); | ||||
#endif | |||||
if (module_verbose < MODULE_VERBOSE_TWIDDLE) { | |||||
/* A hack for now; we do not want twiddling */ | |||||
twiddle_divisor(UINT_MAX); | |||||
} | |||||
Not Done Inline Actions
imp: >= here maybe | |||||
fp->f_size = __elfN(loadimage)(fp, &ef, dest); | fp->f_size = __elfN(loadimage)(fp, &ef, dest); | ||||
if (fp->f_size == 0 || fp->f_addr == 0) | if (fp->f_size == 0 || fp->f_addr == 0) | ||||
goto ioerr; | goto ioerr; | ||||
/* save exec header as metadata */ | /* save exec header as metadata */ | ||||
file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr); | file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr); | ||||
/* Load OK, return module pointer */ | /* Load OK, return module pointer */ | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | if (off & 0xf0000000u) { | ||||
/* | /* | ||||
* XXX the physical load address should not be | * XXX the physical load address should not be | ||||
* hardcoded. Note that the Book-E kernel assumes that | * hardcoded. Note that the Book-E kernel assumes that | ||||
* it's loaded at a 16MB boundary for now... | * it's loaded at a 16MB boundary for now... | ||||
*/ | */ | ||||
off += 0x01000000; | off += 0x01000000; | ||||
} | } | ||||
ehdr->e_entry += off; | ehdr->e_entry += off; | ||||
#ifdef ELF_VERBOSE | if (module_verbose >= MODULE_VERBOSE_FULL) | ||||
printf("Converted entry 0x%jx\n", (uintmax_t)ehdr->e_entry); | printf("Converted entry 0x%jx\n", | ||||
Not Done Inline Actions
imp: >= here | |||||
#endif | (uintmax_t)ehdr->e_entry); | ||||
#elif defined(__arm__) && !defined(EFI) | #elif defined(__arm__) && !defined(EFI) | ||||
/* | /* | ||||
* The elf headers in arm kernels specify virtual addresses in | * The elf headers in arm kernels specify virtual addresses in | ||||
* all header fields, even the ones that should be physical | * all header fields, even the ones that should be physical | ||||
* addresses. We assume the entry point is in the first page, | * addresses. We assume the entry point is in the first page, | ||||
* and masking the page offset will leave us with the virtual | * and masking the page offset will leave us with the virtual | ||||
* address the kernel was linked at. We subtract that from the | * address the kernel was linked at. We subtract that from the | ||||
* load offset, making 'off' into the value which, when added | * load offset, making 'off' into the value which, when added | ||||
* to a virtual address in an elf header, translates it to a | * to a virtual address in an elf header, translates it to a | ||||
* physical address. We do the va->pa conversion on the entry | * physical address. We do the va->pa conversion on the entry | ||||
* point address in the header now, so that later we can launch | * point address in the header now, so that later we can launch | ||||
* the kernel by just jumping to that address. | * the kernel by just jumping to that address. | ||||
* | * | ||||
* When booting from UEFI the copyin and copyout functions | * When booting from UEFI the copyin and copyout functions | ||||
* handle adjusting the location relative to the first virtual | * handle adjusting the location relative to the first virtual | ||||
* address. Because of this there is no need to adjust the | * address. Because of this there is no need to adjust the | ||||
* offset or entry point address as these will both be handled | * offset or entry point address as these will both be handled | ||||
* by the efi code. | * by the efi code. | ||||
*/ | */ | ||||
off -= ehdr->e_entry & ~PAGE_MASK; | off -= ehdr->e_entry & ~PAGE_MASK; | ||||
ehdr->e_entry += off; | ehdr->e_entry += off; | ||||
#ifdef ELF_VERBOSE | if (module_verbose >= MODULE_VERBOSE_FULL) | ||||
printf("ehdr->e_entry 0x%jx, va<->pa off %llx\n", | printf("ehdr->e_entry 0x%jx, va<->pa off %llx\n", | ||||
(uintmax_t)ehdr->e_entry, off); | (uintmax_t)ehdr->e_entry, off); | ||||
#endif | |||||
#else | #else | ||||
off = 0; /* other archs use direct mapped kernels */ | off = 0; /* other archs use direct mapped kernels */ | ||||
#endif | #endif | ||||
} | } | ||||
ef->off = off; | ef->off = off; | ||||
if (ef->kernel) | if (ef->kernel) | ||||
__elfN(relocation_offset) = off; | __elfN(relocation_offset) = off; | ||||
if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > ef->firstlen) { | if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > ef->firstlen) { | ||||
printf("elf" __XSTRING(__ELF_WORD_SIZE) | printf("elf" __XSTRING(__ELF_WORD_SIZE) | ||||
"_loadimage: program header not within first page\n"); | "_loadimage: program header not within first page\n"); | ||||
goto out; | goto out; | ||||
} | } | ||||
phdr = (Elf_Phdr *)(ef->firstpage + ehdr->e_phoff); | phdr = (Elf_Phdr *)(ef->firstpage + ehdr->e_phoff); | ||||
for (i = 0; i < ehdr->e_phnum; i++) { | for (i = 0; i < ehdr->e_phnum; i++) { | ||||
if (elf_program_header_convert(ehdr, phdr)) | if (elf_program_header_convert(ehdr, phdr)) | ||||
continue; | continue; | ||||
/* We want to load PT_LOAD segments only.. */ | /* We want to load PT_LOAD segments only.. */ | ||||
if (phdr[i].p_type != PT_LOAD) | if (phdr[i].p_type != PT_LOAD) | ||||
continue; | continue; | ||||
#ifdef ELF_VERBOSE | if (module_verbose >= MODULE_VERBOSE_FULL) { | ||||
printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx", | printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx", | ||||
(long)phdr[i].p_filesz, (long)phdr[i].p_offset, | (long)phdr[i].p_filesz, (long)phdr[i].p_offset, | ||||
(long)(phdr[i].p_vaddr + off), | (long)(phdr[i].p_vaddr + off), | ||||
(long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1)); | (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1)); | ||||
#else | } else if (module_verbose > MODULE_VERBOSE_SILENT) { | ||||
if ((phdr[i].p_flags & PF_W) == 0) { | if ((phdr[i].p_flags & PF_W) == 0) { | ||||
printf("text=0x%lx ", (long)phdr[i].p_filesz); | printf("text=0x%lx ", (long)phdr[i].p_filesz); | ||||
} else { | } else { | ||||
printf("data=0x%lx", (long)phdr[i].p_filesz); | printf("data=0x%lx", (long)phdr[i].p_filesz); | ||||
if (phdr[i].p_filesz < phdr[i].p_memsz) | if (phdr[i].p_filesz < phdr[i].p_memsz) | ||||
printf("+0x%lx", (long)(phdr[i].p_memsz - | printf("+0x%lx", (long)(phdr[i].p_memsz - | ||||
phdr[i].p_filesz)); | phdr[i].p_filesz)); | ||||
printf(" "); | printf(" "); | ||||
} | } | ||||
#endif | } | ||||
fpcopy = 0; | fpcopy = 0; | ||||
if (ef->firstlen > phdr[i].p_offset) { | if (ef->firstlen > phdr[i].p_offset) { | ||||
fpcopy = ef->firstlen - phdr[i].p_offset; | fpcopy = ef->firstlen - phdr[i].p_offset; | ||||
archsw.arch_copyin(ef->firstpage + phdr[i].p_offset, | archsw.arch_copyin(ef->firstpage + phdr[i].p_offset, | ||||
phdr[i].p_vaddr + off, fpcopy); | phdr[i].p_vaddr + off, fpcopy); | ||||
} | } | ||||
if (phdr[i].p_filesz > fpcopy) { | if (phdr[i].p_filesz > fpcopy) { | ||||
if (kern_pread(VECTX_HANDLE(ef), | if (kern_pread(VECTX_HANDLE(ef), | ||||
phdr[i].p_vaddr + off + fpcopy, | phdr[i].p_vaddr + off + fpcopy, | ||||
phdr[i].p_filesz - fpcopy, | phdr[i].p_filesz - fpcopy, | ||||
phdr[i].p_offset + fpcopy) != 0) { | phdr[i].p_offset + fpcopy) != 0) { | ||||
printf("\nelf" __XSTRING(__ELF_WORD_SIZE) | printf("\nelf" __XSTRING(__ELF_WORD_SIZE) | ||||
"_loadimage: read failed\n"); | "_loadimage: read failed\n"); | ||||
goto out; | goto out; | ||||
} | } | ||||
} | } | ||||
/* clear space from oversized segments; eg: bss */ | /* clear space from oversized segments; eg: bss */ | ||||
if (phdr[i].p_filesz < phdr[i].p_memsz) { | if (phdr[i].p_filesz < phdr[i].p_memsz) { | ||||
#ifdef ELF_VERBOSE | if (module_verbose >= MODULE_VERBOSE_FULL) { | ||||
printf(" (bss: 0x%lx-0x%lx)", | printf(" (bss: 0x%lx-0x%lx)", | ||||
(long)(phdr[i].p_vaddr + off + phdr[i].p_filesz), | (long)(phdr[i].p_vaddr + off + phdr[i].p_filesz), | ||||
(long)(phdr[i].p_vaddr + off + phdr[i].p_memsz -1)); | (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz -1)); | ||||
#endif | } | ||||
kern_bzero(phdr[i].p_vaddr + off + phdr[i].p_filesz, | kern_bzero(phdr[i].p_vaddr + off + phdr[i].p_filesz, | ||||
phdr[i].p_memsz - phdr[i].p_filesz); | phdr[i].p_memsz - phdr[i].p_filesz); | ||||
} | } | ||||
#ifdef ELF_VERBOSE | if (module_verbose >= MODULE_VERBOSE_FULL) | ||||
printf("\n"); | printf("\n"); | ||||
#endif | |||||
if (archsw.arch_loadseg != NULL) | if (archsw.arch_loadseg != NULL) | ||||
archsw.arch_loadseg(ehdr, phdr + i, off); | archsw.arch_loadseg(ehdr, phdr + i, off); | ||||
if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off)) | if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off)) | ||||
firstaddr = phdr[i].p_vaddr + off; | firstaddr = phdr[i].p_vaddr + off; | ||||
if (lastaddr == 0 || lastaddr < | if (lastaddr == 0 || lastaddr < | ||||
(phdr[i].p_vaddr + off + phdr[i].p_memsz)) | (phdr[i].p_vaddr + off + phdr[i].p_memsz)) | ||||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | for (i = 0; i < ehdr->e_shnum; i++) { | ||||
/* Save it for loading below */ | /* Save it for loading below */ | ||||
symtabindex = i; | symtabindex = i; | ||||
symstrindex = shdr[i].sh_link; | symstrindex = shdr[i].sh_link; | ||||
} | } | ||||
if (symtabindex < 0 || symstrindex < 0) | if (symtabindex < 0 || symstrindex < 0) | ||||
goto nosyms; | goto nosyms; | ||||
/* Ok, committed to a load. */ | /* Ok, committed to a load. */ | ||||
#ifndef ELF_VERBOSE | if (module_verbose >= MODULE_VERBOSE_FULL) | ||||
printf("syms=["); | printf("syms=["); | ||||
#endif | |||||
ssym = lastaddr; | ssym = lastaddr; | ||||
for (i = symtabindex; i >= 0; i = symstrindex) { | for (i = symtabindex; i >= 0; i = symstrindex) { | ||||
#ifdef ELF_VERBOSE | |||||
char *secname; | char *secname; | ||||
switch(shdr[i].sh_type) { | switch(shdr[i].sh_type) { | ||||
case SHT_SYMTAB: /* Symbol table */ | case SHT_SYMTAB: /* Symbol table */ | ||||
secname = "symtab"; | secname = "symtab"; | ||||
break; | break; | ||||
case SHT_STRTAB: /* String table */ | case SHT_STRTAB: /* String table */ | ||||
secname = "strtab"; | secname = "strtab"; | ||||
break; | break; | ||||
default: | default: | ||||
secname = "WHOA!!"; | secname = "WHOA!!"; | ||||
break; | break; | ||||
} | } | ||||
#endif | |||||
size = shdr[i].sh_size; | size = shdr[i].sh_size; | ||||
archsw.arch_copyin(&size, lastaddr, sizeof(size)); | archsw.arch_copyin(&size, lastaddr, sizeof(size)); | ||||
lastaddr += sizeof(size); | lastaddr += sizeof(size); | ||||
#ifdef ELF_VERBOSE | if (module_verbose >= MODULE_VERBOSE_FULL) { | ||||
printf("\n%s: 0x%jx@0x%jx -> 0x%jx-0x%jx", secname, | printf("\n%s: 0x%jx@0x%jx -> 0x%jx-0x%jx", secname, | ||||
(uintmax_t)shdr[i].sh_size, (uintmax_t)shdr[i].sh_offset, | (uintmax_t)shdr[i].sh_size, (uintmax_t)shdr[i].sh_offset, | ||||
(uintmax_t)lastaddr, | (uintmax_t)lastaddr, | ||||
(uintmax_t)(lastaddr + shdr[i].sh_size)); | (uintmax_t)(lastaddr + shdr[i].sh_size)); | ||||
#else | } else if (module_verbose > MODULE_VERBOSE_SILENT) { | ||||
if (i == symstrindex) | if (i == symstrindex) | ||||
printf("+"); | printf("+"); | ||||
printf("0x%lx+0x%lx", (long)sizeof(size), (long)size); | printf("0x%lx+0x%lx", (long)sizeof(size), (long)size); | ||||
#endif | } | ||||
if (VECTX_LSEEK(VECTX_HANDLE(ef), (off_t)shdr[i].sh_offset, SEEK_SET) == -1) { | if (VECTX_LSEEK(VECTX_HANDLE(ef), (off_t)shdr[i].sh_offset, SEEK_SET) == -1) { | ||||
printf("\nelf" __XSTRING(__ELF_WORD_SIZE) | printf("\nelf" __XSTRING(__ELF_WORD_SIZE) | ||||
"_loadimage: could not seek for symbols - skipped!"); | "_loadimage: could not seek for symbols - skipped!"); | ||||
lastaddr = ssym; | lastaddr = ssym; | ||||
ssym = 0; | ssym = 0; | ||||
goto nosyms; | goto nosyms; | ||||
} | } | ||||
result = archsw.arch_readin(VECTX_HANDLE(ef), lastaddr, shdr[i].sh_size); | result = archsw.arch_readin(VECTX_HANDLE(ef), lastaddr, shdr[i].sh_size); | ||||
Show All 10 Lines | for (i = symtabindex; i >= 0; i = symstrindex) { | ||||
lastaddr += shdr[i].sh_size; | lastaddr += shdr[i].sh_size; | ||||
lastaddr = roundup(lastaddr, sizeof(size)); | lastaddr = roundup(lastaddr, sizeof(size)); | ||||
if (i == symtabindex) | if (i == symtabindex) | ||||
symtabindex = -1; | symtabindex = -1; | ||||
else if (i == symstrindex) | else if (i == symstrindex) | ||||
symstrindex = -1; | symstrindex = -1; | ||||
} | } | ||||
esym = lastaddr; | esym = lastaddr; | ||||
#ifndef ELF_VERBOSE | if (module_verbose >= MODULE_VERBOSE_FULL) | ||||
printf("]"); | printf("]"); | ||||
#endif | |||||
file_addmetadata(fp, MODINFOMD_SSYM, sizeof(ssym), &ssym); | file_addmetadata(fp, MODINFOMD_SSYM, sizeof(ssym), &ssym); | ||||
file_addmetadata(fp, MODINFOMD_ESYM, sizeof(esym), &esym); | file_addmetadata(fp, MODINFOMD_ESYM, sizeof(esym), &esym); | ||||
nosyms: | nosyms: | ||||
if (module_verbose > MODULE_VERBOSE_SILENT) | |||||
printf("\n"); | printf("\n"); | ||||
ret = lastaddr - firstaddr; | ret = lastaddr - firstaddr; | ||||
fp->f_addr = firstaddr; | fp->f_addr = firstaddr; | ||||
php = NULL; | php = NULL; | ||||
for (i = 0; i < ehdr->e_phnum; i++) { | for (i = 0; i < ehdr->e_phnum; i++) { | ||||
if (phdr[i].p_type == PT_DYNAMIC) { | if (phdr[i].p_type == PT_DYNAMIC) { | ||||
php = phdr + i; | php = phdr + i; | ||||
▲ Show 20 Lines • Show All 472 Lines • Show Last 20 Lines |
I'd be tempted to print the ELF_VERBOSE stuff at level 3 and adjust the documented range.