xref: /qemu/bsd-user/elfload.c (revision 0475f8fa)
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