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
290475f8faSWarner 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"
330475f8faSWarner Losh #include "target_os_user.h"
3484778508Sblueswir1
3598b34d35SWarner Losh abi_ulong target_stksiz;
3698b34d35SWarner Losh abi_ulong target_stkbas;
3784778508Sblueswir1
380475f8faSWarner Losh static int elf_core_dump(int signr, CPUArchState *env);
39c09f12feSWarner Losh static int load_elf_sections(const struct elfhdr *hdr, struct elf_phdr *phdr,
40c09f12feSWarner Losh int fd, abi_ulong rbase, abi_ulong *baddrp);
410475f8faSWarner Losh
memcpy_fromfs(void * to,const void * from,unsigned long n)4284778508Sblueswir1 static inline void memcpy_fromfs(void *to, const void *from, unsigned long n)
4384778508Sblueswir1 {
4484778508Sblueswir1 memcpy(to, from, n);
4584778508Sblueswir1 }
4684778508Sblueswir1
4784778508Sblueswir1 #ifdef BSWAP_NEEDED
bswap_ehdr(struct elfhdr * ehdr)4884778508Sblueswir1 static void bswap_ehdr(struct elfhdr *ehdr)
4984778508Sblueswir1 {
5084778508Sblueswir1 bswap16s(&ehdr->e_type); /* Object file type */
5184778508Sblueswir1 bswap16s(&ehdr->e_machine); /* Architecture */
5284778508Sblueswir1 bswap32s(&ehdr->e_version); /* Object file version */
5384778508Sblueswir1 bswaptls(&ehdr->e_entry); /* Entry point virtual address */
5484778508Sblueswir1 bswaptls(&ehdr->e_phoff); /* Program header table file offset */
5584778508Sblueswir1 bswaptls(&ehdr->e_shoff); /* Section header table file offset */
5684778508Sblueswir1 bswap32s(&ehdr->e_flags); /* Processor-specific flags */
5784778508Sblueswir1 bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */
5884778508Sblueswir1 bswap16s(&ehdr->e_phentsize); /* Program header table entry size */
5984778508Sblueswir1 bswap16s(&ehdr->e_phnum); /* Program header table entry count */
6084778508Sblueswir1 bswap16s(&ehdr->e_shentsize); /* Section header table entry size */
6184778508Sblueswir1 bswap16s(&ehdr->e_shnum); /* Section header table entry count */
6284778508Sblueswir1 bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
6384778508Sblueswir1 }
6484778508Sblueswir1
bswap_phdr(struct elf_phdr * phdr,int phnum)65b62f790cSWarner Losh static void bswap_phdr(struct elf_phdr *phdr, int phnum)
6684778508Sblueswir1 {
67b62f790cSWarner Losh int i;
68b62f790cSWarner Losh
69b62f790cSWarner Losh for (i = 0; i < phnum; i++, phdr++) {
7084778508Sblueswir1 bswap32s(&phdr->p_type); /* Segment type */
71b62f790cSWarner Losh bswap32s(&phdr->p_flags); /* Segment flags */
7284778508Sblueswir1 bswaptls(&phdr->p_offset); /* Segment file offset */
7384778508Sblueswir1 bswaptls(&phdr->p_vaddr); /* Segment virtual address */
7484778508Sblueswir1 bswaptls(&phdr->p_paddr); /* Segment physical address */
7584778508Sblueswir1 bswaptls(&phdr->p_filesz); /* Segment size in file */
7684778508Sblueswir1 bswaptls(&phdr->p_memsz); /* Segment size in memory */
7784778508Sblueswir1 bswaptls(&phdr->p_align); /* Segment alignment */
7884778508Sblueswir1 }
79b62f790cSWarner Losh }
8084778508Sblueswir1
bswap_shdr(struct elf_shdr * shdr,int shnum)81b62f790cSWarner Losh static void bswap_shdr(struct elf_shdr *shdr, int shnum)
8284778508Sblueswir1 {
83b62f790cSWarner Losh int i;
84b62f790cSWarner Losh
85b62f790cSWarner Losh for (i = 0; i < shnum; i++, shdr++) {
8684778508Sblueswir1 bswap32s(&shdr->sh_name);
8784778508Sblueswir1 bswap32s(&shdr->sh_type);
8884778508Sblueswir1 bswaptls(&shdr->sh_flags);
8984778508Sblueswir1 bswaptls(&shdr->sh_addr);
9084778508Sblueswir1 bswaptls(&shdr->sh_offset);
9184778508Sblueswir1 bswaptls(&shdr->sh_size);
9284778508Sblueswir1 bswap32s(&shdr->sh_link);
9384778508Sblueswir1 bswap32s(&shdr->sh_info);
9484778508Sblueswir1 bswaptls(&shdr->sh_addralign);
9584778508Sblueswir1 bswaptls(&shdr->sh_entsize);
9684778508Sblueswir1 }
97b62f790cSWarner Losh }
9884778508Sblueswir1
bswap_sym(struct elf_sym * sym)9984778508Sblueswir1 static void bswap_sym(struct elf_sym *sym)
10084778508Sblueswir1 {
10184778508Sblueswir1 bswap32s(&sym->st_name);
10284778508Sblueswir1 bswaptls(&sym->st_value);
10384778508Sblueswir1 bswaptls(&sym->st_size);
10484778508Sblueswir1 bswap16s(&sym->st_shndx);
10584778508Sblueswir1 }
106b62f790cSWarner Losh
bswap_note(struct elf_note * en)1070475f8faSWarner Losh static void bswap_note(struct elf_note *en)
1080475f8faSWarner Losh {
1090475f8faSWarner Losh bswap32s(&en->n_namesz);
1100475f8faSWarner Losh bswap32s(&en->n_descsz);
1110475f8faSWarner Losh bswap32s(&en->n_type);
1120475f8faSWarner Losh }
1130475f8faSWarner Losh
114b62f790cSWarner Losh #else /* ! BSWAP_NEEDED */
115b62f790cSWarner Losh
bswap_ehdr(struct elfhdr * ehdr)116b62f790cSWarner Losh static void bswap_ehdr(struct elfhdr *ehdr) { }
bswap_phdr(struct elf_phdr * phdr,int phnum)117b62f790cSWarner Losh static void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
bswap_shdr(struct elf_shdr * shdr,int shnum)118b62f790cSWarner Losh static void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
bswap_sym(struct elf_sym * sym)119b62f790cSWarner Losh static void bswap_sym(struct elf_sym *sym) { }
bswap_note(struct elf_note * en)1200475f8faSWarner Losh static void bswap_note(struct elf_note *en) { }
121b62f790cSWarner Losh
122b62f790cSWarner Losh #endif /* ! BSWAP_NEEDED */
12384778508Sblueswir1
1240475f8faSWarner Losh #include "elfcore.c"
1250475f8faSWarner Losh
12684778508Sblueswir1 /*
12784778508Sblueswir1 * 'copy_elf_strings()' copies argument/envelope strings from user
12884778508Sblueswir1 * memory to free pages in kernel mem. These are in a format ready
12984778508Sblueswir1 * to be put directly into the top of new user memory.
13084778508Sblueswir1 *
13184778508Sblueswir1 */
copy_elf_strings(int argc,char ** argv,void ** page,abi_ulong p)13284778508Sblueswir1 static abi_ulong copy_elf_strings(int argc, char **argv, void **page,
13384778508Sblueswir1 abi_ulong p)
13484778508Sblueswir1 {
13584778508Sblueswir1 char *tmp, *tmp1, *pag = NULL;
13684778508Sblueswir1 int len, offset = 0;
13784778508Sblueswir1
13884778508Sblueswir1 if (!p) {
13984778508Sblueswir1 return 0; /* bullet-proofing */
14084778508Sblueswir1 }
14184778508Sblueswir1 while (argc-- > 0) {
14284778508Sblueswir1 tmp = argv[argc];
14384778508Sblueswir1 if (!tmp) {
1449bb93180SPeter Maydell fprintf(stderr, "VFS: argc is wrong");
14584778508Sblueswir1 exit(-1);
14684778508Sblueswir1 }
14784778508Sblueswir1 tmp1 = tmp;
1480456a177SWarner Losh while (*tmp++) {
1490456a177SWarner Losh continue;
1500456a177SWarner Losh }
15184778508Sblueswir1 len = tmp - tmp1;
15284778508Sblueswir1 if (p < len) { /* this shouldn't happen - 128kB */
15384778508Sblueswir1 return 0;
15484778508Sblueswir1 }
15584778508Sblueswir1 while (len) {
15684778508Sblueswir1 --p; --tmp; --len;
15784778508Sblueswir1 if (--offset < 0) {
15884778508Sblueswir1 offset = p % TARGET_PAGE_SIZE;
1593d558330SMarkus Armbruster pag = page[p / TARGET_PAGE_SIZE];
16084778508Sblueswir1 if (!pag) {
161c580dee4SStefan Weil pag = g_try_malloc0(TARGET_PAGE_SIZE);
16284778508Sblueswir1 page[p / TARGET_PAGE_SIZE] = pag;
1630456a177SWarner Losh if (!pag) {
16484778508Sblueswir1 return 0;
16584778508Sblueswir1 }
16684778508Sblueswir1 }
1670456a177SWarner Losh }
16884778508Sblueswir1 if (len == 0 || offset == 0) {
16984778508Sblueswir1 *(pag + offset) = *tmp;
1700456a177SWarner Losh } else {
17184778508Sblueswir1 int bytes_to_copy = (len > offset) ? offset : len;
17284778508Sblueswir1 tmp -= bytes_to_copy;
17384778508Sblueswir1 p -= bytes_to_copy;
17484778508Sblueswir1 offset -= bytes_to_copy;
17584778508Sblueswir1 len -= bytes_to_copy;
17684778508Sblueswir1 memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
17784778508Sblueswir1 }
17884778508Sblueswir1 }
17984778508Sblueswir1 }
18084778508Sblueswir1 return p;
18184778508Sblueswir1 }
18284778508Sblueswir1
setup_arg_pages(struct bsd_binprm * bprm,struct image_info * info,abi_ulong * stackp,abi_ulong * stringp)18398b34d35SWarner Losh static void setup_arg_pages(struct bsd_binprm *bprm, struct image_info *info,
18498b34d35SWarner Losh abi_ulong *stackp, abi_ulong *stringp)
18584778508Sblueswir1 {
18698b34d35SWarner Losh abi_ulong stack_base, size;
18798b34d35SWarner Losh abi_long addr;
18884778508Sblueswir1
1890456a177SWarner Losh /*
1900456a177SWarner Losh * Create enough stack to hold everything. If we don't use it for args,
1910456a177SWarner Losh * we'll use it for something else...
19284778508Sblueswir1 */
193312a0b1cSWarner Losh size = target_dflssiz;
19498b34d35SWarner Losh stack_base = TARGET_USRSTACK - size;
1950456a177SWarner Losh addr = target_mmap(stack_base , size + qemu_host_page_size,
1960456a177SWarner Losh PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
19798b34d35SWarner Losh if (addr == -1) {
19884778508Sblueswir1 perror("stk mmap");
19984778508Sblueswir1 exit(-1);
20084778508Sblueswir1 }
20184778508Sblueswir1 /* we reserve one extra page at the top of the stack as guard */
20298b34d35SWarner Losh target_mprotect(addr + size, qemu_host_page_size, PROT_NONE);
20384778508Sblueswir1
20498b34d35SWarner Losh target_stksiz = size;
20598b34d35SWarner Losh target_stkbas = addr;
20684778508Sblueswir1
20798b34d35SWarner Losh if (setup_initial_stack(bprm, stackp, stringp) != 0) {
20898b34d35SWarner Losh perror("stk setup");
20998b34d35SWarner Losh exit(-1);
21084778508Sblueswir1 }
21184778508Sblueswir1 }
21284778508Sblueswir1
set_brk(abi_ulong start,abi_ulong end)21384778508Sblueswir1 static void set_brk(abi_ulong start, abi_ulong end)
21484778508Sblueswir1 {
21584778508Sblueswir1 /* page-align the start and end addresses... */
21684778508Sblueswir1 start = HOST_PAGE_ALIGN(start);
21784778508Sblueswir1 end = HOST_PAGE_ALIGN(end);
2180456a177SWarner Losh if (end <= start) {
21984778508Sblueswir1 return;
2200456a177SWarner Losh }
2210456a177SWarner Losh if (target_mmap(start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC,
22284778508Sblueswir1 MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0) == -1) {
22384778508Sblueswir1 perror("cannot mmap brk");
22484778508Sblueswir1 exit(-1);
22584778508Sblueswir1 }
22684778508Sblueswir1 }
22784778508Sblueswir1
22884778508Sblueswir1
2290456a177SWarner Losh /*
2300456a177SWarner Losh * We need to explicitly zero any fractional pages after the data
2310456a177SWarner Losh * section (i.e. bss). This would contain the junk from the file that
2320456a177SWarner Losh * should not be in memory.
2330456a177SWarner Losh */
padzero(abi_ulong elf_bss,abi_ulong last_bss)23484778508Sblueswir1 static void padzero(abi_ulong elf_bss, abi_ulong last_bss)
23584778508Sblueswir1 {
23684778508Sblueswir1 abi_ulong nbyte;
23784778508Sblueswir1
2380456a177SWarner Losh if (elf_bss >= last_bss) {
23984778508Sblueswir1 return;
2400456a177SWarner Losh }
24184778508Sblueswir1
2420456a177SWarner Losh /*
2430456a177SWarner Losh * XXX: this is really a hack : if the real host page size is
2440456a177SWarner Losh * smaller than the target page size, some pages after the end
2450456a177SWarner Losh * of the file may not be mapped. A better fix would be to
2460456a177SWarner Losh * patch target_mmap(), but it is more complicated as the file
2470456a177SWarner Losh * size must be known.
2480456a177SWarner Losh */
2498e3b0cbbSMarc-André Lureau if (qemu_real_host_page_size() < qemu_host_page_size) {
25084778508Sblueswir1 abi_ulong end_addr, end_addr1;
2510c2d70c4SPaolo Bonzini end_addr1 = REAL_HOST_PAGE_ALIGN(elf_bss);
25284778508Sblueswir1 end_addr = HOST_PAGE_ALIGN(elf_bss);
25384778508Sblueswir1 if (end_addr1 < end_addr) {
2543e8f1628SRichard Henderson mmap((void *)g2h_untagged(end_addr1), end_addr - end_addr1,
25584778508Sblueswir1 PROT_READ | PROT_WRITE | PROT_EXEC,
25684778508Sblueswir1 MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
25784778508Sblueswir1 }
25884778508Sblueswir1 }
25984778508Sblueswir1
26084778508Sblueswir1 nbyte = elf_bss & (qemu_host_page_size - 1);
26184778508Sblueswir1 if (nbyte) {
26284778508Sblueswir1 nbyte = qemu_host_page_size - nbyte;
26384778508Sblueswir1 do {
26484778508Sblueswir1 /* FIXME - what to do if put_user() fails? */
26584778508Sblueswir1 put_user_u8(0, elf_bss);
26684778508Sblueswir1 elf_bss++;
26784778508Sblueswir1 } while (--nbyte);
26884778508Sblueswir1 }
26984778508Sblueswir1 }
27084778508Sblueswir1
load_elf_interp(struct elfhdr * interp_elf_ex,int interpreter_fd,abi_ulong * interp_load_addr)27184778508Sblueswir1 static abi_ulong load_elf_interp(struct elfhdr *interp_elf_ex,
27284778508Sblueswir1 int interpreter_fd,
27384778508Sblueswir1 abi_ulong *interp_load_addr)
27484778508Sblueswir1 {
27584778508Sblueswir1 struct elf_phdr *elf_phdata = NULL;
276c09f12feSWarner Losh abi_ulong rbase;
27784778508Sblueswir1 int retval;
278c09f12feSWarner Losh abi_ulong baddr, error;
27984778508Sblueswir1
28084778508Sblueswir1 error = 0;
28184778508Sblueswir1
28284778508Sblueswir1 bswap_ehdr(interp_elf_ex);
28384778508Sblueswir1 /* First of all, some simple consistency checks */
2840456a177SWarner Losh if ((interp_elf_ex->e_type != ET_EXEC && 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 */
2910456a177SWarner Losh if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) {
29284778508Sblueswir1 return ~(abi_ulong)0UL;
2930456a177SWarner Losh }
29484778508Sblueswir1
2950456a177SWarner Losh elf_phdata = (struct elf_phdr *) malloc(sizeof(struct elf_phdr) *
2960456a177SWarner Losh interp_elf_ex->e_phnum);
29784778508Sblueswir1
2980456a177SWarner Losh if (!elf_phdata) {
29984778508Sblueswir1 return ~((abi_ulong)0UL);
3000456a177SWarner Losh }
30184778508Sblueswir1
30284778508Sblueswir1 /*
30384778508Sblueswir1 * If the size of this structure has changed, then punt, since
30484778508Sblueswir1 * we will be doing the wrong thing.
30584778508Sblueswir1 */
30684778508Sblueswir1 if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
30784778508Sblueswir1 free(elf_phdata);
30884778508Sblueswir1 return ~((abi_ulong)0UL);
30984778508Sblueswir1 }
31084778508Sblueswir1
31184778508Sblueswir1 retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
31284778508Sblueswir1 if (retval >= 0) {
3130456a177SWarner Losh retval = read(interpreter_fd, (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
324c09f12feSWarner Losh rbase = 0;
32584778508Sblueswir1 if (interp_elf_ex->e_type == ET_DYN) {
3260456a177SWarner Losh /*
3270456a177SWarner Losh * In order to avoid hardcoding the interpreter load
3280456a177SWarner Losh * address in qemu, we allocate a big enough memory zone.
3290456a177SWarner Losh */
330c09f12feSWarner Losh rbase = target_mmap(0, INTERP_MAP_SIZE, PROT_NONE,
3310456a177SWarner Losh MAP_PRIVATE | MAP_ANON, -1, 0);
332c09f12feSWarner Losh if (rbase == -1) {
33384778508Sblueswir1 perror("mmap");
33484778508Sblueswir1 exit(-1);
33584778508Sblueswir1 }
33684778508Sblueswir1 }
33784778508Sblueswir1
338c09f12feSWarner Losh error = load_elf_sections(interp_elf_ex, elf_phdata, interpreter_fd, rbase,
339c09f12feSWarner Losh &baddr);
340c09f12feSWarner Losh if (error != 0) {
341c09f12feSWarner Losh perror("load_elf_sections");
342c09f12feSWarner Losh exit(-1);
34384778508Sblueswir1 }
34484778508Sblueswir1
34584778508Sblueswir1 /* Now use mmap to map the library into memory. */
34684778508Sblueswir1 close(interpreter_fd);
34784778508Sblueswir1 free(elf_phdata);
34884778508Sblueswir1
349c09f12feSWarner Losh *interp_load_addr = baddr;
350c09f12feSWarner Losh return ((abi_ulong) interp_elf_ex->e_entry) + rbase;
35184778508Sblueswir1 }
35284778508Sblueswir1
symfind(const void * s0,const void * s1)35384778508Sblueswir1 static int symfind(const void *s0, const void *s1)
35484778508Sblueswir1 {
35584778508Sblueswir1 struct elf_sym *sym = (struct elf_sym *)s1;
356b6235a75SRichard Henderson __typeof(sym->st_value) addr = *(uint64_t *)s0;
35784778508Sblueswir1 int result = 0;
358b6235a75SRichard Henderson
359c7c530cdSStefan Weil if (addr < sym->st_value) {
36084778508Sblueswir1 result = -1;
361c7c530cdSStefan Weil } else if (addr >= sym->st_value + sym->st_size) {
36284778508Sblueswir1 result = 1;
36384778508Sblueswir1 }
36484778508Sblueswir1 return result;
36584778508Sblueswir1 }
36684778508Sblueswir1
lookup_symbolxx(struct syminfo * s,uint64_t orig_addr)367b6235a75SRichard Henderson static const char *lookup_symbolxx(struct syminfo *s, uint64_t orig_addr)
36884778508Sblueswir1 {
36984778508Sblueswir1 #if ELF_CLASS == ELFCLASS32
37084778508Sblueswir1 struct elf_sym *syms = s->disas_symtab.elf32;
37184778508Sblueswir1 #else
37284778508Sblueswir1 struct elf_sym *syms = s->disas_symtab.elf64;
37384778508Sblueswir1 #endif
37484778508Sblueswir1
3750456a177SWarner Losh /* binary search */
37684778508Sblueswir1 struct elf_sym *sym;
37784778508Sblueswir1
378c7c530cdSStefan Weil sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms), symfind);
3797cba04f6SBlue Swirl if (sym != NULL) {
38084778508Sblueswir1 return s->disas_strtab + sym->st_name;
38184778508Sblueswir1 }
38284778508Sblueswir1
38384778508Sblueswir1 return "";
38484778508Sblueswir1 }
38584778508Sblueswir1
386159fb790SPhilippe Mathieu-Daudé /* FIXME: This should use elf_ops.h.inc */
symcmp(const void * s0,const void * s1)38784778508Sblueswir1 static int symcmp(const void *s0, const void *s1)
38884778508Sblueswir1 {
38984778508Sblueswir1 struct elf_sym *sym0 = (struct elf_sym *)s0;
39084778508Sblueswir1 struct elf_sym *sym1 = (struct elf_sym *)s1;
3910456a177SWarner Losh return (sym0->st_value < sym1->st_value) ? -1 :
3920456a177SWarner Losh ((sym0->st_value > sym1->st_value) ? 1 : 0);
39384778508Sblueswir1 }
39484778508Sblueswir1
39584778508Sblueswir1 /* Best attempt to load symbols from this ELF object. */
load_symbols(struct elfhdr * hdr,int fd)39684778508Sblueswir1 static void load_symbols(struct elfhdr *hdr, int fd)
39784778508Sblueswir1 {
39884778508Sblueswir1 unsigned int i, nsyms;
39984778508Sblueswir1 struct elf_shdr sechdr, symtab, strtab;
40084778508Sblueswir1 char *strings;
40184778508Sblueswir1 struct syminfo *s;
40229718712SStefan Weil struct elf_sym *syms, *new_syms;
40384778508Sblueswir1
40484778508Sblueswir1 lseek(fd, hdr->e_shoff, SEEK_SET);
40584778508Sblueswir1 for (i = 0; i < hdr->e_shnum; i++) {
4060456a177SWarner Losh if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) {
40784778508Sblueswir1 return;
4080456a177SWarner Losh }
409b62f790cSWarner Losh bswap_shdr(&sechdr, 1);
41084778508Sblueswir1 if (sechdr.sh_type == SHT_SYMTAB) {
41184778508Sblueswir1 symtab = sechdr;
4120456a177SWarner Losh lseek(fd, hdr->e_shoff + sizeof(sechdr) * sechdr.sh_link,
4130456a177SWarner Losh SEEK_SET);
4140456a177SWarner Losh if (read(fd, &strtab, sizeof(strtab)) != sizeof(strtab)) {
41584778508Sblueswir1 return;
4160456a177SWarner Losh }
417b62f790cSWarner Losh bswap_shdr(&strtab, 1);
41884778508Sblueswir1 goto found;
41984778508Sblueswir1 }
42084778508Sblueswir1 }
42184778508Sblueswir1 return; /* Shouldn't happen... */
42284778508Sblueswir1
42384778508Sblueswir1 found:
42484778508Sblueswir1 /* Now know where the strtab and symtab are. Snarf them. */
42584778508Sblueswir1 s = malloc(sizeof(*s));
42684778508Sblueswir1 syms = malloc(symtab.sh_size);
42729718712SStefan Weil if (!syms) {
42829718712SStefan Weil free(s);
42984778508Sblueswir1 return;
43029718712SStefan Weil }
43184778508Sblueswir1 s->disas_strtab = strings = malloc(strtab.sh_size);
43229718712SStefan Weil if (!s->disas_strtab) {
43329718712SStefan Weil free(s);
43429718712SStefan Weil free(syms);
43584778508Sblueswir1 return;
43629718712SStefan Weil }
43784778508Sblueswir1
43884778508Sblueswir1 lseek(fd, symtab.sh_offset, SEEK_SET);
43929718712SStefan Weil if (read(fd, syms, symtab.sh_size) != symtab.sh_size) {
44029718712SStefan Weil free(s);
44129718712SStefan Weil free(syms);
44229718712SStefan Weil free(strings);
44384778508Sblueswir1 return;
44429718712SStefan Weil }
44584778508Sblueswir1
44684778508Sblueswir1 nsyms = symtab.sh_size / sizeof(struct elf_sym);
44784778508Sblueswir1
44884778508Sblueswir1 i = 0;
44984778508Sblueswir1 while (i < nsyms) {
45084778508Sblueswir1 bswap_sym(syms + i);
4510456a177SWarner Losh /* Throw away entries which we do not need. */
45284778508Sblueswir1 if (syms[i].st_shndx == SHN_UNDEF ||
45384778508Sblueswir1 syms[i].st_shndx >= SHN_LORESERVE ||
45484778508Sblueswir1 ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
45584778508Sblueswir1 nsyms--;
45684778508Sblueswir1 if (i < nsyms) {
45784778508Sblueswir1 syms[i] = syms[nsyms];
45884778508Sblueswir1 }
45984778508Sblueswir1 continue;
46084778508Sblueswir1 }
461c09f12feSWarner Losh #if defined(TARGET_ARM) || defined(TARGET_MIPS)
462c09f12feSWarner Losh /* The bottom address bit marks a Thumb or MIPS16 symbol. */
463c09f12feSWarner Losh syms[i].st_value &= ~(target_ulong)1;
464c09f12feSWarner Losh #endif
46584778508Sblueswir1 i++;
46684778508Sblueswir1 }
46729718712SStefan Weil
4680456a177SWarner Losh /*
4690456a177SWarner Losh * Attempt to free the storage associated with the local symbols
4700456a177SWarner Losh * that we threw away. Whether or not this has any effect on the
4710456a177SWarner Losh * memory allocation depends on the malloc implementation and how
4720456a177SWarner Losh * many symbols we managed to discard.
4730456a177SWarner Losh */
47429718712SStefan Weil new_syms = realloc(syms, nsyms * sizeof(*syms));
47529718712SStefan Weil if (new_syms == NULL) {
47629718712SStefan Weil free(s);
47729718712SStefan Weil free(syms);
47829718712SStefan Weil free(strings);
47929718712SStefan Weil return;
48029718712SStefan Weil }
48129718712SStefan Weil syms = new_syms;
48284778508Sblueswir1
48384778508Sblueswir1 qsort(syms, nsyms, sizeof(*syms), symcmp);
48484778508Sblueswir1
48584778508Sblueswir1 lseek(fd, strtab.sh_offset, SEEK_SET);
48629718712SStefan Weil if (read(fd, strings, strtab.sh_size) != strtab.sh_size) {
48729718712SStefan Weil free(s);
48829718712SStefan Weil free(syms);
48929718712SStefan Weil free(strings);
49084778508Sblueswir1 return;
49129718712SStefan Weil }
49284778508Sblueswir1 s->disas_num_syms = nsyms;
49384778508Sblueswir1 #if ELF_CLASS == ELFCLASS32
49484778508Sblueswir1 s->disas_symtab.elf32 = syms;
495032e51d7SBlue Swirl s->lookup_symbol = (lookup_symbol_t)lookup_symbolxx;
49684778508Sblueswir1 #else
49784778508Sblueswir1 s->disas_symtab.elf64 = syms;
498032e51d7SBlue Swirl s->lookup_symbol = (lookup_symbol_t)lookup_symbolxx;
49984778508Sblueswir1 #endif
50084778508Sblueswir1 s->next = syminfos;
50184778508Sblueswir1 syminfos = s;
50284778508Sblueswir1 }
50384778508Sblueswir1
504c09f12feSWarner Losh /* Check the elf header and see if this a target elf binary. */
is_target_elf_binary(int fd)505c09f12feSWarner Losh int is_target_elf_binary(int fd)
506c09f12feSWarner Losh {
507c09f12feSWarner Losh uint8_t buf[128];
508c09f12feSWarner Losh struct elfhdr elf_ex;
509c09f12feSWarner Losh
510c09f12feSWarner Losh if (lseek(fd, 0L, SEEK_SET) < 0) {
511c09f12feSWarner Losh return 0;
512c09f12feSWarner Losh }
513c09f12feSWarner Losh if (read(fd, buf, sizeof(buf)) < 0) {
514c09f12feSWarner Losh return 0;
515c09f12feSWarner Losh }
516c09f12feSWarner Losh
517c09f12feSWarner Losh elf_ex = *((struct elfhdr *)buf);
518c09f12feSWarner Losh bswap_ehdr(&elf_ex);
519c09f12feSWarner Losh
520c09f12feSWarner Losh if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
521c09f12feSWarner Losh (!elf_check_arch(elf_ex.e_machine))) {
522c09f12feSWarner Losh return 0;
523c09f12feSWarner Losh } else {
524c09f12feSWarner Losh return 1;
525c09f12feSWarner Losh }
526c09f12feSWarner Losh }
527c09f12feSWarner Losh
528c09f12feSWarner Losh static int
load_elf_sections(const struct elfhdr * hdr,struct elf_phdr * phdr,int fd,abi_ulong rbase,abi_ulong * baddrp)529c09f12feSWarner Losh load_elf_sections(const struct elfhdr *hdr, struct elf_phdr *phdr, int fd,
530c09f12feSWarner Losh abi_ulong rbase, abi_ulong *baddrp)
531c09f12feSWarner Losh {
532c09f12feSWarner Losh struct elf_phdr *elf_ppnt;
533c09f12feSWarner Losh abi_ulong baddr;
534c09f12feSWarner Losh int i;
535c09f12feSWarner Losh bool first;
536c09f12feSWarner Losh
537c09f12feSWarner Losh /*
538c09f12feSWarner Losh * Now we do a little grungy work by mmaping the ELF image into
539c09f12feSWarner Losh * the correct location in memory. At this point, we assume that
540c09f12feSWarner Losh * the image should be loaded at fixed address, not at a variable
541c09f12feSWarner Losh * address.
542c09f12feSWarner Losh */
543c09f12feSWarner Losh first = true;
544c09f12feSWarner Losh for (i = 0, elf_ppnt = phdr; i < hdr->e_phnum; i++, elf_ppnt++) {
545c09f12feSWarner Losh int elf_prot = 0;
546c09f12feSWarner Losh abi_ulong error;
547c09f12feSWarner Losh
548c09f12feSWarner Losh /* XXX Skip memsz == 0. */
549c09f12feSWarner Losh if (elf_ppnt->p_type != PT_LOAD) {
550c09f12feSWarner Losh continue;
551c09f12feSWarner Losh }
552c09f12feSWarner Losh
553c09f12feSWarner Losh if (elf_ppnt->p_flags & PF_R) {
554c09f12feSWarner Losh elf_prot |= PROT_READ;
555c09f12feSWarner Losh }
556c09f12feSWarner Losh if (elf_ppnt->p_flags & PF_W) {
557c09f12feSWarner Losh elf_prot |= PROT_WRITE;
558c09f12feSWarner Losh }
559c09f12feSWarner Losh if (elf_ppnt->p_flags & PF_X) {
560c09f12feSWarner Losh elf_prot |= PROT_EXEC;
561c09f12feSWarner Losh }
562c09f12feSWarner Losh
563c09f12feSWarner Losh error = target_mmap(TARGET_ELF_PAGESTART(rbase + elf_ppnt->p_vaddr),
564c09f12feSWarner Losh (elf_ppnt->p_filesz +
565c09f12feSWarner Losh TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
566c09f12feSWarner Losh elf_prot,
567c09f12feSWarner Losh (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
568c09f12feSWarner Losh fd,
569c09f12feSWarner Losh (elf_ppnt->p_offset -
570c09f12feSWarner Losh TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
571c09f12feSWarner Losh if (error == -1) {
572c09f12feSWarner Losh perror("mmap");
573c09f12feSWarner Losh exit(-1);
574c09f12feSWarner Losh } else if (elf_ppnt->p_memsz != elf_ppnt->p_filesz) {
575c09f12feSWarner Losh abi_ulong start_bss, end_bss;
576c09f12feSWarner Losh
577c09f12feSWarner Losh start_bss = rbase + elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
578c09f12feSWarner Losh end_bss = rbase + elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
579c09f12feSWarner Losh
580c09f12feSWarner Losh /*
581c09f12feSWarner Losh * Calling set_brk effectively mmaps the pages that we need for the
582c09f12feSWarner Losh * bss and break sections.
583c09f12feSWarner Losh */
584c09f12feSWarner Losh set_brk(start_bss, end_bss);
585c09f12feSWarner Losh padzero(start_bss, end_bss);
586c09f12feSWarner Losh }
587c09f12feSWarner Losh
588c09f12feSWarner Losh if (first) {
589c09f12feSWarner Losh baddr = TARGET_ELF_PAGESTART(rbase + elf_ppnt->p_vaddr);
590c09f12feSWarner Losh first = false;
591c09f12feSWarner Losh }
592c09f12feSWarner Losh }
593c09f12feSWarner Losh
594c09f12feSWarner Losh if (baddrp != NULL) {
595c09f12feSWarner Losh *baddrp = baddr;
596c09f12feSWarner Losh }
597c09f12feSWarner Losh return 0;
598c09f12feSWarner Losh }
599c09f12feSWarner Losh
load_elf_binary(struct bsd_binprm * bprm,struct target_pt_regs * regs,struct image_info * info)600afcbcff8SWarner Losh int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
60184778508Sblueswir1 struct image_info *info)
60284778508Sblueswir1 {
60384778508Sblueswir1 struct elfhdr elf_ex;
60484778508Sblueswir1 struct elfhdr interp_elf_ex;
60584778508Sblueswir1 int interpreter_fd = -1; /* avoid warning */
606c09f12feSWarner Losh abi_ulong load_addr;
60784778508Sblueswir1 int i;
60884778508Sblueswir1 struct elf_phdr *elf_ppnt;
60984778508Sblueswir1 struct elf_phdr *elf_phdata;
610c09f12feSWarner Losh abi_ulong elf_brk;
611c09f12feSWarner Losh int error, retval;
61284778508Sblueswir1 char *elf_interpreter;
613c09f12feSWarner Losh abi_ulong baddr, elf_entry, et_dyn_addr, interp_load_addr = 0;
61484778508Sblueswir1 abi_ulong reloc_func_desc = 0;
61584778508Sblueswir1
61684778508Sblueswir1 load_addr = 0;
61784778508Sblueswir1 elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
61884778508Sblueswir1 bswap_ehdr(&elf_ex);
61984778508Sblueswir1
62084778508Sblueswir1 /* First of all, some simple consistency checks */
62184778508Sblueswir1 if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
62284778508Sblueswir1 (!elf_check_arch(elf_ex.e_machine))) {
62384778508Sblueswir1 return -ENOEXEC;
62484778508Sblueswir1 }
62584778508Sblueswir1
62684778508Sblueswir1 bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
62784778508Sblueswir1 bprm->p = copy_elf_strings(bprm->envc, bprm->envp, bprm->page, bprm->p);
62884778508Sblueswir1 bprm->p = copy_elf_strings(bprm->argc, bprm->argv, bprm->page, bprm->p);
62984778508Sblueswir1 if (!bprm->p) {
63084778508Sblueswir1 retval = -E2BIG;
63184778508Sblueswir1 }
63284778508Sblueswir1
63384778508Sblueswir1 /* Now read in all of the header information */
63484778508Sblueswir1 elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize * elf_ex.e_phnum);
63584778508Sblueswir1 if (elf_phdata == NULL) {
63684778508Sblueswir1 return -ENOMEM;
63784778508Sblueswir1 }
63884778508Sblueswir1
63984778508Sblueswir1 retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
64084778508Sblueswir1 if (retval > 0) {
64184778508Sblueswir1 retval = read(bprm->fd, (char *)elf_phdata,
64284778508Sblueswir1 elf_ex.e_phentsize * elf_ex.e_phnum);
64384778508Sblueswir1 }
64484778508Sblueswir1
64584778508Sblueswir1 if (retval < 0) {
64684778508Sblueswir1 perror("load_elf_binary");
64784778508Sblueswir1 exit(-1);
64884778508Sblueswir1 free(elf_phdata);
64984778508Sblueswir1 return -errno;
65084778508Sblueswir1 }
65184778508Sblueswir1
652b62f790cSWarner Losh bswap_phdr(elf_phdata, elf_ex.e_phnum);
65384778508Sblueswir1 elf_ppnt = elf_phdata;
65484778508Sblueswir1
65584778508Sblueswir1 elf_brk = 0;
65684778508Sblueswir1
65784778508Sblueswir1
65884778508Sblueswir1 elf_interpreter = NULL;
65984778508Sblueswir1 for (i = 0; i < elf_ex.e_phnum; i++) {
66084778508Sblueswir1 if (elf_ppnt->p_type == PT_INTERP) {
6610456a177SWarner Losh if (elf_interpreter != NULL) {
66284778508Sblueswir1 free(elf_phdata);
66384778508Sblueswir1 free(elf_interpreter);
66484778508Sblueswir1 close(bprm->fd);
66584778508Sblueswir1 return -EINVAL;
66684778508Sblueswir1 }
66784778508Sblueswir1
66884778508Sblueswir1 elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
66984778508Sblueswir1 if (elf_interpreter == NULL) {
67084778508Sblueswir1 free(elf_phdata);
67184778508Sblueswir1 close(bprm->fd);
67284778508Sblueswir1 return -ENOMEM;
67384778508Sblueswir1 }
67484778508Sblueswir1
67584778508Sblueswir1 retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
67684778508Sblueswir1 if (retval >= 0) {
67784778508Sblueswir1 retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
67884778508Sblueswir1 }
67984778508Sblueswir1 if (retval < 0) {
68084778508Sblueswir1 perror("load_elf_binary2");
68184778508Sblueswir1 exit(-1);
68284778508Sblueswir1 }
68384778508Sblueswir1
68484778508Sblueswir1 if (retval >= 0) {
68584778508Sblueswir1 retval = open(path(elf_interpreter), O_RDONLY);
68684778508Sblueswir1 if (retval >= 0) {
68784778508Sblueswir1 interpreter_fd = retval;
6880456a177SWarner Losh } else {
68984778508Sblueswir1 perror(elf_interpreter);
69084778508Sblueswir1 exit(-1);
69184778508Sblueswir1 /* retval = -errno; */
69284778508Sblueswir1 }
69384778508Sblueswir1 }
69484778508Sblueswir1
69584778508Sblueswir1 if (retval >= 0) {
69684778508Sblueswir1 retval = lseek(interpreter_fd, 0, SEEK_SET);
69784778508Sblueswir1 if (retval >= 0) {
69884778508Sblueswir1 retval = read(interpreter_fd, bprm->buf, 128);
69984778508Sblueswir1 }
70084778508Sblueswir1 }
70184778508Sblueswir1 if (retval >= 0) {
7020456a177SWarner Losh interp_elf_ex = *((struct elfhdr *) bprm->buf);
70384778508Sblueswir1 }
70484778508Sblueswir1 if (retval < 0) {
70584778508Sblueswir1 perror("load_elf_binary3");
70684778508Sblueswir1 exit(-1);
70784778508Sblueswir1 free(elf_phdata);
70884778508Sblueswir1 free(elf_interpreter);
70984778508Sblueswir1 close(bprm->fd);
71084778508Sblueswir1 return retval;
71184778508Sblueswir1 }
71284778508Sblueswir1 }
71384778508Sblueswir1 elf_ppnt++;
71484778508Sblueswir1 }
71584778508Sblueswir1
71684778508Sblueswir1 /* Some simple consistency checks for the interpreter */
71784778508Sblueswir1 if (elf_interpreter) {
71884778508Sblueswir1 if (interp_elf_ex.e_ident[0] != 0x7f ||
719fff2a02fSChristoph Egger strncmp((char *)&interp_elf_ex.e_ident[1], "ELF", 3) != 0) {
72084778508Sblueswir1 free(elf_interpreter);
72184778508Sblueswir1 free(elf_phdata);
72284778508Sblueswir1 close(bprm->fd);
72384778508Sblueswir1 return -ELIBBAD;
72484778508Sblueswir1 }
72584778508Sblueswir1 }
72684778508Sblueswir1
7270456a177SWarner Losh /*
7280456a177SWarner Losh * OK, we are done with that, now set up the arg stuff, and then start this
7290456a177SWarner Losh * sucker up
7300456a177SWarner Losh */
73184778508Sblueswir1 if (!bprm->p) {
73284778508Sblueswir1 free(elf_interpreter);
73384778508Sblueswir1 free(elf_phdata);
73484778508Sblueswir1 close(bprm->fd);
73584778508Sblueswir1 return -E2BIG;
73684778508Sblueswir1 }
73784778508Sblueswir1
73884778508Sblueswir1 /* OK, This is the point of no return */
73984778508Sblueswir1 info->end_data = 0;
74084778508Sblueswir1 info->end_code = 0;
74184778508Sblueswir1 elf_entry = (abi_ulong) elf_ex.e_entry;
74284778508Sblueswir1
743c09f12feSWarner Losh /* XXX Join this with PT_INTERP search? */
744c09f12feSWarner Losh baddr = 0;
745c09f12feSWarner Losh for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
746c09f12feSWarner Losh if (elf_ppnt->p_type != PT_LOAD) {
747c09f12feSWarner Losh continue;
748c09f12feSWarner Losh }
749c09f12feSWarner Losh baddr = elf_ppnt->p_vaddr;
750c09f12feSWarner Losh break;
751c09f12feSWarner Losh }
752c09f12feSWarner Losh
753c09f12feSWarner Losh et_dyn_addr = 0;
754c09f12feSWarner Losh if (elf_ex.e_type == ET_DYN && baddr == 0) {
755c09f12feSWarner Losh et_dyn_addr = ELF_ET_DYN_LOAD_ADDR;
756c09f12feSWarner Losh }
757c09f12feSWarner Losh
758c09f12feSWarner Losh /*
759c09f12feSWarner Losh * Do this so that we can load the interpreter, if need be. We will
760c09f12feSWarner Losh * change some of these later
761c09f12feSWarner Losh */
76284778508Sblueswir1 info->rss = 0;
76398b34d35SWarner Losh setup_arg_pages(bprm, info, &bprm->p, &bprm->stringp);
76484778508Sblueswir1 info->start_stack = bprm->p;
76584778508Sblueswir1
766c09f12feSWarner Losh info->elf_flags = elf_ex.e_flags;
76784778508Sblueswir1
768c09f12feSWarner Losh error = load_elf_sections(&elf_ex, elf_phdata, bprm->fd, et_dyn_addr,
769c09f12feSWarner Losh &load_addr);
77084778508Sblueswir1 for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
771c09f12feSWarner Losh if (elf_ppnt->p_type != PT_LOAD) {
77284778508Sblueswir1 continue;
773c09f12feSWarner Losh }
774c09f12feSWarner Losh if (elf_ppnt->p_memsz > elf_ppnt->p_filesz)
775c09f12feSWarner Losh elf_brk = MAX(elf_brk, et_dyn_addr + elf_ppnt->p_vaddr +
776c09f12feSWarner Losh elf_ppnt->p_memsz);
777c09f12feSWarner Losh }
778c09f12feSWarner Losh if (error != 0) {
779c09f12feSWarner Losh perror("load_elf_sections");
78084778508Sblueswir1 exit(-1);
78184778508Sblueswir1 }
78284778508Sblueswir1
78384778508Sblueswir1 if (elf_interpreter) {
78484778508Sblueswir1 elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
78584778508Sblueswir1 &interp_load_addr);
78684778508Sblueswir1 reloc_func_desc = interp_load_addr;
78784778508Sblueswir1
78884778508Sblueswir1 close(interpreter_fd);
78984778508Sblueswir1 free(elf_interpreter);
79084778508Sblueswir1
79184778508Sblueswir1 if (elf_entry == ~((abi_ulong)0UL)) {
79284778508Sblueswir1 printf("Unable to load interpreter\n");
79384778508Sblueswir1 free(elf_phdata);
79484778508Sblueswir1 exit(-1);
79584778508Sblueswir1 return 0;
79684778508Sblueswir1 }
797c09f12feSWarner Losh } else {
798c09f12feSWarner Losh interp_load_addr = et_dyn_addr;
799c09f12feSWarner Losh elf_entry += interp_load_addr;
80084778508Sblueswir1 }
80184778508Sblueswir1
80284778508Sblueswir1 free(elf_phdata);
80384778508Sblueswir1
8040456a177SWarner Losh if (qemu_log_enabled()) {
80584778508Sblueswir1 load_symbols(&elf_ex, bprm->fd);
8060456a177SWarner Losh }
80784778508Sblueswir1
808ffa03665SWarner Losh close(bprm->fd);
80984778508Sblueswir1
81098b34d35SWarner Losh bprm->p = target_create_elf_tables(bprm->p, bprm->argc, bprm->envc,
81198b34d35SWarner Losh bprm->stringp, &elf_ex, load_addr,
812c09f12feSWarner Losh et_dyn_addr, interp_load_addr, info);
81384778508Sblueswir1 info->load_addr = reloc_func_desc;
8144436e2ffSRichard Henderson info->brk = elf_brk;
81584778508Sblueswir1 info->start_stack = bprm->p;
816c09f12feSWarner Losh info->load_bias = 0;
81784778508Sblueswir1
81884778508Sblueswir1 info->entry = elf_entry;
81984778508Sblueswir1
8200475f8faSWarner Losh #ifdef USE_ELF_CORE_DUMP
8210475f8faSWarner Losh bprm->core_dump = &elf_core_dump;
8220475f8faSWarner Losh #else
8230475f8faSWarner Losh bprm->core_dump = NULL;
8240475f8faSWarner Losh #endif
8250475f8faSWarner Losh
82684778508Sblueswir1 return 0;
82784778508Sblueswir1 }
82884778508Sblueswir1
do_init_thread(struct target_pt_regs * regs,struct image_info * infop)82984778508Sblueswir1 void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
83084778508Sblueswir1 {
831a8fe6d5dSWarner Losh
832a8fe6d5dSWarner Losh target_thread_init(regs, infop);
83384778508Sblueswir1 }
834