xref: /qemu/linux-user/elfload.c (revision eba2af633fb8fa3b20ad578184d79e1f0eabcefe)
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 {                                                       \
130274da6b2Sbellard     target_ulong *pos = (target_ulong *)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 static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
26709bfb054Sbellard {
26809bfb054Sbellard 	memcpy(to, from, n);
26909bfb054Sbellard }
27009bfb054Sbellard 
27131e31b8aSbellard extern unsigned long x86_stack_size;
27231e31b8aSbellard 
27331e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd);
27431e31b8aSbellard 
27531e31b8aSbellard #ifdef BSWAP_NEEDED
27631e31b8aSbellard static void bswap_ehdr(Elf32_Ehdr *ehdr)
27731e31b8aSbellard {
27831e31b8aSbellard     bswap16s(&ehdr->e_type);			/* Object file type */
27931e31b8aSbellard     bswap16s(&ehdr->e_machine);		/* Architecture */
28031e31b8aSbellard     bswap32s(&ehdr->e_version);		/* Object file version */
28131e31b8aSbellard     bswap32s(&ehdr->e_entry);		/* Entry point virtual address */
28231e31b8aSbellard     bswap32s(&ehdr->e_phoff);		/* Program header table file offset */
28331e31b8aSbellard     bswap32s(&ehdr->e_shoff);		/* Section header table file offset */
28431e31b8aSbellard     bswap32s(&ehdr->e_flags);		/* Processor-specific flags */
28531e31b8aSbellard     bswap16s(&ehdr->e_ehsize);		/* ELF header size in bytes */
28631e31b8aSbellard     bswap16s(&ehdr->e_phentsize);		/* Program header table entry size */
28731e31b8aSbellard     bswap16s(&ehdr->e_phnum);		/* Program header table entry count */
28831e31b8aSbellard     bswap16s(&ehdr->e_shentsize);		/* Section header table entry size */
28931e31b8aSbellard     bswap16s(&ehdr->e_shnum);		/* Section header table entry count */
29031e31b8aSbellard     bswap16s(&ehdr->e_shstrndx);		/* Section header string table index */
29131e31b8aSbellard }
29231e31b8aSbellard 
29331e31b8aSbellard static void bswap_phdr(Elf32_Phdr *phdr)
29431e31b8aSbellard {
29531e31b8aSbellard     bswap32s(&phdr->p_type);			/* Segment type */
29631e31b8aSbellard     bswap32s(&phdr->p_offset);		/* Segment file offset */
29731e31b8aSbellard     bswap32s(&phdr->p_vaddr);		/* Segment virtual address */
29831e31b8aSbellard     bswap32s(&phdr->p_paddr);		/* Segment physical address */
29931e31b8aSbellard     bswap32s(&phdr->p_filesz);		/* Segment size in file */
30031e31b8aSbellard     bswap32s(&phdr->p_memsz);		/* Segment size in memory */
30131e31b8aSbellard     bswap32s(&phdr->p_flags);		/* Segment flags */
30231e31b8aSbellard     bswap32s(&phdr->p_align);		/* Segment alignment */
30331e31b8aSbellard }
304689f936fSbellard 
305689f936fSbellard static void bswap_shdr(Elf32_Shdr *shdr)
306689f936fSbellard {
307689f936fSbellard     bswap32s(&shdr->sh_name);
308689f936fSbellard     bswap32s(&shdr->sh_type);
309689f936fSbellard     bswap32s(&shdr->sh_flags);
310689f936fSbellard     bswap32s(&shdr->sh_addr);
311689f936fSbellard     bswap32s(&shdr->sh_offset);
312689f936fSbellard     bswap32s(&shdr->sh_size);
313689f936fSbellard     bswap32s(&shdr->sh_link);
314689f936fSbellard     bswap32s(&shdr->sh_info);
315689f936fSbellard     bswap32s(&shdr->sh_addralign);
316689f936fSbellard     bswap32s(&shdr->sh_entsize);
317689f936fSbellard }
318689f936fSbellard 
319689f936fSbellard static void bswap_sym(Elf32_Sym *sym)
320689f936fSbellard {
321689f936fSbellard     bswap32s(&sym->st_name);
322689f936fSbellard     bswap32s(&sym->st_value);
323689f936fSbellard     bswap32s(&sym->st_size);
324689f936fSbellard     bswap16s(&sym->st_shndx);
325689f936fSbellard }
32631e31b8aSbellard #endif
32731e31b8aSbellard 
32831e31b8aSbellard static void * get_free_page(void)
32931e31b8aSbellard {
33031e31b8aSbellard     void *	retval;
33131e31b8aSbellard 
33231e31b8aSbellard     /* User-space version of kernel get_free_page.  Returns a page-aligned
33331e31b8aSbellard      * page-sized chunk of memory.
33431e31b8aSbellard      */
33554936004Sbellard     retval = (void *)target_mmap(0, host_page_size, PROT_READ|PROT_WRITE,
33631e31b8aSbellard                                  MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
33731e31b8aSbellard 
33831e31b8aSbellard     if((long)retval == -1) {
33931e31b8aSbellard 	perror("get_free_page");
34031e31b8aSbellard 	exit(-1);
34131e31b8aSbellard     }
34231e31b8aSbellard     else {
34331e31b8aSbellard 	return(retval);
34431e31b8aSbellard     }
34531e31b8aSbellard }
34631e31b8aSbellard 
34731e31b8aSbellard static void free_page(void * pageaddr)
34831e31b8aSbellard {
34954936004Sbellard     target_munmap((unsigned long)pageaddr, host_page_size);
35031e31b8aSbellard }
35131e31b8aSbellard 
35231e31b8aSbellard /*
35331e31b8aSbellard  * 'copy_string()' copies argument/envelope strings from user
35431e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
35531e31b8aSbellard  * to be put directly into the top of new user memory.
35631e31b8aSbellard  *
35731e31b8aSbellard  */
35831e31b8aSbellard static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
35931e31b8aSbellard                 unsigned long p)
36031e31b8aSbellard {
36131e31b8aSbellard     char *tmp, *tmp1, *pag = NULL;
36231e31b8aSbellard     int len, offset = 0;
36331e31b8aSbellard 
36431e31b8aSbellard     if (!p) {
36531e31b8aSbellard 	return 0;       /* bullet-proofing */
36631e31b8aSbellard     }
36731e31b8aSbellard     while (argc-- > 0) {
368edf779ffSbellard         tmp = argv[argc];
369edf779ffSbellard         if (!tmp) {
37031e31b8aSbellard 	    fprintf(stderr, "VFS: argc is wrong");
37131e31b8aSbellard 	    exit(-1);
37231e31b8aSbellard 	}
373edf779ffSbellard         tmp1 = tmp;
374edf779ffSbellard 	while (*tmp++);
37531e31b8aSbellard 	len = tmp - tmp1;
37631e31b8aSbellard 	if (p < len) {  /* this shouldn't happen - 128kB */
37731e31b8aSbellard 		return 0;
37831e31b8aSbellard 	}
37931e31b8aSbellard 	while (len) {
38031e31b8aSbellard 	    --p; --tmp; --len;
38131e31b8aSbellard 	    if (--offset < 0) {
38254936004Sbellard 		offset = p % TARGET_PAGE_SIZE;
38344a91caeSbellard                 pag = (char *) page[p/TARGET_PAGE_SIZE];
38444a91caeSbellard                 if (!pag) {
38544a91caeSbellard                     pag = (char *)get_free_page();
38644a91caeSbellard                     page[p/TARGET_PAGE_SIZE] = (unsigned long)pag;
38744a91caeSbellard                     if (!pag)
38831e31b8aSbellard                         return 0;
38931e31b8aSbellard 		}
39031e31b8aSbellard 	    }
39131e31b8aSbellard 	    if (len == 0 || offset == 0) {
392edf779ffSbellard 	        *(pag + offset) = *tmp;
39331e31b8aSbellard 	    }
39431e31b8aSbellard 	    else {
39531e31b8aSbellard 	      int bytes_to_copy = (len > offset) ? offset : len;
39631e31b8aSbellard 	      tmp -= bytes_to_copy;
39731e31b8aSbellard 	      p -= bytes_to_copy;
39831e31b8aSbellard 	      offset -= bytes_to_copy;
39931e31b8aSbellard 	      len -= bytes_to_copy;
40031e31b8aSbellard 	      memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
40131e31b8aSbellard 	    }
40231e31b8aSbellard 	}
40331e31b8aSbellard     }
40431e31b8aSbellard     return p;
40531e31b8aSbellard }
40631e31b8aSbellard 
40731e31b8aSbellard static int in_group_p(gid_t g)
40831e31b8aSbellard {
40931e31b8aSbellard     /* return TRUE if we're in the specified group, FALSE otherwise */
41031e31b8aSbellard     int		ngroup;
41131e31b8aSbellard     int		i;
41231e31b8aSbellard     gid_t	grouplist[NGROUPS];
41331e31b8aSbellard 
41431e31b8aSbellard     ngroup = getgroups(NGROUPS, grouplist);
41531e31b8aSbellard     for(i = 0; i < ngroup; i++) {
41631e31b8aSbellard 	if(grouplist[i] == g) {
41731e31b8aSbellard 	    return 1;
41831e31b8aSbellard 	}
41931e31b8aSbellard     }
42031e31b8aSbellard     return 0;
42131e31b8aSbellard }
42231e31b8aSbellard 
42331e31b8aSbellard static int count(char ** vec)
42431e31b8aSbellard {
42531e31b8aSbellard     int		i;
42631e31b8aSbellard 
42731e31b8aSbellard     for(i = 0; *vec; i++) {
42831e31b8aSbellard         vec++;
42931e31b8aSbellard     }
43031e31b8aSbellard 
43131e31b8aSbellard     return(i);
43231e31b8aSbellard }
43331e31b8aSbellard 
43431e31b8aSbellard static int prepare_binprm(struct linux_binprm *bprm)
43531e31b8aSbellard {
43631e31b8aSbellard     struct stat		st;
43731e31b8aSbellard     int mode;
43831e31b8aSbellard     int retval, id_change;
43931e31b8aSbellard 
44031e31b8aSbellard     if(fstat(bprm->fd, &st) < 0) {
44131e31b8aSbellard 	return(-errno);
44231e31b8aSbellard     }
44331e31b8aSbellard 
44431e31b8aSbellard     mode = st.st_mode;
44531e31b8aSbellard     if(!S_ISREG(mode)) {	/* Must be regular file */
44631e31b8aSbellard 	return(-EACCES);
44731e31b8aSbellard     }
44831e31b8aSbellard     if(!(mode & 0111)) {	/* Must have at least one execute bit set */
44931e31b8aSbellard 	return(-EACCES);
45031e31b8aSbellard     }
45131e31b8aSbellard 
45231e31b8aSbellard     bprm->e_uid = geteuid();
45331e31b8aSbellard     bprm->e_gid = getegid();
45431e31b8aSbellard     id_change = 0;
45531e31b8aSbellard 
45631e31b8aSbellard     /* Set-uid? */
45731e31b8aSbellard     if(mode & S_ISUID) {
45831e31b8aSbellard     	bprm->e_uid = st.st_uid;
45931e31b8aSbellard 	if(bprm->e_uid != geteuid()) {
46031e31b8aSbellard 	    id_change = 1;
46131e31b8aSbellard 	}
46231e31b8aSbellard     }
46331e31b8aSbellard 
46431e31b8aSbellard     /* Set-gid? */
46531e31b8aSbellard     /*
46631e31b8aSbellard      * If setgid is set but no group execute bit then this
46731e31b8aSbellard      * is a candidate for mandatory locking, not a setgid
46831e31b8aSbellard      * executable.
46931e31b8aSbellard      */
47031e31b8aSbellard     if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
47131e31b8aSbellard 	bprm->e_gid = st.st_gid;
47231e31b8aSbellard 	if (!in_group_p(bprm->e_gid)) {
47331e31b8aSbellard 		id_change = 1;
47431e31b8aSbellard 	}
47531e31b8aSbellard     }
47631e31b8aSbellard 
47731e31b8aSbellard     memset(bprm->buf, 0, sizeof(bprm->buf));
47831e31b8aSbellard     retval = lseek(bprm->fd, 0L, SEEK_SET);
47931e31b8aSbellard     if(retval >= 0) {
48031e31b8aSbellard         retval = read(bprm->fd, bprm->buf, 128);
48131e31b8aSbellard     }
48231e31b8aSbellard     if(retval < 0) {
48331e31b8aSbellard 	perror("prepare_binprm");
48431e31b8aSbellard 	exit(-1);
48531e31b8aSbellard 	/* return(-errno); */
48631e31b8aSbellard     }
48731e31b8aSbellard     else {
48831e31b8aSbellard 	return(retval);
48931e31b8aSbellard     }
49031e31b8aSbellard }
49131e31b8aSbellard 
49231e31b8aSbellard unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
49331e31b8aSbellard 						struct image_info * info)
49431e31b8aSbellard {
49509bfb054Sbellard     unsigned long stack_base, size, error;
49631e31b8aSbellard     int i;
49731e31b8aSbellard 
49831e31b8aSbellard     /* Create enough stack to hold everything.  If we don't use
49931e31b8aSbellard      * it for args, we'll use it for something else...
50031e31b8aSbellard      */
50109bfb054Sbellard     size = x86_stack_size;
50254936004Sbellard     if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
50354936004Sbellard         size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
50454936004Sbellard     error = target_mmap(0,
50554936004Sbellard                         size + host_page_size,
50631e31b8aSbellard                         PROT_READ | PROT_WRITE,
50709bfb054Sbellard                         MAP_PRIVATE | MAP_ANONYMOUS,
50809bfb054Sbellard                         -1, 0);
50909bfb054Sbellard     if (error == -1) {
51031e31b8aSbellard         perror("stk mmap");
51131e31b8aSbellard         exit(-1);
51231e31b8aSbellard     }
51309bfb054Sbellard     /* we reserve one extra page at the top of the stack as guard */
51454936004Sbellard     target_mprotect(error + size, host_page_size, PROT_NONE);
51531e31b8aSbellard 
51654936004Sbellard     stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
51709bfb054Sbellard     p += stack_base;
51809bfb054Sbellard 
51909bfb054Sbellard     if (bprm->loader) {
52009bfb054Sbellard 	bprm->loader += stack_base;
52109bfb054Sbellard     }
52209bfb054Sbellard     bprm->exec += stack_base;
52331e31b8aSbellard 
52431e31b8aSbellard     for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
52531e31b8aSbellard 	if (bprm->page[i]) {
52631e31b8aSbellard 	    info->rss++;
52731e31b8aSbellard 
52854936004Sbellard 	    memcpy((void *)stack_base, (void *)bprm->page[i], TARGET_PAGE_SIZE);
52931e31b8aSbellard 	    free_page((void *)bprm->page[i]);
53031e31b8aSbellard 	}
53154936004Sbellard 	stack_base += TARGET_PAGE_SIZE;
53231e31b8aSbellard     }
53331e31b8aSbellard     return p;
53431e31b8aSbellard }
53531e31b8aSbellard 
53631e31b8aSbellard static void set_brk(unsigned long start, unsigned long end)
53731e31b8aSbellard {
53831e31b8aSbellard 	/* page-align the start and end addresses... */
53954936004Sbellard         start = HOST_PAGE_ALIGN(start);
54054936004Sbellard         end = HOST_PAGE_ALIGN(end);
54131e31b8aSbellard         if (end <= start)
54231e31b8aSbellard                 return;
54354936004Sbellard         if(target_mmap(start, end - start,
54431e31b8aSbellard                        PROT_READ | PROT_WRITE | PROT_EXEC,
54531e31b8aSbellard                        MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
54631e31b8aSbellard 	    perror("cannot mmap brk");
54731e31b8aSbellard 	    exit(-1);
54831e31b8aSbellard 	}
54931e31b8aSbellard }
55031e31b8aSbellard 
55131e31b8aSbellard 
552853d6f7aSbellard /* We need to explicitly zero any fractional pages after the data
553853d6f7aSbellard    section (i.e. bss).  This would contain the junk from the file that
554853d6f7aSbellard    should not be in memory. */
55531e31b8aSbellard static void padzero(unsigned long elf_bss)
55631e31b8aSbellard {
55731e31b8aSbellard         unsigned long nbyte;
55831e31b8aSbellard         char * fpnt;
55931e31b8aSbellard 
560853d6f7aSbellard         /* XXX: this is really a hack : if the real host page size is
561853d6f7aSbellard            smaller than the target page size, some pages after the end
562853d6f7aSbellard            of the file may not be mapped. A better fix would be to
563853d6f7aSbellard            patch target_mmap(), but it is more complicated as the file
564853d6f7aSbellard            size must be known */
565853d6f7aSbellard         if (real_host_page_size < host_page_size) {
566853d6f7aSbellard             unsigned long end_addr, end_addr1;
567853d6f7aSbellard             end_addr1 = (elf_bss + real_host_page_size - 1) &
568853d6f7aSbellard                 ~(real_host_page_size - 1);
569853d6f7aSbellard             end_addr = HOST_PAGE_ALIGN(elf_bss);
570853d6f7aSbellard             if (end_addr1 < end_addr) {
571853d6f7aSbellard                 mmap((void *)end_addr1, end_addr - end_addr1,
572853d6f7aSbellard                      PROT_READ|PROT_WRITE|PROT_EXEC,
573853d6f7aSbellard                      MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
574853d6f7aSbellard             }
575853d6f7aSbellard         }
576853d6f7aSbellard 
577853d6f7aSbellard         nbyte = elf_bss & (host_page_size-1);
57831e31b8aSbellard         if (nbyte) {
57954936004Sbellard 	    nbyte = host_page_size - nbyte;
58031e31b8aSbellard 	    fpnt = (char *) elf_bss;
58131e31b8aSbellard 	    do {
58231e31b8aSbellard 		*fpnt++ = 0;
58331e31b8aSbellard 	    } while (--nbyte);
58431e31b8aSbellard         }
58531e31b8aSbellard }
58631e31b8aSbellard 
58731e31b8aSbellard static unsigned int * create_elf_tables(char *p, int argc, int envc,
58831e31b8aSbellard                                         struct elfhdr * exec,
58931e31b8aSbellard                                         unsigned long load_addr,
59009bfb054Sbellard                                         unsigned long load_bias,
59131e31b8aSbellard                                         unsigned long interp_load_addr, int ibcs,
59231e31b8aSbellard                                         struct image_info *info)
59331e31b8aSbellard {
594f5155289Sbellard         target_ulong *argv, *envp;
595f5155289Sbellard         target_ulong *sp, *csp;
596edf779ffSbellard         int v;
59731e31b8aSbellard 
59831e31b8aSbellard 	/*
599f5155289Sbellard 	 * Force 16 byte _final_ alignment here for generality.
60031e31b8aSbellard 	 */
60131e31b8aSbellard         sp = (unsigned int *) (~15UL & (unsigned long) p);
602f5155289Sbellard         csp = sp;
603f5155289Sbellard         csp -= (DLINFO_ITEMS + 1) * 2;
604f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS
605f5155289Sbellard 	csp -= DLINFO_ARCH_ITEMS*2;
606f5155289Sbellard #endif
607f5155289Sbellard         csp -= envc+1;
608f5155289Sbellard         csp -= argc+1;
609f5155289Sbellard 	csp -= (!ibcs ? 3 : 1);	/* argc itself */
610f5155289Sbellard         if ((unsigned long)csp & 15UL)
611f5155289Sbellard             sp -= ((unsigned long)csp & 15UL) / sizeof(*sp);
612f5155289Sbellard 
613f5155289Sbellard #define NEW_AUX_ENT(nr, id, val) \
614edf779ffSbellard           put_user (id, sp + (nr * 2)); \
615edf779ffSbellard           put_user (val, sp + (nr * 2 + 1))
616f5155289Sbellard         sp -= 2;
617f5155289Sbellard         NEW_AUX_ENT (0, AT_NULL, 0);
618f5155289Sbellard 
619a1516e92Sbellard 	sp -= DLINFO_ITEMS*2;
620f5155289Sbellard         NEW_AUX_ENT( 0, AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
621f5155289Sbellard         NEW_AUX_ENT( 1, AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
622f5155289Sbellard         NEW_AUX_ENT( 2, AT_PHNUM, (target_ulong)(exec->e_phnum));
623f5155289Sbellard         NEW_AUX_ENT( 3, AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
624f5155289Sbellard         NEW_AUX_ENT( 4, AT_BASE, (target_ulong)(interp_load_addr));
625f5155289Sbellard         NEW_AUX_ENT( 5, AT_FLAGS, (target_ulong)0);
626f5155289Sbellard         NEW_AUX_ENT( 6, AT_ENTRY, load_bias + exec->e_entry);
627f5155289Sbellard         NEW_AUX_ENT( 7, AT_UID, (target_ulong) getuid());
628f5155289Sbellard         NEW_AUX_ENT( 8, AT_EUID, (target_ulong) geteuid());
629f5155289Sbellard         NEW_AUX_ENT( 9, AT_GID, (target_ulong) getgid());
630f5155289Sbellard         NEW_AUX_ENT(11, AT_EGID, (target_ulong) getegid());
631f5155289Sbellard #ifdef ARCH_DLINFO
632f5155289Sbellard 	/*
633f5155289Sbellard 	 * ARCH_DLINFO must come last so platform specific code can enforce
634f5155289Sbellard 	 * special alignment requirements on the AUXV if necessary (eg. PPC).
635f5155289Sbellard 	 */
636f5155289Sbellard         ARCH_DLINFO;
637f5155289Sbellard #endif
638f5155289Sbellard #undef NEW_AUX_ENT
639f5155289Sbellard 
64031e31b8aSbellard         sp -= envc+1;
64131e31b8aSbellard         envp = sp;
64231e31b8aSbellard         sp -= argc+1;
64331e31b8aSbellard         argv = sp;
64431e31b8aSbellard         if (!ibcs) {
645edf779ffSbellard                 put_user((target_ulong)envp,--sp);
646edf779ffSbellard                 put_user((target_ulong)argv,--sp);
64731e31b8aSbellard         }
648edf779ffSbellard         put_user(argc,--sp);
64931e31b8aSbellard         info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff);
65031e31b8aSbellard         while (argc-->0) {
651edf779ffSbellard                 put_user((target_ulong)p,argv++);
652edf779ffSbellard                 do {
653edf779ffSbellard                     get_user(v, p);
654edf779ffSbellard                     p++;
655edf779ffSbellard                 } while (v != 0);
65631e31b8aSbellard         }
65731e31b8aSbellard         put_user(0,argv);
65831e31b8aSbellard         info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff);
65931e31b8aSbellard         while (envc-->0) {
660edf779ffSbellard                 put_user((target_ulong)p,envp++);
661edf779ffSbellard                 do {
662edf779ffSbellard                     get_user(v, p);
663edf779ffSbellard                     p++;
664edf779ffSbellard                 } while (v != 0);
66531e31b8aSbellard         }
66631e31b8aSbellard         put_user(0,envp);
66731e31b8aSbellard         info->env_end = (unsigned int)((unsigned long)p & 0xffffffff);
66831e31b8aSbellard         return sp;
66931e31b8aSbellard }
67031e31b8aSbellard 
67131e31b8aSbellard 
67231e31b8aSbellard 
67331e31b8aSbellard static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
67431e31b8aSbellard 				     int interpreter_fd,
67531e31b8aSbellard 				     unsigned long *interp_load_addr)
67631e31b8aSbellard {
67731e31b8aSbellard 	struct elf_phdr *elf_phdata  =  NULL;
67831e31b8aSbellard 	struct elf_phdr *eppnt;
67909bfb054Sbellard 	unsigned long load_addr = 0;
68031e31b8aSbellard 	int load_addr_set = 0;
68131e31b8aSbellard 	int retval;
68231e31b8aSbellard 	unsigned long last_bss, elf_bss;
68331e31b8aSbellard 	unsigned long error;
68431e31b8aSbellard 	int i;
68531e31b8aSbellard 
68631e31b8aSbellard 	elf_bss = 0;
68731e31b8aSbellard 	last_bss = 0;
68831e31b8aSbellard 	error = 0;
68931e31b8aSbellard 
690644c433cSbellard #ifdef BSWAP_NEEDED
691644c433cSbellard         bswap_ehdr(interp_elf_ex);
692644c433cSbellard #endif
69331e31b8aSbellard 	/* First of all, some simple consistency checks */
69431e31b8aSbellard 	if ((interp_elf_ex->e_type != ET_EXEC &&
69531e31b8aSbellard              interp_elf_ex->e_type != ET_DYN) ||
69631e31b8aSbellard 	   !elf_check_arch(interp_elf_ex->e_machine)) {
69731e31b8aSbellard 		return ~0UL;
69831e31b8aSbellard 	}
69931e31b8aSbellard 
700644c433cSbellard 
70131e31b8aSbellard 	/* Now read in all of the header information */
70231e31b8aSbellard 
70354936004Sbellard 	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
70431e31b8aSbellard 	    return ~0UL;
70531e31b8aSbellard 
70631e31b8aSbellard 	elf_phdata =  (struct elf_phdr *)
70731e31b8aSbellard 		malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
70831e31b8aSbellard 
70931e31b8aSbellard 	if (!elf_phdata)
71031e31b8aSbellard 	  return ~0UL;
71131e31b8aSbellard 
71231e31b8aSbellard 	/*
71331e31b8aSbellard 	 * If the size of this structure has changed, then punt, since
71431e31b8aSbellard 	 * we will be doing the wrong thing.
71531e31b8aSbellard 	 */
71609bfb054Sbellard 	if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
71731e31b8aSbellard 	    free(elf_phdata);
71831e31b8aSbellard 	    return ~0UL;
71931e31b8aSbellard         }
72031e31b8aSbellard 
72131e31b8aSbellard 	retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
72231e31b8aSbellard 	if(retval >= 0) {
72331e31b8aSbellard 	    retval = read(interpreter_fd,
72431e31b8aSbellard 			   (char *) elf_phdata,
72531e31b8aSbellard 			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
72631e31b8aSbellard 	}
72731e31b8aSbellard 	if (retval < 0) {
72831e31b8aSbellard 		perror("load_elf_interp");
72931e31b8aSbellard 		exit(-1);
73031e31b8aSbellard 		free (elf_phdata);
73131e31b8aSbellard 		return retval;
73231e31b8aSbellard  	}
73331e31b8aSbellard #ifdef BSWAP_NEEDED
73431e31b8aSbellard 	eppnt = elf_phdata;
73531e31b8aSbellard 	for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
73631e31b8aSbellard             bswap_phdr(eppnt);
73731e31b8aSbellard         }
73831e31b8aSbellard #endif
73909bfb054Sbellard 
74009bfb054Sbellard         if (interp_elf_ex->e_type == ET_DYN) {
74109bfb054Sbellard             /* in order to avoid harcoding the interpreter load
74209bfb054Sbellard                address in qemu, we allocate a big enough memory zone */
74354936004Sbellard             error = target_mmap(0, INTERP_MAP_SIZE,
74409bfb054Sbellard                                 PROT_NONE, MAP_PRIVATE | MAP_ANON,
74509bfb054Sbellard                                 -1, 0);
74609bfb054Sbellard             if (error == -1) {
74709bfb054Sbellard                 perror("mmap");
74809bfb054Sbellard                 exit(-1);
74909bfb054Sbellard             }
75009bfb054Sbellard             load_addr = error;
75109bfb054Sbellard             load_addr_set = 1;
75209bfb054Sbellard         }
75309bfb054Sbellard 
75431e31b8aSbellard 	eppnt = elf_phdata;
75531e31b8aSbellard 	for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
75631e31b8aSbellard 	  if (eppnt->p_type == PT_LOAD) {
75731e31b8aSbellard 	    int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
75831e31b8aSbellard 	    int elf_prot = 0;
75931e31b8aSbellard 	    unsigned long vaddr = 0;
76031e31b8aSbellard 	    unsigned long k;
76131e31b8aSbellard 
76231e31b8aSbellard 	    if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
76331e31b8aSbellard 	    if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
76431e31b8aSbellard 	    if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
76531e31b8aSbellard 	    if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
76631e31b8aSbellard 	    	elf_type |= MAP_FIXED;
76731e31b8aSbellard 	    	vaddr = eppnt->p_vaddr;
76831e31b8aSbellard 	    }
76954936004Sbellard 	    error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
77054936004Sbellard 		 eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
77131e31b8aSbellard 		 elf_prot,
77231e31b8aSbellard 		 elf_type,
77331e31b8aSbellard 		 interpreter_fd,
77454936004Sbellard 		 eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
77531e31b8aSbellard 
77631e31b8aSbellard 	    if (error > -1024UL) {
77731e31b8aSbellard 	      /* Real error */
77831e31b8aSbellard 	      close(interpreter_fd);
77931e31b8aSbellard 	      free(elf_phdata);
78031e31b8aSbellard 	      return ~0UL;
78131e31b8aSbellard 	    }
78231e31b8aSbellard 
78331e31b8aSbellard 	    if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
78431e31b8aSbellard 	      load_addr = error;
78531e31b8aSbellard 	      load_addr_set = 1;
78631e31b8aSbellard 	    }
78731e31b8aSbellard 
78831e31b8aSbellard 	    /*
78931e31b8aSbellard 	     * Find the end of the file  mapping for this phdr, and keep
79031e31b8aSbellard 	     * track of the largest address we see for this.
79131e31b8aSbellard 	     */
79231e31b8aSbellard 	    k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
79331e31b8aSbellard 	    if (k > elf_bss) elf_bss = k;
79431e31b8aSbellard 
79531e31b8aSbellard 	    /*
79631e31b8aSbellard 	     * Do the same thing for the memory mapping - between
79731e31b8aSbellard 	     * elf_bss and last_bss is the bss section.
79831e31b8aSbellard 	     */
79931e31b8aSbellard 	    k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
80031e31b8aSbellard 	    if (k > last_bss) last_bss = k;
80131e31b8aSbellard 	  }
80231e31b8aSbellard 
80331e31b8aSbellard 	/* Now use mmap to map the library into memory. */
80431e31b8aSbellard 
80531e31b8aSbellard 	close(interpreter_fd);
80631e31b8aSbellard 
80731e31b8aSbellard 	/*
80831e31b8aSbellard 	 * Now fill out the bss section.  First pad the last page up
80931e31b8aSbellard 	 * to the page boundary, and then perform a mmap to make sure
81031e31b8aSbellard 	 * that there are zeromapped pages up to and including the last
81131e31b8aSbellard 	 * bss page.
81231e31b8aSbellard 	 */
81331e31b8aSbellard 	padzero(elf_bss);
81454936004Sbellard 	elf_bss = TARGET_ELF_PAGESTART(elf_bss + host_page_size - 1); /* What we have mapped so far */
81531e31b8aSbellard 
81631e31b8aSbellard 	/* Map the last of the bss segment */
81731e31b8aSbellard 	if (last_bss > elf_bss) {
81854936004Sbellard             target_mmap(elf_bss, last_bss-elf_bss,
81931e31b8aSbellard                         PROT_READ|PROT_WRITE|PROT_EXEC,
82031e31b8aSbellard                         MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
82131e31b8aSbellard 	}
82231e31b8aSbellard 	free(elf_phdata);
82331e31b8aSbellard 
82431e31b8aSbellard 	*interp_load_addr = load_addr;
82531e31b8aSbellard 	return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
82631e31b8aSbellard }
82731e31b8aSbellard 
828689f936fSbellard /* Best attempt to load symbols from this ELF object. */
829689f936fSbellard static void load_symbols(struct elfhdr *hdr, int fd)
830689f936fSbellard {
831689f936fSbellard     unsigned int i;
832689f936fSbellard     struct elf_shdr sechdr, symtab, strtab;
833689f936fSbellard     char *strings;
83431e31b8aSbellard 
835689f936fSbellard     lseek(fd, hdr->e_shoff, SEEK_SET);
836689f936fSbellard     for (i = 0; i < hdr->e_shnum; i++) {
837689f936fSbellard 	if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
838689f936fSbellard 	    return;
839689f936fSbellard #ifdef BSWAP_NEEDED
840689f936fSbellard 	bswap_shdr(&sechdr);
841689f936fSbellard #endif
842689f936fSbellard 	if (sechdr.sh_type == SHT_SYMTAB) {
843689f936fSbellard 	    symtab = sechdr;
844689f936fSbellard 	    lseek(fd, hdr->e_shoff
845689f936fSbellard 		  + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
846689f936fSbellard 	    if (read(fd, &strtab, sizeof(strtab))
847689f936fSbellard 		!= sizeof(strtab))
848689f936fSbellard 		return;
849689f936fSbellard #ifdef BSWAP_NEEDED
850689f936fSbellard 	    bswap_shdr(&strtab);
851689f936fSbellard #endif
852689f936fSbellard 	    goto found;
853689f936fSbellard 	}
854689f936fSbellard     }
855689f936fSbellard     return; /* Shouldn't happen... */
856689f936fSbellard 
857689f936fSbellard  found:
858689f936fSbellard     /* Now know where the strtab and symtab are.  Snarf them. */
859689f936fSbellard     disas_symtab = malloc(symtab.sh_size);
860689f936fSbellard     disas_strtab = strings = malloc(strtab.sh_size);
861689f936fSbellard     if (!disas_symtab || !disas_strtab)
862689f936fSbellard 	return;
863689f936fSbellard 
864689f936fSbellard     lseek(fd, symtab.sh_offset, SEEK_SET);
865689f936fSbellard     if (read(fd, disas_symtab, symtab.sh_size) != symtab.sh_size)
866689f936fSbellard 	return;
867689f936fSbellard 
868689f936fSbellard #ifdef BSWAP_NEEDED
869689f936fSbellard     for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++)
870689f936fSbellard 	bswap_sym(disas_symtab + sizeof(struct elf_sym)*i);
871689f936fSbellard #endif
872689f936fSbellard 
873689f936fSbellard     lseek(fd, strtab.sh_offset, SEEK_SET);
874689f936fSbellard     if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
875689f936fSbellard 	return;
876689f936fSbellard     disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
877689f936fSbellard }
87831e31b8aSbellard 
879b17780d5Sbellard static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
88031e31b8aSbellard                            struct image_info * info)
88131e31b8aSbellard {
88231e31b8aSbellard     struct elfhdr elf_ex;
88331e31b8aSbellard     struct elfhdr interp_elf_ex;
88431e31b8aSbellard     struct exec interp_ex;
88531e31b8aSbellard     int interpreter_fd = -1; /* avoid warning */
88609bfb054Sbellard     unsigned long load_addr, load_bias;
88731e31b8aSbellard     int load_addr_set = 0;
88831e31b8aSbellard     unsigned int interpreter_type = INTERPRETER_NONE;
88931e31b8aSbellard     unsigned char ibcs2_interpreter;
89031e31b8aSbellard     int i;
89154936004Sbellard     unsigned long mapped_addr;
89231e31b8aSbellard     struct elf_phdr * elf_ppnt;
89331e31b8aSbellard     struct elf_phdr *elf_phdata;
89431e31b8aSbellard     unsigned long elf_bss, k, elf_brk;
89531e31b8aSbellard     int retval;
89631e31b8aSbellard     char * elf_interpreter;
89731e31b8aSbellard     unsigned long elf_entry, interp_load_addr = 0;
89831e31b8aSbellard     int status;
89931e31b8aSbellard     unsigned long start_code, end_code, end_data;
90031e31b8aSbellard     unsigned long elf_stack;
90131e31b8aSbellard     char passed_fileno[6];
90231e31b8aSbellard 
90331e31b8aSbellard     ibcs2_interpreter = 0;
90431e31b8aSbellard     status = 0;
90531e31b8aSbellard     load_addr = 0;
90609bfb054Sbellard     load_bias = 0;
90731e31b8aSbellard     elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
90831e31b8aSbellard #ifdef BSWAP_NEEDED
90931e31b8aSbellard     bswap_ehdr(&elf_ex);
91031e31b8aSbellard #endif
91131e31b8aSbellard 
91231e31b8aSbellard     if (elf_ex.e_ident[0] != 0x7f ||
91331e31b8aSbellard 	strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
91431e31b8aSbellard 	    return  -ENOEXEC;
91531e31b8aSbellard     }
91631e31b8aSbellard 
91731e31b8aSbellard     /* First of all, some simple consistency checks */
91831e31b8aSbellard     if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
91931e31b8aSbellard        				(! elf_check_arch(elf_ex.e_machine))) {
92031e31b8aSbellard 	    return -ENOEXEC;
92131e31b8aSbellard     }
92231e31b8aSbellard 
92331e31b8aSbellard     /* Now read in all of the header information */
92431e31b8aSbellard     elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
92531e31b8aSbellard     if (elf_phdata == NULL) {
92631e31b8aSbellard 	return -ENOMEM;
92731e31b8aSbellard     }
92831e31b8aSbellard 
92931e31b8aSbellard     retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
93031e31b8aSbellard     if(retval > 0) {
93131e31b8aSbellard 	retval = read(bprm->fd, (char *) elf_phdata,
93231e31b8aSbellard 				elf_ex.e_phentsize * elf_ex.e_phnum);
93331e31b8aSbellard     }
93431e31b8aSbellard 
93531e31b8aSbellard     if (retval < 0) {
93631e31b8aSbellard 	perror("load_elf_binary");
93731e31b8aSbellard 	exit(-1);
93831e31b8aSbellard 	free (elf_phdata);
93931e31b8aSbellard 	return -errno;
94031e31b8aSbellard     }
94131e31b8aSbellard 
942b17780d5Sbellard #ifdef BSWAP_NEEDED
943b17780d5Sbellard     elf_ppnt = elf_phdata;
944b17780d5Sbellard     for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
945b17780d5Sbellard         bswap_phdr(elf_ppnt);
946b17780d5Sbellard     }
947b17780d5Sbellard #endif
94831e31b8aSbellard     elf_ppnt = elf_phdata;
94931e31b8aSbellard 
95031e31b8aSbellard     elf_bss = 0;
95131e31b8aSbellard     elf_brk = 0;
95231e31b8aSbellard 
95331e31b8aSbellard 
95431e31b8aSbellard     elf_stack = ~0UL;
95531e31b8aSbellard     elf_interpreter = NULL;
95631e31b8aSbellard     start_code = ~0UL;
95731e31b8aSbellard     end_code = 0;
95831e31b8aSbellard     end_data = 0;
95931e31b8aSbellard 
96031e31b8aSbellard     for(i=0;i < elf_ex.e_phnum; i++) {
96131e31b8aSbellard 	if (elf_ppnt->p_type == PT_INTERP) {
96231e31b8aSbellard 	    if ( elf_interpreter != NULL )
96331e31b8aSbellard 	    {
96431e31b8aSbellard 		free (elf_phdata);
96531e31b8aSbellard 		free(elf_interpreter);
96631e31b8aSbellard 		close(bprm->fd);
96731e31b8aSbellard 		return -EINVAL;
96831e31b8aSbellard 	    }
96931e31b8aSbellard 
97031e31b8aSbellard 	    /* This is the program interpreter used for
97131e31b8aSbellard 	     * shared libraries - for now assume that this
97231e31b8aSbellard 	     * is an a.out format binary
97331e31b8aSbellard 	     */
97431e31b8aSbellard 
97532ce6337Sbellard 	    elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
97631e31b8aSbellard 
97731e31b8aSbellard 	    if (elf_interpreter == NULL) {
97831e31b8aSbellard 		free (elf_phdata);
97931e31b8aSbellard 		close(bprm->fd);
98031e31b8aSbellard 		return -ENOMEM;
98131e31b8aSbellard 	    }
98231e31b8aSbellard 
98331e31b8aSbellard 	    retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
98431e31b8aSbellard 	    if(retval >= 0) {
98532ce6337Sbellard 		retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
98631e31b8aSbellard 	    }
98731e31b8aSbellard 	    if(retval < 0) {
98831e31b8aSbellard 	 	perror("load_elf_binary2");
98931e31b8aSbellard 		exit(-1);
99031e31b8aSbellard 	    }
99131e31b8aSbellard 
99231e31b8aSbellard 	    /* If the program interpreter is one of these two,
99331e31b8aSbellard 	       then assume an iBCS2 image. Otherwise assume
99431e31b8aSbellard 	       a native linux image. */
99531e31b8aSbellard 
99631e31b8aSbellard 	    /* JRP - Need to add X86 lib dir stuff here... */
99731e31b8aSbellard 
99831e31b8aSbellard 	    if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
99931e31b8aSbellard 		strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
100031e31b8aSbellard 	      ibcs2_interpreter = 1;
100131e31b8aSbellard 	    }
100231e31b8aSbellard 
100331e31b8aSbellard #if 0
100431e31b8aSbellard 	    printf("Using ELF interpreter %s\n", elf_interpreter);
100531e31b8aSbellard #endif
100631e31b8aSbellard 	    if (retval >= 0) {
100732ce6337Sbellard 		retval = open(path(elf_interpreter), O_RDONLY);
100831e31b8aSbellard 		if(retval >= 0) {
100931e31b8aSbellard 		    interpreter_fd = retval;
101031e31b8aSbellard 		}
101131e31b8aSbellard 		else {
101231e31b8aSbellard 		    perror(elf_interpreter);
101331e31b8aSbellard 		    exit(-1);
101431e31b8aSbellard 		    /* retval = -errno; */
101531e31b8aSbellard 		}
101631e31b8aSbellard 	    }
101731e31b8aSbellard 
101831e31b8aSbellard 	    if (retval >= 0) {
101931e31b8aSbellard 		retval = lseek(interpreter_fd, 0, SEEK_SET);
102031e31b8aSbellard 		if(retval >= 0) {
102131e31b8aSbellard 		    retval = read(interpreter_fd,bprm->buf,128);
102231e31b8aSbellard 		}
102331e31b8aSbellard 	    }
102431e31b8aSbellard 	    if (retval >= 0) {
102531e31b8aSbellard 		interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
102631e31b8aSbellard 		interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */
102731e31b8aSbellard 	    }
102831e31b8aSbellard 	    if (retval < 0) {
102931e31b8aSbellard 		perror("load_elf_binary3");
103031e31b8aSbellard 		exit(-1);
103131e31b8aSbellard 		free (elf_phdata);
103231e31b8aSbellard 		free(elf_interpreter);
103331e31b8aSbellard 		close(bprm->fd);
103431e31b8aSbellard 		return retval;
103531e31b8aSbellard 	    }
103631e31b8aSbellard 	}
103731e31b8aSbellard 	elf_ppnt++;
103831e31b8aSbellard     }
103931e31b8aSbellard 
104031e31b8aSbellard     /* Some simple consistency checks for the interpreter */
104131e31b8aSbellard     if (elf_interpreter){
104231e31b8aSbellard 	interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
104331e31b8aSbellard 
104431e31b8aSbellard 	/* Now figure out which format our binary is */
104531e31b8aSbellard 	if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
104631e31b8aSbellard 	    	(N_MAGIC(interp_ex) != QMAGIC)) {
104731e31b8aSbellard 	  interpreter_type = INTERPRETER_ELF;
104831e31b8aSbellard 	}
104931e31b8aSbellard 
105031e31b8aSbellard 	if (interp_elf_ex.e_ident[0] != 0x7f ||
105131e31b8aSbellard 	    	strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) {
105231e31b8aSbellard 	    interpreter_type &= ~INTERPRETER_ELF;
105331e31b8aSbellard 	}
105431e31b8aSbellard 
105531e31b8aSbellard 	if (!interpreter_type) {
105631e31b8aSbellard 	    free(elf_interpreter);
105731e31b8aSbellard 	    free(elf_phdata);
105831e31b8aSbellard 	    close(bprm->fd);
105931e31b8aSbellard 	    return -ELIBBAD;
106031e31b8aSbellard 	}
106131e31b8aSbellard     }
106231e31b8aSbellard 
106331e31b8aSbellard     /* OK, we are done with that, now set up the arg stuff,
106431e31b8aSbellard        and then start this sucker up */
106531e31b8aSbellard 
106631e31b8aSbellard     if (!bprm->sh_bang) {
106731e31b8aSbellard 	char * passed_p;
106831e31b8aSbellard 
106931e31b8aSbellard 	if (interpreter_type == INTERPRETER_AOUT) {
1070*eba2af63Sbellard 	    snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
107131e31b8aSbellard 	    passed_p = passed_fileno;
107231e31b8aSbellard 
107331e31b8aSbellard 	    if (elf_interpreter) {
107431e31b8aSbellard 		bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p);
107531e31b8aSbellard 		bprm->argc++;
107631e31b8aSbellard 	    }
107731e31b8aSbellard 	}
107831e31b8aSbellard 	if (!bprm->p) {
107931e31b8aSbellard 	    if (elf_interpreter) {
108031e31b8aSbellard 	        free(elf_interpreter);
108131e31b8aSbellard 	    }
108231e31b8aSbellard 	    free (elf_phdata);
108331e31b8aSbellard 	    close(bprm->fd);
108431e31b8aSbellard 	    return -E2BIG;
108531e31b8aSbellard 	}
108631e31b8aSbellard     }
108731e31b8aSbellard 
108831e31b8aSbellard     /* OK, This is the point of no return */
108931e31b8aSbellard     info->end_data = 0;
109031e31b8aSbellard     info->end_code = 0;
109131e31b8aSbellard     info->start_mmap = (unsigned long)ELF_START_MMAP;
109231e31b8aSbellard     info->mmap = 0;
109331e31b8aSbellard     elf_entry = (unsigned long) elf_ex.e_entry;
109431e31b8aSbellard 
109531e31b8aSbellard     /* Do this so that we can load the interpreter, if need be.  We will
109631e31b8aSbellard        change some of these later */
109731e31b8aSbellard     info->rss = 0;
109831e31b8aSbellard     bprm->p = setup_arg_pages(bprm->p, bprm, info);
109931e31b8aSbellard     info->start_stack = bprm->p;
110031e31b8aSbellard 
110131e31b8aSbellard     /* Now we do a little grungy work by mmaping the ELF image into
110231e31b8aSbellard      * the correct location in memory.  At this point, we assume that
110331e31b8aSbellard      * the image should be loaded at fixed address, not at a variable
110431e31b8aSbellard      * address.
110531e31b8aSbellard      */
110631e31b8aSbellard 
110731e31b8aSbellard     for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
110831e31b8aSbellard         int elf_prot = 0;
110909bfb054Sbellard         int elf_flags = 0;
111009bfb054Sbellard         unsigned long error;
111109bfb054Sbellard 
111209bfb054Sbellard 	if (elf_ppnt->p_type != PT_LOAD)
111309bfb054Sbellard             continue;
111409bfb054Sbellard 
111531e31b8aSbellard         if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
111631e31b8aSbellard         if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
111731e31b8aSbellard         if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
111809bfb054Sbellard         elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
111909bfb054Sbellard         if (elf_ex.e_type == ET_EXEC || load_addr_set) {
112009bfb054Sbellard             elf_flags |= MAP_FIXED;
112109bfb054Sbellard         } else if (elf_ex.e_type == ET_DYN) {
112209bfb054Sbellard             /* Try and get dynamic programs out of the way of the default mmap
112309bfb054Sbellard                base, as well as whatever program they might try to exec.  This
112409bfb054Sbellard                is because the brk will follow the loader, and is not movable.  */
112509bfb054Sbellard             /* NOTE: for qemu, we do a big mmap to get enough space
112609bfb054Sbellard                without harcoding any address */
112754936004Sbellard             error = target_mmap(0, ET_DYN_MAP_SIZE,
112809bfb054Sbellard                                 PROT_NONE, MAP_PRIVATE | MAP_ANON,
112909bfb054Sbellard                                 -1, 0);
113009bfb054Sbellard             if (error == -1) {
113109bfb054Sbellard                 perror("mmap");
113209bfb054Sbellard                 exit(-1);
113309bfb054Sbellard             }
113454936004Sbellard             load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
113509bfb054Sbellard         }
113631e31b8aSbellard 
113754936004Sbellard         error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
113831e31b8aSbellard                             (elf_ppnt->p_filesz +
113954936004Sbellard                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
114031e31b8aSbellard                             elf_prot,
114131e31b8aSbellard                             (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
114231e31b8aSbellard                             bprm->fd,
114331e31b8aSbellard                             (elf_ppnt->p_offset -
114454936004Sbellard                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
114509bfb054Sbellard         if (error == -1) {
114631e31b8aSbellard             perror("mmap");
114731e31b8aSbellard             exit(-1);
114831e31b8aSbellard         }
114931e31b8aSbellard 
115031e31b8aSbellard #ifdef LOW_ELF_STACK
115154936004Sbellard         if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
115254936004Sbellard             elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr);
115331e31b8aSbellard #endif
115431e31b8aSbellard 
115531e31b8aSbellard         if (!load_addr_set) {
115631e31b8aSbellard             load_addr_set = 1;
115709bfb054Sbellard             load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
115809bfb054Sbellard             if (elf_ex.e_type == ET_DYN) {
115909bfb054Sbellard                 load_bias += error -
116054936004Sbellard                     TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
116109bfb054Sbellard                 load_addr += load_bias;
116209bfb054Sbellard             }
116331e31b8aSbellard         }
116431e31b8aSbellard         k = elf_ppnt->p_vaddr;
116509bfb054Sbellard         if (k < start_code)
116609bfb054Sbellard             start_code = k;
116731e31b8aSbellard         k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
116809bfb054Sbellard         if (k > elf_bss)
116909bfb054Sbellard             elf_bss = k;
117031e31b8aSbellard         if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
117131e31b8aSbellard             end_code = k;
117209bfb054Sbellard         if (end_data < k)
117309bfb054Sbellard             end_data = k;
117431e31b8aSbellard         k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
117531e31b8aSbellard         if (k > elf_brk) elf_brk = k;
117631e31b8aSbellard     }
117709bfb054Sbellard 
117809bfb054Sbellard     elf_entry += load_bias;
117909bfb054Sbellard     elf_bss += load_bias;
118009bfb054Sbellard     elf_brk += load_bias;
118109bfb054Sbellard     start_code += load_bias;
118209bfb054Sbellard     end_code += load_bias;
118309bfb054Sbellard     //    start_data += load_bias;
118409bfb054Sbellard     end_data += load_bias;
118531e31b8aSbellard 
118631e31b8aSbellard     if (elf_interpreter) {
118731e31b8aSbellard 	if (interpreter_type & 1) {
118831e31b8aSbellard 	    elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
118931e31b8aSbellard 	}
119031e31b8aSbellard 	else if (interpreter_type & 2) {
119131e31b8aSbellard 	    elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
119231e31b8aSbellard 					    &interp_load_addr);
119331e31b8aSbellard 	}
119431e31b8aSbellard 
119531e31b8aSbellard 	close(interpreter_fd);
119631e31b8aSbellard 	free(elf_interpreter);
119731e31b8aSbellard 
119831e31b8aSbellard 	if (elf_entry == ~0UL) {
119931e31b8aSbellard 	    printf("Unable to load interpreter\n");
120031e31b8aSbellard 	    free(elf_phdata);
120131e31b8aSbellard 	    exit(-1);
120231e31b8aSbellard 	    return 0;
120331e31b8aSbellard 	}
120431e31b8aSbellard     }
120531e31b8aSbellard 
120631e31b8aSbellard     free(elf_phdata);
120731e31b8aSbellard 
1208689f936fSbellard     if (loglevel)
1209689f936fSbellard 	load_symbols(&elf_ex, bprm->fd);
1210689f936fSbellard 
121131e31b8aSbellard     if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
121231e31b8aSbellard     info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
121331e31b8aSbellard 
121431e31b8aSbellard #ifdef LOW_ELF_STACK
121531e31b8aSbellard     info->start_stack = bprm->p = elf_stack - 4;
121631e31b8aSbellard #endif
121731e31b8aSbellard     bprm->p = (unsigned long)
121831e31b8aSbellard       create_elf_tables((char *)bprm->p,
121931e31b8aSbellard 		    bprm->argc,
122031e31b8aSbellard 		    bprm->envc,
1221a1516e92Sbellard                     &elf_ex,
122209bfb054Sbellard                     load_addr, load_bias,
122331e31b8aSbellard 		    interp_load_addr,
122431e31b8aSbellard 		    (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
122531e31b8aSbellard 		    info);
122631e31b8aSbellard     if (interpreter_type == INTERPRETER_AOUT)
122731e31b8aSbellard       info->arg_start += strlen(passed_fileno) + 1;
122831e31b8aSbellard     info->start_brk = info->brk = elf_brk;
122931e31b8aSbellard     info->end_code = end_code;
123031e31b8aSbellard     info->start_code = start_code;
123131e31b8aSbellard     info->end_data = end_data;
123231e31b8aSbellard     info->start_stack = bprm->p;
123331e31b8aSbellard 
123431e31b8aSbellard     /* Calling set_brk effectively mmaps the pages that we need for the bss and break
123531e31b8aSbellard        sections */
123631e31b8aSbellard     set_brk(elf_bss, elf_brk);
123731e31b8aSbellard 
123831e31b8aSbellard     padzero(elf_bss);
123931e31b8aSbellard 
124031e31b8aSbellard #if 0
124131e31b8aSbellard     printf("(start_brk) %x\n" , info->start_brk);
124231e31b8aSbellard     printf("(end_code) %x\n" , info->end_code);
124331e31b8aSbellard     printf("(start_code) %x\n" , info->start_code);
124431e31b8aSbellard     printf("(end_data) %x\n" , info->end_data);
124531e31b8aSbellard     printf("(start_stack) %x\n" , info->start_stack);
124631e31b8aSbellard     printf("(brk) %x\n" , info->brk);
124731e31b8aSbellard #endif
124831e31b8aSbellard 
124931e31b8aSbellard     if ( info->personality == PER_SVR4 )
125031e31b8aSbellard     {
125131e31b8aSbellard 	    /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
125231e31b8aSbellard 	       and some applications "depend" upon this behavior.
125331e31b8aSbellard 	       Since we do not have the power to recompile these, we
125431e31b8aSbellard 	       emulate the SVr4 behavior.  Sigh.  */
125554936004Sbellard 	    mapped_addr = target_mmap(0, host_page_size, PROT_READ | PROT_EXEC,
125631e31b8aSbellard                                       MAP_FIXED | MAP_PRIVATE, -1, 0);
125731e31b8aSbellard     }
125831e31b8aSbellard 
125931e31b8aSbellard #ifdef ELF_PLAT_INIT
126031e31b8aSbellard     /*
126131e31b8aSbellard      * The ABI may specify that certain registers be set up in special
126231e31b8aSbellard      * ways (on i386 %edx is the address of a DT_FINI function, for
126331e31b8aSbellard      * example.  This macro performs whatever initialization to
126431e31b8aSbellard      * the regs structure is required.
126531e31b8aSbellard      */
126631e31b8aSbellard     ELF_PLAT_INIT(regs);
126731e31b8aSbellard #endif
126831e31b8aSbellard 
126931e31b8aSbellard 
127031e31b8aSbellard     info->entry = elf_entry;
127131e31b8aSbellard 
127231e31b8aSbellard     return 0;
127331e31b8aSbellard }
127431e31b8aSbellard 
127531e31b8aSbellard 
127631e31b8aSbellard 
127732ce6337Sbellard int elf_exec(const char * filename, char ** argv, char ** envp,
1278b17780d5Sbellard              struct target_pt_regs * regs, struct image_info *infop)
127931e31b8aSbellard {
128031e31b8aSbellard         struct linux_binprm bprm;
128131e31b8aSbellard         int retval;
128231e31b8aSbellard         int i;
128331e31b8aSbellard 
128454936004Sbellard         bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
128531e31b8aSbellard         for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
128631e31b8aSbellard                 bprm.page[i] = 0;
128731e31b8aSbellard         retval = open(filename, O_RDONLY);
1288c2735790Sbellard         if (retval < 0)
1289c2735790Sbellard             return retval;
129031e31b8aSbellard         bprm.fd = retval;
129131e31b8aSbellard         bprm.filename = (char *)filename;
129231e31b8aSbellard         bprm.sh_bang = 0;
129331e31b8aSbellard         bprm.loader = 0;
129431e31b8aSbellard         bprm.exec = 0;
129531e31b8aSbellard         bprm.dont_iput = 0;
129631e31b8aSbellard 	bprm.argc = count(argv);
129731e31b8aSbellard 	bprm.envc = count(envp);
129831e31b8aSbellard 
129931e31b8aSbellard         retval = prepare_binprm(&bprm);
130031e31b8aSbellard 
130131e31b8aSbellard         if(retval>=0) {
130231e31b8aSbellard 	    bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p);
130331e31b8aSbellard 	    bprm.exec = bprm.p;
130431e31b8aSbellard 	    bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p);
130531e31b8aSbellard 	    bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p);
130631e31b8aSbellard 	    if (!bprm.p) {
130731e31b8aSbellard 		retval = -E2BIG;
130831e31b8aSbellard 	    }
130931e31b8aSbellard         }
131031e31b8aSbellard 
131131e31b8aSbellard         if(retval>=0) {
131231e31b8aSbellard 	    retval = load_elf_binary(&bprm,regs,infop);
131331e31b8aSbellard 	}
131431e31b8aSbellard         if(retval>=0) {
131531e31b8aSbellard 	    /* success.  Initialize important registers */
1316b346ff46Sbellard             init_thread(regs, infop);
131731e31b8aSbellard 	    return retval;
131831e31b8aSbellard 	}
131931e31b8aSbellard 
132031e31b8aSbellard         /* Something went wrong, return the inode and free the argument pages*/
132131e31b8aSbellard         for (i=0 ; i<MAX_ARG_PAGES ; i++) {
132231e31b8aSbellard 	    free_page((void *)bprm.page[i]);
132331e31b8aSbellard 	}
132431e31b8aSbellard         return(retval);
132531e31b8aSbellard }
132631e31b8aSbellard 
132731e31b8aSbellard 
132831e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd)
132931e31b8aSbellard {
133031e31b8aSbellard     printf("a.out interpreter not yet supported\n");
133131e31b8aSbellard     return(0);
133231e31b8aSbellard }
133331e31b8aSbellard 
1334