xref: /qemu/linux-user/elfload.c (revision 2f6196984b98fe2a852b1b5254756f1614eb7635)
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 
15cb33da57Sblueswir1 /* from personality.h */
16cb33da57Sblueswir1 
17cb33da57Sblueswir1 /*
18cb33da57Sblueswir1  * Flags for bug emulation.
19cb33da57Sblueswir1  *
20cb33da57Sblueswir1  * These occupy the top three bytes.
21cb33da57Sblueswir1  */
22cb33da57Sblueswir1 enum {
23cb33da57Sblueswir1 	ADDR_NO_RANDOMIZE = 	0x0040000,	/* disable randomization of VA space */
24cb33da57Sblueswir1 	FDPIC_FUNCPTRS =	0x0080000,	/* userspace function ptrs point to descriptors
25cb33da57Sblueswir1 						 * (signal handling)
26cb33da57Sblueswir1 						 */
27cb33da57Sblueswir1 	MMAP_PAGE_ZERO =	0x0100000,
28cb33da57Sblueswir1 	ADDR_COMPAT_LAYOUT =	0x0200000,
29cb33da57Sblueswir1 	READ_IMPLIES_EXEC =	0x0400000,
30cb33da57Sblueswir1 	ADDR_LIMIT_32BIT =	0x0800000,
31cb33da57Sblueswir1 	SHORT_INODE =		0x1000000,
32cb33da57Sblueswir1 	WHOLE_SECONDS =		0x2000000,
33cb33da57Sblueswir1 	STICKY_TIMEOUTS	=	0x4000000,
34cb33da57Sblueswir1 	ADDR_LIMIT_3GB = 	0x8000000,
35cb33da57Sblueswir1 };
36cb33da57Sblueswir1 
37cb33da57Sblueswir1 /*
38cb33da57Sblueswir1  * Personality types.
39cb33da57Sblueswir1  *
40cb33da57Sblueswir1  * These go in the low byte.  Avoid using the top bit, it will
41cb33da57Sblueswir1  * conflict with error returns.
42cb33da57Sblueswir1  */
43cb33da57Sblueswir1 enum {
44cb33da57Sblueswir1 	PER_LINUX =		0x0000,
45cb33da57Sblueswir1 	PER_LINUX_32BIT =	0x0000 | ADDR_LIMIT_32BIT,
46cb33da57Sblueswir1 	PER_LINUX_FDPIC =	0x0000 | FDPIC_FUNCPTRS,
47cb33da57Sblueswir1 	PER_SVR4 =		0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
48cb33da57Sblueswir1 	PER_SVR3 =		0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
49cb33da57Sblueswir1 	PER_SCOSVR3 =		0x0003 | STICKY_TIMEOUTS |
50cb33da57Sblueswir1 					 WHOLE_SECONDS | SHORT_INODE,
51cb33da57Sblueswir1 	PER_OSR5 =		0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
52cb33da57Sblueswir1 	PER_WYSEV386 =		0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
53cb33da57Sblueswir1 	PER_ISCR4 =		0x0005 | STICKY_TIMEOUTS,
54cb33da57Sblueswir1 	PER_BSD =		0x0006,
55cb33da57Sblueswir1 	PER_SUNOS =		0x0006 | STICKY_TIMEOUTS,
56cb33da57Sblueswir1 	PER_XENIX =		0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
57cb33da57Sblueswir1 	PER_LINUX32 =		0x0008,
58cb33da57Sblueswir1 	PER_LINUX32_3GB =	0x0008 | ADDR_LIMIT_3GB,
59cb33da57Sblueswir1 	PER_IRIX32 =		0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
60cb33da57Sblueswir1 	PER_IRIXN32 =		0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
61cb33da57Sblueswir1 	PER_IRIX64 =		0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
62cb33da57Sblueswir1 	PER_RISCOS =		0x000c,
63cb33da57Sblueswir1 	PER_SOLARIS =		0x000d | STICKY_TIMEOUTS,
64cb33da57Sblueswir1 	PER_UW7 =		0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
65cb33da57Sblueswir1 	PER_OSF4 =		0x000f,			 /* OSF/1 v4 */
66cb33da57Sblueswir1 	PER_HPUX =		0x0010,
67cb33da57Sblueswir1 	PER_MASK =		0x00ff,
68cb33da57Sblueswir1 };
69cb33da57Sblueswir1 
70cb33da57Sblueswir1 /*
71cb33da57Sblueswir1  * Return the base personality without flags.
72cb33da57Sblueswir1  */
73cb33da57Sblueswir1 #define personality(pers)	(pers & PER_MASK)
74cb33da57Sblueswir1 
7583fb7adfSbellard /* this flag is uneffective under linux too, should be deleted */
7683fb7adfSbellard #ifndef MAP_DENYWRITE
7783fb7adfSbellard #define MAP_DENYWRITE 0
7883fb7adfSbellard #endif
7983fb7adfSbellard 
8083fb7adfSbellard /* should probably go in elf.h */
8183fb7adfSbellard #ifndef ELIBBAD
8283fb7adfSbellard #define ELIBBAD 80
8383fb7adfSbellard #endif
8483fb7adfSbellard 
8530ac07d4Sbellard #ifdef TARGET_I386
8630ac07d4Sbellard 
8715338fd7Sbellard #define ELF_PLATFORM get_elf_platform()
8815338fd7Sbellard 
8915338fd7Sbellard static const char *get_elf_platform(void)
9015338fd7Sbellard {
9115338fd7Sbellard     static char elf_platform[] = "i386";
9215338fd7Sbellard     int family = (global_env->cpuid_version >> 8) & 0xff;
9315338fd7Sbellard     if (family > 6)
9415338fd7Sbellard         family = 6;
9515338fd7Sbellard     if (family >= 3)
9615338fd7Sbellard         elf_platform[1] = '0' + family;
9715338fd7Sbellard     return elf_platform;
9815338fd7Sbellard }
9915338fd7Sbellard 
10015338fd7Sbellard #define ELF_HWCAP get_elf_hwcap()
10115338fd7Sbellard 
10215338fd7Sbellard static uint32_t get_elf_hwcap(void)
10315338fd7Sbellard {
10415338fd7Sbellard   return global_env->cpuid_features;
10515338fd7Sbellard }
10615338fd7Sbellard 
10784409ddbSj_mayer #ifdef TARGET_X86_64
10884409ddbSj_mayer #define ELF_START_MMAP 0x2aaaaab000ULL
10984409ddbSj_mayer #define elf_check_arch(x) ( ((x) == ELF_ARCH) )
11084409ddbSj_mayer 
11184409ddbSj_mayer #define ELF_CLASS      ELFCLASS64
11284409ddbSj_mayer #define ELF_DATA       ELFDATA2LSB
11384409ddbSj_mayer #define ELF_ARCH       EM_X86_64
11484409ddbSj_mayer 
11584409ddbSj_mayer static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
11684409ddbSj_mayer {
11784409ddbSj_mayer     regs->rax = 0;
11884409ddbSj_mayer     regs->rsp = infop->start_stack;
11984409ddbSj_mayer     regs->rip = infop->entry;
12084409ddbSj_mayer }
12184409ddbSj_mayer 
12284409ddbSj_mayer #else
12384409ddbSj_mayer 
12430ac07d4Sbellard #define ELF_START_MMAP 0x80000000
12530ac07d4Sbellard 
12630ac07d4Sbellard /*
12730ac07d4Sbellard  * This is used to ensure we don't load something for the wrong architecture.
12830ac07d4Sbellard  */
12930ac07d4Sbellard #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
13030ac07d4Sbellard 
13130ac07d4Sbellard /*
13230ac07d4Sbellard  * These are used to set parameters in the core dumps.
13330ac07d4Sbellard  */
13430ac07d4Sbellard #define ELF_CLASS	ELFCLASS32
13530ac07d4Sbellard #define ELF_DATA	ELFDATA2LSB
13630ac07d4Sbellard #define ELF_ARCH	EM_386
13730ac07d4Sbellard 
138e5fe0c52Spbrook static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
139e5fe0c52Spbrook {
140e5fe0c52Spbrook     regs->esp = infop->start_stack;
141e5fe0c52Spbrook     regs->eip = infop->entry;
142e5fe0c52Spbrook 
14330ac07d4Sbellard     /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
14430ac07d4Sbellard        starts %edx contains a pointer to a function which might be
14530ac07d4Sbellard        registered using `atexit'.  This provides a mean for the
14630ac07d4Sbellard        dynamic linker to call DT_FINI functions for shared libraries
14730ac07d4Sbellard        that have been loaded before the code runs.
14830ac07d4Sbellard 
14930ac07d4Sbellard        A value of 0 tells we have no such handler.  */
150e5fe0c52Spbrook     regs->edx = 0;
151b346ff46Sbellard }
15284409ddbSj_mayer #endif
153b346ff46Sbellard 
154b346ff46Sbellard #define USE_ELF_CORE_DUMP
155b346ff46Sbellard #define ELF_EXEC_PAGESIZE	4096
156b346ff46Sbellard 
157b346ff46Sbellard #endif
158b346ff46Sbellard 
159b346ff46Sbellard #ifdef TARGET_ARM
160b346ff46Sbellard 
161b346ff46Sbellard #define ELF_START_MMAP 0x80000000
162b346ff46Sbellard 
163b346ff46Sbellard #define elf_check_arch(x) ( (x) == EM_ARM )
164b346ff46Sbellard 
165b346ff46Sbellard #define ELF_CLASS	ELFCLASS32
166b346ff46Sbellard #ifdef TARGET_WORDS_BIGENDIAN
167b346ff46Sbellard #define ELF_DATA	ELFDATA2MSB
168b346ff46Sbellard #else
169b346ff46Sbellard #define ELF_DATA	ELFDATA2LSB
170b346ff46Sbellard #endif
171b346ff46Sbellard #define ELF_ARCH	EM_ARM
172b346ff46Sbellard 
173b346ff46Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
174b346ff46Sbellard {
175992f48a0Sblueswir1     abi_long stack = infop->start_stack;
176b346ff46Sbellard     memset(regs, 0, sizeof(*regs));
177b346ff46Sbellard     regs->ARM_cpsr = 0x10;
1780240ded8Spbrook     if (infop->entry & 1)
1790240ded8Spbrook       regs->ARM_cpsr |= CPSR_T;
1800240ded8Spbrook     regs->ARM_pc = infop->entry & 0xfffffffe;
181b346ff46Sbellard     regs->ARM_sp = infop->start_stack;
182*2f619698Sbellard     /* FIXME - what to for failure of get_user()? */
183*2f619698Sbellard     get_user_ual(regs->ARM_r2, stack + 8); /* envp */
184*2f619698Sbellard     get_user_ual(regs->ARM_r1, stack + 4); /* envp */
185a1516e92Sbellard     /* XXX: it seems that r0 is zeroed after ! */
186e5fe0c52Spbrook     regs->ARM_r0 = 0;
187e5fe0c52Spbrook     /* For uClinux PIC binaries.  */
188863cf0b7Sj_mayer     /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
189e5fe0c52Spbrook     regs->ARM_r10 = infop->start_data;
190b346ff46Sbellard }
191b346ff46Sbellard 
19230ac07d4Sbellard #define USE_ELF_CORE_DUMP
19330ac07d4Sbellard #define ELF_EXEC_PAGESIZE	4096
19430ac07d4Sbellard 
195afce2927Sbellard enum
196afce2927Sbellard {
197afce2927Sbellard   ARM_HWCAP_ARM_SWP       = 1 << 0,
198afce2927Sbellard   ARM_HWCAP_ARM_HALF      = 1 << 1,
199afce2927Sbellard   ARM_HWCAP_ARM_THUMB     = 1 << 2,
200afce2927Sbellard   ARM_HWCAP_ARM_26BIT     = 1 << 3,
201afce2927Sbellard   ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
202afce2927Sbellard   ARM_HWCAP_ARM_FPA       = 1 << 5,
203afce2927Sbellard   ARM_HWCAP_ARM_VFP       = 1 << 6,
204afce2927Sbellard   ARM_HWCAP_ARM_EDSP      = 1 << 7,
205afce2927Sbellard };
206afce2927Sbellard 
20715338fd7Sbellard #define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF              \
208afce2927Sbellard                     | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT     \
209afce2927Sbellard                     | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP)
210afce2927Sbellard 
21130ac07d4Sbellard #endif
21230ac07d4Sbellard 
213853d6f7aSbellard #ifdef TARGET_SPARC
214a315a145Sbellard #ifdef TARGET_SPARC64
215853d6f7aSbellard 
216853d6f7aSbellard #define ELF_START_MMAP 0x80000000
217853d6f7aSbellard 
218992f48a0Sblueswir1 #ifndef TARGET_ABI32
219cb33da57Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
220992f48a0Sblueswir1 #else
221992f48a0Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
222992f48a0Sblueswir1 #endif
223853d6f7aSbellard 
224a315a145Sbellard #define ELF_CLASS   ELFCLASS64
225a315a145Sbellard #define ELF_DATA    ELFDATA2MSB
2265ef54116Sbellard #define ELF_ARCH    EM_SPARCV9
2275ef54116Sbellard 
2285ef54116Sbellard #define STACK_BIAS		2047
229a315a145Sbellard 
230a315a145Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
231a315a145Sbellard {
232992f48a0Sblueswir1 #ifndef TARGET_ABI32
233a315a145Sbellard     regs->tstate = 0;
234992f48a0Sblueswir1 #endif
235a315a145Sbellard     regs->pc = infop->entry;
236a315a145Sbellard     regs->npc = regs->pc + 4;
237a315a145Sbellard     regs->y = 0;
238992f48a0Sblueswir1 #ifdef TARGET_ABI32
239992f48a0Sblueswir1     regs->u_regs[14] = infop->start_stack - 16 * 4;
240992f48a0Sblueswir1 #else
241cb33da57Sblueswir1     if (personality(infop->personality) == PER_LINUX32)
242cb33da57Sblueswir1         regs->u_regs[14] = infop->start_stack - 16 * 4;
243cb33da57Sblueswir1     else
2445ef54116Sbellard         regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
245992f48a0Sblueswir1 #endif
246a315a145Sbellard }
247a315a145Sbellard 
248a315a145Sbellard #else
249a315a145Sbellard #define ELF_START_MMAP 0x80000000
250a315a145Sbellard 
251a315a145Sbellard #define elf_check_arch(x) ( (x) == EM_SPARC )
252a315a145Sbellard 
253853d6f7aSbellard #define ELF_CLASS   ELFCLASS32
254853d6f7aSbellard #define ELF_DATA    ELFDATA2MSB
255853d6f7aSbellard #define ELF_ARCH    EM_SPARC
256853d6f7aSbellard 
257853d6f7aSbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
258853d6f7aSbellard {
259f5155289Sbellard     regs->psr = 0;
260f5155289Sbellard     regs->pc = infop->entry;
261f5155289Sbellard     regs->npc = regs->pc + 4;
262f5155289Sbellard     regs->y = 0;
263f5155289Sbellard     regs->u_regs[14] = infop->start_stack - 16 * 4;
264853d6f7aSbellard }
265853d6f7aSbellard 
266853d6f7aSbellard #endif
267a315a145Sbellard #endif
268853d6f7aSbellard 
26967867308Sbellard #ifdef TARGET_PPC
27067867308Sbellard 
27167867308Sbellard #define ELF_START_MMAP 0x80000000
27267867308Sbellard 
273e85e7c6eSj_mayer #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
27484409ddbSj_mayer 
27584409ddbSj_mayer #define elf_check_arch(x) ( (x) == EM_PPC64 )
27684409ddbSj_mayer 
27784409ddbSj_mayer #define ELF_CLASS	ELFCLASS64
27884409ddbSj_mayer 
27984409ddbSj_mayer #else
28084409ddbSj_mayer 
28167867308Sbellard #define elf_check_arch(x) ( (x) == EM_PPC )
28267867308Sbellard 
28367867308Sbellard #define ELF_CLASS	ELFCLASS32
28484409ddbSj_mayer 
28584409ddbSj_mayer #endif
28684409ddbSj_mayer 
28767867308Sbellard #ifdef TARGET_WORDS_BIGENDIAN
28867867308Sbellard #define ELF_DATA	ELFDATA2MSB
28967867308Sbellard #else
29067867308Sbellard #define ELF_DATA	ELFDATA2LSB
29167867308Sbellard #endif
29267867308Sbellard #define ELF_ARCH	EM_PPC
29367867308Sbellard 
294f5155289Sbellard /*
295f5155289Sbellard  * We need to put in some extra aux table entries to tell glibc what
296f5155289Sbellard  * the cache block size is, so it can use the dcbz instruction safely.
297f5155289Sbellard  */
298f5155289Sbellard #define AT_DCACHEBSIZE          19
299f5155289Sbellard #define AT_ICACHEBSIZE          20
300f5155289Sbellard #define AT_UCACHEBSIZE          21
301f5155289Sbellard /* A special ignored type value for PPC, for glibc compatibility.  */
302f5155289Sbellard #define AT_IGNOREPPC            22
303f5155289Sbellard /*
304f5155289Sbellard  * The requirements here are:
305f5155289Sbellard  * - keep the final alignment of sp (sp & 0xf)
306f5155289Sbellard  * - make sure the 32-bit value at the first 16 byte aligned position of
307f5155289Sbellard  *   AUXV is greater than 16 for glibc compatibility.
308f5155289Sbellard  *   AT_IGNOREPPC is used for that.
309f5155289Sbellard  * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
310f5155289Sbellard  *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
311f5155289Sbellard  */
3120bccf03dSbellard #define DLINFO_ARCH_ITEMS       5
313f5155289Sbellard #define ARCH_DLINFO                                                     \
314f5155289Sbellard do {                                                                    \
3150bccf03dSbellard         NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20);                              \
3160bccf03dSbellard         NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20);                              \
3170bccf03dSbellard         NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                                 \
318f5155289Sbellard         /*                                                              \
319f5155289Sbellard          * Now handle glibc compatibility.                              \
320f5155289Sbellard          */                                                             \
3210bccf03dSbellard 	NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);			\
3220bccf03dSbellard 	NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);			\
323f5155289Sbellard  } while (0)
324f5155289Sbellard 
32567867308Sbellard static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
32667867308Sbellard {
327992f48a0Sblueswir1     abi_ulong pos = infop->start_stack;
328992f48a0Sblueswir1     abi_ulong tmp;
329e85e7c6eSj_mayer #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
330992f48a0Sblueswir1     abi_ulong entry, toc;
33184409ddbSj_mayer #endif
332e5fe0c52Spbrook 
33367867308Sbellard     _regs->gpr[1] = infop->start_stack;
334e85e7c6eSj_mayer #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
33584409ddbSj_mayer     entry = ldq_raw(infop->entry) + infop->load_addr;
33684409ddbSj_mayer     toc = ldq_raw(infop->entry + 8) + infop->load_addr;
33784409ddbSj_mayer     _regs->gpr[2] = toc;
33884409ddbSj_mayer     infop->entry = entry;
33984409ddbSj_mayer #endif
34067867308Sbellard     _regs->nip = infop->entry;
341e5fe0c52Spbrook     /* Note that isn't exactly what regular kernel does
342e5fe0c52Spbrook      * but this is what the ABI wants and is needed to allow
343e5fe0c52Spbrook      * execution of PPC BSD programs.
344e5fe0c52Spbrook      */
345*2f619698Sbellard     /* FIXME - what to for failure of get_user()? */
346*2f619698Sbellard     get_user_ual(_regs->gpr[3], pos);
347992f48a0Sblueswir1     pos += sizeof(abi_ulong);
348e5fe0c52Spbrook     _regs->gpr[4] = pos;
349992f48a0Sblueswir1     for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong))
350e5fe0c52Spbrook         tmp = ldl(pos);
351e5fe0c52Spbrook     _regs->gpr[5] = pos;
35267867308Sbellard }
35367867308Sbellard 
35467867308Sbellard #define USE_ELF_CORE_DUMP
35567867308Sbellard #define ELF_EXEC_PAGESIZE	4096
35667867308Sbellard 
35767867308Sbellard #endif
35867867308Sbellard 
359048f6b4dSbellard #ifdef TARGET_MIPS
360048f6b4dSbellard 
361048f6b4dSbellard #define ELF_START_MMAP 0x80000000
362048f6b4dSbellard 
363048f6b4dSbellard #define elf_check_arch(x) ( (x) == EM_MIPS )
364048f6b4dSbellard 
365388bb21aSths #ifdef TARGET_MIPS64
366388bb21aSths #define ELF_CLASS   ELFCLASS64
367388bb21aSths #else
368048f6b4dSbellard #define ELF_CLASS   ELFCLASS32
369388bb21aSths #endif
370048f6b4dSbellard #ifdef TARGET_WORDS_BIGENDIAN
371048f6b4dSbellard #define ELF_DATA	ELFDATA2MSB
372048f6b4dSbellard #else
373048f6b4dSbellard #define ELF_DATA	ELFDATA2LSB
374048f6b4dSbellard #endif
375048f6b4dSbellard #define ELF_ARCH    EM_MIPS
376048f6b4dSbellard 
377048f6b4dSbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
378048f6b4dSbellard {
379623a930eSths     regs->cp0_status = 2 << CP0St_KSU;
380048f6b4dSbellard     regs->cp0_epc = infop->entry;
381048f6b4dSbellard     regs->regs[29] = infop->start_stack;
382048f6b4dSbellard }
383048f6b4dSbellard 
384388bb21aSths #define USE_ELF_CORE_DUMP
385388bb21aSths #define ELF_EXEC_PAGESIZE        4096
386388bb21aSths 
387048f6b4dSbellard #endif /* TARGET_MIPS */
388048f6b4dSbellard 
389fdf9b3e8Sbellard #ifdef TARGET_SH4
390fdf9b3e8Sbellard 
391fdf9b3e8Sbellard #define ELF_START_MMAP 0x80000000
392fdf9b3e8Sbellard 
393fdf9b3e8Sbellard #define elf_check_arch(x) ( (x) == EM_SH )
394fdf9b3e8Sbellard 
395fdf9b3e8Sbellard #define ELF_CLASS ELFCLASS32
396fdf9b3e8Sbellard #define ELF_DATA  ELFDATA2LSB
397fdf9b3e8Sbellard #define ELF_ARCH  EM_SH
398fdf9b3e8Sbellard 
399fdf9b3e8Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
400fdf9b3e8Sbellard {
401fdf9b3e8Sbellard   /* Check other registers XXXXX */
402fdf9b3e8Sbellard   regs->pc = infop->entry;
403072ae847Sths   regs->regs[15] = infop->start_stack;
404fdf9b3e8Sbellard }
405fdf9b3e8Sbellard 
406fdf9b3e8Sbellard #define USE_ELF_CORE_DUMP
407fdf9b3e8Sbellard #define ELF_EXEC_PAGESIZE        4096
408fdf9b3e8Sbellard 
409fdf9b3e8Sbellard #endif
410fdf9b3e8Sbellard 
41148733d19Sths #ifdef TARGET_CRIS
41248733d19Sths 
41348733d19Sths #define ELF_START_MMAP 0x80000000
41448733d19Sths 
41548733d19Sths #define elf_check_arch(x) ( (x) == EM_CRIS )
41648733d19Sths 
41748733d19Sths #define ELF_CLASS ELFCLASS32
41848733d19Sths #define ELF_DATA  ELFDATA2LSB
41948733d19Sths #define ELF_ARCH  EM_CRIS
42048733d19Sths 
42148733d19Sths static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
42248733d19Sths {
42348733d19Sths   regs->erp = infop->entry;
42448733d19Sths }
42548733d19Sths 
42648733d19Sths #define USE_ELF_CORE_DUMP
42748733d19Sths #define ELF_EXEC_PAGESIZE        8192
42848733d19Sths 
42948733d19Sths #endif
43048733d19Sths 
431e6e5906bSpbrook #ifdef TARGET_M68K
432e6e5906bSpbrook 
433e6e5906bSpbrook #define ELF_START_MMAP 0x80000000
434e6e5906bSpbrook 
435e6e5906bSpbrook #define elf_check_arch(x) ( (x) == EM_68K )
436e6e5906bSpbrook 
437e6e5906bSpbrook #define ELF_CLASS	ELFCLASS32
438e6e5906bSpbrook #define ELF_DATA	ELFDATA2MSB
439e6e5906bSpbrook #define ELF_ARCH	EM_68K
440e6e5906bSpbrook 
441e6e5906bSpbrook /* ??? Does this need to do anything?
442e6e5906bSpbrook #define ELF_PLAT_INIT(_r) */
443e6e5906bSpbrook 
444e6e5906bSpbrook static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
445e6e5906bSpbrook {
446e6e5906bSpbrook     regs->usp = infop->start_stack;
447e6e5906bSpbrook     regs->sr = 0;
448e6e5906bSpbrook     regs->pc = infop->entry;
449e6e5906bSpbrook }
450e6e5906bSpbrook 
451e6e5906bSpbrook #define USE_ELF_CORE_DUMP
452e6e5906bSpbrook #define ELF_EXEC_PAGESIZE	8192
453e6e5906bSpbrook 
454e6e5906bSpbrook #endif
455e6e5906bSpbrook 
4567a3148a9Sj_mayer #ifdef TARGET_ALPHA
4577a3148a9Sj_mayer 
4587a3148a9Sj_mayer #define ELF_START_MMAP (0x30000000000ULL)
4597a3148a9Sj_mayer 
4607a3148a9Sj_mayer #define elf_check_arch(x) ( (x) == ELF_ARCH )
4617a3148a9Sj_mayer 
4627a3148a9Sj_mayer #define ELF_CLASS      ELFCLASS64
4637a3148a9Sj_mayer #define ELF_DATA       ELFDATA2MSB
4647a3148a9Sj_mayer #define ELF_ARCH       EM_ALPHA
4657a3148a9Sj_mayer 
4667a3148a9Sj_mayer static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
4677a3148a9Sj_mayer {
4687a3148a9Sj_mayer     regs->pc = infop->entry;
4697a3148a9Sj_mayer     regs->ps = 8;
4707a3148a9Sj_mayer     regs->usp = infop->start_stack;
4717a3148a9Sj_mayer     regs->unique = infop->start_data; /* ? */
4727a3148a9Sj_mayer     printf("Set unique value to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n",
4737a3148a9Sj_mayer            regs->unique, infop->start_data);
4747a3148a9Sj_mayer }
4757a3148a9Sj_mayer 
4767a3148a9Sj_mayer #define USE_ELF_CORE_DUMP
4777a3148a9Sj_mayer #define ELF_EXEC_PAGESIZE        8192
4787a3148a9Sj_mayer 
4797a3148a9Sj_mayer #endif /* TARGET_ALPHA */
4807a3148a9Sj_mayer 
48115338fd7Sbellard #ifndef ELF_PLATFORM
48215338fd7Sbellard #define ELF_PLATFORM (NULL)
48315338fd7Sbellard #endif
48415338fd7Sbellard 
48515338fd7Sbellard #ifndef ELF_HWCAP
48615338fd7Sbellard #define ELF_HWCAP 0
48715338fd7Sbellard #endif
48815338fd7Sbellard 
489992f48a0Sblueswir1 #ifdef TARGET_ABI32
490cb33da57Sblueswir1 #undef ELF_CLASS
491992f48a0Sblueswir1 #define ELF_CLASS ELFCLASS32
492cb33da57Sblueswir1 #undef bswaptls
493cb33da57Sblueswir1 #define bswaptls(ptr) bswap32s(ptr)
494cb33da57Sblueswir1 #endif
495cb33da57Sblueswir1 
49631e31b8aSbellard #include "elf.h"
49709bfb054Sbellard 
49809bfb054Sbellard struct exec
49909bfb054Sbellard {
50009bfb054Sbellard   unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
50109bfb054Sbellard   unsigned int a_text;   /* length of text, in bytes */
50209bfb054Sbellard   unsigned int a_data;   /* length of data, in bytes */
50309bfb054Sbellard   unsigned int a_bss;    /* length of uninitialized data area, in bytes */
50409bfb054Sbellard   unsigned int a_syms;   /* length of symbol table data in file, in bytes */
50509bfb054Sbellard   unsigned int a_entry;  /* start address */
50609bfb054Sbellard   unsigned int a_trsize; /* length of relocation info for text, in bytes */
50709bfb054Sbellard   unsigned int a_drsize; /* length of relocation info for data, in bytes */
50809bfb054Sbellard };
50909bfb054Sbellard 
51009bfb054Sbellard 
51109bfb054Sbellard #define N_MAGIC(exec) ((exec).a_info & 0xffff)
51209bfb054Sbellard #define OMAGIC 0407
51309bfb054Sbellard #define NMAGIC 0410
51409bfb054Sbellard #define ZMAGIC 0413
51509bfb054Sbellard #define QMAGIC 0314
51609bfb054Sbellard 
51709bfb054Sbellard /* max code+data+bss space allocated to elf interpreter */
51809bfb054Sbellard #define INTERP_MAP_SIZE (32 * 1024 * 1024)
51909bfb054Sbellard 
52009bfb054Sbellard /* max code+data+bss+brk space allocated to ET_DYN executables */
52109bfb054Sbellard #define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
52209bfb054Sbellard 
52331e31b8aSbellard /* Necessary parameters */
52454936004Sbellard #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
52554936004Sbellard #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
52654936004Sbellard #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
52731e31b8aSbellard 
52831e31b8aSbellard #define INTERPRETER_NONE 0
52931e31b8aSbellard #define INTERPRETER_AOUT 1
53031e31b8aSbellard #define INTERPRETER_ELF 2
53131e31b8aSbellard 
53215338fd7Sbellard #define DLINFO_ITEMS 12
53331e31b8aSbellard 
53409bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
53509bfb054Sbellard {
53609bfb054Sbellard 	memcpy(to, from, n);
53709bfb054Sbellard }
53809bfb054Sbellard 
53931e31b8aSbellard extern unsigned long x86_stack_size;
54031e31b8aSbellard 
54131e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd);
54231e31b8aSbellard 
54331e31b8aSbellard #ifdef BSWAP_NEEDED
54492a31b1fSbellard static void bswap_ehdr(struct elfhdr *ehdr)
54531e31b8aSbellard {
54631e31b8aSbellard     bswap16s(&ehdr->e_type);			/* Object file type */
54731e31b8aSbellard     bswap16s(&ehdr->e_machine);		/* Architecture */
54831e31b8aSbellard     bswap32s(&ehdr->e_version);		/* Object file version */
54992a31b1fSbellard     bswaptls(&ehdr->e_entry);		/* Entry point virtual address */
55092a31b1fSbellard     bswaptls(&ehdr->e_phoff);		/* Program header table file offset */
55192a31b1fSbellard     bswaptls(&ehdr->e_shoff);		/* Section header table file offset */
55231e31b8aSbellard     bswap32s(&ehdr->e_flags);		/* Processor-specific flags */
55331e31b8aSbellard     bswap16s(&ehdr->e_ehsize);		/* ELF header size in bytes */
55431e31b8aSbellard     bswap16s(&ehdr->e_phentsize);		/* Program header table entry size */
55531e31b8aSbellard     bswap16s(&ehdr->e_phnum);		/* Program header table entry count */
55631e31b8aSbellard     bswap16s(&ehdr->e_shentsize);		/* Section header table entry size */
55731e31b8aSbellard     bswap16s(&ehdr->e_shnum);		/* Section header table entry count */
55831e31b8aSbellard     bswap16s(&ehdr->e_shstrndx);		/* Section header string table index */
55931e31b8aSbellard }
56031e31b8aSbellard 
56192a31b1fSbellard static void bswap_phdr(struct elf_phdr *phdr)
56231e31b8aSbellard {
56331e31b8aSbellard     bswap32s(&phdr->p_type);			/* Segment type */
56492a31b1fSbellard     bswaptls(&phdr->p_offset);		/* Segment file offset */
56592a31b1fSbellard     bswaptls(&phdr->p_vaddr);		/* Segment virtual address */
56692a31b1fSbellard     bswaptls(&phdr->p_paddr);		/* Segment physical address */
56792a31b1fSbellard     bswaptls(&phdr->p_filesz);		/* Segment size in file */
56892a31b1fSbellard     bswaptls(&phdr->p_memsz);		/* Segment size in memory */
56931e31b8aSbellard     bswap32s(&phdr->p_flags);		/* Segment flags */
57092a31b1fSbellard     bswaptls(&phdr->p_align);		/* Segment alignment */
57131e31b8aSbellard }
572689f936fSbellard 
57392a31b1fSbellard static void bswap_shdr(struct elf_shdr *shdr)
574689f936fSbellard {
575689f936fSbellard     bswap32s(&shdr->sh_name);
576689f936fSbellard     bswap32s(&shdr->sh_type);
57792a31b1fSbellard     bswaptls(&shdr->sh_flags);
57892a31b1fSbellard     bswaptls(&shdr->sh_addr);
57992a31b1fSbellard     bswaptls(&shdr->sh_offset);
58092a31b1fSbellard     bswaptls(&shdr->sh_size);
581689f936fSbellard     bswap32s(&shdr->sh_link);
582689f936fSbellard     bswap32s(&shdr->sh_info);
58392a31b1fSbellard     bswaptls(&shdr->sh_addralign);
58492a31b1fSbellard     bswaptls(&shdr->sh_entsize);
585689f936fSbellard }
586689f936fSbellard 
5877a3148a9Sj_mayer static void bswap_sym(struct elf_sym *sym)
588689f936fSbellard {
589689f936fSbellard     bswap32s(&sym->st_name);
5907a3148a9Sj_mayer     bswaptls(&sym->st_value);
5917a3148a9Sj_mayer     bswaptls(&sym->st_size);
592689f936fSbellard     bswap16s(&sym->st_shndx);
593689f936fSbellard }
59431e31b8aSbellard #endif
59531e31b8aSbellard 
59631e31b8aSbellard /*
597e5fe0c52Spbrook  * 'copy_elf_strings()' copies argument/envelope strings from user
59831e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
59931e31b8aSbellard  * to be put directly into the top of new user memory.
60031e31b8aSbellard  *
60131e31b8aSbellard  */
602992f48a0Sblueswir1 static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
603992f48a0Sblueswir1                                   abi_ulong p)
60431e31b8aSbellard {
60531e31b8aSbellard     char *tmp, *tmp1, *pag = NULL;
60631e31b8aSbellard     int len, offset = 0;
60731e31b8aSbellard 
60831e31b8aSbellard     if (!p) {
60931e31b8aSbellard 	return 0;       /* bullet-proofing */
61031e31b8aSbellard     }
61131e31b8aSbellard     while (argc-- > 0) {
612edf779ffSbellard         tmp = argv[argc];
613edf779ffSbellard         if (!tmp) {
61431e31b8aSbellard 	    fprintf(stderr, "VFS: argc is wrong");
61531e31b8aSbellard 	    exit(-1);
61631e31b8aSbellard 	}
617edf779ffSbellard         tmp1 = tmp;
618edf779ffSbellard 	while (*tmp++);
61931e31b8aSbellard 	len = tmp - tmp1;
62031e31b8aSbellard 	if (p < len) {  /* this shouldn't happen - 128kB */
62131e31b8aSbellard 		return 0;
62231e31b8aSbellard 	}
62331e31b8aSbellard 	while (len) {
62431e31b8aSbellard 	    --p; --tmp; --len;
62531e31b8aSbellard 	    if (--offset < 0) {
62654936004Sbellard 		offset = p % TARGET_PAGE_SIZE;
62744a91caeSbellard                 pag = (char *)page[p/TARGET_PAGE_SIZE];
62844a91caeSbellard                 if (!pag) {
62953a5960aSpbrook                     pag = (char *)malloc(TARGET_PAGE_SIZE);
6304118a970Sj_mayer                     memset(pag, 0, TARGET_PAGE_SIZE);
63153a5960aSpbrook                     page[p/TARGET_PAGE_SIZE] = pag;
63244a91caeSbellard                     if (!pag)
63331e31b8aSbellard                         return 0;
63431e31b8aSbellard 		}
63531e31b8aSbellard 	    }
63631e31b8aSbellard 	    if (len == 0 || offset == 0) {
637edf779ffSbellard 	        *(pag + offset) = *tmp;
63831e31b8aSbellard 	    }
63931e31b8aSbellard 	    else {
64031e31b8aSbellard 	      int bytes_to_copy = (len > offset) ? offset : len;
64131e31b8aSbellard 	      tmp -= bytes_to_copy;
64231e31b8aSbellard 	      p -= bytes_to_copy;
64331e31b8aSbellard 	      offset -= bytes_to_copy;
64431e31b8aSbellard 	      len -= bytes_to_copy;
64531e31b8aSbellard 	      memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
64631e31b8aSbellard 	    }
64731e31b8aSbellard 	}
64831e31b8aSbellard     }
64931e31b8aSbellard     return p;
65031e31b8aSbellard }
65131e31b8aSbellard 
652992f48a0Sblueswir1 static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
65331e31b8aSbellard                                  struct image_info *info)
65431e31b8aSbellard {
655992f48a0Sblueswir1     abi_ulong stack_base, size, error;
65631e31b8aSbellard     int i;
65731e31b8aSbellard 
65831e31b8aSbellard     /* Create enough stack to hold everything.  If we don't use
65931e31b8aSbellard      * it for args, we'll use it for something else...
66031e31b8aSbellard      */
66109bfb054Sbellard     size = x86_stack_size;
66254936004Sbellard     if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
66354936004Sbellard         size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
66454936004Sbellard     error = target_mmap(0,
66583fb7adfSbellard                         size + qemu_host_page_size,
66631e31b8aSbellard                         PROT_READ | PROT_WRITE,
66709bfb054Sbellard                         MAP_PRIVATE | MAP_ANONYMOUS,
66809bfb054Sbellard                         -1, 0);
66909bfb054Sbellard     if (error == -1) {
67031e31b8aSbellard         perror("stk mmap");
67131e31b8aSbellard         exit(-1);
67231e31b8aSbellard     }
67309bfb054Sbellard     /* we reserve one extra page at the top of the stack as guard */
67483fb7adfSbellard     target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
67531e31b8aSbellard 
67654936004Sbellard     stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
67709bfb054Sbellard     p += stack_base;
67809bfb054Sbellard 
67931e31b8aSbellard     for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
68031e31b8aSbellard 	if (bprm->page[i]) {
68131e31b8aSbellard 	    info->rss++;
682579a97f7Sbellard             /* FIXME - check return value of memcpy_to_target() for failure */
68353a5960aSpbrook 	    memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
68453a5960aSpbrook 	    free(bprm->page[i]);
68531e31b8aSbellard 	}
68654936004Sbellard         stack_base += TARGET_PAGE_SIZE;
68731e31b8aSbellard     }
68831e31b8aSbellard     return p;
68931e31b8aSbellard }
69031e31b8aSbellard 
691992f48a0Sblueswir1 static void set_brk(abi_ulong start, abi_ulong end)
69231e31b8aSbellard {
69331e31b8aSbellard 	/* page-align the start and end addresses... */
69454936004Sbellard         start = HOST_PAGE_ALIGN(start);
69554936004Sbellard         end = HOST_PAGE_ALIGN(end);
69631e31b8aSbellard         if (end <= start)
69731e31b8aSbellard                 return;
69854936004Sbellard         if(target_mmap(start, end - start,
69931e31b8aSbellard                        PROT_READ | PROT_WRITE | PROT_EXEC,
70031e31b8aSbellard                        MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
70131e31b8aSbellard 	    perror("cannot mmap brk");
70231e31b8aSbellard 	    exit(-1);
70331e31b8aSbellard 	}
70431e31b8aSbellard }
70531e31b8aSbellard 
70631e31b8aSbellard 
707853d6f7aSbellard /* We need to explicitly zero any fractional pages after the data
708853d6f7aSbellard    section (i.e. bss).  This would contain the junk from the file that
709853d6f7aSbellard    should not be in memory. */
710992f48a0Sblueswir1 static void padzero(abi_ulong elf_bss, abi_ulong last_bss)
71131e31b8aSbellard {
712992f48a0Sblueswir1         abi_ulong nbyte;
71331e31b8aSbellard 
714768a4a36Sths 	if (elf_bss >= last_bss)
715768a4a36Sths 		return;
716768a4a36Sths 
717853d6f7aSbellard         /* XXX: this is really a hack : if the real host page size is
718853d6f7aSbellard            smaller than the target page size, some pages after the end
719853d6f7aSbellard            of the file may not be mapped. A better fix would be to
720853d6f7aSbellard            patch target_mmap(), but it is more complicated as the file
721853d6f7aSbellard            size must be known */
72283fb7adfSbellard         if (qemu_real_host_page_size < qemu_host_page_size) {
723992f48a0Sblueswir1             abi_ulong end_addr, end_addr1;
72483fb7adfSbellard             end_addr1 = (elf_bss + qemu_real_host_page_size - 1) &
72583fb7adfSbellard                 ~(qemu_real_host_page_size - 1);
726853d6f7aSbellard             end_addr = HOST_PAGE_ALIGN(elf_bss);
727853d6f7aSbellard             if (end_addr1 < end_addr) {
728863cf0b7Sj_mayer                 mmap((void *)g2h(end_addr1), end_addr - end_addr1,
729853d6f7aSbellard                      PROT_READ|PROT_WRITE|PROT_EXEC,
730853d6f7aSbellard                      MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
731853d6f7aSbellard             }
732853d6f7aSbellard         }
733853d6f7aSbellard 
73483fb7adfSbellard         nbyte = elf_bss & (qemu_host_page_size-1);
73531e31b8aSbellard         if (nbyte) {
73683fb7adfSbellard 	    nbyte = qemu_host_page_size - nbyte;
73731e31b8aSbellard 	    do {
738*2f619698Sbellard                 /* FIXME - what to do if put_user() fails? */
739*2f619698Sbellard 		put_user_u8(0, elf_bss);
74053a5960aSpbrook                 elf_bss++;
74131e31b8aSbellard 	    } while (--nbyte);
74231e31b8aSbellard         }
74331e31b8aSbellard }
74431e31b8aSbellard 
74553a5960aSpbrook 
746992f48a0Sblueswir1 static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
74731e31b8aSbellard                                    struct elfhdr * exec,
748992f48a0Sblueswir1                                    abi_ulong load_addr,
749992f48a0Sblueswir1                                    abi_ulong load_bias,
750992f48a0Sblueswir1                                    abi_ulong interp_load_addr, int ibcs,
75131e31b8aSbellard                                    struct image_info *info)
75231e31b8aSbellard {
753992f48a0Sblueswir1         abi_ulong sp;
75453a5960aSpbrook         int size;
755992f48a0Sblueswir1         abi_ulong u_platform;
75615338fd7Sbellard         const char *k_platform;
757863cf0b7Sj_mayer         const int n = sizeof(elf_addr_t);
75831e31b8aSbellard 
75953a5960aSpbrook         sp = p;
76053a5960aSpbrook         u_platform = 0;
76115338fd7Sbellard         k_platform = ELF_PLATFORM;
76215338fd7Sbellard         if (k_platform) {
76315338fd7Sbellard             size_t len = strlen(k_platform) + 1;
76453a5960aSpbrook             sp -= (len + n - 1) & ~(n - 1);
76553a5960aSpbrook             u_platform = sp;
766579a97f7Sbellard             /* FIXME - check return value of memcpy_to_target() for failure */
76753a5960aSpbrook             memcpy_to_target(sp, k_platform, len);
76815338fd7Sbellard         }
76953a5960aSpbrook 	/*
77053a5960aSpbrook 	 * Force 16 byte _final_ alignment here for generality.
77153a5960aSpbrook 	 */
772992f48a0Sblueswir1         sp = sp &~ (abi_ulong)15;
77353a5960aSpbrook         size = (DLINFO_ITEMS + 1) * 2;
77415338fd7Sbellard         if (k_platform)
77553a5960aSpbrook           size += 2;
776f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS
77753a5960aSpbrook 	size += DLINFO_ARCH_ITEMS * 2;
778f5155289Sbellard #endif
77953a5960aSpbrook         size += envc + argc + 2;
78053a5960aSpbrook 	size += (!ibcs ? 3 : 1);	/* argc itself */
78153a5960aSpbrook         size *= n;
78253a5960aSpbrook         if (size & 15)
78353a5960aSpbrook             sp -= 16 - (size & 15);
784f5155289Sbellard 
785863cf0b7Sj_mayer         /* This is correct because Linux defines
786863cf0b7Sj_mayer          * elf_addr_t as Elf32_Off / Elf64_Off
787863cf0b7Sj_mayer          */
78853a5960aSpbrook #define NEW_AUX_ENT(id, val) do {		\
789*2f619698Sbellard             sp -= n; put_user_ual(val, sp);	\
790*2f619698Sbellard             sp -= n; put_user_ual(id, sp);	\
79153a5960aSpbrook           } while(0)
792*2f619698Sbellard 
7930bccf03dSbellard         NEW_AUX_ENT (AT_NULL, 0);
794f5155289Sbellard 
7950bccf03dSbellard         /* There must be exactly DLINFO_ITEMS entries here.  */
796992f48a0Sblueswir1         NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
797992f48a0Sblueswir1         NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
798992f48a0Sblueswir1         NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
799992f48a0Sblueswir1         NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
800992f48a0Sblueswir1         NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
801992f48a0Sblueswir1         NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
8020bccf03dSbellard         NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
803992f48a0Sblueswir1         NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
804992f48a0Sblueswir1         NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
805992f48a0Sblueswir1         NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
806992f48a0Sblueswir1         NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
807992f48a0Sblueswir1         NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
80815338fd7Sbellard         if (k_platform)
80953a5960aSpbrook             NEW_AUX_ENT(AT_PLATFORM, u_platform);
810f5155289Sbellard #ifdef ARCH_DLINFO
811f5155289Sbellard 	/*
812f5155289Sbellard 	 * ARCH_DLINFO must come last so platform specific code can enforce
813f5155289Sbellard 	 * special alignment requirements on the AUXV if necessary (eg. PPC).
814f5155289Sbellard 	 */
815f5155289Sbellard         ARCH_DLINFO;
816f5155289Sbellard #endif
817f5155289Sbellard #undef NEW_AUX_ENT
818f5155289Sbellard 
819e5fe0c52Spbrook         sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
82031e31b8aSbellard         return sp;
82131e31b8aSbellard }
82231e31b8aSbellard 
82331e31b8aSbellard 
824992f48a0Sblueswir1 static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
82531e31b8aSbellard                                  int interpreter_fd,
826992f48a0Sblueswir1                                  abi_ulong *interp_load_addr)
82731e31b8aSbellard {
82831e31b8aSbellard 	struct elf_phdr *elf_phdata  =  NULL;
82931e31b8aSbellard 	struct elf_phdr *eppnt;
830992f48a0Sblueswir1 	abi_ulong load_addr = 0;
83131e31b8aSbellard 	int load_addr_set = 0;
83231e31b8aSbellard 	int retval;
833992f48a0Sblueswir1 	abi_ulong last_bss, elf_bss;
834992f48a0Sblueswir1 	abi_ulong error;
83531e31b8aSbellard 	int i;
83631e31b8aSbellard 
83731e31b8aSbellard 	elf_bss = 0;
83831e31b8aSbellard 	last_bss = 0;
83931e31b8aSbellard 	error = 0;
84031e31b8aSbellard 
841644c433cSbellard #ifdef BSWAP_NEEDED
842644c433cSbellard         bswap_ehdr(interp_elf_ex);
843644c433cSbellard #endif
84431e31b8aSbellard 	/* First of all, some simple consistency checks */
84531e31b8aSbellard 	if ((interp_elf_ex->e_type != ET_EXEC &&
84631e31b8aSbellard              interp_elf_ex->e_type != ET_DYN) ||
84731e31b8aSbellard 	   !elf_check_arch(interp_elf_ex->e_machine)) {
848992f48a0Sblueswir1 		return ~((abi_ulong)0UL);
84931e31b8aSbellard 	}
85031e31b8aSbellard 
851644c433cSbellard 
85231e31b8aSbellard 	/* Now read in all of the header information */
85331e31b8aSbellard 
85454936004Sbellard 	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
855992f48a0Sblueswir1 	    return ~(abi_ulong)0UL;
85631e31b8aSbellard 
85731e31b8aSbellard 	elf_phdata =  (struct elf_phdr *)
85831e31b8aSbellard 		malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
85931e31b8aSbellard 
86031e31b8aSbellard 	if (!elf_phdata)
861992f48a0Sblueswir1 	  return ~((abi_ulong)0UL);
86231e31b8aSbellard 
86331e31b8aSbellard 	/*
86431e31b8aSbellard 	 * If the size of this structure has changed, then punt, since
86531e31b8aSbellard 	 * we will be doing the wrong thing.
86631e31b8aSbellard 	 */
86709bfb054Sbellard 	if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
86831e31b8aSbellard 	    free(elf_phdata);
869992f48a0Sblueswir1 	    return ~((abi_ulong)0UL);
87031e31b8aSbellard         }
87131e31b8aSbellard 
87231e31b8aSbellard 	retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
87331e31b8aSbellard 	if(retval >= 0) {
87431e31b8aSbellard 	    retval = read(interpreter_fd,
87531e31b8aSbellard 			   (char *) elf_phdata,
87631e31b8aSbellard 			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
87731e31b8aSbellard 	}
87831e31b8aSbellard 	if (retval < 0) {
87931e31b8aSbellard 		perror("load_elf_interp");
88031e31b8aSbellard 		exit(-1);
88131e31b8aSbellard 		free (elf_phdata);
88231e31b8aSbellard 		return retval;
88331e31b8aSbellard  	}
88431e31b8aSbellard #ifdef BSWAP_NEEDED
88531e31b8aSbellard 	eppnt = elf_phdata;
88631e31b8aSbellard 	for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
88731e31b8aSbellard             bswap_phdr(eppnt);
88831e31b8aSbellard         }
88931e31b8aSbellard #endif
89009bfb054Sbellard 
89109bfb054Sbellard         if (interp_elf_ex->e_type == ET_DYN) {
892e91c8a77Sths             /* in order to avoid hardcoding the interpreter load
89309bfb054Sbellard                address in qemu, we allocate a big enough memory zone */
89454936004Sbellard             error = target_mmap(0, INTERP_MAP_SIZE,
89509bfb054Sbellard                                 PROT_NONE, MAP_PRIVATE | MAP_ANON,
89609bfb054Sbellard                                 -1, 0);
89709bfb054Sbellard             if (error == -1) {
89809bfb054Sbellard                 perror("mmap");
89909bfb054Sbellard                 exit(-1);
90009bfb054Sbellard             }
90109bfb054Sbellard             load_addr = error;
90209bfb054Sbellard             load_addr_set = 1;
90309bfb054Sbellard         }
90409bfb054Sbellard 
90531e31b8aSbellard 	eppnt = elf_phdata;
90631e31b8aSbellard 	for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
90731e31b8aSbellard 	  if (eppnt->p_type == PT_LOAD) {
90831e31b8aSbellard 	    int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
90931e31b8aSbellard 	    int elf_prot = 0;
910992f48a0Sblueswir1 	    abi_ulong vaddr = 0;
911992f48a0Sblueswir1 	    abi_ulong k;
91231e31b8aSbellard 
91331e31b8aSbellard 	    if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
91431e31b8aSbellard 	    if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
91531e31b8aSbellard 	    if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
91631e31b8aSbellard 	    if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
91731e31b8aSbellard 	    	elf_type |= MAP_FIXED;
91831e31b8aSbellard 	    	vaddr = eppnt->p_vaddr;
91931e31b8aSbellard 	    }
92054936004Sbellard 	    error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
92154936004Sbellard 		 eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
92231e31b8aSbellard 		 elf_prot,
92331e31b8aSbellard 		 elf_type,
92431e31b8aSbellard 		 interpreter_fd,
92554936004Sbellard 		 eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
92631e31b8aSbellard 
927e89f07d3Spbrook 	    if (error == -1) {
92831e31b8aSbellard 	      /* Real error */
92931e31b8aSbellard 	      close(interpreter_fd);
93031e31b8aSbellard 	      free(elf_phdata);
931992f48a0Sblueswir1 	      return ~((abi_ulong)0UL);
93231e31b8aSbellard 	    }
93331e31b8aSbellard 
93431e31b8aSbellard 	    if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
93531e31b8aSbellard 	      load_addr = error;
93631e31b8aSbellard 	      load_addr_set = 1;
93731e31b8aSbellard 	    }
93831e31b8aSbellard 
93931e31b8aSbellard 	    /*
94031e31b8aSbellard 	     * Find the end of the file  mapping for this phdr, and keep
94131e31b8aSbellard 	     * track of the largest address we see for this.
94231e31b8aSbellard 	     */
94331e31b8aSbellard 	    k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
94431e31b8aSbellard 	    if (k > elf_bss) elf_bss = k;
94531e31b8aSbellard 
94631e31b8aSbellard 	    /*
94731e31b8aSbellard 	     * Do the same thing for the memory mapping - between
94831e31b8aSbellard 	     * elf_bss and last_bss is the bss section.
94931e31b8aSbellard 	     */
95031e31b8aSbellard 	    k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
95131e31b8aSbellard 	    if (k > last_bss) last_bss = k;
95231e31b8aSbellard 	  }
95331e31b8aSbellard 
95431e31b8aSbellard 	/* Now use mmap to map the library into memory. */
95531e31b8aSbellard 
95631e31b8aSbellard 	close(interpreter_fd);
95731e31b8aSbellard 
95831e31b8aSbellard 	/*
95931e31b8aSbellard 	 * Now fill out the bss section.  First pad the last page up
96031e31b8aSbellard 	 * to the page boundary, and then perform a mmap to make sure
96131e31b8aSbellard 	 * that there are zeromapped pages up to and including the last
96231e31b8aSbellard 	 * bss page.
96331e31b8aSbellard 	 */
964768a4a36Sths 	padzero(elf_bss, last_bss);
96583fb7adfSbellard 	elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */
96631e31b8aSbellard 
96731e31b8aSbellard 	/* Map the last of the bss segment */
96831e31b8aSbellard 	if (last_bss > elf_bss) {
96954936004Sbellard             target_mmap(elf_bss, last_bss-elf_bss,
97031e31b8aSbellard                         PROT_READ|PROT_WRITE|PROT_EXEC,
97131e31b8aSbellard                         MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
97231e31b8aSbellard 	}
97331e31b8aSbellard 	free(elf_phdata);
97431e31b8aSbellard 
97531e31b8aSbellard 	*interp_load_addr = load_addr;
976992f48a0Sblueswir1 	return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
97731e31b8aSbellard }
97831e31b8aSbellard 
979689f936fSbellard /* Best attempt to load symbols from this ELF object. */
980689f936fSbellard static void load_symbols(struct elfhdr *hdr, int fd)
981689f936fSbellard {
982689f936fSbellard     unsigned int i;
983689f936fSbellard     struct elf_shdr sechdr, symtab, strtab;
984689f936fSbellard     char *strings;
985e80cfcfcSbellard     struct syminfo *s;
9860774bed1Sblueswir1 #if (ELF_CLASS == ELFCLASS64)
9870774bed1Sblueswir1     // Disas uses 32 bit symbols
9880774bed1Sblueswir1     struct elf32_sym *syms32 = NULL;
9890774bed1Sblueswir1     struct elf_sym *sym;
9900774bed1Sblueswir1 #endif
99131e31b8aSbellard 
992689f936fSbellard     lseek(fd, hdr->e_shoff, SEEK_SET);
993689f936fSbellard     for (i = 0; i < hdr->e_shnum; i++) {
994689f936fSbellard 	if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
995689f936fSbellard 	    return;
996689f936fSbellard #ifdef BSWAP_NEEDED
997689f936fSbellard 	bswap_shdr(&sechdr);
998689f936fSbellard #endif
999689f936fSbellard 	if (sechdr.sh_type == SHT_SYMTAB) {
1000689f936fSbellard 	    symtab = sechdr;
1001689f936fSbellard 	    lseek(fd, hdr->e_shoff
1002689f936fSbellard 		  + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
1003689f936fSbellard 	    if (read(fd, &strtab, sizeof(strtab))
1004689f936fSbellard 		!= sizeof(strtab))
1005689f936fSbellard 		return;
1006689f936fSbellard #ifdef BSWAP_NEEDED
1007689f936fSbellard 	    bswap_shdr(&strtab);
1008689f936fSbellard #endif
1009689f936fSbellard 	    goto found;
1010689f936fSbellard 	}
1011689f936fSbellard     }
1012689f936fSbellard     return; /* Shouldn't happen... */
1013689f936fSbellard 
1014689f936fSbellard  found:
1015689f936fSbellard     /* Now know where the strtab and symtab are.  Snarf them. */
1016e80cfcfcSbellard     s = malloc(sizeof(*s));
1017e80cfcfcSbellard     s->disas_symtab = malloc(symtab.sh_size);
10180774bed1Sblueswir1 #if (ELF_CLASS == ELFCLASS64)
10190774bed1Sblueswir1     syms32 = malloc(symtab.sh_size / sizeof(struct elf_sym)
10200774bed1Sblueswir1                     * sizeof(struct elf32_sym));
10210774bed1Sblueswir1 #endif
1022e80cfcfcSbellard     s->disas_strtab = strings = malloc(strtab.sh_size);
1023e80cfcfcSbellard     if (!s->disas_symtab || !s->disas_strtab)
1024689f936fSbellard 	return;
1025689f936fSbellard 
1026689f936fSbellard     lseek(fd, symtab.sh_offset, SEEK_SET);
1027e80cfcfcSbellard     if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size)
1028689f936fSbellard 	return;
1029689f936fSbellard 
10300774bed1Sblueswir1     for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) {
1031689f936fSbellard #ifdef BSWAP_NEEDED
1032e80cfcfcSbellard 	bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i);
1033689f936fSbellard #endif
10340774bed1Sblueswir1 #if (ELF_CLASS == ELFCLASS64)
10350774bed1Sblueswir1         sym = s->disas_symtab + sizeof(struct elf_sym)*i;
10360774bed1Sblueswir1         syms32[i].st_name = sym->st_name;
10370774bed1Sblueswir1         syms32[i].st_info = sym->st_info;
10380774bed1Sblueswir1         syms32[i].st_other = sym->st_other;
10390774bed1Sblueswir1         syms32[i].st_shndx = sym->st_shndx;
10400774bed1Sblueswir1         syms32[i].st_value = sym->st_value & 0xffffffff;
10410774bed1Sblueswir1         syms32[i].st_size = sym->st_size & 0xffffffff;
10420774bed1Sblueswir1 #endif
10430774bed1Sblueswir1     }
1044689f936fSbellard 
10450774bed1Sblueswir1 #if (ELF_CLASS == ELFCLASS64)
10460774bed1Sblueswir1     free(s->disas_symtab);
10470774bed1Sblueswir1     s->disas_symtab = syms32;
10480774bed1Sblueswir1 #endif
1049689f936fSbellard     lseek(fd, strtab.sh_offset, SEEK_SET);
1050689f936fSbellard     if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
1051689f936fSbellard 	return;
1052e80cfcfcSbellard     s->disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
1053e80cfcfcSbellard     s->next = syminfos;
1054e80cfcfcSbellard     syminfos = s;
1055689f936fSbellard }
105631e31b8aSbellard 
1057e5fe0c52Spbrook int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
105831e31b8aSbellard                     struct image_info * info)
105931e31b8aSbellard {
106031e31b8aSbellard     struct elfhdr elf_ex;
106131e31b8aSbellard     struct elfhdr interp_elf_ex;
106231e31b8aSbellard     struct exec interp_ex;
106331e31b8aSbellard     int interpreter_fd = -1; /* avoid warning */
1064992f48a0Sblueswir1     abi_ulong load_addr, load_bias;
106531e31b8aSbellard     int load_addr_set = 0;
106631e31b8aSbellard     unsigned int interpreter_type = INTERPRETER_NONE;
106731e31b8aSbellard     unsigned char ibcs2_interpreter;
106831e31b8aSbellard     int i;
1069992f48a0Sblueswir1     abi_ulong mapped_addr;
107031e31b8aSbellard     struct elf_phdr * elf_ppnt;
107131e31b8aSbellard     struct elf_phdr *elf_phdata;
1072992f48a0Sblueswir1     abi_ulong elf_bss, k, elf_brk;
107331e31b8aSbellard     int retval;
107431e31b8aSbellard     char * elf_interpreter;
1075992f48a0Sblueswir1     abi_ulong elf_entry, interp_load_addr = 0;
107631e31b8aSbellard     int status;
1077992f48a0Sblueswir1     abi_ulong start_code, end_code, start_data, end_data;
1078992f48a0Sblueswir1     abi_ulong reloc_func_desc = 0;
1079992f48a0Sblueswir1     abi_ulong elf_stack;
108031e31b8aSbellard     char passed_fileno[6];
108131e31b8aSbellard 
108231e31b8aSbellard     ibcs2_interpreter = 0;
108331e31b8aSbellard     status = 0;
108431e31b8aSbellard     load_addr = 0;
108509bfb054Sbellard     load_bias = 0;
108631e31b8aSbellard     elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
108731e31b8aSbellard #ifdef BSWAP_NEEDED
108831e31b8aSbellard     bswap_ehdr(&elf_ex);
108931e31b8aSbellard #endif
109031e31b8aSbellard 
109131e31b8aSbellard     /* First of all, some simple consistency checks */
109231e31b8aSbellard     if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
109331e31b8aSbellard        				(! elf_check_arch(elf_ex.e_machine))) {
109431e31b8aSbellard 	    return -ENOEXEC;
109531e31b8aSbellard     }
109631e31b8aSbellard 
1097e5fe0c52Spbrook     bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
1098e5fe0c52Spbrook     bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
1099e5fe0c52Spbrook     bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
1100e5fe0c52Spbrook     if (!bprm->p) {
1101e5fe0c52Spbrook         retval = -E2BIG;
1102e5fe0c52Spbrook     }
1103e5fe0c52Spbrook 
110431e31b8aSbellard     /* Now read in all of the header information */
110531e31b8aSbellard     elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
110631e31b8aSbellard     if (elf_phdata == NULL) {
110731e31b8aSbellard 	return -ENOMEM;
110831e31b8aSbellard     }
110931e31b8aSbellard 
111031e31b8aSbellard     retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
111131e31b8aSbellard     if(retval > 0) {
111231e31b8aSbellard 	retval = read(bprm->fd, (char *) elf_phdata,
111331e31b8aSbellard 				elf_ex.e_phentsize * elf_ex.e_phnum);
111431e31b8aSbellard     }
111531e31b8aSbellard 
111631e31b8aSbellard     if (retval < 0) {
111731e31b8aSbellard 	perror("load_elf_binary");
111831e31b8aSbellard 	exit(-1);
111931e31b8aSbellard 	free (elf_phdata);
112031e31b8aSbellard 	return -errno;
112131e31b8aSbellard     }
112231e31b8aSbellard 
1123b17780d5Sbellard #ifdef BSWAP_NEEDED
1124b17780d5Sbellard     elf_ppnt = elf_phdata;
1125b17780d5Sbellard     for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
1126b17780d5Sbellard         bswap_phdr(elf_ppnt);
1127b17780d5Sbellard     }
1128b17780d5Sbellard #endif
112931e31b8aSbellard     elf_ppnt = elf_phdata;
113031e31b8aSbellard 
113131e31b8aSbellard     elf_bss = 0;
113231e31b8aSbellard     elf_brk = 0;
113331e31b8aSbellard 
113431e31b8aSbellard 
1135992f48a0Sblueswir1     elf_stack = ~((abi_ulong)0UL);
113631e31b8aSbellard     elf_interpreter = NULL;
1137992f48a0Sblueswir1     start_code = ~((abi_ulong)0UL);
113831e31b8aSbellard     end_code = 0;
1139863cf0b7Sj_mayer     start_data = 0;
114031e31b8aSbellard     end_data = 0;
114131e31b8aSbellard 
114231e31b8aSbellard     for(i=0;i < elf_ex.e_phnum; i++) {
114331e31b8aSbellard 	if (elf_ppnt->p_type == PT_INTERP) {
114431e31b8aSbellard 	    if ( elf_interpreter != NULL )
114531e31b8aSbellard 	    {
114631e31b8aSbellard 		free (elf_phdata);
114731e31b8aSbellard 		free(elf_interpreter);
114831e31b8aSbellard 		close(bprm->fd);
114931e31b8aSbellard 		return -EINVAL;
115031e31b8aSbellard 	    }
115131e31b8aSbellard 
115231e31b8aSbellard 	    /* This is the program interpreter used for
115331e31b8aSbellard 	     * shared libraries - for now assume that this
115431e31b8aSbellard 	     * is an a.out format binary
115531e31b8aSbellard 	     */
115631e31b8aSbellard 
115732ce6337Sbellard 	    elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
115831e31b8aSbellard 
115931e31b8aSbellard 	    if (elf_interpreter == NULL) {
116031e31b8aSbellard 		free (elf_phdata);
116131e31b8aSbellard 		close(bprm->fd);
116231e31b8aSbellard 		return -ENOMEM;
116331e31b8aSbellard 	    }
116431e31b8aSbellard 
116531e31b8aSbellard 	    retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
116631e31b8aSbellard 	    if(retval >= 0) {
116732ce6337Sbellard 		retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
116831e31b8aSbellard 	    }
116931e31b8aSbellard 	    if(retval < 0) {
117031e31b8aSbellard 	 	perror("load_elf_binary2");
117131e31b8aSbellard 		exit(-1);
117231e31b8aSbellard 	    }
117331e31b8aSbellard 
117431e31b8aSbellard 	    /* If the program interpreter is one of these two,
117531e31b8aSbellard 	       then assume an iBCS2 image. Otherwise assume
117631e31b8aSbellard 	       a native linux image. */
117731e31b8aSbellard 
117831e31b8aSbellard 	    /* JRP - Need to add X86 lib dir stuff here... */
117931e31b8aSbellard 
118031e31b8aSbellard 	    if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
118131e31b8aSbellard 		strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
118231e31b8aSbellard 	      ibcs2_interpreter = 1;
118331e31b8aSbellard 	    }
118431e31b8aSbellard 
118531e31b8aSbellard #if 0
118631e31b8aSbellard 	    printf("Using ELF interpreter %s\n", elf_interpreter);
118731e31b8aSbellard #endif
118831e31b8aSbellard 	    if (retval >= 0) {
118932ce6337Sbellard 		retval = open(path(elf_interpreter), O_RDONLY);
119031e31b8aSbellard 		if(retval >= 0) {
119131e31b8aSbellard 		    interpreter_fd = retval;
119231e31b8aSbellard 		}
119331e31b8aSbellard 		else {
119431e31b8aSbellard 		    perror(elf_interpreter);
119531e31b8aSbellard 		    exit(-1);
119631e31b8aSbellard 		    /* retval = -errno; */
119731e31b8aSbellard 		}
119831e31b8aSbellard 	    }
119931e31b8aSbellard 
120031e31b8aSbellard 	    if (retval >= 0) {
120131e31b8aSbellard 		retval = lseek(interpreter_fd, 0, SEEK_SET);
120231e31b8aSbellard 		if(retval >= 0) {
120331e31b8aSbellard 		    retval = read(interpreter_fd,bprm->buf,128);
120431e31b8aSbellard 		}
120531e31b8aSbellard 	    }
120631e31b8aSbellard 	    if (retval >= 0) {
120731e31b8aSbellard 		interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
120831e31b8aSbellard 		interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */
120931e31b8aSbellard 	    }
121031e31b8aSbellard 	    if (retval < 0) {
121131e31b8aSbellard 		perror("load_elf_binary3");
121231e31b8aSbellard 		exit(-1);
121331e31b8aSbellard 		free (elf_phdata);
121431e31b8aSbellard 		free(elf_interpreter);
121531e31b8aSbellard 		close(bprm->fd);
121631e31b8aSbellard 		return retval;
121731e31b8aSbellard 	    }
121831e31b8aSbellard 	}
121931e31b8aSbellard 	elf_ppnt++;
122031e31b8aSbellard     }
122131e31b8aSbellard 
122231e31b8aSbellard     /* Some simple consistency checks for the interpreter */
122331e31b8aSbellard     if (elf_interpreter){
122431e31b8aSbellard 	interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
122531e31b8aSbellard 
122631e31b8aSbellard 	/* Now figure out which format our binary is */
122731e31b8aSbellard 	if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
122831e31b8aSbellard 	    	(N_MAGIC(interp_ex) != QMAGIC)) {
122931e31b8aSbellard 	  interpreter_type = INTERPRETER_ELF;
123031e31b8aSbellard 	}
123131e31b8aSbellard 
123231e31b8aSbellard 	if (interp_elf_ex.e_ident[0] != 0x7f ||
123331e31b8aSbellard 	    	strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) {
123431e31b8aSbellard 	    interpreter_type &= ~INTERPRETER_ELF;
123531e31b8aSbellard 	}
123631e31b8aSbellard 
123731e31b8aSbellard 	if (!interpreter_type) {
123831e31b8aSbellard 	    free(elf_interpreter);
123931e31b8aSbellard 	    free(elf_phdata);
124031e31b8aSbellard 	    close(bprm->fd);
124131e31b8aSbellard 	    return -ELIBBAD;
124231e31b8aSbellard 	}
124331e31b8aSbellard     }
124431e31b8aSbellard 
124531e31b8aSbellard     /* OK, we are done with that, now set up the arg stuff,
124631e31b8aSbellard        and then start this sucker up */
124731e31b8aSbellard 
1248e5fe0c52Spbrook     {
124931e31b8aSbellard 	char * passed_p;
125031e31b8aSbellard 
125131e31b8aSbellard 	if (interpreter_type == INTERPRETER_AOUT) {
1252eba2af63Sbellard 	    snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
125331e31b8aSbellard 	    passed_p = passed_fileno;
125431e31b8aSbellard 
125531e31b8aSbellard 	    if (elf_interpreter) {
1256e5fe0c52Spbrook 		bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p);
125731e31b8aSbellard 		bprm->argc++;
125831e31b8aSbellard 	    }
125931e31b8aSbellard 	}
126031e31b8aSbellard 	if (!bprm->p) {
126131e31b8aSbellard 	    if (elf_interpreter) {
126231e31b8aSbellard 	        free(elf_interpreter);
126331e31b8aSbellard 	    }
126431e31b8aSbellard 	    free (elf_phdata);
126531e31b8aSbellard 	    close(bprm->fd);
126631e31b8aSbellard 	    return -E2BIG;
126731e31b8aSbellard 	}
126831e31b8aSbellard     }
126931e31b8aSbellard 
127031e31b8aSbellard     /* OK, This is the point of no return */
127131e31b8aSbellard     info->end_data = 0;
127231e31b8aSbellard     info->end_code = 0;
1273992f48a0Sblueswir1     info->start_mmap = (abi_ulong)ELF_START_MMAP;
127431e31b8aSbellard     info->mmap = 0;
1275992f48a0Sblueswir1     elf_entry = (abi_ulong) elf_ex.e_entry;
127631e31b8aSbellard 
127731e31b8aSbellard     /* Do this so that we can load the interpreter, if need be.  We will
127831e31b8aSbellard        change some of these later */
127931e31b8aSbellard     info->rss = 0;
128031e31b8aSbellard     bprm->p = setup_arg_pages(bprm->p, bprm, info);
128131e31b8aSbellard     info->start_stack = bprm->p;
128231e31b8aSbellard 
128331e31b8aSbellard     /* Now we do a little grungy work by mmaping the ELF image into
128431e31b8aSbellard      * the correct location in memory.  At this point, we assume that
128531e31b8aSbellard      * the image should be loaded at fixed address, not at a variable
128631e31b8aSbellard      * address.
128731e31b8aSbellard      */
128831e31b8aSbellard 
128931e31b8aSbellard     for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
129031e31b8aSbellard         int elf_prot = 0;
129109bfb054Sbellard         int elf_flags = 0;
1292992f48a0Sblueswir1         abi_ulong error;
129309bfb054Sbellard 
129409bfb054Sbellard 	if (elf_ppnt->p_type != PT_LOAD)
129509bfb054Sbellard             continue;
129609bfb054Sbellard 
129731e31b8aSbellard         if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
129831e31b8aSbellard         if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
129931e31b8aSbellard         if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
130009bfb054Sbellard         elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
130109bfb054Sbellard         if (elf_ex.e_type == ET_EXEC || load_addr_set) {
130209bfb054Sbellard             elf_flags |= MAP_FIXED;
130309bfb054Sbellard         } else if (elf_ex.e_type == ET_DYN) {
130409bfb054Sbellard             /* Try and get dynamic programs out of the way of the default mmap
130509bfb054Sbellard                base, as well as whatever program they might try to exec.  This
130609bfb054Sbellard                is because the brk will follow the loader, and is not movable.  */
130709bfb054Sbellard             /* NOTE: for qemu, we do a big mmap to get enough space
1308e91c8a77Sths                without hardcoding any address */
130954936004Sbellard             error = target_mmap(0, ET_DYN_MAP_SIZE,
131009bfb054Sbellard                                 PROT_NONE, MAP_PRIVATE | MAP_ANON,
131109bfb054Sbellard                                 -1, 0);
131209bfb054Sbellard             if (error == -1) {
131309bfb054Sbellard                 perror("mmap");
131409bfb054Sbellard                 exit(-1);
131509bfb054Sbellard             }
131654936004Sbellard             load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
131709bfb054Sbellard         }
131831e31b8aSbellard 
131954936004Sbellard         error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
132031e31b8aSbellard                             (elf_ppnt->p_filesz +
132154936004Sbellard                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
132231e31b8aSbellard                             elf_prot,
132331e31b8aSbellard                             (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
132431e31b8aSbellard                             bprm->fd,
132531e31b8aSbellard                             (elf_ppnt->p_offset -
132654936004Sbellard                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
132709bfb054Sbellard         if (error == -1) {
132831e31b8aSbellard             perror("mmap");
132931e31b8aSbellard             exit(-1);
133031e31b8aSbellard         }
133131e31b8aSbellard 
133231e31b8aSbellard #ifdef LOW_ELF_STACK
133354936004Sbellard         if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
133454936004Sbellard             elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr);
133531e31b8aSbellard #endif
133631e31b8aSbellard 
133731e31b8aSbellard         if (!load_addr_set) {
133831e31b8aSbellard             load_addr_set = 1;
133909bfb054Sbellard             load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
134009bfb054Sbellard             if (elf_ex.e_type == ET_DYN) {
134109bfb054Sbellard                 load_bias += error -
134254936004Sbellard                     TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
134309bfb054Sbellard                 load_addr += load_bias;
134484409ddbSj_mayer                 reloc_func_desc = load_bias;
134509bfb054Sbellard             }
134631e31b8aSbellard         }
134731e31b8aSbellard         k = elf_ppnt->p_vaddr;
134809bfb054Sbellard         if (k < start_code)
134909bfb054Sbellard             start_code = k;
1350863cf0b7Sj_mayer         if (start_data < k)
1351863cf0b7Sj_mayer             start_data = k;
135231e31b8aSbellard         k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
135309bfb054Sbellard         if (k > elf_bss)
135409bfb054Sbellard             elf_bss = k;
135531e31b8aSbellard         if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
135631e31b8aSbellard             end_code = k;
135709bfb054Sbellard         if (end_data < k)
135809bfb054Sbellard             end_data = k;
135931e31b8aSbellard         k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
136031e31b8aSbellard         if (k > elf_brk) elf_brk = k;
136131e31b8aSbellard     }
136209bfb054Sbellard 
136309bfb054Sbellard     elf_entry += load_bias;
136409bfb054Sbellard     elf_bss += load_bias;
136509bfb054Sbellard     elf_brk += load_bias;
136609bfb054Sbellard     start_code += load_bias;
136709bfb054Sbellard     end_code += load_bias;
1368863cf0b7Sj_mayer     start_data += load_bias;
136909bfb054Sbellard     end_data += load_bias;
137031e31b8aSbellard 
137131e31b8aSbellard     if (elf_interpreter) {
137231e31b8aSbellard 	if (interpreter_type & 1) {
137331e31b8aSbellard 	    elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
137431e31b8aSbellard 	}
137531e31b8aSbellard 	else if (interpreter_type & 2) {
137631e31b8aSbellard 	    elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
137731e31b8aSbellard 					    &interp_load_addr);
137831e31b8aSbellard 	}
137984409ddbSj_mayer         reloc_func_desc = interp_load_addr;
138031e31b8aSbellard 
138131e31b8aSbellard 	close(interpreter_fd);
138231e31b8aSbellard 	free(elf_interpreter);
138331e31b8aSbellard 
1384992f48a0Sblueswir1 	if (elf_entry == ~((abi_ulong)0UL)) {
138531e31b8aSbellard 	    printf("Unable to load interpreter\n");
138631e31b8aSbellard 	    free(elf_phdata);
138731e31b8aSbellard 	    exit(-1);
138831e31b8aSbellard 	    return 0;
138931e31b8aSbellard 	}
139031e31b8aSbellard     }
139131e31b8aSbellard 
139231e31b8aSbellard     free(elf_phdata);
139331e31b8aSbellard 
1394689f936fSbellard     if (loglevel)
1395689f936fSbellard 	load_symbols(&elf_ex, bprm->fd);
1396689f936fSbellard 
139731e31b8aSbellard     if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
139831e31b8aSbellard     info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
139931e31b8aSbellard 
140031e31b8aSbellard #ifdef LOW_ELF_STACK
140131e31b8aSbellard     info->start_stack = bprm->p = elf_stack - 4;
140231e31b8aSbellard #endif
140353a5960aSpbrook     bprm->p = create_elf_tables(bprm->p,
140431e31b8aSbellard 		    bprm->argc,
140531e31b8aSbellard 		    bprm->envc,
1406a1516e92Sbellard                     &elf_ex,
140709bfb054Sbellard                     load_addr, load_bias,
140831e31b8aSbellard 		    interp_load_addr,
140931e31b8aSbellard 		    (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
141031e31b8aSbellard 		    info);
141192a343daSj_mayer     info->load_addr = reloc_func_desc;
141231e31b8aSbellard     info->start_brk = info->brk = elf_brk;
141331e31b8aSbellard     info->end_code = end_code;
141431e31b8aSbellard     info->start_code = start_code;
1415863cf0b7Sj_mayer     info->start_data = start_data;
141631e31b8aSbellard     info->end_data = end_data;
141731e31b8aSbellard     info->start_stack = bprm->p;
141831e31b8aSbellard 
141931e31b8aSbellard     /* Calling set_brk effectively mmaps the pages that we need for the bss and break
142031e31b8aSbellard        sections */
142131e31b8aSbellard     set_brk(elf_bss, elf_brk);
142231e31b8aSbellard 
1423768a4a36Sths     padzero(elf_bss, elf_brk);
142431e31b8aSbellard 
142531e31b8aSbellard #if 0
142631e31b8aSbellard     printf("(start_brk) %x\n" , info->start_brk);
142731e31b8aSbellard     printf("(end_code) %x\n" , info->end_code);
142831e31b8aSbellard     printf("(start_code) %x\n" , info->start_code);
142931e31b8aSbellard     printf("(end_data) %x\n" , info->end_data);
143031e31b8aSbellard     printf("(start_stack) %x\n" , info->start_stack);
143131e31b8aSbellard     printf("(brk) %x\n" , info->brk);
143231e31b8aSbellard #endif
143331e31b8aSbellard 
143431e31b8aSbellard     if ( info->personality == PER_SVR4 )
143531e31b8aSbellard     {
143631e31b8aSbellard 	    /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
143731e31b8aSbellard 	       and some applications "depend" upon this behavior.
143831e31b8aSbellard 	       Since we do not have the power to recompile these, we
143931e31b8aSbellard 	       emulate the SVr4 behavior.  Sigh.  */
144083fb7adfSbellard 	    mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
144131e31b8aSbellard                                       MAP_FIXED | MAP_PRIVATE, -1, 0);
144231e31b8aSbellard     }
144331e31b8aSbellard 
144431e31b8aSbellard     info->entry = elf_entry;
144531e31b8aSbellard 
144631e31b8aSbellard     return 0;
144731e31b8aSbellard }
144831e31b8aSbellard 
144931e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd)
145031e31b8aSbellard {
145131e31b8aSbellard     printf("a.out interpreter not yet supported\n");
145231e31b8aSbellard     return(0);
145331e31b8aSbellard }
145431e31b8aSbellard 
1455e5fe0c52Spbrook void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
1456e5fe0c52Spbrook {
1457e5fe0c52Spbrook     init_thread(regs, infop);
1458e5fe0c52Spbrook }
1459