xref: /qemu/linux-user/elfload.c (revision 92a343da3f50db3130f988b14650eb09e9748d11)
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;
328072ae847Sths   regs->regs[15] = infop->start_stack;
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) {
802e91c8a77Sths             /* 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;
8960774bed1Sblueswir1 #if (ELF_CLASS == ELFCLASS64)
8970774bed1Sblueswir1     // Disas uses 32 bit symbols
8980774bed1Sblueswir1     struct elf32_sym *syms32 = NULL;
8990774bed1Sblueswir1     struct elf_sym *sym;
9000774bed1Sblueswir1 #endif
90131e31b8aSbellard 
902689f936fSbellard     lseek(fd, hdr->e_shoff, SEEK_SET);
903689f936fSbellard     for (i = 0; i < hdr->e_shnum; i++) {
904689f936fSbellard 	if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
905689f936fSbellard 	    return;
906689f936fSbellard #ifdef BSWAP_NEEDED
907689f936fSbellard 	bswap_shdr(&sechdr);
908689f936fSbellard #endif
909689f936fSbellard 	if (sechdr.sh_type == SHT_SYMTAB) {
910689f936fSbellard 	    symtab = sechdr;
911689f936fSbellard 	    lseek(fd, hdr->e_shoff
912689f936fSbellard 		  + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
913689f936fSbellard 	    if (read(fd, &strtab, sizeof(strtab))
914689f936fSbellard 		!= sizeof(strtab))
915689f936fSbellard 		return;
916689f936fSbellard #ifdef BSWAP_NEEDED
917689f936fSbellard 	    bswap_shdr(&strtab);
918689f936fSbellard #endif
919689f936fSbellard 	    goto found;
920689f936fSbellard 	}
921689f936fSbellard     }
922689f936fSbellard     return; /* Shouldn't happen... */
923689f936fSbellard 
924689f936fSbellard  found:
925689f936fSbellard     /* Now know where the strtab and symtab are.  Snarf them. */
926e80cfcfcSbellard     s = malloc(sizeof(*s));
927e80cfcfcSbellard     s->disas_symtab = malloc(symtab.sh_size);
9280774bed1Sblueswir1 #if (ELF_CLASS == ELFCLASS64)
9290774bed1Sblueswir1     syms32 = malloc(symtab.sh_size / sizeof(struct elf_sym)
9300774bed1Sblueswir1                     * sizeof(struct elf32_sym));
9310774bed1Sblueswir1 #endif
932e80cfcfcSbellard     s->disas_strtab = strings = malloc(strtab.sh_size);
933e80cfcfcSbellard     if (!s->disas_symtab || !s->disas_strtab)
934689f936fSbellard 	return;
935689f936fSbellard 
936689f936fSbellard     lseek(fd, symtab.sh_offset, SEEK_SET);
937e80cfcfcSbellard     if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size)
938689f936fSbellard 	return;
939689f936fSbellard 
9400774bed1Sblueswir1     for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) {
941689f936fSbellard #ifdef BSWAP_NEEDED
942e80cfcfcSbellard 	bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i);
943689f936fSbellard #endif
9440774bed1Sblueswir1 #if (ELF_CLASS == ELFCLASS64)
9450774bed1Sblueswir1         sym = s->disas_symtab + sizeof(struct elf_sym)*i;
9460774bed1Sblueswir1         syms32[i].st_name = sym->st_name;
9470774bed1Sblueswir1         syms32[i].st_info = sym->st_info;
9480774bed1Sblueswir1         syms32[i].st_other = sym->st_other;
9490774bed1Sblueswir1         syms32[i].st_shndx = sym->st_shndx;
9500774bed1Sblueswir1         syms32[i].st_value = sym->st_value & 0xffffffff;
9510774bed1Sblueswir1         syms32[i].st_size = sym->st_size & 0xffffffff;
9520774bed1Sblueswir1 #endif
9530774bed1Sblueswir1     }
954689f936fSbellard 
9550774bed1Sblueswir1 #if (ELF_CLASS == ELFCLASS64)
9560774bed1Sblueswir1     free(s->disas_symtab);
9570774bed1Sblueswir1     s->disas_symtab = syms32;
9580774bed1Sblueswir1 #endif
959689f936fSbellard     lseek(fd, strtab.sh_offset, SEEK_SET);
960689f936fSbellard     if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
961689f936fSbellard 	return;
962e80cfcfcSbellard     s->disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
963e80cfcfcSbellard     s->next = syminfos;
964e80cfcfcSbellard     syminfos = s;
965689f936fSbellard }
96631e31b8aSbellard 
967e5fe0c52Spbrook int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
96831e31b8aSbellard                     struct image_info * info)
96931e31b8aSbellard {
97031e31b8aSbellard     struct elfhdr elf_ex;
97131e31b8aSbellard     struct elfhdr interp_elf_ex;
97231e31b8aSbellard     struct exec interp_ex;
97331e31b8aSbellard     int interpreter_fd = -1; /* avoid warning */
97409bfb054Sbellard     unsigned long load_addr, load_bias;
97531e31b8aSbellard     int load_addr_set = 0;
97631e31b8aSbellard     unsigned int interpreter_type = INTERPRETER_NONE;
97731e31b8aSbellard     unsigned char ibcs2_interpreter;
97831e31b8aSbellard     int i;
97954936004Sbellard     unsigned long mapped_addr;
98031e31b8aSbellard     struct elf_phdr * elf_ppnt;
98131e31b8aSbellard     struct elf_phdr *elf_phdata;
98231e31b8aSbellard     unsigned long elf_bss, k, elf_brk;
98331e31b8aSbellard     int retval;
98431e31b8aSbellard     char * elf_interpreter;
98531e31b8aSbellard     unsigned long elf_entry, interp_load_addr = 0;
98631e31b8aSbellard     int status;
98731e31b8aSbellard     unsigned long start_code, end_code, end_data;
98884409ddbSj_mayer     unsigned long reloc_func_desc = 0;
98931e31b8aSbellard     unsigned long elf_stack;
99031e31b8aSbellard     char passed_fileno[6];
99131e31b8aSbellard 
99231e31b8aSbellard     ibcs2_interpreter = 0;
99331e31b8aSbellard     status = 0;
99431e31b8aSbellard     load_addr = 0;
99509bfb054Sbellard     load_bias = 0;
99631e31b8aSbellard     elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
99731e31b8aSbellard #ifdef BSWAP_NEEDED
99831e31b8aSbellard     bswap_ehdr(&elf_ex);
99931e31b8aSbellard #endif
100031e31b8aSbellard 
100131e31b8aSbellard     /* First of all, some simple consistency checks */
100231e31b8aSbellard     if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
100331e31b8aSbellard        				(! elf_check_arch(elf_ex.e_machine))) {
100431e31b8aSbellard 	    return -ENOEXEC;
100531e31b8aSbellard     }
100631e31b8aSbellard 
1007e5fe0c52Spbrook     bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
1008e5fe0c52Spbrook     bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
1009e5fe0c52Spbrook     bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
1010e5fe0c52Spbrook     if (!bprm->p) {
1011e5fe0c52Spbrook         retval = -E2BIG;
1012e5fe0c52Spbrook     }
1013e5fe0c52Spbrook 
101431e31b8aSbellard     /* Now read in all of the header information */
101531e31b8aSbellard     elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
101631e31b8aSbellard     if (elf_phdata == NULL) {
101731e31b8aSbellard 	return -ENOMEM;
101831e31b8aSbellard     }
101931e31b8aSbellard 
102031e31b8aSbellard     retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
102131e31b8aSbellard     if(retval > 0) {
102231e31b8aSbellard 	retval = read(bprm->fd, (char *) elf_phdata,
102331e31b8aSbellard 				elf_ex.e_phentsize * elf_ex.e_phnum);
102431e31b8aSbellard     }
102531e31b8aSbellard 
102631e31b8aSbellard     if (retval < 0) {
102731e31b8aSbellard 	perror("load_elf_binary");
102831e31b8aSbellard 	exit(-1);
102931e31b8aSbellard 	free (elf_phdata);
103031e31b8aSbellard 	return -errno;
103131e31b8aSbellard     }
103231e31b8aSbellard 
1033b17780d5Sbellard #ifdef BSWAP_NEEDED
1034b17780d5Sbellard     elf_ppnt = elf_phdata;
1035b17780d5Sbellard     for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
1036b17780d5Sbellard         bswap_phdr(elf_ppnt);
1037b17780d5Sbellard     }
1038b17780d5Sbellard #endif
103931e31b8aSbellard     elf_ppnt = elf_phdata;
104031e31b8aSbellard 
104131e31b8aSbellard     elf_bss = 0;
104231e31b8aSbellard     elf_brk = 0;
104331e31b8aSbellard 
104431e31b8aSbellard 
104531e31b8aSbellard     elf_stack = ~0UL;
104631e31b8aSbellard     elf_interpreter = NULL;
104731e31b8aSbellard     start_code = ~0UL;
104831e31b8aSbellard     end_code = 0;
104931e31b8aSbellard     end_data = 0;
105031e31b8aSbellard 
105131e31b8aSbellard     for(i=0;i < elf_ex.e_phnum; i++) {
105231e31b8aSbellard 	if (elf_ppnt->p_type == PT_INTERP) {
105331e31b8aSbellard 	    if ( elf_interpreter != NULL )
105431e31b8aSbellard 	    {
105531e31b8aSbellard 		free (elf_phdata);
105631e31b8aSbellard 		free(elf_interpreter);
105731e31b8aSbellard 		close(bprm->fd);
105831e31b8aSbellard 		return -EINVAL;
105931e31b8aSbellard 	    }
106031e31b8aSbellard 
106131e31b8aSbellard 	    /* This is the program interpreter used for
106231e31b8aSbellard 	     * shared libraries - for now assume that this
106331e31b8aSbellard 	     * is an a.out format binary
106431e31b8aSbellard 	     */
106531e31b8aSbellard 
106632ce6337Sbellard 	    elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
106731e31b8aSbellard 
106831e31b8aSbellard 	    if (elf_interpreter == NULL) {
106931e31b8aSbellard 		free (elf_phdata);
107031e31b8aSbellard 		close(bprm->fd);
107131e31b8aSbellard 		return -ENOMEM;
107231e31b8aSbellard 	    }
107331e31b8aSbellard 
107431e31b8aSbellard 	    retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
107531e31b8aSbellard 	    if(retval >= 0) {
107632ce6337Sbellard 		retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
107731e31b8aSbellard 	    }
107831e31b8aSbellard 	    if(retval < 0) {
107931e31b8aSbellard 	 	perror("load_elf_binary2");
108031e31b8aSbellard 		exit(-1);
108131e31b8aSbellard 	    }
108231e31b8aSbellard 
108331e31b8aSbellard 	    /* If the program interpreter is one of these two,
108431e31b8aSbellard 	       then assume an iBCS2 image. Otherwise assume
108531e31b8aSbellard 	       a native linux image. */
108631e31b8aSbellard 
108731e31b8aSbellard 	    /* JRP - Need to add X86 lib dir stuff here... */
108831e31b8aSbellard 
108931e31b8aSbellard 	    if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
109031e31b8aSbellard 		strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
109131e31b8aSbellard 	      ibcs2_interpreter = 1;
109231e31b8aSbellard 	    }
109331e31b8aSbellard 
109431e31b8aSbellard #if 0
109531e31b8aSbellard 	    printf("Using ELF interpreter %s\n", elf_interpreter);
109631e31b8aSbellard #endif
109731e31b8aSbellard 	    if (retval >= 0) {
109832ce6337Sbellard 		retval = open(path(elf_interpreter), O_RDONLY);
109931e31b8aSbellard 		if(retval >= 0) {
110031e31b8aSbellard 		    interpreter_fd = retval;
110131e31b8aSbellard 		}
110231e31b8aSbellard 		else {
110331e31b8aSbellard 		    perror(elf_interpreter);
110431e31b8aSbellard 		    exit(-1);
110531e31b8aSbellard 		    /* retval = -errno; */
110631e31b8aSbellard 		}
110731e31b8aSbellard 	    }
110831e31b8aSbellard 
110931e31b8aSbellard 	    if (retval >= 0) {
111031e31b8aSbellard 		retval = lseek(interpreter_fd, 0, SEEK_SET);
111131e31b8aSbellard 		if(retval >= 0) {
111231e31b8aSbellard 		    retval = read(interpreter_fd,bprm->buf,128);
111331e31b8aSbellard 		}
111431e31b8aSbellard 	    }
111531e31b8aSbellard 	    if (retval >= 0) {
111631e31b8aSbellard 		interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
111731e31b8aSbellard 		interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */
111831e31b8aSbellard 	    }
111931e31b8aSbellard 	    if (retval < 0) {
112031e31b8aSbellard 		perror("load_elf_binary3");
112131e31b8aSbellard 		exit(-1);
112231e31b8aSbellard 		free (elf_phdata);
112331e31b8aSbellard 		free(elf_interpreter);
112431e31b8aSbellard 		close(bprm->fd);
112531e31b8aSbellard 		return retval;
112631e31b8aSbellard 	    }
112731e31b8aSbellard 	}
112831e31b8aSbellard 	elf_ppnt++;
112931e31b8aSbellard     }
113031e31b8aSbellard 
113131e31b8aSbellard     /* Some simple consistency checks for the interpreter */
113231e31b8aSbellard     if (elf_interpreter){
113331e31b8aSbellard 	interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
113431e31b8aSbellard 
113531e31b8aSbellard 	/* Now figure out which format our binary is */
113631e31b8aSbellard 	if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
113731e31b8aSbellard 	    	(N_MAGIC(interp_ex) != QMAGIC)) {
113831e31b8aSbellard 	  interpreter_type = INTERPRETER_ELF;
113931e31b8aSbellard 	}
114031e31b8aSbellard 
114131e31b8aSbellard 	if (interp_elf_ex.e_ident[0] != 0x7f ||
114231e31b8aSbellard 	    	strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) {
114331e31b8aSbellard 	    interpreter_type &= ~INTERPRETER_ELF;
114431e31b8aSbellard 	}
114531e31b8aSbellard 
114631e31b8aSbellard 	if (!interpreter_type) {
114731e31b8aSbellard 	    free(elf_interpreter);
114831e31b8aSbellard 	    free(elf_phdata);
114931e31b8aSbellard 	    close(bprm->fd);
115031e31b8aSbellard 	    return -ELIBBAD;
115131e31b8aSbellard 	}
115231e31b8aSbellard     }
115331e31b8aSbellard 
115431e31b8aSbellard     /* OK, we are done with that, now set up the arg stuff,
115531e31b8aSbellard        and then start this sucker up */
115631e31b8aSbellard 
1157e5fe0c52Spbrook     {
115831e31b8aSbellard 	char * passed_p;
115931e31b8aSbellard 
116031e31b8aSbellard 	if (interpreter_type == INTERPRETER_AOUT) {
1161eba2af63Sbellard 	    snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
116231e31b8aSbellard 	    passed_p = passed_fileno;
116331e31b8aSbellard 
116431e31b8aSbellard 	    if (elf_interpreter) {
1165e5fe0c52Spbrook 		bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p);
116631e31b8aSbellard 		bprm->argc++;
116731e31b8aSbellard 	    }
116831e31b8aSbellard 	}
116931e31b8aSbellard 	if (!bprm->p) {
117031e31b8aSbellard 	    if (elf_interpreter) {
117131e31b8aSbellard 	        free(elf_interpreter);
117231e31b8aSbellard 	    }
117331e31b8aSbellard 	    free (elf_phdata);
117431e31b8aSbellard 	    close(bprm->fd);
117531e31b8aSbellard 	    return -E2BIG;
117631e31b8aSbellard 	}
117731e31b8aSbellard     }
117831e31b8aSbellard 
117931e31b8aSbellard     /* OK, This is the point of no return */
118031e31b8aSbellard     info->end_data = 0;
118131e31b8aSbellard     info->end_code = 0;
118231e31b8aSbellard     info->start_mmap = (unsigned long)ELF_START_MMAP;
118331e31b8aSbellard     info->mmap = 0;
118431e31b8aSbellard     elf_entry = (unsigned long) elf_ex.e_entry;
118531e31b8aSbellard 
118631e31b8aSbellard     /* Do this so that we can load the interpreter, if need be.  We will
118731e31b8aSbellard        change some of these later */
118831e31b8aSbellard     info->rss = 0;
118931e31b8aSbellard     bprm->p = setup_arg_pages(bprm->p, bprm, info);
119031e31b8aSbellard     info->start_stack = bprm->p;
119131e31b8aSbellard 
119231e31b8aSbellard     /* Now we do a little grungy work by mmaping the ELF image into
119331e31b8aSbellard      * the correct location in memory.  At this point, we assume that
119431e31b8aSbellard      * the image should be loaded at fixed address, not at a variable
119531e31b8aSbellard      * address.
119631e31b8aSbellard      */
119731e31b8aSbellard 
119831e31b8aSbellard     for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
119931e31b8aSbellard         int elf_prot = 0;
120009bfb054Sbellard         int elf_flags = 0;
120109bfb054Sbellard         unsigned long error;
120209bfb054Sbellard 
120309bfb054Sbellard 	if (elf_ppnt->p_type != PT_LOAD)
120409bfb054Sbellard             continue;
120509bfb054Sbellard 
120631e31b8aSbellard         if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
120731e31b8aSbellard         if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
120831e31b8aSbellard         if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
120909bfb054Sbellard         elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
121009bfb054Sbellard         if (elf_ex.e_type == ET_EXEC || load_addr_set) {
121109bfb054Sbellard             elf_flags |= MAP_FIXED;
121209bfb054Sbellard         } else if (elf_ex.e_type == ET_DYN) {
121309bfb054Sbellard             /* Try and get dynamic programs out of the way of the default mmap
121409bfb054Sbellard                base, as well as whatever program they might try to exec.  This
121509bfb054Sbellard                is because the brk will follow the loader, and is not movable.  */
121609bfb054Sbellard             /* NOTE: for qemu, we do a big mmap to get enough space
1217e91c8a77Sths                without hardcoding any address */
121854936004Sbellard             error = target_mmap(0, ET_DYN_MAP_SIZE,
121909bfb054Sbellard                                 PROT_NONE, MAP_PRIVATE | MAP_ANON,
122009bfb054Sbellard                                 -1, 0);
122109bfb054Sbellard             if (error == -1) {
122209bfb054Sbellard                 perror("mmap");
122309bfb054Sbellard                 exit(-1);
122409bfb054Sbellard             }
122554936004Sbellard             load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
122609bfb054Sbellard         }
122731e31b8aSbellard 
122854936004Sbellard         error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
122931e31b8aSbellard                             (elf_ppnt->p_filesz +
123054936004Sbellard                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
123131e31b8aSbellard                             elf_prot,
123231e31b8aSbellard                             (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
123331e31b8aSbellard                             bprm->fd,
123431e31b8aSbellard                             (elf_ppnt->p_offset -
123554936004Sbellard                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
123609bfb054Sbellard         if (error == -1) {
123731e31b8aSbellard             perror("mmap");
123831e31b8aSbellard             exit(-1);
123931e31b8aSbellard         }
124031e31b8aSbellard 
124131e31b8aSbellard #ifdef LOW_ELF_STACK
124254936004Sbellard         if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
124354936004Sbellard             elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr);
124431e31b8aSbellard #endif
124531e31b8aSbellard 
124631e31b8aSbellard         if (!load_addr_set) {
124731e31b8aSbellard             load_addr_set = 1;
124809bfb054Sbellard             load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
124909bfb054Sbellard             if (elf_ex.e_type == ET_DYN) {
125009bfb054Sbellard                 load_bias += error -
125154936004Sbellard                     TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
125209bfb054Sbellard                 load_addr += load_bias;
125384409ddbSj_mayer                 reloc_func_desc = load_bias;
125409bfb054Sbellard             }
125531e31b8aSbellard         }
125631e31b8aSbellard         k = elf_ppnt->p_vaddr;
125709bfb054Sbellard         if (k < start_code)
125809bfb054Sbellard             start_code = k;
125931e31b8aSbellard         k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
126009bfb054Sbellard         if (k > elf_bss)
126109bfb054Sbellard             elf_bss = k;
126231e31b8aSbellard         if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
126331e31b8aSbellard             end_code = k;
126409bfb054Sbellard         if (end_data < k)
126509bfb054Sbellard             end_data = k;
126631e31b8aSbellard         k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
126731e31b8aSbellard         if (k > elf_brk) elf_brk = k;
126831e31b8aSbellard     }
126909bfb054Sbellard 
127009bfb054Sbellard     elf_entry += load_bias;
127109bfb054Sbellard     elf_bss += load_bias;
127209bfb054Sbellard     elf_brk += load_bias;
127309bfb054Sbellard     start_code += load_bias;
127409bfb054Sbellard     end_code += load_bias;
127509bfb054Sbellard     //    start_data += load_bias;
127609bfb054Sbellard     end_data += load_bias;
127731e31b8aSbellard 
127831e31b8aSbellard     if (elf_interpreter) {
127931e31b8aSbellard 	if (interpreter_type & 1) {
128031e31b8aSbellard 	    elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
128131e31b8aSbellard 	}
128231e31b8aSbellard 	else if (interpreter_type & 2) {
128331e31b8aSbellard 	    elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
128431e31b8aSbellard 					    &interp_load_addr);
128531e31b8aSbellard 	}
128684409ddbSj_mayer         reloc_func_desc = interp_load_addr;
128731e31b8aSbellard 
128831e31b8aSbellard 	close(interpreter_fd);
128931e31b8aSbellard 	free(elf_interpreter);
129031e31b8aSbellard 
129131e31b8aSbellard 	if (elf_entry == ~0UL) {
129231e31b8aSbellard 	    printf("Unable to load interpreter\n");
129331e31b8aSbellard 	    free(elf_phdata);
129431e31b8aSbellard 	    exit(-1);
129531e31b8aSbellard 	    return 0;
129631e31b8aSbellard 	}
129731e31b8aSbellard     }
129831e31b8aSbellard 
129931e31b8aSbellard     free(elf_phdata);
130031e31b8aSbellard 
1301689f936fSbellard     if (loglevel)
1302689f936fSbellard 	load_symbols(&elf_ex, bprm->fd);
1303689f936fSbellard 
130431e31b8aSbellard     if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
130531e31b8aSbellard     info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
130631e31b8aSbellard 
130731e31b8aSbellard #ifdef LOW_ELF_STACK
130831e31b8aSbellard     info->start_stack = bprm->p = elf_stack - 4;
130931e31b8aSbellard #endif
131053a5960aSpbrook     bprm->p = create_elf_tables(bprm->p,
131131e31b8aSbellard 		    bprm->argc,
131231e31b8aSbellard 		    bprm->envc,
1313a1516e92Sbellard                     &elf_ex,
131409bfb054Sbellard                     load_addr, load_bias,
131531e31b8aSbellard 		    interp_load_addr,
131631e31b8aSbellard 		    (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
131731e31b8aSbellard 		    info);
1318*92a343daSj_mayer     info->load_addr = reloc_func_desc;
131931e31b8aSbellard     info->start_brk = info->brk = elf_brk;
132031e31b8aSbellard     info->end_code = end_code;
132131e31b8aSbellard     info->start_code = start_code;
1322e5fe0c52Spbrook     info->start_data = end_code;
132331e31b8aSbellard     info->end_data = end_data;
132431e31b8aSbellard     info->start_stack = bprm->p;
132531e31b8aSbellard 
132631e31b8aSbellard     /* Calling set_brk effectively mmaps the pages that we need for the bss and break
132731e31b8aSbellard        sections */
132831e31b8aSbellard     set_brk(elf_bss, elf_brk);
132931e31b8aSbellard 
1330768a4a36Sths     padzero(elf_bss, elf_brk);
133131e31b8aSbellard 
133231e31b8aSbellard #if 0
133331e31b8aSbellard     printf("(start_brk) %x\n" , info->start_brk);
133431e31b8aSbellard     printf("(end_code) %x\n" , info->end_code);
133531e31b8aSbellard     printf("(start_code) %x\n" , info->start_code);
133631e31b8aSbellard     printf("(end_data) %x\n" , info->end_data);
133731e31b8aSbellard     printf("(start_stack) %x\n" , info->start_stack);
133831e31b8aSbellard     printf("(brk) %x\n" , info->brk);
133931e31b8aSbellard #endif
134031e31b8aSbellard 
134131e31b8aSbellard     if ( info->personality == PER_SVR4 )
134231e31b8aSbellard     {
134331e31b8aSbellard 	    /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
134431e31b8aSbellard 	       and some applications "depend" upon this behavior.
134531e31b8aSbellard 	       Since we do not have the power to recompile these, we
134631e31b8aSbellard 	       emulate the SVr4 behavior.  Sigh.  */
134783fb7adfSbellard 	    mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
134831e31b8aSbellard                                       MAP_FIXED | MAP_PRIVATE, -1, 0);
134931e31b8aSbellard     }
135031e31b8aSbellard 
135131e31b8aSbellard     info->entry = elf_entry;
135231e31b8aSbellard 
135331e31b8aSbellard     return 0;
135431e31b8aSbellard }
135531e31b8aSbellard 
135631e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd)
135731e31b8aSbellard {
135831e31b8aSbellard     printf("a.out interpreter not yet supported\n");
135931e31b8aSbellard     return(0);
136031e31b8aSbellard }
136131e31b8aSbellard 
1362e5fe0c52Spbrook void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
1363e5fe0c52Spbrook {
1364e5fe0c52Spbrook     init_thread(regs, infop);
1365e5fe0c52Spbrook }
1366