Index: qemu/linux-user/elfload.c =================================================================== --- qemu.orig/linux-user/elfload.c 2007-10-07 08:49:55.000000000 +0000 +++ qemu/linux-user/elfload.c 2007-10-07 12:17:56.000000000 +0000 @@ -48,7 +48,6 @@ #define ELF_START_MMAP 0x2aaaaab000ULL #define elf_check_arch(x) ( ((x) == ELF_ARCH) ) -#define ELF_CLASS ELFCLASS64 #define ELF_DATA ELFDATA2LSB #define ELF_ARCH EM_X86_64 @@ -71,7 +70,6 @@ /* * These are used to set parameters in the core dumps. */ -#define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2LSB #define ELF_ARCH EM_386 @@ -102,7 +100,6 @@ #define elf_check_arch(x) ( (x) == EM_ARM ) -#define ELF_CLASS ELFCLASS32 #ifdef TARGET_WORDS_BIGENDIAN #define ELF_DATA ELFDATA2MSB #else @@ -153,9 +150,8 @@ #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_SPARCV9 ) +#define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS ) -#define ELF_CLASS ELFCLASS64 #define ELF_DATA ELFDATA2MSB #define ELF_ARCH EM_SPARCV9 @@ -167,7 +163,10 @@ regs->pc = infop->entry; regs->npc = regs->pc + 4; regs->y = 0; - regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS; + if (infop->is_64bits) + regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS; + else + regs->u_regs[14] = infop->start_stack - 16 * 4; } #else @@ -175,7 +174,6 @@ #define elf_check_arch(x) ( (x) == EM_SPARC ) -#define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2MSB #define ELF_ARCH EM_SPARC @@ -199,14 +197,10 @@ #define elf_check_arch(x) ( (x) == EM_PPC64 ) -#define ELF_CLASS ELFCLASS64 - #else #define elf_check_arch(x) ( (x) == EM_PPC ) -#define ELF_CLASS ELFCLASS32 - #endif #ifdef TARGET_WORDS_BIGENDIAN @@ -287,11 +281,6 @@ #define elf_check_arch(x) ( (x) == EM_MIPS ) -#ifdef TARGET_MIPS64 -#define ELF_CLASS ELFCLASS64 -#else -#define ELF_CLASS ELFCLASS32 -#endif #ifdef TARGET_WORDS_BIGENDIAN #define ELF_DATA ELFDATA2MSB #else @@ -317,7 +306,6 @@ #define elf_check_arch(x) ( (x) == EM_SH ) -#define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2LSB #define ELF_ARCH EM_SH @@ -339,7 +327,6 @@ #define elf_check_arch(x) ( (x) == EM_68K ) -#define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2MSB #define ELF_ARCH EM_68K @@ -364,7 +351,6 @@ #define elf_check_arch(x) ( (x) == ELF_ARCH ) -#define ELF_CLASS ELFCLASS64 #define ELF_DATA ELFDATA2MSB #define ELF_ARCH EM_ALPHA @@ -391,6 +377,7 @@ #define ELF_HWCAP 0 #endif +#define ELF_CLASS ELFCLASS32 #include "elf.h" struct exec @@ -457,59 +444,6 @@ static int load_aout_interp(void * exptr, int interp_fd); -#ifdef BSWAP_NEEDED -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 */ - 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 */ - bswap16s(&ehdr->e_phnum); /* Program header table entry count */ - bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ - bswap16s(&ehdr->e_shnum); /* Section header table entry count */ - bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ -} - -static void bswap_phdr(struct elf_phdr *phdr) -{ - bswap32s(&phdr->p_type); /* Segment type */ - 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 */ - bswaptls(&phdr->p_align); /* Segment alignment */ -} - -static void bswap_shdr(struct elf_shdr *shdr) -{ - 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 bswap_sym(struct elf_sym *sym) -{ - bswap32s(&sym->st_name); - bswaptls(&sym->st_value); - bswaptls(&sym->st_size); - bswap16s(&sym->st_shndx); -} -#endif - /* * 'copy_elf_strings()' copies argument/envelope strings from user * memory to free pages in kernel mem. These are in a format ready @@ -566,8 +500,8 @@ return p; } -unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm, - struct image_info * info) +static unsigned long setup_arg_pages(target_ulong p, struct linux_binprm *bprm, + struct image_info * info) { target_ulong stack_base, size, error; int i; @@ -658,700 +592,52 @@ } } - -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 - - 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 = 0; - int load_addr_set = 0; - int retval; - unsigned long last_bss, elf_bss; - unsigned long error; - int i; - - elf_bss = 0; - last_bss = 0; - error = 0; - -#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) || - !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 > TARGET_PAGE_SIZE) - return ~0UL; - - elf_phdata = (struct elf_phdr *) - malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); - - if (!elf_phdata) - return ~0UL; - - /* - * 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)) { - free(elf_phdata); - return ~0UL; - } - - retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); - if(retval >= 0) { - retval = read(interpreter_fd, - (char *) elf_phdata, - sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); - } - if (retval < 0) { - perror("load_elf_interp"); - exit(-1); - free (elf_phdata); - return retval; - } -#ifdef BSWAP_NEEDED - eppnt = elf_phdata; - for (i=0; ie_phnum; i++, eppnt++) { - bswap_phdr(eppnt); - } -#endif - - if (interp_elf_ex->e_type == ET_DYN) { - /* in order to avoid hardcoding 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) { - int elf_type = MAP_PRIVATE | MAP_DENYWRITE; - int elf_prot = 0; - unsigned long vaddr = 0; - unsigned long k; - - if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; - if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; - if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; - if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { - elf_type |= MAP_FIXED; - vaddr = 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 - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); - - if (error == -1) { - /* Real error */ - close(interpreter_fd); - free(elf_phdata); - return ~0UL; - } - - if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { - load_addr = error; - load_addr_set = 1; - } - - /* - * Find the end of the file mapping for this phdr, and keep - * track of the largest address we see for this. - */ - k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; - if (k > elf_bss) elf_bss = k; - - /* - * Do the same thing for the memory mapping - between - * elf_bss and last_bss is the bss section. - */ - k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; - if (k > last_bss) last_bss = k; - } - - /* Now use mmap to map the library into memory. */ - - close(interpreter_fd); - - /* - * Now fill out the bss section. First pad the last page up - * to the page boundary, and then perform a mmap to make sure - * that there are zeromapped pages up to and including the last - * bss page. - */ - 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) { - 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); - - *interp_load_addr = load_addr; - 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; -#if (ELF_CLASS == ELFCLASS64) - // Disas uses 32 bit symbols - struct elf32_sym *syms32 = NULL; - struct elf_sym *sym; -#endif - - 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); -#if (ELF_CLASS == ELFCLASS64) - syms32 = malloc(symtab.sh_size / sizeof(struct elf_sym) - * sizeof(struct elf32_sym)); -#endif - 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; - - for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) { -#ifdef BSWAP_NEEDED - bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i); -#endif -#if (ELF_CLASS == ELFCLASS64) - sym = s->disas_symtab + sizeof(struct elf_sym)*i; - syms32[i].st_name = sym->st_name; - syms32[i].st_info = sym->st_info; - syms32[i].st_other = sym->st_other; - syms32[i].st_shndx = sym->st_shndx; - syms32[i].st_value = sym->st_value & 0xffffffff; - syms32[i].st_size = sym->st_size & 0xffffffff; -#endif - } - -#if (ELF_CLASS == ELFCLASS64) - free(s->disas_symtab); - s->disas_symtab = syms32; -#endif - 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; -} +#ifndef glue +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) +#define stringify(s) tostring(s) +#define tostring(s) #s +#endif + +#define elf_word uint32_t +#define bswapSZs bswap32s +#define SZ 32 +#include "elfload_ops.h" + +#undef elfhdr +#undef elf_phdr +#undef elf_shdr +#undef elf_sym +#undef elf_note +#undef elf_word +#undef bswapSZs +#undef SZ +#define elfhdr elf64_hdr +#define elf_phdr elf64_phdr +#define elf_shdr elf64_shdr +#define elf_sym elf64_sym +#define elf_note elf64_note +#define elf_word uint64_t +#define bswapSZs bswap64s +#define SZ 64 +#include "elfload_ops.h" 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, load_bias; - int load_addr_set = 0; - unsigned int interpreter_type = INTERPRETER_NONE; - unsigned char ibcs2_interpreter; - int i; - unsigned long mapped_addr; - struct elf_phdr * elf_ppnt; - struct elf_phdr *elf_phdata; - unsigned long elf_bss, k, elf_brk; + struct elfhdr *elf_ex; int retval; - char * elf_interpreter; - unsigned long 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; - char passed_fileno[6]; - - 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 - - /* 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) { - return -ENOMEM; + elf_ex = (struct elfhdr *) bprm->buf; /* exec-header */ + if (elf_ex->e_ident[EI_CLASS] == ELFCLASS64) { + info->is_64bits = 1; + retval = load_elf_binary64(bprm, regs, info); + } else { + info->is_64bits = 0; + retval = load_elf_binary32(bprm, regs, info); } - retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); - if(retval > 0) { - retval = read(bprm->fd, (char *) elf_phdata, - elf_ex.e_phentsize * elf_ex.e_phnum); - } - - if (retval < 0) { - perror("load_elf_binary"); - exit(-1); - free (elf_phdata); - return -errno; - } - -#ifdef BSWAP_NEEDED - elf_ppnt = elf_phdata; - for (i=0; ip_type == PT_INTERP) { - if ( elf_interpreter != NULL ) - { - free (elf_phdata); - free(elf_interpreter); - close(bprm->fd); - return -EINVAL; - } - - /* This is the program interpreter used for - * shared libraries - for now assume that this - * is an a.out format binary - */ - - elf_interpreter = (char *)malloc(elf_ppnt->p_filesz); - - if (elf_interpreter == NULL) { - free (elf_phdata); - close(bprm->fd); - return -ENOMEM; - } - - retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); - if(retval >= 0) { - retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz); - } - if(retval < 0) { - perror("load_elf_binary2"); - exit(-1); - } - - /* If the program interpreter is one of these two, - then assume an iBCS2 image. Otherwise assume - a native linux image. */ - - /* JRP - Need to add X86 lib dir stuff here... */ - - if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || - strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) { - ibcs2_interpreter = 1; - } - -#if 0 - printf("Using ELF interpreter %s\n", elf_interpreter); -#endif - if (retval >= 0) { - retval = open(path(elf_interpreter), O_RDONLY); - if(retval >= 0) { - interpreter_fd = retval; - } - else { - perror(elf_interpreter); - exit(-1); - /* retval = -errno; */ - } - } - - if (retval >= 0) { - retval = lseek(interpreter_fd, 0, SEEK_SET); - if(retval >= 0) { - retval = read(interpreter_fd,bprm->buf,128); - } - } - if (retval >= 0) { - interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */ - interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */ - } - if (retval < 0) { - perror("load_elf_binary3"); - exit(-1); - free (elf_phdata); - free(elf_interpreter); - close(bprm->fd); - return retval; - } - } - elf_ppnt++; - } - - /* Some simple consistency checks for the interpreter */ - if (elf_interpreter){ - interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; - - /* Now figure out which format our binary is */ - if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && - (N_MAGIC(interp_ex) != QMAGIC)) { - interpreter_type = INTERPRETER_ELF; - } - - if (interp_elf_ex.e_ident[0] != 0x7f || - strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) { - interpreter_type &= ~INTERPRETER_ELF; - } - - if (!interpreter_type) { - free(elf_interpreter); - free(elf_phdata); - close(bprm->fd); - return -ELIBBAD; - } - } - - /* OK, we are done with that, now set up the arg stuff, - and then start this sucker up */ - - { - char * passed_p; - - if (interpreter_type == INTERPRETER_AOUT) { - snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd); - passed_p = passed_fileno; - - if (elf_interpreter) { - bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p); - bprm->argc++; - } - } - if (!bprm->p) { - if (elf_interpreter) { - free(elf_interpreter); - } - free (elf_phdata); - close(bprm->fd); - return -E2BIG; - } - } - - /* 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->mmap = 0; - elf_entry = (unsigned long) elf_ex.e_entry; - - /* Do this so that we can load the interpreter, if need be. We will - change some of these later */ - info->rss = 0; - bprm->p = setup_arg_pages(bprm->p, bprm, info); - info->start_stack = bprm->p; - - /* Now we do a little grungy work by mmaping the ELF image into - * the correct location in memory. At this point, we assume that - * the image should be loaded at fixed address, not at a variable - * address. - */ - - 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; - - 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 hardcoding 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 (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) - elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr); -#endif - - 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; - reloc_func_desc = 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); - } - else if (interpreter_type & 2) { - elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, - &interp_load_addr); - } - reloc_func_desc = interp_load_addr; - - close(interpreter_fd); - free(elf_interpreter); - - if (elf_entry == ~0UL) { - printf("Unable to load interpreter\n"); - free(elf_phdata); - exit(-1); - return 0; - } - } - - 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 = create_elf_tables(bprm->p, - bprm->argc, - bprm->envc, - &elf_ex, - load_addr, load_bias, - interp_load_addr, - (interpreter_type == INTERPRETER_AOUT ? 0 : 1), - info); - info->load_addr = reloc_func_desc; - 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; - - /* Calling set_brk effectively mmaps the pages that we need for the bss and break - sections */ - set_brk(elf_bss, elf_brk); - - padzero(elf_bss, elf_brk); - -#if 0 - printf("(start_brk) %x\n" , info->start_brk); - printf("(end_code) %x\n" , info->end_code); - printf("(start_code) %x\n" , info->start_code); - printf("(end_data) %x\n" , info->end_data); - printf("(start_stack) %x\n" , info->start_stack); - printf("(brk) %x\n" , info->brk); -#endif - - if ( info->personality == PER_SVR4 ) - { - /* Why this, you ask??? Well SVr4 maps page 0 as read-only, - 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, qemu_host_page_size, PROT_READ | PROT_EXEC, - MAP_FIXED | MAP_PRIVATE, -1, 0); - } - - info->entry = elf_entry; - - return 0; + return retval; } static int load_aout_interp(void * exptr, int interp_fd) Index: qemu/linux-user/elfload_ops.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ qemu/linux-user/elfload_ops.h 2007-10-07 11:44:09.000000000 +0000 @@ -0,0 +1,749 @@ +#ifdef BSWAP_NEEDED +static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr) +{ + bswap16s(&ehdr->e_type); /* Object file type */ + bswap16s(&ehdr->e_machine); /* Architecture */ + bswap32s(&ehdr->e_version); /* Object file version */ + bswapSZs(&ehdr->e_entry); /* Entry point virtual address */ + bswapSZs(&ehdr->e_phoff); /* Program header table file offset */ + bswapSZs(&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 */ + bswap16s(&ehdr->e_phnum); /* Program header table entry count */ + bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ + bswap16s(&ehdr->e_shnum); /* Section header table entry count */ + bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ +} + +static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr) +{ + bswap32s(&phdr->p_type); /* Segment type */ + bswapSZs(&phdr->p_offset); /* Segment file offset */ + bswapSZs(&phdr->p_vaddr); /* Segment virtual address */ + bswapSZs(&phdr->p_paddr); /* Segment physical address */ + bswapSZs(&phdr->p_filesz); /* Segment size in file */ + bswapSZs(&phdr->p_memsz); /* Segment size in memory */ + bswap32s(&phdr->p_flags); /* Segment flags */ + bswapSZs(&phdr->p_align); /* Segment alignment */ +} + +static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr) +{ + bswap32s(&shdr->sh_name); + bswap32s(&shdr->sh_type); + bswapSZs(&shdr->sh_flags); + bswapSZs(&shdr->sh_addr); + bswapSZs(&shdr->sh_offset); + bswapSZs(&shdr->sh_size); + bswap32s(&shdr->sh_link); + bswap32s(&shdr->sh_info); + bswapSZs(&shdr->sh_addralign); + bswapSZs(&shdr->sh_entsize); +} + +static void glue(bswap_sym, SZ)(struct elf_sym *sym) +{ + bswap32s(&sym->st_name); + bswapSZs(&sym->st_value); + bswapSZs(&sym->st_size); + bswap16s(&sym->st_shndx); +} +#endif + +static unsigned long glue(create_elf_tables, SZ)(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 + + sp = loader_build_argptr(envc, argc, sp, p, !ibcs); + return sp; +} + +static unsigned long glue(load_elf_interp, SZ)(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 = 0; + int load_addr_set = 0; + int retval; + unsigned long last_bss, elf_bss; + unsigned long error; + int i; + + elf_bss = 0; + last_bss = 0; + error = 0; + +#ifdef BSWAP_NEEDED + glue(bswap_ehdr, SZ)(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) || + !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 > TARGET_PAGE_SIZE) + return ~0UL; + + elf_phdata = (struct elf_phdr *) + malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); + + if (!elf_phdata) + return ~0UL; + + /* + * 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)) { + free(elf_phdata); + return ~0UL; + } + + retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); + if (retval >= 0) { + retval = read(interpreter_fd, + (char *) elf_phdata, + sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); + } + if (retval < 0) { + perror("load_elf_interp"); + exit(-1); + free (elf_phdata); + return retval; + } +#ifdef BSWAP_NEEDED + eppnt = elf_phdata; + for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) { + glue(bswap_phdr, SZ)(eppnt); + } +#endif + + if (interp_elf_ex->e_type == ET_DYN) { + /* in order to avoid hardcoding 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; i < interp_elf_ex->e_phnum; i++, eppnt++) + if (eppnt->p_type == PT_LOAD) { + int elf_type = MAP_PRIVATE | MAP_DENYWRITE; + int elf_prot = 0; + unsigned long vaddr = 0; + unsigned long k; + + if (eppnt->p_flags & PF_R) + elf_prot = PROT_READ; + if (eppnt->p_flags & PF_W) + elf_prot |= PROT_WRITE; + if (eppnt->p_flags & PF_X) + elf_prot |= PROT_EXEC; + if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { + elf_type |= MAP_FIXED; + vaddr = 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 - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); + + if (error == -1) { + /* Real error */ + close(interpreter_fd); + free(elf_phdata); + return ~0UL; + } + + if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { + load_addr = error; + load_addr_set = 1; + } + + /* + * Find the end of the file mapping for this phdr, and keep + * track of the largest address we see for this. + */ + k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; + if (k > elf_bss) + elf_bss = k; + + /* + * Do the same thing for the memory mapping - between + * elf_bss and last_bss is the bss section. + */ + k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; + if (k > last_bss) + last_bss = k; + } + + /* Now use mmap to map the library into memory. */ + + close(interpreter_fd); + + /* + * Now fill out the bss section. First pad the last page up + * to the page boundary, and then perform a mmap to make sure + * that there are zeromapped pages up to and including the last + * bss page. + */ + padzero(elf_bss, last_bss); + /* What we have mapped so far */ + elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); + + /* Map the last of the bss segment */ + if (last_bss > elf_bss) { + 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); + + *interp_load_addr = load_addr; + return ((unsigned long)interp_elf_ex->e_entry) + load_addr; +} + +/* Best attempt to load symbols from this ELF object. */ +static void glue(load_symbols, SZ)(struct elfhdr *hdr, int fd) +{ + unsigned int i; + struct elf_shdr sechdr, symtab, strtab; + char *strings; + struct syminfo *s; +#if (ELF_CLASS == ELFCLASS64) + // Disas uses 32 bit symbols + struct elf32_sym *syms32 = NULL; + struct elf_sym *sym; +#endif + + 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 + glue(bswap_shdr, SZ)(&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 + glue(bswap_shdr, SZ)(&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); +#if (ELF_CLASS == ELFCLASS64) + syms32 = malloc(symtab.sh_size / sizeof(struct elf_sym) + * sizeof(struct elf32_sym)); +#endif + 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; + + for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) { +#ifdef BSWAP_NEEDED + glue(bswap_sym, SZ)(s->disas_symtab + sizeof(struct elf_sym)*i); +#endif +#if (ELF_CLASS == ELFCLASS64) + sym = s->disas_symtab + sizeof(struct elf_sym)*i; + syms32[i].st_name = sym->st_name; + syms32[i].st_info = sym->st_info; + syms32[i].st_other = sym->st_other; + syms32[i].st_shndx = sym->st_shndx; + syms32[i].st_value = sym->st_value & 0xffffffff; + syms32[i].st_size = sym->st_size & 0xffffffff; +#endif + } + +#if (ELF_CLASS == ELFCLASS64) + free(s->disas_symtab); + s->disas_symtab = syms32; +#endif + 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; +} + +static int glue(load_elf_binary, SZ)(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, load_bias; + int load_addr_set = 0; + unsigned int interpreter_type = INTERPRETER_NONE; + unsigned char ibcs2_interpreter; + int i; + unsigned long mapped_addr; + struct elf_phdr * elf_ppnt; + struct elf_phdr *elf_phdata; + unsigned long elf_bss, k, elf_brk; + int retval; + char * elf_interpreter; + unsigned long 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; + char passed_fileno[6]; + + ibcs2_interpreter = 0; + status = 0; + load_addr = 0; + load_bias = 0; + elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ +#ifdef BSWAP_NEEDED + glue(bswap_ehdr, SZ)(&elf_ex); +#endif + + /* 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) { + return -ENOMEM; + } + + retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); + if (retval > 0) { + retval = read(bprm->fd, (char *)elf_phdata, + elf_ex.e_phentsize * elf_ex.e_phnum); + } + + if (retval < 0) { + perror("load_elf_binary"); + exit(-1); + } + +#ifdef BSWAP_NEEDED + elf_ppnt = elf_phdata; + for (i = 0; i < elf_ex.e_phnum; i++, elf_ppnt++) { + glue(bswap_phdr, SZ)(elf_ppnt); + } +#endif + elf_ppnt = elf_phdata; + + elf_bss = 0; + elf_brk = 0; + + + elf_stack = ~0UL; + elf_interpreter = NULL; + start_code = ~0UL; + end_code = 0; + end_data = 0; + + for (i = 0; i < elf_ex.e_phnum; i++) { + if (elf_ppnt->p_type == PT_INTERP) { + if (elf_interpreter != NULL) { + free (elf_phdata); + free(elf_interpreter); + close(bprm->fd); + return -EINVAL; + } + + /* This is the program interpreter used for + * shared libraries - for now assume that this + * is an a.out format binary + */ + elf_interpreter = (char *)malloc(elf_ppnt->p_filesz); + + if (elf_interpreter == NULL) { + free (elf_phdata); + close(bprm->fd); + return -ENOMEM; + } + + retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); + if (retval >= 0) { + retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz); + } + if (retval < 0) { + perror("load_elf_binary2"); + exit(-1); + } + + /* If the program interpreter is one of these two, + then assume an iBCS2 image. Otherwise assume + a native linux image. */ + + /* JRP - Need to add X86 lib dir stuff here... */ + + if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0 || + strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) { + ibcs2_interpreter = 1; + } + +#if 0 + printf("Using ELF interpreter %s\n", elf_interpreter); +#endif + if (retval >= 0) { + retval = open(path(elf_interpreter), O_RDONLY); + if (retval >= 0) { + interpreter_fd = retval; + } else { + perror(elf_interpreter); + exit(-1); + } + } + + if (retval >= 0) { + retval = lseek(interpreter_fd, 0, SEEK_SET); + if (retval >= 0) { + retval = read(interpreter_fd, bprm->buf, 128); + } + } + if (retval >= 0) { + interp_ex = *((struct exec *)bprm->buf); /* aout exec-header */ + interp_elf_ex = *((struct elfhdr *)bprm->buf); /* elf exec-header */ + } + if (retval < 0) { + perror("load_elf_binary3"); + exit(-1); + } + } + elf_ppnt++; + } + + /* Some simple consistency checks for the interpreter */ + if (elf_interpreter) { + interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; + + /* Now figure out which format our binary is */ + if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && + (N_MAGIC(interp_ex) != QMAGIC)) { + interpreter_type = INTERPRETER_ELF; + } + + if (interp_elf_ex.e_ident[0] != 0x7f || + strncmp(&interp_elf_ex.e_ident[1], "ELF", 3) != 0) { + interpreter_type &= ~INTERPRETER_ELF; + } + + if (!interpreter_type) { + free(elf_interpreter); + free(elf_phdata); + close(bprm->fd); + return -ELIBBAD; + } + } + + /* OK, we are done with that, now set up the arg stuff, + and then start this sucker up */ + + { + char *passed_p; + + if (interpreter_type == INTERPRETER_AOUT) { + snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd); + passed_p = passed_fileno; + + if (elf_interpreter) { + bprm->p = copy_elf_strings(1, &passed_p, bprm->page, bprm->p); + bprm->argc++; + } + } + if (!bprm->p) { + if (elf_interpreter) { + free(elf_interpreter); + } + free (elf_phdata); + close(bprm->fd); + return -E2BIG; + } + } + + /* 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->mmap = 0; + elf_entry = (unsigned long) elf_ex.e_entry; + + /* Do this so that we can load the interpreter, if need be. We will + change some of these later */ + info->rss = 0; + bprm->p = setup_arg_pages(bprm->p, bprm, info); + info->start_stack = bprm->p; + + /* Now we do a little grungy work by mmaping the ELF image into + * the correct location in memory. At this point, we assume that + * the image should be loaded at fixed address, not at a variable + * address. + */ + + 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; + + 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 hardcoding 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 (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) + elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr); +#endif + + 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; + reloc_func_desc = 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); + } + else if (interpreter_type & 2) { + elf_entry = glue(load_elf_interp, SZ)(&interp_elf_ex, interpreter_fd, + &interp_load_addr); + } + reloc_func_desc = interp_load_addr; + + close(interpreter_fd); + free(elf_interpreter); + + if (elf_entry == ~0UL) { + printf("Unable to load interpreter\n"); + free(elf_phdata); + exit(-1); + } + } + + free(elf_phdata); + + if (loglevel) + glue(load_symbols, SZ)(&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 = glue(create_elf_tables, SZ)(bprm->p, + bprm->argc, + bprm->envc, + &elf_ex, + load_addr, load_bias, + interp_load_addr, + (interpreter_type == + INTERPRETER_AOUT ? 0 : 1), + info); + info->load_addr = reloc_func_desc; + 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; + + /* Calling set_brk effectively mmaps the pages that we need for the bss and break + sections */ + set_brk(elf_bss, elf_brk); + + padzero(elf_bss, elf_brk); + +#if 0 + printf("(start_brk) %x\n" , info->start_brk); + printf("(end_code) %x\n" , info->end_code); + printf("(start_code) %x\n" , info->start_code); + printf("(end_data) %x\n" , info->end_data); + printf("(start_stack) %x\n" , info->start_stack); + printf("(brk) %x\n" , info->brk); +#endif + + if (info->personality == PER_SVR4) { + /* Why this, you ask??? Well SVr4 maps page 0 as read-only, + 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, qemu_host_page_size, PROT_READ | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, -1, 0); + } + + info->entry = elf_entry; + + return 0; +} Index: qemu/linux-user/main.c =================================================================== --- qemu.orig/linux-user/main.c 2007-10-07 10:55:45.000000000 +0000 +++ qemu/linux-user/main.c 2007-10-07 10:55:54.000000000 +0000 @@ -564,6 +564,7 @@ case 0x88: case 0x90: #else + case 0x110: case 0x16d: #endif ret = do_syscall (env, env->gregs[1], Index: qemu/linux-user/qemu.h =================================================================== --- qemu.orig/linux-user/qemu.h 2007-10-07 10:50:05.000000000 +0000 +++ qemu/linux-user/qemu.h 2007-10-07 10:51:09.000000000 +0000 @@ -33,6 +33,7 @@ target_ulong data_offset; char **host_argv; int personality; + int is_64bits; }; #ifdef TARGET_I386 Index: qemu/linux-user/sparc64/syscall_nr.h =================================================================== --- qemu.orig/linux-user/sparc64/syscall_nr.h 2007-10-07 11:01:06.000000000 +0000 +++ qemu/linux-user/sparc64/syscall_nr.h 2007-10-07 11:11:58.000000000 +0000 @@ -29,11 +29,11 @@ #define TARGET_NR_sigaltstack 28 /* Common */ #define TARGET_NR_pause 29 /* Is sigblock(0)->sigpause() in SunOS */ #define TARGET_NR_utime 30 /* Implemented via utimes() under SunOS */ -/* #define TARGET_NR_lchown32 31 Linux sparc32 specific */ -/* #define TARGET_NR_fchown32 32 Linux sparc32 specific */ +#define TARGET_NR_lchown32 31 /* Linux sparc32 specific */ +#define TARGET_NR_fchown32 32 /* Linux sparc32 specific */ #define TARGET_NR_access 33 /* Common */ #define TARGET_NR_nice 34 /* Implemented via get/setpriority() in SunOS */ -/* #define TARGET_NR_chown32 35 Linux sparc32 specific */ +#define TARGET_NR_chown32 35 /* Linux sparc32 specific */ #define TARGET_NR_sync 36 /* Common */ #define TARGET_NR_kill 37 /* Common */ #define TARGET_NR_stat 38 /* Common */ @@ -42,7 +42,7 @@ #define TARGET_NR_dup 41 /* Common */ #define TARGET_NR_pipe 42 /* Common */ #define TARGET_NR_times 43 /* Implemented via getrusage() in SunOS */ -/* #define TARGET_NR_getuid32 44 Linux sparc32 specific */ +#define TARGET_NR_getuid32 44 /* Linux sparc32 specific */ #define TARGET_NR_umount2 45 /* Linux Specific */ #define TARGET_NR_setgid 46 /* Implemented via setregid() in SunOS */ #define TARGET_NR_getgid 47 /* Common */ @@ -51,48 +51,48 @@ #define TARGET_NR_getegid 50 /* SunOS calls getgid() */ #define TARGET_NR_acct 51 /* Common */ #define TARGET_NR_memory_ordering 52 /* Linux Specific */ -/* #define TARGET_NR_getgid32 53 Linux sparc32 specific */ +#define TARGET_NR_getgid32 53 /* Linux sparc32 specific */ #define TARGET_NR_ioctl 54 /* Common */ #define TARGET_NR_reboot 55 /* Common */ -/* #define TARGET_NR_mmap2 56 Linux sparc32 Specific */ +#define TARGET_NR_mmap2 56 /* Linux sparc32 Specific */ #define TARGET_NR_symlink 57 /* Common */ #define TARGET_NR_readlink 58 /* Common */ #define TARGET_NR_execve 59 /* Common */ #define TARGET_NR_umask 60 /* Common */ #define TARGET_NR_chroot 61 /* Common */ #define TARGET_NR_fstat 62 /* Common */ -/* #define TARGET_NR_fstat64 63 Linux sparc32 Specific */ +#define TARGET_NR_fstat64 63 /* Linux sparc32 Specific */ #define TARGET_NR_getpagesize 64 /* Common */ #define TARGET_NR_msync 65 /* Common in newer 1.3.x revs... */ #define TARGET_NR_vfork 66 /* Common */ #define TARGET_NR_pread64 67 /* Linux Specific */ #define TARGET_NR_pwrite64 68 /* Linux Specific */ -/* #define TARGET_NR_geteuid32 69 Linux sparc32, sbrk under SunOS */ -/* #define TARGET_NR_getegid32 70 Linux sparc32, sstk under SunOS */ +#define TARGET_NR_geteuid32 69 /* Linux sparc32, sbrk under SunOS */ +#define TARGET_NR_getegid32 70 /* Linux sparc32, sstk under SunOS */ #define TARGET_NR_mmap 71 /* Common */ -/* #define TARGET_NR_setreuid32 72 Linux sparc32, vadvise under SunOS */ +#define TARGET_NR_setreuid32 72 /* Linux sparc32, vadvise under SunOS */ #define TARGET_NR_munmap 73 /* Common */ #define TARGET_NR_mprotect 74 /* Common */ #define TARGET_NR_madvise 75 /* Common */ #define TARGET_NR_vhangup 76 /* Common */ -/* #define TARGET_NR_truncate64 77 Linux sparc32 Specific */ +#define TARGET_NR_truncate64 77 /* Linux sparc32 Specific */ #define TARGET_NR_mincore 78 /* Common */ #define TARGET_NR_getgroups 79 /* Common */ #define TARGET_NR_setgroups 80 /* Common */ #define TARGET_NR_getpgrp 81 /* Common */ -/* #define TARGET_NR_setgroups32 82 Linux sparc32, setpgrp under SunOS */ +#define TARGET_NR_setgroups32 82 /* Linux sparc32, setpgrp under SunOS */ #define TARGET_NR_setitimer 83 /* Common */ -/* #define TARGET_NR_ftruncate64 84 Linux sparc32 Specific */ +#define TARGET_NR_ftruncate64 84 /* Linux sparc32 Specific */ #define TARGET_NR_swapon 85 /* Common */ #define TARGET_NR_getitimer 86 /* Common */ -/* #define TARGET_NR_setuid32 87 Linux sparc32, gethostname under SunOS */ +#define TARGET_NR_setuid32 87 /* Linux sparc32, gethostname under SunOS */ #define TARGET_NR_sethostname 88 /* Common */ -/* #define TARGET_NR_setgid32 89 Linux sparc32, getdtablesize under SunOS */ +#define TARGET_NR_setgid32 89 /* Linux sparc32, getdtablesize under SunOS */ #define TARGET_NR_dup2 90 /* Common */ -/* #define TARGET_NR_setfsuid32 91 Linux sparc32, getdopt under SunOS */ +#define TARGET_NR_setfsuid32 91 /* Linux sparc32, getdopt under SunOS */ #define TARGET_NR_fcntl 92 /* Common */ #define TARGET_NR_select 93 /* Common */ -/* #define TARGET_NR_setfsgid32 94 Linux sparc32, setdopt under SunOS */ +#define TARGET_NR_setfsgid32 94 /* Linux sparc32, setdopt under SunOS */ #define TARGET_NR_fsync 95 /* Common */ #define TARGET_NR_setpriority 96 /* Common */ #define TARGET_NR_socket 97 /* Common */ @@ -110,10 +110,10 @@ #define TARGET_NR_getresuid 109 /* Linux Specific, sigblock under SunOS */ #define TARGET_NR_setresgid 110 /* Linux Specific, sigsetmask under SunOS */ #define TARGET_NR_getresgid 111 /* Linux Specific, sigpause under SunOS */ -/* #define TARGET_NR_setregid32 75 Linux sparc32, sigstack under SunOS */ +/* #define TARGET_NR_setregid32 75 Linux sparc32, sigstack under SunOS */ #define TARGET_NR_recvmsg 113 /* Common */ #define TARGET_NR_sendmsg 114 /* Common */ -/* #define TARGET_NR_getgroups32 115 Linux sparc32, vtrace under SunOS */ +#define TARGET_NR_getgroups32 115 /* Linux sparc32, vtrace under SunOS */ #define TARGET_NR_gettimeofday 116 /* Common */ #define TARGET_NR_getrusage 117 /* Common */ #define TARGET_NR_getsockopt 118 /* Common */ @@ -130,14 +130,14 @@ #define TARGET_NR_truncate 129 /* Common */ #define TARGET_NR_ftruncate 130 /* Common */ #define TARGET_NR_flock 131 /* Common */ -/* #define TARGET_NR_lstat64 132 Linux sparc32 Specific */ +#define TARGET_NR_lstat64 132 /* Linux sparc32 Specific */ #define TARGET_NR_sendto 133 /* Common */ #define TARGET_NR_shutdown 134 /* Common */ #define TARGET_NR_socketpair 135 /* Common */ #define TARGET_NR_mkdir 136 /* Common */ #define TARGET_NR_rmdir 137 /* Common */ #define TARGET_NR_utimes 138 /* SunOS Specific */ -/* #define TARGET_NR_stat64 139 Linux sparc32 Specific */ +#define TARGET_NR_stat64 139 /* Linux sparc32 Specific */ #define TARGET_NR_sendfile64 140 /* adjtime under SunOS */ #define TARGET_NR_getpeername 141 /* Common */ #define TARGET_NR_futex 142 /* gethostid under SunOS */ @@ -153,7 +153,7 @@ /* #define TARGET_NR_putmsg 152 SunOS Specific */ #define TARGET_NR_poll 153 /* Common */ #define TARGET_NR_getdents64 154 /* Linux specific */ -/* #define TARGET_NR_fcntl64 155 Linux sparc32 Specific */ +#define TARGET_NR_fcntl64 155 /* Linux sparc32 Specific */ /* #define TARGET_NR_getdirentries 156 SunOS Specific */ #define TARGET_NR_statfs 157 /* Common */ #define TARGET_NR_fstatfs 158 /* Common */ @@ -229,9 +229,7 @@ #define TARGET_NR_setfsuid 228 /* Linux Specific */ #define TARGET_NR_setfsgid 229 /* Linux Specific */ #define TARGET_NR__newselect 230 /* Linux Specific */ -#ifdef __KERNEL__ -#define TARGET_NR_time 231 /* Linux sparc32 */ -#endif +#define TARGET_NR_time 231 /* Linux sparc32 */ /* #define TARGET_NR_oldstat 232 Linux Specific */ #define TARGET_NR_stime 233 /* Linux Specific */ #define TARGET_NR_statfs64 234 /* Linux Specific */