diff options
Diffstat (limited to 'linux-user/elfload.c')
-rw-r--r-- | linux-user/elfload.c | 292 |
1 files changed, 192 insertions, 100 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 22e3283ae..cde3c49a7 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -12,6 +12,66 @@ #include "qemu.h" #include "disas.h" +/* from personality.h */ + +/* + * Flags for bug emulation. + * + * These occupy the top three bytes. + */ +enum { + ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization of VA space */ + FDPIC_FUNCPTRS = 0x0080000, /* userspace function ptrs point to descriptors + * (signal handling) + */ + MMAP_PAGE_ZERO = 0x0100000, + ADDR_COMPAT_LAYOUT = 0x0200000, + READ_IMPLIES_EXEC = 0x0400000, + ADDR_LIMIT_32BIT = 0x0800000, + SHORT_INODE = 0x1000000, + WHOLE_SECONDS = 0x2000000, + STICKY_TIMEOUTS = 0x4000000, + ADDR_LIMIT_3GB = 0x8000000, +}; + +/* + * Personality types. + * + * These go in the low byte. Avoid using the top bit, it will + * conflict with error returns. + */ +enum { + PER_LINUX = 0x0000, + PER_LINUX_32BIT = 0x0000 | ADDR_LIMIT_32BIT, + PER_LINUX_FDPIC = 0x0000 | FDPIC_FUNCPTRS, + PER_SVR4 = 0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, + PER_SVR3 = 0x0002 | STICKY_TIMEOUTS | SHORT_INODE, + PER_SCOSVR3 = 0x0003 | STICKY_TIMEOUTS | + WHOLE_SECONDS | SHORT_INODE, + PER_OSR5 = 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS, + PER_WYSEV386 = 0x0004 | STICKY_TIMEOUTS | SHORT_INODE, + PER_ISCR4 = 0x0005 | STICKY_TIMEOUTS, + PER_BSD = 0x0006, + PER_SUNOS = 0x0006 | STICKY_TIMEOUTS, + PER_XENIX = 0x0007 | STICKY_TIMEOUTS | SHORT_INODE, + PER_LINUX32 = 0x0008, + PER_LINUX32_3GB = 0x0008 | ADDR_LIMIT_3GB, + PER_IRIX32 = 0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */ + PER_IRIXN32 = 0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */ + PER_IRIX64 = 0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */ + PER_RISCOS = 0x000c, + PER_SOLARIS = 0x000d | STICKY_TIMEOUTS, + PER_UW7 = 0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, + PER_OSF4 = 0x000f, /* OSF/1 v4 */ + PER_HPUX = 0x0010, + PER_MASK = 0x00ff, +}; + +/* + * Return the base personality without flags. + */ +#define personality(pers) (pers & PER_MASK) + /* this flag is uneffective under linux too, should be deleted */ #ifndef MAP_DENYWRITE #define MAP_DENYWRITE 0 @@ -112,18 +172,20 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { - target_long stack = infop->start_stack; + abi_long stack = infop->start_stack; memset(regs, 0, sizeof(*regs)); regs->ARM_cpsr = 0x10; if (infop->entry & 1) regs->ARM_cpsr |= CPSR_T; regs->ARM_pc = infop->entry & 0xfffffffe; regs->ARM_sp = infop->start_stack; - regs->ARM_r2 = tgetl(stack + 8); /* envp */ - regs->ARM_r1 = tgetl(stack + 4); /* envp */ + /* FIXME - what to for failure of get_user()? */ + get_user_ual(regs->ARM_r2, stack + 8); /* envp */ + get_user_ual(regs->ARM_r1, stack + 4); /* envp */ /* 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; } @@ -153,7 +215,11 @@ enum #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_SPARCV9 ) +#ifndef TARGET_ABI32 +#define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS ) +#else +#define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC ) +#endif #define ELF_CLASS ELFCLASS64 #define ELF_DATA ELFDATA2MSB @@ -163,11 +229,20 @@ enum static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { +#ifndef TARGET_ABI32 regs->tstate = 0; +#endif regs->pc = infop->entry; regs->npc = regs->pc + 4; regs->y = 0; - regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS; +#ifdef TARGET_ABI32 + regs->u_regs[14] = infop->start_stack - 16 * 4; +#else + if (personality(infop->personality) == PER_LINUX32) + regs->u_regs[14] = infop->start_stack - 16 * 4; + else + regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS; +#endif } #else @@ -195,7 +270,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_START_MMAP 0x80000000 -#ifdef TARGET_PPC64 +#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) #define elf_check_arch(x) ( (x) == EM_PPC64 ) @@ -249,15 +324,14 @@ do { \ static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop) { - target_ulong pos = infop->start_stack; - target_ulong tmp; -#ifdef TARGET_PPC64 - target_ulong entry, toc; + abi_ulong pos = infop->start_stack; + abi_ulong tmp; +#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) + abi_ulong entry, toc; #endif - _regs->msr = 1 << MSR_PR; /* Set user mode */ _regs->gpr[1] = infop->start_stack; -#ifdef TARGET_PPC64 +#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) entry = ldq_raw(infop->entry) + infop->load_addr; toc = ldq_raw(infop->entry + 8) + infop->load_addr; _regs->gpr[2] = toc; @@ -268,10 +342,11 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * * but this is what the ABI wants and is needed to allow * execution of PPC BSD programs. */ - _regs->gpr[3] = tgetl(pos); - pos += sizeof(target_ulong); + /* FIXME - what to for failure of get_user()? */ + get_user_ual(_regs->gpr[3], pos); + pos += sizeof(abi_ulong); _regs->gpr[4] = pos; - for (tmp = 1; tmp != 0; pos += sizeof(target_ulong)) + for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong)) tmp = ldl(pos); _regs->gpr[5] = pos; } @@ -301,7 +376,7 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { - regs->cp0_status = CP0St_UM; + regs->cp0_status = 2 << CP0St_KSU; regs->cp0_epc = infop->entry; regs->regs[29] = infop->start_stack; } @@ -333,6 +408,26 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #endif +#ifdef TARGET_CRIS + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_CRIS ) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_CRIS + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->erp = infop->entry; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 8192 + +#endif + #ifdef TARGET_M68K #define ELF_START_MMAP 0x80000000 @@ -391,6 +486,13 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_HWCAP 0 #endif +#ifdef TARGET_ABI32 +#undef ELF_CLASS +#define ELF_CLASS ELFCLASS32 +#undef bswaptls +#define bswaptls(ptr) bswap32s(ptr) +#endif + #include "elf.h" struct exec @@ -418,25 +520,6 @@ struct exec /* max code+data+bss+brk space allocated to ET_DYN executables */ #define ET_DYN_MAP_SIZE (128 * 1024 * 1024) -/* from personality.h */ - -/* Flags for bug emulation. These occupy the top three bytes. */ -#define STICKY_TIMEOUTS 0x4000000 -#define WHOLE_SECONDS 0x2000000 - -/* Personality types. These go in the low byte. Avoid using the top bit, - * it will conflict with error returns. - */ -#define PER_MASK (0x00ff) -#define PER_LINUX (0x0000) -#define PER_SVR4 (0x0001 | STICKY_TIMEOUTS) -#define PER_SVR3 (0x0002 | STICKY_TIMEOUTS) -#define PER_SCOSVR3 (0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS) -#define PER_WYSEV386 (0x0004 | STICKY_TIMEOUTS) -#define PER_ISCR4 (0x0005 | STICKY_TIMEOUTS) -#define PER_BSD (0x0006) -#define PER_XENIX (0x0007 | STICKY_TIMEOUTS) - /* Necessary parameters */ #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1)) @@ -516,8 +599,8 @@ static void bswap_sym(struct elf_sym *sym) * 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 abi_ulong copy_elf_strings(int argc,char ** argv, void **page, + abi_ulong p) { char *tmp, *tmp1, *pag = NULL; int len, offset = 0; @@ -566,10 +649,10 @@ static unsigned long copy_elf_strings(int argc,char ** argv, void **page, return p; } -unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm, - struct image_info * info) +static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, + struct image_info *info) { - target_ulong stack_base, size, error; + abi_ulong stack_base, size, error; int i; /* Create enough stack to hold everything. If we don't use @@ -596,7 +679,7 @@ unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm, for (i = 0 ; i < MAX_ARG_PAGES ; i++) { if (bprm->page[i]) { info->rss++; - + /* FIXME - check return value of memcpy_to_target() for failure */ memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE); free(bprm->page[i]); } @@ -605,7 +688,7 @@ unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm, return p; } -static void set_brk(unsigned long start, unsigned long end) +static void set_brk(abi_ulong start, abi_ulong end) { /* page-align the start and end addresses... */ start = HOST_PAGE_ALIGN(start); @@ -624,9 +707,9 @@ static void set_brk(unsigned long start, unsigned long end) /* 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(abi_ulong elf_bss, abi_ulong last_bss) { - unsigned long nbyte; + abi_ulong nbyte; if (elf_bss >= last_bss) return; @@ -637,12 +720,12 @@ static void padzero(unsigned long elf_bss, unsigned long last_bss) 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; + abi_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); } @@ -652,25 +735,26 @@ static void padzero(unsigned long elf_bss, unsigned long last_bss) if (nbyte) { nbyte = qemu_host_page_size - nbyte; do { - tput8(elf_bss, 0); + /* FIXME - what to do if put_user() fails? */ + put_user_u8(0, elf_bss); elf_bss++; } while (--nbyte); } } -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 abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, + struct elfhdr * exec, + abi_ulong load_addr, + abi_ulong load_bias, + abi_ulong interp_load_addr, int ibcs, + struct image_info *info) { - target_ulong sp; + abi_ulong sp; int size; - target_ulong u_platform; + abi_ulong u_platform; const char *k_platform; - const int n = sizeof(target_ulong); + const int n = sizeof(elf_addr_t); sp = p; u_platform = 0; @@ -679,12 +763,13 @@ static unsigned long create_elf_tables(target_ulong p, int argc, int envc, size_t len = strlen(k_platform) + 1; sp -= (len + n - 1) & ~(n - 1); u_platform = sp; + /* FIXME - check return value of memcpy_to_target() for failure */ memcpy_to_target(sp, k_platform, len); } /* * Force 16 byte _final_ alignment here for generality. */ - sp = sp &~ (target_ulong)15; + sp = sp &~ (abi_ulong)15; size = (DLINFO_ITEMS + 1) * 2; if (k_platform) size += 2; @@ -697,25 +782,29 @@ static unsigned long create_elf_tables(target_ulong p, int argc, int envc, if (size & 15) sp -= 16 - (size & 15); -#define NEW_AUX_ENT(id, val) do { \ - sp -= n; tputl(sp, val); \ - sp -= n; tputl(sp, id); \ + /* This is correct because Linux defines + * elf_addr_t as Elf32_Off / Elf64_Off + */ +#define NEW_AUX_ENT(id, val) do { \ + sp -= n; put_user_ual(val, sp); \ + sp -= n; put_user_ual(id, sp); \ } while(0) + NEW_AUX_ENT (AT_NULL, 0); /* There must be exactly DLINFO_ITEMS entries here. */ - NEW_AUX_ENT(AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); - NEW_AUX_ENT(AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); - NEW_AUX_ENT(AT_PHNUM, (target_ulong)(exec->e_phnum)); - NEW_AUX_ENT(AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE)); - NEW_AUX_ENT(AT_BASE, (target_ulong)(interp_load_addr)); - NEW_AUX_ENT(AT_FLAGS, (target_ulong)0); + NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff)); + NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr))); + NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum)); + NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE)); + NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr)); + NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0); NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry); - NEW_AUX_ENT(AT_UID, (target_ulong) getuid()); - NEW_AUX_ENT(AT_EUID, (target_ulong) geteuid()); - NEW_AUX_ENT(AT_GID, (target_ulong) getgid()); - NEW_AUX_ENT(AT_EGID, (target_ulong) getegid()); - NEW_AUX_ENT(AT_HWCAP, (target_ulong) ELF_HWCAP); + NEW_AUX_ENT(AT_UID, (abi_ulong) getuid()); + NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid()); + NEW_AUX_ENT(AT_GID, (abi_ulong) getgid()); + NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid()); + NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP); if (k_platform) NEW_AUX_ENT(AT_PLATFORM, u_platform); #ifdef ARCH_DLINFO @@ -732,17 +821,17 @@ static unsigned long create_elf_tables(target_ulong p, int argc, int envc, } -static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, - int interpreter_fd, - unsigned long *interp_load_addr) +static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex, + int interpreter_fd, + abi_ulong *interp_load_addr) { struct elf_phdr *elf_phdata = NULL; struct elf_phdr *eppnt; - unsigned long load_addr = 0; + abi_ulong load_addr = 0; int load_addr_set = 0; int retval; - unsigned long last_bss, elf_bss; - unsigned long error; + abi_ulong last_bss, elf_bss; + abi_ulong error; int i; elf_bss = 0; @@ -756,20 +845,20 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, if ((interp_elf_ex->e_type != ET_EXEC && interp_elf_ex->e_type != ET_DYN) || !elf_check_arch(interp_elf_ex->e_machine)) { - return ~0UL; + return ~((abi_ulong)0UL); } /* Now read in all of the header information */ if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) - return ~0UL; + return ~(abi_ulong)0UL; elf_phdata = (struct elf_phdr *) malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); if (!elf_phdata) - return ~0UL; + return ~((abi_ulong)0UL); /* * If the size of this structure has changed, then punt, since @@ -777,7 +866,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, */ if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { free(elf_phdata); - return ~0UL; + return ~((abi_ulong)0UL); } retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); @@ -818,8 +907,8 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, if (eppnt->p_type == PT_LOAD) { int elf_type = MAP_PRIVATE | MAP_DENYWRITE; int elf_prot = 0; - unsigned long vaddr = 0; - unsigned long k; + abi_ulong vaddr = 0; + abi_ulong k; if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; @@ -839,7 +928,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, /* Real error */ close(interpreter_fd); free(elf_phdata); - return ~0UL; + return ~((abi_ulong)0UL); } if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { @@ -884,7 +973,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, free(elf_phdata); *interp_load_addr = load_addr; - return ((unsigned long) interp_elf_ex->e_entry) + load_addr; + return ((abi_ulong) interp_elf_ex->e_entry) + load_addr; } /* Best attempt to load symbols from this ELF object. */ @@ -972,22 +1061,22 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, struct elfhdr interp_elf_ex; struct exec interp_ex; int interpreter_fd = -1; /* avoid warning */ - unsigned long load_addr, load_bias; + abi_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; + abi_ulong mapped_addr; struct elf_phdr * elf_ppnt; struct elf_phdr *elf_phdata; - unsigned long elf_bss, k, elf_brk; + abi_ulong elf_bss, k, elf_brk; int retval; char * elf_interpreter; - unsigned long elf_entry, interp_load_addr = 0; + abi_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; + abi_ulong start_code, end_code, start_data, end_data; + abi_ulong reloc_func_desc = 0; + abi_ulong elf_stack; char passed_fileno[6]; ibcs2_interpreter = 0; @@ -1043,10 +1132,11 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, elf_brk = 0; - elf_stack = ~0UL; + elf_stack = ~((abi_ulong)0UL); elf_interpreter = NULL; - start_code = ~0UL; + start_code = ~((abi_ulong)0UL); end_code = 0; + start_data = 0; end_data = 0; for(i=0;i < elf_ex.e_phnum; i++) { @@ -1180,9 +1270,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, /* 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 = (abi_ulong)ELF_START_MMAP; info->mmap = 0; - elf_entry = (unsigned long) elf_ex.e_entry; + elf_entry = (abi_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 +1289,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, 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; + abi_ulong error; if (elf_ppnt->p_type != PT_LOAD) continue; @@ -1257,6 +1347,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, 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 +1365,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, 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) { @@ -1289,7 +1381,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, close(interpreter_fd); free(elf_interpreter); - if (elf_entry == ~0UL) { + if (elf_entry == ~((abi_ulong)0UL)) { printf("Unable to load interpreter\n"); free(elf_phdata); exit(-1); @@ -1320,7 +1412,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, 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; |