xref: /qemu/linux-user/elfload.c (revision e91c8a778349982eb49fd319ab6506911e2d837e)
131e31b8aSbellard /* This is the Linux kernel elf-loading code, ported into user space */
231e31b8aSbellard 
331e31b8aSbellard #include <stdio.h>
431e31b8aSbellard #include <sys/types.h>
531e31b8aSbellard #include <fcntl.h>
631e31b8aSbellard #include <errno.h>
731e31b8aSbellard #include <unistd.h>
831e31b8aSbellard #include <sys/mman.h>
931e31b8aSbellard #include <stdlib.h>
1031e31b8aSbellard #include <string.h>
1131e31b8aSbellard 
123ef693a0Sbellard #include "qemu.h"
13689f936fSbellard #include "disas.h"
1431e31b8aSbellard 
1583fb7adfSbellard /* this flag is uneffective under linux too, should be deleted */
1683fb7adfSbellard #ifndef MAP_DENYWRITE
1783fb7adfSbellard #define MAP_DENYWRITE 0
1883fb7adfSbellard #endif
1983fb7adfSbellard 
2083fb7adfSbellard /* should probably go in elf.h */
2183fb7adfSbellard #ifndef ELIBBAD
2283fb7adfSbellard #define ELIBBAD 80
2383fb7adfSbellard #endif
2483fb7adfSbellard 
2530ac07d4Sbellard #ifdef TARGET_I386
2630ac07d4Sbellard 
2715338fd7Sbellard #define ELF_PLATFORM get_elf_platform()
2815338fd7Sbellard 
2915338fd7Sbellard static const char *get_elf_platform(void)
3015338fd7Sbellard {
3115338fd7Sbellard     static char elf_platform[] = "i386";
3215338fd7Sbellard     int family = (global_env->cpuid_version >> 8) & 0xff;
3315338fd7Sbellard     if (family > 6)
3415338fd7Sbellard         family = 6;
3515338fd7Sbellard     if (family >= 3)
3615338fd7Sbellard         elf_platform[1] = '0' + family;
3715338fd7Sbellard     return elf_platform;
3815338fd7Sbellard }
3915338fd7Sbellard 
4015338fd7Sbellard #define ELF_HWCAP get_elf_hwcap()
4115338fd7Sbellard 
4215338fd7Sbellard static uint32_t get_elf_hwcap(void)
4315338fd7Sbellard {
4415338fd7Sbellard   return global_env->cpuid_features;
4515338fd7Sbellard }
4615338fd7Sbellard 
4784409ddbSj_mayer #ifdef TARGET_X86_64
4884409ddbSj_mayer #define ELF_START_MMAP 0x2aaaaab000ULL
4984409ddbSj_mayer #define elf_check_arch(x) ( ((x) == ELF_ARCH) )
5084409ddbSj_mayer 
5184409ddbSj_mayer #define ELF_CLASS      ELFCLASS64
5284409ddbSj_mayer #define ELF_DATA       ELFDATA2LSB
5384409ddbSj_mayer #define ELF_ARCH       EM_X86_64
5484409ddbSj_mayer 
5584409ddbSj_mayer static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
5684409ddbSj_mayer {
5784409ddbSj_mayer     regs->rax = 0;
5884409ddbSj_mayer     regs->rsp = infop->start_stack;
5984409ddbSj_mayer     regs->rip = infop->entry;
6084409ddbSj_mayer }
6184409ddbSj_mayer 
6284409ddbSj_mayer #else
6384409ddbSj_mayer 
6430ac07d4Sbellard #define ELF_START_MMAP 0x80000000
6530ac07d4Sbellard 
6630ac07d4Sbellard /*
6730ac07d4Sbellard  * This is used to ensure we don't load something for the wrong architecture.
6830ac07d4Sbellard  */
6930ac07d4Sbellard #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
7030ac07d4Sbellard 
7130ac07d4Sbellard /*
7230ac07d4Sbellard  * These are used to set parameters in the core dumps.
7330ac07d4Sbellard  */
7430ac07d4Sbellard #define ELF_CLASS	ELFCLASS32
7530ac07d4Sbellard #define ELF_DATA	ELFDATA2LSB
7630ac07d4Sbellard #define ELF_ARCH	EM_386
7730ac07d4Sbellard 
78e5fe0c52Spbrook static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
79e5fe0c52Spbrook {
80e5fe0c52Spbrook     regs->esp = infop->start_stack;
81e5fe0c52Spbrook     regs->eip = infop->entry;
82e5fe0c52Spbrook 
8330ac07d4Sbellard     /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
8430ac07d4Sbellard        starts %edx contains a pointer to a function which might be
8530ac07d4Sbellard        registered using `atexit'.  This provides a mean for the
8630ac07d4Sbellard        dynamic linker to call DT_FINI functions for shared libraries
8730ac07d4Sbellard        that have been loaded before the code runs.
8830ac07d4Sbellard 
8930ac07d4Sbellard        A value of 0 tells we have no such handler.  */
90e5fe0c52Spbrook     regs->edx = 0;
91b346ff46Sbellard }
9284409ddbSj_mayer #endif
93b346ff46Sbellard 
94b346ff46Sbellard #define USE_ELF_CORE_DUMP
95b346ff46Sbellard #define ELF_EXEC_PAGESIZE	4096
96b346ff46Sbellard 
97b346ff46Sbellard #endif
98b346ff46Sbellard 
99b346ff46Sbellard #ifdef TARGET_ARM
100b346ff46Sbellard 
101b346ff46Sbellard #define ELF_START_MMAP 0x80000000
102b346ff46Sbellard 
103b346ff46Sbellard #define elf_check_arch(x) ( (x) == EM_ARM )
104b346ff46Sbellard 
105b346ff46Sbellard #define ELF_CLASS	ELFCLASS32
106b346ff46Sbellard #ifdef TARGET_WORDS_BIGENDIAN
107b346ff46Sbellard #define ELF_DATA	ELFDATA2MSB
108b346ff46Sbellard #else
109b346ff46Sbellard #define ELF_DATA	ELFDATA2LSB
110b346ff46Sbellard #endif
111b346ff46Sbellard #define ELF_ARCH	EM_ARM
112b346ff46Sbellard 
113b346ff46Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
114b346ff46Sbellard {
11553a5960aSpbrook     target_long stack = infop->start_stack;
116b346ff46Sbellard     memset(regs, 0, sizeof(*regs));
117b346ff46Sbellard     regs->ARM_cpsr = 0x10;
1180240ded8Spbrook     if (infop->entry & 1)
1190240ded8Spbrook       regs->ARM_cpsr |= CPSR_T;
1200240ded8Spbrook     regs->ARM_pc = infop->entry & 0xfffffffe;
121b346ff46Sbellard     regs->ARM_sp = infop->start_stack;
12253a5960aSpbrook     regs->ARM_r2 = tgetl(stack + 8); /* envp */
12353a5960aSpbrook     regs->ARM_r1 = tgetl(stack + 4); /* envp */
124a1516e92Sbellard     /* XXX: it seems that r0 is zeroed after ! */
125e5fe0c52Spbrook     regs->ARM_r0 = 0;
126e5fe0c52Spbrook     /* For uClinux PIC binaries.  */
127e5fe0c52Spbrook     regs->ARM_r10 = infop->start_data;
128b346ff46Sbellard }
129b346ff46Sbellard 
13030ac07d4Sbellard #define USE_ELF_CORE_DUMP
13130ac07d4Sbellard #define ELF_EXEC_PAGESIZE	4096
13230ac07d4Sbellard 
133afce2927Sbellard enum
134afce2927Sbellard {
135afce2927Sbellard   ARM_HWCAP_ARM_SWP       = 1 << 0,
136afce2927Sbellard   ARM_HWCAP_ARM_HALF      = 1 << 1,
137afce2927Sbellard   ARM_HWCAP_ARM_THUMB     = 1 << 2,
138afce2927Sbellard   ARM_HWCAP_ARM_26BIT     = 1 << 3,
139afce2927Sbellard   ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
140afce2927Sbellard   ARM_HWCAP_ARM_FPA       = 1 << 5,
141afce2927Sbellard   ARM_HWCAP_ARM_VFP       = 1 << 6,
142afce2927Sbellard   ARM_HWCAP_ARM_EDSP      = 1 << 7,
143afce2927Sbellard };
144afce2927Sbellard 
14515338fd7Sbellard #define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF              \
146afce2927Sbellard                     | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT     \
147afce2927Sbellard                     | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP)
148afce2927Sbellard 
14930ac07d4Sbellard #endif
15030ac07d4Sbellard 
151853d6f7aSbellard #ifdef TARGET_SPARC
152a315a145Sbellard #ifdef TARGET_SPARC64
153853d6f7aSbellard 
154853d6f7aSbellard #define ELF_START_MMAP 0x80000000
155853d6f7aSbellard 
1565ef54116Sbellard #define elf_check_arch(x) ( (x) == EM_SPARCV9 )
157853d6f7aSbellard 
158a315a145Sbellard #define ELF_CLASS   ELFCLASS64
159a315a145Sbellard #define ELF_DATA    ELFDATA2MSB
1605ef54116Sbellard #define ELF_ARCH    EM_SPARCV9
1615ef54116Sbellard 
1625ef54116Sbellard #define STACK_BIAS		2047
163a315a145Sbellard 
164a315a145Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
165a315a145Sbellard {
166a315a145Sbellard     regs->tstate = 0;
167a315a145Sbellard     regs->pc = infop->entry;
168a315a145Sbellard     regs->npc = regs->pc + 4;
169a315a145Sbellard     regs->y = 0;
1705ef54116Sbellard     regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
171a315a145Sbellard }
172a315a145Sbellard 
173a315a145Sbellard #else
174a315a145Sbellard #define ELF_START_MMAP 0x80000000
175a315a145Sbellard 
176a315a145Sbellard #define elf_check_arch(x) ( (x) == EM_SPARC )
177a315a145Sbellard 
178853d6f7aSbellard #define ELF_CLASS   ELFCLASS32
179853d6f7aSbellard #define ELF_DATA    ELFDATA2MSB
180853d6f7aSbellard #define ELF_ARCH    EM_SPARC
181853d6f7aSbellard 
182853d6f7aSbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
183853d6f7aSbellard {
184f5155289Sbellard     regs->psr = 0;
185f5155289Sbellard     regs->pc = infop->entry;
186f5155289Sbellard     regs->npc = regs->pc + 4;
187f5155289Sbellard     regs->y = 0;
188f5155289Sbellard     regs->u_regs[14] = infop->start_stack - 16 * 4;
189853d6f7aSbellard }
190853d6f7aSbellard 
191853d6f7aSbellard #endif
192a315a145Sbellard #endif
193853d6f7aSbellard 
19467867308Sbellard #ifdef TARGET_PPC
19567867308Sbellard 
19667867308Sbellard #define ELF_START_MMAP 0x80000000
19767867308Sbellard 
19884409ddbSj_mayer #ifdef TARGET_PPC64
19984409ddbSj_mayer 
20084409ddbSj_mayer #define elf_check_arch(x) ( (x) == EM_PPC64 )
20184409ddbSj_mayer 
20284409ddbSj_mayer #define ELF_CLASS	ELFCLASS64
20384409ddbSj_mayer 
20484409ddbSj_mayer #else
20584409ddbSj_mayer 
20667867308Sbellard #define elf_check_arch(x) ( (x) == EM_PPC )
20767867308Sbellard 
20867867308Sbellard #define ELF_CLASS	ELFCLASS32
20984409ddbSj_mayer 
21084409ddbSj_mayer #endif
21184409ddbSj_mayer 
21267867308Sbellard #ifdef TARGET_WORDS_BIGENDIAN
21367867308Sbellard #define ELF_DATA	ELFDATA2MSB
21467867308Sbellard #else
21567867308Sbellard #define ELF_DATA	ELFDATA2LSB
21667867308Sbellard #endif
21767867308Sbellard #define ELF_ARCH	EM_PPC
21867867308Sbellard 
219f5155289Sbellard /*
220f5155289Sbellard  * We need to put in some extra aux table entries to tell glibc what
221f5155289Sbellard  * the cache block size is, so it can use the dcbz instruction safely.
222f5155289Sbellard  */
223f5155289Sbellard #define AT_DCACHEBSIZE          19
224f5155289Sbellard #define AT_ICACHEBSIZE          20
225f5155289Sbellard #define AT_UCACHEBSIZE          21
226f5155289Sbellard /* A special ignored type value for PPC, for glibc compatibility.  */
227f5155289Sbellard #define AT_IGNOREPPC            22
228f5155289Sbellard /*
229f5155289Sbellard  * The requirements here are:
230f5155289Sbellard  * - keep the final alignment of sp (sp & 0xf)
231f5155289Sbellard  * - make sure the 32-bit value at the first 16 byte aligned position of
232f5155289Sbellard  *   AUXV is greater than 16 for glibc compatibility.
233f5155289Sbellard  *   AT_IGNOREPPC is used for that.
234f5155289Sbellard  * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
235f5155289Sbellard  *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
236f5155289Sbellard  */
2370bccf03dSbellard #define DLINFO_ARCH_ITEMS       5
238f5155289Sbellard #define ARCH_DLINFO                                                     \
239f5155289Sbellard do {                                                                    \
2400bccf03dSbellard         NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20);                              \
2410bccf03dSbellard         NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20);                              \
2420bccf03dSbellard         NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                                 \
243f5155289Sbellard         /*                                                              \
244f5155289Sbellard          * Now handle glibc compatibility.                              \
245f5155289Sbellard          */                                                             \
2460bccf03dSbellard 	NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);			\
2470bccf03dSbellard 	NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);			\
248f5155289Sbellard  } while (0)
249f5155289Sbellard 
25067867308Sbellard static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
25167867308Sbellard {
252e5fe0c52Spbrook     target_ulong pos = infop->start_stack;
253e5fe0c52Spbrook     target_ulong tmp;
25484409ddbSj_mayer #ifdef TARGET_PPC64
25584409ddbSj_mayer     target_ulong entry, toc;
25684409ddbSj_mayer #endif
257e5fe0c52Spbrook 
25867867308Sbellard     _regs->msr = 1 << MSR_PR; /* Set user mode */
25967867308Sbellard     _regs->gpr[1] = infop->start_stack;
26084409ddbSj_mayer #ifdef TARGET_PPC64
26184409ddbSj_mayer     entry = ldq_raw(infop->entry) + infop->load_addr;
26284409ddbSj_mayer     toc = ldq_raw(infop->entry + 8) + infop->load_addr;
26384409ddbSj_mayer     _regs->gpr[2] = toc;
26484409ddbSj_mayer     infop->entry = entry;
26584409ddbSj_mayer #endif
26667867308Sbellard     _regs->nip = infop->entry;
267e5fe0c52Spbrook     /* Note that isn't exactly what regular kernel does
268e5fe0c52Spbrook      * but this is what the ABI wants and is needed to allow
269e5fe0c52Spbrook      * execution of PPC BSD programs.
270e5fe0c52Spbrook      */
271e5fe0c52Spbrook     _regs->gpr[3] = tgetl(pos);
272e5fe0c52Spbrook     pos += sizeof(target_ulong);
273e5fe0c52Spbrook     _regs->gpr[4] = pos;
274e5fe0c52Spbrook     for (tmp = 1; tmp != 0; pos += sizeof(target_ulong))
275e5fe0c52Spbrook         tmp = ldl(pos);
276e5fe0c52Spbrook     _regs->gpr[5] = pos;
27767867308Sbellard }
27867867308Sbellard 
27967867308Sbellard #define USE_ELF_CORE_DUMP
28067867308Sbellard #define ELF_EXEC_PAGESIZE	4096
28167867308Sbellard 
28267867308Sbellard #endif
28367867308Sbellard 
284048f6b4dSbellard #ifdef TARGET_MIPS
285048f6b4dSbellard 
286048f6b4dSbellard #define ELF_START_MMAP 0x80000000
287048f6b4dSbellard 
288048f6b4dSbellard #define elf_check_arch(x) ( (x) == EM_MIPS )
289048f6b4dSbellard 
290388bb21aSths #ifdef TARGET_MIPS64
291388bb21aSths #define ELF_CLASS   ELFCLASS64
292388bb21aSths #else
293048f6b4dSbellard #define ELF_CLASS   ELFCLASS32
294388bb21aSths #endif
295048f6b4dSbellard #ifdef TARGET_WORDS_BIGENDIAN
296048f6b4dSbellard #define ELF_DATA	ELFDATA2MSB
297048f6b4dSbellard #else
298048f6b4dSbellard #define ELF_DATA	ELFDATA2LSB
299048f6b4dSbellard #endif
300048f6b4dSbellard #define ELF_ARCH    EM_MIPS
301048f6b4dSbellard 
302048f6b4dSbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
303048f6b4dSbellard {
304048f6b4dSbellard     regs->cp0_status = CP0St_UM;
305048f6b4dSbellard     regs->cp0_epc = infop->entry;
306048f6b4dSbellard     regs->regs[29] = infop->start_stack;
307048f6b4dSbellard }
308048f6b4dSbellard 
309388bb21aSths #define USE_ELF_CORE_DUMP
310388bb21aSths #define ELF_EXEC_PAGESIZE        4096
311388bb21aSths 
312048f6b4dSbellard #endif /* TARGET_MIPS */
313048f6b4dSbellard 
314fdf9b3e8Sbellard #ifdef TARGET_SH4
315fdf9b3e8Sbellard 
316fdf9b3e8Sbellard #define ELF_START_MMAP 0x80000000
317fdf9b3e8Sbellard 
318fdf9b3e8Sbellard #define elf_check_arch(x) ( (x) == EM_SH )
319fdf9b3e8Sbellard 
320fdf9b3e8Sbellard #define ELF_CLASS ELFCLASS32
321fdf9b3e8Sbellard #define ELF_DATA  ELFDATA2LSB
322fdf9b3e8Sbellard #define ELF_ARCH  EM_SH
323fdf9b3e8Sbellard 
324fdf9b3e8Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
325fdf9b3e8Sbellard {
326fdf9b3e8Sbellard   /* Check other registers XXXXX */
327fdf9b3e8Sbellard   regs->pc = infop->entry;
328fdf9b3e8Sbellard   regs->regs[15] = infop->start_stack - 16 * 4;
329fdf9b3e8Sbellard }
330fdf9b3e8Sbellard 
331fdf9b3e8Sbellard #define USE_ELF_CORE_DUMP
332fdf9b3e8Sbellard #define ELF_EXEC_PAGESIZE        4096
333fdf9b3e8Sbellard 
334fdf9b3e8Sbellard #endif
335fdf9b3e8Sbellard 
336e6e5906bSpbrook #ifdef TARGET_M68K
337e6e5906bSpbrook 
338e6e5906bSpbrook #define ELF_START_MMAP 0x80000000
339e6e5906bSpbrook 
340e6e5906bSpbrook #define elf_check_arch(x) ( (x) == EM_68K )
341e6e5906bSpbrook 
342e6e5906bSpbrook #define ELF_CLASS	ELFCLASS32
343e6e5906bSpbrook #define ELF_DATA	ELFDATA2MSB
344e6e5906bSpbrook #define ELF_ARCH	EM_68K
345e6e5906bSpbrook 
346e6e5906bSpbrook /* ??? Does this need to do anything?
347e6e5906bSpbrook #define ELF_PLAT_INIT(_r) */
348e6e5906bSpbrook 
349e6e5906bSpbrook static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
350e6e5906bSpbrook {
351e6e5906bSpbrook     regs->usp = infop->start_stack;
352e6e5906bSpbrook     regs->sr = 0;
353e6e5906bSpbrook     regs->pc = infop->entry;
354e6e5906bSpbrook }
355e6e5906bSpbrook 
356e6e5906bSpbrook #define USE_ELF_CORE_DUMP
357e6e5906bSpbrook #define ELF_EXEC_PAGESIZE	8192
358e6e5906bSpbrook 
359e6e5906bSpbrook #endif
360e6e5906bSpbrook 
3617a3148a9Sj_mayer #ifdef TARGET_ALPHA
3627a3148a9Sj_mayer 
3637a3148a9Sj_mayer #define ELF_START_MMAP (0x30000000000ULL)
3647a3148a9Sj_mayer 
3657a3148a9Sj_mayer #define elf_check_arch(x) ( (x) == ELF_ARCH )
3667a3148a9Sj_mayer 
3677a3148a9Sj_mayer #define ELF_CLASS      ELFCLASS64
3687a3148a9Sj_mayer #define ELF_DATA       ELFDATA2MSB
3697a3148a9Sj_mayer #define ELF_ARCH       EM_ALPHA
3707a3148a9Sj_mayer 
3717a3148a9Sj_mayer static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
3727a3148a9Sj_mayer {
3737a3148a9Sj_mayer     regs->pc = infop->entry;
3747a3148a9Sj_mayer     regs->ps = 8;
3757a3148a9Sj_mayer     regs->usp = infop->start_stack;
3767a3148a9Sj_mayer     regs->unique = infop->start_data; /* ? */
3777a3148a9Sj_mayer     printf("Set unique value to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n",
3787a3148a9Sj_mayer            regs->unique, infop->start_data);
3797a3148a9Sj_mayer }
3807a3148a9Sj_mayer 
3817a3148a9Sj_mayer #define USE_ELF_CORE_DUMP
3827a3148a9Sj_mayer #define ELF_EXEC_PAGESIZE        8192
3837a3148a9Sj_mayer 
3847a3148a9Sj_mayer #endif /* TARGET_ALPHA */
3857a3148a9Sj_mayer 
38615338fd7Sbellard #ifndef ELF_PLATFORM
38715338fd7Sbellard #define ELF_PLATFORM (NULL)
38815338fd7Sbellard #endif
38915338fd7Sbellard 
39015338fd7Sbellard #ifndef ELF_HWCAP
39115338fd7Sbellard #define ELF_HWCAP 0
39215338fd7Sbellard #endif
39315338fd7Sbellard 
39431e31b8aSbellard #include "elf.h"
39509bfb054Sbellard 
39609bfb054Sbellard struct exec
39709bfb054Sbellard {
39809bfb054Sbellard   unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
39909bfb054Sbellard   unsigned int a_text;   /* length of text, in bytes */
40009bfb054Sbellard   unsigned int a_data;   /* length of data, in bytes */
40109bfb054Sbellard   unsigned int a_bss;    /* length of uninitialized data area, in bytes */
40209bfb054Sbellard   unsigned int a_syms;   /* length of symbol table data in file, in bytes */
40309bfb054Sbellard   unsigned int a_entry;  /* start address */
40409bfb054Sbellard   unsigned int a_trsize; /* length of relocation info for text, in bytes */
40509bfb054Sbellard   unsigned int a_drsize; /* length of relocation info for data, in bytes */
40609bfb054Sbellard };
40709bfb054Sbellard 
40809bfb054Sbellard 
40909bfb054Sbellard #define N_MAGIC(exec) ((exec).a_info & 0xffff)
41009bfb054Sbellard #define OMAGIC 0407
41109bfb054Sbellard #define NMAGIC 0410
41209bfb054Sbellard #define ZMAGIC 0413
41309bfb054Sbellard #define QMAGIC 0314
41409bfb054Sbellard 
41509bfb054Sbellard /* max code+data+bss space allocated to elf interpreter */
41609bfb054Sbellard #define INTERP_MAP_SIZE (32 * 1024 * 1024)
41709bfb054Sbellard 
41809bfb054Sbellard /* max code+data+bss+brk space allocated to ET_DYN executables */
41909bfb054Sbellard #define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
42009bfb054Sbellard 
42109bfb054Sbellard /* from personality.h */
42209bfb054Sbellard 
42309bfb054Sbellard /* Flags for bug emulation. These occupy the top three bytes. */
42409bfb054Sbellard #define STICKY_TIMEOUTS		0x4000000
42509bfb054Sbellard #define WHOLE_SECONDS		0x2000000
42609bfb054Sbellard 
42709bfb054Sbellard /* Personality types. These go in the low byte. Avoid using the top bit,
42809bfb054Sbellard  * it will conflict with error returns.
42909bfb054Sbellard  */
43009bfb054Sbellard #define PER_MASK		(0x00ff)
43109bfb054Sbellard #define PER_LINUX		(0x0000)
43209bfb054Sbellard #define PER_SVR4		(0x0001 | STICKY_TIMEOUTS)
43309bfb054Sbellard #define PER_SVR3		(0x0002 | STICKY_TIMEOUTS)
43409bfb054Sbellard #define PER_SCOSVR3		(0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS)
43509bfb054Sbellard #define PER_WYSEV386		(0x0004 | STICKY_TIMEOUTS)
43609bfb054Sbellard #define PER_ISCR4		(0x0005 | STICKY_TIMEOUTS)
43709bfb054Sbellard #define PER_BSD			(0x0006)
43809bfb054Sbellard #define PER_XENIX		(0x0007 | STICKY_TIMEOUTS)
43931e31b8aSbellard 
44031e31b8aSbellard /* Necessary parameters */
44154936004Sbellard #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
44254936004Sbellard #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
44354936004Sbellard #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
44431e31b8aSbellard 
44531e31b8aSbellard #define INTERPRETER_NONE 0
44631e31b8aSbellard #define INTERPRETER_AOUT 1
44731e31b8aSbellard #define INTERPRETER_ELF 2
44831e31b8aSbellard 
44915338fd7Sbellard #define DLINFO_ITEMS 12
45031e31b8aSbellard 
45109bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
45209bfb054Sbellard {
45309bfb054Sbellard 	memcpy(to, from, n);
45409bfb054Sbellard }
45509bfb054Sbellard 
45631e31b8aSbellard extern unsigned long x86_stack_size;
45731e31b8aSbellard 
45831e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd);
45931e31b8aSbellard 
46031e31b8aSbellard #ifdef BSWAP_NEEDED
46192a31b1fSbellard static void bswap_ehdr(struct elfhdr *ehdr)
46231e31b8aSbellard {
46331e31b8aSbellard     bswap16s(&ehdr->e_type);			/* Object file type */
46431e31b8aSbellard     bswap16s(&ehdr->e_machine);		/* Architecture */
46531e31b8aSbellard     bswap32s(&ehdr->e_version);		/* Object file version */
46692a31b1fSbellard     bswaptls(&ehdr->e_entry);		/* Entry point virtual address */
46792a31b1fSbellard     bswaptls(&ehdr->e_phoff);		/* Program header table file offset */
46892a31b1fSbellard     bswaptls(&ehdr->e_shoff);		/* Section header table file offset */
46931e31b8aSbellard     bswap32s(&ehdr->e_flags);		/* Processor-specific flags */
47031e31b8aSbellard     bswap16s(&ehdr->e_ehsize);		/* ELF header size in bytes */
47131e31b8aSbellard     bswap16s(&ehdr->e_phentsize);		/* Program header table entry size */
47231e31b8aSbellard     bswap16s(&ehdr->e_phnum);		/* Program header table entry count */
47331e31b8aSbellard     bswap16s(&ehdr->e_shentsize);		/* Section header table entry size */
47431e31b8aSbellard     bswap16s(&ehdr->e_shnum);		/* Section header table entry count */
47531e31b8aSbellard     bswap16s(&ehdr->e_shstrndx);		/* Section header string table index */
47631e31b8aSbellard }
47731e31b8aSbellard 
47892a31b1fSbellard static void bswap_phdr(struct elf_phdr *phdr)
47931e31b8aSbellard {
48031e31b8aSbellard     bswap32s(&phdr->p_type);			/* Segment type */
48192a31b1fSbellard     bswaptls(&phdr->p_offset);		/* Segment file offset */
48292a31b1fSbellard     bswaptls(&phdr->p_vaddr);		/* Segment virtual address */
48392a31b1fSbellard     bswaptls(&phdr->p_paddr);		/* Segment physical address */
48492a31b1fSbellard     bswaptls(&phdr->p_filesz);		/* Segment size in file */
48592a31b1fSbellard     bswaptls(&phdr->p_memsz);		/* Segment size in memory */
48631e31b8aSbellard     bswap32s(&phdr->p_flags);		/* Segment flags */
48792a31b1fSbellard     bswaptls(&phdr->p_align);		/* Segment alignment */
48831e31b8aSbellard }
489689f936fSbellard 
49092a31b1fSbellard static void bswap_shdr(struct elf_shdr *shdr)
491689f936fSbellard {
492689f936fSbellard     bswap32s(&shdr->sh_name);
493689f936fSbellard     bswap32s(&shdr->sh_type);
49492a31b1fSbellard     bswaptls(&shdr->sh_flags);
49592a31b1fSbellard     bswaptls(&shdr->sh_addr);
49692a31b1fSbellard     bswaptls(&shdr->sh_offset);
49792a31b1fSbellard     bswaptls(&shdr->sh_size);
498689f936fSbellard     bswap32s(&shdr->sh_link);
499689f936fSbellard     bswap32s(&shdr->sh_info);
50092a31b1fSbellard     bswaptls(&shdr->sh_addralign);
50192a31b1fSbellard     bswaptls(&shdr->sh_entsize);
502689f936fSbellard }
503689f936fSbellard 
5047a3148a9Sj_mayer static void bswap_sym(struct elf_sym *sym)
505689f936fSbellard {
506689f936fSbellard     bswap32s(&sym->st_name);
5077a3148a9Sj_mayer     bswaptls(&sym->st_value);
5087a3148a9Sj_mayer     bswaptls(&sym->st_size);
509689f936fSbellard     bswap16s(&sym->st_shndx);
510689f936fSbellard }
51131e31b8aSbellard #endif
51231e31b8aSbellard 
51331e31b8aSbellard /*
514e5fe0c52Spbrook  * 'copy_elf_strings()' copies argument/envelope strings from user
51531e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
51631e31b8aSbellard  * to be put directly into the top of new user memory.
51731e31b8aSbellard  *
51831e31b8aSbellard  */
519e5fe0c52Spbrook static unsigned long copy_elf_strings(int argc,char ** argv, void **page,
52031e31b8aSbellard                                       unsigned long p)
52131e31b8aSbellard {
52231e31b8aSbellard     char *tmp, *tmp1, *pag = NULL;
52331e31b8aSbellard     int len, offset = 0;
52431e31b8aSbellard 
52531e31b8aSbellard     if (!p) {
52631e31b8aSbellard 	return 0;       /* bullet-proofing */
52731e31b8aSbellard     }
52831e31b8aSbellard     while (argc-- > 0) {
529edf779ffSbellard         tmp = argv[argc];
530edf779ffSbellard         if (!tmp) {
53131e31b8aSbellard 	    fprintf(stderr, "VFS: argc is wrong");
53231e31b8aSbellard 	    exit(-1);
53331e31b8aSbellard 	}
534edf779ffSbellard         tmp1 = tmp;
535edf779ffSbellard 	while (*tmp++);
53631e31b8aSbellard 	len = tmp - tmp1;
53731e31b8aSbellard 	if (p < len) {  /* this shouldn't happen - 128kB */
53831e31b8aSbellard 		return 0;
53931e31b8aSbellard 	}
54031e31b8aSbellard 	while (len) {
54131e31b8aSbellard 	    --p; --tmp; --len;
54231e31b8aSbellard 	    if (--offset < 0) {
54354936004Sbellard 		offset = p % TARGET_PAGE_SIZE;
54444a91caeSbellard                 pag = (char *)page[p/TARGET_PAGE_SIZE];
54544a91caeSbellard                 if (!pag) {
54653a5960aSpbrook                     pag = (char *)malloc(TARGET_PAGE_SIZE);
54753a5960aSpbrook                     page[p/TARGET_PAGE_SIZE] = pag;
54844a91caeSbellard                     if (!pag)
54931e31b8aSbellard                         return 0;
55031e31b8aSbellard 		}
55131e31b8aSbellard 	    }
55231e31b8aSbellard 	    if (len == 0 || offset == 0) {
553edf779ffSbellard 	        *(pag + offset) = *tmp;
55431e31b8aSbellard 	    }
55531e31b8aSbellard 	    else {
55631e31b8aSbellard 	      int bytes_to_copy = (len > offset) ? offset : len;
55731e31b8aSbellard 	      tmp -= bytes_to_copy;
55831e31b8aSbellard 	      p -= bytes_to_copy;
55931e31b8aSbellard 	      offset -= bytes_to_copy;
56031e31b8aSbellard 	      len -= bytes_to_copy;
56131e31b8aSbellard 	      memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
56231e31b8aSbellard 	    }
56331e31b8aSbellard 	}
56431e31b8aSbellard     }
56531e31b8aSbellard     return p;
56631e31b8aSbellard }
56731e31b8aSbellard 
56853a5960aSpbrook unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm,
56931e31b8aSbellard 					      struct image_info * info)
57031e31b8aSbellard {
57153a5960aSpbrook     target_ulong stack_base, size, error;
57231e31b8aSbellard     int i;
57331e31b8aSbellard 
57431e31b8aSbellard     /* Create enough stack to hold everything.  If we don't use
57531e31b8aSbellard      * it for args, we'll use it for something else...
57631e31b8aSbellard      */
57709bfb054Sbellard     size = x86_stack_size;
57854936004Sbellard     if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
57954936004Sbellard         size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
58054936004Sbellard     error = target_mmap(0,
58183fb7adfSbellard                         size + qemu_host_page_size,
58231e31b8aSbellard                         PROT_READ | PROT_WRITE,
58309bfb054Sbellard                         MAP_PRIVATE | MAP_ANONYMOUS,
58409bfb054Sbellard                         -1, 0);
58509bfb054Sbellard     if (error == -1) {
58631e31b8aSbellard         perror("stk mmap");
58731e31b8aSbellard         exit(-1);
58831e31b8aSbellard     }
58909bfb054Sbellard     /* we reserve one extra page at the top of the stack as guard */
59083fb7adfSbellard     target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
59131e31b8aSbellard 
59254936004Sbellard     stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
59309bfb054Sbellard     p += stack_base;
59409bfb054Sbellard 
59531e31b8aSbellard     for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
59631e31b8aSbellard 	if (bprm->page[i]) {
59731e31b8aSbellard 	    info->rss++;
59831e31b8aSbellard 
59953a5960aSpbrook 	    memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
60053a5960aSpbrook 	    free(bprm->page[i]);
60131e31b8aSbellard 	}
60254936004Sbellard         stack_base += TARGET_PAGE_SIZE;
60331e31b8aSbellard     }
60431e31b8aSbellard     return p;
60531e31b8aSbellard }
60631e31b8aSbellard 
60731e31b8aSbellard static void set_brk(unsigned long start, unsigned long end)
60831e31b8aSbellard {
60931e31b8aSbellard 	/* page-align the start and end addresses... */
61054936004Sbellard         start = HOST_PAGE_ALIGN(start);
61154936004Sbellard         end = HOST_PAGE_ALIGN(end);
61231e31b8aSbellard         if (end <= start)
61331e31b8aSbellard                 return;
61454936004Sbellard         if(target_mmap(start, end - start,
61531e31b8aSbellard                        PROT_READ | PROT_WRITE | PROT_EXEC,
61631e31b8aSbellard                        MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
61731e31b8aSbellard 	    perror("cannot mmap brk");
61831e31b8aSbellard 	    exit(-1);
61931e31b8aSbellard 	}
62031e31b8aSbellard }
62131e31b8aSbellard 
62231e31b8aSbellard 
623853d6f7aSbellard /* We need to explicitly zero any fractional pages after the data
624853d6f7aSbellard    section (i.e. bss).  This would contain the junk from the file that
625853d6f7aSbellard    should not be in memory. */
626768a4a36Sths static void padzero(unsigned long elf_bss, unsigned long last_bss)
62731e31b8aSbellard {
62831e31b8aSbellard         unsigned long nbyte;
62931e31b8aSbellard 
630768a4a36Sths 	if (elf_bss >= last_bss)
631768a4a36Sths 		return;
632768a4a36Sths 
633853d6f7aSbellard         /* XXX: this is really a hack : if the real host page size is
634853d6f7aSbellard            smaller than the target page size, some pages after the end
635853d6f7aSbellard            of the file may not be mapped. A better fix would be to
636853d6f7aSbellard            patch target_mmap(), but it is more complicated as the file
637853d6f7aSbellard            size must be known */
63883fb7adfSbellard         if (qemu_real_host_page_size < qemu_host_page_size) {
639853d6f7aSbellard             unsigned long end_addr, end_addr1;
64083fb7adfSbellard             end_addr1 = (elf_bss + qemu_real_host_page_size - 1) &
64183fb7adfSbellard                 ~(qemu_real_host_page_size - 1);
642853d6f7aSbellard             end_addr = HOST_PAGE_ALIGN(elf_bss);
643853d6f7aSbellard             if (end_addr1 < end_addr) {
644853d6f7aSbellard                 mmap((void *)end_addr1, end_addr - end_addr1,
645853d6f7aSbellard                      PROT_READ|PROT_WRITE|PROT_EXEC,
646853d6f7aSbellard                      MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
647853d6f7aSbellard             }
648853d6f7aSbellard         }
649853d6f7aSbellard 
65083fb7adfSbellard         nbyte = elf_bss & (qemu_host_page_size-1);
65131e31b8aSbellard         if (nbyte) {
65283fb7adfSbellard 	    nbyte = qemu_host_page_size - nbyte;
65331e31b8aSbellard 	    do {
65453a5960aSpbrook 		tput8(elf_bss, 0);
65553a5960aSpbrook                 elf_bss++;
65631e31b8aSbellard 	    } while (--nbyte);
65731e31b8aSbellard         }
65831e31b8aSbellard }
65931e31b8aSbellard 
66053a5960aSpbrook 
66153a5960aSpbrook static unsigned long create_elf_tables(target_ulong p, int argc, int envc,
66231e31b8aSbellard                                        struct elfhdr * exec,
66331e31b8aSbellard                                        unsigned long load_addr,
66409bfb054Sbellard                                        unsigned long load_bias,
66531e31b8aSbellard                                        unsigned long interp_load_addr, int ibcs,
66631e31b8aSbellard                                        struct image_info *info)
66731e31b8aSbellard {
66853a5960aSpbrook         target_ulong sp;
66953a5960aSpbrook         int size;
67053a5960aSpbrook         target_ulong u_platform;
67115338fd7Sbellard         const char *k_platform;
67253a5960aSpbrook         const int n = sizeof(target_ulong);
67331e31b8aSbellard 
67453a5960aSpbrook         sp = p;
67553a5960aSpbrook         u_platform = 0;
67615338fd7Sbellard         k_platform = ELF_PLATFORM;
67715338fd7Sbellard         if (k_platform) {
67815338fd7Sbellard             size_t len = strlen(k_platform) + 1;
67953a5960aSpbrook             sp -= (len + n - 1) & ~(n - 1);
68053a5960aSpbrook             u_platform = sp;
68153a5960aSpbrook             memcpy_to_target(sp, k_platform, len);
68215338fd7Sbellard         }
68353a5960aSpbrook 	/*
68453a5960aSpbrook 	 * Force 16 byte _final_ alignment here for generality.
68553a5960aSpbrook 	 */
68653a5960aSpbrook         sp = sp &~ (target_ulong)15;
68753a5960aSpbrook         size = (DLINFO_ITEMS + 1) * 2;
68815338fd7Sbellard         if (k_platform)
68953a5960aSpbrook           size += 2;
690f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS
69153a5960aSpbrook 	size += DLINFO_ARCH_ITEMS * 2;
692f5155289Sbellard #endif
69353a5960aSpbrook         size += envc + argc + 2;
69453a5960aSpbrook 	size += (!ibcs ? 3 : 1);	/* argc itself */
69553a5960aSpbrook         size *= n;
69653a5960aSpbrook         if (size & 15)
69753a5960aSpbrook             sp -= 16 - (size & 15);
698f5155289Sbellard 
69953a5960aSpbrook #define NEW_AUX_ENT(id, val) do { \
70053a5960aSpbrook             sp -= n; tputl(sp, val); \
70153a5960aSpbrook             sp -= n; tputl(sp, id); \
70253a5960aSpbrook           } while(0)
7030bccf03dSbellard         NEW_AUX_ENT (AT_NULL, 0);
704f5155289Sbellard 
7050bccf03dSbellard         /* There must be exactly DLINFO_ITEMS entries here.  */
7060bccf03dSbellard         NEW_AUX_ENT(AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
7070bccf03dSbellard         NEW_AUX_ENT(AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
7080bccf03dSbellard         NEW_AUX_ENT(AT_PHNUM, (target_ulong)(exec->e_phnum));
7090bccf03dSbellard         NEW_AUX_ENT(AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
7100bccf03dSbellard         NEW_AUX_ENT(AT_BASE, (target_ulong)(interp_load_addr));
7110bccf03dSbellard         NEW_AUX_ENT(AT_FLAGS, (target_ulong)0);
7120bccf03dSbellard         NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
7130bccf03dSbellard         NEW_AUX_ENT(AT_UID, (target_ulong) getuid());
7140bccf03dSbellard         NEW_AUX_ENT(AT_EUID, (target_ulong) geteuid());
7150bccf03dSbellard         NEW_AUX_ENT(AT_GID, (target_ulong) getgid());
7160bccf03dSbellard         NEW_AUX_ENT(AT_EGID, (target_ulong) getegid());
71715338fd7Sbellard         NEW_AUX_ENT(AT_HWCAP, (target_ulong) ELF_HWCAP);
71815338fd7Sbellard         if (k_platform)
71953a5960aSpbrook             NEW_AUX_ENT(AT_PLATFORM, u_platform);
720f5155289Sbellard #ifdef ARCH_DLINFO
721f5155289Sbellard 	/*
722f5155289Sbellard 	 * ARCH_DLINFO must come last so platform specific code can enforce
723f5155289Sbellard 	 * special alignment requirements on the AUXV if necessary (eg. PPC).
724f5155289Sbellard 	 */
725f5155289Sbellard         ARCH_DLINFO;
726f5155289Sbellard #endif
727f5155289Sbellard #undef NEW_AUX_ENT
728f5155289Sbellard 
729e5fe0c52Spbrook         sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
73031e31b8aSbellard         return sp;
73131e31b8aSbellard }
73231e31b8aSbellard 
73331e31b8aSbellard 
73431e31b8aSbellard static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
73531e31b8aSbellard 				     int interpreter_fd,
73631e31b8aSbellard 				     unsigned long *interp_load_addr)
73731e31b8aSbellard {
73831e31b8aSbellard 	struct elf_phdr *elf_phdata  =  NULL;
73931e31b8aSbellard 	struct elf_phdr *eppnt;
74009bfb054Sbellard 	unsigned long load_addr = 0;
74131e31b8aSbellard 	int load_addr_set = 0;
74231e31b8aSbellard 	int retval;
74331e31b8aSbellard 	unsigned long last_bss, elf_bss;
74431e31b8aSbellard 	unsigned long error;
74531e31b8aSbellard 	int i;
74631e31b8aSbellard 
74731e31b8aSbellard 	elf_bss = 0;
74831e31b8aSbellard 	last_bss = 0;
74931e31b8aSbellard 	error = 0;
75031e31b8aSbellard 
751644c433cSbellard #ifdef BSWAP_NEEDED
752644c433cSbellard         bswap_ehdr(interp_elf_ex);
753644c433cSbellard #endif
75431e31b8aSbellard 	/* First of all, some simple consistency checks */
75531e31b8aSbellard 	if ((interp_elf_ex->e_type != ET_EXEC &&
75631e31b8aSbellard              interp_elf_ex->e_type != ET_DYN) ||
75731e31b8aSbellard 	   !elf_check_arch(interp_elf_ex->e_machine)) {
75831e31b8aSbellard 		return ~0UL;
75931e31b8aSbellard 	}
76031e31b8aSbellard 
761644c433cSbellard 
76231e31b8aSbellard 	/* Now read in all of the header information */
76331e31b8aSbellard 
76454936004Sbellard 	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
76531e31b8aSbellard 	    return ~0UL;
76631e31b8aSbellard 
76731e31b8aSbellard 	elf_phdata =  (struct elf_phdr *)
76831e31b8aSbellard 		malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
76931e31b8aSbellard 
77031e31b8aSbellard 	if (!elf_phdata)
77131e31b8aSbellard 	  return ~0UL;
77231e31b8aSbellard 
77331e31b8aSbellard 	/*
77431e31b8aSbellard 	 * If the size of this structure has changed, then punt, since
77531e31b8aSbellard 	 * we will be doing the wrong thing.
77631e31b8aSbellard 	 */
77709bfb054Sbellard 	if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
77831e31b8aSbellard 	    free(elf_phdata);
77931e31b8aSbellard 	    return ~0UL;
78031e31b8aSbellard         }
78131e31b8aSbellard 
78231e31b8aSbellard 	retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
78331e31b8aSbellard 	if(retval >= 0) {
78431e31b8aSbellard 	    retval = read(interpreter_fd,
78531e31b8aSbellard 			   (char *) elf_phdata,
78631e31b8aSbellard 			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
78731e31b8aSbellard 	}
78831e31b8aSbellard 	if (retval < 0) {
78931e31b8aSbellard 		perror("load_elf_interp");
79031e31b8aSbellard 		exit(-1);
79131e31b8aSbellard 		free (elf_phdata);
79231e31b8aSbellard 		return retval;
79331e31b8aSbellard  	}
79431e31b8aSbellard #ifdef BSWAP_NEEDED
79531e31b8aSbellard 	eppnt = elf_phdata;
79631e31b8aSbellard 	for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
79731e31b8aSbellard             bswap_phdr(eppnt);
79831e31b8aSbellard         }
79931e31b8aSbellard #endif
80009bfb054Sbellard 
80109bfb054Sbellard         if (interp_elf_ex->e_type == ET_DYN) {
802*e91c8a77Sths             /* in order to avoid hardcoding the interpreter load
80309bfb054Sbellard                address in qemu, we allocate a big enough memory zone */
80454936004Sbellard             error = target_mmap(0, INTERP_MAP_SIZE,
80509bfb054Sbellard                                 PROT_NONE, MAP_PRIVATE | MAP_ANON,
80609bfb054Sbellard                                 -1, 0);
80709bfb054Sbellard             if (error == -1) {
80809bfb054Sbellard                 perror("mmap");
80909bfb054Sbellard                 exit(-1);
81009bfb054Sbellard             }
81109bfb054Sbellard             load_addr = error;
81209bfb054Sbellard             load_addr_set = 1;
81309bfb054Sbellard         }
81409bfb054Sbellard 
81531e31b8aSbellard 	eppnt = elf_phdata;
81631e31b8aSbellard 	for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
81731e31b8aSbellard 	  if (eppnt->p_type == PT_LOAD) {
81831e31b8aSbellard 	    int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
81931e31b8aSbellard 	    int elf_prot = 0;
82031e31b8aSbellard 	    unsigned long vaddr = 0;
82131e31b8aSbellard 	    unsigned long k;
82231e31b8aSbellard 
82331e31b8aSbellard 	    if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
82431e31b8aSbellard 	    if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
82531e31b8aSbellard 	    if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
82631e31b8aSbellard 	    if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
82731e31b8aSbellard 	    	elf_type |= MAP_FIXED;
82831e31b8aSbellard 	    	vaddr = eppnt->p_vaddr;
82931e31b8aSbellard 	    }
83054936004Sbellard 	    error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
83154936004Sbellard 		 eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
83231e31b8aSbellard 		 elf_prot,
83331e31b8aSbellard 		 elf_type,
83431e31b8aSbellard 		 interpreter_fd,
83554936004Sbellard 		 eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
83631e31b8aSbellard 
837e89f07d3Spbrook 	    if (error == -1) {
83831e31b8aSbellard 	      /* Real error */
83931e31b8aSbellard 	      close(interpreter_fd);
84031e31b8aSbellard 	      free(elf_phdata);
84131e31b8aSbellard 	      return ~0UL;
84231e31b8aSbellard 	    }
84331e31b8aSbellard 
84431e31b8aSbellard 	    if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
84531e31b8aSbellard 	      load_addr = error;
84631e31b8aSbellard 	      load_addr_set = 1;
84731e31b8aSbellard 	    }
84831e31b8aSbellard 
84931e31b8aSbellard 	    /*
85031e31b8aSbellard 	     * Find the end of the file  mapping for this phdr, and keep
85131e31b8aSbellard 	     * track of the largest address we see for this.
85231e31b8aSbellard 	     */
85331e31b8aSbellard 	    k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
85431e31b8aSbellard 	    if (k > elf_bss) elf_bss = k;
85531e31b8aSbellard 
85631e31b8aSbellard 	    /*
85731e31b8aSbellard 	     * Do the same thing for the memory mapping - between
85831e31b8aSbellard 	     * elf_bss and last_bss is the bss section.
85931e31b8aSbellard 	     */
86031e31b8aSbellard 	    k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
86131e31b8aSbellard 	    if (k > last_bss) last_bss = k;
86231e31b8aSbellard 	  }
86331e31b8aSbellard 
86431e31b8aSbellard 	/* Now use mmap to map the library into memory. */
86531e31b8aSbellard 
86631e31b8aSbellard 	close(interpreter_fd);
86731e31b8aSbellard 
86831e31b8aSbellard 	/*
86931e31b8aSbellard 	 * Now fill out the bss section.  First pad the last page up
87031e31b8aSbellard 	 * to the page boundary, and then perform a mmap to make sure
87131e31b8aSbellard 	 * that there are zeromapped pages up to and including the last
87231e31b8aSbellard 	 * bss page.
87331e31b8aSbellard 	 */
874768a4a36Sths 	padzero(elf_bss, last_bss);
87583fb7adfSbellard 	elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */
87631e31b8aSbellard 
87731e31b8aSbellard 	/* Map the last of the bss segment */
87831e31b8aSbellard 	if (last_bss > elf_bss) {
87954936004Sbellard             target_mmap(elf_bss, last_bss-elf_bss,
88031e31b8aSbellard                         PROT_READ|PROT_WRITE|PROT_EXEC,
88131e31b8aSbellard                         MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
88231e31b8aSbellard 	}
88331e31b8aSbellard 	free(elf_phdata);
88431e31b8aSbellard 
88531e31b8aSbellard 	*interp_load_addr = load_addr;
88631e31b8aSbellard 	return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
88731e31b8aSbellard }
88831e31b8aSbellard 
889689f936fSbellard /* Best attempt to load symbols from this ELF object. */
890689f936fSbellard static void load_symbols(struct elfhdr *hdr, int fd)
891689f936fSbellard {
892689f936fSbellard     unsigned int i;
893689f936fSbellard     struct elf_shdr sechdr, symtab, strtab;
894689f936fSbellard     char *strings;
895e80cfcfcSbellard     struct syminfo *s;
89631e31b8aSbellard 
897689f936fSbellard     lseek(fd, hdr->e_shoff, SEEK_SET);
898689f936fSbellard     for (i = 0; i < hdr->e_shnum; i++) {
899689f936fSbellard 	if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
900689f936fSbellard 	    return;
901689f936fSbellard #ifdef BSWAP_NEEDED
902689f936fSbellard 	bswap_shdr(&sechdr);
903689f936fSbellard #endif
904689f936fSbellard 	if (sechdr.sh_type == SHT_SYMTAB) {
905689f936fSbellard 	    symtab = sechdr;
906689f936fSbellard 	    lseek(fd, hdr->e_shoff
907689f936fSbellard 		  + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
908689f936fSbellard 	    if (read(fd, &strtab, sizeof(strtab))
909689f936fSbellard 		!= sizeof(strtab))
910689f936fSbellard 		return;
911689f936fSbellard #ifdef BSWAP_NEEDED
912689f936fSbellard 	    bswap_shdr(&strtab);
913689f936fSbellard #endif
914689f936fSbellard 	    goto found;
915689f936fSbellard 	}
916689f936fSbellard     }
917689f936fSbellard     return; /* Shouldn't happen... */
918689f936fSbellard 
919689f936fSbellard  found:
920689f936fSbellard     /* Now know where the strtab and symtab are.  Snarf them. */
921e80cfcfcSbellard     s = malloc(sizeof(*s));
922e80cfcfcSbellard     s->disas_symtab = malloc(symtab.sh_size);
923e80cfcfcSbellard     s->disas_strtab = strings = malloc(strtab.sh_size);
924e80cfcfcSbellard     if (!s->disas_symtab || !s->disas_strtab)
925689f936fSbellard 	return;
926689f936fSbellard 
927689f936fSbellard     lseek(fd, symtab.sh_offset, SEEK_SET);
928e80cfcfcSbellard     if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size)
929689f936fSbellard 	return;
930689f936fSbellard 
931689f936fSbellard #ifdef BSWAP_NEEDED
932689f936fSbellard     for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++)
933e80cfcfcSbellard 	bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i);
934689f936fSbellard #endif
935689f936fSbellard 
936689f936fSbellard     lseek(fd, strtab.sh_offset, SEEK_SET);
937689f936fSbellard     if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
938689f936fSbellard 	return;
939e80cfcfcSbellard     s->disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
940e80cfcfcSbellard     s->next = syminfos;
941e80cfcfcSbellard     syminfos = s;
942689f936fSbellard }
94331e31b8aSbellard 
944e5fe0c52Spbrook int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
94531e31b8aSbellard                     struct image_info * info)
94631e31b8aSbellard {
94731e31b8aSbellard     struct elfhdr elf_ex;
94831e31b8aSbellard     struct elfhdr interp_elf_ex;
94931e31b8aSbellard     struct exec interp_ex;
95031e31b8aSbellard     int interpreter_fd = -1; /* avoid warning */
95109bfb054Sbellard     unsigned long load_addr, load_bias;
95231e31b8aSbellard     int load_addr_set = 0;
95331e31b8aSbellard     unsigned int interpreter_type = INTERPRETER_NONE;
95431e31b8aSbellard     unsigned char ibcs2_interpreter;
95531e31b8aSbellard     int i;
95654936004Sbellard     unsigned long mapped_addr;
95731e31b8aSbellard     struct elf_phdr * elf_ppnt;
95831e31b8aSbellard     struct elf_phdr *elf_phdata;
95931e31b8aSbellard     unsigned long elf_bss, k, elf_brk;
96031e31b8aSbellard     int retval;
96131e31b8aSbellard     char * elf_interpreter;
96231e31b8aSbellard     unsigned long elf_entry, interp_load_addr = 0;
96331e31b8aSbellard     int status;
96431e31b8aSbellard     unsigned long start_code, end_code, end_data;
96584409ddbSj_mayer     unsigned long reloc_func_desc = 0;
96631e31b8aSbellard     unsigned long elf_stack;
96731e31b8aSbellard     char passed_fileno[6];
96831e31b8aSbellard 
96931e31b8aSbellard     ibcs2_interpreter = 0;
97031e31b8aSbellard     status = 0;
97131e31b8aSbellard     load_addr = 0;
97209bfb054Sbellard     load_bias = 0;
97331e31b8aSbellard     elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
97431e31b8aSbellard #ifdef BSWAP_NEEDED
97531e31b8aSbellard     bswap_ehdr(&elf_ex);
97631e31b8aSbellard #endif
97731e31b8aSbellard 
97831e31b8aSbellard     /* First of all, some simple consistency checks */
97931e31b8aSbellard     if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
98031e31b8aSbellard        				(! elf_check_arch(elf_ex.e_machine))) {
98131e31b8aSbellard 	    return -ENOEXEC;
98231e31b8aSbellard     }
98331e31b8aSbellard 
984e5fe0c52Spbrook     bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
985e5fe0c52Spbrook     bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
986e5fe0c52Spbrook     bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
987e5fe0c52Spbrook     if (!bprm->p) {
988e5fe0c52Spbrook         retval = -E2BIG;
989e5fe0c52Spbrook     }
990e5fe0c52Spbrook 
99131e31b8aSbellard     /* Now read in all of the header information */
99231e31b8aSbellard     elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
99331e31b8aSbellard     if (elf_phdata == NULL) {
99431e31b8aSbellard 	return -ENOMEM;
99531e31b8aSbellard     }
99631e31b8aSbellard 
99731e31b8aSbellard     retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
99831e31b8aSbellard     if(retval > 0) {
99931e31b8aSbellard 	retval = read(bprm->fd, (char *) elf_phdata,
100031e31b8aSbellard 				elf_ex.e_phentsize * elf_ex.e_phnum);
100131e31b8aSbellard     }
100231e31b8aSbellard 
100331e31b8aSbellard     if (retval < 0) {
100431e31b8aSbellard 	perror("load_elf_binary");
100531e31b8aSbellard 	exit(-1);
100631e31b8aSbellard 	free (elf_phdata);
100731e31b8aSbellard 	return -errno;
100831e31b8aSbellard     }
100931e31b8aSbellard 
1010b17780d5Sbellard #ifdef BSWAP_NEEDED
1011b17780d5Sbellard     elf_ppnt = elf_phdata;
1012b17780d5Sbellard     for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
1013b17780d5Sbellard         bswap_phdr(elf_ppnt);
1014b17780d5Sbellard     }
1015b17780d5Sbellard #endif
101631e31b8aSbellard     elf_ppnt = elf_phdata;
101731e31b8aSbellard 
101831e31b8aSbellard     elf_bss = 0;
101931e31b8aSbellard     elf_brk = 0;
102031e31b8aSbellard 
102131e31b8aSbellard 
102231e31b8aSbellard     elf_stack = ~0UL;
102331e31b8aSbellard     elf_interpreter = NULL;
102431e31b8aSbellard     start_code = ~0UL;
102531e31b8aSbellard     end_code = 0;
102631e31b8aSbellard     end_data = 0;
102731e31b8aSbellard 
102831e31b8aSbellard     for(i=0;i < elf_ex.e_phnum; i++) {
102931e31b8aSbellard 	if (elf_ppnt->p_type == PT_INTERP) {
103031e31b8aSbellard 	    if ( elf_interpreter != NULL )
103131e31b8aSbellard 	    {
103231e31b8aSbellard 		free (elf_phdata);
103331e31b8aSbellard 		free(elf_interpreter);
103431e31b8aSbellard 		close(bprm->fd);
103531e31b8aSbellard 		return -EINVAL;
103631e31b8aSbellard 	    }
103731e31b8aSbellard 
103831e31b8aSbellard 	    /* This is the program interpreter used for
103931e31b8aSbellard 	     * shared libraries - for now assume that this
104031e31b8aSbellard 	     * is an a.out format binary
104131e31b8aSbellard 	     */
104231e31b8aSbellard 
104332ce6337Sbellard 	    elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
104431e31b8aSbellard 
104531e31b8aSbellard 	    if (elf_interpreter == NULL) {
104631e31b8aSbellard 		free (elf_phdata);
104731e31b8aSbellard 		close(bprm->fd);
104831e31b8aSbellard 		return -ENOMEM;
104931e31b8aSbellard 	    }
105031e31b8aSbellard 
105131e31b8aSbellard 	    retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
105231e31b8aSbellard 	    if(retval >= 0) {
105332ce6337Sbellard 		retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
105431e31b8aSbellard 	    }
105531e31b8aSbellard 	    if(retval < 0) {
105631e31b8aSbellard 	 	perror("load_elf_binary2");
105731e31b8aSbellard 		exit(-1);
105831e31b8aSbellard 	    }
105931e31b8aSbellard 
106031e31b8aSbellard 	    /* If the program interpreter is one of these two,
106131e31b8aSbellard 	       then assume an iBCS2 image. Otherwise assume
106231e31b8aSbellard 	       a native linux image. */
106331e31b8aSbellard 
106431e31b8aSbellard 	    /* JRP - Need to add X86 lib dir stuff here... */
106531e31b8aSbellard 
106631e31b8aSbellard 	    if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
106731e31b8aSbellard 		strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
106831e31b8aSbellard 	      ibcs2_interpreter = 1;
106931e31b8aSbellard 	    }
107031e31b8aSbellard 
107131e31b8aSbellard #if 0
107231e31b8aSbellard 	    printf("Using ELF interpreter %s\n", elf_interpreter);
107331e31b8aSbellard #endif
107431e31b8aSbellard 	    if (retval >= 0) {
107532ce6337Sbellard 		retval = open(path(elf_interpreter), O_RDONLY);
107631e31b8aSbellard 		if(retval >= 0) {
107731e31b8aSbellard 		    interpreter_fd = retval;
107831e31b8aSbellard 		}
107931e31b8aSbellard 		else {
108031e31b8aSbellard 		    perror(elf_interpreter);
108131e31b8aSbellard 		    exit(-1);
108231e31b8aSbellard 		    /* retval = -errno; */
108331e31b8aSbellard 		}
108431e31b8aSbellard 	    }
108531e31b8aSbellard 
108631e31b8aSbellard 	    if (retval >= 0) {
108731e31b8aSbellard 		retval = lseek(interpreter_fd, 0, SEEK_SET);
108831e31b8aSbellard 		if(retval >= 0) {
108931e31b8aSbellard 		    retval = read(interpreter_fd,bprm->buf,128);
109031e31b8aSbellard 		}
109131e31b8aSbellard 	    }
109231e31b8aSbellard 	    if (retval >= 0) {
109331e31b8aSbellard 		interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
109431e31b8aSbellard 		interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */
109531e31b8aSbellard 	    }
109631e31b8aSbellard 	    if (retval < 0) {
109731e31b8aSbellard 		perror("load_elf_binary3");
109831e31b8aSbellard 		exit(-1);
109931e31b8aSbellard 		free (elf_phdata);
110031e31b8aSbellard 		free(elf_interpreter);
110131e31b8aSbellard 		close(bprm->fd);
110231e31b8aSbellard 		return retval;
110331e31b8aSbellard 	    }
110431e31b8aSbellard 	}
110531e31b8aSbellard 	elf_ppnt++;
110631e31b8aSbellard     }
110731e31b8aSbellard 
110831e31b8aSbellard     /* Some simple consistency checks for the interpreter */
110931e31b8aSbellard     if (elf_interpreter){
111031e31b8aSbellard 	interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
111131e31b8aSbellard 
111231e31b8aSbellard 	/* Now figure out which format our binary is */
111331e31b8aSbellard 	if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
111431e31b8aSbellard 	    	(N_MAGIC(interp_ex) != QMAGIC)) {
111531e31b8aSbellard 	  interpreter_type = INTERPRETER_ELF;
111631e31b8aSbellard 	}
111731e31b8aSbellard 
111831e31b8aSbellard 	if (interp_elf_ex.e_ident[0] != 0x7f ||
111931e31b8aSbellard 	    	strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) {
112031e31b8aSbellard 	    interpreter_type &= ~INTERPRETER_ELF;
112131e31b8aSbellard 	}
112231e31b8aSbellard 
112331e31b8aSbellard 	if (!interpreter_type) {
112431e31b8aSbellard 	    free(elf_interpreter);
112531e31b8aSbellard 	    free(elf_phdata);
112631e31b8aSbellard 	    close(bprm->fd);
112731e31b8aSbellard 	    return -ELIBBAD;
112831e31b8aSbellard 	}
112931e31b8aSbellard     }
113031e31b8aSbellard 
113131e31b8aSbellard     /* OK, we are done with that, now set up the arg stuff,
113231e31b8aSbellard        and then start this sucker up */
113331e31b8aSbellard 
1134e5fe0c52Spbrook     {
113531e31b8aSbellard 	char * passed_p;
113631e31b8aSbellard 
113731e31b8aSbellard 	if (interpreter_type == INTERPRETER_AOUT) {
1138eba2af63Sbellard 	    snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
113931e31b8aSbellard 	    passed_p = passed_fileno;
114031e31b8aSbellard 
114131e31b8aSbellard 	    if (elf_interpreter) {
1142e5fe0c52Spbrook 		bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p);
114331e31b8aSbellard 		bprm->argc++;
114431e31b8aSbellard 	    }
114531e31b8aSbellard 	}
114631e31b8aSbellard 	if (!bprm->p) {
114731e31b8aSbellard 	    if (elf_interpreter) {
114831e31b8aSbellard 	        free(elf_interpreter);
114931e31b8aSbellard 	    }
115031e31b8aSbellard 	    free (elf_phdata);
115131e31b8aSbellard 	    close(bprm->fd);
115231e31b8aSbellard 	    return -E2BIG;
115331e31b8aSbellard 	}
115431e31b8aSbellard     }
115531e31b8aSbellard 
115631e31b8aSbellard     /* OK, This is the point of no return */
115731e31b8aSbellard     info->end_data = 0;
115831e31b8aSbellard     info->end_code = 0;
115931e31b8aSbellard     info->start_mmap = (unsigned long)ELF_START_MMAP;
116031e31b8aSbellard     info->mmap = 0;
116131e31b8aSbellard     elf_entry = (unsigned long) elf_ex.e_entry;
116231e31b8aSbellard 
116331e31b8aSbellard     /* Do this so that we can load the interpreter, if need be.  We will
116431e31b8aSbellard        change some of these later */
116531e31b8aSbellard     info->rss = 0;
116631e31b8aSbellard     bprm->p = setup_arg_pages(bprm->p, bprm, info);
116731e31b8aSbellard     info->start_stack = bprm->p;
116831e31b8aSbellard 
116931e31b8aSbellard     /* Now we do a little grungy work by mmaping the ELF image into
117031e31b8aSbellard      * the correct location in memory.  At this point, we assume that
117131e31b8aSbellard      * the image should be loaded at fixed address, not at a variable
117231e31b8aSbellard      * address.
117331e31b8aSbellard      */
117431e31b8aSbellard 
117531e31b8aSbellard     for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
117631e31b8aSbellard         int elf_prot = 0;
117709bfb054Sbellard         int elf_flags = 0;
117809bfb054Sbellard         unsigned long error;
117909bfb054Sbellard 
118009bfb054Sbellard 	if (elf_ppnt->p_type != PT_LOAD)
118109bfb054Sbellard             continue;
118209bfb054Sbellard 
118331e31b8aSbellard         if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
118431e31b8aSbellard         if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
118531e31b8aSbellard         if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
118609bfb054Sbellard         elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
118709bfb054Sbellard         if (elf_ex.e_type == ET_EXEC || load_addr_set) {
118809bfb054Sbellard             elf_flags |= MAP_FIXED;
118909bfb054Sbellard         } else if (elf_ex.e_type == ET_DYN) {
119009bfb054Sbellard             /* Try and get dynamic programs out of the way of the default mmap
119109bfb054Sbellard                base, as well as whatever program they might try to exec.  This
119209bfb054Sbellard                is because the brk will follow the loader, and is not movable.  */
119309bfb054Sbellard             /* NOTE: for qemu, we do a big mmap to get enough space
1194*e91c8a77Sths                without hardcoding any address */
119554936004Sbellard             error = target_mmap(0, ET_DYN_MAP_SIZE,
119609bfb054Sbellard                                 PROT_NONE, MAP_PRIVATE | MAP_ANON,
119709bfb054Sbellard                                 -1, 0);
119809bfb054Sbellard             if (error == -1) {
119909bfb054Sbellard                 perror("mmap");
120009bfb054Sbellard                 exit(-1);
120109bfb054Sbellard             }
120254936004Sbellard             load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
120309bfb054Sbellard         }
120431e31b8aSbellard 
120554936004Sbellard         error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
120631e31b8aSbellard                             (elf_ppnt->p_filesz +
120754936004Sbellard                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
120831e31b8aSbellard                             elf_prot,
120931e31b8aSbellard                             (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
121031e31b8aSbellard                             bprm->fd,
121131e31b8aSbellard                             (elf_ppnt->p_offset -
121254936004Sbellard                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
121309bfb054Sbellard         if (error == -1) {
121431e31b8aSbellard             perror("mmap");
121531e31b8aSbellard             exit(-1);
121631e31b8aSbellard         }
121731e31b8aSbellard 
121831e31b8aSbellard #ifdef LOW_ELF_STACK
121954936004Sbellard         if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
122054936004Sbellard             elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr);
122131e31b8aSbellard #endif
122231e31b8aSbellard 
122331e31b8aSbellard         if (!load_addr_set) {
122431e31b8aSbellard             load_addr_set = 1;
122509bfb054Sbellard             load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
122609bfb054Sbellard             if (elf_ex.e_type == ET_DYN) {
122709bfb054Sbellard                 load_bias += error -
122854936004Sbellard                     TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
122909bfb054Sbellard                 load_addr += load_bias;
123084409ddbSj_mayer                 reloc_func_desc = load_bias;
123109bfb054Sbellard             }
123231e31b8aSbellard         }
123331e31b8aSbellard         k = elf_ppnt->p_vaddr;
123409bfb054Sbellard         if (k < start_code)
123509bfb054Sbellard             start_code = k;
123631e31b8aSbellard         k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
123709bfb054Sbellard         if (k > elf_bss)
123809bfb054Sbellard             elf_bss = k;
123931e31b8aSbellard         if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
124031e31b8aSbellard             end_code = k;
124109bfb054Sbellard         if (end_data < k)
124209bfb054Sbellard             end_data = k;
124331e31b8aSbellard         k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
124431e31b8aSbellard         if (k > elf_brk) elf_brk = k;
124531e31b8aSbellard     }
124609bfb054Sbellard 
124709bfb054Sbellard     elf_entry += load_bias;
124809bfb054Sbellard     elf_bss += load_bias;
124909bfb054Sbellard     elf_brk += load_bias;
125009bfb054Sbellard     start_code += load_bias;
125109bfb054Sbellard     end_code += load_bias;
125209bfb054Sbellard     //    start_data += load_bias;
125309bfb054Sbellard     end_data += load_bias;
125431e31b8aSbellard 
125531e31b8aSbellard     if (elf_interpreter) {
125631e31b8aSbellard 	if (interpreter_type & 1) {
125731e31b8aSbellard 	    elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
125831e31b8aSbellard 	}
125931e31b8aSbellard 	else if (interpreter_type & 2) {
126031e31b8aSbellard 	    elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
126131e31b8aSbellard 					    &interp_load_addr);
126231e31b8aSbellard 	}
126384409ddbSj_mayer         reloc_func_desc = interp_load_addr;
126431e31b8aSbellard 
126531e31b8aSbellard 	close(interpreter_fd);
126631e31b8aSbellard 	free(elf_interpreter);
126731e31b8aSbellard 
126831e31b8aSbellard 	if (elf_entry == ~0UL) {
126931e31b8aSbellard 	    printf("Unable to load interpreter\n");
127031e31b8aSbellard 	    free(elf_phdata);
127131e31b8aSbellard 	    exit(-1);
127231e31b8aSbellard 	    return 0;
127331e31b8aSbellard 	}
127431e31b8aSbellard     }
127531e31b8aSbellard 
127631e31b8aSbellard     free(elf_phdata);
127731e31b8aSbellard 
1278689f936fSbellard     if (loglevel)
1279689f936fSbellard 	load_symbols(&elf_ex, bprm->fd);
1280689f936fSbellard 
128131e31b8aSbellard     if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
128231e31b8aSbellard     info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
128331e31b8aSbellard 
128431e31b8aSbellard #ifdef LOW_ELF_STACK
128531e31b8aSbellard     info->start_stack = bprm->p = elf_stack - 4;
128631e31b8aSbellard #endif
128753a5960aSpbrook     bprm->p = create_elf_tables(bprm->p,
128831e31b8aSbellard 		    bprm->argc,
128931e31b8aSbellard 		    bprm->envc,
1290a1516e92Sbellard                     &elf_ex,
129109bfb054Sbellard                     load_addr, load_bias,
129231e31b8aSbellard 		    interp_load_addr,
129331e31b8aSbellard 		    (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
129431e31b8aSbellard 		    info);
129531e31b8aSbellard     info->start_brk = info->brk = elf_brk;
129631e31b8aSbellard     info->end_code = end_code;
129731e31b8aSbellard     info->start_code = start_code;
1298e5fe0c52Spbrook     info->start_data = end_code;
129931e31b8aSbellard     info->end_data = end_data;
130031e31b8aSbellard     info->start_stack = bprm->p;
130131e31b8aSbellard 
130231e31b8aSbellard     /* Calling set_brk effectively mmaps the pages that we need for the bss and break
130331e31b8aSbellard        sections */
130431e31b8aSbellard     set_brk(elf_bss, elf_brk);
130531e31b8aSbellard 
1306768a4a36Sths     padzero(elf_bss, elf_brk);
130731e31b8aSbellard 
130831e31b8aSbellard #if 0
130931e31b8aSbellard     printf("(start_brk) %x\n" , info->start_brk);
131031e31b8aSbellard     printf("(end_code) %x\n" , info->end_code);
131131e31b8aSbellard     printf("(start_code) %x\n" , info->start_code);
131231e31b8aSbellard     printf("(end_data) %x\n" , info->end_data);
131331e31b8aSbellard     printf("(start_stack) %x\n" , info->start_stack);
131431e31b8aSbellard     printf("(brk) %x\n" , info->brk);
131531e31b8aSbellard #endif
131631e31b8aSbellard 
131731e31b8aSbellard     if ( info->personality == PER_SVR4 )
131831e31b8aSbellard     {
131931e31b8aSbellard 	    /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
132031e31b8aSbellard 	       and some applications "depend" upon this behavior.
132131e31b8aSbellard 	       Since we do not have the power to recompile these, we
132231e31b8aSbellard 	       emulate the SVr4 behavior.  Sigh.  */
132383fb7adfSbellard 	    mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
132431e31b8aSbellard                                       MAP_FIXED | MAP_PRIVATE, -1, 0);
132531e31b8aSbellard     }
132631e31b8aSbellard 
132731e31b8aSbellard     info->entry = elf_entry;
132831e31b8aSbellard 
132931e31b8aSbellard     return 0;
133031e31b8aSbellard }
133131e31b8aSbellard 
133231e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd)
133331e31b8aSbellard {
133431e31b8aSbellard     printf("a.out interpreter not yet supported\n");
133531e31b8aSbellard     return(0);
133631e31b8aSbellard }
133731e31b8aSbellard 
1338e5fe0c52Spbrook void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
1339e5fe0c52Spbrook {
1340e5fe0c52Spbrook     init_thread(regs, infop);
1341e5fe0c52Spbrook }
1342