xref: /qemu/linux-user/elfload.c (revision c27357906a339eb55e600efc71aef3f7617cb277)
131e31b8aSbellard /* This is the Linux kernel elf-loading code, ported into user space */
231e31b8aSbellard 
331e31b8aSbellard #include <stdio.h>
431e31b8aSbellard #include <sys/types.h>
531e31b8aSbellard #include <fcntl.h>
631e31b8aSbellard #include <sys/stat.h>
731e31b8aSbellard #include <errno.h>
831e31b8aSbellard #include <unistd.h>
931e31b8aSbellard #include <sys/mman.h>
1031e31b8aSbellard #include <stdlib.h>
1131e31b8aSbellard #include <string.h>
1231e31b8aSbellard 
133ef693a0Sbellard #include "qemu.h"
14689f936fSbellard #include "disas.h"
1531e31b8aSbellard 
1630ac07d4Sbellard #ifdef TARGET_I386
1730ac07d4Sbellard 
1830ac07d4Sbellard #define ELF_START_MMAP 0x80000000
1930ac07d4Sbellard 
2030ac07d4Sbellard /*
2130ac07d4Sbellard  * This is used to ensure we don't load something for the wrong architecture.
2230ac07d4Sbellard  */
2330ac07d4Sbellard #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
2430ac07d4Sbellard 
2530ac07d4Sbellard /*
2630ac07d4Sbellard  * These are used to set parameters in the core dumps.
2730ac07d4Sbellard  */
2830ac07d4Sbellard #define ELF_CLASS	ELFCLASS32
2930ac07d4Sbellard #define ELF_DATA	ELFDATA2LSB
3030ac07d4Sbellard #define ELF_ARCH	EM_386
3130ac07d4Sbellard 
3230ac07d4Sbellard 	/* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
3330ac07d4Sbellard 	   starts %edx contains a pointer to a function which might be
3430ac07d4Sbellard 	   registered using `atexit'.  This provides a mean for the
3530ac07d4Sbellard 	   dynamic linker to call DT_FINI functions for shared libraries
3630ac07d4Sbellard 	   that have been loaded before the code runs.
3730ac07d4Sbellard 
3830ac07d4Sbellard 	   A value of 0 tells we have no such handler.  */
3930ac07d4Sbellard #define ELF_PLAT_INIT(_r)	_r->edx = 0
4030ac07d4Sbellard 
41b346ff46Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
42b346ff46Sbellard {
43b346ff46Sbellard     regs->esp = infop->start_stack;
44b346ff46Sbellard     regs->eip = infop->entry;
45b346ff46Sbellard }
46b346ff46Sbellard 
47b346ff46Sbellard #define USE_ELF_CORE_DUMP
48b346ff46Sbellard #define ELF_EXEC_PAGESIZE	4096
49b346ff46Sbellard 
50b346ff46Sbellard #endif
51b346ff46Sbellard 
52b346ff46Sbellard #ifdef TARGET_ARM
53b346ff46Sbellard 
54b346ff46Sbellard #define ELF_START_MMAP 0x80000000
55b346ff46Sbellard 
56b346ff46Sbellard #define elf_check_arch(x) ( (x) == EM_ARM )
57b346ff46Sbellard 
58b346ff46Sbellard #define ELF_CLASS	ELFCLASS32
59b346ff46Sbellard #ifdef TARGET_WORDS_BIGENDIAN
60b346ff46Sbellard #define ELF_DATA	ELFDATA2MSB
61b346ff46Sbellard #else
62b346ff46Sbellard #define ELF_DATA	ELFDATA2LSB
63b346ff46Sbellard #endif
64b346ff46Sbellard #define ELF_ARCH	EM_ARM
65b346ff46Sbellard 
66b346ff46Sbellard #define ELF_PLAT_INIT(_r)	_r->ARM_r0 = 0
67b346ff46Sbellard 
68b346ff46Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
69b346ff46Sbellard {
70b346ff46Sbellard     target_long *stack = (void *)infop->start_stack;
71b346ff46Sbellard     memset(regs, 0, sizeof(*regs));
72b346ff46Sbellard     regs->ARM_cpsr = 0x10;
73b346ff46Sbellard     regs->ARM_pc = infop->entry;
74b346ff46Sbellard     regs->ARM_sp = infop->start_stack;
75b346ff46Sbellard     regs->ARM_r2 = tswapl(stack[2]); /* envp */
76b346ff46Sbellard     regs->ARM_r1 = tswapl(stack[1]); /* argv */
77a1516e92Sbellard     /* XXX: it seems that r0 is zeroed after ! */
78a1516e92Sbellard     //    regs->ARM_r0 = tswapl(stack[0]); /* argc */
79b346ff46Sbellard }
80b346ff46Sbellard 
8130ac07d4Sbellard #define USE_ELF_CORE_DUMP
8230ac07d4Sbellard #define ELF_EXEC_PAGESIZE	4096
8330ac07d4Sbellard 
8430ac07d4Sbellard #endif
8530ac07d4Sbellard 
86853d6f7aSbellard #ifdef TARGET_SPARC
87853d6f7aSbellard 
88853d6f7aSbellard #define ELF_START_MMAP 0x80000000
89853d6f7aSbellard 
90853d6f7aSbellard #define elf_check_arch(x) ( (x) == EM_SPARC )
91853d6f7aSbellard 
92853d6f7aSbellard #define ELF_CLASS   ELFCLASS32
93853d6f7aSbellard #define ELF_DATA    ELFDATA2MSB
94853d6f7aSbellard #define ELF_ARCH    EM_SPARC
95853d6f7aSbellard 
96853d6f7aSbellard /*XXX*/
97853d6f7aSbellard #define ELF_PLAT_INIT(_r)
98853d6f7aSbellard 
99853d6f7aSbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
100853d6f7aSbellard {
101f5155289Sbellard     regs->psr = 0;
102f5155289Sbellard     regs->pc = infop->entry;
103f5155289Sbellard     regs->npc = regs->pc + 4;
104f5155289Sbellard     regs->y = 0;
105f5155289Sbellard     regs->u_regs[14] = infop->start_stack - 16 * 4;
106853d6f7aSbellard }
107853d6f7aSbellard 
108853d6f7aSbellard #endif
109853d6f7aSbellard 
11067867308Sbellard #ifdef TARGET_PPC
11167867308Sbellard 
11267867308Sbellard #define ELF_START_MMAP 0x80000000
11367867308Sbellard 
11467867308Sbellard #define elf_check_arch(x) ( (x) == EM_PPC )
11567867308Sbellard 
11667867308Sbellard #define ELF_CLASS	ELFCLASS32
11767867308Sbellard #ifdef TARGET_WORDS_BIGENDIAN
11867867308Sbellard #define ELF_DATA	ELFDATA2MSB
11967867308Sbellard #else
12067867308Sbellard #define ELF_DATA	ELFDATA2LSB
12167867308Sbellard #endif
12267867308Sbellard #define ELF_ARCH	EM_PPC
12367867308Sbellard 
12467867308Sbellard /* Note that isn't exactly what regular kernel does
12567867308Sbellard  * but this is what the ABI wants and is needed to allow
12667867308Sbellard  * execution of PPC BSD programs.
12767867308Sbellard  */
12867867308Sbellard #define ELF_PLAT_INIT(_r)                                  \
12967867308Sbellard do {                                                       \
13067867308Sbellard    unsigned long *pos = (unsigned long *)bprm->p, tmp = 1; \
13167867308Sbellard     _r->gpr[3] = bprm->argc;                               \
13267867308Sbellard     _r->gpr[4] = (unsigned long)++pos;                     \
13367867308Sbellard     for (; tmp != 0; pos++)                                \
13467867308Sbellard         tmp = *pos;                                        \
13567867308Sbellard     _r->gpr[5] = (unsigned long)pos;                       \
13667867308Sbellard } while (0)
13767867308Sbellard 
138f5155289Sbellard /*
139f5155289Sbellard  * We need to put in some extra aux table entries to tell glibc what
140f5155289Sbellard  * the cache block size is, so it can use the dcbz instruction safely.
141f5155289Sbellard  */
142f5155289Sbellard #define AT_DCACHEBSIZE          19
143f5155289Sbellard #define AT_ICACHEBSIZE          20
144f5155289Sbellard #define AT_UCACHEBSIZE          21
145f5155289Sbellard /* A special ignored type value for PPC, for glibc compatibility.  */
146f5155289Sbellard #define AT_IGNOREPPC            22
147f5155289Sbellard /*
148f5155289Sbellard  * The requirements here are:
149f5155289Sbellard  * - keep the final alignment of sp (sp & 0xf)
150f5155289Sbellard  * - make sure the 32-bit value at the first 16 byte aligned position of
151f5155289Sbellard  *   AUXV is greater than 16 for glibc compatibility.
152f5155289Sbellard  *   AT_IGNOREPPC is used for that.
153f5155289Sbellard  * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
154f5155289Sbellard  *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
155f5155289Sbellard  */
156f5155289Sbellard #define DLINFO_ARCH_ITEMS       3
157f5155289Sbellard #define ARCH_DLINFO                                                     \
158f5155289Sbellard do {                                                                    \
159f5155289Sbellard 	sp -= DLINFO_ARCH_ITEMS * 2;					\
160f5155289Sbellard         NEW_AUX_ENT(0, AT_DCACHEBSIZE, 0x20);                           \
161f5155289Sbellard         NEW_AUX_ENT(1, AT_ICACHEBSIZE, 0x20);                           \
162f5155289Sbellard         NEW_AUX_ENT(2, AT_UCACHEBSIZE, 0);                              \
163f5155289Sbellard         /*                                                              \
164f5155289Sbellard          * Now handle glibc compatibility.                              \
165f5155289Sbellard          */                                                             \
166f5155289Sbellard 	sp -= 2*2;							\
167f5155289Sbellard 	NEW_AUX_ENT(0, AT_IGNOREPPC, AT_IGNOREPPC);			\
168f5155289Sbellard 	NEW_AUX_ENT(1, AT_IGNOREPPC, AT_IGNOREPPC);			\
169f5155289Sbellard  } while (0)
170f5155289Sbellard 
17167867308Sbellard static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
17267867308Sbellard {
17367867308Sbellard     _regs->msr = 1 << MSR_PR; /* Set user mode */
17467867308Sbellard     _regs->gpr[1] = infop->start_stack;
17567867308Sbellard     _regs->nip = infop->entry;
17667867308Sbellard }
17767867308Sbellard 
17867867308Sbellard #define USE_ELF_CORE_DUMP
17967867308Sbellard #define ELF_EXEC_PAGESIZE	4096
18067867308Sbellard 
18167867308Sbellard #endif
18267867308Sbellard 
18331e31b8aSbellard #include "elf.h"
18409bfb054Sbellard 
18509bfb054Sbellard /*
18609bfb054Sbellard  * MAX_ARG_PAGES defines the number of pages allocated for arguments
18709bfb054Sbellard  * and envelope for the new program. 32 should suffice, this gives
18809bfb054Sbellard  * a maximum env+arg of 128kB w/4KB pages!
18909bfb054Sbellard  */
19009bfb054Sbellard #define MAX_ARG_PAGES 32
19109bfb054Sbellard 
19209bfb054Sbellard /*
19309bfb054Sbellard  * This structure is used to hold the arguments that are
19409bfb054Sbellard  * used when loading binaries.
19509bfb054Sbellard  */
19609bfb054Sbellard struct linux_binprm {
19709bfb054Sbellard         char buf[128];
19809bfb054Sbellard         unsigned long page[MAX_ARG_PAGES];
19909bfb054Sbellard         unsigned long p;
20009bfb054Sbellard         int sh_bang;
20109bfb054Sbellard 	int fd;
20209bfb054Sbellard         int e_uid, e_gid;
20309bfb054Sbellard         int argc, envc;
20409bfb054Sbellard         char * filename;        /* Name of binary */
20509bfb054Sbellard         unsigned long loader, exec;
20609bfb054Sbellard         int dont_iput;          /* binfmt handler has put inode */
20709bfb054Sbellard };
20809bfb054Sbellard 
20909bfb054Sbellard struct exec
21009bfb054Sbellard {
21109bfb054Sbellard   unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
21209bfb054Sbellard   unsigned int a_text;   /* length of text, in bytes */
21309bfb054Sbellard   unsigned int a_data;   /* length of data, in bytes */
21409bfb054Sbellard   unsigned int a_bss;    /* length of uninitialized data area, in bytes */
21509bfb054Sbellard   unsigned int a_syms;   /* length of symbol table data in file, in bytes */
21609bfb054Sbellard   unsigned int a_entry;  /* start address */
21709bfb054Sbellard   unsigned int a_trsize; /* length of relocation info for text, in bytes */
21809bfb054Sbellard   unsigned int a_drsize; /* length of relocation info for data, in bytes */
21909bfb054Sbellard };
22009bfb054Sbellard 
22109bfb054Sbellard 
22209bfb054Sbellard #define N_MAGIC(exec) ((exec).a_info & 0xffff)
22309bfb054Sbellard #define OMAGIC 0407
22409bfb054Sbellard #define NMAGIC 0410
22509bfb054Sbellard #define ZMAGIC 0413
22609bfb054Sbellard #define QMAGIC 0314
22709bfb054Sbellard 
22809bfb054Sbellard /* max code+data+bss space allocated to elf interpreter */
22909bfb054Sbellard #define INTERP_MAP_SIZE (32 * 1024 * 1024)
23009bfb054Sbellard 
23109bfb054Sbellard /* max code+data+bss+brk space allocated to ET_DYN executables */
23209bfb054Sbellard #define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
23309bfb054Sbellard 
23409bfb054Sbellard /* from personality.h */
23509bfb054Sbellard 
23609bfb054Sbellard /* Flags for bug emulation. These occupy the top three bytes. */
23709bfb054Sbellard #define STICKY_TIMEOUTS		0x4000000
23809bfb054Sbellard #define WHOLE_SECONDS		0x2000000
23909bfb054Sbellard 
24009bfb054Sbellard /* Personality types. These go in the low byte. Avoid using the top bit,
24109bfb054Sbellard  * it will conflict with error returns.
24209bfb054Sbellard  */
24309bfb054Sbellard #define PER_MASK		(0x00ff)
24409bfb054Sbellard #define PER_LINUX		(0x0000)
24509bfb054Sbellard #define PER_SVR4		(0x0001 | STICKY_TIMEOUTS)
24609bfb054Sbellard #define PER_SVR3		(0x0002 | STICKY_TIMEOUTS)
24709bfb054Sbellard #define PER_SCOSVR3		(0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS)
24809bfb054Sbellard #define PER_WYSEV386		(0x0004 | STICKY_TIMEOUTS)
24909bfb054Sbellard #define PER_ISCR4		(0x0005 | STICKY_TIMEOUTS)
25009bfb054Sbellard #define PER_BSD			(0x0006)
25109bfb054Sbellard #define PER_XENIX		(0x0007 | STICKY_TIMEOUTS)
25231e31b8aSbellard 
25331e31b8aSbellard /* Necessary parameters */
25431e31b8aSbellard #define NGROUPS 32
25531e31b8aSbellard 
25654936004Sbellard #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
25754936004Sbellard #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
25854936004Sbellard #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
25931e31b8aSbellard 
26031e31b8aSbellard #define INTERPRETER_NONE 0
26131e31b8aSbellard #define INTERPRETER_AOUT 1
26231e31b8aSbellard #define INTERPRETER_ELF 2
26331e31b8aSbellard 
264f5155289Sbellard #define DLINFO_ITEMS 11
26531e31b8aSbellard 
26609bfb054Sbellard #define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x))
26709bfb054Sbellard #define get_user(ptr) (typeof(*ptr))(*(ptr))
268d691f669Sbellard 
26909bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
27009bfb054Sbellard {
27109bfb054Sbellard 	memcpy(to, from, n);
27209bfb054Sbellard }
27309bfb054Sbellard 
27409bfb054Sbellard static inline void memcpy_tofs(void * to, const void * from, unsigned long n)
27509bfb054Sbellard {
27609bfb054Sbellard 	memcpy(to, from, n);
27709bfb054Sbellard }
27831e31b8aSbellard 
27931e31b8aSbellard extern unsigned long x86_stack_size;
28031e31b8aSbellard 
28131e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd);
28231e31b8aSbellard 
28331e31b8aSbellard #ifdef BSWAP_NEEDED
28431e31b8aSbellard static void bswap_ehdr(Elf32_Ehdr *ehdr)
28531e31b8aSbellard {
28631e31b8aSbellard     bswap16s(&ehdr->e_type);			/* Object file type */
28731e31b8aSbellard     bswap16s(&ehdr->e_machine);		/* Architecture */
28831e31b8aSbellard     bswap32s(&ehdr->e_version);		/* Object file version */
28931e31b8aSbellard     bswap32s(&ehdr->e_entry);		/* Entry point virtual address */
29031e31b8aSbellard     bswap32s(&ehdr->e_phoff);		/* Program header table file offset */
29131e31b8aSbellard     bswap32s(&ehdr->e_shoff);		/* Section header table file offset */
29231e31b8aSbellard     bswap32s(&ehdr->e_flags);		/* Processor-specific flags */
29331e31b8aSbellard     bswap16s(&ehdr->e_ehsize);		/* ELF header size in bytes */
29431e31b8aSbellard     bswap16s(&ehdr->e_phentsize);		/* Program header table entry size */
29531e31b8aSbellard     bswap16s(&ehdr->e_phnum);		/* Program header table entry count */
29631e31b8aSbellard     bswap16s(&ehdr->e_shentsize);		/* Section header table entry size */
29731e31b8aSbellard     bswap16s(&ehdr->e_shnum);		/* Section header table entry count */
29831e31b8aSbellard     bswap16s(&ehdr->e_shstrndx);		/* Section header string table index */
29931e31b8aSbellard }
30031e31b8aSbellard 
30131e31b8aSbellard static void bswap_phdr(Elf32_Phdr *phdr)
30231e31b8aSbellard {
30331e31b8aSbellard     bswap32s(&phdr->p_type);			/* Segment type */
30431e31b8aSbellard     bswap32s(&phdr->p_offset);		/* Segment file offset */
30531e31b8aSbellard     bswap32s(&phdr->p_vaddr);		/* Segment virtual address */
30631e31b8aSbellard     bswap32s(&phdr->p_paddr);		/* Segment physical address */
30731e31b8aSbellard     bswap32s(&phdr->p_filesz);		/* Segment size in file */
30831e31b8aSbellard     bswap32s(&phdr->p_memsz);		/* Segment size in memory */
30931e31b8aSbellard     bswap32s(&phdr->p_flags);		/* Segment flags */
31031e31b8aSbellard     bswap32s(&phdr->p_align);		/* Segment alignment */
31131e31b8aSbellard }
312689f936fSbellard 
313689f936fSbellard static void bswap_shdr(Elf32_Shdr *shdr)
314689f936fSbellard {
315689f936fSbellard     bswap32s(&shdr->sh_name);
316689f936fSbellard     bswap32s(&shdr->sh_type);
317689f936fSbellard     bswap32s(&shdr->sh_flags);
318689f936fSbellard     bswap32s(&shdr->sh_addr);
319689f936fSbellard     bswap32s(&shdr->sh_offset);
320689f936fSbellard     bswap32s(&shdr->sh_size);
321689f936fSbellard     bswap32s(&shdr->sh_link);
322689f936fSbellard     bswap32s(&shdr->sh_info);
323689f936fSbellard     bswap32s(&shdr->sh_addralign);
324689f936fSbellard     bswap32s(&shdr->sh_entsize);
325689f936fSbellard }
326689f936fSbellard 
327689f936fSbellard static void bswap_sym(Elf32_Sym *sym)
328689f936fSbellard {
329689f936fSbellard     bswap32s(&sym->st_name);
330689f936fSbellard     bswap32s(&sym->st_value);
331689f936fSbellard     bswap32s(&sym->st_size);
332689f936fSbellard     bswap16s(&sym->st_shndx);
333689f936fSbellard }
33431e31b8aSbellard #endif
33531e31b8aSbellard 
33631e31b8aSbellard static void * get_free_page(void)
33731e31b8aSbellard {
33831e31b8aSbellard     void *	retval;
33931e31b8aSbellard 
34031e31b8aSbellard     /* User-space version of kernel get_free_page.  Returns a page-aligned
34131e31b8aSbellard      * page-sized chunk of memory.
34231e31b8aSbellard      */
34354936004Sbellard     retval = (void *)target_mmap(0, host_page_size, PROT_READ|PROT_WRITE,
34431e31b8aSbellard                                  MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
34531e31b8aSbellard 
34631e31b8aSbellard     if((long)retval == -1) {
34731e31b8aSbellard 	perror("get_free_page");
34831e31b8aSbellard 	exit(-1);
34931e31b8aSbellard     }
35031e31b8aSbellard     else {
35131e31b8aSbellard 	return(retval);
35231e31b8aSbellard     }
35331e31b8aSbellard }
35431e31b8aSbellard 
35531e31b8aSbellard static void free_page(void * pageaddr)
35631e31b8aSbellard {
35754936004Sbellard     target_munmap((unsigned long)pageaddr, host_page_size);
35831e31b8aSbellard }
35931e31b8aSbellard 
36031e31b8aSbellard /*
36131e31b8aSbellard  * 'copy_string()' copies argument/envelope strings from user
36231e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
36331e31b8aSbellard  * to be put directly into the top of new user memory.
36431e31b8aSbellard  *
36531e31b8aSbellard  */
36631e31b8aSbellard static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
36731e31b8aSbellard                 unsigned long p)
36831e31b8aSbellard {
36931e31b8aSbellard     char *tmp, *tmp1, *pag = NULL;
37031e31b8aSbellard     int len, offset = 0;
37131e31b8aSbellard 
37231e31b8aSbellard     if (!p) {
37331e31b8aSbellard 	return 0;       /* bullet-proofing */
37431e31b8aSbellard     }
37531e31b8aSbellard     while (argc-- > 0) {
37631e31b8aSbellard 	if (!(tmp1 = tmp = get_user(argv+argc))) {
37731e31b8aSbellard 	    fprintf(stderr, "VFS: argc is wrong");
37831e31b8aSbellard 	    exit(-1);
37931e31b8aSbellard 	}
38031e31b8aSbellard 	while (get_user(tmp++));
38131e31b8aSbellard 	len = tmp - tmp1;
38231e31b8aSbellard 	if (p < len) {  /* this shouldn't happen - 128kB */
38331e31b8aSbellard 		return 0;
38431e31b8aSbellard 	}
38531e31b8aSbellard 	while (len) {
38631e31b8aSbellard 	    --p; --tmp; --len;
38731e31b8aSbellard 	    if (--offset < 0) {
38854936004Sbellard 		offset = p % TARGET_PAGE_SIZE;
38944a91caeSbellard                 pag = (char *) page[p/TARGET_PAGE_SIZE];
39044a91caeSbellard                 if (!pag) {
39144a91caeSbellard                     pag = (char *)get_free_page();
39244a91caeSbellard                     page[p/TARGET_PAGE_SIZE] = (unsigned long)pag;
39344a91caeSbellard                     if (!pag)
39431e31b8aSbellard                         return 0;
39531e31b8aSbellard 		}
39631e31b8aSbellard 	    }
39731e31b8aSbellard 	    if (len == 0 || offset == 0) {
39831e31b8aSbellard 	        *(pag + offset) = get_user(tmp);
39931e31b8aSbellard 	    }
40031e31b8aSbellard 	    else {
40131e31b8aSbellard 	      int bytes_to_copy = (len > offset) ? offset : len;
40231e31b8aSbellard 	      tmp -= bytes_to_copy;
40331e31b8aSbellard 	      p -= bytes_to_copy;
40431e31b8aSbellard 	      offset -= bytes_to_copy;
40531e31b8aSbellard 	      len -= bytes_to_copy;
40631e31b8aSbellard 	      memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
40731e31b8aSbellard 	    }
40831e31b8aSbellard 	}
40931e31b8aSbellard     }
41031e31b8aSbellard     return p;
41131e31b8aSbellard }
41231e31b8aSbellard 
41331e31b8aSbellard static int in_group_p(gid_t g)
41431e31b8aSbellard {
41531e31b8aSbellard     /* return TRUE if we're in the specified group, FALSE otherwise */
41631e31b8aSbellard     int		ngroup;
41731e31b8aSbellard     int		i;
41831e31b8aSbellard     gid_t	grouplist[NGROUPS];
41931e31b8aSbellard 
42031e31b8aSbellard     ngroup = getgroups(NGROUPS, grouplist);
42131e31b8aSbellard     for(i = 0; i < ngroup; i++) {
42231e31b8aSbellard 	if(grouplist[i] == g) {
42331e31b8aSbellard 	    return 1;
42431e31b8aSbellard 	}
42531e31b8aSbellard     }
42631e31b8aSbellard     return 0;
42731e31b8aSbellard }
42831e31b8aSbellard 
42931e31b8aSbellard static int count(char ** vec)
43031e31b8aSbellard {
43131e31b8aSbellard     int		i;
43231e31b8aSbellard 
43331e31b8aSbellard     for(i = 0; *vec; i++) {
43431e31b8aSbellard         vec++;
43531e31b8aSbellard     }
43631e31b8aSbellard 
43731e31b8aSbellard     return(i);
43831e31b8aSbellard }
43931e31b8aSbellard 
44031e31b8aSbellard static int prepare_binprm(struct linux_binprm *bprm)
44131e31b8aSbellard {
44231e31b8aSbellard     struct stat		st;
44331e31b8aSbellard     int mode;
44431e31b8aSbellard     int retval, id_change;
44531e31b8aSbellard 
44631e31b8aSbellard     if(fstat(bprm->fd, &st) < 0) {
44731e31b8aSbellard 	return(-errno);
44831e31b8aSbellard     }
44931e31b8aSbellard 
45031e31b8aSbellard     mode = st.st_mode;
45131e31b8aSbellard     if(!S_ISREG(mode)) {	/* Must be regular file */
45231e31b8aSbellard 	return(-EACCES);
45331e31b8aSbellard     }
45431e31b8aSbellard     if(!(mode & 0111)) {	/* Must have at least one execute bit set */
45531e31b8aSbellard 	return(-EACCES);
45631e31b8aSbellard     }
45731e31b8aSbellard 
45831e31b8aSbellard     bprm->e_uid = geteuid();
45931e31b8aSbellard     bprm->e_gid = getegid();
46031e31b8aSbellard     id_change = 0;
46131e31b8aSbellard 
46231e31b8aSbellard     /* Set-uid? */
46331e31b8aSbellard     if(mode & S_ISUID) {
46431e31b8aSbellard     	bprm->e_uid = st.st_uid;
46531e31b8aSbellard 	if(bprm->e_uid != geteuid()) {
46631e31b8aSbellard 	    id_change = 1;
46731e31b8aSbellard 	}
46831e31b8aSbellard     }
46931e31b8aSbellard 
47031e31b8aSbellard     /* Set-gid? */
47131e31b8aSbellard     /*
47231e31b8aSbellard      * If setgid is set but no group execute bit then this
47331e31b8aSbellard      * is a candidate for mandatory locking, not a setgid
47431e31b8aSbellard      * executable.
47531e31b8aSbellard      */
47631e31b8aSbellard     if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
47731e31b8aSbellard 	bprm->e_gid = st.st_gid;
47831e31b8aSbellard 	if (!in_group_p(bprm->e_gid)) {
47931e31b8aSbellard 		id_change = 1;
48031e31b8aSbellard 	}
48131e31b8aSbellard     }
48231e31b8aSbellard 
48331e31b8aSbellard     memset(bprm->buf, 0, sizeof(bprm->buf));
48431e31b8aSbellard     retval = lseek(bprm->fd, 0L, SEEK_SET);
48531e31b8aSbellard     if(retval >= 0) {
48631e31b8aSbellard         retval = read(bprm->fd, bprm->buf, 128);
48731e31b8aSbellard     }
48831e31b8aSbellard     if(retval < 0) {
48931e31b8aSbellard 	perror("prepare_binprm");
49031e31b8aSbellard 	exit(-1);
49131e31b8aSbellard 	/* return(-errno); */
49231e31b8aSbellard     }
49331e31b8aSbellard     else {
49431e31b8aSbellard 	return(retval);
49531e31b8aSbellard     }
49631e31b8aSbellard }
49731e31b8aSbellard 
49831e31b8aSbellard unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
49931e31b8aSbellard 						struct image_info * info)
50031e31b8aSbellard {
50109bfb054Sbellard     unsigned long stack_base, size, error;
50231e31b8aSbellard     int i;
50331e31b8aSbellard 
50431e31b8aSbellard     /* Create enough stack to hold everything.  If we don't use
50531e31b8aSbellard      * it for args, we'll use it for something else...
50631e31b8aSbellard      */
50709bfb054Sbellard     size = x86_stack_size;
50854936004Sbellard     if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
50954936004Sbellard         size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
51054936004Sbellard     error = target_mmap(0,
51154936004Sbellard                         size + host_page_size,
51231e31b8aSbellard                         PROT_READ | PROT_WRITE,
51309bfb054Sbellard                         MAP_PRIVATE | MAP_ANONYMOUS,
51409bfb054Sbellard                         -1, 0);
51509bfb054Sbellard     if (error == -1) {
51631e31b8aSbellard         perror("stk mmap");
51731e31b8aSbellard         exit(-1);
51831e31b8aSbellard     }
51909bfb054Sbellard     /* we reserve one extra page at the top of the stack as guard */
52054936004Sbellard     target_mprotect(error + size, host_page_size, PROT_NONE);
52131e31b8aSbellard 
52254936004Sbellard     stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
52309bfb054Sbellard     p += stack_base;
52409bfb054Sbellard 
52509bfb054Sbellard     if (bprm->loader) {
52609bfb054Sbellard 	bprm->loader += stack_base;
52709bfb054Sbellard     }
52809bfb054Sbellard     bprm->exec += stack_base;
52931e31b8aSbellard 
53031e31b8aSbellard     for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
53131e31b8aSbellard 	if (bprm->page[i]) {
53231e31b8aSbellard 	    info->rss++;
53331e31b8aSbellard 
53454936004Sbellard 	    memcpy((void *)stack_base, (void *)bprm->page[i], TARGET_PAGE_SIZE);
53531e31b8aSbellard 	    free_page((void *)bprm->page[i]);
53631e31b8aSbellard 	}
53754936004Sbellard 	stack_base += TARGET_PAGE_SIZE;
53831e31b8aSbellard     }
53931e31b8aSbellard     return p;
54031e31b8aSbellard }
54131e31b8aSbellard 
54231e31b8aSbellard static void set_brk(unsigned long start, unsigned long end)
54331e31b8aSbellard {
54431e31b8aSbellard 	/* page-align the start and end addresses... */
54554936004Sbellard         start = HOST_PAGE_ALIGN(start);
54654936004Sbellard         end = HOST_PAGE_ALIGN(end);
54731e31b8aSbellard         if (end <= start)
54831e31b8aSbellard                 return;
54954936004Sbellard         if(target_mmap(start, end - start,
55031e31b8aSbellard                        PROT_READ | PROT_WRITE | PROT_EXEC,
55131e31b8aSbellard                        MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
55231e31b8aSbellard 	    perror("cannot mmap brk");
55331e31b8aSbellard 	    exit(-1);
55431e31b8aSbellard 	}
55531e31b8aSbellard }
55631e31b8aSbellard 
55731e31b8aSbellard 
558853d6f7aSbellard /* We need to explicitly zero any fractional pages after the data
559853d6f7aSbellard    section (i.e. bss).  This would contain the junk from the file that
560853d6f7aSbellard    should not be in memory. */
56131e31b8aSbellard static void padzero(unsigned long elf_bss)
56231e31b8aSbellard {
56331e31b8aSbellard         unsigned long nbyte;
56431e31b8aSbellard         char * fpnt;
56531e31b8aSbellard 
566853d6f7aSbellard         /* XXX: this is really a hack : if the real host page size is
567853d6f7aSbellard            smaller than the target page size, some pages after the end
568853d6f7aSbellard            of the file may not be mapped. A better fix would be to
569853d6f7aSbellard            patch target_mmap(), but it is more complicated as the file
570853d6f7aSbellard            size must be known */
571853d6f7aSbellard         if (real_host_page_size < host_page_size) {
572853d6f7aSbellard             unsigned long end_addr, end_addr1;
573853d6f7aSbellard             end_addr1 = (elf_bss + real_host_page_size - 1) &
574853d6f7aSbellard                 ~(real_host_page_size - 1);
575853d6f7aSbellard             end_addr = HOST_PAGE_ALIGN(elf_bss);
576853d6f7aSbellard             if (end_addr1 < end_addr) {
577853d6f7aSbellard                 mmap((void *)end_addr1, end_addr - end_addr1,
578853d6f7aSbellard                      PROT_READ|PROT_WRITE|PROT_EXEC,
579853d6f7aSbellard                      MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
580853d6f7aSbellard             }
581853d6f7aSbellard         }
582853d6f7aSbellard 
583853d6f7aSbellard         nbyte = elf_bss & (host_page_size-1);
58431e31b8aSbellard         if (nbyte) {
58554936004Sbellard 	    nbyte = host_page_size - nbyte;
58631e31b8aSbellard 	    fpnt = (char *) elf_bss;
58731e31b8aSbellard 	    do {
58831e31b8aSbellard 		*fpnt++ = 0;
58931e31b8aSbellard 	    } while (--nbyte);
59031e31b8aSbellard         }
59131e31b8aSbellard }
59231e31b8aSbellard 
59331e31b8aSbellard static unsigned int * create_elf_tables(char *p, int argc, int envc,
59431e31b8aSbellard                                         struct elfhdr * exec,
59531e31b8aSbellard                                         unsigned long load_addr,
59609bfb054Sbellard                                         unsigned long load_bias,
59731e31b8aSbellard                                         unsigned long interp_load_addr, int ibcs,
59831e31b8aSbellard                                         struct image_info *info)
59931e31b8aSbellard {
600f5155289Sbellard         target_ulong *argv, *envp;
601f5155289Sbellard         target_ulong *sp, *csp;
60231e31b8aSbellard 
60331e31b8aSbellard 	/*
604f5155289Sbellard 	 * Force 16 byte _final_ alignment here for generality.
60531e31b8aSbellard 	 */
60631e31b8aSbellard         sp = (unsigned int *) (~15UL & (unsigned long) p);
607f5155289Sbellard         csp = sp;
608f5155289Sbellard         csp -= (DLINFO_ITEMS + 1) * 2;
609f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS
610f5155289Sbellard 	csp -= DLINFO_ARCH_ITEMS*2;
611f5155289Sbellard #endif
612f5155289Sbellard         csp -= envc+1;
613f5155289Sbellard         csp -= argc+1;
614f5155289Sbellard 	csp -= (!ibcs ? 3 : 1);	/* argc itself */
615f5155289Sbellard         if ((unsigned long)csp & 15UL)
616f5155289Sbellard             sp -= ((unsigned long)csp & 15UL) / sizeof(*sp);
617f5155289Sbellard 
618f5155289Sbellard #define NEW_AUX_ENT(nr, id, val) \
619f5155289Sbellard           put_user (tswapl(id), sp + (nr * 2)); \
620f5155289Sbellard           put_user (tswapl(val), sp + (nr * 2 + 1))
621f5155289Sbellard         sp -= 2;
622f5155289Sbellard         NEW_AUX_ENT (0, AT_NULL, 0);
623f5155289Sbellard 
624a1516e92Sbellard 	sp -= DLINFO_ITEMS*2;
625f5155289Sbellard         NEW_AUX_ENT( 0, AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
626f5155289Sbellard         NEW_AUX_ENT( 1, AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
627f5155289Sbellard         NEW_AUX_ENT( 2, AT_PHNUM, (target_ulong)(exec->e_phnum));
628f5155289Sbellard         NEW_AUX_ENT( 3, AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
629f5155289Sbellard         NEW_AUX_ENT( 4, AT_BASE, (target_ulong)(interp_load_addr));
630f5155289Sbellard         NEW_AUX_ENT( 5, AT_FLAGS, (target_ulong)0);
631f5155289Sbellard         NEW_AUX_ENT( 6, AT_ENTRY, load_bias + exec->e_entry);
632f5155289Sbellard         NEW_AUX_ENT( 7, AT_UID, (target_ulong) getuid());
633f5155289Sbellard         NEW_AUX_ENT( 8, AT_EUID, (target_ulong) geteuid());
634f5155289Sbellard         NEW_AUX_ENT( 9, AT_GID, (target_ulong) getgid());
635f5155289Sbellard         NEW_AUX_ENT(11, AT_EGID, (target_ulong) getegid());
636f5155289Sbellard #ifdef ARCH_DLINFO
637f5155289Sbellard 	/*
638f5155289Sbellard 	 * ARCH_DLINFO must come last so platform specific code can enforce
639f5155289Sbellard 	 * special alignment requirements on the AUXV if necessary (eg. PPC).
640f5155289Sbellard 	 */
641f5155289Sbellard         ARCH_DLINFO;
642f5155289Sbellard #endif
643f5155289Sbellard #undef NEW_AUX_ENT
644f5155289Sbellard 
64531e31b8aSbellard         sp -= envc+1;
64631e31b8aSbellard         envp = sp;
64731e31b8aSbellard         sp -= argc+1;
64831e31b8aSbellard         argv = sp;
64931e31b8aSbellard         if (!ibcs) {
650b17780d5Sbellard                 put_user(tswapl((target_ulong)envp),--sp);
651b17780d5Sbellard                 put_user(tswapl((target_ulong)argv),--sp);
65231e31b8aSbellard         }
653b17780d5Sbellard         put_user(tswapl(argc),--sp);
65431e31b8aSbellard         info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff);
65531e31b8aSbellard         while (argc-->0) {
656b17780d5Sbellard                 put_user(tswapl((target_ulong)p),argv++);
65731e31b8aSbellard                 while (get_user(p++)) /* nothing */ ;
65831e31b8aSbellard         }
65931e31b8aSbellard         put_user(0,argv);
66031e31b8aSbellard         info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff);
66131e31b8aSbellard         while (envc-->0) {
662b17780d5Sbellard                 put_user(tswapl((target_ulong)p),envp++);
66331e31b8aSbellard                 while (get_user(p++)) /* nothing */ ;
66431e31b8aSbellard         }
66531e31b8aSbellard         put_user(0,envp);
66631e31b8aSbellard         info->env_end = (unsigned int)((unsigned long)p & 0xffffffff);
66731e31b8aSbellard         return sp;
66831e31b8aSbellard }
66931e31b8aSbellard 
67031e31b8aSbellard 
67131e31b8aSbellard 
67231e31b8aSbellard static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
67331e31b8aSbellard 				     int interpreter_fd,
67431e31b8aSbellard 				     unsigned long *interp_load_addr)
67531e31b8aSbellard {
67631e31b8aSbellard 	struct elf_phdr *elf_phdata  =  NULL;
67731e31b8aSbellard 	struct elf_phdr *eppnt;
67809bfb054Sbellard 	unsigned long load_addr = 0;
67931e31b8aSbellard 	int load_addr_set = 0;
68031e31b8aSbellard 	int retval;
68131e31b8aSbellard 	unsigned long last_bss, elf_bss;
68231e31b8aSbellard 	unsigned long error;
68331e31b8aSbellard 	int i;
68431e31b8aSbellard 
68531e31b8aSbellard 	elf_bss = 0;
68631e31b8aSbellard 	last_bss = 0;
68731e31b8aSbellard 	error = 0;
68831e31b8aSbellard 
689644c433cSbellard #ifdef BSWAP_NEEDED
690644c433cSbellard         bswap_ehdr(interp_elf_ex);
691644c433cSbellard #endif
69231e31b8aSbellard 	/* First of all, some simple consistency checks */
69331e31b8aSbellard 	if ((interp_elf_ex->e_type != ET_EXEC &&
69431e31b8aSbellard              interp_elf_ex->e_type != ET_DYN) ||
69531e31b8aSbellard 	   !elf_check_arch(interp_elf_ex->e_machine)) {
69631e31b8aSbellard 		return ~0UL;
69731e31b8aSbellard 	}
69831e31b8aSbellard 
699644c433cSbellard 
70031e31b8aSbellard 	/* Now read in all of the header information */
70131e31b8aSbellard 
70254936004Sbellard 	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
70331e31b8aSbellard 	    return ~0UL;
70431e31b8aSbellard 
70531e31b8aSbellard 	elf_phdata =  (struct elf_phdr *)
70631e31b8aSbellard 		malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
70731e31b8aSbellard 
70831e31b8aSbellard 	if (!elf_phdata)
70931e31b8aSbellard 	  return ~0UL;
71031e31b8aSbellard 
71131e31b8aSbellard 	/*
71231e31b8aSbellard 	 * If the size of this structure has changed, then punt, since
71331e31b8aSbellard 	 * we will be doing the wrong thing.
71431e31b8aSbellard 	 */
71509bfb054Sbellard 	if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
71631e31b8aSbellard 	    free(elf_phdata);
71731e31b8aSbellard 	    return ~0UL;
71831e31b8aSbellard         }
71931e31b8aSbellard 
72031e31b8aSbellard 	retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
72131e31b8aSbellard 	if(retval >= 0) {
72231e31b8aSbellard 	    retval = read(interpreter_fd,
72331e31b8aSbellard 			   (char *) elf_phdata,
72431e31b8aSbellard 			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
72531e31b8aSbellard 	}
72631e31b8aSbellard 	if (retval < 0) {
72731e31b8aSbellard 		perror("load_elf_interp");
72831e31b8aSbellard 		exit(-1);
72931e31b8aSbellard 		free (elf_phdata);
73031e31b8aSbellard 		return retval;
73131e31b8aSbellard  	}
73231e31b8aSbellard #ifdef BSWAP_NEEDED
73331e31b8aSbellard 	eppnt = elf_phdata;
73431e31b8aSbellard 	for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
73531e31b8aSbellard             bswap_phdr(eppnt);
73631e31b8aSbellard         }
73731e31b8aSbellard #endif
73809bfb054Sbellard 
73909bfb054Sbellard         if (interp_elf_ex->e_type == ET_DYN) {
74009bfb054Sbellard             /* in order to avoid harcoding the interpreter load
74109bfb054Sbellard                address in qemu, we allocate a big enough memory zone */
74254936004Sbellard             error = target_mmap(0, INTERP_MAP_SIZE,
74309bfb054Sbellard                                 PROT_NONE, MAP_PRIVATE | MAP_ANON,
74409bfb054Sbellard                                 -1, 0);
74509bfb054Sbellard             if (error == -1) {
74609bfb054Sbellard                 perror("mmap");
74709bfb054Sbellard                 exit(-1);
74809bfb054Sbellard             }
74909bfb054Sbellard             load_addr = error;
75009bfb054Sbellard             load_addr_set = 1;
75109bfb054Sbellard         }
75209bfb054Sbellard 
75331e31b8aSbellard 	eppnt = elf_phdata;
75431e31b8aSbellard 	for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
75531e31b8aSbellard 	  if (eppnt->p_type == PT_LOAD) {
75631e31b8aSbellard 	    int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
75731e31b8aSbellard 	    int elf_prot = 0;
75831e31b8aSbellard 	    unsigned long vaddr = 0;
75931e31b8aSbellard 	    unsigned long k;
76031e31b8aSbellard 
76131e31b8aSbellard 	    if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
76231e31b8aSbellard 	    if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
76331e31b8aSbellard 	    if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
76431e31b8aSbellard 	    if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
76531e31b8aSbellard 	    	elf_type |= MAP_FIXED;
76631e31b8aSbellard 	    	vaddr = eppnt->p_vaddr;
76731e31b8aSbellard 	    }
76854936004Sbellard 	    error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
76954936004Sbellard 		 eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
77031e31b8aSbellard 		 elf_prot,
77131e31b8aSbellard 		 elf_type,
77231e31b8aSbellard 		 interpreter_fd,
77354936004Sbellard 		 eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
77431e31b8aSbellard 
77531e31b8aSbellard 	    if (error > -1024UL) {
77631e31b8aSbellard 	      /* Real error */
77731e31b8aSbellard 	      close(interpreter_fd);
77831e31b8aSbellard 	      free(elf_phdata);
77931e31b8aSbellard 	      return ~0UL;
78031e31b8aSbellard 	    }
78131e31b8aSbellard 
78231e31b8aSbellard 	    if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
78331e31b8aSbellard 	      load_addr = error;
78431e31b8aSbellard 	      load_addr_set = 1;
78531e31b8aSbellard 	    }
78631e31b8aSbellard 
78731e31b8aSbellard 	    /*
78831e31b8aSbellard 	     * Find the end of the file  mapping for this phdr, and keep
78931e31b8aSbellard 	     * track of the largest address we see for this.
79031e31b8aSbellard 	     */
79131e31b8aSbellard 	    k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
79231e31b8aSbellard 	    if (k > elf_bss) elf_bss = k;
79331e31b8aSbellard 
79431e31b8aSbellard 	    /*
79531e31b8aSbellard 	     * Do the same thing for the memory mapping - between
79631e31b8aSbellard 	     * elf_bss and last_bss is the bss section.
79731e31b8aSbellard 	     */
79831e31b8aSbellard 	    k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
79931e31b8aSbellard 	    if (k > last_bss) last_bss = k;
80031e31b8aSbellard 	  }
80131e31b8aSbellard 
80231e31b8aSbellard 	/* Now use mmap to map the library into memory. */
80331e31b8aSbellard 
80431e31b8aSbellard 	close(interpreter_fd);
80531e31b8aSbellard 
80631e31b8aSbellard 	/*
80731e31b8aSbellard 	 * Now fill out the bss section.  First pad the last page up
80831e31b8aSbellard 	 * to the page boundary, and then perform a mmap to make sure
80931e31b8aSbellard 	 * that there are zeromapped pages up to and including the last
81031e31b8aSbellard 	 * bss page.
81131e31b8aSbellard 	 */
81231e31b8aSbellard 	padzero(elf_bss);
81354936004Sbellard 	elf_bss = TARGET_ELF_PAGESTART(elf_bss + host_page_size - 1); /* What we have mapped so far */
81431e31b8aSbellard 
81531e31b8aSbellard 	/* Map the last of the bss segment */
81631e31b8aSbellard 	if (last_bss > elf_bss) {
81754936004Sbellard             target_mmap(elf_bss, last_bss-elf_bss,
81831e31b8aSbellard                         PROT_READ|PROT_WRITE|PROT_EXEC,
81931e31b8aSbellard                         MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
82031e31b8aSbellard 	}
82131e31b8aSbellard 	free(elf_phdata);
82231e31b8aSbellard 
82331e31b8aSbellard 	*interp_load_addr = load_addr;
82431e31b8aSbellard 	return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
82531e31b8aSbellard }
82631e31b8aSbellard 
827689f936fSbellard /* Best attempt to load symbols from this ELF object. */
828689f936fSbellard static void load_symbols(struct elfhdr *hdr, int fd)
829689f936fSbellard {
830689f936fSbellard     unsigned int i;
831689f936fSbellard     struct elf_shdr sechdr, symtab, strtab;
832689f936fSbellard     char *strings;
83331e31b8aSbellard 
834689f936fSbellard     lseek(fd, hdr->e_shoff, SEEK_SET);
835689f936fSbellard     for (i = 0; i < hdr->e_shnum; i++) {
836689f936fSbellard 	if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
837689f936fSbellard 	    return;
838689f936fSbellard #ifdef BSWAP_NEEDED
839689f936fSbellard 	bswap_shdr(&sechdr);
840689f936fSbellard #endif
841689f936fSbellard 	if (sechdr.sh_type == SHT_SYMTAB) {
842689f936fSbellard 	    symtab = sechdr;
843689f936fSbellard 	    lseek(fd, hdr->e_shoff
844689f936fSbellard 		  + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
845689f936fSbellard 	    if (read(fd, &strtab, sizeof(strtab))
846689f936fSbellard 		!= sizeof(strtab))
847689f936fSbellard 		return;
848689f936fSbellard #ifdef BSWAP_NEEDED
849689f936fSbellard 	    bswap_shdr(&strtab);
850689f936fSbellard #endif
851689f936fSbellard 	    goto found;
852689f936fSbellard 	}
853689f936fSbellard     }
854689f936fSbellard     return; /* Shouldn't happen... */
855689f936fSbellard 
856689f936fSbellard  found:
857689f936fSbellard     /* Now know where the strtab and symtab are.  Snarf them. */
858689f936fSbellard     disas_symtab = malloc(symtab.sh_size);
859689f936fSbellard     disas_strtab = strings = malloc(strtab.sh_size);
860689f936fSbellard     if (!disas_symtab || !disas_strtab)
861689f936fSbellard 	return;
862689f936fSbellard 
863689f936fSbellard     lseek(fd, symtab.sh_offset, SEEK_SET);
864689f936fSbellard     if (read(fd, disas_symtab, symtab.sh_size) != symtab.sh_size)
865689f936fSbellard 	return;
866689f936fSbellard 
867689f936fSbellard #ifdef BSWAP_NEEDED
868689f936fSbellard     for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++)
869689f936fSbellard 	bswap_sym(disas_symtab + sizeof(struct elf_sym)*i);
870689f936fSbellard #endif
871689f936fSbellard 
872689f936fSbellard     lseek(fd, strtab.sh_offset, SEEK_SET);
873689f936fSbellard     if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
874689f936fSbellard 	return;
875689f936fSbellard     disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
876689f936fSbellard }
87731e31b8aSbellard 
878b17780d5Sbellard static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
87931e31b8aSbellard                            struct image_info * info)
88031e31b8aSbellard {
88131e31b8aSbellard     struct elfhdr elf_ex;
88231e31b8aSbellard     struct elfhdr interp_elf_ex;
88331e31b8aSbellard     struct exec interp_ex;
88431e31b8aSbellard     int interpreter_fd = -1; /* avoid warning */
88509bfb054Sbellard     unsigned long load_addr, load_bias;
88631e31b8aSbellard     int load_addr_set = 0;
88731e31b8aSbellard     unsigned int interpreter_type = INTERPRETER_NONE;
88831e31b8aSbellard     unsigned char ibcs2_interpreter;
88931e31b8aSbellard     int i;
89054936004Sbellard     unsigned long mapped_addr;
89131e31b8aSbellard     struct elf_phdr * elf_ppnt;
89231e31b8aSbellard     struct elf_phdr *elf_phdata;
89331e31b8aSbellard     unsigned long elf_bss, k, elf_brk;
89431e31b8aSbellard     int retval;
89531e31b8aSbellard     char * elf_interpreter;
89631e31b8aSbellard     unsigned long elf_entry, interp_load_addr = 0;
89731e31b8aSbellard     int status;
89831e31b8aSbellard     unsigned long start_code, end_code, end_data;
89931e31b8aSbellard     unsigned long elf_stack;
90031e31b8aSbellard     char passed_fileno[6];
90131e31b8aSbellard 
90231e31b8aSbellard     ibcs2_interpreter = 0;
90331e31b8aSbellard     status = 0;
90431e31b8aSbellard     load_addr = 0;
90509bfb054Sbellard     load_bias = 0;
90631e31b8aSbellard     elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
90731e31b8aSbellard #ifdef BSWAP_NEEDED
90831e31b8aSbellard     bswap_ehdr(&elf_ex);
90931e31b8aSbellard #endif
91031e31b8aSbellard 
91131e31b8aSbellard     if (elf_ex.e_ident[0] != 0x7f ||
91231e31b8aSbellard 	strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
91331e31b8aSbellard 	    return  -ENOEXEC;
91431e31b8aSbellard     }
91531e31b8aSbellard 
91631e31b8aSbellard     /* First of all, some simple consistency checks */
91731e31b8aSbellard     if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
91831e31b8aSbellard        				(! elf_check_arch(elf_ex.e_machine))) {
91931e31b8aSbellard 	    return -ENOEXEC;
92031e31b8aSbellard     }
92131e31b8aSbellard 
92231e31b8aSbellard     /* Now read in all of the header information */
92331e31b8aSbellard     elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
92431e31b8aSbellard     if (elf_phdata == NULL) {
92531e31b8aSbellard 	return -ENOMEM;
92631e31b8aSbellard     }
92731e31b8aSbellard 
92831e31b8aSbellard     retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
92931e31b8aSbellard     if(retval > 0) {
93031e31b8aSbellard 	retval = read(bprm->fd, (char *) elf_phdata,
93131e31b8aSbellard 				elf_ex.e_phentsize * elf_ex.e_phnum);
93231e31b8aSbellard     }
93331e31b8aSbellard 
93431e31b8aSbellard     if (retval < 0) {
93531e31b8aSbellard 	perror("load_elf_binary");
93631e31b8aSbellard 	exit(-1);
93731e31b8aSbellard 	free (elf_phdata);
93831e31b8aSbellard 	return -errno;
93931e31b8aSbellard     }
94031e31b8aSbellard 
941b17780d5Sbellard #ifdef BSWAP_NEEDED
942b17780d5Sbellard     elf_ppnt = elf_phdata;
943b17780d5Sbellard     for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
944b17780d5Sbellard         bswap_phdr(elf_ppnt);
945b17780d5Sbellard     }
946b17780d5Sbellard #endif
94731e31b8aSbellard     elf_ppnt = elf_phdata;
94831e31b8aSbellard 
94931e31b8aSbellard     elf_bss = 0;
95031e31b8aSbellard     elf_brk = 0;
95131e31b8aSbellard 
95231e31b8aSbellard 
95331e31b8aSbellard     elf_stack = ~0UL;
95431e31b8aSbellard     elf_interpreter = NULL;
95531e31b8aSbellard     start_code = ~0UL;
95631e31b8aSbellard     end_code = 0;
95731e31b8aSbellard     end_data = 0;
95831e31b8aSbellard 
95931e31b8aSbellard     for(i=0;i < elf_ex.e_phnum; i++) {
96031e31b8aSbellard 	if (elf_ppnt->p_type == PT_INTERP) {
96131e31b8aSbellard 	    if ( elf_interpreter != NULL )
96231e31b8aSbellard 	    {
96331e31b8aSbellard 		free (elf_phdata);
96431e31b8aSbellard 		free(elf_interpreter);
96531e31b8aSbellard 		close(bprm->fd);
96631e31b8aSbellard 		return -EINVAL;
96731e31b8aSbellard 	    }
96831e31b8aSbellard 
96931e31b8aSbellard 	    /* This is the program interpreter used for
97031e31b8aSbellard 	     * shared libraries - for now assume that this
97131e31b8aSbellard 	     * is an a.out format binary
97231e31b8aSbellard 	     */
97331e31b8aSbellard 
97432ce6337Sbellard 	    elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
97531e31b8aSbellard 
97631e31b8aSbellard 	    if (elf_interpreter == NULL) {
97731e31b8aSbellard 		free (elf_phdata);
97831e31b8aSbellard 		close(bprm->fd);
97931e31b8aSbellard 		return -ENOMEM;
98031e31b8aSbellard 	    }
98131e31b8aSbellard 
98231e31b8aSbellard 	    retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
98331e31b8aSbellard 	    if(retval >= 0) {
98432ce6337Sbellard 		retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
98531e31b8aSbellard 	    }
98631e31b8aSbellard 	    if(retval < 0) {
98731e31b8aSbellard 	 	perror("load_elf_binary2");
98831e31b8aSbellard 		exit(-1);
98931e31b8aSbellard 	    }
99031e31b8aSbellard 
99131e31b8aSbellard 	    /* If the program interpreter is one of these two,
99231e31b8aSbellard 	       then assume an iBCS2 image. Otherwise assume
99331e31b8aSbellard 	       a native linux image. */
99431e31b8aSbellard 
99531e31b8aSbellard 	    /* JRP - Need to add X86 lib dir stuff here... */
99631e31b8aSbellard 
99731e31b8aSbellard 	    if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
99831e31b8aSbellard 		strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
99931e31b8aSbellard 	      ibcs2_interpreter = 1;
100031e31b8aSbellard 	    }
100131e31b8aSbellard 
100231e31b8aSbellard #if 0
100331e31b8aSbellard 	    printf("Using ELF interpreter %s\n", elf_interpreter);
100431e31b8aSbellard #endif
100531e31b8aSbellard 	    if (retval >= 0) {
100632ce6337Sbellard 		retval = open(path(elf_interpreter), O_RDONLY);
100731e31b8aSbellard 		if(retval >= 0) {
100831e31b8aSbellard 		    interpreter_fd = retval;
100931e31b8aSbellard 		}
101031e31b8aSbellard 		else {
101131e31b8aSbellard 		    perror(elf_interpreter);
101231e31b8aSbellard 		    exit(-1);
101331e31b8aSbellard 		    /* retval = -errno; */
101431e31b8aSbellard 		}
101531e31b8aSbellard 	    }
101631e31b8aSbellard 
101731e31b8aSbellard 	    if (retval >= 0) {
101831e31b8aSbellard 		retval = lseek(interpreter_fd, 0, SEEK_SET);
101931e31b8aSbellard 		if(retval >= 0) {
102031e31b8aSbellard 		    retval = read(interpreter_fd,bprm->buf,128);
102131e31b8aSbellard 		}
102231e31b8aSbellard 	    }
102331e31b8aSbellard 	    if (retval >= 0) {
102431e31b8aSbellard 		interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
102531e31b8aSbellard 		interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */
102631e31b8aSbellard 	    }
102731e31b8aSbellard 	    if (retval < 0) {
102831e31b8aSbellard 		perror("load_elf_binary3");
102931e31b8aSbellard 		exit(-1);
103031e31b8aSbellard 		free (elf_phdata);
103131e31b8aSbellard 		free(elf_interpreter);
103231e31b8aSbellard 		close(bprm->fd);
103331e31b8aSbellard 		return retval;
103431e31b8aSbellard 	    }
103531e31b8aSbellard 	}
103631e31b8aSbellard 	elf_ppnt++;
103731e31b8aSbellard     }
103831e31b8aSbellard 
103931e31b8aSbellard     /* Some simple consistency checks for the interpreter */
104031e31b8aSbellard     if (elf_interpreter){
104131e31b8aSbellard 	interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
104231e31b8aSbellard 
104331e31b8aSbellard 	/* Now figure out which format our binary is */
104431e31b8aSbellard 	if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
104531e31b8aSbellard 	    	(N_MAGIC(interp_ex) != QMAGIC)) {
104631e31b8aSbellard 	  interpreter_type = INTERPRETER_ELF;
104731e31b8aSbellard 	}
104831e31b8aSbellard 
104931e31b8aSbellard 	if (interp_elf_ex.e_ident[0] != 0x7f ||
105031e31b8aSbellard 	    	strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) {
105131e31b8aSbellard 	    interpreter_type &= ~INTERPRETER_ELF;
105231e31b8aSbellard 	}
105331e31b8aSbellard 
105431e31b8aSbellard 	if (!interpreter_type) {
105531e31b8aSbellard 	    free(elf_interpreter);
105631e31b8aSbellard 	    free(elf_phdata);
105731e31b8aSbellard 	    close(bprm->fd);
105831e31b8aSbellard 	    return -ELIBBAD;
105931e31b8aSbellard 	}
106031e31b8aSbellard     }
106131e31b8aSbellard 
106231e31b8aSbellard     /* OK, we are done with that, now set up the arg stuff,
106331e31b8aSbellard        and then start this sucker up */
106431e31b8aSbellard 
106531e31b8aSbellard     if (!bprm->sh_bang) {
106631e31b8aSbellard 	char * passed_p;
106731e31b8aSbellard 
106831e31b8aSbellard 	if (interpreter_type == INTERPRETER_AOUT) {
106931e31b8aSbellard 	    sprintf(passed_fileno, "%d", bprm->fd);
107031e31b8aSbellard 	    passed_p = passed_fileno;
107131e31b8aSbellard 
107231e31b8aSbellard 	    if (elf_interpreter) {
107331e31b8aSbellard 		bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p);
107431e31b8aSbellard 		bprm->argc++;
107531e31b8aSbellard 	    }
107631e31b8aSbellard 	}
107731e31b8aSbellard 	if (!bprm->p) {
107831e31b8aSbellard 	    if (elf_interpreter) {
107931e31b8aSbellard 	        free(elf_interpreter);
108031e31b8aSbellard 	    }
108131e31b8aSbellard 	    free (elf_phdata);
108231e31b8aSbellard 	    close(bprm->fd);
108331e31b8aSbellard 	    return -E2BIG;
108431e31b8aSbellard 	}
108531e31b8aSbellard     }
108631e31b8aSbellard 
108731e31b8aSbellard     /* OK, This is the point of no return */
108831e31b8aSbellard     info->end_data = 0;
108931e31b8aSbellard     info->end_code = 0;
109031e31b8aSbellard     info->start_mmap = (unsigned long)ELF_START_MMAP;
109131e31b8aSbellard     info->mmap = 0;
109231e31b8aSbellard     elf_entry = (unsigned long) elf_ex.e_entry;
109331e31b8aSbellard 
109431e31b8aSbellard     /* Do this so that we can load the interpreter, if need be.  We will
109531e31b8aSbellard        change some of these later */
109631e31b8aSbellard     info->rss = 0;
109731e31b8aSbellard     bprm->p = setup_arg_pages(bprm->p, bprm, info);
109831e31b8aSbellard     info->start_stack = bprm->p;
109931e31b8aSbellard 
110031e31b8aSbellard     /* Now we do a little grungy work by mmaping the ELF image into
110131e31b8aSbellard      * the correct location in memory.  At this point, we assume that
110231e31b8aSbellard      * the image should be loaded at fixed address, not at a variable
110331e31b8aSbellard      * address.
110431e31b8aSbellard      */
110531e31b8aSbellard 
110631e31b8aSbellard     for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
110731e31b8aSbellard         int elf_prot = 0;
110809bfb054Sbellard         int elf_flags = 0;
110909bfb054Sbellard         unsigned long error;
111009bfb054Sbellard 
111109bfb054Sbellard 	if (elf_ppnt->p_type != PT_LOAD)
111209bfb054Sbellard             continue;
111309bfb054Sbellard 
111431e31b8aSbellard         if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
111531e31b8aSbellard         if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
111631e31b8aSbellard         if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
111709bfb054Sbellard         elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
111809bfb054Sbellard         if (elf_ex.e_type == ET_EXEC || load_addr_set) {
111909bfb054Sbellard             elf_flags |= MAP_FIXED;
112009bfb054Sbellard         } else if (elf_ex.e_type == ET_DYN) {
112109bfb054Sbellard             /* Try and get dynamic programs out of the way of the default mmap
112209bfb054Sbellard                base, as well as whatever program they might try to exec.  This
112309bfb054Sbellard                is because the brk will follow the loader, and is not movable.  */
112409bfb054Sbellard             /* NOTE: for qemu, we do a big mmap to get enough space
112509bfb054Sbellard                without harcoding any address */
112654936004Sbellard             error = target_mmap(0, ET_DYN_MAP_SIZE,
112709bfb054Sbellard                                 PROT_NONE, MAP_PRIVATE | MAP_ANON,
112809bfb054Sbellard                                 -1, 0);
112909bfb054Sbellard             if (error == -1) {
113009bfb054Sbellard                 perror("mmap");
113109bfb054Sbellard                 exit(-1);
113209bfb054Sbellard             }
113354936004Sbellard             load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
113409bfb054Sbellard         }
113531e31b8aSbellard 
113654936004Sbellard         error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
113731e31b8aSbellard                             (elf_ppnt->p_filesz +
113854936004Sbellard                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
113931e31b8aSbellard                             elf_prot,
114031e31b8aSbellard                             (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
114131e31b8aSbellard                             bprm->fd,
114231e31b8aSbellard                             (elf_ppnt->p_offset -
114354936004Sbellard                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
114409bfb054Sbellard         if (error == -1) {
114531e31b8aSbellard             perror("mmap");
114631e31b8aSbellard             exit(-1);
114731e31b8aSbellard         }
114831e31b8aSbellard 
114931e31b8aSbellard #ifdef LOW_ELF_STACK
115054936004Sbellard         if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
115154936004Sbellard             elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr);
115231e31b8aSbellard #endif
115331e31b8aSbellard 
115431e31b8aSbellard         if (!load_addr_set) {
115531e31b8aSbellard             load_addr_set = 1;
115609bfb054Sbellard             load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
115709bfb054Sbellard             if (elf_ex.e_type == ET_DYN) {
115809bfb054Sbellard                 load_bias += error -
115954936004Sbellard                     TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
116009bfb054Sbellard                 load_addr += load_bias;
116109bfb054Sbellard             }
116231e31b8aSbellard         }
116331e31b8aSbellard         k = elf_ppnt->p_vaddr;
116409bfb054Sbellard         if (k < start_code)
116509bfb054Sbellard             start_code = k;
116631e31b8aSbellard         k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
116709bfb054Sbellard         if (k > elf_bss)
116809bfb054Sbellard             elf_bss = k;
116931e31b8aSbellard         if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
117031e31b8aSbellard             end_code = k;
117109bfb054Sbellard         if (end_data < k)
117209bfb054Sbellard             end_data = k;
117331e31b8aSbellard         k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
117431e31b8aSbellard         if (k > elf_brk) elf_brk = k;
117531e31b8aSbellard     }
117609bfb054Sbellard 
117709bfb054Sbellard     elf_entry += load_bias;
117809bfb054Sbellard     elf_bss += load_bias;
117909bfb054Sbellard     elf_brk += load_bias;
118009bfb054Sbellard     start_code += load_bias;
118109bfb054Sbellard     end_code += load_bias;
118209bfb054Sbellard     //    start_data += load_bias;
118309bfb054Sbellard     end_data += load_bias;
118431e31b8aSbellard 
118531e31b8aSbellard     if (elf_interpreter) {
118631e31b8aSbellard 	if (interpreter_type & 1) {
118731e31b8aSbellard 	    elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
118831e31b8aSbellard 	}
118931e31b8aSbellard 	else if (interpreter_type & 2) {
119031e31b8aSbellard 	    elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
119131e31b8aSbellard 					    &interp_load_addr);
119231e31b8aSbellard 	}
119331e31b8aSbellard 
119431e31b8aSbellard 	close(interpreter_fd);
119531e31b8aSbellard 	free(elf_interpreter);
119631e31b8aSbellard 
119731e31b8aSbellard 	if (elf_entry == ~0UL) {
119831e31b8aSbellard 	    printf("Unable to load interpreter\n");
119931e31b8aSbellard 	    free(elf_phdata);
120031e31b8aSbellard 	    exit(-1);
120131e31b8aSbellard 	    return 0;
120231e31b8aSbellard 	}
120331e31b8aSbellard     }
120431e31b8aSbellard 
120531e31b8aSbellard     free(elf_phdata);
120631e31b8aSbellard 
1207689f936fSbellard     if (loglevel)
1208689f936fSbellard 	load_symbols(&elf_ex, bprm->fd);
1209689f936fSbellard 
121031e31b8aSbellard     if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
121131e31b8aSbellard     info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
121231e31b8aSbellard 
121331e31b8aSbellard #ifdef LOW_ELF_STACK
121431e31b8aSbellard     info->start_stack = bprm->p = elf_stack - 4;
121531e31b8aSbellard #endif
121631e31b8aSbellard     bprm->p = (unsigned long)
121731e31b8aSbellard       create_elf_tables((char *)bprm->p,
121831e31b8aSbellard 		    bprm->argc,
121931e31b8aSbellard 		    bprm->envc,
1220a1516e92Sbellard                     &elf_ex,
122109bfb054Sbellard                     load_addr, load_bias,
122231e31b8aSbellard 		    interp_load_addr,
122331e31b8aSbellard 		    (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
122431e31b8aSbellard 		    info);
122531e31b8aSbellard     if (interpreter_type == INTERPRETER_AOUT)
122631e31b8aSbellard       info->arg_start += strlen(passed_fileno) + 1;
122731e31b8aSbellard     info->start_brk = info->brk = elf_brk;
122831e31b8aSbellard     info->end_code = end_code;
122931e31b8aSbellard     info->start_code = start_code;
123031e31b8aSbellard     info->end_data = end_data;
123131e31b8aSbellard     info->start_stack = bprm->p;
123231e31b8aSbellard 
123331e31b8aSbellard     /* Calling set_brk effectively mmaps the pages that we need for the bss and break
123431e31b8aSbellard        sections */
123531e31b8aSbellard     set_brk(elf_bss, elf_brk);
123631e31b8aSbellard 
123731e31b8aSbellard     padzero(elf_bss);
123831e31b8aSbellard 
123931e31b8aSbellard #if 0
124031e31b8aSbellard     printf("(start_brk) %x\n" , info->start_brk);
124131e31b8aSbellard     printf("(end_code) %x\n" , info->end_code);
124231e31b8aSbellard     printf("(start_code) %x\n" , info->start_code);
124331e31b8aSbellard     printf("(end_data) %x\n" , info->end_data);
124431e31b8aSbellard     printf("(start_stack) %x\n" , info->start_stack);
124531e31b8aSbellard     printf("(brk) %x\n" , info->brk);
124631e31b8aSbellard #endif
124731e31b8aSbellard 
124831e31b8aSbellard     if ( info->personality == PER_SVR4 )
124931e31b8aSbellard     {
125031e31b8aSbellard 	    /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
125131e31b8aSbellard 	       and some applications "depend" upon this behavior.
125231e31b8aSbellard 	       Since we do not have the power to recompile these, we
125331e31b8aSbellard 	       emulate the SVr4 behavior.  Sigh.  */
125454936004Sbellard 	    mapped_addr = target_mmap(0, host_page_size, PROT_READ | PROT_EXEC,
125531e31b8aSbellard                                       MAP_FIXED | MAP_PRIVATE, -1, 0);
125631e31b8aSbellard     }
125731e31b8aSbellard 
125831e31b8aSbellard #ifdef ELF_PLAT_INIT
125931e31b8aSbellard     /*
126031e31b8aSbellard      * The ABI may specify that certain registers be set up in special
126131e31b8aSbellard      * ways (on i386 %edx is the address of a DT_FINI function, for
126231e31b8aSbellard      * example.  This macro performs whatever initialization to
126331e31b8aSbellard      * the regs structure is required.
126431e31b8aSbellard      */
126531e31b8aSbellard     ELF_PLAT_INIT(regs);
126631e31b8aSbellard #endif
126731e31b8aSbellard 
126831e31b8aSbellard 
126931e31b8aSbellard     info->entry = elf_entry;
127031e31b8aSbellard 
127131e31b8aSbellard     return 0;
127231e31b8aSbellard }
127331e31b8aSbellard 
127431e31b8aSbellard 
127531e31b8aSbellard 
127632ce6337Sbellard int elf_exec(const char * filename, char ** argv, char ** envp,
1277b17780d5Sbellard              struct target_pt_regs * regs, struct image_info *infop)
127831e31b8aSbellard {
127931e31b8aSbellard         struct linux_binprm bprm;
128031e31b8aSbellard         int retval;
128131e31b8aSbellard         int i;
128231e31b8aSbellard 
128354936004Sbellard         bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
128431e31b8aSbellard         for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
128531e31b8aSbellard                 bprm.page[i] = 0;
128631e31b8aSbellard         retval = open(filename, O_RDONLY);
1287*c2735790Sbellard         if (retval < 0)
1288*c2735790Sbellard             return retval;
128931e31b8aSbellard         bprm.fd = retval;
129031e31b8aSbellard         bprm.filename = (char *)filename;
129131e31b8aSbellard         bprm.sh_bang = 0;
129231e31b8aSbellard         bprm.loader = 0;
129331e31b8aSbellard         bprm.exec = 0;
129431e31b8aSbellard         bprm.dont_iput = 0;
129531e31b8aSbellard 	bprm.argc = count(argv);
129631e31b8aSbellard 	bprm.envc = count(envp);
129731e31b8aSbellard 
129831e31b8aSbellard         retval = prepare_binprm(&bprm);
129931e31b8aSbellard 
130031e31b8aSbellard         if(retval>=0) {
130131e31b8aSbellard 	    bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p);
130231e31b8aSbellard 	    bprm.exec = bprm.p;
130331e31b8aSbellard 	    bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p);
130431e31b8aSbellard 	    bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p);
130531e31b8aSbellard 	    if (!bprm.p) {
130631e31b8aSbellard 		retval = -E2BIG;
130731e31b8aSbellard 	    }
130831e31b8aSbellard         }
130931e31b8aSbellard 
131031e31b8aSbellard         if(retval>=0) {
131131e31b8aSbellard 	    retval = load_elf_binary(&bprm,regs,infop);
131231e31b8aSbellard 	}
131331e31b8aSbellard         if(retval>=0) {
131431e31b8aSbellard 	    /* success.  Initialize important registers */
1315b346ff46Sbellard             init_thread(regs, infop);
131631e31b8aSbellard 	    return retval;
131731e31b8aSbellard 	}
131831e31b8aSbellard 
131931e31b8aSbellard         /* Something went wrong, return the inode and free the argument pages*/
132031e31b8aSbellard         for (i=0 ; i<MAX_ARG_PAGES ; i++) {
132131e31b8aSbellard 	    free_page((void *)bprm.page[i]);
132231e31b8aSbellard 	}
132331e31b8aSbellard         return(retval);
132431e31b8aSbellard }
132531e31b8aSbellard 
132631e31b8aSbellard 
132731e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd)
132831e31b8aSbellard {
132931e31b8aSbellard     printf("a.out interpreter not yet supported\n");
133031e31b8aSbellard     return(0);
133131e31b8aSbellard }
133231e31b8aSbellard 
1333