xref: /qemu/linux-user/elfload.c (revision 768a4a36a444ef5aef1f103adf42553eadfe4614)
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 <errno.h>
731e31b8aSbellard #include <unistd.h>
831e31b8aSbellard #include <sys/mman.h>
931e31b8aSbellard #include <stdlib.h>
1031e31b8aSbellard #include <string.h>
1131e31b8aSbellard 
123ef693a0Sbellard #include "qemu.h"
13689f936fSbellard #include "disas.h"
1431e31b8aSbellard 
1583fb7adfSbellard /* this flag is uneffective under linux too, should be deleted */
1683fb7adfSbellard #ifndef MAP_DENYWRITE
1783fb7adfSbellard #define MAP_DENYWRITE 0
1883fb7adfSbellard #endif
1983fb7adfSbellard 
2083fb7adfSbellard /* should probably go in elf.h */
2183fb7adfSbellard #ifndef ELIBBAD
2283fb7adfSbellard #define ELIBBAD 80
2383fb7adfSbellard #endif
2483fb7adfSbellard 
2530ac07d4Sbellard #ifdef TARGET_I386
2630ac07d4Sbellard 
2715338fd7Sbellard #define ELF_PLATFORM get_elf_platform()
2815338fd7Sbellard 
2915338fd7Sbellard static const char *get_elf_platform(void)
3015338fd7Sbellard {
3115338fd7Sbellard     static char elf_platform[] = "i386";
3215338fd7Sbellard     int family = (global_env->cpuid_version >> 8) & 0xff;
3315338fd7Sbellard     if (family > 6)
3415338fd7Sbellard         family = 6;
3515338fd7Sbellard     if (family >= 3)
3615338fd7Sbellard         elf_platform[1] = '0' + family;
3715338fd7Sbellard     return elf_platform;
3815338fd7Sbellard }
3915338fd7Sbellard 
4015338fd7Sbellard #define ELF_HWCAP get_elf_hwcap()
4115338fd7Sbellard 
4215338fd7Sbellard static uint32_t get_elf_hwcap(void)
4315338fd7Sbellard {
4415338fd7Sbellard   return global_env->cpuid_features;
4515338fd7Sbellard }
4615338fd7Sbellard 
4730ac07d4Sbellard #define ELF_START_MMAP 0x80000000
4830ac07d4Sbellard 
4930ac07d4Sbellard /*
5030ac07d4Sbellard  * This is used to ensure we don't load something for the wrong architecture.
5130ac07d4Sbellard  */
5230ac07d4Sbellard #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
5330ac07d4Sbellard 
5430ac07d4Sbellard /*
5530ac07d4Sbellard  * These are used to set parameters in the core dumps.
5630ac07d4Sbellard  */
5730ac07d4Sbellard #define ELF_CLASS	ELFCLASS32
5830ac07d4Sbellard #define ELF_DATA	ELFDATA2LSB
5930ac07d4Sbellard #define ELF_ARCH	EM_386
6030ac07d4Sbellard 
61e5fe0c52Spbrook static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
62e5fe0c52Spbrook {
63e5fe0c52Spbrook     regs->esp = infop->start_stack;
64e5fe0c52Spbrook     regs->eip = infop->entry;
65e5fe0c52Spbrook 
6630ac07d4Sbellard     /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
6730ac07d4Sbellard        starts %edx contains a pointer to a function which might be
6830ac07d4Sbellard        registered using `atexit'.  This provides a mean for the
6930ac07d4Sbellard        dynamic linker to call DT_FINI functions for shared libraries
7030ac07d4Sbellard        that have been loaded before the code runs.
7130ac07d4Sbellard 
7230ac07d4Sbellard        A value of 0 tells we have no such handler.  */
73e5fe0c52Spbrook     regs->edx = 0;
74b346ff46Sbellard }
75b346ff46Sbellard 
76b346ff46Sbellard #define USE_ELF_CORE_DUMP
77b346ff46Sbellard #define ELF_EXEC_PAGESIZE	4096
78b346ff46Sbellard 
79b346ff46Sbellard #endif
80b346ff46Sbellard 
81b346ff46Sbellard #ifdef TARGET_ARM
82b346ff46Sbellard 
83b346ff46Sbellard #define ELF_START_MMAP 0x80000000
84b346ff46Sbellard 
85b346ff46Sbellard #define elf_check_arch(x) ( (x) == EM_ARM )
86b346ff46Sbellard 
87b346ff46Sbellard #define ELF_CLASS	ELFCLASS32
88b346ff46Sbellard #ifdef TARGET_WORDS_BIGENDIAN
89b346ff46Sbellard #define ELF_DATA	ELFDATA2MSB
90b346ff46Sbellard #else
91b346ff46Sbellard #define ELF_DATA	ELFDATA2LSB
92b346ff46Sbellard #endif
93b346ff46Sbellard #define ELF_ARCH	EM_ARM
94b346ff46Sbellard 
95b346ff46Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
96b346ff46Sbellard {
9753a5960aSpbrook     target_long stack = infop->start_stack;
98b346ff46Sbellard     memset(regs, 0, sizeof(*regs));
99b346ff46Sbellard     regs->ARM_cpsr = 0x10;
1000240ded8Spbrook     if (infop->entry & 1)
1010240ded8Spbrook       regs->ARM_cpsr |= CPSR_T;
1020240ded8Spbrook     regs->ARM_pc = infop->entry & 0xfffffffe;
103b346ff46Sbellard     regs->ARM_sp = infop->start_stack;
10453a5960aSpbrook     regs->ARM_r2 = tgetl(stack + 8); /* envp */
10553a5960aSpbrook     regs->ARM_r1 = tgetl(stack + 4); /* envp */
106a1516e92Sbellard     /* XXX: it seems that r0 is zeroed after ! */
107e5fe0c52Spbrook     regs->ARM_r0 = 0;
108e5fe0c52Spbrook     /* For uClinux PIC binaries.  */
109e5fe0c52Spbrook     regs->ARM_r10 = infop->start_data;
110b346ff46Sbellard }
111b346ff46Sbellard 
11230ac07d4Sbellard #define USE_ELF_CORE_DUMP
11330ac07d4Sbellard #define ELF_EXEC_PAGESIZE	4096
11430ac07d4Sbellard 
115afce2927Sbellard enum
116afce2927Sbellard {
117afce2927Sbellard   ARM_HWCAP_ARM_SWP       = 1 << 0,
118afce2927Sbellard   ARM_HWCAP_ARM_HALF      = 1 << 1,
119afce2927Sbellard   ARM_HWCAP_ARM_THUMB     = 1 << 2,
120afce2927Sbellard   ARM_HWCAP_ARM_26BIT     = 1 << 3,
121afce2927Sbellard   ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
122afce2927Sbellard   ARM_HWCAP_ARM_FPA       = 1 << 5,
123afce2927Sbellard   ARM_HWCAP_ARM_VFP       = 1 << 6,
124afce2927Sbellard   ARM_HWCAP_ARM_EDSP      = 1 << 7,
125afce2927Sbellard };
126afce2927Sbellard 
12715338fd7Sbellard #define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF              \
128afce2927Sbellard                     | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT     \
129afce2927Sbellard                     | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP)
130afce2927Sbellard 
13130ac07d4Sbellard #endif
13230ac07d4Sbellard 
133853d6f7aSbellard #ifdef TARGET_SPARC
134a315a145Sbellard #ifdef TARGET_SPARC64
135853d6f7aSbellard 
136853d6f7aSbellard #define ELF_START_MMAP 0x80000000
137853d6f7aSbellard 
1385ef54116Sbellard #define elf_check_arch(x) ( (x) == EM_SPARCV9 )
139853d6f7aSbellard 
140a315a145Sbellard #define ELF_CLASS   ELFCLASS64
141a315a145Sbellard #define ELF_DATA    ELFDATA2MSB
1425ef54116Sbellard #define ELF_ARCH    EM_SPARCV9
1435ef54116Sbellard 
1445ef54116Sbellard #define STACK_BIAS		2047
145a315a145Sbellard 
146a315a145Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
147a315a145Sbellard {
148a315a145Sbellard     regs->tstate = 0;
149a315a145Sbellard     regs->pc = infop->entry;
150a315a145Sbellard     regs->npc = regs->pc + 4;
151a315a145Sbellard     regs->y = 0;
1525ef54116Sbellard     regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
153a315a145Sbellard }
154a315a145Sbellard 
155a315a145Sbellard #else
156a315a145Sbellard #define ELF_START_MMAP 0x80000000
157a315a145Sbellard 
158a315a145Sbellard #define elf_check_arch(x) ( (x) == EM_SPARC )
159a315a145Sbellard 
160853d6f7aSbellard #define ELF_CLASS   ELFCLASS32
161853d6f7aSbellard #define ELF_DATA    ELFDATA2MSB
162853d6f7aSbellard #define ELF_ARCH    EM_SPARC
163853d6f7aSbellard 
164853d6f7aSbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
165853d6f7aSbellard {
166f5155289Sbellard     regs->psr = 0;
167f5155289Sbellard     regs->pc = infop->entry;
168f5155289Sbellard     regs->npc = regs->pc + 4;
169f5155289Sbellard     regs->y = 0;
170f5155289Sbellard     regs->u_regs[14] = infop->start_stack - 16 * 4;
171853d6f7aSbellard }
172853d6f7aSbellard 
173853d6f7aSbellard #endif
174a315a145Sbellard #endif
175853d6f7aSbellard 
17667867308Sbellard #ifdef TARGET_PPC
17767867308Sbellard 
17867867308Sbellard #define ELF_START_MMAP 0x80000000
17967867308Sbellard 
18067867308Sbellard #define elf_check_arch(x) ( (x) == EM_PPC )
18167867308Sbellard 
18267867308Sbellard #define ELF_CLASS	ELFCLASS32
18367867308Sbellard #ifdef TARGET_WORDS_BIGENDIAN
18467867308Sbellard #define ELF_DATA	ELFDATA2MSB
18567867308Sbellard #else
18667867308Sbellard #define ELF_DATA	ELFDATA2LSB
18767867308Sbellard #endif
18867867308Sbellard #define ELF_ARCH	EM_PPC
18967867308Sbellard 
190f5155289Sbellard /*
191f5155289Sbellard  * We need to put in some extra aux table entries to tell glibc what
192f5155289Sbellard  * the cache block size is, so it can use the dcbz instruction safely.
193f5155289Sbellard  */
194f5155289Sbellard #define AT_DCACHEBSIZE          19
195f5155289Sbellard #define AT_ICACHEBSIZE          20
196f5155289Sbellard #define AT_UCACHEBSIZE          21
197f5155289Sbellard /* A special ignored type value for PPC, for glibc compatibility.  */
198f5155289Sbellard #define AT_IGNOREPPC            22
199f5155289Sbellard /*
200f5155289Sbellard  * The requirements here are:
201f5155289Sbellard  * - keep the final alignment of sp (sp & 0xf)
202f5155289Sbellard  * - make sure the 32-bit value at the first 16 byte aligned position of
203f5155289Sbellard  *   AUXV is greater than 16 for glibc compatibility.
204f5155289Sbellard  *   AT_IGNOREPPC is used for that.
205f5155289Sbellard  * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
206f5155289Sbellard  *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
207f5155289Sbellard  */
2080bccf03dSbellard #define DLINFO_ARCH_ITEMS       5
209f5155289Sbellard #define ARCH_DLINFO                                                     \
210f5155289Sbellard do {                                                                    \
2110bccf03dSbellard         NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20);                              \
2120bccf03dSbellard         NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20);                              \
2130bccf03dSbellard         NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                                 \
214f5155289Sbellard         /*                                                              \
215f5155289Sbellard          * Now handle glibc compatibility.                              \
216f5155289Sbellard          */                                                             \
2170bccf03dSbellard 	NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);			\
2180bccf03dSbellard 	NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);			\
219f5155289Sbellard  } while (0)
220f5155289Sbellard 
22167867308Sbellard static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
22267867308Sbellard {
223e5fe0c52Spbrook     target_ulong pos = infop->start_stack;
224e5fe0c52Spbrook     target_ulong tmp;
225e5fe0c52Spbrook 
22667867308Sbellard     _regs->msr = 1 << MSR_PR; /* Set user mode */
22767867308Sbellard     _regs->gpr[1] = infop->start_stack;
22867867308Sbellard     _regs->nip = infop->entry;
229e5fe0c52Spbrook     /* Note that isn't exactly what regular kernel does
230e5fe0c52Spbrook      * but this is what the ABI wants and is needed to allow
231e5fe0c52Spbrook      * execution of PPC BSD programs.
232e5fe0c52Spbrook      */
233e5fe0c52Spbrook     _regs->gpr[3] = tgetl(pos);
234e5fe0c52Spbrook     pos += sizeof(target_ulong);
235e5fe0c52Spbrook     _regs->gpr[4] = pos;
236e5fe0c52Spbrook     for (tmp = 1; tmp != 0; pos += sizeof(target_ulong))
237e5fe0c52Spbrook         tmp = ldl(pos);
238e5fe0c52Spbrook     _regs->gpr[5] = pos;
23967867308Sbellard }
24067867308Sbellard 
24167867308Sbellard #define USE_ELF_CORE_DUMP
24267867308Sbellard #define ELF_EXEC_PAGESIZE	4096
24367867308Sbellard 
24467867308Sbellard #endif
24567867308Sbellard 
246048f6b4dSbellard #ifdef TARGET_MIPS
247048f6b4dSbellard 
248048f6b4dSbellard #define ELF_START_MMAP 0x80000000
249048f6b4dSbellard 
250048f6b4dSbellard #define elf_check_arch(x) ( (x) == EM_MIPS )
251048f6b4dSbellard 
252048f6b4dSbellard #define ELF_CLASS   ELFCLASS32
253048f6b4dSbellard #ifdef TARGET_WORDS_BIGENDIAN
254048f6b4dSbellard #define ELF_DATA	ELFDATA2MSB
255048f6b4dSbellard #else
256048f6b4dSbellard #define ELF_DATA	ELFDATA2LSB
257048f6b4dSbellard #endif
258048f6b4dSbellard #define ELF_ARCH    EM_MIPS
259048f6b4dSbellard 
260048f6b4dSbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
261048f6b4dSbellard {
262048f6b4dSbellard     regs->cp0_status = CP0St_UM;
263048f6b4dSbellard     regs->cp0_epc = infop->entry;
264048f6b4dSbellard     regs->regs[29] = infop->start_stack;
265048f6b4dSbellard }
266048f6b4dSbellard 
267048f6b4dSbellard #endif /* TARGET_MIPS */
268048f6b4dSbellard 
269fdf9b3e8Sbellard #ifdef TARGET_SH4
270fdf9b3e8Sbellard 
271fdf9b3e8Sbellard #define ELF_START_MMAP 0x80000000
272fdf9b3e8Sbellard 
273fdf9b3e8Sbellard #define elf_check_arch(x) ( (x) == EM_SH )
274fdf9b3e8Sbellard 
275fdf9b3e8Sbellard #define ELF_CLASS ELFCLASS32
276fdf9b3e8Sbellard #define ELF_DATA  ELFDATA2LSB
277fdf9b3e8Sbellard #define ELF_ARCH  EM_SH
278fdf9b3e8Sbellard 
279fdf9b3e8Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
280fdf9b3e8Sbellard {
281fdf9b3e8Sbellard   /* Check other registers XXXXX */
282fdf9b3e8Sbellard   regs->pc = infop->entry;
283fdf9b3e8Sbellard   regs->regs[15] = infop->start_stack - 16 * 4;
284fdf9b3e8Sbellard }
285fdf9b3e8Sbellard 
286fdf9b3e8Sbellard #define USE_ELF_CORE_DUMP
287fdf9b3e8Sbellard #define ELF_EXEC_PAGESIZE        4096
288fdf9b3e8Sbellard 
289fdf9b3e8Sbellard #endif
290fdf9b3e8Sbellard 
291e6e5906bSpbrook #ifdef TARGET_M68K
292e6e5906bSpbrook 
293e6e5906bSpbrook #define ELF_START_MMAP 0x80000000
294e6e5906bSpbrook 
295e6e5906bSpbrook #define elf_check_arch(x) ( (x) == EM_68K )
296e6e5906bSpbrook 
297e6e5906bSpbrook #define ELF_CLASS	ELFCLASS32
298e6e5906bSpbrook #define ELF_DATA	ELFDATA2MSB
299e6e5906bSpbrook #define ELF_ARCH	EM_68K
300e6e5906bSpbrook 
301e6e5906bSpbrook /* ??? Does this need to do anything?
302e6e5906bSpbrook #define ELF_PLAT_INIT(_r) */
303e6e5906bSpbrook 
304e6e5906bSpbrook static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
305e6e5906bSpbrook {
306e6e5906bSpbrook     regs->usp = infop->start_stack;
307e6e5906bSpbrook     regs->sr = 0;
308e6e5906bSpbrook     regs->pc = infop->entry;
309e6e5906bSpbrook }
310e6e5906bSpbrook 
311e6e5906bSpbrook #define USE_ELF_CORE_DUMP
312e6e5906bSpbrook #define ELF_EXEC_PAGESIZE	8192
313e6e5906bSpbrook 
314e6e5906bSpbrook #endif
315e6e5906bSpbrook 
31615338fd7Sbellard #ifndef ELF_PLATFORM
31715338fd7Sbellard #define ELF_PLATFORM (NULL)
31815338fd7Sbellard #endif
31915338fd7Sbellard 
32015338fd7Sbellard #ifndef ELF_HWCAP
32115338fd7Sbellard #define ELF_HWCAP 0
32215338fd7Sbellard #endif
32315338fd7Sbellard 
32431e31b8aSbellard #include "elf.h"
32509bfb054Sbellard 
32609bfb054Sbellard struct exec
32709bfb054Sbellard {
32809bfb054Sbellard   unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
32909bfb054Sbellard   unsigned int a_text;   /* length of text, in bytes */
33009bfb054Sbellard   unsigned int a_data;   /* length of data, in bytes */
33109bfb054Sbellard   unsigned int a_bss;    /* length of uninitialized data area, in bytes */
33209bfb054Sbellard   unsigned int a_syms;   /* length of symbol table data in file, in bytes */
33309bfb054Sbellard   unsigned int a_entry;  /* start address */
33409bfb054Sbellard   unsigned int a_trsize; /* length of relocation info for text, in bytes */
33509bfb054Sbellard   unsigned int a_drsize; /* length of relocation info for data, in bytes */
33609bfb054Sbellard };
33709bfb054Sbellard 
33809bfb054Sbellard 
33909bfb054Sbellard #define N_MAGIC(exec) ((exec).a_info & 0xffff)
34009bfb054Sbellard #define OMAGIC 0407
34109bfb054Sbellard #define NMAGIC 0410
34209bfb054Sbellard #define ZMAGIC 0413
34309bfb054Sbellard #define QMAGIC 0314
34409bfb054Sbellard 
34509bfb054Sbellard /* max code+data+bss space allocated to elf interpreter */
34609bfb054Sbellard #define INTERP_MAP_SIZE (32 * 1024 * 1024)
34709bfb054Sbellard 
34809bfb054Sbellard /* max code+data+bss+brk space allocated to ET_DYN executables */
34909bfb054Sbellard #define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
35009bfb054Sbellard 
35109bfb054Sbellard /* from personality.h */
35209bfb054Sbellard 
35309bfb054Sbellard /* Flags for bug emulation. These occupy the top three bytes. */
35409bfb054Sbellard #define STICKY_TIMEOUTS		0x4000000
35509bfb054Sbellard #define WHOLE_SECONDS		0x2000000
35609bfb054Sbellard 
35709bfb054Sbellard /* Personality types. These go in the low byte. Avoid using the top bit,
35809bfb054Sbellard  * it will conflict with error returns.
35909bfb054Sbellard  */
36009bfb054Sbellard #define PER_MASK		(0x00ff)
36109bfb054Sbellard #define PER_LINUX		(0x0000)
36209bfb054Sbellard #define PER_SVR4		(0x0001 | STICKY_TIMEOUTS)
36309bfb054Sbellard #define PER_SVR3		(0x0002 | STICKY_TIMEOUTS)
36409bfb054Sbellard #define PER_SCOSVR3		(0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS)
36509bfb054Sbellard #define PER_WYSEV386		(0x0004 | STICKY_TIMEOUTS)
36609bfb054Sbellard #define PER_ISCR4		(0x0005 | STICKY_TIMEOUTS)
36709bfb054Sbellard #define PER_BSD			(0x0006)
36809bfb054Sbellard #define PER_XENIX		(0x0007 | STICKY_TIMEOUTS)
36931e31b8aSbellard 
37031e31b8aSbellard /* Necessary parameters */
37154936004Sbellard #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
37254936004Sbellard #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
37354936004Sbellard #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
37431e31b8aSbellard 
37531e31b8aSbellard #define INTERPRETER_NONE 0
37631e31b8aSbellard #define INTERPRETER_AOUT 1
37731e31b8aSbellard #define INTERPRETER_ELF 2
37831e31b8aSbellard 
37915338fd7Sbellard #define DLINFO_ITEMS 12
38031e31b8aSbellard 
38109bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
38209bfb054Sbellard {
38309bfb054Sbellard 	memcpy(to, from, n);
38409bfb054Sbellard }
38509bfb054Sbellard 
38631e31b8aSbellard extern unsigned long x86_stack_size;
38731e31b8aSbellard 
38831e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd);
38931e31b8aSbellard 
39031e31b8aSbellard #ifdef BSWAP_NEEDED
39192a31b1fSbellard static void bswap_ehdr(struct elfhdr *ehdr)
39231e31b8aSbellard {
39331e31b8aSbellard     bswap16s(&ehdr->e_type);			/* Object file type */
39431e31b8aSbellard     bswap16s(&ehdr->e_machine);		/* Architecture */
39531e31b8aSbellard     bswap32s(&ehdr->e_version);		/* Object file version */
39692a31b1fSbellard     bswaptls(&ehdr->e_entry);		/* Entry point virtual address */
39792a31b1fSbellard     bswaptls(&ehdr->e_phoff);		/* Program header table file offset */
39892a31b1fSbellard     bswaptls(&ehdr->e_shoff);		/* Section header table file offset */
39931e31b8aSbellard     bswap32s(&ehdr->e_flags);		/* Processor-specific flags */
40031e31b8aSbellard     bswap16s(&ehdr->e_ehsize);		/* ELF header size in bytes */
40131e31b8aSbellard     bswap16s(&ehdr->e_phentsize);		/* Program header table entry size */
40231e31b8aSbellard     bswap16s(&ehdr->e_phnum);		/* Program header table entry count */
40331e31b8aSbellard     bswap16s(&ehdr->e_shentsize);		/* Section header table entry size */
40431e31b8aSbellard     bswap16s(&ehdr->e_shnum);		/* Section header table entry count */
40531e31b8aSbellard     bswap16s(&ehdr->e_shstrndx);		/* Section header string table index */
40631e31b8aSbellard }
40731e31b8aSbellard 
40892a31b1fSbellard static void bswap_phdr(struct elf_phdr *phdr)
40931e31b8aSbellard {
41031e31b8aSbellard     bswap32s(&phdr->p_type);			/* Segment type */
41192a31b1fSbellard     bswaptls(&phdr->p_offset);		/* Segment file offset */
41292a31b1fSbellard     bswaptls(&phdr->p_vaddr);		/* Segment virtual address */
41392a31b1fSbellard     bswaptls(&phdr->p_paddr);		/* Segment physical address */
41492a31b1fSbellard     bswaptls(&phdr->p_filesz);		/* Segment size in file */
41592a31b1fSbellard     bswaptls(&phdr->p_memsz);		/* Segment size in memory */
41631e31b8aSbellard     bswap32s(&phdr->p_flags);		/* Segment flags */
41792a31b1fSbellard     bswaptls(&phdr->p_align);		/* Segment alignment */
41831e31b8aSbellard }
419689f936fSbellard 
42092a31b1fSbellard static void bswap_shdr(struct elf_shdr *shdr)
421689f936fSbellard {
422689f936fSbellard     bswap32s(&shdr->sh_name);
423689f936fSbellard     bswap32s(&shdr->sh_type);
42492a31b1fSbellard     bswaptls(&shdr->sh_flags);
42592a31b1fSbellard     bswaptls(&shdr->sh_addr);
42692a31b1fSbellard     bswaptls(&shdr->sh_offset);
42792a31b1fSbellard     bswaptls(&shdr->sh_size);
428689f936fSbellard     bswap32s(&shdr->sh_link);
429689f936fSbellard     bswap32s(&shdr->sh_info);
43092a31b1fSbellard     bswaptls(&shdr->sh_addralign);
43192a31b1fSbellard     bswaptls(&shdr->sh_entsize);
432689f936fSbellard }
433689f936fSbellard 
434689f936fSbellard static void bswap_sym(Elf32_Sym *sym)
435689f936fSbellard {
436689f936fSbellard     bswap32s(&sym->st_name);
437689f936fSbellard     bswap32s(&sym->st_value);
438689f936fSbellard     bswap32s(&sym->st_size);
439689f936fSbellard     bswap16s(&sym->st_shndx);
440689f936fSbellard }
44131e31b8aSbellard #endif
44231e31b8aSbellard 
44331e31b8aSbellard /*
444e5fe0c52Spbrook  * 'copy_elf_strings()' copies argument/envelope strings from user
44531e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
44631e31b8aSbellard  * to be put directly into the top of new user memory.
44731e31b8aSbellard  *
44831e31b8aSbellard  */
449e5fe0c52Spbrook static unsigned long copy_elf_strings(int argc,char ** argv, void **page,
45031e31b8aSbellard                                       unsigned long p)
45131e31b8aSbellard {
45231e31b8aSbellard     char *tmp, *tmp1, *pag = NULL;
45331e31b8aSbellard     int len, offset = 0;
45431e31b8aSbellard 
45531e31b8aSbellard     if (!p) {
45631e31b8aSbellard 	return 0;       /* bullet-proofing */
45731e31b8aSbellard     }
45831e31b8aSbellard     while (argc-- > 0) {
459edf779ffSbellard         tmp = argv[argc];
460edf779ffSbellard         if (!tmp) {
46131e31b8aSbellard 	    fprintf(stderr, "VFS: argc is wrong");
46231e31b8aSbellard 	    exit(-1);
46331e31b8aSbellard 	}
464edf779ffSbellard         tmp1 = tmp;
465edf779ffSbellard 	while (*tmp++);
46631e31b8aSbellard 	len = tmp - tmp1;
46731e31b8aSbellard 	if (p < len) {  /* this shouldn't happen - 128kB */
46831e31b8aSbellard 		return 0;
46931e31b8aSbellard 	}
47031e31b8aSbellard 	while (len) {
47131e31b8aSbellard 	    --p; --tmp; --len;
47231e31b8aSbellard 	    if (--offset < 0) {
47354936004Sbellard 		offset = p % TARGET_PAGE_SIZE;
47444a91caeSbellard                 pag = (char *)page[p/TARGET_PAGE_SIZE];
47544a91caeSbellard                 if (!pag) {
47653a5960aSpbrook                     pag = (char *)malloc(TARGET_PAGE_SIZE);
47753a5960aSpbrook                     page[p/TARGET_PAGE_SIZE] = pag;
47844a91caeSbellard                     if (!pag)
47931e31b8aSbellard                         return 0;
48031e31b8aSbellard 		}
48131e31b8aSbellard 	    }
48231e31b8aSbellard 	    if (len == 0 || offset == 0) {
483edf779ffSbellard 	        *(pag + offset) = *tmp;
48431e31b8aSbellard 	    }
48531e31b8aSbellard 	    else {
48631e31b8aSbellard 	      int bytes_to_copy = (len > offset) ? offset : len;
48731e31b8aSbellard 	      tmp -= bytes_to_copy;
48831e31b8aSbellard 	      p -= bytes_to_copy;
48931e31b8aSbellard 	      offset -= bytes_to_copy;
49031e31b8aSbellard 	      len -= bytes_to_copy;
49131e31b8aSbellard 	      memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
49231e31b8aSbellard 	    }
49331e31b8aSbellard 	}
49431e31b8aSbellard     }
49531e31b8aSbellard     return p;
49631e31b8aSbellard }
49731e31b8aSbellard 
49853a5960aSpbrook unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm,
49931e31b8aSbellard 					      struct image_info * info)
50031e31b8aSbellard {
50153a5960aSpbrook     target_ulong 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,
51183fb7adfSbellard                         size + qemu_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 */
52083fb7adfSbellard     target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
52131e31b8aSbellard 
52254936004Sbellard     stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
52309bfb054Sbellard     p += stack_base;
52409bfb054Sbellard 
52531e31b8aSbellard     for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
52631e31b8aSbellard 	if (bprm->page[i]) {
52731e31b8aSbellard 	    info->rss++;
52831e31b8aSbellard 
52953a5960aSpbrook 	    memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
53053a5960aSpbrook 	    free(bprm->page[i]);
53131e31b8aSbellard 	}
53254936004Sbellard         stack_base += TARGET_PAGE_SIZE;
53331e31b8aSbellard     }
53431e31b8aSbellard     return p;
53531e31b8aSbellard }
53631e31b8aSbellard 
53731e31b8aSbellard static void set_brk(unsigned long start, unsigned long end)
53831e31b8aSbellard {
53931e31b8aSbellard 	/* page-align the start and end addresses... */
54054936004Sbellard         start = HOST_PAGE_ALIGN(start);
54154936004Sbellard         end = HOST_PAGE_ALIGN(end);
54231e31b8aSbellard         if (end <= start)
54331e31b8aSbellard                 return;
54454936004Sbellard         if(target_mmap(start, end - start,
54531e31b8aSbellard                        PROT_READ | PROT_WRITE | PROT_EXEC,
54631e31b8aSbellard                        MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
54731e31b8aSbellard 	    perror("cannot mmap brk");
54831e31b8aSbellard 	    exit(-1);
54931e31b8aSbellard 	}
55031e31b8aSbellard }
55131e31b8aSbellard 
55231e31b8aSbellard 
553853d6f7aSbellard /* We need to explicitly zero any fractional pages after the data
554853d6f7aSbellard    section (i.e. bss).  This would contain the junk from the file that
555853d6f7aSbellard    should not be in memory. */
556*768a4a36Sths static void padzero(unsigned long elf_bss, unsigned long last_bss)
55731e31b8aSbellard {
55831e31b8aSbellard         unsigned long nbyte;
55931e31b8aSbellard 
560*768a4a36Sths 	if (elf_bss >= last_bss)
561*768a4a36Sths 		return;
562*768a4a36Sths 
563853d6f7aSbellard         /* XXX: this is really a hack : if the real host page size is
564853d6f7aSbellard            smaller than the target page size, some pages after the end
565853d6f7aSbellard            of the file may not be mapped. A better fix would be to
566853d6f7aSbellard            patch target_mmap(), but it is more complicated as the file
567853d6f7aSbellard            size must be known */
56883fb7adfSbellard         if (qemu_real_host_page_size < qemu_host_page_size) {
569853d6f7aSbellard             unsigned long end_addr, end_addr1;
57083fb7adfSbellard             end_addr1 = (elf_bss + qemu_real_host_page_size - 1) &
57183fb7adfSbellard                 ~(qemu_real_host_page_size - 1);
572853d6f7aSbellard             end_addr = HOST_PAGE_ALIGN(elf_bss);
573853d6f7aSbellard             if (end_addr1 < end_addr) {
574853d6f7aSbellard                 mmap((void *)end_addr1, end_addr - end_addr1,
575853d6f7aSbellard                      PROT_READ|PROT_WRITE|PROT_EXEC,
576853d6f7aSbellard                      MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
577853d6f7aSbellard             }
578853d6f7aSbellard         }
579853d6f7aSbellard 
58083fb7adfSbellard         nbyte = elf_bss & (qemu_host_page_size-1);
58131e31b8aSbellard         if (nbyte) {
58283fb7adfSbellard 	    nbyte = qemu_host_page_size - nbyte;
58331e31b8aSbellard 	    do {
58453a5960aSpbrook 		tput8(elf_bss, 0);
58553a5960aSpbrook                 elf_bss++;
58631e31b8aSbellard 	    } while (--nbyte);
58731e31b8aSbellard         }
58831e31b8aSbellard }
58931e31b8aSbellard 
59053a5960aSpbrook 
59153a5960aSpbrook static unsigned long create_elf_tables(target_ulong p, int argc, int envc,
59231e31b8aSbellard                                        struct elfhdr * exec,
59331e31b8aSbellard                                        unsigned long load_addr,
59409bfb054Sbellard                                        unsigned long load_bias,
59531e31b8aSbellard                                        unsigned long interp_load_addr, int ibcs,
59631e31b8aSbellard                                        struct image_info *info)
59731e31b8aSbellard {
59853a5960aSpbrook         target_ulong sp;
59953a5960aSpbrook         int size;
60053a5960aSpbrook         target_ulong u_platform;
60115338fd7Sbellard         const char *k_platform;
60253a5960aSpbrook         const int n = sizeof(target_ulong);
60331e31b8aSbellard 
60453a5960aSpbrook         sp = p;
60553a5960aSpbrook         u_platform = 0;
60615338fd7Sbellard         k_platform = ELF_PLATFORM;
60715338fd7Sbellard         if (k_platform) {
60815338fd7Sbellard             size_t len = strlen(k_platform) + 1;
60953a5960aSpbrook             sp -= (len + n - 1) & ~(n - 1);
61053a5960aSpbrook             u_platform = sp;
61153a5960aSpbrook             memcpy_to_target(sp, k_platform, len);
61215338fd7Sbellard         }
61353a5960aSpbrook 	/*
61453a5960aSpbrook 	 * Force 16 byte _final_ alignment here for generality.
61553a5960aSpbrook 	 */
61653a5960aSpbrook         sp = sp &~ (target_ulong)15;
61753a5960aSpbrook         size = (DLINFO_ITEMS + 1) * 2;
61815338fd7Sbellard         if (k_platform)
61953a5960aSpbrook           size += 2;
620f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS
62153a5960aSpbrook 	size += DLINFO_ARCH_ITEMS * 2;
622f5155289Sbellard #endif
62353a5960aSpbrook         size += envc + argc + 2;
62453a5960aSpbrook 	size += (!ibcs ? 3 : 1);	/* argc itself */
62553a5960aSpbrook         size *= n;
62653a5960aSpbrook         if (size & 15)
62753a5960aSpbrook             sp -= 16 - (size & 15);
628f5155289Sbellard 
62953a5960aSpbrook #define NEW_AUX_ENT(id, val) do { \
63053a5960aSpbrook             sp -= n; tputl(sp, val); \
63153a5960aSpbrook             sp -= n; tputl(sp, id); \
63253a5960aSpbrook           } while(0)
6330bccf03dSbellard         NEW_AUX_ENT (AT_NULL, 0);
634f5155289Sbellard 
6350bccf03dSbellard         /* There must be exactly DLINFO_ITEMS entries here.  */
6360bccf03dSbellard         NEW_AUX_ENT(AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
6370bccf03dSbellard         NEW_AUX_ENT(AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
6380bccf03dSbellard         NEW_AUX_ENT(AT_PHNUM, (target_ulong)(exec->e_phnum));
6390bccf03dSbellard         NEW_AUX_ENT(AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
6400bccf03dSbellard         NEW_AUX_ENT(AT_BASE, (target_ulong)(interp_load_addr));
6410bccf03dSbellard         NEW_AUX_ENT(AT_FLAGS, (target_ulong)0);
6420bccf03dSbellard         NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
6430bccf03dSbellard         NEW_AUX_ENT(AT_UID, (target_ulong) getuid());
6440bccf03dSbellard         NEW_AUX_ENT(AT_EUID, (target_ulong) geteuid());
6450bccf03dSbellard         NEW_AUX_ENT(AT_GID, (target_ulong) getgid());
6460bccf03dSbellard         NEW_AUX_ENT(AT_EGID, (target_ulong) getegid());
64715338fd7Sbellard         NEW_AUX_ENT(AT_HWCAP, (target_ulong) ELF_HWCAP);
64815338fd7Sbellard         if (k_platform)
64953a5960aSpbrook             NEW_AUX_ENT(AT_PLATFORM, u_platform);
650f5155289Sbellard #ifdef ARCH_DLINFO
651f5155289Sbellard 	/*
652f5155289Sbellard 	 * ARCH_DLINFO must come last so platform specific code can enforce
653f5155289Sbellard 	 * special alignment requirements on the AUXV if necessary (eg. PPC).
654f5155289Sbellard 	 */
655f5155289Sbellard         ARCH_DLINFO;
656f5155289Sbellard #endif
657f5155289Sbellard #undef NEW_AUX_ENT
658f5155289Sbellard 
659e5fe0c52Spbrook         sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
66031e31b8aSbellard         return sp;
66131e31b8aSbellard }
66231e31b8aSbellard 
66331e31b8aSbellard 
66431e31b8aSbellard static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
66531e31b8aSbellard 				     int interpreter_fd,
66631e31b8aSbellard 				     unsigned long *interp_load_addr)
66731e31b8aSbellard {
66831e31b8aSbellard 	struct elf_phdr *elf_phdata  =  NULL;
66931e31b8aSbellard 	struct elf_phdr *eppnt;
67009bfb054Sbellard 	unsigned long load_addr = 0;
67131e31b8aSbellard 	int load_addr_set = 0;
67231e31b8aSbellard 	int retval;
67331e31b8aSbellard 	unsigned long last_bss, elf_bss;
67431e31b8aSbellard 	unsigned long error;
67531e31b8aSbellard 	int i;
67631e31b8aSbellard 
67731e31b8aSbellard 	elf_bss = 0;
67831e31b8aSbellard 	last_bss = 0;
67931e31b8aSbellard 	error = 0;
68031e31b8aSbellard 
681644c433cSbellard #ifdef BSWAP_NEEDED
682644c433cSbellard         bswap_ehdr(interp_elf_ex);
683644c433cSbellard #endif
68431e31b8aSbellard 	/* First of all, some simple consistency checks */
68531e31b8aSbellard 	if ((interp_elf_ex->e_type != ET_EXEC &&
68631e31b8aSbellard              interp_elf_ex->e_type != ET_DYN) ||
68731e31b8aSbellard 	   !elf_check_arch(interp_elf_ex->e_machine)) {
68831e31b8aSbellard 		return ~0UL;
68931e31b8aSbellard 	}
69031e31b8aSbellard 
691644c433cSbellard 
69231e31b8aSbellard 	/* Now read in all of the header information */
69331e31b8aSbellard 
69454936004Sbellard 	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
69531e31b8aSbellard 	    return ~0UL;
69631e31b8aSbellard 
69731e31b8aSbellard 	elf_phdata =  (struct elf_phdr *)
69831e31b8aSbellard 		malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
69931e31b8aSbellard 
70031e31b8aSbellard 	if (!elf_phdata)
70131e31b8aSbellard 	  return ~0UL;
70231e31b8aSbellard 
70331e31b8aSbellard 	/*
70431e31b8aSbellard 	 * If the size of this structure has changed, then punt, since
70531e31b8aSbellard 	 * we will be doing the wrong thing.
70631e31b8aSbellard 	 */
70709bfb054Sbellard 	if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
70831e31b8aSbellard 	    free(elf_phdata);
70931e31b8aSbellard 	    return ~0UL;
71031e31b8aSbellard         }
71131e31b8aSbellard 
71231e31b8aSbellard 	retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
71331e31b8aSbellard 	if(retval >= 0) {
71431e31b8aSbellard 	    retval = read(interpreter_fd,
71531e31b8aSbellard 			   (char *) elf_phdata,
71631e31b8aSbellard 			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
71731e31b8aSbellard 	}
71831e31b8aSbellard 	if (retval < 0) {
71931e31b8aSbellard 		perror("load_elf_interp");
72031e31b8aSbellard 		exit(-1);
72131e31b8aSbellard 		free (elf_phdata);
72231e31b8aSbellard 		return retval;
72331e31b8aSbellard  	}
72431e31b8aSbellard #ifdef BSWAP_NEEDED
72531e31b8aSbellard 	eppnt = elf_phdata;
72631e31b8aSbellard 	for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
72731e31b8aSbellard             bswap_phdr(eppnt);
72831e31b8aSbellard         }
72931e31b8aSbellard #endif
73009bfb054Sbellard 
73109bfb054Sbellard         if (interp_elf_ex->e_type == ET_DYN) {
73209bfb054Sbellard             /* in order to avoid harcoding the interpreter load
73309bfb054Sbellard                address in qemu, we allocate a big enough memory zone */
73454936004Sbellard             error = target_mmap(0, INTERP_MAP_SIZE,
73509bfb054Sbellard                                 PROT_NONE, MAP_PRIVATE | MAP_ANON,
73609bfb054Sbellard                                 -1, 0);
73709bfb054Sbellard             if (error == -1) {
73809bfb054Sbellard                 perror("mmap");
73909bfb054Sbellard                 exit(-1);
74009bfb054Sbellard             }
74109bfb054Sbellard             load_addr = error;
74209bfb054Sbellard             load_addr_set = 1;
74309bfb054Sbellard         }
74409bfb054Sbellard 
74531e31b8aSbellard 	eppnt = elf_phdata;
74631e31b8aSbellard 	for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
74731e31b8aSbellard 	  if (eppnt->p_type == PT_LOAD) {
74831e31b8aSbellard 	    int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
74931e31b8aSbellard 	    int elf_prot = 0;
75031e31b8aSbellard 	    unsigned long vaddr = 0;
75131e31b8aSbellard 	    unsigned long k;
75231e31b8aSbellard 
75331e31b8aSbellard 	    if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
75431e31b8aSbellard 	    if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
75531e31b8aSbellard 	    if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
75631e31b8aSbellard 	    if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
75731e31b8aSbellard 	    	elf_type |= MAP_FIXED;
75831e31b8aSbellard 	    	vaddr = eppnt->p_vaddr;
75931e31b8aSbellard 	    }
76054936004Sbellard 	    error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
76154936004Sbellard 		 eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
76231e31b8aSbellard 		 elf_prot,
76331e31b8aSbellard 		 elf_type,
76431e31b8aSbellard 		 interpreter_fd,
76554936004Sbellard 		 eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
76631e31b8aSbellard 
767e89f07d3Spbrook 	    if (error == -1) {
76831e31b8aSbellard 	      /* Real error */
76931e31b8aSbellard 	      close(interpreter_fd);
77031e31b8aSbellard 	      free(elf_phdata);
77131e31b8aSbellard 	      return ~0UL;
77231e31b8aSbellard 	    }
77331e31b8aSbellard 
77431e31b8aSbellard 	    if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
77531e31b8aSbellard 	      load_addr = error;
77631e31b8aSbellard 	      load_addr_set = 1;
77731e31b8aSbellard 	    }
77831e31b8aSbellard 
77931e31b8aSbellard 	    /*
78031e31b8aSbellard 	     * Find the end of the file  mapping for this phdr, and keep
78131e31b8aSbellard 	     * track of the largest address we see for this.
78231e31b8aSbellard 	     */
78331e31b8aSbellard 	    k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
78431e31b8aSbellard 	    if (k > elf_bss) elf_bss = k;
78531e31b8aSbellard 
78631e31b8aSbellard 	    /*
78731e31b8aSbellard 	     * Do the same thing for the memory mapping - between
78831e31b8aSbellard 	     * elf_bss and last_bss is the bss section.
78931e31b8aSbellard 	     */
79031e31b8aSbellard 	    k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
79131e31b8aSbellard 	    if (k > last_bss) last_bss = k;
79231e31b8aSbellard 	  }
79331e31b8aSbellard 
79431e31b8aSbellard 	/* Now use mmap to map the library into memory. */
79531e31b8aSbellard 
79631e31b8aSbellard 	close(interpreter_fd);
79731e31b8aSbellard 
79831e31b8aSbellard 	/*
79931e31b8aSbellard 	 * Now fill out the bss section.  First pad the last page up
80031e31b8aSbellard 	 * to the page boundary, and then perform a mmap to make sure
80131e31b8aSbellard 	 * that there are zeromapped pages up to and including the last
80231e31b8aSbellard 	 * bss page.
80331e31b8aSbellard 	 */
804*768a4a36Sths 	padzero(elf_bss, last_bss);
80583fb7adfSbellard 	elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */
80631e31b8aSbellard 
80731e31b8aSbellard 	/* Map the last of the bss segment */
80831e31b8aSbellard 	if (last_bss > elf_bss) {
80954936004Sbellard             target_mmap(elf_bss, last_bss-elf_bss,
81031e31b8aSbellard                         PROT_READ|PROT_WRITE|PROT_EXEC,
81131e31b8aSbellard                         MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
81231e31b8aSbellard 	}
81331e31b8aSbellard 	free(elf_phdata);
81431e31b8aSbellard 
81531e31b8aSbellard 	*interp_load_addr = load_addr;
81631e31b8aSbellard 	return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
81731e31b8aSbellard }
81831e31b8aSbellard 
819689f936fSbellard /* Best attempt to load symbols from this ELF object. */
820689f936fSbellard static void load_symbols(struct elfhdr *hdr, int fd)
821689f936fSbellard {
822689f936fSbellard     unsigned int i;
823689f936fSbellard     struct elf_shdr sechdr, symtab, strtab;
824689f936fSbellard     char *strings;
825e80cfcfcSbellard     struct syminfo *s;
82631e31b8aSbellard 
827689f936fSbellard     lseek(fd, hdr->e_shoff, SEEK_SET);
828689f936fSbellard     for (i = 0; i < hdr->e_shnum; i++) {
829689f936fSbellard 	if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
830689f936fSbellard 	    return;
831689f936fSbellard #ifdef BSWAP_NEEDED
832689f936fSbellard 	bswap_shdr(&sechdr);
833689f936fSbellard #endif
834689f936fSbellard 	if (sechdr.sh_type == SHT_SYMTAB) {
835689f936fSbellard 	    symtab = sechdr;
836689f936fSbellard 	    lseek(fd, hdr->e_shoff
837689f936fSbellard 		  + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
838689f936fSbellard 	    if (read(fd, &strtab, sizeof(strtab))
839689f936fSbellard 		!= sizeof(strtab))
840689f936fSbellard 		return;
841689f936fSbellard #ifdef BSWAP_NEEDED
842689f936fSbellard 	    bswap_shdr(&strtab);
843689f936fSbellard #endif
844689f936fSbellard 	    goto found;
845689f936fSbellard 	}
846689f936fSbellard     }
847689f936fSbellard     return; /* Shouldn't happen... */
848689f936fSbellard 
849689f936fSbellard  found:
850689f936fSbellard     /* Now know where the strtab and symtab are.  Snarf them. */
851e80cfcfcSbellard     s = malloc(sizeof(*s));
852e80cfcfcSbellard     s->disas_symtab = malloc(symtab.sh_size);
853e80cfcfcSbellard     s->disas_strtab = strings = malloc(strtab.sh_size);
854e80cfcfcSbellard     if (!s->disas_symtab || !s->disas_strtab)
855689f936fSbellard 	return;
856689f936fSbellard 
857689f936fSbellard     lseek(fd, symtab.sh_offset, SEEK_SET);
858e80cfcfcSbellard     if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size)
859689f936fSbellard 	return;
860689f936fSbellard 
861689f936fSbellard #ifdef BSWAP_NEEDED
862689f936fSbellard     for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++)
863e80cfcfcSbellard 	bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i);
864689f936fSbellard #endif
865689f936fSbellard 
866689f936fSbellard     lseek(fd, strtab.sh_offset, SEEK_SET);
867689f936fSbellard     if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
868689f936fSbellard 	return;
869e80cfcfcSbellard     s->disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
870e80cfcfcSbellard     s->next = syminfos;
871e80cfcfcSbellard     syminfos = s;
872689f936fSbellard }
87331e31b8aSbellard 
874e5fe0c52Spbrook int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
87531e31b8aSbellard                     struct image_info * info)
87631e31b8aSbellard {
87731e31b8aSbellard     struct elfhdr elf_ex;
87831e31b8aSbellard     struct elfhdr interp_elf_ex;
87931e31b8aSbellard     struct exec interp_ex;
88031e31b8aSbellard     int interpreter_fd = -1; /* avoid warning */
88109bfb054Sbellard     unsigned long load_addr, load_bias;
88231e31b8aSbellard     int load_addr_set = 0;
88331e31b8aSbellard     unsigned int interpreter_type = INTERPRETER_NONE;
88431e31b8aSbellard     unsigned char ibcs2_interpreter;
88531e31b8aSbellard     int i;
88654936004Sbellard     unsigned long mapped_addr;
88731e31b8aSbellard     struct elf_phdr * elf_ppnt;
88831e31b8aSbellard     struct elf_phdr *elf_phdata;
88931e31b8aSbellard     unsigned long elf_bss, k, elf_brk;
89031e31b8aSbellard     int retval;
89131e31b8aSbellard     char * elf_interpreter;
89231e31b8aSbellard     unsigned long elf_entry, interp_load_addr = 0;
89331e31b8aSbellard     int status;
89431e31b8aSbellard     unsigned long start_code, end_code, end_data;
89531e31b8aSbellard     unsigned long elf_stack;
89631e31b8aSbellard     char passed_fileno[6];
89731e31b8aSbellard 
89831e31b8aSbellard     ibcs2_interpreter = 0;
89931e31b8aSbellard     status = 0;
90031e31b8aSbellard     load_addr = 0;
90109bfb054Sbellard     load_bias = 0;
90231e31b8aSbellard     elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
90331e31b8aSbellard #ifdef BSWAP_NEEDED
90431e31b8aSbellard     bswap_ehdr(&elf_ex);
90531e31b8aSbellard #endif
90631e31b8aSbellard 
90731e31b8aSbellard     /* First of all, some simple consistency checks */
90831e31b8aSbellard     if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
90931e31b8aSbellard        				(! elf_check_arch(elf_ex.e_machine))) {
91031e31b8aSbellard 	    return -ENOEXEC;
91131e31b8aSbellard     }
91231e31b8aSbellard 
913e5fe0c52Spbrook     bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
914e5fe0c52Spbrook     bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
915e5fe0c52Spbrook     bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
916e5fe0c52Spbrook     if (!bprm->p) {
917e5fe0c52Spbrook         retval = -E2BIG;
918e5fe0c52Spbrook     }
919e5fe0c52Spbrook 
92031e31b8aSbellard     /* Now read in all of the header information */
92131e31b8aSbellard     elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
92231e31b8aSbellard     if (elf_phdata == NULL) {
92331e31b8aSbellard 	return -ENOMEM;
92431e31b8aSbellard     }
92531e31b8aSbellard 
92631e31b8aSbellard     retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
92731e31b8aSbellard     if(retval > 0) {
92831e31b8aSbellard 	retval = read(bprm->fd, (char *) elf_phdata,
92931e31b8aSbellard 				elf_ex.e_phentsize * elf_ex.e_phnum);
93031e31b8aSbellard     }
93131e31b8aSbellard 
93231e31b8aSbellard     if (retval < 0) {
93331e31b8aSbellard 	perror("load_elf_binary");
93431e31b8aSbellard 	exit(-1);
93531e31b8aSbellard 	free (elf_phdata);
93631e31b8aSbellard 	return -errno;
93731e31b8aSbellard     }
93831e31b8aSbellard 
939b17780d5Sbellard #ifdef BSWAP_NEEDED
940b17780d5Sbellard     elf_ppnt = elf_phdata;
941b17780d5Sbellard     for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
942b17780d5Sbellard         bswap_phdr(elf_ppnt);
943b17780d5Sbellard     }
944b17780d5Sbellard #endif
94531e31b8aSbellard     elf_ppnt = elf_phdata;
94631e31b8aSbellard 
94731e31b8aSbellard     elf_bss = 0;
94831e31b8aSbellard     elf_brk = 0;
94931e31b8aSbellard 
95031e31b8aSbellard 
95131e31b8aSbellard     elf_stack = ~0UL;
95231e31b8aSbellard     elf_interpreter = NULL;
95331e31b8aSbellard     start_code = ~0UL;
95431e31b8aSbellard     end_code = 0;
95531e31b8aSbellard     end_data = 0;
95631e31b8aSbellard 
95731e31b8aSbellard     for(i=0;i < elf_ex.e_phnum; i++) {
95831e31b8aSbellard 	if (elf_ppnt->p_type == PT_INTERP) {
95931e31b8aSbellard 	    if ( elf_interpreter != NULL )
96031e31b8aSbellard 	    {
96131e31b8aSbellard 		free (elf_phdata);
96231e31b8aSbellard 		free(elf_interpreter);
96331e31b8aSbellard 		close(bprm->fd);
96431e31b8aSbellard 		return -EINVAL;
96531e31b8aSbellard 	    }
96631e31b8aSbellard 
96731e31b8aSbellard 	    /* This is the program interpreter used for
96831e31b8aSbellard 	     * shared libraries - for now assume that this
96931e31b8aSbellard 	     * is an a.out format binary
97031e31b8aSbellard 	     */
97131e31b8aSbellard 
97232ce6337Sbellard 	    elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
97331e31b8aSbellard 
97431e31b8aSbellard 	    if (elf_interpreter == NULL) {
97531e31b8aSbellard 		free (elf_phdata);
97631e31b8aSbellard 		close(bprm->fd);
97731e31b8aSbellard 		return -ENOMEM;
97831e31b8aSbellard 	    }
97931e31b8aSbellard 
98031e31b8aSbellard 	    retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
98131e31b8aSbellard 	    if(retval >= 0) {
98232ce6337Sbellard 		retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
98331e31b8aSbellard 	    }
98431e31b8aSbellard 	    if(retval < 0) {
98531e31b8aSbellard 	 	perror("load_elf_binary2");
98631e31b8aSbellard 		exit(-1);
98731e31b8aSbellard 	    }
98831e31b8aSbellard 
98931e31b8aSbellard 	    /* If the program interpreter is one of these two,
99031e31b8aSbellard 	       then assume an iBCS2 image. Otherwise assume
99131e31b8aSbellard 	       a native linux image. */
99231e31b8aSbellard 
99331e31b8aSbellard 	    /* JRP - Need to add X86 lib dir stuff here... */
99431e31b8aSbellard 
99531e31b8aSbellard 	    if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
99631e31b8aSbellard 		strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
99731e31b8aSbellard 	      ibcs2_interpreter = 1;
99831e31b8aSbellard 	    }
99931e31b8aSbellard 
100031e31b8aSbellard #if 0
100131e31b8aSbellard 	    printf("Using ELF interpreter %s\n", elf_interpreter);
100231e31b8aSbellard #endif
100331e31b8aSbellard 	    if (retval >= 0) {
100432ce6337Sbellard 		retval = open(path(elf_interpreter), O_RDONLY);
100531e31b8aSbellard 		if(retval >= 0) {
100631e31b8aSbellard 		    interpreter_fd = retval;
100731e31b8aSbellard 		}
100831e31b8aSbellard 		else {
100931e31b8aSbellard 		    perror(elf_interpreter);
101031e31b8aSbellard 		    exit(-1);
101131e31b8aSbellard 		    /* retval = -errno; */
101231e31b8aSbellard 		}
101331e31b8aSbellard 	    }
101431e31b8aSbellard 
101531e31b8aSbellard 	    if (retval >= 0) {
101631e31b8aSbellard 		retval = lseek(interpreter_fd, 0, SEEK_SET);
101731e31b8aSbellard 		if(retval >= 0) {
101831e31b8aSbellard 		    retval = read(interpreter_fd,bprm->buf,128);
101931e31b8aSbellard 		}
102031e31b8aSbellard 	    }
102131e31b8aSbellard 	    if (retval >= 0) {
102231e31b8aSbellard 		interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
102331e31b8aSbellard 		interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */
102431e31b8aSbellard 	    }
102531e31b8aSbellard 	    if (retval < 0) {
102631e31b8aSbellard 		perror("load_elf_binary3");
102731e31b8aSbellard 		exit(-1);
102831e31b8aSbellard 		free (elf_phdata);
102931e31b8aSbellard 		free(elf_interpreter);
103031e31b8aSbellard 		close(bprm->fd);
103131e31b8aSbellard 		return retval;
103231e31b8aSbellard 	    }
103331e31b8aSbellard 	}
103431e31b8aSbellard 	elf_ppnt++;
103531e31b8aSbellard     }
103631e31b8aSbellard 
103731e31b8aSbellard     /* Some simple consistency checks for the interpreter */
103831e31b8aSbellard     if (elf_interpreter){
103931e31b8aSbellard 	interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
104031e31b8aSbellard 
104131e31b8aSbellard 	/* Now figure out which format our binary is */
104231e31b8aSbellard 	if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
104331e31b8aSbellard 	    	(N_MAGIC(interp_ex) != QMAGIC)) {
104431e31b8aSbellard 	  interpreter_type = INTERPRETER_ELF;
104531e31b8aSbellard 	}
104631e31b8aSbellard 
104731e31b8aSbellard 	if (interp_elf_ex.e_ident[0] != 0x7f ||
104831e31b8aSbellard 	    	strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) {
104931e31b8aSbellard 	    interpreter_type &= ~INTERPRETER_ELF;
105031e31b8aSbellard 	}
105131e31b8aSbellard 
105231e31b8aSbellard 	if (!interpreter_type) {
105331e31b8aSbellard 	    free(elf_interpreter);
105431e31b8aSbellard 	    free(elf_phdata);
105531e31b8aSbellard 	    close(bprm->fd);
105631e31b8aSbellard 	    return -ELIBBAD;
105731e31b8aSbellard 	}
105831e31b8aSbellard     }
105931e31b8aSbellard 
106031e31b8aSbellard     /* OK, we are done with that, now set up the arg stuff,
106131e31b8aSbellard        and then start this sucker up */
106231e31b8aSbellard 
1063e5fe0c52Spbrook     {
106431e31b8aSbellard 	char * passed_p;
106531e31b8aSbellard 
106631e31b8aSbellard 	if (interpreter_type == INTERPRETER_AOUT) {
1067eba2af63Sbellard 	    snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
106831e31b8aSbellard 	    passed_p = passed_fileno;
106931e31b8aSbellard 
107031e31b8aSbellard 	    if (elf_interpreter) {
1071e5fe0c52Spbrook 		bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p);
107231e31b8aSbellard 		bprm->argc++;
107331e31b8aSbellard 	    }
107431e31b8aSbellard 	}
107531e31b8aSbellard 	if (!bprm->p) {
107631e31b8aSbellard 	    if (elf_interpreter) {
107731e31b8aSbellard 	        free(elf_interpreter);
107831e31b8aSbellard 	    }
107931e31b8aSbellard 	    free (elf_phdata);
108031e31b8aSbellard 	    close(bprm->fd);
108131e31b8aSbellard 	    return -E2BIG;
108231e31b8aSbellard 	}
108331e31b8aSbellard     }
108431e31b8aSbellard 
108531e31b8aSbellard     /* OK, This is the point of no return */
108631e31b8aSbellard     info->end_data = 0;
108731e31b8aSbellard     info->end_code = 0;
108831e31b8aSbellard     info->start_mmap = (unsigned long)ELF_START_MMAP;
108931e31b8aSbellard     info->mmap = 0;
109031e31b8aSbellard     elf_entry = (unsigned long) elf_ex.e_entry;
109131e31b8aSbellard 
109231e31b8aSbellard     /* Do this so that we can load the interpreter, if need be.  We will
109331e31b8aSbellard        change some of these later */
109431e31b8aSbellard     info->rss = 0;
109531e31b8aSbellard     bprm->p = setup_arg_pages(bprm->p, bprm, info);
109631e31b8aSbellard     info->start_stack = bprm->p;
109731e31b8aSbellard 
109831e31b8aSbellard     /* Now we do a little grungy work by mmaping the ELF image into
109931e31b8aSbellard      * the correct location in memory.  At this point, we assume that
110031e31b8aSbellard      * the image should be loaded at fixed address, not at a variable
110131e31b8aSbellard      * address.
110231e31b8aSbellard      */
110331e31b8aSbellard 
110431e31b8aSbellard     for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
110531e31b8aSbellard         int elf_prot = 0;
110609bfb054Sbellard         int elf_flags = 0;
110709bfb054Sbellard         unsigned long error;
110809bfb054Sbellard 
110909bfb054Sbellard 	if (elf_ppnt->p_type != PT_LOAD)
111009bfb054Sbellard             continue;
111109bfb054Sbellard 
111231e31b8aSbellard         if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
111331e31b8aSbellard         if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
111431e31b8aSbellard         if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
111509bfb054Sbellard         elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
111609bfb054Sbellard         if (elf_ex.e_type == ET_EXEC || load_addr_set) {
111709bfb054Sbellard             elf_flags |= MAP_FIXED;
111809bfb054Sbellard         } else if (elf_ex.e_type == ET_DYN) {
111909bfb054Sbellard             /* Try and get dynamic programs out of the way of the default mmap
112009bfb054Sbellard                base, as well as whatever program they might try to exec.  This
112109bfb054Sbellard                is because the brk will follow the loader, and is not movable.  */
112209bfb054Sbellard             /* NOTE: for qemu, we do a big mmap to get enough space
112309bfb054Sbellard                without harcoding any address */
112454936004Sbellard             error = target_mmap(0, ET_DYN_MAP_SIZE,
112509bfb054Sbellard                                 PROT_NONE, MAP_PRIVATE | MAP_ANON,
112609bfb054Sbellard                                 -1, 0);
112709bfb054Sbellard             if (error == -1) {
112809bfb054Sbellard                 perror("mmap");
112909bfb054Sbellard                 exit(-1);
113009bfb054Sbellard             }
113154936004Sbellard             load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
113209bfb054Sbellard         }
113331e31b8aSbellard 
113454936004Sbellard         error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
113531e31b8aSbellard                             (elf_ppnt->p_filesz +
113654936004Sbellard                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
113731e31b8aSbellard                             elf_prot,
113831e31b8aSbellard                             (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
113931e31b8aSbellard                             bprm->fd,
114031e31b8aSbellard                             (elf_ppnt->p_offset -
114154936004Sbellard                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
114209bfb054Sbellard         if (error == -1) {
114331e31b8aSbellard             perror("mmap");
114431e31b8aSbellard             exit(-1);
114531e31b8aSbellard         }
114631e31b8aSbellard 
114731e31b8aSbellard #ifdef LOW_ELF_STACK
114854936004Sbellard         if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
114954936004Sbellard             elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr);
115031e31b8aSbellard #endif
115131e31b8aSbellard 
115231e31b8aSbellard         if (!load_addr_set) {
115331e31b8aSbellard             load_addr_set = 1;
115409bfb054Sbellard             load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
115509bfb054Sbellard             if (elf_ex.e_type == ET_DYN) {
115609bfb054Sbellard                 load_bias += error -
115754936004Sbellard                     TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
115809bfb054Sbellard                 load_addr += load_bias;
115909bfb054Sbellard             }
116031e31b8aSbellard         }
116131e31b8aSbellard         k = elf_ppnt->p_vaddr;
116209bfb054Sbellard         if (k < start_code)
116309bfb054Sbellard             start_code = k;
116431e31b8aSbellard         k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
116509bfb054Sbellard         if (k > elf_bss)
116609bfb054Sbellard             elf_bss = k;
116731e31b8aSbellard         if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
116831e31b8aSbellard             end_code = k;
116909bfb054Sbellard         if (end_data < k)
117009bfb054Sbellard             end_data = k;
117131e31b8aSbellard         k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
117231e31b8aSbellard         if (k > elf_brk) elf_brk = k;
117331e31b8aSbellard     }
117409bfb054Sbellard 
117509bfb054Sbellard     elf_entry += load_bias;
117609bfb054Sbellard     elf_bss += load_bias;
117709bfb054Sbellard     elf_brk += load_bias;
117809bfb054Sbellard     start_code += load_bias;
117909bfb054Sbellard     end_code += load_bias;
118009bfb054Sbellard     //    start_data += load_bias;
118109bfb054Sbellard     end_data += load_bias;
118231e31b8aSbellard 
118331e31b8aSbellard     if (elf_interpreter) {
118431e31b8aSbellard 	if (interpreter_type & 1) {
118531e31b8aSbellard 	    elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
118631e31b8aSbellard 	}
118731e31b8aSbellard 	else if (interpreter_type & 2) {
118831e31b8aSbellard 	    elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
118931e31b8aSbellard 					    &interp_load_addr);
119031e31b8aSbellard 	}
119131e31b8aSbellard 
119231e31b8aSbellard 	close(interpreter_fd);
119331e31b8aSbellard 	free(elf_interpreter);
119431e31b8aSbellard 
119531e31b8aSbellard 	if (elf_entry == ~0UL) {
119631e31b8aSbellard 	    printf("Unable to load interpreter\n");
119731e31b8aSbellard 	    free(elf_phdata);
119831e31b8aSbellard 	    exit(-1);
119931e31b8aSbellard 	    return 0;
120031e31b8aSbellard 	}
120131e31b8aSbellard     }
120231e31b8aSbellard 
120331e31b8aSbellard     free(elf_phdata);
120431e31b8aSbellard 
1205689f936fSbellard     if (loglevel)
1206689f936fSbellard 	load_symbols(&elf_ex, bprm->fd);
1207689f936fSbellard 
120831e31b8aSbellard     if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
120931e31b8aSbellard     info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
121031e31b8aSbellard 
121131e31b8aSbellard #ifdef LOW_ELF_STACK
121231e31b8aSbellard     info->start_stack = bprm->p = elf_stack - 4;
121331e31b8aSbellard #endif
121453a5960aSpbrook     bprm->p = create_elf_tables(bprm->p,
121531e31b8aSbellard 		    bprm->argc,
121631e31b8aSbellard 		    bprm->envc,
1217a1516e92Sbellard                     &elf_ex,
121809bfb054Sbellard                     load_addr, load_bias,
121931e31b8aSbellard 		    interp_load_addr,
122031e31b8aSbellard 		    (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
122131e31b8aSbellard 		    info);
122231e31b8aSbellard     info->start_brk = info->brk = elf_brk;
122331e31b8aSbellard     info->end_code = end_code;
122431e31b8aSbellard     info->start_code = start_code;
1225e5fe0c52Spbrook     info->start_data = end_code;
122631e31b8aSbellard     info->end_data = end_data;
122731e31b8aSbellard     info->start_stack = bprm->p;
122831e31b8aSbellard 
122931e31b8aSbellard     /* Calling set_brk effectively mmaps the pages that we need for the bss and break
123031e31b8aSbellard        sections */
123131e31b8aSbellard     set_brk(elf_bss, elf_brk);
123231e31b8aSbellard 
1233*768a4a36Sths     padzero(elf_bss, elf_brk);
123431e31b8aSbellard 
123531e31b8aSbellard #if 0
123631e31b8aSbellard     printf("(start_brk) %x\n" , info->start_brk);
123731e31b8aSbellard     printf("(end_code) %x\n" , info->end_code);
123831e31b8aSbellard     printf("(start_code) %x\n" , info->start_code);
123931e31b8aSbellard     printf("(end_data) %x\n" , info->end_data);
124031e31b8aSbellard     printf("(start_stack) %x\n" , info->start_stack);
124131e31b8aSbellard     printf("(brk) %x\n" , info->brk);
124231e31b8aSbellard #endif
124331e31b8aSbellard 
124431e31b8aSbellard     if ( info->personality == PER_SVR4 )
124531e31b8aSbellard     {
124631e31b8aSbellard 	    /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
124731e31b8aSbellard 	       and some applications "depend" upon this behavior.
124831e31b8aSbellard 	       Since we do not have the power to recompile these, we
124931e31b8aSbellard 	       emulate the SVr4 behavior.  Sigh.  */
125083fb7adfSbellard 	    mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
125131e31b8aSbellard                                       MAP_FIXED | MAP_PRIVATE, -1, 0);
125231e31b8aSbellard     }
125331e31b8aSbellard 
125431e31b8aSbellard     info->entry = elf_entry;
125531e31b8aSbellard 
125631e31b8aSbellard     return 0;
125731e31b8aSbellard }
125831e31b8aSbellard 
125931e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd)
126031e31b8aSbellard {
126131e31b8aSbellard     printf("a.out interpreter not yet supported\n");
126231e31b8aSbellard     return(0);
126331e31b8aSbellard }
126431e31b8aSbellard 
1265e5fe0c52Spbrook void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
1266e5fe0c52Spbrook {
1267e5fe0c52Spbrook     init_thread(regs, infop);
1268e5fe0c52Spbrook }
1269