diff options
author | pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162> | 2006-06-11 13:32:59 +0000 |
---|---|---|
committer | pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162> | 2006-06-11 13:32:59 +0000 |
commit | e5fe0c5230cc7780de852cefb5df57e05e2c613e (patch) | |
tree | e9336966c143de451ee699c37714200ce9f96079 /linux-user/elfload.c | |
parent | ac62f715c6b8bde0fc4cfb0bed8e4f12ad4b5503 (diff) |
bFLT loader (for uClinux binaries).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1951 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'linux-user/elfload.c')
-rw-r--r-- | linux-user/elfload.c | 310 |
1 files changed, 45 insertions, 265 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 98c6e3f85c..687ff77b4d 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -3,7 +3,6 @@ #include <stdio.h> #include <sys/types.h> #include <fcntl.h> -#include <sys/stat.h> #include <errno.h> #include <unistd.h> #include <sys/mman.h> @@ -59,19 +58,19 @@ static uint32_t get_elf_hwcap(void) #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 @@ -93,8 +92,6 @@ 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 = infop->start_stack; @@ -107,7 +104,9 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i 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 = tgetl(stack); /* argc */ + regs->ARM_r0 = 0; + /* For uClinux PIC binaries. */ + regs->ARM_r10 = infop->start_data; } #define USE_ELF_CORE_DUMP @@ -142,9 +141,6 @@ enum #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->tstate = 0; @@ -163,9 +159,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #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; @@ -192,20 +185,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 { \ - target_ulong *pos = (target_ulong *)bprm->p, tmp = 1; \ - _r->gpr[3] = bprm->argc; \ - _r->gpr[4] = (unsigned long)++pos; \ - for (; tmp != 0; pos++) \ - tmp = ldl(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. @@ -239,9 +218,22 @@ do { \ 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 @@ -263,8 +255,6 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * #endif #define ELF_ARCH EM_MIPS -#define ELF_PLAT_INIT(_r) - static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { regs->cp0_status = CP0St_UM; @@ -284,8 +274,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_DATA ELFDATA2LSB #define ELF_ARCH EM_SH -#define ELF_PLAT_INIT(_r) /* XXXXX */ - static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { /* Check other registers XXXXX */ @@ -308,30 +296,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #include "elf.h" -/* - * 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 - -/* - * This structure is used to hold the arguments that are - * used when loading binaries. - */ -struct linux_binprm { - char buf[128]; - void *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 */ -}; - struct exec { unsigned int a_info; /* Use macros N_MAGIC, etc for access */ @@ -377,8 +341,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)) @@ -452,13 +414,13 @@ static void bswap_sym(Elf32_Sym *sym) #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, void **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; @@ -506,101 +468,6 @@ static unsigned long copy_strings(int argc,char ** argv, void **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); - } -} - -static inline void memcpy_to_target(target_ulong dest, const void *src, - unsigned long len) -{ - void *host_ptr; - - host_ptr = lock_user(dest, len, 0); - memcpy(host_ptr, src, len); - unlock_user(host_ptr, dest, 1); -} - unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm, struct image_info * info) { @@ -628,11 +495,6 @@ unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm, 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++; @@ -703,7 +565,6 @@ static unsigned long create_elf_tables(target_ulong p, int argc, int envc, unsigned long interp_load_addr, int ibcs, struct image_info *info) { - target_ulong argv, envp; target_ulong sp; int size; target_ulong u_platform; @@ -765,28 +626,7 @@ static unsigned long create_elf_tables(target_ulong p, int argc, int envc, #endif #undef NEW_AUX_ENT - sp -= (envc + 1) * n; - envp = sp; - sp -= (argc + 1) * n; - argv = sp; - if (!ibcs) { - sp -= n; tputl(sp, envp); - sp -= n; tputl(sp, argv); - } - sp -= n; tputl(sp, argc); - info->arg_start = p; - while (argc-->0) { - tputl(argv, p); argv += n; - p += target_strlen(p) + 1; - } - tputl(argv, 0); - info->arg_end = info->env_start = p; - while (envc-->0) { - tputl(envp, p); envp += n; - p += target_strlen(p) + 1; - } - tputl(envp, 0); - info->env_end = p; + sp = loader_build_argptr(envc, argc, sp, p, !ibcs); return sp; } @@ -1001,8 +841,8 @@ static void load_symbols(struct elfhdr *hdr, int fd) 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; @@ -1034,17 +874,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) { @@ -1188,7 +1030,7 @@ 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) { @@ -1196,7 +1038,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r 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++; } } @@ -1347,11 +1189,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; @@ -1380,79 +1221,18 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r 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<MAX_ARG_PAGES ; i++) /* clear page-table */ - bprm.page[i] = 0; - retval = open(filename, O_RDONLY); - if (retval < 0) - return retval; - bprm.fd = retval; - bprm.filename = (char *)filename; - bprm.sh_bang = 0; - bprm.loader = 0; - bprm.exec = 0; - bprm.dont_iput = 0; - bprm.argc = count(argv); - bprm.envc = count(envp); - - retval = prepare_binprm(&bprm); - - if(retval>=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<MAX_ARG_PAGES ; i++) { - free(bprm.page[i]); - } - return(retval); -} - - static int load_aout_interp(void * exptr, int interp_fd) { printf("a.out interpreter not yet supported\n"); return(0); } +void do_init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + init_thread(regs, infop); +} |