X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=linux-user%2Felfload.c;h=c0ea5a01256116ba02b952ef69b97b4b0d07b086;hb=c35734b2a6f9b028edacd5813ff271728ce2a9e3;hp=285d8f5c73bb95d8ccacb791bf635182e8187c4b;hpb=9de5e440b9f6a6c6305c0b81d1df4ddcc5a4b966;p=qemu diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 285d8f5..c0ea5a0 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -3,37 +3,374 @@ #include #include #include -#include #include #include #include #include #include -#include "gemu.h" +#include "qemu.h" +#include "disas.h" + +/* this flag is uneffective under linux too, should be deleted */ +#ifndef MAP_DENYWRITE +#define MAP_DENYWRITE 0 +#endif + +/* should probably go in elf.h */ +#ifndef ELIBBAD +#define ELIBBAD 80 +#endif + +#ifdef TARGET_I386 + +#define ELF_PLATFORM get_elf_platform() + +static const char *get_elf_platform(void) +{ + static char elf_platform[] = "i386"; + int family = (global_env->cpuid_version >> 8) & 0xff; + if (family > 6) + family = 6; + if (family >= 3) + elf_platform[1] = '0' + family; + return elf_platform; +} + +#define ELF_HWCAP get_elf_hwcap() + +static uint32_t get_elf_hwcap(void) +{ + return global_env->cpuid_features; +} + +#define ELF_START_MMAP 0x80000000 + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) ) + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_386 + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->esp = infop->start_stack; + regs->eip = infop->entry; + + /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program + starts %edx contains a pointer to a function which might be + registered using `atexit'. This provides a mean for the + dynamic linker to call DT_FINI functions for shared libraries + that have been loaded before the code runs. + + A value of 0 tells we have no such handler. */ + regs->edx = 0; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#endif + +#ifdef TARGET_ARM + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_ARM ) + +#define ELF_CLASS ELFCLASS32 +#ifdef TARGET_WORDS_BIGENDIAN +#define ELF_DATA ELFDATA2MSB +#else +#define ELF_DATA ELFDATA2LSB +#endif +#define ELF_ARCH EM_ARM + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + target_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 */ + /* XXX: it seems that r0 is zeroed after ! */ + regs->ARM_r0 = 0; + /* For uClinux PIC binaries. */ + regs->ARM_r10 = infop->start_data; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +enum +{ + ARM_HWCAP_ARM_SWP = 1 << 0, + ARM_HWCAP_ARM_HALF = 1 << 1, + ARM_HWCAP_ARM_THUMB = 1 << 2, + ARM_HWCAP_ARM_26BIT = 1 << 3, + ARM_HWCAP_ARM_FAST_MULT = 1 << 4, + ARM_HWCAP_ARM_FPA = 1 << 5, + ARM_HWCAP_ARM_VFP = 1 << 6, + ARM_HWCAP_ARM_EDSP = 1 << 7, +}; + +#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF \ + | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT \ + | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP) + +#endif + +#ifdef TARGET_SPARC +#ifdef TARGET_SPARC64 + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_SPARCV9 ) + +#define ELF_CLASS ELFCLASS64 +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_SPARCV9 + +#define STACK_BIAS 2047 + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->tstate = 0; + regs->pc = infop->entry; + regs->npc = regs->pc + 4; + regs->y = 0; + regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS; +} + +#else +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_SPARC ) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_SPARC + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->psr = 0; + regs->pc = infop->entry; + regs->npc = regs->pc + 4; + regs->y = 0; + regs->u_regs[14] = infop->start_stack - 16 * 4; +} + +#endif +#endif + +#ifdef TARGET_PPC + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_PPC ) + +#define ELF_CLASS ELFCLASS32 +#ifdef TARGET_WORDS_BIGENDIAN +#define ELF_DATA ELFDATA2MSB +#else +#define ELF_DATA ELFDATA2LSB +#endif +#define ELF_ARCH EM_PPC + +/* + * We need to put in some extra aux table entries to tell glibc what + * the cache block size is, so it can use the dcbz instruction safely. + */ +#define AT_DCACHEBSIZE 19 +#define AT_ICACHEBSIZE 20 +#define AT_UCACHEBSIZE 21 +/* A special ignored type value for PPC, for glibc compatibility. */ +#define AT_IGNOREPPC 22 +/* + * The requirements here are: + * - keep the final alignment of sp (sp & 0xf) + * - make sure the 32-bit value at the first 16 byte aligned position of + * AUXV is greater than 16 for glibc compatibility. + * AT_IGNOREPPC is used for that. + * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC, + * even if DLINFO_ARCH_ITEMS goes to zero or is undefined. + */ +#define DLINFO_ARCH_ITEMS 5 +#define ARCH_DLINFO \ +do { \ + NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20); \ + NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20); \ + NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \ + /* \ + * Now handle glibc compatibility. \ + */ \ + NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ + NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ + } while (0) + +static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop) +{ + target_ulong pos = infop->start_stack; + target_ulong tmp; + + _regs->msr = 1 << MSR_PR; /* Set user mode */ + _regs->gpr[1] = infop->start_stack; + _regs->nip = infop->entry; + /* Note that isn't exactly what regular kernel does + * 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); + _regs->gpr[4] = pos; + for (tmp = 1; tmp != 0; pos += sizeof(target_ulong)) + tmp = ldl(pos); + _regs->gpr[5] = pos; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#endif + +#ifdef TARGET_MIPS + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_MIPS ) + +#define ELF_CLASS ELFCLASS32 +#ifdef TARGET_WORDS_BIGENDIAN +#define ELF_DATA ELFDATA2MSB +#else +#define ELF_DATA ELFDATA2LSB +#endif +#define ELF_ARCH EM_MIPS + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->cp0_status = CP0St_UM; + regs->cp0_epc = infop->entry; + regs->regs[29] = infop->start_stack; +} + +#endif /* TARGET_MIPS */ + +#ifdef TARGET_SH4 + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_SH ) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_SH + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + /* Check other registers XXXXX */ + regs->pc = infop->entry; + regs->regs[15] = infop->start_stack - 16 * 4; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#endif + +#ifdef TARGET_M68K + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_68K ) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_68K + +/* ??? Does this need to do anything? +#define ELF_PLAT_INIT(_r) */ + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->usp = infop->start_stack; + regs->sr = 0; + regs->pc = infop->entry; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 8192 + +#endif + +#ifndef ELF_PLATFORM +#define ELF_PLATFORM (NULL) +#endif + +#ifndef ELF_HWCAP +#define ELF_HWCAP 0 +#endif -#include "linux_bin.h" #include "elf.h" -#include "segment.h" -/* Necessary parameters */ -#define ALPHA_PAGE_SIZE 4096 -#define X86_PAGE_SIZE 4096 +struct exec +{ + unsigned int a_info; /* Use macros N_MAGIC, etc for access */ + unsigned int a_text; /* length of text, in bytes */ + unsigned int a_data; /* length of data, in bytes */ + unsigned int a_bss; /* length of uninitialized data area, in bytes */ + unsigned int a_syms; /* length of symbol table data in file, in bytes */ + unsigned int a_entry; /* start address */ + unsigned int a_trsize; /* length of relocation info for text, in bytes */ + unsigned int a_drsize; /* length of relocation info for data, in bytes */ +}; -#define ALPHA_PAGE_MASK (~(ALPHA_PAGE_SIZE-1)) -#define X86_PAGE_MASK (~(X86_PAGE_SIZE-1)) -#define ALPHA_PAGE_ALIGN(addr) ((((addr)+ALPHA_PAGE_SIZE)-1)&ALPHA_PAGE_MASK) -#define X86_PAGE_ALIGN(addr) ((((addr)+X86_PAGE_SIZE)-1)&X86_PAGE_MASK) +#define N_MAGIC(exec) ((exec).a_info & 0xffff) +#define OMAGIC 0407 +#define NMAGIC 0410 +#define ZMAGIC 0413 +#define QMAGIC 0314 -#define NGROUPS 32 +/* max code+data+bss space allocated to elf interpreter */ +#define INTERP_MAP_SIZE (32 * 1024 * 1024) -#define X86_ELF_EXEC_PAGESIZE X86_PAGE_SIZE -#define X86_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(X86_ELF_EXEC_PAGESIZE-1)) -#define X86_ELF_PAGEOFFSET(_v) ((_v) & (X86_ELF_EXEC_PAGESIZE-1)) +/* max code+data+bss+brk space allocated to ET_DYN executables */ +#define ET_DYN_MAP_SIZE (128 * 1024 * 1024) -#define ALPHA_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ALPHA_PAGE_SIZE-1)) -#define ALPHA_ELF_PAGEOFFSET(_v) ((_v) & (ALPHA_PAGE_SIZE-1)) +/* 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)) +#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1)) #define INTERPRETER_NONE 0 #define INTERPRETER_AOUT 1 @@ -41,26 +378,24 @@ #define DLINFO_ITEMS 12 -/* Where we find X86 libraries... */ -//#define X86_DEFAULT_LIB_DIR "/usr/x86/" -#define X86_DEFAULT_LIB_DIR "/" - -//extern void * mmap4k(); -#define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f) +static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) +{ + memcpy(to, from, n); +} extern unsigned long x86_stack_size; static int load_aout_interp(void * exptr, int interp_fd); #ifdef BSWAP_NEEDED -static void bswap_ehdr(Elf32_Ehdr *ehdr) +static void bswap_ehdr(struct elfhdr *ehdr) { bswap16s(&ehdr->e_type); /* Object file type */ bswap16s(&ehdr->e_machine); /* Architecture */ bswap32s(&ehdr->e_version); /* Object file version */ - bswap32s(&ehdr->e_entry); /* Entry point virtual address */ - bswap32s(&ehdr->e_phoff); /* Program header table file offset */ - bswap32s(&ehdr->e_shoff); /* Section header table file offset */ + bswaptls(&ehdr->e_entry); /* Entry point virtual address */ + bswaptls(&ehdr->e_phoff); /* Program header table file offset */ + bswaptls(&ehdr->e_shoff); /* Section header table file offset */ bswap32s(&ehdr->e_flags); /* Processor-specific flags */ bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ @@ -70,51 +405,49 @@ static void bswap_ehdr(Elf32_Ehdr *ehdr) bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ } -static void bswap_phdr(Elf32_Phdr *phdr) +static void bswap_phdr(struct elf_phdr *phdr) { bswap32s(&phdr->p_type); /* Segment type */ - bswap32s(&phdr->p_offset); /* Segment file offset */ - bswap32s(&phdr->p_vaddr); /* Segment virtual address */ - bswap32s(&phdr->p_paddr); /* Segment physical address */ - bswap32s(&phdr->p_filesz); /* Segment size in file */ - bswap32s(&phdr->p_memsz); /* Segment size in memory */ + bswaptls(&phdr->p_offset); /* Segment file offset */ + bswaptls(&phdr->p_vaddr); /* Segment virtual address */ + bswaptls(&phdr->p_paddr); /* Segment physical address */ + bswaptls(&phdr->p_filesz); /* Segment size in file */ + bswaptls(&phdr->p_memsz); /* Segment size in memory */ bswap32s(&phdr->p_flags); /* Segment flags */ - bswap32s(&phdr->p_align); /* Segment alignment */ + bswaptls(&phdr->p_align); /* Segment alignment */ } -#endif -static void * get_free_page(void) +static void bswap_shdr(struct elf_shdr *shdr) { - void * retval; - - /* User-space version of kernel get_free_page. Returns a page-aligned - * page-sized chunk of memory. - */ - retval = mmap4k(0, ALPHA_PAGE_SIZE, PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); - - if((long)retval == -1) { - perror("get_free_page"); - exit(-1); - } - else { - return(retval); - } + bswap32s(&shdr->sh_name); + bswap32s(&shdr->sh_type); + bswaptls(&shdr->sh_flags); + bswaptls(&shdr->sh_addr); + bswaptls(&shdr->sh_offset); + bswaptls(&shdr->sh_size); + bswap32s(&shdr->sh_link); + bswap32s(&shdr->sh_info); + bswaptls(&shdr->sh_addralign); + bswaptls(&shdr->sh_entsize); } -static void free_page(void * pageaddr) +static void bswap_sym(Elf32_Sym *sym) { - (void)munmap(pageaddr, ALPHA_PAGE_SIZE); + bswap32s(&sym->st_name); + bswap32s(&sym->st_value); + bswap32s(&sym->st_size); + bswap16s(&sym->st_shndx); } +#endif /* - * 'copy_string()' copies argument/envelope strings from user + * 'copy_elf_strings()' copies argument/envelope strings from user * memory to free pages in kernel mem. These are in a format ready * to be put directly into the top of new user memory. * */ -static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, - unsigned long p) +static unsigned long copy_elf_strings(int argc,char ** argv, void **page, + unsigned long p) { char *tmp, *tmp1, *pag = NULL; int len, offset = 0; @@ -123,11 +456,13 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, return 0; /* bullet-proofing */ } while (argc-- > 0) { - if (!(tmp1 = tmp = get_user(argv+argc))) { + tmp = argv[argc]; + if (!tmp) { fprintf(stderr, "VFS: argc is wrong"); exit(-1); } - while (get_user(tmp++)); + tmp1 = tmp; + while (*tmp++); len = tmp - tmp1; if (p < len) { /* this shouldn't happen - 128kB */ return 0; @@ -135,15 +470,17 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, while (len) { --p; --tmp; --len; if (--offset < 0) { - offset = p % X86_PAGE_SIZE; - if (!(pag = (char *) page[p/X86_PAGE_SIZE]) && - !(pag = (char *) page[p/X86_PAGE_SIZE] = - (unsigned long *) get_free_page())) { - return 0; + offset = p % TARGET_PAGE_SIZE; + pag = (char *)page[p/TARGET_PAGE_SIZE]; + if (!pag) { + pag = (char *)malloc(TARGET_PAGE_SIZE); + page[p/TARGET_PAGE_SIZE] = pag; + if (!pag) + return 0; } } if (len == 0 || offset == 0) { - *(pag + offset) = get_user(tmp); + *(pag + offset) = *tmp; } else { int bytes_to_copy = (len > offset) ? offset : len; @@ -158,139 +495,41 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, return p; } -static int in_group_p(gid_t g) +unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm, + struct image_info * info) { - /* return TRUE if we're in the specified group, FALSE otherwise */ - int ngroup; - int i; - gid_t grouplist[NGROUPS]; - - ngroup = getgroups(NGROUPS, grouplist); - for(i = 0; i < ngroup; i++) { - if(grouplist[i] == g) { - return 1; - } - } - return 0; -} - -static int count(char ** vec) -{ - int i; - - for(i = 0; *vec; i++) { - vec++; - } - - return(i); -} - -static int prepare_binprm(struct linux_binprm *bprm) -{ - struct stat st; - int mode; - int retval, id_change; - - if(fstat(bprm->fd, &st) < 0) { - return(-errno); - } - - mode = st.st_mode; - if(!S_ISREG(mode)) { /* Must be regular file */ - return(-EACCES); - } - if(!(mode & 0111)) { /* Must have at least one execute bit set */ - return(-EACCES); - } - - bprm->e_uid = geteuid(); - bprm->e_gid = getegid(); - id_change = 0; - - /* Set-uid? */ - if(mode & S_ISUID) { - bprm->e_uid = st.st_uid; - if(bprm->e_uid != geteuid()) { - id_change = 1; - } - } - - /* Set-gid? */ - /* - * If setgid is set but no group execute bit then this - * is a candidate for mandatory locking, not a setgid - * executable. - */ - if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { - bprm->e_gid = st.st_gid; - if (!in_group_p(bprm->e_gid)) { - id_change = 1; - } - } - - memset(bprm->buf, 0, sizeof(bprm->buf)); - retval = lseek(bprm->fd, 0L, SEEK_SET); - if(retval >= 0) { - retval = read(bprm->fd, bprm->buf, 128); - } - if(retval < 0) { - perror("prepare_binprm"); - exit(-1); - /* return(-errno); */ - } - else { - return(retval); - } -} - -unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, - struct image_info * info) -{ - unsigned long stack_base; + target_ulong stack_base, size, error; int i; - extern unsigned long stktop; - - stack_base = X86_STACK_TOP - MAX_ARG_PAGES*X86_PAGE_SIZE; - - p += stack_base; - if (bprm->loader) { - bprm->loader += stack_base; - } - bprm->exec += stack_base; /* Create enough stack to hold everything. If we don't use * it for args, we'll use it for something else... */ - /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so - we allocate a bigger stack. Need a better solution, for example - by remapping the process stack directly at the right place */ - if(x86_stack_size > MAX_ARG_PAGES*X86_PAGE_SIZE) { - if((long)mmap4k((void *)(X86_STACK_TOP-x86_stack_size), x86_stack_size + X86_PAGE_SIZE, - PROT_READ | PROT_WRITE, - MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { - perror("stk mmap"); - exit(-1); - } - } - else { - if((long)mmap4k((void *)stack_base, (MAX_ARG_PAGES+1)*X86_PAGE_SIZE, - PROT_READ | PROT_WRITE, - MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { - perror("stk mmap"); - exit(-1); - } + size = x86_stack_size; + if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) + size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; + error = target_mmap(0, + size + qemu_host_page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + if (error == -1) { + perror("stk mmap"); + exit(-1); } - - stktop = stack_base; + /* we reserve one extra page at the top of the stack as guard */ + target_mprotect(error + size, qemu_host_page_size, PROT_NONE); + + stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; + p += stack_base; for (i = 0 ; i < MAX_ARG_PAGES ; i++) { if (bprm->page[i]) { info->rss++; - memcpy((void *)stack_base, (void *)bprm->page[i], X86_PAGE_SIZE); - free_page((void *)bprm->page[i]); + memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE); + free(bprm->page[i]); } - stack_base += X86_PAGE_SIZE; + stack_base += TARGET_PAGE_SIZE; } return p; } @@ -298,112 +537,137 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, static void set_brk(unsigned long start, unsigned long end) { /* page-align the start and end addresses... */ - start = ALPHA_PAGE_ALIGN(start); - end = ALPHA_PAGE_ALIGN(end); + start = HOST_PAGE_ALIGN(start); + end = HOST_PAGE_ALIGN(end); if (end <= start) return; - if((long)mmap4k(start, end - start, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { + if(target_mmap(start, end - start, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { perror("cannot mmap brk"); exit(-1); } } -/* 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) +/* 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) { unsigned long nbyte; - char * fpnt; - nbyte = elf_bss & (ALPHA_PAGE_SIZE-1); /* was X86_PAGE_SIZE - JRP */ + if (elf_bss >= last_bss) + return; + + /* XXX: this is really a hack : if the real host page size is + smaller than the target page size, some pages after the end + of the file may not be mapped. A better fix would be to + 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; + 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, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + } + } + + nbyte = elf_bss & (qemu_host_page_size-1); if (nbyte) { - nbyte = ALPHA_PAGE_SIZE - nbyte; - fpnt = (char *) elf_bss; + nbyte = qemu_host_page_size - nbyte; do { - *fpnt++ = 0; + tput8(elf_bss, 0); + elf_bss++; } while (--nbyte); } } -static unsigned int * create_elf_tables(char *p, int argc, int envc, - struct elfhdr * exec, - unsigned long load_addr, - unsigned long interp_load_addr, int ibcs, - struct image_info *info) -{ - target_ulong *argv, *envp, *dlinfo; - target_ulong *sp; - - /* - * Force 16 byte alignment here for generality. - */ - sp = (unsigned int *) (~15UL & (unsigned long) p); - sp -= exec ? DLINFO_ITEMS*2 : 2; - dlinfo = sp; - sp -= envc+1; - envp = sp; - sp -= argc+1; - argv = sp; - if (!ibcs) { - put_user(tswapl((target_ulong)envp),--sp); - put_user(tswapl((target_ulong)argv),--sp); - } -#define NEW_AUX_ENT(id, val) \ - put_user (tswapl(id), dlinfo++); \ - put_user (tswapl(val), dlinfo++) - - if (exec) { /* Put this here for an ELF program interpreter */ - struct elf_phdr * eppnt; - eppnt = (struct elf_phdr *)((unsigned long)exec->e_phoff); - - NEW_AUX_ENT (AT_PHDR, (unsigned int)(load_addr + exec->e_phoff)); - NEW_AUX_ENT (AT_PHENT, (unsigned int)(sizeof (struct elf_phdr))); - NEW_AUX_ENT (AT_PHNUM, (unsigned int)(exec->e_phnum)); - NEW_AUX_ENT (AT_PAGESZ, (unsigned int)(ALPHA_PAGE_SIZE)); - NEW_AUX_ENT (AT_BASE, (unsigned int)(interp_load_addr)); - NEW_AUX_ENT (AT_FLAGS, (unsigned int)0); - NEW_AUX_ENT (AT_ENTRY, (unsigned int) exec->e_entry); - NEW_AUX_ENT (AT_UID, (unsigned int) getuid()); - NEW_AUX_ENT (AT_EUID, (unsigned int) geteuid()); - NEW_AUX_ENT (AT_GID, (unsigned int) getgid()); - NEW_AUX_ENT (AT_EGID, (unsigned int) getegid()); +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) +{ + target_ulong sp; + int size; + target_ulong u_platform; + const char *k_platform; + const int n = sizeof(target_ulong); + + sp = p; + u_platform = 0; + k_platform = ELF_PLATFORM; + if (k_platform) { + size_t len = strlen(k_platform) + 1; + sp -= (len + n - 1) & ~(n - 1); + u_platform = sp; + memcpy_to_target(sp, k_platform, len); } + /* + * Force 16 byte _final_ alignment here for generality. + */ + sp = sp &~ (target_ulong)15; + size = (DLINFO_ITEMS + 1) * 2; + if (k_platform) + size += 2; +#ifdef DLINFO_ARCH_ITEMS + size += DLINFO_ARCH_ITEMS * 2; +#endif + size += envc + argc + 2; + size += (!ibcs ? 3 : 1); /* argc itself */ + size *= n; + if (size & 15) + sp -= 16 - (size & 15); + +#define NEW_AUX_ENT(id, val) do { \ + sp -= n; tputl(sp, val); \ + sp -= n; tputl(sp, id); \ + } 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_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); + if (k_platform) + NEW_AUX_ENT(AT_PLATFORM, u_platform); +#ifdef ARCH_DLINFO + /* + * ARCH_DLINFO must come last so platform specific code can enforce + * special alignment requirements on the AUXV if necessary (eg. PPC). + */ + ARCH_DLINFO; +#endif #undef NEW_AUX_ENT - put_user(tswapl(argc),--sp); - info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff); - while (argc-->0) { - put_user(tswapl((target_ulong)p),argv++); - while (get_user(p++)) /* nothing */ ; - } - put_user(0,argv); - info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff); - while (envc-->0) { - put_user(tswapl((target_ulong)p),envp++); - while (get_user(p++)) /* nothing */ ; - } - put_user(0,envp); - info->env_end = (unsigned int)((unsigned long)p & 0xffffffff); + + sp = loader_build_argptr(envc, argc, sp, p, !ibcs); return sp; } - static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, int interpreter_fd, unsigned long *interp_load_addr) { struct elf_phdr *elf_phdata = NULL; struct elf_phdr *eppnt; - unsigned long load_addr; + unsigned long load_addr = 0; int load_addr_set = 0; int retval; unsigned long last_bss, elf_bss; @@ -414,21 +678,20 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, last_bss = 0; error = 0; - /* We put this here so that mmap will search for the *first* - * available memory... - */ - load_addr = INTERP_LOADADDR; - +#ifdef BSWAP_NEEDED + bswap_ehdr(interp_elf_ex); +#endif /* First of all, some simple consistency checks */ if ((interp_elf_ex->e_type != ET_EXEC && - interp_elf_ex->e_type != ET_DYN) || + interp_elf_ex->e_type != ET_DYN) || !elf_check_arch(interp_elf_ex->e_machine)) { return ~0UL; } + /* Now read in all of the header information */ - if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > X86_PAGE_SIZE) + if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) return ~0UL; elf_phdata = (struct elf_phdr *) @@ -441,11 +704,10 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, * If the size of this structure has changed, then punt, since * we will be doing the wrong thing. */ - if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) - { + if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { free(elf_phdata); return ~0UL; - } + } retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); if(retval >= 0) { @@ -453,7 +715,6 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, (char *) elf_phdata, sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); } - if (retval < 0) { perror("load_elf_interp"); exit(-1); @@ -466,6 +727,21 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, bswap_phdr(eppnt); } #endif + + if (interp_elf_ex->e_type == ET_DYN) { + /* in order to avoid harcoding the interpreter load + address in qemu, we allocate a big enough memory zone */ + error = target_mmap(0, INTERP_MAP_SIZE, + PROT_NONE, MAP_PRIVATE | MAP_ANON, + -1, 0); + if (error == -1) { + perror("mmap"); + exit(-1); + } + load_addr = error; + load_addr_set = 1; + } + eppnt = elf_phdata; for(i=0; ie_phnum; i++, eppnt++) if (eppnt->p_type == PT_LOAD) { @@ -481,14 +757,14 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, elf_type |= MAP_FIXED; vaddr = eppnt->p_vaddr; } - error = (unsigned long)mmap4k(load_addr+X86_ELF_PAGESTART(vaddr), - eppnt->p_filesz + X86_ELF_PAGEOFFSET(eppnt->p_vaddr), + error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr), + eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr), elf_prot, elf_type, interpreter_fd, - eppnt->p_offset - X86_ELF_PAGEOFFSET(eppnt->p_vaddr)); + eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); - if (error > -1024UL) { + if (error == -1) { /* Real error */ close(interpreter_fd); free(elf_phdata); @@ -525,14 +801,14 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, * that there are zeromapped pages up to and including the last * bss page. */ - padzero(elf_bss); - elf_bss = X86_ELF_PAGESTART(elf_bss + ALPHA_PAGE_SIZE - 1); /* What we have mapped so far */ + padzero(elf_bss, last_bss); + elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */ /* Map the last of the bss segment */ if (last_bss > elf_bss) { - mmap4k(elf_bss, last_bss-elf_bss, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + target_mmap(elf_bss, last_bss-elf_bss, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); } free(elf_phdata); @@ -540,21 +816,74 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, return ((unsigned long) interp_elf_ex->e_entry) + load_addr; } +/* Best attempt to load symbols from this ELF object. */ +static void load_symbols(struct elfhdr *hdr, int fd) +{ + unsigned int i; + struct elf_shdr sechdr, symtab, strtab; + char *strings; + struct syminfo *s; + + lseek(fd, hdr->e_shoff, SEEK_SET); + for (i = 0; i < hdr->e_shnum; i++) { + if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) + return; +#ifdef BSWAP_NEEDED + bswap_shdr(&sechdr); +#endif + if (sechdr.sh_type == SHT_SYMTAB) { + symtab = sechdr; + lseek(fd, hdr->e_shoff + + sizeof(sechdr) * sechdr.sh_link, SEEK_SET); + if (read(fd, &strtab, sizeof(strtab)) + != sizeof(strtab)) + return; +#ifdef BSWAP_NEEDED + bswap_shdr(&strtab); +#endif + goto found; + } + } + return; /* Shouldn't happen... */ + + found: + /* Now know where the strtab and symtab are. Snarf them. */ + s = malloc(sizeof(*s)); + s->disas_symtab = malloc(symtab.sh_size); + s->disas_strtab = strings = malloc(strtab.sh_size); + if (!s->disas_symtab || !s->disas_strtab) + return; + + lseek(fd, symtab.sh_offset, SEEK_SET); + if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size) + return; +#ifdef BSWAP_NEEDED + for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) + bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i); +#endif -static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, - struct image_info * info) + lseek(fd, strtab.sh_offset, SEEK_SET); + if (read(fd, strings, strtab.sh_size) != strtab.sh_size) + return; + s->disas_num_syms = symtab.sh_size / sizeof(struct elf_sym); + s->next = syminfos; + syminfos = s; +} + +int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, + struct image_info * info) { struct elfhdr elf_ex; struct elfhdr interp_elf_ex; struct exec interp_ex; int interpreter_fd = -1; /* avoid warning */ - unsigned long load_addr; + unsigned long load_addr, load_bias; int load_addr_set = 0; unsigned int interpreter_type = INTERPRETER_NONE; unsigned char ibcs2_interpreter; int i; - void * mapped_addr; + unsigned long mapped_addr; struct elf_phdr * elf_ppnt; struct elf_phdr *elf_phdata; unsigned long elf_bss, k, elf_brk; @@ -569,24 +898,26 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r ibcs2_interpreter = 0; status = 0; load_addr = 0; + load_bias = 0; elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ #ifdef BSWAP_NEEDED bswap_ehdr(&elf_ex); #endif - if (elf_ex.e_ident[0] != 0x7f || - strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) { - return -ENOEXEC; - } - /* First of all, some simple consistency checks */ if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || (! elf_check_arch(elf_ex.e_machine))) { return -ENOEXEC; } - /* Now read in all of the header information */ + bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p); + bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p); + bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p); + if (!bprm->p) { + retval = -E2BIG; + } + /* Now read in all of the header information */ elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum); if (elf_phdata == NULL) { return -ENOMEM; @@ -638,7 +969,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r * is an a.out format binary */ - elf_interpreter = (char *)malloc(elf_ppnt->p_filesz+strlen(X86_DEFAULT_LIB_DIR)); + elf_interpreter = (char *)malloc(elf_ppnt->p_filesz); if (elf_interpreter == NULL) { free (elf_phdata); @@ -646,12 +977,9 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r return -ENOMEM; } - strcpy(elf_interpreter, X86_DEFAULT_LIB_DIR); retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); if(retval >= 0) { - retval = read(bprm->fd, - elf_interpreter+strlen(X86_DEFAULT_LIB_DIR), - elf_ppnt->p_filesz); + retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz); } if(retval < 0) { perror("load_elf_binary2"); @@ -673,7 +1001,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r printf("Using ELF interpreter %s\n", elf_interpreter); #endif if (retval >= 0) { - retval = open(elf_interpreter, O_RDONLY); + retval = open(path(elf_interpreter), O_RDONLY); if(retval >= 0) { interpreter_fd = retval; } @@ -732,15 +1060,15 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r /* OK, we are done with that, now set up the arg stuff, and then start this sucker up */ - if (!bprm->sh_bang) { + { char * passed_p; if (interpreter_type == INTERPRETER_AOUT) { - sprintf(passed_fileno, "%d", bprm->fd); + snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd); passed_p = passed_fileno; if (elf_interpreter) { - bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p); + bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p); bprm->argc++; } } @@ -773,56 +1101,85 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r * address. */ - - for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { - if (elf_ppnt->p_type == PT_LOAD) { - int elf_prot = 0; - if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; - if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; - if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; - - mapped_addr = mmap4k(X86_ELF_PAGESTART(elf_ppnt->p_vaddr), - (elf_ppnt->p_filesz + - X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), - elf_prot, - (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), - bprm->fd, - (elf_ppnt->p_offset - - X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); - - if((unsigned long)mapped_addr == 0xffffffffffffffff) { - perror("mmap"); - exit(-1); - } - - + int elf_prot = 0; + int elf_flags = 0; + unsigned long error; + + if (elf_ppnt->p_type != PT_LOAD) + continue; + + if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; + if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; + if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; + elf_flags = MAP_PRIVATE | MAP_DENYWRITE; + if (elf_ex.e_type == ET_EXEC || load_addr_set) { + elf_flags |= MAP_FIXED; + } else if (elf_ex.e_type == ET_DYN) { + /* Try and get dynamic programs out of the way of the default mmap + base, as well as whatever program they might try to exec. This + is because the brk will follow the loader, and is not movable. */ + /* NOTE: for qemu, we do a big mmap to get enough space + without harcoding any address */ + error = target_mmap(0, ET_DYN_MAP_SIZE, + PROT_NONE, MAP_PRIVATE | MAP_ANON, + -1, 0); + if (error == -1) { + perror("mmap"); + exit(-1); + } + load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr); + } + + error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), + (elf_ppnt->p_filesz + + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), + elf_prot, + (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), + bprm->fd, + (elf_ppnt->p_offset - + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); + if (error == -1) { + perror("mmap"); + exit(-1); + } #ifdef LOW_ELF_STACK - if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) - elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr); -#endif - - if (!load_addr_set) { - load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; - load_addr_set = 1; - } - k = elf_ppnt->p_vaddr; - if (k < start_code) start_code = k; - k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; - if (k > elf_bss) elf_bss = k; -#if 1 - if ((elf_ppnt->p_flags & PF_X) && end_code < k) -#else - if ( !(elf_ppnt->p_flags & PF_W) && end_code < k) + if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) + elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr); #endif - end_code = k; - if (end_data < k) end_data = k; - k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; - if (k > elf_brk) elf_brk = k; - } + + if (!load_addr_set) { + load_addr_set = 1; + load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; + if (elf_ex.e_type == ET_DYN) { + load_bias += error - + TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); + load_addr += load_bias; + } + } + k = elf_ppnt->p_vaddr; + if (k < start_code) + start_code = k; + k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; + if (k > elf_bss) + elf_bss = k; + if ((elf_ppnt->p_flags & PF_X) && end_code < k) + end_code = k; + if (end_data < k) + end_data = k; + k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; + if (k > elf_brk) elf_brk = k; } + elf_entry += load_bias; + elf_bss += load_bias; + elf_brk += load_bias; + start_code += load_bias; + end_code += load_bias; + // start_data += load_bias; + end_data += load_bias; + if (elf_interpreter) { if (interpreter_type & 1) { elf_entry = load_aout_interp(&interp_ex, interpreter_fd); @@ -845,26 +1202,27 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r free(elf_phdata); + if (loglevel) + load_symbols(&elf_ex, bprm->fd); + if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd); info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX); #ifdef LOW_ELF_STACK info->start_stack = bprm->p = elf_stack - 4; #endif - bprm->p = (unsigned long) - create_elf_tables((char *)bprm->p, + bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, - (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), - load_addr, + &elf_ex, + load_addr, load_bias, interp_load_addr, (interpreter_type == INTERPRETER_AOUT ? 0 : 1), info); - if (interpreter_type == INTERPRETER_AOUT) - info->arg_start += strlen(passed_fileno) + 1; info->start_brk = info->brk = elf_brk; info->end_code = end_code; info->start_code = start_code; + info->start_data = end_code; info->end_data = end_data; info->start_stack = bprm->p; @@ -872,7 +1230,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r sections */ set_brk(elf_bss, elf_brk); - padzero(elf_bss); + padzero(elf_bss, elf_brk); #if 0 printf("(start_brk) %x\n" , info->start_brk); @@ -889,88 +1247,22 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r and some applications "depend" upon this behavior. Since we do not have the power to recompile these, we emulate the SVr4 behavior. Sigh. */ - mapped_addr = mmap4k(NULL, ALPHA_PAGE_SIZE, PROT_READ | PROT_EXEC, - MAP_FIXED | MAP_PRIVATE, -1, 0); + mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, -1, 0); } -#ifdef ELF_PLAT_INIT - /* - * The ABI may specify that certain registers be set up in special - * ways (on i386 %edx is the address of a DT_FINI function, for - * example. This macro performs whatever initialization to - * the regs structure is required. - */ - ELF_PLAT_INIT(regs); -#endif - - info->entry = elf_entry; return 0; } - - -int elf_exec(const char * filename, char ** argv, char ** envp, - struct target_pt_regs * regs, struct image_info *infop) -{ - struct linux_binprm bprm; - int retval; - int i; - - bprm.p = X86_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); - for (i=0 ; i=0) { - bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p); - bprm.exec = bprm.p; - bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p); - bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p); - if (!bprm.p) { - retval = -E2BIG; - } - } - - if(retval>=0) { - retval = load_elf_binary(&bprm,regs,infop); - } - if(retval>=0) { - /* success. Initialize important registers */ - regs->esp = infop->start_stack; - regs->eip = infop->entry; - return retval; - } - - /* Something went wrong, return the inode and free the argument pages*/ - for (i=0 ; i