1310df056SWarner Losh /* 2310df056SWarner Losh * ELF loading code 3310df056SWarner Losh * 4310df056SWarner Losh * Copyright (c) 2013 Stacey D. Son 5310df056SWarner Losh * 6310df056SWarner Losh * This program is free software; you can redistribute it and/or modify 7310df056SWarner Losh * it under the terms of the GNU General Public License as published by 8310df056SWarner Losh * the Free Software Foundation; either version 2 of the License, or 9310df056SWarner Losh * (at your option) any later version. 10310df056SWarner Losh * 11310df056SWarner Losh * This program is distributed in the hope that it will be useful, 12310df056SWarner Losh * but WITHOUT ANY WARRANTY; without even the implied warranty of 13310df056SWarner Losh * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14310df056SWarner Losh * GNU General Public License for more details. 15310df056SWarner Losh * 16310df056SWarner Losh * You should have received a copy of the GNU General Public License 17310df056SWarner Losh * along with this program; if not, see <http://www.gnu.org/licenses/>. 18310df056SWarner Losh */ 1984778508Sblueswir1 202231197cSPeter Maydell #include "qemu/osdep.h" 2184778508Sblueswir1 2284778508Sblueswir1 #include "qemu.h" 2376cad711SPaolo Bonzini #include "disas/disas.h" 24f348b6d1SVeronia Bahaa #include "qemu/path.h" 2584778508Sblueswir1 2698b34d35SWarner Losh static abi_ulong target_auxents; /* Where the AUX entries are in target */ 2798b34d35SWarner Losh static size_t target_auxents_sz; /* Size of AUX entries including AT_NULL */ 2898b34d35SWarner Losh 29*0475f8faSWarner Losh #include "target_arch_reg.h" 3098b34d35SWarner Losh #include "target_os_elf.h" 3198b34d35SWarner Losh #include "target_os_stack.h" 32a8fe6d5dSWarner Losh #include "target_os_thread.h" 33*0475f8faSWarner Losh #include "target_os_user.h" 3484778508Sblueswir1 3598b34d35SWarner Losh abi_ulong target_stksiz; 3698b34d35SWarner Losh abi_ulong target_stkbas; 3784778508Sblueswir1 38*0475f8faSWarner Losh static int elf_core_dump(int signr, CPUArchState *env); 39*0475f8faSWarner Losh 4084778508Sblueswir1 static inline void memcpy_fromfs(void *to, const void *from, unsigned long n) 4184778508Sblueswir1 { 4284778508Sblueswir1 memcpy(to, from, n); 4384778508Sblueswir1 } 4484778508Sblueswir1 4584778508Sblueswir1 #ifdef BSWAP_NEEDED 4684778508Sblueswir1 static void bswap_ehdr(struct elfhdr *ehdr) 4784778508Sblueswir1 { 4884778508Sblueswir1 bswap16s(&ehdr->e_type); /* Object file type */ 4984778508Sblueswir1 bswap16s(&ehdr->e_machine); /* Architecture */ 5084778508Sblueswir1 bswap32s(&ehdr->e_version); /* Object file version */ 5184778508Sblueswir1 bswaptls(&ehdr->e_entry); /* Entry point virtual address */ 5284778508Sblueswir1 bswaptls(&ehdr->e_phoff); /* Program header table file offset */ 5384778508Sblueswir1 bswaptls(&ehdr->e_shoff); /* Section header table file offset */ 5484778508Sblueswir1 bswap32s(&ehdr->e_flags); /* Processor-specific flags */ 5584778508Sblueswir1 bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ 5684778508Sblueswir1 bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ 5784778508Sblueswir1 bswap16s(&ehdr->e_phnum); /* Program header table entry count */ 5884778508Sblueswir1 bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ 5984778508Sblueswir1 bswap16s(&ehdr->e_shnum); /* Section header table entry count */ 6084778508Sblueswir1 bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ 6184778508Sblueswir1 } 6284778508Sblueswir1 63b62f790cSWarner Losh static void bswap_phdr(struct elf_phdr *phdr, int phnum) 6484778508Sblueswir1 { 65b62f790cSWarner Losh int i; 66b62f790cSWarner Losh 67b62f790cSWarner Losh for (i = 0; i < phnum; i++, phdr++) { 6884778508Sblueswir1 bswap32s(&phdr->p_type); /* Segment type */ 69b62f790cSWarner Losh bswap32s(&phdr->p_flags); /* Segment flags */ 7084778508Sblueswir1 bswaptls(&phdr->p_offset); /* Segment file offset */ 7184778508Sblueswir1 bswaptls(&phdr->p_vaddr); /* Segment virtual address */ 7284778508Sblueswir1 bswaptls(&phdr->p_paddr); /* Segment physical address */ 7384778508Sblueswir1 bswaptls(&phdr->p_filesz); /* Segment size in file */ 7484778508Sblueswir1 bswaptls(&phdr->p_memsz); /* Segment size in memory */ 7584778508Sblueswir1 bswaptls(&phdr->p_align); /* Segment alignment */ 7684778508Sblueswir1 } 77b62f790cSWarner Losh } 7884778508Sblueswir1 79b62f790cSWarner Losh static void bswap_shdr(struct elf_shdr *shdr, int shnum) 8084778508Sblueswir1 { 81b62f790cSWarner Losh int i; 82b62f790cSWarner Losh 83b62f790cSWarner Losh for (i = 0; i < shnum; i++, shdr++) { 8484778508Sblueswir1 bswap32s(&shdr->sh_name); 8584778508Sblueswir1 bswap32s(&shdr->sh_type); 8684778508Sblueswir1 bswaptls(&shdr->sh_flags); 8784778508Sblueswir1 bswaptls(&shdr->sh_addr); 8884778508Sblueswir1 bswaptls(&shdr->sh_offset); 8984778508Sblueswir1 bswaptls(&shdr->sh_size); 9084778508Sblueswir1 bswap32s(&shdr->sh_link); 9184778508Sblueswir1 bswap32s(&shdr->sh_info); 9284778508Sblueswir1 bswaptls(&shdr->sh_addralign); 9384778508Sblueswir1 bswaptls(&shdr->sh_entsize); 9484778508Sblueswir1 } 95b62f790cSWarner Losh } 9684778508Sblueswir1 9784778508Sblueswir1 static void bswap_sym(struct elf_sym *sym) 9884778508Sblueswir1 { 9984778508Sblueswir1 bswap32s(&sym->st_name); 10084778508Sblueswir1 bswaptls(&sym->st_value); 10184778508Sblueswir1 bswaptls(&sym->st_size); 10284778508Sblueswir1 bswap16s(&sym->st_shndx); 10384778508Sblueswir1 } 104b62f790cSWarner Losh 105*0475f8faSWarner Losh static void bswap_note(struct elf_note *en) 106*0475f8faSWarner Losh { 107*0475f8faSWarner Losh bswap32s(&en->n_namesz); 108*0475f8faSWarner Losh bswap32s(&en->n_descsz); 109*0475f8faSWarner Losh bswap32s(&en->n_type); 110*0475f8faSWarner Losh } 111*0475f8faSWarner Losh 112b62f790cSWarner Losh #else /* ! BSWAP_NEEDED */ 113b62f790cSWarner Losh 114b62f790cSWarner Losh static void bswap_ehdr(struct elfhdr *ehdr) { } 115b62f790cSWarner Losh static void bswap_phdr(struct elf_phdr *phdr, int phnum) { } 116b62f790cSWarner Losh static void bswap_shdr(struct elf_shdr *shdr, int shnum) { } 117b62f790cSWarner Losh static void bswap_sym(struct elf_sym *sym) { } 118*0475f8faSWarner Losh static void bswap_note(struct elf_note *en) { } 119b62f790cSWarner Losh 120b62f790cSWarner Losh #endif /* ! BSWAP_NEEDED */ 12184778508Sblueswir1 122*0475f8faSWarner Losh #include "elfcore.c" 123*0475f8faSWarner Losh 12484778508Sblueswir1 /* 12584778508Sblueswir1 * 'copy_elf_strings()' copies argument/envelope strings from user 12684778508Sblueswir1 * memory to free pages in kernel mem. These are in a format ready 12784778508Sblueswir1 * to be put directly into the top of new user memory. 12884778508Sblueswir1 * 12984778508Sblueswir1 */ 13084778508Sblueswir1 static abi_ulong copy_elf_strings(int argc, char **argv, void **page, 13184778508Sblueswir1 abi_ulong p) 13284778508Sblueswir1 { 13384778508Sblueswir1 char *tmp, *tmp1, *pag = NULL; 13484778508Sblueswir1 int len, offset = 0; 13584778508Sblueswir1 13684778508Sblueswir1 if (!p) { 13784778508Sblueswir1 return 0; /* bullet-proofing */ 13884778508Sblueswir1 } 13984778508Sblueswir1 while (argc-- > 0) { 14084778508Sblueswir1 tmp = argv[argc]; 14184778508Sblueswir1 if (!tmp) { 1429bb93180SPeter Maydell fprintf(stderr, "VFS: argc is wrong"); 14384778508Sblueswir1 exit(-1); 14484778508Sblueswir1 } 14584778508Sblueswir1 tmp1 = tmp; 14684778508Sblueswir1 while (*tmp++); 14784778508Sblueswir1 len = tmp - tmp1; 14884778508Sblueswir1 if (p < len) { /* this shouldn't happen - 128kB */ 14984778508Sblueswir1 return 0; 15084778508Sblueswir1 } 15184778508Sblueswir1 while (len) { 15284778508Sblueswir1 --p; --tmp; --len; 15384778508Sblueswir1 if (--offset < 0) { 15484778508Sblueswir1 offset = p % TARGET_PAGE_SIZE; 15584778508Sblueswir1 pag = (char *)page[p / TARGET_PAGE_SIZE]; 15684778508Sblueswir1 if (!pag) { 157c580dee4SStefan Weil pag = g_try_malloc0(TARGET_PAGE_SIZE); 15884778508Sblueswir1 page[p / TARGET_PAGE_SIZE] = pag; 15984778508Sblueswir1 if (!pag) 16084778508Sblueswir1 return 0; 16184778508Sblueswir1 } 16284778508Sblueswir1 } 16384778508Sblueswir1 if (len == 0 || offset == 0) { 16484778508Sblueswir1 *(pag + offset) = *tmp; 16584778508Sblueswir1 } 16684778508Sblueswir1 else { 16784778508Sblueswir1 int bytes_to_copy = (len > offset) ? offset : len; 16884778508Sblueswir1 tmp -= bytes_to_copy; 16984778508Sblueswir1 p -= bytes_to_copy; 17084778508Sblueswir1 offset -= bytes_to_copy; 17184778508Sblueswir1 len -= bytes_to_copy; 17284778508Sblueswir1 memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1); 17384778508Sblueswir1 } 17484778508Sblueswir1 } 17584778508Sblueswir1 } 17684778508Sblueswir1 return p; 17784778508Sblueswir1 } 17884778508Sblueswir1 17998b34d35SWarner Losh static void setup_arg_pages(struct bsd_binprm *bprm, struct image_info *info, 18098b34d35SWarner Losh abi_ulong *stackp, abi_ulong *stringp) 18184778508Sblueswir1 { 18298b34d35SWarner Losh abi_ulong stack_base, size; 18398b34d35SWarner Losh abi_long addr; 18484778508Sblueswir1 18584778508Sblueswir1 /* Create enough stack to hold everything. If we don't use 18684778508Sblueswir1 * it for args, we'll use it for something else... 18784778508Sblueswir1 */ 188312a0b1cSWarner Losh size = target_dflssiz; 18998b34d35SWarner Losh stack_base = TARGET_USRSTACK - size; 19098b34d35SWarner Losh addr = target_mmap(stack_base, 19184778508Sblueswir1 size + qemu_host_page_size, 19284778508Sblueswir1 PROT_READ | PROT_WRITE, 19384778508Sblueswir1 MAP_PRIVATE | MAP_ANON, 19484778508Sblueswir1 -1, 0); 19598b34d35SWarner Losh if (addr == -1) { 19684778508Sblueswir1 perror("stk mmap"); 19784778508Sblueswir1 exit(-1); 19884778508Sblueswir1 } 19984778508Sblueswir1 /* we reserve one extra page at the top of the stack as guard */ 20098b34d35SWarner Losh target_mprotect(addr + size, qemu_host_page_size, PROT_NONE); 20184778508Sblueswir1 20298b34d35SWarner Losh target_stksiz = size; 20398b34d35SWarner Losh target_stkbas = addr; 20484778508Sblueswir1 20598b34d35SWarner Losh if (setup_initial_stack(bprm, stackp, stringp) != 0) { 20698b34d35SWarner Losh perror("stk setup"); 20798b34d35SWarner Losh exit(-1); 20884778508Sblueswir1 } 20984778508Sblueswir1 } 21084778508Sblueswir1 21184778508Sblueswir1 static void set_brk(abi_ulong start, abi_ulong end) 21284778508Sblueswir1 { 21384778508Sblueswir1 /* page-align the start and end addresses... */ 21484778508Sblueswir1 start = HOST_PAGE_ALIGN(start); 21584778508Sblueswir1 end = HOST_PAGE_ALIGN(end); 21684778508Sblueswir1 if (end <= start) 21784778508Sblueswir1 return; 21884778508Sblueswir1 if (target_mmap(start, end - start, 21984778508Sblueswir1 PROT_READ | PROT_WRITE | PROT_EXEC, 22084778508Sblueswir1 MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0) == -1) { 22184778508Sblueswir1 perror("cannot mmap brk"); 22284778508Sblueswir1 exit(-1); 22384778508Sblueswir1 } 22484778508Sblueswir1 } 22584778508Sblueswir1 22684778508Sblueswir1 22784778508Sblueswir1 /* We need to explicitly zero any fractional pages after the data 22884778508Sblueswir1 section (i.e. bss). This would contain the junk from the file that 22984778508Sblueswir1 should not be in memory. */ 23084778508Sblueswir1 static void padzero(abi_ulong elf_bss, abi_ulong last_bss) 23184778508Sblueswir1 { 23284778508Sblueswir1 abi_ulong nbyte; 23384778508Sblueswir1 23484778508Sblueswir1 if (elf_bss >= last_bss) 23584778508Sblueswir1 return; 23684778508Sblueswir1 23784778508Sblueswir1 /* XXX: this is really a hack : if the real host page size is 23884778508Sblueswir1 smaller than the target page size, some pages after the end 23984778508Sblueswir1 of the file may not be mapped. A better fix would be to 24084778508Sblueswir1 patch target_mmap(), but it is more complicated as the file 24184778508Sblueswir1 size must be known */ 24284778508Sblueswir1 if (qemu_real_host_page_size < qemu_host_page_size) { 24384778508Sblueswir1 abi_ulong end_addr, end_addr1; 2440c2d70c4SPaolo Bonzini end_addr1 = REAL_HOST_PAGE_ALIGN(elf_bss); 24584778508Sblueswir1 end_addr = HOST_PAGE_ALIGN(elf_bss); 24684778508Sblueswir1 if (end_addr1 < end_addr) { 2473e8f1628SRichard Henderson mmap((void *)g2h_untagged(end_addr1), end_addr - end_addr1, 24884778508Sblueswir1 PROT_READ | PROT_WRITE | PROT_EXEC, 24984778508Sblueswir1 MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0); 25084778508Sblueswir1 } 25184778508Sblueswir1 } 25284778508Sblueswir1 25384778508Sblueswir1 nbyte = elf_bss & (qemu_host_page_size - 1); 25484778508Sblueswir1 if (nbyte) { 25584778508Sblueswir1 nbyte = qemu_host_page_size - nbyte; 25684778508Sblueswir1 do { 25784778508Sblueswir1 /* FIXME - what to do if put_user() fails? */ 25884778508Sblueswir1 put_user_u8(0, elf_bss); 25984778508Sblueswir1 elf_bss++; 26084778508Sblueswir1 } while (--nbyte); 26184778508Sblueswir1 } 26284778508Sblueswir1 } 26384778508Sblueswir1 26484778508Sblueswir1 static abi_ulong load_elf_interp(struct elfhdr *interp_elf_ex, 26584778508Sblueswir1 int interpreter_fd, 26684778508Sblueswir1 abi_ulong *interp_load_addr) 26784778508Sblueswir1 { 26884778508Sblueswir1 struct elf_phdr *elf_phdata = NULL; 26984778508Sblueswir1 struct elf_phdr *eppnt; 27084778508Sblueswir1 abi_ulong load_addr = 0; 27184778508Sblueswir1 int load_addr_set = 0; 27284778508Sblueswir1 int retval; 27384778508Sblueswir1 abi_ulong last_bss, elf_bss; 27484778508Sblueswir1 abi_ulong error; 27584778508Sblueswir1 int i; 27684778508Sblueswir1 27784778508Sblueswir1 elf_bss = 0; 27884778508Sblueswir1 last_bss = 0; 27984778508Sblueswir1 error = 0; 28084778508Sblueswir1 28184778508Sblueswir1 bswap_ehdr(interp_elf_ex); 28284778508Sblueswir1 /* First of all, some simple consistency checks */ 28384778508Sblueswir1 if ((interp_elf_ex->e_type != ET_EXEC && 28484778508Sblueswir1 interp_elf_ex->e_type != ET_DYN) || 28584778508Sblueswir1 !elf_check_arch(interp_elf_ex->e_machine)) { 28684778508Sblueswir1 return ~((abi_ulong)0UL); 28784778508Sblueswir1 } 28884778508Sblueswir1 28984778508Sblueswir1 29084778508Sblueswir1 /* Now read in all of the header information */ 29184778508Sblueswir1 29284778508Sblueswir1 if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) 29384778508Sblueswir1 return ~(abi_ulong)0UL; 29484778508Sblueswir1 29584778508Sblueswir1 elf_phdata = (struct elf_phdr *) 29684778508Sblueswir1 malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); 29784778508Sblueswir1 29884778508Sblueswir1 if (!elf_phdata) 29984778508Sblueswir1 return ~((abi_ulong)0UL); 30084778508Sblueswir1 30184778508Sblueswir1 /* 30284778508Sblueswir1 * If the size of this structure has changed, then punt, since 30384778508Sblueswir1 * we will be doing the wrong thing. 30484778508Sblueswir1 */ 30584778508Sblueswir1 if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { 30684778508Sblueswir1 free(elf_phdata); 30784778508Sblueswir1 return ~((abi_ulong)0UL); 30884778508Sblueswir1 } 30984778508Sblueswir1 31084778508Sblueswir1 retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); 31184778508Sblueswir1 if (retval >= 0) { 31284778508Sblueswir1 retval = read(interpreter_fd, 31384778508Sblueswir1 (char *) elf_phdata, 31484778508Sblueswir1 sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); 31584778508Sblueswir1 } 31684778508Sblueswir1 if (retval < 0) { 31784778508Sblueswir1 perror("load_elf_interp"); 31884778508Sblueswir1 exit(-1); 31984778508Sblueswir1 free(elf_phdata); 32084778508Sblueswir1 return retval; 32184778508Sblueswir1 } 322b62f790cSWarner Losh bswap_phdr(elf_phdata, interp_elf_ex->e_phnum); 32384778508Sblueswir1 32484778508Sblueswir1 if (interp_elf_ex->e_type == ET_DYN) { 32584778508Sblueswir1 /* in order to avoid hardcoding the interpreter load 32684778508Sblueswir1 address in qemu, we allocate a big enough memory zone */ 32784778508Sblueswir1 error = target_mmap(0, INTERP_MAP_SIZE, 32884778508Sblueswir1 PROT_NONE, MAP_PRIVATE | MAP_ANON, 32984778508Sblueswir1 -1, 0); 33084778508Sblueswir1 if (error == -1) { 33184778508Sblueswir1 perror("mmap"); 33284778508Sblueswir1 exit(-1); 33384778508Sblueswir1 } 33484778508Sblueswir1 load_addr = error; 33584778508Sblueswir1 load_addr_set = 1; 33684778508Sblueswir1 } 33784778508Sblueswir1 33884778508Sblueswir1 eppnt = elf_phdata; 33984778508Sblueswir1 for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) 34084778508Sblueswir1 if (eppnt->p_type == PT_LOAD) { 34184778508Sblueswir1 int elf_type = MAP_PRIVATE | MAP_DENYWRITE; 34284778508Sblueswir1 int elf_prot = 0; 34384778508Sblueswir1 abi_ulong vaddr = 0; 34484778508Sblueswir1 abi_ulong k; 34584778508Sblueswir1 34684778508Sblueswir1 if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; 34784778508Sblueswir1 if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; 34884778508Sblueswir1 if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; 34984778508Sblueswir1 if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { 35084778508Sblueswir1 elf_type |= MAP_FIXED; 35184778508Sblueswir1 vaddr = eppnt->p_vaddr; 35284778508Sblueswir1 } 35384778508Sblueswir1 error = target_mmap(load_addr + TARGET_ELF_PAGESTART(vaddr), 35484778508Sblueswir1 eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr), 35584778508Sblueswir1 elf_prot, 35684778508Sblueswir1 elf_type, 35784778508Sblueswir1 interpreter_fd, 35884778508Sblueswir1 eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); 35984778508Sblueswir1 36084778508Sblueswir1 if (error == -1) { 36184778508Sblueswir1 /* Real error */ 36284778508Sblueswir1 close(interpreter_fd); 36384778508Sblueswir1 free(elf_phdata); 36484778508Sblueswir1 return ~((abi_ulong)0UL); 36584778508Sblueswir1 } 36684778508Sblueswir1 36784778508Sblueswir1 if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { 36884778508Sblueswir1 load_addr = error; 36984778508Sblueswir1 load_addr_set = 1; 37084778508Sblueswir1 } 37184778508Sblueswir1 37284778508Sblueswir1 /* 37384778508Sblueswir1 * Find the end of the file mapping for this phdr, and keep 37484778508Sblueswir1 * track of the largest address we see for this. 37584778508Sblueswir1 */ 37684778508Sblueswir1 k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; 37784778508Sblueswir1 if (k > elf_bss) elf_bss = k; 37884778508Sblueswir1 37984778508Sblueswir1 /* 38084778508Sblueswir1 * Do the same thing for the memory mapping - between 38184778508Sblueswir1 * elf_bss and last_bss is the bss section. 38284778508Sblueswir1 */ 38384778508Sblueswir1 k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; 38484778508Sblueswir1 if (k > last_bss) last_bss = k; 38584778508Sblueswir1 } 38684778508Sblueswir1 38784778508Sblueswir1 /* Now use mmap to map the library into memory. */ 38884778508Sblueswir1 38984778508Sblueswir1 close(interpreter_fd); 39084778508Sblueswir1 39184778508Sblueswir1 /* 39284778508Sblueswir1 * Now fill out the bss section. First pad the last page up 39384778508Sblueswir1 * to the page boundary, and then perform a mmap to make sure 39484778508Sblueswir1 * that there are zeromapped pages up to and including the last 39584778508Sblueswir1 * bss page. 39684778508Sblueswir1 */ 39784778508Sblueswir1 padzero(elf_bss, last_bss); 39884778508Sblueswir1 elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */ 39984778508Sblueswir1 40084778508Sblueswir1 /* Map the last of the bss segment */ 40184778508Sblueswir1 if (last_bss > elf_bss) { 40284778508Sblueswir1 target_mmap(elf_bss, last_bss - elf_bss, 40384778508Sblueswir1 PROT_READ | PROT_WRITE | PROT_EXEC, 40484778508Sblueswir1 MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0); 40584778508Sblueswir1 } 40684778508Sblueswir1 free(elf_phdata); 40784778508Sblueswir1 40884778508Sblueswir1 *interp_load_addr = load_addr; 40984778508Sblueswir1 return ((abi_ulong) interp_elf_ex->e_entry) + load_addr; 41084778508Sblueswir1 } 41184778508Sblueswir1 41284778508Sblueswir1 static int symfind(const void *s0, const void *s1) 41384778508Sblueswir1 { 414c7c530cdSStefan Weil target_ulong addr = *(target_ulong *)s0; 41584778508Sblueswir1 struct elf_sym *sym = (struct elf_sym *)s1; 41684778508Sblueswir1 int result = 0; 417c7c530cdSStefan Weil if (addr < sym->st_value) { 41884778508Sblueswir1 result = -1; 419c7c530cdSStefan Weil } else if (addr >= sym->st_value + sym->st_size) { 42084778508Sblueswir1 result = 1; 42184778508Sblueswir1 } 42284778508Sblueswir1 return result; 42384778508Sblueswir1 } 42484778508Sblueswir1 42584778508Sblueswir1 static const char *lookup_symbolxx(struct syminfo *s, target_ulong orig_addr) 42684778508Sblueswir1 { 42784778508Sblueswir1 #if ELF_CLASS == ELFCLASS32 42884778508Sblueswir1 struct elf_sym *syms = s->disas_symtab.elf32; 42984778508Sblueswir1 #else 43084778508Sblueswir1 struct elf_sym *syms = s->disas_symtab.elf64; 43184778508Sblueswir1 #endif 43284778508Sblueswir1 43384778508Sblueswir1 // binary search 43484778508Sblueswir1 struct elf_sym *sym; 43584778508Sblueswir1 436c7c530cdSStefan Weil sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms), symfind); 4377cba04f6SBlue Swirl if (sym != NULL) { 43884778508Sblueswir1 return s->disas_strtab + sym->st_name; 43984778508Sblueswir1 } 44084778508Sblueswir1 44184778508Sblueswir1 return ""; 44284778508Sblueswir1 } 44384778508Sblueswir1 44484778508Sblueswir1 /* FIXME: This should use elf_ops.h */ 44584778508Sblueswir1 static int symcmp(const void *s0, const void *s1) 44684778508Sblueswir1 { 44784778508Sblueswir1 struct elf_sym *sym0 = (struct elf_sym *)s0; 44884778508Sblueswir1 struct elf_sym *sym1 = (struct elf_sym *)s1; 44984778508Sblueswir1 return (sym0->st_value < sym1->st_value) 45084778508Sblueswir1 ? -1 45184778508Sblueswir1 : ((sym0->st_value > sym1->st_value) ? 1 : 0); 45284778508Sblueswir1 } 45384778508Sblueswir1 45484778508Sblueswir1 /* Best attempt to load symbols from this ELF object. */ 45584778508Sblueswir1 static void load_symbols(struct elfhdr *hdr, int fd) 45684778508Sblueswir1 { 45784778508Sblueswir1 unsigned int i, nsyms; 45884778508Sblueswir1 struct elf_shdr sechdr, symtab, strtab; 45984778508Sblueswir1 char *strings; 46084778508Sblueswir1 struct syminfo *s; 46129718712SStefan Weil struct elf_sym *syms, *new_syms; 46284778508Sblueswir1 46384778508Sblueswir1 lseek(fd, hdr->e_shoff, SEEK_SET); 46484778508Sblueswir1 for (i = 0; i < hdr->e_shnum; i++) { 46584778508Sblueswir1 if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) 46684778508Sblueswir1 return; 467b62f790cSWarner Losh bswap_shdr(&sechdr, 1); 46884778508Sblueswir1 if (sechdr.sh_type == SHT_SYMTAB) { 46984778508Sblueswir1 symtab = sechdr; 47084778508Sblueswir1 lseek(fd, hdr->e_shoff 47184778508Sblueswir1 + sizeof(sechdr) * sechdr.sh_link, SEEK_SET); 47284778508Sblueswir1 if (read(fd, &strtab, sizeof(strtab)) 47384778508Sblueswir1 != sizeof(strtab)) 47484778508Sblueswir1 return; 475b62f790cSWarner Losh bswap_shdr(&strtab, 1); 47684778508Sblueswir1 goto found; 47784778508Sblueswir1 } 47884778508Sblueswir1 } 47984778508Sblueswir1 return; /* Shouldn't happen... */ 48084778508Sblueswir1 48184778508Sblueswir1 found: 48284778508Sblueswir1 /* Now know where the strtab and symtab are. Snarf them. */ 48384778508Sblueswir1 s = malloc(sizeof(*s)); 48484778508Sblueswir1 syms = malloc(symtab.sh_size); 48529718712SStefan Weil if (!syms) { 48629718712SStefan Weil free(s); 48784778508Sblueswir1 return; 48829718712SStefan Weil } 48984778508Sblueswir1 s->disas_strtab = strings = malloc(strtab.sh_size); 49029718712SStefan Weil if (!s->disas_strtab) { 49129718712SStefan Weil free(s); 49229718712SStefan Weil free(syms); 49384778508Sblueswir1 return; 49429718712SStefan Weil } 49584778508Sblueswir1 49684778508Sblueswir1 lseek(fd, symtab.sh_offset, SEEK_SET); 49729718712SStefan Weil if (read(fd, syms, symtab.sh_size) != symtab.sh_size) { 49829718712SStefan Weil free(s); 49929718712SStefan Weil free(syms); 50029718712SStefan Weil free(strings); 50184778508Sblueswir1 return; 50229718712SStefan Weil } 50384778508Sblueswir1 50484778508Sblueswir1 nsyms = symtab.sh_size / sizeof(struct elf_sym); 50584778508Sblueswir1 50684778508Sblueswir1 i = 0; 50784778508Sblueswir1 while (i < nsyms) { 50884778508Sblueswir1 bswap_sym(syms + i); 50984778508Sblueswir1 // Throw away entries which we do not need. 51084778508Sblueswir1 if (syms[i].st_shndx == SHN_UNDEF || 51184778508Sblueswir1 syms[i].st_shndx >= SHN_LORESERVE || 51284778508Sblueswir1 ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) { 51384778508Sblueswir1 nsyms--; 51484778508Sblueswir1 if (i < nsyms) { 51584778508Sblueswir1 syms[i] = syms[nsyms]; 51684778508Sblueswir1 } 51784778508Sblueswir1 continue; 51884778508Sblueswir1 } 51984778508Sblueswir1 i++; 52084778508Sblueswir1 } 52129718712SStefan Weil 52229718712SStefan Weil /* Attempt to free the storage associated with the local symbols 52329718712SStefan Weil that we threw away. Whether or not this has any effect on the 52429718712SStefan Weil memory allocation depends on the malloc implementation and how 52529718712SStefan Weil many symbols we managed to discard. */ 52629718712SStefan Weil new_syms = realloc(syms, nsyms * sizeof(*syms)); 52729718712SStefan Weil if (new_syms == NULL) { 52829718712SStefan Weil free(s); 52929718712SStefan Weil free(syms); 53029718712SStefan Weil free(strings); 53129718712SStefan Weil return; 53229718712SStefan Weil } 53329718712SStefan Weil syms = new_syms; 53484778508Sblueswir1 53584778508Sblueswir1 qsort(syms, nsyms, sizeof(*syms), symcmp); 53684778508Sblueswir1 53784778508Sblueswir1 lseek(fd, strtab.sh_offset, SEEK_SET); 53829718712SStefan Weil if (read(fd, strings, strtab.sh_size) != strtab.sh_size) { 53929718712SStefan Weil free(s); 54029718712SStefan Weil free(syms); 54129718712SStefan Weil free(strings); 54284778508Sblueswir1 return; 54329718712SStefan Weil } 54484778508Sblueswir1 s->disas_num_syms = nsyms; 54584778508Sblueswir1 #if ELF_CLASS == ELFCLASS32 54684778508Sblueswir1 s->disas_symtab.elf32 = syms; 547032e51d7SBlue Swirl s->lookup_symbol = (lookup_symbol_t)lookup_symbolxx; 54884778508Sblueswir1 #else 54984778508Sblueswir1 s->disas_symtab.elf64 = syms; 550032e51d7SBlue Swirl s->lookup_symbol = (lookup_symbol_t)lookup_symbolxx; 55184778508Sblueswir1 #endif 55284778508Sblueswir1 s->next = syminfos; 55384778508Sblueswir1 syminfos = s; 55484778508Sblueswir1 } 55584778508Sblueswir1 556afcbcff8SWarner Losh int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, 55784778508Sblueswir1 struct image_info *info) 55884778508Sblueswir1 { 55984778508Sblueswir1 struct elfhdr elf_ex; 56084778508Sblueswir1 struct elfhdr interp_elf_ex; 56184778508Sblueswir1 int interpreter_fd = -1; /* avoid warning */ 56284778508Sblueswir1 abi_ulong load_addr, load_bias; 56384778508Sblueswir1 int load_addr_set = 0; 56484778508Sblueswir1 int i; 56584778508Sblueswir1 struct elf_phdr * elf_ppnt; 56684778508Sblueswir1 struct elf_phdr *elf_phdata; 56784778508Sblueswir1 abi_ulong elf_bss, k, elf_brk; 56884778508Sblueswir1 int retval; 56984778508Sblueswir1 char * elf_interpreter; 57084778508Sblueswir1 abi_ulong elf_entry, interp_load_addr = 0; 57184778508Sblueswir1 abi_ulong start_code, end_code, start_data, end_data; 57284778508Sblueswir1 abi_ulong reloc_func_desc = 0; 57384778508Sblueswir1 57484778508Sblueswir1 load_addr = 0; 57584778508Sblueswir1 load_bias = 0; 57684778508Sblueswir1 elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ 57784778508Sblueswir1 bswap_ehdr(&elf_ex); 57884778508Sblueswir1 57984778508Sblueswir1 /* First of all, some simple consistency checks */ 58084778508Sblueswir1 if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || 58184778508Sblueswir1 (!elf_check_arch(elf_ex.e_machine))) { 58284778508Sblueswir1 return -ENOEXEC; 58384778508Sblueswir1 } 58484778508Sblueswir1 58584778508Sblueswir1 bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p); 58684778508Sblueswir1 bprm->p = copy_elf_strings(bprm->envc, bprm->envp, bprm->page,bprm->p); 58784778508Sblueswir1 bprm->p = copy_elf_strings(bprm->argc, bprm->argv, bprm->page,bprm->p); 58884778508Sblueswir1 if (!bprm->p) { 58984778508Sblueswir1 retval = -E2BIG; 59084778508Sblueswir1 } 59184778508Sblueswir1 59284778508Sblueswir1 /* Now read in all of the header information */ 59384778508Sblueswir1 elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum); 59484778508Sblueswir1 if (elf_phdata == NULL) { 59584778508Sblueswir1 return -ENOMEM; 59684778508Sblueswir1 } 59784778508Sblueswir1 59884778508Sblueswir1 retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); 59984778508Sblueswir1 if (retval > 0) { 60084778508Sblueswir1 retval = read(bprm->fd, (char *)elf_phdata, 60184778508Sblueswir1 elf_ex.e_phentsize * elf_ex.e_phnum); 60284778508Sblueswir1 } 60384778508Sblueswir1 60484778508Sblueswir1 if (retval < 0) { 60584778508Sblueswir1 perror("load_elf_binary"); 60684778508Sblueswir1 exit(-1); 60784778508Sblueswir1 free(elf_phdata); 60884778508Sblueswir1 return -errno; 60984778508Sblueswir1 } 61084778508Sblueswir1 611b62f790cSWarner Losh bswap_phdr(elf_phdata, elf_ex.e_phnum); 612b62f790cSWarner Losh 61384778508Sblueswir1 elf_ppnt = elf_phdata; 61484778508Sblueswir1 61584778508Sblueswir1 elf_bss = 0; 61684778508Sblueswir1 elf_brk = 0; 61784778508Sblueswir1 61884778508Sblueswir1 61984778508Sblueswir1 elf_interpreter = NULL; 62084778508Sblueswir1 start_code = ~((abi_ulong)0UL); 62184778508Sblueswir1 end_code = 0; 62284778508Sblueswir1 start_data = 0; 62384778508Sblueswir1 end_data = 0; 62484778508Sblueswir1 62584778508Sblueswir1 for (i = 0;i < elf_ex.e_phnum; i++) { 62684778508Sblueswir1 if (elf_ppnt->p_type == PT_INTERP) { 62784778508Sblueswir1 if (elf_interpreter != NULL) 62884778508Sblueswir1 { 62984778508Sblueswir1 free(elf_phdata); 63084778508Sblueswir1 free(elf_interpreter); 63184778508Sblueswir1 close(bprm->fd); 63284778508Sblueswir1 return -EINVAL; 63384778508Sblueswir1 } 63484778508Sblueswir1 63584778508Sblueswir1 /* This is the program interpreter used for 63684778508Sblueswir1 * shared libraries - for now assume that this 63784778508Sblueswir1 * is an a.out format binary 63884778508Sblueswir1 */ 63984778508Sblueswir1 64084778508Sblueswir1 elf_interpreter = (char *)malloc(elf_ppnt->p_filesz); 64184778508Sblueswir1 64284778508Sblueswir1 if (elf_interpreter == NULL) { 64384778508Sblueswir1 free(elf_phdata); 64484778508Sblueswir1 close(bprm->fd); 64584778508Sblueswir1 return -ENOMEM; 64684778508Sblueswir1 } 64784778508Sblueswir1 64884778508Sblueswir1 retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); 64984778508Sblueswir1 if (retval >= 0) { 65084778508Sblueswir1 retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz); 65184778508Sblueswir1 } 65284778508Sblueswir1 if (retval < 0) { 65384778508Sblueswir1 perror("load_elf_binary2"); 65484778508Sblueswir1 exit(-1); 65584778508Sblueswir1 } 65684778508Sblueswir1 65784778508Sblueswir1 if (retval >= 0) { 65884778508Sblueswir1 retval = open(path(elf_interpreter), O_RDONLY); 65984778508Sblueswir1 if (retval >= 0) { 66084778508Sblueswir1 interpreter_fd = retval; 66184778508Sblueswir1 } 66284778508Sblueswir1 else { 66384778508Sblueswir1 perror(elf_interpreter); 66484778508Sblueswir1 exit(-1); 66584778508Sblueswir1 /* retval = -errno; */ 66684778508Sblueswir1 } 66784778508Sblueswir1 } 66884778508Sblueswir1 66984778508Sblueswir1 if (retval >= 0) { 67084778508Sblueswir1 retval = lseek(interpreter_fd, 0, SEEK_SET); 67184778508Sblueswir1 if (retval >= 0) { 67284778508Sblueswir1 retval = read(interpreter_fd, bprm->buf, 128); 67384778508Sblueswir1 } 67484778508Sblueswir1 } 67584778508Sblueswir1 if (retval >= 0) { 67684778508Sblueswir1 interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */ 67784778508Sblueswir1 } 67884778508Sblueswir1 if (retval < 0) { 67984778508Sblueswir1 perror("load_elf_binary3"); 68084778508Sblueswir1 exit(-1); 68184778508Sblueswir1 free(elf_phdata); 68284778508Sblueswir1 free(elf_interpreter); 68384778508Sblueswir1 close(bprm->fd); 68484778508Sblueswir1 return retval; 68584778508Sblueswir1 } 68684778508Sblueswir1 } 68784778508Sblueswir1 elf_ppnt++; 68884778508Sblueswir1 } 68984778508Sblueswir1 69084778508Sblueswir1 /* Some simple consistency checks for the interpreter */ 69184778508Sblueswir1 if (elf_interpreter) { 69284778508Sblueswir1 if (interp_elf_ex.e_ident[0] != 0x7f || 693fff2a02fSChristoph Egger strncmp((char *)&interp_elf_ex.e_ident[1], "ELF", 3) != 0) { 69484778508Sblueswir1 free(elf_interpreter); 69584778508Sblueswir1 free(elf_phdata); 69684778508Sblueswir1 close(bprm->fd); 69784778508Sblueswir1 return -ELIBBAD; 69884778508Sblueswir1 } 69984778508Sblueswir1 } 70084778508Sblueswir1 70184778508Sblueswir1 /* OK, we are done with that, now set up the arg stuff, 70284778508Sblueswir1 and then start this sucker up */ 70384778508Sblueswir1 70484778508Sblueswir1 if (!bprm->p) { 70584778508Sblueswir1 free(elf_interpreter); 70684778508Sblueswir1 free(elf_phdata); 70784778508Sblueswir1 close(bprm->fd); 70884778508Sblueswir1 return -E2BIG; 70984778508Sblueswir1 } 71084778508Sblueswir1 71184778508Sblueswir1 /* OK, This is the point of no return */ 71284778508Sblueswir1 info->end_data = 0; 71384778508Sblueswir1 info->end_code = 0; 71484778508Sblueswir1 info->start_mmap = (abi_ulong)ELF_START_MMAP; 71584778508Sblueswir1 info->mmap = 0; 71684778508Sblueswir1 elf_entry = (abi_ulong) elf_ex.e_entry; 71784778508Sblueswir1 71884778508Sblueswir1 /* Do this so that we can load the interpreter, if need be. We will 71984778508Sblueswir1 change some of these later */ 72084778508Sblueswir1 info->rss = 0; 72198b34d35SWarner Losh setup_arg_pages(bprm, info, &bprm->p, &bprm->stringp); 72284778508Sblueswir1 info->start_stack = bprm->p; 72384778508Sblueswir1 72484778508Sblueswir1 /* Now we do a little grungy work by mmaping the ELF image into 72584778508Sblueswir1 * the correct location in memory. At this point, we assume that 72684778508Sblueswir1 * the image should be loaded at fixed address, not at a variable 72784778508Sblueswir1 * address. 72884778508Sblueswir1 */ 72984778508Sblueswir1 73084778508Sblueswir1 for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { 73184778508Sblueswir1 int elf_prot = 0; 73284778508Sblueswir1 int elf_flags = 0; 73384778508Sblueswir1 abi_ulong error; 73484778508Sblueswir1 73584778508Sblueswir1 if (elf_ppnt->p_type != PT_LOAD) 73684778508Sblueswir1 continue; 73784778508Sblueswir1 73884778508Sblueswir1 if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; 73984778508Sblueswir1 if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; 74084778508Sblueswir1 if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; 74184778508Sblueswir1 elf_flags = MAP_PRIVATE | MAP_DENYWRITE; 74284778508Sblueswir1 if (elf_ex.e_type == ET_EXEC || load_addr_set) { 74384778508Sblueswir1 elf_flags |= MAP_FIXED; 74484778508Sblueswir1 } else if (elf_ex.e_type == ET_DYN) { 74584778508Sblueswir1 /* Try and get dynamic programs out of the way of the default mmap 74684778508Sblueswir1 base, as well as whatever program they might try to exec. This 74784778508Sblueswir1 is because the brk will follow the loader, and is not movable. */ 74884778508Sblueswir1 /* NOTE: for qemu, we do a big mmap to get enough space 74984778508Sblueswir1 without hardcoding any address */ 75084778508Sblueswir1 error = target_mmap(0, ET_DYN_MAP_SIZE, 75184778508Sblueswir1 PROT_NONE, MAP_PRIVATE | MAP_ANON, 75284778508Sblueswir1 -1, 0); 75384778508Sblueswir1 if (error == -1) { 75484778508Sblueswir1 perror("mmap"); 75584778508Sblueswir1 exit(-1); 75684778508Sblueswir1 } 75784778508Sblueswir1 load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr); 75884778508Sblueswir1 } 75984778508Sblueswir1 76084778508Sblueswir1 error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), 76184778508Sblueswir1 (elf_ppnt->p_filesz + 76284778508Sblueswir1 TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), 76384778508Sblueswir1 elf_prot, 76484778508Sblueswir1 (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), 76584778508Sblueswir1 bprm->fd, 76684778508Sblueswir1 (elf_ppnt->p_offset - 76784778508Sblueswir1 TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); 76884778508Sblueswir1 if (error == -1) { 76984778508Sblueswir1 perror("mmap"); 77084778508Sblueswir1 exit(-1); 77184778508Sblueswir1 } 77284778508Sblueswir1 77384778508Sblueswir1 if (!load_addr_set) { 77484778508Sblueswir1 load_addr_set = 1; 77584778508Sblueswir1 load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; 77684778508Sblueswir1 if (elf_ex.e_type == ET_DYN) { 77784778508Sblueswir1 load_bias += error - 77884778508Sblueswir1 TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); 77984778508Sblueswir1 load_addr += load_bias; 78084778508Sblueswir1 reloc_func_desc = load_bias; 78184778508Sblueswir1 } 78284778508Sblueswir1 } 78384778508Sblueswir1 k = elf_ppnt->p_vaddr; 78484778508Sblueswir1 if (k < start_code) 78584778508Sblueswir1 start_code = k; 78684778508Sblueswir1 if (start_data < k) 78784778508Sblueswir1 start_data = k; 78884778508Sblueswir1 k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; 78984778508Sblueswir1 if (k > elf_bss) 79084778508Sblueswir1 elf_bss = k; 79184778508Sblueswir1 if ((elf_ppnt->p_flags & PF_X) && end_code < k) 79284778508Sblueswir1 end_code = k; 79384778508Sblueswir1 if (end_data < k) 79484778508Sblueswir1 end_data = k; 79584778508Sblueswir1 k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; 79684778508Sblueswir1 if (k > elf_brk) elf_brk = k; 79784778508Sblueswir1 } 79884778508Sblueswir1 79984778508Sblueswir1 elf_entry += load_bias; 80084778508Sblueswir1 elf_bss += load_bias; 80184778508Sblueswir1 elf_brk += load_bias; 80284778508Sblueswir1 start_code += load_bias; 80384778508Sblueswir1 end_code += load_bias; 80484778508Sblueswir1 start_data += load_bias; 80584778508Sblueswir1 end_data += load_bias; 80684778508Sblueswir1 80784778508Sblueswir1 if (elf_interpreter) { 80884778508Sblueswir1 elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, 80984778508Sblueswir1 &interp_load_addr); 81084778508Sblueswir1 reloc_func_desc = interp_load_addr; 81184778508Sblueswir1 81284778508Sblueswir1 close(interpreter_fd); 81384778508Sblueswir1 free(elf_interpreter); 81484778508Sblueswir1 81584778508Sblueswir1 if (elf_entry == ~((abi_ulong)0UL)) { 81684778508Sblueswir1 printf("Unable to load interpreter\n"); 81784778508Sblueswir1 free(elf_phdata); 81884778508Sblueswir1 exit(-1); 81984778508Sblueswir1 return 0; 82084778508Sblueswir1 } 82184778508Sblueswir1 } 82284778508Sblueswir1 82384778508Sblueswir1 free(elf_phdata); 82484778508Sblueswir1 82593fcfe39Saliguori if (qemu_log_enabled()) 82684778508Sblueswir1 load_symbols(&elf_ex, bprm->fd); 82784778508Sblueswir1 828ffa03665SWarner Losh close(bprm->fd); 82984778508Sblueswir1 83098b34d35SWarner Losh bprm->p = target_create_elf_tables(bprm->p, bprm->argc, bprm->envc, 83198b34d35SWarner Losh bprm->stringp, &elf_ex, load_addr, 83298b34d35SWarner Losh load_bias, interp_load_addr, info); 83384778508Sblueswir1 info->load_addr = reloc_func_desc; 83484778508Sblueswir1 info->start_brk = info->brk = elf_brk; 83584778508Sblueswir1 info->end_code = end_code; 83684778508Sblueswir1 info->start_code = start_code; 83784778508Sblueswir1 info->start_data = start_data; 83884778508Sblueswir1 info->end_data = end_data; 83984778508Sblueswir1 info->start_stack = bprm->p; 84084778508Sblueswir1 84184778508Sblueswir1 /* Calling set_brk effectively mmaps the pages that we need for the bss and break 84284778508Sblueswir1 sections */ 84384778508Sblueswir1 set_brk(elf_bss, elf_brk); 84484778508Sblueswir1 84584778508Sblueswir1 padzero(elf_bss, elf_brk); 84684778508Sblueswir1 84784778508Sblueswir1 info->entry = elf_entry; 84884778508Sblueswir1 849*0475f8faSWarner Losh #ifdef USE_ELF_CORE_DUMP 850*0475f8faSWarner Losh bprm->core_dump = &elf_core_dump; 851*0475f8faSWarner Losh #else 852*0475f8faSWarner Losh bprm->core_dump = NULL; 853*0475f8faSWarner Losh #endif 854*0475f8faSWarner Losh 85584778508Sblueswir1 return 0; 85684778508Sblueswir1 } 85784778508Sblueswir1 85884778508Sblueswir1 void do_init_thread(struct target_pt_regs *regs, struct image_info *infop) 85984778508Sblueswir1 { 860a8fe6d5dSWarner Losh 861a8fe6d5dSWarner Losh target_thread_init(regs, infop); 86284778508Sblueswir1 } 863