我正在尝试在 64 位 x86 环境中的 Linux 上加载使用“gcc -m32 test.c -o test.exe”编译的 ELF 文件。我正在尝试在具有以下核心逻辑(32 位 ELF)的用户空间 ELF 加载器中加载该 32 位文件(test.exe)。
问题是调用返回的起始地址会导致分段错误核心转储。这是代码:
void *image_load (char *elf_start, unsigned int size)
{
Elf32_Ehdr *hdr = NULL;
Elf32_Phdr *phdr = NULL;
unsigned char *start = NULL;
Elf32_Addr taddr = 0;
Elf32_Addr offset = 0;
int i = 0;
unsigned char *exec = NULL;
Elf32_Addr estart = 0;
hdr = (Elf32_Ehdr *) elf_start;
if(!is_image_valid(hdr)) {
printk("image_load:: invalid ELF image\n");
return 0;
}
exec = (unsigned char *)mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
if(!exec) {
printk("image_load:: error allocating memory\n");
return 0;
}
// Start with clean memory.
memset(exec,0x0,size);
phdr = (Elf32_Phdr *)(elf_start + hdr->e_phoff);
for(i=0; i < hdr->e_phnum; ++i) {
if(phdr[i].p_type != PT_LOAD) {
continue;
}
if(phdr[i].p_filesz > phdr[i].p_memsz) {
printk("image_load:: p_filesz > p_memsz\n");
munmap(exec, size);
return 0;
}
if(!phdr[i].p_filesz) {
continue;
}
// p_filesz can be smaller than p_memsz,
// the difference is zeroe'd out.
start = (unsigned char *) (elf_start + phdr[i].p_offset);
// taddr = phdr[i].p_vaddr + (Elf32_Addr)exec;
if(!estart) {
estart = phdr[i].p_paddr;
}
taddr = (Elf32_Addr)exec + offset + (phdr[i].p_paddr - estart);
memmove((unsigned char *)taddr,
(unsigned char *)start,phdr[i].p_filesz);
offset += (phdr[i].p_memsz + (phdr[i].p_paddr - estart));
if(!(phdr[i].p_flags & PF_W)) {
// Read-only.
mprotect((unsigned char *) taddr,
phdr[i].p_memsz,
PROT_READ);
}
if(phdr[i].p_flags & PF_X) {
// Executable.
mprotect((unsigned char *) taddr,
phdr[i].p_memsz,
PROT_EXEC);
}
}
return (void *)((hdr->e_entry - estart) + (Elf32_Addr)exec);
}/* image_load */
...
int (*main)(int, char **)=image_load(...);
main(argc,argv); // Crash...
...