X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=linux-user%2Felfload.c;h=c0ea5a01256116ba02b952ef69b97b4b0d07b086;hb=c35734b2a6f9b028edacd5813ff271728ce2a9e3;hp=9999268eaa0ffdd726051c15b228d0a1964707e5;hpb=f515528907764d1fb1fab2e68a8be25e15b3c096;p=qemu diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 9999268..c0ea5a0 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -13,8 +12,38 @@ #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 /* @@ -29,19 +58,19 @@ #define ELF_DATA ELFDATA2LSB #define ELF_ARCH EM_386 - /* 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. */ -#define ELF_PLAT_INIT(_r) _r->edx = 0 - 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 @@ -63,39 +92,75 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #endif #define ELF_ARCH EM_ARM -#define ELF_PLAT_INIT(_r) _r->ARM_r0 = 0 - static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { - target_long *stack = (void *)infop->start_stack; + target_long stack = infop->start_stack; memset(regs, 0, sizeof(*regs)); regs->ARM_cpsr = 0x10; - regs->ARM_pc = infop->entry; + if (infop->entry & 1) + regs->ARM_cpsr |= CPSR_T; + regs->ARM_pc = infop->entry & 0xfffffffe; regs->ARM_sp = infop->start_stack; - regs->ARM_r2 = tswapl(stack[2]); /* envp */ - regs->ARM_r1 = tswapl(stack[1]); /* argv */ + 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 = tswapl(stack[0]); /* argc */ + 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 -/*XXX*/ -#define ELF_PLAT_INIT(_r) - static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { regs->psr = 0; @@ -106,6 +171,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i } #endif +#endif #ifdef TARGET_PPC @@ -121,20 +187,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #endif #define ELF_ARCH EM_PPC -/* 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. - */ -#define ELF_PLAT_INIT(_r) \ -do { \ - unsigned long *pos = (unsigned long *)bprm->p, tmp = 1; \ - _r->gpr[3] = bprm->argc; \ - _r->gpr[4] = (unsigned long)++pos; \ - for (; tmp != 0; pos++) \ - tmp = *pos; \ - _r->gpr[5] = (unsigned long)pos; \ -} while (0) - /* * 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. @@ -153,26 +205,37 @@ do { \ * - 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 3 +#define DLINFO_ARCH_ITEMS 5 #define ARCH_DLINFO \ do { \ - sp -= DLINFO_ARCH_ITEMS * 2; \ - NEW_AUX_ENT(0, AT_DCACHEBSIZE, 0x20); \ - NEW_AUX_ENT(1, AT_ICACHEBSIZE, 0x20); \ - NEW_AUX_ENT(2, AT_UCACHEBSIZE, 0); \ + NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20); \ + NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20); \ + NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \ /* \ * Now handle glibc compatibility. \ */ \ - sp -= 2*2; \ - NEW_AUX_ENT(0, AT_IGNOREPPC, AT_IGNOREPPC); \ - NEW_AUX_ENT(1, AT_IGNOREPPC, AT_IGNOREPPC); \ + 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 @@ -180,31 +243,85 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * #endif -#include "elf.h" +#ifdef TARGET_MIPS -/* - * MAX_ARG_PAGES defines the number of pages allocated for arguments - * and envelope for the new program. 32 should suffice, this gives - * a maximum env+arg of 128kB w/4KB pages! - */ -#define MAX_ARG_PAGES 32 +#define ELF_START_MMAP 0x80000000 -/* - * This structure is used to hold the arguments that are - * used when loading binaries. - */ -struct linux_binprm { - char buf[128]; - unsigned long page[MAX_ARG_PAGES]; - unsigned long p; - int sh_bang; - int fd; - int e_uid, e_gid; - int argc, envc; - char * filename; /* Name of binary */ - unsigned long loader, exec; - int dont_iput; /* binfmt handler has put inode */ -}; +#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 "elf.h" struct exec { @@ -251,8 +368,6 @@ struct exec #define PER_XENIX (0x0007 | STICKY_TIMEOUTS) /* Necessary parameters */ -#define NGROUPS 32 - #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)) @@ -261,34 +376,26 @@ struct exec #define INTERPRETER_AOUT 1 #define INTERPRETER_ELF 2 -#define DLINFO_ITEMS 11 - -#define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x)) -#define get_user(ptr) (typeof(*ptr))(*(ptr)) +#define DLINFO_ITEMS 12 static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) { memcpy(to, from, n); } -static inline void memcpy_tofs(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 */ @@ -298,30 +405,30 @@ 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 */ } -static void bswap_shdr(Elf32_Shdr *shdr) +static void bswap_shdr(struct elf_shdr *shdr) { bswap32s(&shdr->sh_name); bswap32s(&shdr->sh_type); - bswap32s(&shdr->sh_flags); - bswap32s(&shdr->sh_addr); - bswap32s(&shdr->sh_offset); - bswap32s(&shdr->sh_size); + bswaptls(&shdr->sh_flags); + bswaptls(&shdr->sh_addr); + bswaptls(&shdr->sh_offset); + bswaptls(&shdr->sh_size); bswap32s(&shdr->sh_link); bswap32s(&shdr->sh_info); - bswap32s(&shdr->sh_addralign); - bswap32s(&shdr->sh_entsize); + bswaptls(&shdr->sh_addralign); + bswaptls(&shdr->sh_entsize); } static void bswap_sym(Elf32_Sym *sym) @@ -333,38 +440,14 @@ static void bswap_sym(Elf32_Sym *sym) } #endif -static void * get_free_page(void) -{ - void * retval; - - /* User-space version of kernel get_free_page. Returns a page-aligned - * page-sized chunk of memory. - */ - retval = (void *)target_mmap(0, host_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); - } -} - -static void free_page(void * pageaddr) -{ - target_munmap((unsigned long)pageaddr, host_page_size); -} - /* - * '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; @@ -373,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; @@ -386,14 +471,16 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, --p; --tmp; --len; if (--offset < 0) { offset = p % TARGET_PAGE_SIZE; - if (!(pag = (char *) page[p/TARGET_PAGE_SIZE]) && - !(pag = (char *) page[p/TARGET_PAGE_SIZE] = - (unsigned long *) get_free_page())) { - return 0; + 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; @@ -408,95 +495,10 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, return p; } -static int in_group_p(gid_t g) -{ - /* 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 setup_arg_pages(target_ulong p, struct linux_binprm * bprm, + struct image_info * info) { - unsigned long stack_base, size, error; + target_ulong stack_base, size, error; int i; /* Create enough stack to hold everything. If we don't use @@ -506,7 +508,7 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; error = target_mmap(0, - size + host_page_size, + size + qemu_host_page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); @@ -515,24 +517,19 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, exit(-1); } /* we reserve one extra page at the top of the stack as guard */ - target_mprotect(error + size, host_page_size, PROT_NONE); + target_mprotect(error + size, qemu_host_page_size, PROT_NONE); stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; p += stack_base; - if (bprm->loader) { - bprm->loader += stack_base; - } - bprm->exec += stack_base; - for (i = 0 ; i < MAX_ARG_PAGES ; i++) { if (bprm->page[i]) { info->rss++; - memcpy((void *)stack_base, (void *)bprm->page[i], TARGET_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 += TARGET_PAGE_SIZE; + stack_base += TARGET_PAGE_SIZE; } return p; } @@ -556,20 +553,22 @@ 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) +static void padzero(unsigned long elf_bss, unsigned long last_bss) { unsigned long nbyte; - char * fpnt; + + 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 (real_host_page_size < host_page_size) { + if (qemu_real_host_page_size < qemu_host_page_size) { unsigned long end_addr, end_addr1; - end_addr1 = (elf_bss + real_host_page_size - 1) & - ~(real_host_page_size - 1); + 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, @@ -578,59 +577,76 @@ static void padzero(unsigned long elf_bss) } } - nbyte = elf_bss & (host_page_size-1); + nbyte = elf_bss & (qemu_host_page_size-1); if (nbyte) { - nbyte = host_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 load_bias, - unsigned long interp_load_addr, int ibcs, - struct image_info *info) + +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 *argv, *envp; - target_ulong *sp, *csp; - + 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 = (unsigned int *) (~15UL & (unsigned long) p); - csp = sp; - csp -= (DLINFO_ITEMS + 1) * 2; + sp = sp &~ (target_ulong)15; + size = (DLINFO_ITEMS + 1) * 2; + if (k_platform) + size += 2; #ifdef DLINFO_ARCH_ITEMS - csp -= DLINFO_ARCH_ITEMS*2; + size += DLINFO_ARCH_ITEMS * 2; #endif - csp -= envc+1; - csp -= argc+1; - csp -= (!ibcs ? 3 : 1); /* argc itself */ - if ((unsigned long)csp & 15UL) - sp -= ((unsigned long)csp & 15UL) / sizeof(*sp); + size += envc + argc + 2; + size += (!ibcs ? 3 : 1); /* argc itself */ + size *= n; + if (size & 15) + sp -= 16 - (size & 15); -#define NEW_AUX_ENT(nr, id, val) \ - put_user (tswapl(id), sp + (nr * 2)); \ - put_user (tswapl(val), sp + (nr * 2 + 1)) - sp -= 2; - NEW_AUX_ENT (0, AT_NULL, 0); - - sp -= DLINFO_ITEMS*2; - NEW_AUX_ENT( 0, AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); - NEW_AUX_ENT( 1, AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); - NEW_AUX_ENT( 2, AT_PHNUM, (target_ulong)(exec->e_phnum)); - NEW_AUX_ENT( 3, AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE)); - NEW_AUX_ENT( 4, AT_BASE, (target_ulong)(interp_load_addr)); - NEW_AUX_ENT( 5, AT_FLAGS, (target_ulong)0); - NEW_AUX_ENT( 6, AT_ENTRY, load_bias + exec->e_entry); - NEW_AUX_ENT( 7, AT_UID, (target_ulong) getuid()); - NEW_AUX_ENT( 8, AT_EUID, (target_ulong) geteuid()); - NEW_AUX_ENT( 9, AT_GID, (target_ulong) getgid()); - NEW_AUX_ENT(11, AT_EGID, (target_ulong) getegid()); +#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 @@ -640,33 +656,11 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, #endif #undef NEW_AUX_ENT - 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); - } - 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) @@ -770,7 +764,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, interpreter_fd, eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); - if (error > -1024UL) { + if (error == -1) { /* Real error */ close(interpreter_fd); free(elf_phdata); @@ -807,8 +801,8 @@ 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 = TARGET_ELF_PAGESTART(elf_bss + host_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) { @@ -828,6 +822,7 @@ 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++) { @@ -853,28 +848,31 @@ static void load_symbols(struct elfhdr *hdr, int fd) found: /* Now know where the strtab and symtab are. Snarf them. */ - disas_symtab = malloc(symtab.sh_size); - disas_strtab = strings = malloc(strtab.sh_size); - if (!disas_symtab || !disas_strtab) + 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, disas_symtab, symtab.sh_size) != symtab.sh_size) + 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(disas_symtab + sizeof(struct elf_sym)*i); + bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i); #endif lseek(fd, strtab.sh_offset, SEEK_SET); if (read(fd, strings, strtab.sh_size) != strtab.sh_size) return; - disas_num_syms = symtab.sh_size / sizeof(struct elf_sym); + s->disas_num_syms = symtab.sh_size / sizeof(struct elf_sym); + s->next = syminfos; + syminfos = s; } -static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, - struct image_info * info) +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; @@ -906,17 +904,19 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r 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; } + 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) { @@ -1060,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++; } } @@ -1211,8 +1211,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r #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, &elf_ex, @@ -1220,11 +1219,10 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r 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; @@ -1232,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); @@ -1249,87 +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 = target_mmap(0, host_page_size, PROT_READ | PROT_EXEC, + 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 = TARGET_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 */ - init_thread(regs, infop); - return retval; - } - - /* Something went wrong, return the inode and free the argument pages*/ - for (i=0 ; i