xref: /qemu/linux-user/elfload.c (revision b55266b5a235afe7b0aa946e2a6d49010f35e71c)
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 
15a6cc84f4Smalc #ifdef __powerpc64__
16a6cc84f4Smalc #undef ARCH_DLINFO
17a6cc84f4Smalc #undef ELF_PLATFORM
18a6cc84f4Smalc #undef ELF_HWCAP
19a6cc84f4Smalc #undef ELF_CLASS
20a6cc84f4Smalc #undef ELF_DATA
21a6cc84f4Smalc #undef ELF_ARCH
22a6cc84f4Smalc #endif
23a6cc84f4Smalc 
24cb33da57Sblueswir1 /* from personality.h */
25cb33da57Sblueswir1 
26cb33da57Sblueswir1 /*
27cb33da57Sblueswir1  * Flags for bug emulation.
28cb33da57Sblueswir1  *
29cb33da57Sblueswir1  * These occupy the top three bytes.
30cb33da57Sblueswir1  */
31cb33da57Sblueswir1 enum {
32cb33da57Sblueswir1 	ADDR_NO_RANDOMIZE = 	0x0040000,	/* disable randomization of VA space */
33cb33da57Sblueswir1 	FDPIC_FUNCPTRS =	0x0080000,	/* userspace function ptrs point to descriptors
34cb33da57Sblueswir1 						 * (signal handling)
35cb33da57Sblueswir1 						 */
36cb33da57Sblueswir1 	MMAP_PAGE_ZERO =	0x0100000,
37cb33da57Sblueswir1 	ADDR_COMPAT_LAYOUT =	0x0200000,
38cb33da57Sblueswir1 	READ_IMPLIES_EXEC =	0x0400000,
39cb33da57Sblueswir1 	ADDR_LIMIT_32BIT =	0x0800000,
40cb33da57Sblueswir1 	SHORT_INODE =		0x1000000,
41cb33da57Sblueswir1 	WHOLE_SECONDS =		0x2000000,
42cb33da57Sblueswir1 	STICKY_TIMEOUTS	=	0x4000000,
43cb33da57Sblueswir1 	ADDR_LIMIT_3GB = 	0x8000000,
44cb33da57Sblueswir1 };
45cb33da57Sblueswir1 
46cb33da57Sblueswir1 /*
47cb33da57Sblueswir1  * Personality types.
48cb33da57Sblueswir1  *
49cb33da57Sblueswir1  * These go in the low byte.  Avoid using the top bit, it will
50cb33da57Sblueswir1  * conflict with error returns.
51cb33da57Sblueswir1  */
52cb33da57Sblueswir1 enum {
53cb33da57Sblueswir1 	PER_LINUX =		0x0000,
54cb33da57Sblueswir1 	PER_LINUX_32BIT =	0x0000 | ADDR_LIMIT_32BIT,
55cb33da57Sblueswir1 	PER_LINUX_FDPIC =	0x0000 | FDPIC_FUNCPTRS,
56cb33da57Sblueswir1 	PER_SVR4 =		0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
57cb33da57Sblueswir1 	PER_SVR3 =		0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
58cb33da57Sblueswir1 	PER_SCOSVR3 =		0x0003 | STICKY_TIMEOUTS |
59cb33da57Sblueswir1 					 WHOLE_SECONDS | SHORT_INODE,
60cb33da57Sblueswir1 	PER_OSR5 =		0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
61cb33da57Sblueswir1 	PER_WYSEV386 =		0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
62cb33da57Sblueswir1 	PER_ISCR4 =		0x0005 | STICKY_TIMEOUTS,
63cb33da57Sblueswir1 	PER_BSD =		0x0006,
64cb33da57Sblueswir1 	PER_SUNOS =		0x0006 | STICKY_TIMEOUTS,
65cb33da57Sblueswir1 	PER_XENIX =		0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
66cb33da57Sblueswir1 	PER_LINUX32 =		0x0008,
67cb33da57Sblueswir1 	PER_LINUX32_3GB =	0x0008 | ADDR_LIMIT_3GB,
68cb33da57Sblueswir1 	PER_IRIX32 =		0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
69cb33da57Sblueswir1 	PER_IRIXN32 =		0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
70cb33da57Sblueswir1 	PER_IRIX64 =		0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
71cb33da57Sblueswir1 	PER_RISCOS =		0x000c,
72cb33da57Sblueswir1 	PER_SOLARIS =		0x000d | STICKY_TIMEOUTS,
73cb33da57Sblueswir1 	PER_UW7 =		0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
74cb33da57Sblueswir1 	PER_OSF4 =		0x000f,			 /* OSF/1 v4 */
75cb33da57Sblueswir1 	PER_HPUX =		0x0010,
76cb33da57Sblueswir1 	PER_MASK =		0x00ff,
77cb33da57Sblueswir1 };
78cb33da57Sblueswir1 
79cb33da57Sblueswir1 /*
80cb33da57Sblueswir1  * Return the base personality without flags.
81cb33da57Sblueswir1  */
82cb33da57Sblueswir1 #define personality(pers)	(pers & PER_MASK)
83cb33da57Sblueswir1 
8483fb7adfSbellard /* this flag is uneffective under linux too, should be deleted */
8583fb7adfSbellard #ifndef MAP_DENYWRITE
8683fb7adfSbellard #define MAP_DENYWRITE 0
8783fb7adfSbellard #endif
8883fb7adfSbellard 
8983fb7adfSbellard /* should probably go in elf.h */
9083fb7adfSbellard #ifndef ELIBBAD
9183fb7adfSbellard #define ELIBBAD 80
9283fb7adfSbellard #endif
9383fb7adfSbellard 
9430ac07d4Sbellard #ifdef TARGET_I386
9530ac07d4Sbellard 
9615338fd7Sbellard #define ELF_PLATFORM get_elf_platform()
9715338fd7Sbellard 
9815338fd7Sbellard static const char *get_elf_platform(void)
9915338fd7Sbellard {
10015338fd7Sbellard     static char elf_platform[] = "i386";
101d5975363Spbrook     int family = (thread_env->cpuid_version >> 8) & 0xff;
10215338fd7Sbellard     if (family > 6)
10315338fd7Sbellard         family = 6;
10415338fd7Sbellard     if (family >= 3)
10515338fd7Sbellard         elf_platform[1] = '0' + family;
10615338fd7Sbellard     return elf_platform;
10715338fd7Sbellard }
10815338fd7Sbellard 
10915338fd7Sbellard #define ELF_HWCAP get_elf_hwcap()
11015338fd7Sbellard 
11115338fd7Sbellard static uint32_t get_elf_hwcap(void)
11215338fd7Sbellard {
113d5975363Spbrook   return thread_env->cpuid_features;
11415338fd7Sbellard }
11515338fd7Sbellard 
11684409ddbSj_mayer #ifdef TARGET_X86_64
11784409ddbSj_mayer #define ELF_START_MMAP 0x2aaaaab000ULL
11884409ddbSj_mayer #define elf_check_arch(x) ( ((x) == ELF_ARCH) )
11984409ddbSj_mayer 
12084409ddbSj_mayer #define ELF_CLASS      ELFCLASS64
12184409ddbSj_mayer #define ELF_DATA       ELFDATA2LSB
12284409ddbSj_mayer #define ELF_ARCH       EM_X86_64
12384409ddbSj_mayer 
12484409ddbSj_mayer static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
12584409ddbSj_mayer {
12684409ddbSj_mayer     regs->rax = 0;
12784409ddbSj_mayer     regs->rsp = infop->start_stack;
12884409ddbSj_mayer     regs->rip = infop->entry;
12984409ddbSj_mayer }
13084409ddbSj_mayer 
13184409ddbSj_mayer #else
13284409ddbSj_mayer 
13330ac07d4Sbellard #define ELF_START_MMAP 0x80000000
13430ac07d4Sbellard 
13530ac07d4Sbellard /*
13630ac07d4Sbellard  * This is used to ensure we don't load something for the wrong architecture.
13730ac07d4Sbellard  */
13830ac07d4Sbellard #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
13930ac07d4Sbellard 
14030ac07d4Sbellard /*
14130ac07d4Sbellard  * These are used to set parameters in the core dumps.
14230ac07d4Sbellard  */
14330ac07d4Sbellard #define ELF_CLASS	ELFCLASS32
14430ac07d4Sbellard #define ELF_DATA	ELFDATA2LSB
14530ac07d4Sbellard #define ELF_ARCH	EM_386
14630ac07d4Sbellard 
147e5fe0c52Spbrook static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
148e5fe0c52Spbrook {
149e5fe0c52Spbrook     regs->esp = infop->start_stack;
150e5fe0c52Spbrook     regs->eip = infop->entry;
151e5fe0c52Spbrook 
15230ac07d4Sbellard     /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
15330ac07d4Sbellard        starts %edx contains a pointer to a function which might be
15430ac07d4Sbellard        registered using `atexit'.  This provides a mean for the
15530ac07d4Sbellard        dynamic linker to call DT_FINI functions for shared libraries
15630ac07d4Sbellard        that have been loaded before the code runs.
15730ac07d4Sbellard 
15830ac07d4Sbellard        A value of 0 tells we have no such handler.  */
159e5fe0c52Spbrook     regs->edx = 0;
160b346ff46Sbellard }
16184409ddbSj_mayer #endif
162b346ff46Sbellard 
163b346ff46Sbellard #define USE_ELF_CORE_DUMP
164b346ff46Sbellard #define ELF_EXEC_PAGESIZE	4096
165b346ff46Sbellard 
166b346ff46Sbellard #endif
167b346ff46Sbellard 
168b346ff46Sbellard #ifdef TARGET_ARM
169b346ff46Sbellard 
170b346ff46Sbellard #define ELF_START_MMAP 0x80000000
171b346ff46Sbellard 
172b346ff46Sbellard #define elf_check_arch(x) ( (x) == EM_ARM )
173b346ff46Sbellard 
174b346ff46Sbellard #define ELF_CLASS	ELFCLASS32
175b346ff46Sbellard #ifdef TARGET_WORDS_BIGENDIAN
176b346ff46Sbellard #define ELF_DATA	ELFDATA2MSB
177b346ff46Sbellard #else
178b346ff46Sbellard #define ELF_DATA	ELFDATA2LSB
179b346ff46Sbellard #endif
180b346ff46Sbellard #define ELF_ARCH	EM_ARM
181b346ff46Sbellard 
182b346ff46Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
183b346ff46Sbellard {
184992f48a0Sblueswir1     abi_long stack = infop->start_stack;
185b346ff46Sbellard     memset(regs, 0, sizeof(*regs));
186b346ff46Sbellard     regs->ARM_cpsr = 0x10;
1870240ded8Spbrook     if (infop->entry & 1)
1880240ded8Spbrook       regs->ARM_cpsr |= CPSR_T;
1890240ded8Spbrook     regs->ARM_pc = infop->entry & 0xfffffffe;
190b346ff46Sbellard     regs->ARM_sp = infop->start_stack;
1912f619698Sbellard     /* FIXME - what to for failure of get_user()? */
1922f619698Sbellard     get_user_ual(regs->ARM_r2, stack + 8); /* envp */
1932f619698Sbellard     get_user_ual(regs->ARM_r1, stack + 4); /* envp */
194a1516e92Sbellard     /* XXX: it seems that r0 is zeroed after ! */
195e5fe0c52Spbrook     regs->ARM_r0 = 0;
196e5fe0c52Spbrook     /* For uClinux PIC binaries.  */
197863cf0b7Sj_mayer     /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
198e5fe0c52Spbrook     regs->ARM_r10 = infop->start_data;
199b346ff46Sbellard }
200b346ff46Sbellard 
20130ac07d4Sbellard #define USE_ELF_CORE_DUMP
20230ac07d4Sbellard #define ELF_EXEC_PAGESIZE	4096
20330ac07d4Sbellard 
204afce2927Sbellard enum
205afce2927Sbellard {
206afce2927Sbellard   ARM_HWCAP_ARM_SWP       = 1 << 0,
207afce2927Sbellard   ARM_HWCAP_ARM_HALF      = 1 << 1,
208afce2927Sbellard   ARM_HWCAP_ARM_THUMB     = 1 << 2,
209afce2927Sbellard   ARM_HWCAP_ARM_26BIT     = 1 << 3,
210afce2927Sbellard   ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
211afce2927Sbellard   ARM_HWCAP_ARM_FPA       = 1 << 5,
212afce2927Sbellard   ARM_HWCAP_ARM_VFP       = 1 << 6,
213afce2927Sbellard   ARM_HWCAP_ARM_EDSP      = 1 << 7,
214afce2927Sbellard };
215afce2927Sbellard 
21615338fd7Sbellard #define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF              \
217afce2927Sbellard                     | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT     \
218afce2927Sbellard                     | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP)
219afce2927Sbellard 
22030ac07d4Sbellard #endif
22130ac07d4Sbellard 
222853d6f7aSbellard #ifdef TARGET_SPARC
223a315a145Sbellard #ifdef TARGET_SPARC64
224853d6f7aSbellard 
225853d6f7aSbellard #define ELF_START_MMAP 0x80000000
226853d6f7aSbellard 
227992f48a0Sblueswir1 #ifndef TARGET_ABI32
228cb33da57Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
229992f48a0Sblueswir1 #else
230992f48a0Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
231992f48a0Sblueswir1 #endif
232853d6f7aSbellard 
233a315a145Sbellard #define ELF_CLASS   ELFCLASS64
234a315a145Sbellard #define ELF_DATA    ELFDATA2MSB
2355ef54116Sbellard #define ELF_ARCH    EM_SPARCV9
2365ef54116Sbellard 
2375ef54116Sbellard #define STACK_BIAS		2047
238a315a145Sbellard 
239a315a145Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
240a315a145Sbellard {
241992f48a0Sblueswir1 #ifndef TARGET_ABI32
242a315a145Sbellard     regs->tstate = 0;
243992f48a0Sblueswir1 #endif
244a315a145Sbellard     regs->pc = infop->entry;
245a315a145Sbellard     regs->npc = regs->pc + 4;
246a315a145Sbellard     regs->y = 0;
247992f48a0Sblueswir1 #ifdef TARGET_ABI32
248992f48a0Sblueswir1     regs->u_regs[14] = infop->start_stack - 16 * 4;
249992f48a0Sblueswir1 #else
250cb33da57Sblueswir1     if (personality(infop->personality) == PER_LINUX32)
251cb33da57Sblueswir1         regs->u_regs[14] = infop->start_stack - 16 * 4;
252cb33da57Sblueswir1     else
2535ef54116Sbellard         regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
254992f48a0Sblueswir1 #endif
255a315a145Sbellard }
256a315a145Sbellard 
257a315a145Sbellard #else
258a315a145Sbellard #define ELF_START_MMAP 0x80000000
259a315a145Sbellard 
260a315a145Sbellard #define elf_check_arch(x) ( (x) == EM_SPARC )
261a315a145Sbellard 
262853d6f7aSbellard #define ELF_CLASS   ELFCLASS32
263853d6f7aSbellard #define ELF_DATA    ELFDATA2MSB
264853d6f7aSbellard #define ELF_ARCH    EM_SPARC
265853d6f7aSbellard 
266853d6f7aSbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
267853d6f7aSbellard {
268f5155289Sbellard     regs->psr = 0;
269f5155289Sbellard     regs->pc = infop->entry;
270f5155289Sbellard     regs->npc = regs->pc + 4;
271f5155289Sbellard     regs->y = 0;
272f5155289Sbellard     regs->u_regs[14] = infop->start_stack - 16 * 4;
273853d6f7aSbellard }
274853d6f7aSbellard 
275853d6f7aSbellard #endif
276a315a145Sbellard #endif
277853d6f7aSbellard 
27867867308Sbellard #ifdef TARGET_PPC
27967867308Sbellard 
28067867308Sbellard #define ELF_START_MMAP 0x80000000
28167867308Sbellard 
282e85e7c6eSj_mayer #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
28384409ddbSj_mayer 
28484409ddbSj_mayer #define elf_check_arch(x) ( (x) == EM_PPC64 )
28584409ddbSj_mayer 
28684409ddbSj_mayer #define ELF_CLASS	ELFCLASS64
28784409ddbSj_mayer 
28884409ddbSj_mayer #else
28984409ddbSj_mayer 
29067867308Sbellard #define elf_check_arch(x) ( (x) == EM_PPC )
29167867308Sbellard 
29267867308Sbellard #define ELF_CLASS	ELFCLASS32
29384409ddbSj_mayer 
29484409ddbSj_mayer #endif
29584409ddbSj_mayer 
29667867308Sbellard #ifdef TARGET_WORDS_BIGENDIAN
29767867308Sbellard #define ELF_DATA	ELFDATA2MSB
29867867308Sbellard #else
29967867308Sbellard #define ELF_DATA	ELFDATA2LSB
30067867308Sbellard #endif
30167867308Sbellard #define ELF_ARCH	EM_PPC
30267867308Sbellard 
303f5155289Sbellard /*
304f5155289Sbellard  * We need to put in some extra aux table entries to tell glibc what
305f5155289Sbellard  * the cache block size is, so it can use the dcbz instruction safely.
306f5155289Sbellard  */
307f5155289Sbellard #define AT_DCACHEBSIZE          19
308f5155289Sbellard #define AT_ICACHEBSIZE          20
309f5155289Sbellard #define AT_UCACHEBSIZE          21
310f5155289Sbellard /* A special ignored type value for PPC, for glibc compatibility.  */
311f5155289Sbellard #define AT_IGNOREPPC            22
312f5155289Sbellard /*
313f5155289Sbellard  * The requirements here are:
314f5155289Sbellard  * - keep the final alignment of sp (sp & 0xf)
315f5155289Sbellard  * - make sure the 32-bit value at the first 16 byte aligned position of
316f5155289Sbellard  *   AUXV is greater than 16 for glibc compatibility.
317f5155289Sbellard  *   AT_IGNOREPPC is used for that.
318f5155289Sbellard  * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
319f5155289Sbellard  *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
320f5155289Sbellard  */
3210bccf03dSbellard #define DLINFO_ARCH_ITEMS       5
322f5155289Sbellard #define ARCH_DLINFO                                                     \
323f5155289Sbellard do {                                                                    \
3240bccf03dSbellard         NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20);                              \
3250bccf03dSbellard         NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20);                              \
3260bccf03dSbellard         NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                                 \
327f5155289Sbellard         /*                                                              \
328f5155289Sbellard          * Now handle glibc compatibility.                              \
329f5155289Sbellard          */                                                             \
3300bccf03dSbellard 	NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);			\
3310bccf03dSbellard 	NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);			\
332f5155289Sbellard  } while (0)
333f5155289Sbellard 
33467867308Sbellard static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
33567867308Sbellard {
336992f48a0Sblueswir1     abi_ulong pos = infop->start_stack;
337992f48a0Sblueswir1     abi_ulong tmp;
338e85e7c6eSj_mayer #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
339992f48a0Sblueswir1     abi_ulong entry, toc;
34084409ddbSj_mayer #endif
341e5fe0c52Spbrook 
34267867308Sbellard     _regs->gpr[1] = infop->start_stack;
343e85e7c6eSj_mayer #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
34484409ddbSj_mayer     entry = ldq_raw(infop->entry) + infop->load_addr;
34584409ddbSj_mayer     toc = ldq_raw(infop->entry + 8) + infop->load_addr;
34684409ddbSj_mayer     _regs->gpr[2] = toc;
34784409ddbSj_mayer     infop->entry = entry;
34884409ddbSj_mayer #endif
34967867308Sbellard     _regs->nip = infop->entry;
350e5fe0c52Spbrook     /* Note that isn't exactly what regular kernel does
351e5fe0c52Spbrook      * but this is what the ABI wants and is needed to allow
352e5fe0c52Spbrook      * execution of PPC BSD programs.
353e5fe0c52Spbrook      */
3542f619698Sbellard     /* FIXME - what to for failure of get_user()? */
3552f619698Sbellard     get_user_ual(_regs->gpr[3], pos);
356992f48a0Sblueswir1     pos += sizeof(abi_ulong);
357e5fe0c52Spbrook     _regs->gpr[4] = pos;
358992f48a0Sblueswir1     for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong))
359e5fe0c52Spbrook         tmp = ldl(pos);
360e5fe0c52Spbrook     _regs->gpr[5] = pos;
36167867308Sbellard }
36267867308Sbellard 
36367867308Sbellard #define USE_ELF_CORE_DUMP
36467867308Sbellard #define ELF_EXEC_PAGESIZE	4096
36567867308Sbellard 
36667867308Sbellard #endif
36767867308Sbellard 
368048f6b4dSbellard #ifdef TARGET_MIPS
369048f6b4dSbellard 
370048f6b4dSbellard #define ELF_START_MMAP 0x80000000
371048f6b4dSbellard 
372048f6b4dSbellard #define elf_check_arch(x) ( (x) == EM_MIPS )
373048f6b4dSbellard 
374388bb21aSths #ifdef TARGET_MIPS64
375388bb21aSths #define ELF_CLASS   ELFCLASS64
376388bb21aSths #else
377048f6b4dSbellard #define ELF_CLASS   ELFCLASS32
378388bb21aSths #endif
379048f6b4dSbellard #ifdef TARGET_WORDS_BIGENDIAN
380048f6b4dSbellard #define ELF_DATA	ELFDATA2MSB
381048f6b4dSbellard #else
382048f6b4dSbellard #define ELF_DATA	ELFDATA2LSB
383048f6b4dSbellard #endif
384048f6b4dSbellard #define ELF_ARCH    EM_MIPS
385048f6b4dSbellard 
386048f6b4dSbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
387048f6b4dSbellard {
388623a930eSths     regs->cp0_status = 2 << CP0St_KSU;
389048f6b4dSbellard     regs->cp0_epc = infop->entry;
390048f6b4dSbellard     regs->regs[29] = infop->start_stack;
391048f6b4dSbellard }
392048f6b4dSbellard 
393388bb21aSths #define USE_ELF_CORE_DUMP
394388bb21aSths #define ELF_EXEC_PAGESIZE        4096
395388bb21aSths 
396048f6b4dSbellard #endif /* TARGET_MIPS */
397048f6b4dSbellard 
398fdf9b3e8Sbellard #ifdef TARGET_SH4
399fdf9b3e8Sbellard 
400fdf9b3e8Sbellard #define ELF_START_MMAP 0x80000000
401fdf9b3e8Sbellard 
402fdf9b3e8Sbellard #define elf_check_arch(x) ( (x) == EM_SH )
403fdf9b3e8Sbellard 
404fdf9b3e8Sbellard #define ELF_CLASS ELFCLASS32
405fdf9b3e8Sbellard #define ELF_DATA  ELFDATA2LSB
406fdf9b3e8Sbellard #define ELF_ARCH  EM_SH
407fdf9b3e8Sbellard 
408fdf9b3e8Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
409fdf9b3e8Sbellard {
410fdf9b3e8Sbellard   /* Check other registers XXXXX */
411fdf9b3e8Sbellard   regs->pc = infop->entry;
412072ae847Sths   regs->regs[15] = infop->start_stack;
413fdf9b3e8Sbellard }
414fdf9b3e8Sbellard 
415fdf9b3e8Sbellard #define USE_ELF_CORE_DUMP
416fdf9b3e8Sbellard #define ELF_EXEC_PAGESIZE        4096
417fdf9b3e8Sbellard 
418fdf9b3e8Sbellard #endif
419fdf9b3e8Sbellard 
42048733d19Sths #ifdef TARGET_CRIS
42148733d19Sths 
42248733d19Sths #define ELF_START_MMAP 0x80000000
42348733d19Sths 
42448733d19Sths #define elf_check_arch(x) ( (x) == EM_CRIS )
42548733d19Sths 
42648733d19Sths #define ELF_CLASS ELFCLASS32
42748733d19Sths #define ELF_DATA  ELFDATA2LSB
42848733d19Sths #define ELF_ARCH  EM_CRIS
42948733d19Sths 
43048733d19Sths static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
43148733d19Sths {
43248733d19Sths   regs->erp = infop->entry;
43348733d19Sths }
43448733d19Sths 
43548733d19Sths #define USE_ELF_CORE_DUMP
43648733d19Sths #define ELF_EXEC_PAGESIZE        8192
43748733d19Sths 
43848733d19Sths #endif
43948733d19Sths 
440e6e5906bSpbrook #ifdef TARGET_M68K
441e6e5906bSpbrook 
442e6e5906bSpbrook #define ELF_START_MMAP 0x80000000
443e6e5906bSpbrook 
444e6e5906bSpbrook #define elf_check_arch(x) ( (x) == EM_68K )
445e6e5906bSpbrook 
446e6e5906bSpbrook #define ELF_CLASS	ELFCLASS32
447e6e5906bSpbrook #define ELF_DATA	ELFDATA2MSB
448e6e5906bSpbrook #define ELF_ARCH	EM_68K
449e6e5906bSpbrook 
450e6e5906bSpbrook /* ??? Does this need to do anything?
451e6e5906bSpbrook #define ELF_PLAT_INIT(_r) */
452e6e5906bSpbrook 
453e6e5906bSpbrook static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
454e6e5906bSpbrook {
455e6e5906bSpbrook     regs->usp = infop->start_stack;
456e6e5906bSpbrook     regs->sr = 0;
457e6e5906bSpbrook     regs->pc = infop->entry;
458e6e5906bSpbrook }
459e6e5906bSpbrook 
460e6e5906bSpbrook #define USE_ELF_CORE_DUMP
461e6e5906bSpbrook #define ELF_EXEC_PAGESIZE	8192
462e6e5906bSpbrook 
463e6e5906bSpbrook #endif
464e6e5906bSpbrook 
4657a3148a9Sj_mayer #ifdef TARGET_ALPHA
4667a3148a9Sj_mayer 
4677a3148a9Sj_mayer #define ELF_START_MMAP (0x30000000000ULL)
4687a3148a9Sj_mayer 
4697a3148a9Sj_mayer #define elf_check_arch(x) ( (x) == ELF_ARCH )
4707a3148a9Sj_mayer 
4717a3148a9Sj_mayer #define ELF_CLASS      ELFCLASS64
4727a3148a9Sj_mayer #define ELF_DATA       ELFDATA2MSB
4737a3148a9Sj_mayer #define ELF_ARCH       EM_ALPHA
4747a3148a9Sj_mayer 
4757a3148a9Sj_mayer static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
4767a3148a9Sj_mayer {
4777a3148a9Sj_mayer     regs->pc = infop->entry;
4787a3148a9Sj_mayer     regs->ps = 8;
4797a3148a9Sj_mayer     regs->usp = infop->start_stack;
4807a3148a9Sj_mayer     regs->unique = infop->start_data; /* ? */
4817a3148a9Sj_mayer     printf("Set unique value to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n",
4827a3148a9Sj_mayer            regs->unique, infop->start_data);
4837a3148a9Sj_mayer }
4847a3148a9Sj_mayer 
4857a3148a9Sj_mayer #define USE_ELF_CORE_DUMP
4867a3148a9Sj_mayer #define ELF_EXEC_PAGESIZE        8192
4877a3148a9Sj_mayer 
4887a3148a9Sj_mayer #endif /* TARGET_ALPHA */
4897a3148a9Sj_mayer 
49015338fd7Sbellard #ifndef ELF_PLATFORM
49115338fd7Sbellard #define ELF_PLATFORM (NULL)
49215338fd7Sbellard #endif
49315338fd7Sbellard 
49415338fd7Sbellard #ifndef ELF_HWCAP
49515338fd7Sbellard #define ELF_HWCAP 0
49615338fd7Sbellard #endif
49715338fd7Sbellard 
498992f48a0Sblueswir1 #ifdef TARGET_ABI32
499cb33da57Sblueswir1 #undef ELF_CLASS
500992f48a0Sblueswir1 #define ELF_CLASS ELFCLASS32
501cb33da57Sblueswir1 #undef bswaptls
502cb33da57Sblueswir1 #define bswaptls(ptr) bswap32s(ptr)
503cb33da57Sblueswir1 #endif
504cb33da57Sblueswir1 
50531e31b8aSbellard #include "elf.h"
50609bfb054Sbellard 
50709bfb054Sbellard struct exec
50809bfb054Sbellard {
50909bfb054Sbellard   unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
51009bfb054Sbellard   unsigned int a_text;   /* length of text, in bytes */
51109bfb054Sbellard   unsigned int a_data;   /* length of data, in bytes */
51209bfb054Sbellard   unsigned int a_bss;    /* length of uninitialized data area, in bytes */
51309bfb054Sbellard   unsigned int a_syms;   /* length of symbol table data in file, in bytes */
51409bfb054Sbellard   unsigned int a_entry;  /* start address */
51509bfb054Sbellard   unsigned int a_trsize; /* length of relocation info for text, in bytes */
51609bfb054Sbellard   unsigned int a_drsize; /* length of relocation info for data, in bytes */
51709bfb054Sbellard };
51809bfb054Sbellard 
51909bfb054Sbellard 
52009bfb054Sbellard #define N_MAGIC(exec) ((exec).a_info & 0xffff)
52109bfb054Sbellard #define OMAGIC 0407
52209bfb054Sbellard #define NMAGIC 0410
52309bfb054Sbellard #define ZMAGIC 0413
52409bfb054Sbellard #define QMAGIC 0314
52509bfb054Sbellard 
52609bfb054Sbellard /* max code+data+bss space allocated to elf interpreter */
52709bfb054Sbellard #define INTERP_MAP_SIZE (32 * 1024 * 1024)
52809bfb054Sbellard 
52909bfb054Sbellard /* max code+data+bss+brk space allocated to ET_DYN executables */
53009bfb054Sbellard #define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
53109bfb054Sbellard 
53231e31b8aSbellard /* Necessary parameters */
53354936004Sbellard #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
53454936004Sbellard #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
53554936004Sbellard #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
53631e31b8aSbellard 
53731e31b8aSbellard #define INTERPRETER_NONE 0
53831e31b8aSbellard #define INTERPRETER_AOUT 1
53931e31b8aSbellard #define INTERPRETER_ELF 2
54031e31b8aSbellard 
54115338fd7Sbellard #define DLINFO_ITEMS 12
54231e31b8aSbellard 
54309bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
54409bfb054Sbellard {
54509bfb054Sbellard 	memcpy(to, from, n);
54609bfb054Sbellard }
54709bfb054Sbellard 
54831e31b8aSbellard extern unsigned long x86_stack_size;
54931e31b8aSbellard 
55031e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd);
55131e31b8aSbellard 
55231e31b8aSbellard #ifdef BSWAP_NEEDED
55392a31b1fSbellard static void bswap_ehdr(struct elfhdr *ehdr)
55431e31b8aSbellard {
55531e31b8aSbellard     bswap16s(&ehdr->e_type);			/* Object file type */
55631e31b8aSbellard     bswap16s(&ehdr->e_machine);		/* Architecture */
55731e31b8aSbellard     bswap32s(&ehdr->e_version);		/* Object file version */
55892a31b1fSbellard     bswaptls(&ehdr->e_entry);		/* Entry point virtual address */
55992a31b1fSbellard     bswaptls(&ehdr->e_phoff);		/* Program header table file offset */
56092a31b1fSbellard     bswaptls(&ehdr->e_shoff);		/* Section header table file offset */
56131e31b8aSbellard     bswap32s(&ehdr->e_flags);		/* Processor-specific flags */
56231e31b8aSbellard     bswap16s(&ehdr->e_ehsize);		/* ELF header size in bytes */
56331e31b8aSbellard     bswap16s(&ehdr->e_phentsize);		/* Program header table entry size */
56431e31b8aSbellard     bswap16s(&ehdr->e_phnum);		/* Program header table entry count */
56531e31b8aSbellard     bswap16s(&ehdr->e_shentsize);		/* Section header table entry size */
56631e31b8aSbellard     bswap16s(&ehdr->e_shnum);		/* Section header table entry count */
56731e31b8aSbellard     bswap16s(&ehdr->e_shstrndx);		/* Section header string table index */
56831e31b8aSbellard }
56931e31b8aSbellard 
57092a31b1fSbellard static void bswap_phdr(struct elf_phdr *phdr)
57131e31b8aSbellard {
57231e31b8aSbellard     bswap32s(&phdr->p_type);			/* Segment type */
57392a31b1fSbellard     bswaptls(&phdr->p_offset);		/* Segment file offset */
57492a31b1fSbellard     bswaptls(&phdr->p_vaddr);		/* Segment virtual address */
57592a31b1fSbellard     bswaptls(&phdr->p_paddr);		/* Segment physical address */
57692a31b1fSbellard     bswaptls(&phdr->p_filesz);		/* Segment size in file */
57792a31b1fSbellard     bswaptls(&phdr->p_memsz);		/* Segment size in memory */
57831e31b8aSbellard     bswap32s(&phdr->p_flags);		/* Segment flags */
57992a31b1fSbellard     bswaptls(&phdr->p_align);		/* Segment alignment */
58031e31b8aSbellard }
581689f936fSbellard 
58292a31b1fSbellard static void bswap_shdr(struct elf_shdr *shdr)
583689f936fSbellard {
584689f936fSbellard     bswap32s(&shdr->sh_name);
585689f936fSbellard     bswap32s(&shdr->sh_type);
58692a31b1fSbellard     bswaptls(&shdr->sh_flags);
58792a31b1fSbellard     bswaptls(&shdr->sh_addr);
58892a31b1fSbellard     bswaptls(&shdr->sh_offset);
58992a31b1fSbellard     bswaptls(&shdr->sh_size);
590689f936fSbellard     bswap32s(&shdr->sh_link);
591689f936fSbellard     bswap32s(&shdr->sh_info);
59292a31b1fSbellard     bswaptls(&shdr->sh_addralign);
59392a31b1fSbellard     bswaptls(&shdr->sh_entsize);
594689f936fSbellard }
595689f936fSbellard 
5967a3148a9Sj_mayer static void bswap_sym(struct elf_sym *sym)
597689f936fSbellard {
598689f936fSbellard     bswap32s(&sym->st_name);
5997a3148a9Sj_mayer     bswaptls(&sym->st_value);
6007a3148a9Sj_mayer     bswaptls(&sym->st_size);
601689f936fSbellard     bswap16s(&sym->st_shndx);
602689f936fSbellard }
60331e31b8aSbellard #endif
60431e31b8aSbellard 
60531e31b8aSbellard /*
606e5fe0c52Spbrook  * 'copy_elf_strings()' copies argument/envelope strings from user
60731e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
60831e31b8aSbellard  * to be put directly into the top of new user memory.
60931e31b8aSbellard  *
61031e31b8aSbellard  */
611992f48a0Sblueswir1 static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
612992f48a0Sblueswir1                                   abi_ulong p)
61331e31b8aSbellard {
61431e31b8aSbellard     char *tmp, *tmp1, *pag = NULL;
61531e31b8aSbellard     int len, offset = 0;
61631e31b8aSbellard 
61731e31b8aSbellard     if (!p) {
61831e31b8aSbellard 	return 0;       /* bullet-proofing */
61931e31b8aSbellard     }
62031e31b8aSbellard     while (argc-- > 0) {
621edf779ffSbellard         tmp = argv[argc];
622edf779ffSbellard         if (!tmp) {
62331e31b8aSbellard 	    fprintf(stderr, "VFS: argc is wrong");
62431e31b8aSbellard 	    exit(-1);
62531e31b8aSbellard 	}
626edf779ffSbellard         tmp1 = tmp;
627edf779ffSbellard 	while (*tmp++);
62831e31b8aSbellard 	len = tmp - tmp1;
62931e31b8aSbellard 	if (p < len) {  /* this shouldn't happen - 128kB */
63031e31b8aSbellard 		return 0;
63131e31b8aSbellard 	}
63231e31b8aSbellard 	while (len) {
63331e31b8aSbellard 	    --p; --tmp; --len;
63431e31b8aSbellard 	    if (--offset < 0) {
63554936004Sbellard 		offset = p % TARGET_PAGE_SIZE;
63644a91caeSbellard                 pag = (char *)page[p/TARGET_PAGE_SIZE];
63744a91caeSbellard                 if (!pag) {
63853a5960aSpbrook                     pag = (char *)malloc(TARGET_PAGE_SIZE);
6394118a970Sj_mayer                     memset(pag, 0, TARGET_PAGE_SIZE);
64053a5960aSpbrook                     page[p/TARGET_PAGE_SIZE] = pag;
64144a91caeSbellard                     if (!pag)
64231e31b8aSbellard                         return 0;
64331e31b8aSbellard 		}
64431e31b8aSbellard 	    }
64531e31b8aSbellard 	    if (len == 0 || offset == 0) {
646edf779ffSbellard 	        *(pag + offset) = *tmp;
64731e31b8aSbellard 	    }
64831e31b8aSbellard 	    else {
64931e31b8aSbellard 	      int bytes_to_copy = (len > offset) ? offset : len;
65031e31b8aSbellard 	      tmp -= bytes_to_copy;
65131e31b8aSbellard 	      p -= bytes_to_copy;
65231e31b8aSbellard 	      offset -= bytes_to_copy;
65331e31b8aSbellard 	      len -= bytes_to_copy;
65431e31b8aSbellard 	      memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
65531e31b8aSbellard 	    }
65631e31b8aSbellard 	}
65731e31b8aSbellard     }
65831e31b8aSbellard     return p;
65931e31b8aSbellard }
66031e31b8aSbellard 
661992f48a0Sblueswir1 static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
66231e31b8aSbellard                                  struct image_info *info)
66331e31b8aSbellard {
664992f48a0Sblueswir1     abi_ulong stack_base, size, error;
66531e31b8aSbellard     int i;
66631e31b8aSbellard 
66731e31b8aSbellard     /* Create enough stack to hold everything.  If we don't use
66831e31b8aSbellard      * it for args, we'll use it for something else...
66931e31b8aSbellard      */
67009bfb054Sbellard     size = x86_stack_size;
67154936004Sbellard     if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
67254936004Sbellard         size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
67354936004Sbellard     error = target_mmap(0,
67483fb7adfSbellard                         size + qemu_host_page_size,
67531e31b8aSbellard                         PROT_READ | PROT_WRITE,
67609bfb054Sbellard                         MAP_PRIVATE | MAP_ANONYMOUS,
67709bfb054Sbellard                         -1, 0);
67809bfb054Sbellard     if (error == -1) {
67931e31b8aSbellard         perror("stk mmap");
68031e31b8aSbellard         exit(-1);
68131e31b8aSbellard     }
68209bfb054Sbellard     /* we reserve one extra page at the top of the stack as guard */
68383fb7adfSbellard     target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
68431e31b8aSbellard 
68554936004Sbellard     stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
68609bfb054Sbellard     p += stack_base;
68709bfb054Sbellard 
68831e31b8aSbellard     for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
68931e31b8aSbellard 	if (bprm->page[i]) {
69031e31b8aSbellard 	    info->rss++;
691579a97f7Sbellard             /* FIXME - check return value of memcpy_to_target() for failure */
69253a5960aSpbrook 	    memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
69353a5960aSpbrook 	    free(bprm->page[i]);
69431e31b8aSbellard 	}
69554936004Sbellard         stack_base += TARGET_PAGE_SIZE;
69631e31b8aSbellard     }
69731e31b8aSbellard     return p;
69831e31b8aSbellard }
69931e31b8aSbellard 
700992f48a0Sblueswir1 static void set_brk(abi_ulong start, abi_ulong end)
70131e31b8aSbellard {
70231e31b8aSbellard 	/* page-align the start and end addresses... */
70354936004Sbellard         start = HOST_PAGE_ALIGN(start);
70454936004Sbellard         end = HOST_PAGE_ALIGN(end);
70531e31b8aSbellard         if (end <= start)
70631e31b8aSbellard                 return;
70754936004Sbellard         if(target_mmap(start, end - start,
70831e31b8aSbellard                        PROT_READ | PROT_WRITE | PROT_EXEC,
70931e31b8aSbellard                        MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
71031e31b8aSbellard 	    perror("cannot mmap brk");
71131e31b8aSbellard 	    exit(-1);
71231e31b8aSbellard 	}
71331e31b8aSbellard }
71431e31b8aSbellard 
71531e31b8aSbellard 
716853d6f7aSbellard /* We need to explicitly zero any fractional pages after the data
717853d6f7aSbellard    section (i.e. bss).  This would contain the junk from the file that
718853d6f7aSbellard    should not be in memory. */
719992f48a0Sblueswir1 static void padzero(abi_ulong elf_bss, abi_ulong last_bss)
72031e31b8aSbellard {
721992f48a0Sblueswir1         abi_ulong nbyte;
72231e31b8aSbellard 
723768a4a36Sths 	if (elf_bss >= last_bss)
724768a4a36Sths 		return;
725768a4a36Sths 
726853d6f7aSbellard         /* XXX: this is really a hack : if the real host page size is
727853d6f7aSbellard            smaller than the target page size, some pages after the end
728853d6f7aSbellard            of the file may not be mapped. A better fix would be to
729853d6f7aSbellard            patch target_mmap(), but it is more complicated as the file
730853d6f7aSbellard            size must be known */
73183fb7adfSbellard         if (qemu_real_host_page_size < qemu_host_page_size) {
732992f48a0Sblueswir1             abi_ulong end_addr, end_addr1;
73383fb7adfSbellard             end_addr1 = (elf_bss + qemu_real_host_page_size - 1) &
73483fb7adfSbellard                 ~(qemu_real_host_page_size - 1);
735853d6f7aSbellard             end_addr = HOST_PAGE_ALIGN(elf_bss);
736853d6f7aSbellard             if (end_addr1 < end_addr) {
737863cf0b7Sj_mayer                 mmap((void *)g2h(end_addr1), end_addr - end_addr1,
738853d6f7aSbellard                      PROT_READ|PROT_WRITE|PROT_EXEC,
739853d6f7aSbellard                      MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
740853d6f7aSbellard             }
741853d6f7aSbellard         }
742853d6f7aSbellard 
74383fb7adfSbellard         nbyte = elf_bss & (qemu_host_page_size-1);
74431e31b8aSbellard         if (nbyte) {
74583fb7adfSbellard 	    nbyte = qemu_host_page_size - nbyte;
74631e31b8aSbellard 	    do {
7472f619698Sbellard                 /* FIXME - what to do if put_user() fails? */
7482f619698Sbellard 		put_user_u8(0, elf_bss);
74953a5960aSpbrook                 elf_bss++;
75031e31b8aSbellard 	    } while (--nbyte);
75131e31b8aSbellard         }
75231e31b8aSbellard }
75331e31b8aSbellard 
75453a5960aSpbrook 
755992f48a0Sblueswir1 static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
75631e31b8aSbellard                                    struct elfhdr * exec,
757992f48a0Sblueswir1                                    abi_ulong load_addr,
758992f48a0Sblueswir1                                    abi_ulong load_bias,
759992f48a0Sblueswir1                                    abi_ulong interp_load_addr, int ibcs,
76031e31b8aSbellard                                    struct image_info *info)
76131e31b8aSbellard {
762992f48a0Sblueswir1         abi_ulong sp;
76353a5960aSpbrook         int size;
764992f48a0Sblueswir1         abi_ulong u_platform;
76515338fd7Sbellard         const char *k_platform;
766863cf0b7Sj_mayer         const int n = sizeof(elf_addr_t);
76731e31b8aSbellard 
76853a5960aSpbrook         sp = p;
76953a5960aSpbrook         u_platform = 0;
77015338fd7Sbellard         k_platform = ELF_PLATFORM;
77115338fd7Sbellard         if (k_platform) {
77215338fd7Sbellard             size_t len = strlen(k_platform) + 1;
77353a5960aSpbrook             sp -= (len + n - 1) & ~(n - 1);
77453a5960aSpbrook             u_platform = sp;
775579a97f7Sbellard             /* FIXME - check return value of memcpy_to_target() for failure */
77653a5960aSpbrook             memcpy_to_target(sp, k_platform, len);
77715338fd7Sbellard         }
77853a5960aSpbrook 	/*
77953a5960aSpbrook 	 * Force 16 byte _final_ alignment here for generality.
78053a5960aSpbrook 	 */
781992f48a0Sblueswir1         sp = sp &~ (abi_ulong)15;
78253a5960aSpbrook         size = (DLINFO_ITEMS + 1) * 2;
78315338fd7Sbellard         if (k_platform)
78453a5960aSpbrook           size += 2;
785f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS
78653a5960aSpbrook 	size += DLINFO_ARCH_ITEMS * 2;
787f5155289Sbellard #endif
78853a5960aSpbrook         size += envc + argc + 2;
78953a5960aSpbrook 	size += (!ibcs ? 3 : 1);	/* argc itself */
79053a5960aSpbrook         size *= n;
79153a5960aSpbrook         if (size & 15)
79253a5960aSpbrook             sp -= 16 - (size & 15);
793f5155289Sbellard 
794863cf0b7Sj_mayer         /* This is correct because Linux defines
795863cf0b7Sj_mayer          * elf_addr_t as Elf32_Off / Elf64_Off
796863cf0b7Sj_mayer          */
79753a5960aSpbrook #define NEW_AUX_ENT(id, val) do {		\
7982f619698Sbellard             sp -= n; put_user_ual(val, sp);	\
7992f619698Sbellard             sp -= n; put_user_ual(id, sp);	\
80053a5960aSpbrook           } while(0)
8012f619698Sbellard 
8020bccf03dSbellard         NEW_AUX_ENT (AT_NULL, 0);
803f5155289Sbellard 
8040bccf03dSbellard         /* There must be exactly DLINFO_ITEMS entries here.  */
805992f48a0Sblueswir1         NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
806992f48a0Sblueswir1         NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
807992f48a0Sblueswir1         NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
808992f48a0Sblueswir1         NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
809992f48a0Sblueswir1         NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
810992f48a0Sblueswir1         NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
8110bccf03dSbellard         NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
812992f48a0Sblueswir1         NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
813992f48a0Sblueswir1         NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
814992f48a0Sblueswir1         NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
815992f48a0Sblueswir1         NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
816992f48a0Sblueswir1         NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
817a07c67dfSpbrook         NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
81815338fd7Sbellard         if (k_platform)
81953a5960aSpbrook             NEW_AUX_ENT(AT_PLATFORM, u_platform);
820f5155289Sbellard #ifdef ARCH_DLINFO
821f5155289Sbellard 	/*
822f5155289Sbellard 	 * ARCH_DLINFO must come last so platform specific code can enforce
823f5155289Sbellard 	 * special alignment requirements on the AUXV if necessary (eg. PPC).
824f5155289Sbellard 	 */
825f5155289Sbellard         ARCH_DLINFO;
826f5155289Sbellard #endif
827f5155289Sbellard #undef NEW_AUX_ENT
828f5155289Sbellard 
829e5fe0c52Spbrook         sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
83031e31b8aSbellard         return sp;
83131e31b8aSbellard }
83231e31b8aSbellard 
83331e31b8aSbellard 
834992f48a0Sblueswir1 static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
83531e31b8aSbellard                                  int interpreter_fd,
836992f48a0Sblueswir1                                  abi_ulong *interp_load_addr)
83731e31b8aSbellard {
83831e31b8aSbellard 	struct elf_phdr *elf_phdata  =  NULL;
83931e31b8aSbellard 	struct elf_phdr *eppnt;
840992f48a0Sblueswir1 	abi_ulong load_addr = 0;
84131e31b8aSbellard 	int load_addr_set = 0;
84231e31b8aSbellard 	int retval;
843992f48a0Sblueswir1 	abi_ulong last_bss, elf_bss;
844992f48a0Sblueswir1 	abi_ulong error;
84531e31b8aSbellard 	int i;
84631e31b8aSbellard 
84731e31b8aSbellard 	elf_bss = 0;
84831e31b8aSbellard 	last_bss = 0;
84931e31b8aSbellard 	error = 0;
85031e31b8aSbellard 
851644c433cSbellard #ifdef BSWAP_NEEDED
852644c433cSbellard         bswap_ehdr(interp_elf_ex);
853644c433cSbellard #endif
85431e31b8aSbellard 	/* First of all, some simple consistency checks */
85531e31b8aSbellard 	if ((interp_elf_ex->e_type != ET_EXEC &&
85631e31b8aSbellard              interp_elf_ex->e_type != ET_DYN) ||
85731e31b8aSbellard 	   !elf_check_arch(interp_elf_ex->e_machine)) {
858992f48a0Sblueswir1 		return ~((abi_ulong)0UL);
85931e31b8aSbellard 	}
86031e31b8aSbellard 
861644c433cSbellard 
86231e31b8aSbellard 	/* Now read in all of the header information */
86331e31b8aSbellard 
86454936004Sbellard 	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
865992f48a0Sblueswir1 	    return ~(abi_ulong)0UL;
86631e31b8aSbellard 
86731e31b8aSbellard 	elf_phdata =  (struct elf_phdr *)
86831e31b8aSbellard 		malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
86931e31b8aSbellard 
87031e31b8aSbellard 	if (!elf_phdata)
871992f48a0Sblueswir1 	  return ~((abi_ulong)0UL);
87231e31b8aSbellard 
87331e31b8aSbellard 	/*
87431e31b8aSbellard 	 * If the size of this structure has changed, then punt, since
87531e31b8aSbellard 	 * we will be doing the wrong thing.
87631e31b8aSbellard 	 */
87709bfb054Sbellard 	if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
87831e31b8aSbellard 	    free(elf_phdata);
879992f48a0Sblueswir1 	    return ~((abi_ulong)0UL);
88031e31b8aSbellard         }
88131e31b8aSbellard 
88231e31b8aSbellard 	retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
88331e31b8aSbellard 	if(retval >= 0) {
88431e31b8aSbellard 	    retval = read(interpreter_fd,
88531e31b8aSbellard 			   (char *) elf_phdata,
88631e31b8aSbellard 			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
88731e31b8aSbellard 	}
88831e31b8aSbellard 	if (retval < 0) {
88931e31b8aSbellard 		perror("load_elf_interp");
89031e31b8aSbellard 		exit(-1);
89131e31b8aSbellard 		free (elf_phdata);
89231e31b8aSbellard 		return retval;
89331e31b8aSbellard  	}
89431e31b8aSbellard #ifdef BSWAP_NEEDED
89531e31b8aSbellard 	eppnt = elf_phdata;
89631e31b8aSbellard 	for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
89731e31b8aSbellard             bswap_phdr(eppnt);
89831e31b8aSbellard         }
89931e31b8aSbellard #endif
90009bfb054Sbellard 
90109bfb054Sbellard         if (interp_elf_ex->e_type == ET_DYN) {
902e91c8a77Sths             /* in order to avoid hardcoding the interpreter load
90309bfb054Sbellard                address in qemu, we allocate a big enough memory zone */
90454936004Sbellard             error = target_mmap(0, INTERP_MAP_SIZE,
90509bfb054Sbellard                                 PROT_NONE, MAP_PRIVATE | MAP_ANON,
90609bfb054Sbellard                                 -1, 0);
90709bfb054Sbellard             if (error == -1) {
90809bfb054Sbellard                 perror("mmap");
90909bfb054Sbellard                 exit(-1);
91009bfb054Sbellard             }
91109bfb054Sbellard             load_addr = error;
91209bfb054Sbellard             load_addr_set = 1;
91309bfb054Sbellard         }
91409bfb054Sbellard 
91531e31b8aSbellard 	eppnt = elf_phdata;
91631e31b8aSbellard 	for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
91731e31b8aSbellard 	  if (eppnt->p_type == PT_LOAD) {
91831e31b8aSbellard 	    int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
91931e31b8aSbellard 	    int elf_prot = 0;
920992f48a0Sblueswir1 	    abi_ulong vaddr = 0;
921992f48a0Sblueswir1 	    abi_ulong k;
92231e31b8aSbellard 
92331e31b8aSbellard 	    if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
92431e31b8aSbellard 	    if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
92531e31b8aSbellard 	    if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
92631e31b8aSbellard 	    if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
92731e31b8aSbellard 	    	elf_type |= MAP_FIXED;
92831e31b8aSbellard 	    	vaddr = eppnt->p_vaddr;
92931e31b8aSbellard 	    }
93054936004Sbellard 	    error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
93154936004Sbellard 		 eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
93231e31b8aSbellard 		 elf_prot,
93331e31b8aSbellard 		 elf_type,
93431e31b8aSbellard 		 interpreter_fd,
93554936004Sbellard 		 eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
93631e31b8aSbellard 
937e89f07d3Spbrook 	    if (error == -1) {
93831e31b8aSbellard 	      /* Real error */
93931e31b8aSbellard 	      close(interpreter_fd);
94031e31b8aSbellard 	      free(elf_phdata);
941992f48a0Sblueswir1 	      return ~((abi_ulong)0UL);
94231e31b8aSbellard 	    }
94331e31b8aSbellard 
94431e31b8aSbellard 	    if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
94531e31b8aSbellard 	      load_addr = error;
94631e31b8aSbellard 	      load_addr_set = 1;
94731e31b8aSbellard 	    }
94831e31b8aSbellard 
94931e31b8aSbellard 	    /*
95031e31b8aSbellard 	     * Find the end of the file  mapping for this phdr, and keep
95131e31b8aSbellard 	     * track of the largest address we see for this.
95231e31b8aSbellard 	     */
95331e31b8aSbellard 	    k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
95431e31b8aSbellard 	    if (k > elf_bss) elf_bss = k;
95531e31b8aSbellard 
95631e31b8aSbellard 	    /*
95731e31b8aSbellard 	     * Do the same thing for the memory mapping - between
95831e31b8aSbellard 	     * elf_bss and last_bss is the bss section.
95931e31b8aSbellard 	     */
96031e31b8aSbellard 	    k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
96131e31b8aSbellard 	    if (k > last_bss) last_bss = k;
96231e31b8aSbellard 	  }
96331e31b8aSbellard 
96431e31b8aSbellard 	/* Now use mmap to map the library into memory. */
96531e31b8aSbellard 
96631e31b8aSbellard 	close(interpreter_fd);
96731e31b8aSbellard 
96831e31b8aSbellard 	/*
96931e31b8aSbellard 	 * Now fill out the bss section.  First pad the last page up
97031e31b8aSbellard 	 * to the page boundary, and then perform a mmap to make sure
97131e31b8aSbellard 	 * that there are zeromapped pages up to and including the last
97231e31b8aSbellard 	 * bss page.
97331e31b8aSbellard 	 */
974768a4a36Sths 	padzero(elf_bss, last_bss);
97583fb7adfSbellard 	elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */
97631e31b8aSbellard 
97731e31b8aSbellard 	/* Map the last of the bss segment */
97831e31b8aSbellard 	if (last_bss > elf_bss) {
97954936004Sbellard             target_mmap(elf_bss, last_bss-elf_bss,
98031e31b8aSbellard                         PROT_READ|PROT_WRITE|PROT_EXEC,
98131e31b8aSbellard                         MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
98231e31b8aSbellard 	}
98331e31b8aSbellard 	free(elf_phdata);
98431e31b8aSbellard 
98531e31b8aSbellard 	*interp_load_addr = load_addr;
986992f48a0Sblueswir1 	return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
98731e31b8aSbellard }
98831e31b8aSbellard 
989689f936fSbellard /* Best attempt to load symbols from this ELF object. */
990689f936fSbellard static void load_symbols(struct elfhdr *hdr, int fd)
991689f936fSbellard {
992689f936fSbellard     unsigned int i;
993689f936fSbellard     struct elf_shdr sechdr, symtab, strtab;
994689f936fSbellard     char *strings;
995e80cfcfcSbellard     struct syminfo *s;
9960774bed1Sblueswir1 #if (ELF_CLASS == ELFCLASS64)
9970774bed1Sblueswir1     // Disas uses 32 bit symbols
9980774bed1Sblueswir1     struct elf32_sym *syms32 = NULL;
9990774bed1Sblueswir1     struct elf_sym *sym;
10000774bed1Sblueswir1 #endif
100131e31b8aSbellard 
1002689f936fSbellard     lseek(fd, hdr->e_shoff, SEEK_SET);
1003689f936fSbellard     for (i = 0; i < hdr->e_shnum; i++) {
1004689f936fSbellard 	if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
1005689f936fSbellard 	    return;
1006689f936fSbellard #ifdef BSWAP_NEEDED
1007689f936fSbellard 	bswap_shdr(&sechdr);
1008689f936fSbellard #endif
1009689f936fSbellard 	if (sechdr.sh_type == SHT_SYMTAB) {
1010689f936fSbellard 	    symtab = sechdr;
1011689f936fSbellard 	    lseek(fd, hdr->e_shoff
1012689f936fSbellard 		  + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
1013689f936fSbellard 	    if (read(fd, &strtab, sizeof(strtab))
1014689f936fSbellard 		!= sizeof(strtab))
1015689f936fSbellard 		return;
1016689f936fSbellard #ifdef BSWAP_NEEDED
1017689f936fSbellard 	    bswap_shdr(&strtab);
1018689f936fSbellard #endif
1019689f936fSbellard 	    goto found;
1020689f936fSbellard 	}
1021689f936fSbellard     }
1022689f936fSbellard     return; /* Shouldn't happen... */
1023689f936fSbellard 
1024689f936fSbellard  found:
1025689f936fSbellard     /* Now know where the strtab and symtab are.  Snarf them. */
1026e80cfcfcSbellard     s = malloc(sizeof(*s));
1027e80cfcfcSbellard     s->disas_symtab = malloc(symtab.sh_size);
10280774bed1Sblueswir1 #if (ELF_CLASS == ELFCLASS64)
10290774bed1Sblueswir1     syms32 = malloc(symtab.sh_size / sizeof(struct elf_sym)
10300774bed1Sblueswir1                     * sizeof(struct elf32_sym));
10310774bed1Sblueswir1 #endif
1032e80cfcfcSbellard     s->disas_strtab = strings = malloc(strtab.sh_size);
1033e80cfcfcSbellard     if (!s->disas_symtab || !s->disas_strtab)
1034689f936fSbellard 	return;
1035689f936fSbellard 
1036689f936fSbellard     lseek(fd, symtab.sh_offset, SEEK_SET);
1037e80cfcfcSbellard     if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size)
1038689f936fSbellard 	return;
1039689f936fSbellard 
10400774bed1Sblueswir1     for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) {
1041689f936fSbellard #ifdef BSWAP_NEEDED
1042e80cfcfcSbellard 	bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i);
1043689f936fSbellard #endif
10440774bed1Sblueswir1 #if (ELF_CLASS == ELFCLASS64)
10450774bed1Sblueswir1         sym = s->disas_symtab + sizeof(struct elf_sym)*i;
10460774bed1Sblueswir1         syms32[i].st_name = sym->st_name;
10470774bed1Sblueswir1         syms32[i].st_info = sym->st_info;
10480774bed1Sblueswir1         syms32[i].st_other = sym->st_other;
10490774bed1Sblueswir1         syms32[i].st_shndx = sym->st_shndx;
10500774bed1Sblueswir1         syms32[i].st_value = sym->st_value & 0xffffffff;
10510774bed1Sblueswir1         syms32[i].st_size = sym->st_size & 0xffffffff;
10520774bed1Sblueswir1 #endif
10530774bed1Sblueswir1     }
1054689f936fSbellard 
10550774bed1Sblueswir1 #if (ELF_CLASS == ELFCLASS64)
10560774bed1Sblueswir1     free(s->disas_symtab);
10570774bed1Sblueswir1     s->disas_symtab = syms32;
10580774bed1Sblueswir1 #endif
1059689f936fSbellard     lseek(fd, strtab.sh_offset, SEEK_SET);
1060689f936fSbellard     if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
1061689f936fSbellard 	return;
1062e80cfcfcSbellard     s->disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
1063e80cfcfcSbellard     s->next = syminfos;
1064e80cfcfcSbellard     syminfos = s;
1065689f936fSbellard }
106631e31b8aSbellard 
1067e5fe0c52Spbrook int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
106831e31b8aSbellard                     struct image_info * info)
106931e31b8aSbellard {
107031e31b8aSbellard     struct elfhdr elf_ex;
107131e31b8aSbellard     struct elfhdr interp_elf_ex;
107231e31b8aSbellard     struct exec interp_ex;
107331e31b8aSbellard     int interpreter_fd = -1; /* avoid warning */
1074992f48a0Sblueswir1     abi_ulong load_addr, load_bias;
107531e31b8aSbellard     int load_addr_set = 0;
107631e31b8aSbellard     unsigned int interpreter_type = INTERPRETER_NONE;
107731e31b8aSbellard     unsigned char ibcs2_interpreter;
107831e31b8aSbellard     int i;
1079992f48a0Sblueswir1     abi_ulong mapped_addr;
108031e31b8aSbellard     struct elf_phdr * elf_ppnt;
108131e31b8aSbellard     struct elf_phdr *elf_phdata;
1082992f48a0Sblueswir1     abi_ulong elf_bss, k, elf_brk;
108331e31b8aSbellard     int retval;
108431e31b8aSbellard     char * elf_interpreter;
1085992f48a0Sblueswir1     abi_ulong elf_entry, interp_load_addr = 0;
108631e31b8aSbellard     int status;
1087992f48a0Sblueswir1     abi_ulong start_code, end_code, start_data, end_data;
1088992f48a0Sblueswir1     abi_ulong reloc_func_desc = 0;
1089992f48a0Sblueswir1     abi_ulong elf_stack;
109031e31b8aSbellard     char passed_fileno[6];
109131e31b8aSbellard 
109231e31b8aSbellard     ibcs2_interpreter = 0;
109331e31b8aSbellard     status = 0;
109431e31b8aSbellard     load_addr = 0;
109509bfb054Sbellard     load_bias = 0;
109631e31b8aSbellard     elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
109731e31b8aSbellard #ifdef BSWAP_NEEDED
109831e31b8aSbellard     bswap_ehdr(&elf_ex);
109931e31b8aSbellard #endif
110031e31b8aSbellard 
110131e31b8aSbellard     /* First of all, some simple consistency checks */
110231e31b8aSbellard     if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
110331e31b8aSbellard        				(! elf_check_arch(elf_ex.e_machine))) {
110431e31b8aSbellard 	    return -ENOEXEC;
110531e31b8aSbellard     }
110631e31b8aSbellard 
1107e5fe0c52Spbrook     bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
1108e5fe0c52Spbrook     bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
1109e5fe0c52Spbrook     bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
1110e5fe0c52Spbrook     if (!bprm->p) {
1111e5fe0c52Spbrook         retval = -E2BIG;
1112e5fe0c52Spbrook     }
1113e5fe0c52Spbrook 
111431e31b8aSbellard     /* Now read in all of the header information */
111531e31b8aSbellard     elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
111631e31b8aSbellard     if (elf_phdata == NULL) {
111731e31b8aSbellard 	return -ENOMEM;
111831e31b8aSbellard     }
111931e31b8aSbellard 
112031e31b8aSbellard     retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
112131e31b8aSbellard     if(retval > 0) {
112231e31b8aSbellard 	retval = read(bprm->fd, (char *) elf_phdata,
112331e31b8aSbellard 				elf_ex.e_phentsize * elf_ex.e_phnum);
112431e31b8aSbellard     }
112531e31b8aSbellard 
112631e31b8aSbellard     if (retval < 0) {
112731e31b8aSbellard 	perror("load_elf_binary");
112831e31b8aSbellard 	exit(-1);
112931e31b8aSbellard 	free (elf_phdata);
113031e31b8aSbellard 	return -errno;
113131e31b8aSbellard     }
113231e31b8aSbellard 
1133b17780d5Sbellard #ifdef BSWAP_NEEDED
1134b17780d5Sbellard     elf_ppnt = elf_phdata;
1135b17780d5Sbellard     for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
1136b17780d5Sbellard         bswap_phdr(elf_ppnt);
1137b17780d5Sbellard     }
1138b17780d5Sbellard #endif
113931e31b8aSbellard     elf_ppnt = elf_phdata;
114031e31b8aSbellard 
114131e31b8aSbellard     elf_bss = 0;
114231e31b8aSbellard     elf_brk = 0;
114331e31b8aSbellard 
114431e31b8aSbellard 
1145992f48a0Sblueswir1     elf_stack = ~((abi_ulong)0UL);
114631e31b8aSbellard     elf_interpreter = NULL;
1147992f48a0Sblueswir1     start_code = ~((abi_ulong)0UL);
114831e31b8aSbellard     end_code = 0;
1149863cf0b7Sj_mayer     start_data = 0;
115031e31b8aSbellard     end_data = 0;
115131e31b8aSbellard 
115231e31b8aSbellard     for(i=0;i < elf_ex.e_phnum; i++) {
115331e31b8aSbellard 	if (elf_ppnt->p_type == PT_INTERP) {
115431e31b8aSbellard 	    if ( elf_interpreter != NULL )
115531e31b8aSbellard 	    {
115631e31b8aSbellard 		free (elf_phdata);
115731e31b8aSbellard 		free(elf_interpreter);
115831e31b8aSbellard 		close(bprm->fd);
115931e31b8aSbellard 		return -EINVAL;
116031e31b8aSbellard 	    }
116131e31b8aSbellard 
116231e31b8aSbellard 	    /* This is the program interpreter used for
116331e31b8aSbellard 	     * shared libraries - for now assume that this
116431e31b8aSbellard 	     * is an a.out format binary
116531e31b8aSbellard 	     */
116631e31b8aSbellard 
116732ce6337Sbellard 	    elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
116831e31b8aSbellard 
116931e31b8aSbellard 	    if (elf_interpreter == NULL) {
117031e31b8aSbellard 		free (elf_phdata);
117131e31b8aSbellard 		close(bprm->fd);
117231e31b8aSbellard 		return -ENOMEM;
117331e31b8aSbellard 	    }
117431e31b8aSbellard 
117531e31b8aSbellard 	    retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
117631e31b8aSbellard 	    if(retval >= 0) {
117732ce6337Sbellard 		retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
117831e31b8aSbellard 	    }
117931e31b8aSbellard 	    if(retval < 0) {
118031e31b8aSbellard 	 	perror("load_elf_binary2");
118131e31b8aSbellard 		exit(-1);
118231e31b8aSbellard 	    }
118331e31b8aSbellard 
118431e31b8aSbellard 	    /* If the program interpreter is one of these two,
118531e31b8aSbellard 	       then assume an iBCS2 image. Otherwise assume
118631e31b8aSbellard 	       a native linux image. */
118731e31b8aSbellard 
118831e31b8aSbellard 	    /* JRP - Need to add X86 lib dir stuff here... */
118931e31b8aSbellard 
119031e31b8aSbellard 	    if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
119131e31b8aSbellard 		strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
119231e31b8aSbellard 	      ibcs2_interpreter = 1;
119331e31b8aSbellard 	    }
119431e31b8aSbellard 
119531e31b8aSbellard #if 0
119631e31b8aSbellard 	    printf("Using ELF interpreter %s\n", elf_interpreter);
119731e31b8aSbellard #endif
119831e31b8aSbellard 	    if (retval >= 0) {
119932ce6337Sbellard 		retval = open(path(elf_interpreter), O_RDONLY);
120031e31b8aSbellard 		if(retval >= 0) {
120131e31b8aSbellard 		    interpreter_fd = retval;
120231e31b8aSbellard 		}
120331e31b8aSbellard 		else {
120431e31b8aSbellard 		    perror(elf_interpreter);
120531e31b8aSbellard 		    exit(-1);
120631e31b8aSbellard 		    /* retval = -errno; */
120731e31b8aSbellard 		}
120831e31b8aSbellard 	    }
120931e31b8aSbellard 
121031e31b8aSbellard 	    if (retval >= 0) {
121131e31b8aSbellard 		retval = lseek(interpreter_fd, 0, SEEK_SET);
121231e31b8aSbellard 		if(retval >= 0) {
121331e31b8aSbellard 		    retval = read(interpreter_fd,bprm->buf,128);
121431e31b8aSbellard 		}
121531e31b8aSbellard 	    }
121631e31b8aSbellard 	    if (retval >= 0) {
121731e31b8aSbellard 		interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
121831e31b8aSbellard 		interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */
121931e31b8aSbellard 	    }
122031e31b8aSbellard 	    if (retval < 0) {
122131e31b8aSbellard 		perror("load_elf_binary3");
122231e31b8aSbellard 		exit(-1);
122331e31b8aSbellard 		free (elf_phdata);
122431e31b8aSbellard 		free(elf_interpreter);
122531e31b8aSbellard 		close(bprm->fd);
122631e31b8aSbellard 		return retval;
122731e31b8aSbellard 	    }
122831e31b8aSbellard 	}
122931e31b8aSbellard 	elf_ppnt++;
123031e31b8aSbellard     }
123131e31b8aSbellard 
123231e31b8aSbellard     /* Some simple consistency checks for the interpreter */
123331e31b8aSbellard     if (elf_interpreter){
123431e31b8aSbellard 	interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
123531e31b8aSbellard 
123631e31b8aSbellard 	/* Now figure out which format our binary is */
123731e31b8aSbellard 	if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
123831e31b8aSbellard 	    	(N_MAGIC(interp_ex) != QMAGIC)) {
123931e31b8aSbellard 	  interpreter_type = INTERPRETER_ELF;
124031e31b8aSbellard 	}
124131e31b8aSbellard 
124231e31b8aSbellard 	if (interp_elf_ex.e_ident[0] != 0x7f ||
1243*b55266b5Sblueswir1             strncmp((char *)&interp_elf_ex.e_ident[1], "ELF",3) != 0) {
124431e31b8aSbellard 	    interpreter_type &= ~INTERPRETER_ELF;
124531e31b8aSbellard 	}
124631e31b8aSbellard 
124731e31b8aSbellard 	if (!interpreter_type) {
124831e31b8aSbellard 	    free(elf_interpreter);
124931e31b8aSbellard 	    free(elf_phdata);
125031e31b8aSbellard 	    close(bprm->fd);
125131e31b8aSbellard 	    return -ELIBBAD;
125231e31b8aSbellard 	}
125331e31b8aSbellard     }
125431e31b8aSbellard 
125531e31b8aSbellard     /* OK, we are done with that, now set up the arg stuff,
125631e31b8aSbellard        and then start this sucker up */
125731e31b8aSbellard 
1258e5fe0c52Spbrook     {
125931e31b8aSbellard 	char * passed_p;
126031e31b8aSbellard 
126131e31b8aSbellard 	if (interpreter_type == INTERPRETER_AOUT) {
1262eba2af63Sbellard 	    snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
126331e31b8aSbellard 	    passed_p = passed_fileno;
126431e31b8aSbellard 
126531e31b8aSbellard 	    if (elf_interpreter) {
1266e5fe0c52Spbrook 		bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p);
126731e31b8aSbellard 		bprm->argc++;
126831e31b8aSbellard 	    }
126931e31b8aSbellard 	}
127031e31b8aSbellard 	if (!bprm->p) {
127131e31b8aSbellard 	    if (elf_interpreter) {
127231e31b8aSbellard 	        free(elf_interpreter);
127331e31b8aSbellard 	    }
127431e31b8aSbellard 	    free (elf_phdata);
127531e31b8aSbellard 	    close(bprm->fd);
127631e31b8aSbellard 	    return -E2BIG;
127731e31b8aSbellard 	}
127831e31b8aSbellard     }
127931e31b8aSbellard 
128031e31b8aSbellard     /* OK, This is the point of no return */
128131e31b8aSbellard     info->end_data = 0;
128231e31b8aSbellard     info->end_code = 0;
1283992f48a0Sblueswir1     info->start_mmap = (abi_ulong)ELF_START_MMAP;
128431e31b8aSbellard     info->mmap = 0;
1285992f48a0Sblueswir1     elf_entry = (abi_ulong) elf_ex.e_entry;
128631e31b8aSbellard 
128731e31b8aSbellard     /* Do this so that we can load the interpreter, if need be.  We will
128831e31b8aSbellard        change some of these later */
128931e31b8aSbellard     info->rss = 0;
129031e31b8aSbellard     bprm->p = setup_arg_pages(bprm->p, bprm, info);
129131e31b8aSbellard     info->start_stack = bprm->p;
129231e31b8aSbellard 
129331e31b8aSbellard     /* Now we do a little grungy work by mmaping the ELF image into
129431e31b8aSbellard      * the correct location in memory.  At this point, we assume that
129531e31b8aSbellard      * the image should be loaded at fixed address, not at a variable
129631e31b8aSbellard      * address.
129731e31b8aSbellard      */
129831e31b8aSbellard 
129931e31b8aSbellard     for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
130031e31b8aSbellard         int elf_prot = 0;
130109bfb054Sbellard         int elf_flags = 0;
1302992f48a0Sblueswir1         abi_ulong error;
130309bfb054Sbellard 
130409bfb054Sbellard 	if (elf_ppnt->p_type != PT_LOAD)
130509bfb054Sbellard             continue;
130609bfb054Sbellard 
130731e31b8aSbellard         if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
130831e31b8aSbellard         if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
130931e31b8aSbellard         if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
131009bfb054Sbellard         elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
131109bfb054Sbellard         if (elf_ex.e_type == ET_EXEC || load_addr_set) {
131209bfb054Sbellard             elf_flags |= MAP_FIXED;
131309bfb054Sbellard         } else if (elf_ex.e_type == ET_DYN) {
131409bfb054Sbellard             /* Try and get dynamic programs out of the way of the default mmap
131509bfb054Sbellard                base, as well as whatever program they might try to exec.  This
131609bfb054Sbellard                is because the brk will follow the loader, and is not movable.  */
131709bfb054Sbellard             /* NOTE: for qemu, we do a big mmap to get enough space
1318e91c8a77Sths                without hardcoding any address */
131954936004Sbellard             error = target_mmap(0, ET_DYN_MAP_SIZE,
132009bfb054Sbellard                                 PROT_NONE, MAP_PRIVATE | MAP_ANON,
132109bfb054Sbellard                                 -1, 0);
132209bfb054Sbellard             if (error == -1) {
132309bfb054Sbellard                 perror("mmap");
132409bfb054Sbellard                 exit(-1);
132509bfb054Sbellard             }
132654936004Sbellard             load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
132709bfb054Sbellard         }
132831e31b8aSbellard 
132954936004Sbellard         error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
133031e31b8aSbellard                             (elf_ppnt->p_filesz +
133154936004Sbellard                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
133231e31b8aSbellard                             elf_prot,
133331e31b8aSbellard                             (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
133431e31b8aSbellard                             bprm->fd,
133531e31b8aSbellard                             (elf_ppnt->p_offset -
133654936004Sbellard                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
133709bfb054Sbellard         if (error == -1) {
133831e31b8aSbellard             perror("mmap");
133931e31b8aSbellard             exit(-1);
134031e31b8aSbellard         }
134131e31b8aSbellard 
134231e31b8aSbellard #ifdef LOW_ELF_STACK
134354936004Sbellard         if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
134454936004Sbellard             elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr);
134531e31b8aSbellard #endif
134631e31b8aSbellard 
134731e31b8aSbellard         if (!load_addr_set) {
134831e31b8aSbellard             load_addr_set = 1;
134909bfb054Sbellard             load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
135009bfb054Sbellard             if (elf_ex.e_type == ET_DYN) {
135109bfb054Sbellard                 load_bias += error -
135254936004Sbellard                     TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
135309bfb054Sbellard                 load_addr += load_bias;
135484409ddbSj_mayer                 reloc_func_desc = load_bias;
135509bfb054Sbellard             }
135631e31b8aSbellard         }
135731e31b8aSbellard         k = elf_ppnt->p_vaddr;
135809bfb054Sbellard         if (k < start_code)
135909bfb054Sbellard             start_code = k;
1360863cf0b7Sj_mayer         if (start_data < k)
1361863cf0b7Sj_mayer             start_data = k;
136231e31b8aSbellard         k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
136309bfb054Sbellard         if (k > elf_bss)
136409bfb054Sbellard             elf_bss = k;
136531e31b8aSbellard         if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
136631e31b8aSbellard             end_code = k;
136709bfb054Sbellard         if (end_data < k)
136809bfb054Sbellard             end_data = k;
136931e31b8aSbellard         k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
137031e31b8aSbellard         if (k > elf_brk) elf_brk = k;
137131e31b8aSbellard     }
137209bfb054Sbellard 
137309bfb054Sbellard     elf_entry += load_bias;
137409bfb054Sbellard     elf_bss += load_bias;
137509bfb054Sbellard     elf_brk += load_bias;
137609bfb054Sbellard     start_code += load_bias;
137709bfb054Sbellard     end_code += load_bias;
1378863cf0b7Sj_mayer     start_data += load_bias;
137909bfb054Sbellard     end_data += load_bias;
138031e31b8aSbellard 
138131e31b8aSbellard     if (elf_interpreter) {
138231e31b8aSbellard 	if (interpreter_type & 1) {
138331e31b8aSbellard 	    elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
138431e31b8aSbellard 	}
138531e31b8aSbellard 	else if (interpreter_type & 2) {
138631e31b8aSbellard 	    elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
138731e31b8aSbellard 					    &interp_load_addr);
138831e31b8aSbellard 	}
138984409ddbSj_mayer         reloc_func_desc = interp_load_addr;
139031e31b8aSbellard 
139131e31b8aSbellard 	close(interpreter_fd);
139231e31b8aSbellard 	free(elf_interpreter);
139331e31b8aSbellard 
1394992f48a0Sblueswir1 	if (elf_entry == ~((abi_ulong)0UL)) {
139531e31b8aSbellard 	    printf("Unable to load interpreter\n");
139631e31b8aSbellard 	    free(elf_phdata);
139731e31b8aSbellard 	    exit(-1);
139831e31b8aSbellard 	    return 0;
139931e31b8aSbellard 	}
140031e31b8aSbellard     }
140131e31b8aSbellard 
140231e31b8aSbellard     free(elf_phdata);
140331e31b8aSbellard 
1404689f936fSbellard     if (loglevel)
1405689f936fSbellard 	load_symbols(&elf_ex, bprm->fd);
1406689f936fSbellard 
140731e31b8aSbellard     if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
140831e31b8aSbellard     info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
140931e31b8aSbellard 
141031e31b8aSbellard #ifdef LOW_ELF_STACK
141131e31b8aSbellard     info->start_stack = bprm->p = elf_stack - 4;
141231e31b8aSbellard #endif
141353a5960aSpbrook     bprm->p = create_elf_tables(bprm->p,
141431e31b8aSbellard 		    bprm->argc,
141531e31b8aSbellard 		    bprm->envc,
1416a1516e92Sbellard                     &elf_ex,
141709bfb054Sbellard                     load_addr, load_bias,
141831e31b8aSbellard 		    interp_load_addr,
141931e31b8aSbellard 		    (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
142031e31b8aSbellard 		    info);
142192a343daSj_mayer     info->load_addr = reloc_func_desc;
142231e31b8aSbellard     info->start_brk = info->brk = elf_brk;
142331e31b8aSbellard     info->end_code = end_code;
142431e31b8aSbellard     info->start_code = start_code;
1425863cf0b7Sj_mayer     info->start_data = start_data;
142631e31b8aSbellard     info->end_data = end_data;
142731e31b8aSbellard     info->start_stack = bprm->p;
142831e31b8aSbellard 
142931e31b8aSbellard     /* Calling set_brk effectively mmaps the pages that we need for the bss and break
143031e31b8aSbellard        sections */
143131e31b8aSbellard     set_brk(elf_bss, elf_brk);
143231e31b8aSbellard 
1433768a4a36Sths     padzero(elf_bss, elf_brk);
143431e31b8aSbellard 
143531e31b8aSbellard #if 0
143631e31b8aSbellard     printf("(start_brk) %x\n" , info->start_brk);
143731e31b8aSbellard     printf("(end_code) %x\n" , info->end_code);
143831e31b8aSbellard     printf("(start_code) %x\n" , info->start_code);
143931e31b8aSbellard     printf("(end_data) %x\n" , info->end_data);
144031e31b8aSbellard     printf("(start_stack) %x\n" , info->start_stack);
144131e31b8aSbellard     printf("(brk) %x\n" , info->brk);
144231e31b8aSbellard #endif
144331e31b8aSbellard 
144431e31b8aSbellard     if ( info->personality == PER_SVR4 )
144531e31b8aSbellard     {
144631e31b8aSbellard 	    /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
144731e31b8aSbellard 	       and some applications "depend" upon this behavior.
144831e31b8aSbellard 	       Since we do not have the power to recompile these, we
144931e31b8aSbellard 	       emulate the SVr4 behavior.  Sigh.  */
145083fb7adfSbellard 	    mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
145131e31b8aSbellard                                       MAP_FIXED | MAP_PRIVATE, -1, 0);
145231e31b8aSbellard     }
145331e31b8aSbellard 
145431e31b8aSbellard     info->entry = elf_entry;
145531e31b8aSbellard 
145631e31b8aSbellard     return 0;
145731e31b8aSbellard }
145831e31b8aSbellard 
145931e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd)
146031e31b8aSbellard {
146131e31b8aSbellard     printf("a.out interpreter not yet supported\n");
146231e31b8aSbellard     return(0);
146331e31b8aSbellard }
146431e31b8aSbellard 
1465e5fe0c52Spbrook void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
1466e5fe0c52Spbrook {
1467e5fe0c52Spbrook     init_thread(regs, infop);
1468e5fe0c52Spbrook }
1469