Following what I've done in the syscalls emulation routines, it appeared to me that there seems to be a lot of confusions between host and target long in the ELF loader. I tried to fix this. I also noticed that the image infos start_data field was not computed as the Linux kernel does. As the ARM and the Alpha targets use this information to initialize the program state before execution, it seems a good idea (to me !) to fix it. As this patch can have an impact on all user-mode emulated targets, I'd be glad to have some comments about it to figure if it seems safe to be commited or if some rework will be needed.
Thanks by advance. -- J. Mayer <[EMAIL PROTECTED]> Never organized
Index: linux-user/elfload.c =================================================================== RCS file: /sources/qemu/qemu/linux-user/elfload.c,v retrieving revision 1.48 diff -u -d -d -p -r1.48 elfload.c --- linux-user/elfload.c 27 Sep 2007 04:10:43 -0000 1.48 +++ linux-user/elfload.c 30 Sep 2007 01:30:45 -0000 @@ -124,6 +124,7 @@ static inline void init_thread(struct ta /* XXX: it seems that r0 is zeroed after ! */ regs->ARM_r0 = 0; /* For uClinux PIC binaries. */ + /* XXX: Linux does this only on ARM with no MMU (do we care ?) */ regs->ARM_r10 = infop->start_data; } @@ -516,8 +517,8 @@ static void bswap_sym(struct elf_sym *sy * to be put directly into the top of new user memory. * */ -static unsigned long copy_elf_strings(int argc,char ** argv, void **page, - target_ulong p) +static target_ulong copy_elf_strings(int argc,char ** argv, void **page, + target_ulong p) { char *tmp, *tmp1, *pag = NULL; int len, offset = 0; @@ -566,8 +567,8 @@ static unsigned long copy_elf_strings(in return p; } -unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm, - struct image_info * info) +target_ulong setup_arg_pages(target_ulong p, struct linux_binprm * bprm, + struct image_info * info) { target_ulong stack_base, size, error; int i; @@ -605,7 +606,7 @@ unsigned long setup_arg_pages(target_ulo return p; } -static void set_brk(unsigned long start, unsigned long end) +static void set_brk(target_ulong start, target_ulong end) { /* page-align the start and end addresses... */ start = HOST_PAGE_ALIGN(start); @@ -624,9 +625,9 @@ static void set_brk(unsigned long start, /* We need to explicitly zero any fractional pages after the data section (i.e. bss). This would contain the junk from the file that should not be in memory. */ -static void padzero(unsigned long elf_bss, unsigned long last_bss) +static void padzero(target_ulong elf_bss, target_ulong last_bss) { - unsigned long nbyte; + target_ulong nbyte; if (elf_bss >= last_bss) return; @@ -637,12 +638,12 @@ static void padzero(unsigned long elf_bs patch target_mmap(), but it is more complicated as the file size must be known */ if (qemu_real_host_page_size < qemu_host_page_size) { - unsigned long end_addr, end_addr1; + target_ulong end_addr, end_addr1; end_addr1 = (elf_bss + qemu_real_host_page_size - 1) & ~(qemu_real_host_page_size - 1); end_addr = HOST_PAGE_ALIGN(elf_bss); if (end_addr1 < end_addr) { - mmap((void *)end_addr1, end_addr - end_addr1, + mmap((void *)g2h(end_addr1), end_addr - end_addr1, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); } @@ -659,12 +660,12 @@ static void padzero(unsigned long elf_bs } -static unsigned long create_elf_tables(target_ulong p, int argc, int envc, - struct elfhdr * exec, - unsigned long load_addr, - unsigned long load_bias, - unsigned long interp_load_addr, int ibcs, - struct image_info *info) +static target_ulong create_elf_tables(target_ulong p, int argc, int envc, + struct elfhdr * exec, + target_ulong load_addr, + target_ulong load_bias, + target_ulong interp_load_addr, int ibcs, + struct image_info *info) { target_ulong sp; int size; @@ -732,17 +733,17 @@ static unsigned long create_elf_tables(t } -static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, - int interpreter_fd, - unsigned long *interp_load_addr) +static target_ulong load_elf_interp(struct elfhdr * interp_elf_ex, + int interpreter_fd, + target_ulong *interp_load_addr) { struct elf_phdr *elf_phdata = NULL; struct elf_phdr *eppnt; - unsigned long load_addr = 0; + target_ulong load_addr = 0; int load_addr_set = 0; int retval; - unsigned long last_bss, elf_bss; - unsigned long error; + target_ulong last_bss, elf_bss; + target_ulong error; int i; elf_bss = 0; @@ -818,8 +819,8 @@ static unsigned long load_elf_interp(str if (eppnt->p_type == PT_LOAD) { int elf_type = MAP_PRIVATE | MAP_DENYWRITE; int elf_prot = 0; - unsigned long vaddr = 0; - unsigned long k; + target_ulong vaddr = 0; + target_ulong k; if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; @@ -884,7 +885,7 @@ static unsigned long load_elf_interp(str free(elf_phdata); *interp_load_addr = load_addr; - return ((unsigned long) interp_elf_ex->e_entry) + load_addr; + return ((target_ulong) interp_elf_ex->e_entry) + load_addr; } /* Best attempt to load symbols from this ELF object. */ @@ -972,22 +973,22 @@ int load_elf_binary(struct linux_binprm struct elfhdr interp_elf_ex; struct exec interp_ex; int interpreter_fd = -1; /* avoid warning */ - unsigned long load_addr, load_bias; + target_ulong load_addr, load_bias; int load_addr_set = 0; unsigned int interpreter_type = INTERPRETER_NONE; unsigned char ibcs2_interpreter; int i; - unsigned long mapped_addr; + target_ulong mapped_addr; struct elf_phdr * elf_ppnt; struct elf_phdr *elf_phdata; - unsigned long elf_bss, k, elf_brk; + target_ulong elf_bss, k, elf_brk; int retval; char * elf_interpreter; - unsigned long elf_entry, interp_load_addr = 0; + target_ulong elf_entry, interp_load_addr = 0; int status; - unsigned long start_code, end_code, end_data; - unsigned long reloc_func_desc = 0; - unsigned long elf_stack; + target_ulong start_code, end_code, start_data, end_data; + target_ulong reloc_func_desc = 0; + target_ulong elf_stack; char passed_fileno[6]; ibcs2_interpreter = 0; @@ -1047,6 +1047,7 @@ int load_elf_binary(struct linux_binprm elf_interpreter = NULL; start_code = ~0UL; end_code = 0; + start_data = 0; end_data = 0; for(i=0;i < elf_ex.e_phnum; i++) { @@ -1180,9 +1181,9 @@ int load_elf_binary(struct linux_binprm /* OK, This is the point of no return */ info->end_data = 0; info->end_code = 0; - info->start_mmap = (unsigned long)ELF_START_MMAP; + info->start_mmap = (target_ulong)ELF_START_MMAP; info->mmap = 0; - elf_entry = (unsigned long) elf_ex.e_entry; + elf_entry = (target_ulong) elf_ex.e_entry; /* Do this so that we can load the interpreter, if need be. We will change some of these later */ @@ -1199,7 +1200,7 @@ int load_elf_binary(struct linux_binprm for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { int elf_prot = 0; int elf_flags = 0; - unsigned long error; + target_ulong error; if (elf_ppnt->p_type != PT_LOAD) continue; @@ -1257,6 +1258,8 @@ int load_elf_binary(struct linux_binprm k = elf_ppnt->p_vaddr; if (k < start_code) start_code = k; + if (start_data < k) + start_data = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; if (k > elf_bss) elf_bss = k; @@ -1273,7 +1276,7 @@ int load_elf_binary(struct linux_binprm elf_brk += load_bias; start_code += load_bias; end_code += load_bias; - // start_data += load_bias; + start_data += load_bias; end_data += load_bias; if (elf_interpreter) { @@ -1320,7 +1323,7 @@ int load_elf_binary(struct linux_binprm info->start_brk = info->brk = elf_brk; info->end_code = end_code; info->start_code = start_code; - info->start_data = end_code; + info->start_data = start_data; info->end_data = end_data; info->start_stack = bprm->p; Index: linux-user/main.c =================================================================== RCS file: /sources/qemu/qemu/linux-user/main.c,v retrieving revision 1.124 diff -u -d -d -p -r1.124 main.c --- linux-user/main.c 30 Sep 2007 00:38:37 -0000 1.124 +++ linux-user/main.c 30 Sep 2007 01:30:45 -0000 @@ -1947,14 +1947,17 @@ int main(int argc, char **argv) if (loglevel) { page_dump(logfile); - fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk); - fprintf(logfile, "end_code 0x%08lx\n" , info->end_code); - fprintf(logfile, "start_code 0x%08lx\n" , info->start_code); - fprintf(logfile, "start_data 0x%08lx\n" , info->start_data); - fprintf(logfile, "end_data 0x%08lx\n" , info->end_data); - fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack); - fprintf(logfile, "brk 0x%08lx\n" , info->brk); - fprintf(logfile, "entry 0x%08lx\n" , info->entry); + fprintf(logfile, "start_brk 0x" TARGET_FMT_lx "\n", info->start_brk); + fprintf(logfile, "end_code 0x" TARGET_FMT_lx "\n", info->end_code); + fprintf(logfile, "start_code 0x" TARGET_FMT_lx "\n", + info->start_code); + fprintf(logfile, "start_data 0x" TARGET_FMT_lx "\n", + info->start_data); + fprintf(logfile, "end_data 0x" TARGET_FMT_lx "\n", info->end_data); + fprintf(logfile, "start_stack 0x" TARGET_FMT_lx "\n", + info->start_stack); + fprintf(logfile, "brk 0x" TARGET_FMT_lx "\n", info->brk); + fprintf(logfile, "entry 0x" TARGET_FMT_lx "\n", info->entry); } target_set_brk(info->brk); Index: linux-user/qemu.h =================================================================== RCS file: /sources/qemu/qemu/linux-user/qemu.h,v retrieving revision 1.36 diff -u -d -d -p -r1.36 qemu.h --- linux-user/qemu.h 27 Sep 2007 13:57:54 -0000 1.36 +++ linux-user/qemu.h 30 Sep 2007 01:30:45 -0000 @@ -17,18 +17,18 @@ * task_struct fields in the kernel */ struct image_info { - target_ulong load_addr; - unsigned long start_code; - unsigned long end_code; - unsigned long start_data; - unsigned long end_data; - unsigned long start_brk; - unsigned long brk; - unsigned long start_mmap; - unsigned long mmap; - unsigned long rss; - unsigned long start_stack; - unsigned long entry; + target_ulong load_addr; + target_ulong start_code; + target_ulong end_code; + target_ulong start_data; + target_ulong end_data; + target_ulong start_brk; + target_ulong brk; + target_ulong start_mmap; + target_ulong mmap; + target_ulong rss; + target_ulong start_stack; + target_ulong entry; target_ulong code_offset; target_ulong data_offset; char **host_argv; @@ -105,7 +105,7 @@ extern const char *qemu_uname_release; struct linux_binprm { char buf[128]; void *page[MAX_ARG_PAGES]; - unsigned long p; + target_ulong p; int fd; int e_uid, e_gid; int argc, envc;