xref: /qemu/bsd-user/elfload.c (revision 3e8f1628)
184778508Sblueswir1 /* This is the Linux kernel elf-loading code, ported into user space */
284778508Sblueswir1 
32231197cSPeter Maydell #include "qemu/osdep.h"
484778508Sblueswir1 
584778508Sblueswir1 #include "qemu.h"
676cad711SPaolo Bonzini #include "disas/disas.h"
7f348b6d1SVeronia Bahaa #include "qemu/path.h"
884778508Sblueswir1 
9e58ffeb3Smalc #ifdef _ARCH_PPC64
1084778508Sblueswir1 #undef ARCH_DLINFO
1184778508Sblueswir1 #undef ELF_PLATFORM
1284778508Sblueswir1 #undef ELF_HWCAP
1384778508Sblueswir1 #undef ELF_CLASS
1484778508Sblueswir1 #undef ELF_DATA
1584778508Sblueswir1 #undef ELF_ARCH
1684778508Sblueswir1 #endif
1784778508Sblueswir1 
1884778508Sblueswir1 /* from personality.h */
1984778508Sblueswir1 
2084778508Sblueswir1 /*
2184778508Sblueswir1  * Flags for bug emulation.
2284778508Sblueswir1  *
2384778508Sblueswir1  * These occupy the top three bytes.
2484778508Sblueswir1  */
2584778508Sblueswir1 enum {
2684778508Sblueswir1         ADDR_NO_RANDOMIZE =     0x0040000,      /* disable randomization of VA space */
2784778508Sblueswir1         FDPIC_FUNCPTRS =        0x0080000,      /* userspace function ptrs point to descriptors
2884778508Sblueswir1                                                  * (signal handling)
2984778508Sblueswir1                                                  */
3084778508Sblueswir1         MMAP_PAGE_ZERO =        0x0100000,
3184778508Sblueswir1         ADDR_COMPAT_LAYOUT =    0x0200000,
3284778508Sblueswir1         READ_IMPLIES_EXEC =     0x0400000,
3384778508Sblueswir1         ADDR_LIMIT_32BIT =      0x0800000,
3484778508Sblueswir1         SHORT_INODE =           0x1000000,
3584778508Sblueswir1         WHOLE_SECONDS =         0x2000000,
3684778508Sblueswir1         STICKY_TIMEOUTS =       0x4000000,
3784778508Sblueswir1         ADDR_LIMIT_3GB =        0x8000000,
3884778508Sblueswir1 };
3984778508Sblueswir1 
4084778508Sblueswir1 /*
4184778508Sblueswir1  * Personality types.
4284778508Sblueswir1  *
4384778508Sblueswir1  * These go in the low byte.  Avoid using the top bit, it will
4484778508Sblueswir1  * conflict with error returns.
4584778508Sblueswir1  */
4684778508Sblueswir1 enum {
4784778508Sblueswir1         PER_LINUX =             0x0000,
4884778508Sblueswir1         PER_LINUX_32BIT =       0x0000 | ADDR_LIMIT_32BIT,
4984778508Sblueswir1         PER_LINUX_FDPIC =       0x0000 | FDPIC_FUNCPTRS,
5084778508Sblueswir1         PER_SVR4 =              0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
5184778508Sblueswir1         PER_SVR3 =              0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
5284778508Sblueswir1         PER_SCOSVR3 =           0x0003 | STICKY_TIMEOUTS |
5384778508Sblueswir1                                          WHOLE_SECONDS | SHORT_INODE,
5484778508Sblueswir1         PER_OSR5 =              0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
5584778508Sblueswir1         PER_WYSEV386 =          0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
5684778508Sblueswir1         PER_ISCR4 =             0x0005 | STICKY_TIMEOUTS,
5784778508Sblueswir1         PER_BSD =               0x0006,
5884778508Sblueswir1         PER_SUNOS =             0x0006 | STICKY_TIMEOUTS,
5984778508Sblueswir1         PER_XENIX =             0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
6084778508Sblueswir1         PER_LINUX32 =           0x0008,
6184778508Sblueswir1         PER_LINUX32_3GB =       0x0008 | ADDR_LIMIT_3GB,
6284778508Sblueswir1         PER_IRIX32 =            0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
6384778508Sblueswir1         PER_IRIXN32 =           0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
6484778508Sblueswir1         PER_IRIX64 =            0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
6584778508Sblueswir1         PER_RISCOS =            0x000c,
6684778508Sblueswir1         PER_SOLARIS =           0x000d | STICKY_TIMEOUTS,
6784778508Sblueswir1         PER_UW7 =               0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
6884778508Sblueswir1         PER_OSF4 =              0x000f,                  /* OSF/1 v4 */
6984778508Sblueswir1         PER_HPUX =              0x0010,
7084778508Sblueswir1         PER_MASK =              0x00ff,
7184778508Sblueswir1 };
7284778508Sblueswir1 
7384778508Sblueswir1 /*
7484778508Sblueswir1  * Return the base personality without flags.
7584778508Sblueswir1  */
7684778508Sblueswir1 #define personality(pers)       (pers & PER_MASK)
7784778508Sblueswir1 
7884778508Sblueswir1 /* this flag is uneffective under linux too, should be deleted */
7984778508Sblueswir1 #ifndef MAP_DENYWRITE
8084778508Sblueswir1 #define MAP_DENYWRITE 0
8184778508Sblueswir1 #endif
8284778508Sblueswir1 
8384778508Sblueswir1 /* should probably go in elf.h */
8484778508Sblueswir1 #ifndef ELIBBAD
8584778508Sblueswir1 #define ELIBBAD 80
8684778508Sblueswir1 #endif
8784778508Sblueswir1 
8884778508Sblueswir1 #ifdef TARGET_I386
8984778508Sblueswir1 
9084778508Sblueswir1 #define ELF_PLATFORM get_elf_platform()
9184778508Sblueswir1 
9284778508Sblueswir1 static const char *get_elf_platform(void)
9384778508Sblueswir1 {
9484778508Sblueswir1     static char elf_platform[] = "i386";
95dca1173cSAndreas Färber     int family = object_property_get_int(OBJECT(thread_cpu), "family", NULL);
9684778508Sblueswir1     if (family > 6)
9784778508Sblueswir1         family = 6;
9884778508Sblueswir1     if (family >= 3)
9984778508Sblueswir1         elf_platform[1] = '0' + family;
10084778508Sblueswir1     return elf_platform;
10184778508Sblueswir1 }
10284778508Sblueswir1 
10384778508Sblueswir1 #define ELF_HWCAP get_elf_hwcap()
10484778508Sblueswir1 
10584778508Sblueswir1 static uint32_t get_elf_hwcap(void)
10684778508Sblueswir1 {
107dca1173cSAndreas Färber     X86CPU *cpu = X86_CPU(thread_cpu);
108dca1173cSAndreas Färber 
109dca1173cSAndreas Färber     return cpu->env.features[FEAT_1_EDX];
11084778508Sblueswir1 }
11184778508Sblueswir1 
11284778508Sblueswir1 #ifdef TARGET_X86_64
11384778508Sblueswir1 #define ELF_START_MMAP 0x2aaaaab000ULL
11484778508Sblueswir1 #define elf_check_arch(x) ( ((x) == ELF_ARCH) )
11584778508Sblueswir1 
11684778508Sblueswir1 #define ELF_CLASS      ELFCLASS64
11784778508Sblueswir1 #define ELF_DATA       ELFDATA2LSB
11884778508Sblueswir1 #define ELF_ARCH       EM_X86_64
11984778508Sblueswir1 
12084778508Sblueswir1 static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
12184778508Sblueswir1 {
12284778508Sblueswir1     regs->rax = 0;
12384778508Sblueswir1     regs->rsp = infop->start_stack;
12484778508Sblueswir1     regs->rip = infop->entry;
12578cfb07fSJuergen Lock     if (bsd_type == target_freebsd) {
12678cfb07fSJuergen Lock         regs->rdi = infop->start_stack;
12778cfb07fSJuergen Lock     }
12884778508Sblueswir1 }
12984778508Sblueswir1 
13084778508Sblueswir1 #else
13184778508Sblueswir1 
13284778508Sblueswir1 #define ELF_START_MMAP 0x80000000
13384778508Sblueswir1 
13484778508Sblueswir1 /*
13584778508Sblueswir1  * This is used to ensure we don't load something for the wrong architecture.
13684778508Sblueswir1  */
13784778508Sblueswir1 #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
13884778508Sblueswir1 
13984778508Sblueswir1 /*
14084778508Sblueswir1  * These are used to set parameters in the core dumps.
14184778508Sblueswir1  */
14284778508Sblueswir1 #define ELF_CLASS       ELFCLASS32
14384778508Sblueswir1 #define ELF_DATA        ELFDATA2LSB
14484778508Sblueswir1 #define ELF_ARCH        EM_386
14584778508Sblueswir1 
14684778508Sblueswir1 static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
14784778508Sblueswir1 {
14884778508Sblueswir1     regs->esp = infop->start_stack;
14984778508Sblueswir1     regs->eip = infop->entry;
15084778508Sblueswir1 
15184778508Sblueswir1     /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
15284778508Sblueswir1        starts %edx contains a pointer to a function which might be
15384778508Sblueswir1        registered using `atexit'.  This provides a mean for the
15484778508Sblueswir1        dynamic linker to call DT_FINI functions for shared libraries
15584778508Sblueswir1        that have been loaded before the code runs.
15684778508Sblueswir1 
15784778508Sblueswir1        A value of 0 tells we have no such handler.  */
15884778508Sblueswir1     regs->edx = 0;
15984778508Sblueswir1 }
16084778508Sblueswir1 #endif
16184778508Sblueswir1 
16284778508Sblueswir1 #define USE_ELF_CORE_DUMP
16384778508Sblueswir1 #define ELF_EXEC_PAGESIZE       4096
16484778508Sblueswir1 
16584778508Sblueswir1 #endif
16684778508Sblueswir1 
16784778508Sblueswir1 #ifdef TARGET_ARM
16884778508Sblueswir1 
16984778508Sblueswir1 #define ELF_START_MMAP 0x80000000
17084778508Sblueswir1 
17184778508Sblueswir1 #define elf_check_arch(x) ( (x) == EM_ARM )
17284778508Sblueswir1 
17384778508Sblueswir1 #define ELF_CLASS       ELFCLASS32
17484778508Sblueswir1 #ifdef TARGET_WORDS_BIGENDIAN
17584778508Sblueswir1 #define ELF_DATA        ELFDATA2MSB
17684778508Sblueswir1 #else
17784778508Sblueswir1 #define ELF_DATA        ELFDATA2LSB
17884778508Sblueswir1 #endif
17984778508Sblueswir1 #define ELF_ARCH        EM_ARM
18084778508Sblueswir1 
18184778508Sblueswir1 static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
18284778508Sblueswir1 {
18384778508Sblueswir1     abi_long stack = infop->start_stack;
18484778508Sblueswir1     memset(regs, 0, sizeof(*regs));
18584778508Sblueswir1     regs->ARM_cpsr = 0x10;
18684778508Sblueswir1     if (infop->entry & 1)
18784778508Sblueswir1       regs->ARM_cpsr |= CPSR_T;
18884778508Sblueswir1     regs->ARM_pc = infop->entry & 0xfffffffe;
18984778508Sblueswir1     regs->ARM_sp = infop->start_stack;
19084778508Sblueswir1     /* FIXME - what to for failure of get_user()? */
19184778508Sblueswir1     get_user_ual(regs->ARM_r2, stack + 8); /* envp */
19284778508Sblueswir1     get_user_ual(regs->ARM_r1, stack + 4); /* envp */
19384778508Sblueswir1     /* XXX: it seems that r0 is zeroed after ! */
19484778508Sblueswir1     regs->ARM_r0 = 0;
19584778508Sblueswir1     /* For uClinux PIC binaries.  */
19684778508Sblueswir1     /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
19784778508Sblueswir1     regs->ARM_r10 = infop->start_data;
19884778508Sblueswir1 }
19984778508Sblueswir1 
20084778508Sblueswir1 #define USE_ELF_CORE_DUMP
20184778508Sblueswir1 #define ELF_EXEC_PAGESIZE       4096
20284778508Sblueswir1 
20384778508Sblueswir1 enum
20484778508Sblueswir1 {
20584778508Sblueswir1   ARM_HWCAP_ARM_SWP       = 1 << 0,
20684778508Sblueswir1   ARM_HWCAP_ARM_HALF      = 1 << 1,
20784778508Sblueswir1   ARM_HWCAP_ARM_THUMB     = 1 << 2,
20884778508Sblueswir1   ARM_HWCAP_ARM_26BIT     = 1 << 3,
20984778508Sblueswir1   ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
21084778508Sblueswir1   ARM_HWCAP_ARM_FPA       = 1 << 5,
21184778508Sblueswir1   ARM_HWCAP_ARM_VFP       = 1 << 6,
21284778508Sblueswir1   ARM_HWCAP_ARM_EDSP      = 1 << 7,
21384778508Sblueswir1 };
21484778508Sblueswir1 
21584778508Sblueswir1 #define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF              \
21684778508Sblueswir1                     | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT     \
21784778508Sblueswir1                     | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP)
21884778508Sblueswir1 
21984778508Sblueswir1 #endif
22084778508Sblueswir1 
22184778508Sblueswir1 #ifdef TARGET_SPARC
22284778508Sblueswir1 #ifdef TARGET_SPARC64
22384778508Sblueswir1 
22484778508Sblueswir1 #define ELF_START_MMAP 0x80000000
22584778508Sblueswir1 
22684778508Sblueswir1 #ifndef TARGET_ABI32
22784778508Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
22884778508Sblueswir1 #else
22984778508Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
23084778508Sblueswir1 #endif
23184778508Sblueswir1 
23284778508Sblueswir1 #define ELF_CLASS   ELFCLASS64
23384778508Sblueswir1 #define ELF_DATA    ELFDATA2MSB
23484778508Sblueswir1 #define ELF_ARCH    EM_SPARCV9
23584778508Sblueswir1 
23684778508Sblueswir1 #define STACK_BIAS              2047
23784778508Sblueswir1 
23884778508Sblueswir1 static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
23984778508Sblueswir1 {
24084778508Sblueswir1 #ifndef TARGET_ABI32
24184778508Sblueswir1     regs->tstate = 0;
24284778508Sblueswir1 #endif
24384778508Sblueswir1     regs->pc = infop->entry;
24484778508Sblueswir1     regs->npc = regs->pc + 4;
24584778508Sblueswir1     regs->y = 0;
24684778508Sblueswir1 #ifdef TARGET_ABI32
24784778508Sblueswir1     regs->u_regs[14] = infop->start_stack - 16 * 4;
24884778508Sblueswir1 #else
24984778508Sblueswir1     if (personality(infop->personality) == PER_LINUX32)
25084778508Sblueswir1         regs->u_regs[14] = infop->start_stack - 16 * 4;
25178cfb07fSJuergen Lock     else {
25284778508Sblueswir1         regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
25378cfb07fSJuergen Lock         if (bsd_type == target_freebsd) {
25478cfb07fSJuergen Lock             regs->u_regs[8] = infop->start_stack;
25578cfb07fSJuergen Lock             regs->u_regs[11] = infop->start_stack;
25678cfb07fSJuergen Lock         }
25778cfb07fSJuergen Lock     }
25884778508Sblueswir1 #endif
25984778508Sblueswir1 }
26084778508Sblueswir1 
26184778508Sblueswir1 #else
26284778508Sblueswir1 #define ELF_START_MMAP 0x80000000
26384778508Sblueswir1 
26484778508Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARC )
26584778508Sblueswir1 
26684778508Sblueswir1 #define ELF_CLASS   ELFCLASS32
26784778508Sblueswir1 #define ELF_DATA    ELFDATA2MSB
26884778508Sblueswir1 #define ELF_ARCH    EM_SPARC
26984778508Sblueswir1 
27084778508Sblueswir1 static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
27184778508Sblueswir1 {
27284778508Sblueswir1     regs->psr = 0;
27384778508Sblueswir1     regs->pc = infop->entry;
27484778508Sblueswir1     regs->npc = regs->pc + 4;
27584778508Sblueswir1     regs->y = 0;
27684778508Sblueswir1     regs->u_regs[14] = infop->start_stack - 16 * 4;
27784778508Sblueswir1 }
27884778508Sblueswir1 
27984778508Sblueswir1 #endif
28084778508Sblueswir1 #endif
28184778508Sblueswir1 
28284778508Sblueswir1 #ifdef TARGET_PPC
28384778508Sblueswir1 
28484778508Sblueswir1 #define ELF_START_MMAP 0x80000000
28584778508Sblueswir1 
28684778508Sblueswir1 #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
28784778508Sblueswir1 
28884778508Sblueswir1 #define elf_check_arch(x) ( (x) == EM_PPC64 )
28984778508Sblueswir1 
29084778508Sblueswir1 #define ELF_CLASS       ELFCLASS64
29184778508Sblueswir1 
29284778508Sblueswir1 #else
29384778508Sblueswir1 
29484778508Sblueswir1 #define elf_check_arch(x) ( (x) == EM_PPC )
29584778508Sblueswir1 
29684778508Sblueswir1 #define ELF_CLASS       ELFCLASS32
29784778508Sblueswir1 
29884778508Sblueswir1 #endif
29984778508Sblueswir1 
30084778508Sblueswir1 #ifdef TARGET_WORDS_BIGENDIAN
30184778508Sblueswir1 #define ELF_DATA        ELFDATA2MSB
30284778508Sblueswir1 #else
30384778508Sblueswir1 #define ELF_DATA        ELFDATA2LSB
30484778508Sblueswir1 #endif
30584778508Sblueswir1 #define ELF_ARCH        EM_PPC
30684778508Sblueswir1 
30784778508Sblueswir1 /*
30884778508Sblueswir1  * We need to put in some extra aux table entries to tell glibc what
30984778508Sblueswir1  * the cache block size is, so it can use the dcbz instruction safely.
31084778508Sblueswir1  */
31184778508Sblueswir1 #define AT_DCACHEBSIZE          19
31284778508Sblueswir1 #define AT_ICACHEBSIZE          20
31384778508Sblueswir1 #define AT_UCACHEBSIZE          21
31484778508Sblueswir1 /* A special ignored type value for PPC, for glibc compatibility.  */
31584778508Sblueswir1 #define AT_IGNOREPPC            22
31684778508Sblueswir1 /*
31784778508Sblueswir1  * The requirements here are:
31884778508Sblueswir1  * - keep the final alignment of sp (sp & 0xf)
31984778508Sblueswir1  * - make sure the 32-bit value at the first 16 byte aligned position of
32084778508Sblueswir1  *   AUXV is greater than 16 for glibc compatibility.
32184778508Sblueswir1  *   AT_IGNOREPPC is used for that.
32284778508Sblueswir1  * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
32384778508Sblueswir1  *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
32484778508Sblueswir1  */
32584778508Sblueswir1 #define DLINFO_ARCH_ITEMS       5
32684778508Sblueswir1 #define ARCH_DLINFO                                                     \
32784778508Sblueswir1 do {                                                                    \
32884778508Sblueswir1         NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20);                              \
32984778508Sblueswir1         NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20);                              \
33084778508Sblueswir1         NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                                 \
33184778508Sblueswir1         /*                                                              \
33284778508Sblueswir1          * Now handle glibc compatibility.                              \
33384778508Sblueswir1          */                                                             \
33484778508Sblueswir1         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);                        \
33584778508Sblueswir1         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);                        \
33684778508Sblueswir1  } while (0)
33784778508Sblueswir1 
33884778508Sblueswir1 static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
33984778508Sblueswir1 {
34084778508Sblueswir1     abi_ulong pos = infop->start_stack;
34184778508Sblueswir1     abi_ulong tmp;
34284778508Sblueswir1 #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
34384778508Sblueswir1     abi_ulong entry, toc;
34484778508Sblueswir1 #endif
34584778508Sblueswir1 
34684778508Sblueswir1     _regs->gpr[1] = infop->start_stack;
34784778508Sblueswir1 #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
348b8d6ac9fSPeter Maydell     get_user_u64(entry, infop->entry);
349b8d6ac9fSPeter Maydell     entry += infop->load_addr;
350b8d6ac9fSPeter Maydell     get_user_u64(toc, infop->entry + 8);
351b8d6ac9fSPeter Maydell     toc += infop->load_addr;
35284778508Sblueswir1     _regs->gpr[2] = toc;
35384778508Sblueswir1     infop->entry = entry;
35484778508Sblueswir1 #endif
35584778508Sblueswir1     _regs->nip = infop->entry;
35684778508Sblueswir1     /* Note that isn't exactly what regular kernel does
35784778508Sblueswir1      * but this is what the ABI wants and is needed to allow
35884778508Sblueswir1      * execution of PPC BSD programs.
35984778508Sblueswir1      */
36084778508Sblueswir1     /* FIXME - what to for failure of get_user()? */
36184778508Sblueswir1     get_user_ual(_regs->gpr[3], pos);
36284778508Sblueswir1     pos += sizeof(abi_ulong);
36384778508Sblueswir1     _regs->gpr[4] = pos;
364b8d6ac9fSPeter Maydell     for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong)) {
365b8d6ac9fSPeter Maydell         get_user_ual(tmp, pos);
366b8d6ac9fSPeter Maydell     }
36784778508Sblueswir1     _regs->gpr[5] = pos;
36884778508Sblueswir1 }
36984778508Sblueswir1 
37084778508Sblueswir1 #define USE_ELF_CORE_DUMP
37184778508Sblueswir1 #define ELF_EXEC_PAGESIZE       4096
37284778508Sblueswir1 
37384778508Sblueswir1 #endif
37484778508Sblueswir1 
37584778508Sblueswir1 #ifdef TARGET_MIPS
37684778508Sblueswir1 
37784778508Sblueswir1 #define ELF_START_MMAP 0x80000000
37884778508Sblueswir1 
37984778508Sblueswir1 #define elf_check_arch(x) ( (x) == EM_MIPS )
38084778508Sblueswir1 
38184778508Sblueswir1 #ifdef TARGET_MIPS64
38284778508Sblueswir1 #define ELF_CLASS   ELFCLASS64
38384778508Sblueswir1 #else
38484778508Sblueswir1 #define ELF_CLASS   ELFCLASS32
38584778508Sblueswir1 #endif
38684778508Sblueswir1 #ifdef TARGET_WORDS_BIGENDIAN
38784778508Sblueswir1 #define ELF_DATA        ELFDATA2MSB
38884778508Sblueswir1 #else
38984778508Sblueswir1 #define ELF_DATA        ELFDATA2LSB
39084778508Sblueswir1 #endif
39184778508Sblueswir1 #define ELF_ARCH    EM_MIPS
39284778508Sblueswir1 
39384778508Sblueswir1 static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
39484778508Sblueswir1 {
39584778508Sblueswir1     regs->cp0_status = 2 << CP0St_KSU;
39684778508Sblueswir1     regs->cp0_epc = infop->entry;
39784778508Sblueswir1     regs->regs[29] = infop->start_stack;
39884778508Sblueswir1 }
39984778508Sblueswir1 
40084778508Sblueswir1 #define USE_ELF_CORE_DUMP
40184778508Sblueswir1 #define ELF_EXEC_PAGESIZE        4096
40284778508Sblueswir1 
40384778508Sblueswir1 #endif /* TARGET_MIPS */
40484778508Sblueswir1 
40584778508Sblueswir1 #ifdef TARGET_SH4
40684778508Sblueswir1 
40784778508Sblueswir1 #define ELF_START_MMAP 0x80000000
40884778508Sblueswir1 
40984778508Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SH )
41084778508Sblueswir1 
41184778508Sblueswir1 #define ELF_CLASS ELFCLASS32
41284778508Sblueswir1 #define ELF_DATA  ELFDATA2LSB
41384778508Sblueswir1 #define ELF_ARCH  EM_SH
41484778508Sblueswir1 
41584778508Sblueswir1 static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
41684778508Sblueswir1 {
41784778508Sblueswir1   /* Check other registers XXXXX */
41884778508Sblueswir1   regs->pc = infop->entry;
41984778508Sblueswir1   regs->regs[15] = infop->start_stack;
42084778508Sblueswir1 }
42184778508Sblueswir1 
42284778508Sblueswir1 #define USE_ELF_CORE_DUMP
42384778508Sblueswir1 #define ELF_EXEC_PAGESIZE        4096
42484778508Sblueswir1 
42584778508Sblueswir1 #endif
42684778508Sblueswir1 
42784778508Sblueswir1 #ifdef TARGET_CRIS
42884778508Sblueswir1 
42984778508Sblueswir1 #define ELF_START_MMAP 0x80000000
43084778508Sblueswir1 
43184778508Sblueswir1 #define elf_check_arch(x) ( (x) == EM_CRIS )
43284778508Sblueswir1 
43384778508Sblueswir1 #define ELF_CLASS ELFCLASS32
43484778508Sblueswir1 #define ELF_DATA  ELFDATA2LSB
43584778508Sblueswir1 #define ELF_ARCH  EM_CRIS
43684778508Sblueswir1 
43784778508Sblueswir1 static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
43884778508Sblueswir1 {
43984778508Sblueswir1   regs->erp = infop->entry;
44084778508Sblueswir1 }
44184778508Sblueswir1 
44284778508Sblueswir1 #define USE_ELF_CORE_DUMP
44384778508Sblueswir1 #define ELF_EXEC_PAGESIZE        8192
44484778508Sblueswir1 
44584778508Sblueswir1 #endif
44684778508Sblueswir1 
44784778508Sblueswir1 #ifdef TARGET_M68K
44884778508Sblueswir1 
44984778508Sblueswir1 #define ELF_START_MMAP 0x80000000
45084778508Sblueswir1 
45184778508Sblueswir1 #define elf_check_arch(x) ( (x) == EM_68K )
45284778508Sblueswir1 
45384778508Sblueswir1 #define ELF_CLASS       ELFCLASS32
45484778508Sblueswir1 #define ELF_DATA        ELFDATA2MSB
45584778508Sblueswir1 #define ELF_ARCH        EM_68K
45684778508Sblueswir1 
45784778508Sblueswir1 /* ??? Does this need to do anything?
45884778508Sblueswir1 #define ELF_PLAT_INIT(_r) */
45984778508Sblueswir1 
46084778508Sblueswir1 static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
46184778508Sblueswir1 {
46284778508Sblueswir1     regs->usp = infop->start_stack;
46384778508Sblueswir1     regs->sr = 0;
46484778508Sblueswir1     regs->pc = infop->entry;
46584778508Sblueswir1 }
46684778508Sblueswir1 
46784778508Sblueswir1 #define USE_ELF_CORE_DUMP
46884778508Sblueswir1 #define ELF_EXEC_PAGESIZE       8192
46984778508Sblueswir1 
47084778508Sblueswir1 #endif
47184778508Sblueswir1 
47284778508Sblueswir1 #ifdef TARGET_ALPHA
47384778508Sblueswir1 
47484778508Sblueswir1 #define ELF_START_MMAP (0x30000000000ULL)
47584778508Sblueswir1 
47684778508Sblueswir1 #define elf_check_arch(x) ( (x) == ELF_ARCH )
47784778508Sblueswir1 
47884778508Sblueswir1 #define ELF_CLASS      ELFCLASS64
47984778508Sblueswir1 #define ELF_DATA       ELFDATA2MSB
48084778508Sblueswir1 #define ELF_ARCH       EM_ALPHA
48184778508Sblueswir1 
48284778508Sblueswir1 static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
48384778508Sblueswir1 {
48484778508Sblueswir1     regs->pc = infop->entry;
48584778508Sblueswir1     regs->ps = 8;
48684778508Sblueswir1     regs->usp = infop->start_stack;
48784778508Sblueswir1     regs->unique = infop->start_data; /* ? */
48884778508Sblueswir1     printf("Set unique value to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n",
48984778508Sblueswir1            regs->unique, infop->start_data);
49084778508Sblueswir1 }
49184778508Sblueswir1 
49284778508Sblueswir1 #define USE_ELF_CORE_DUMP
49384778508Sblueswir1 #define ELF_EXEC_PAGESIZE        8192
49484778508Sblueswir1 
49584778508Sblueswir1 #endif /* TARGET_ALPHA */
49684778508Sblueswir1 
49784778508Sblueswir1 #ifndef ELF_PLATFORM
49884778508Sblueswir1 #define ELF_PLATFORM (NULL)
49984778508Sblueswir1 #endif
50084778508Sblueswir1 
50184778508Sblueswir1 #ifndef ELF_HWCAP
50284778508Sblueswir1 #define ELF_HWCAP 0
50384778508Sblueswir1 #endif
50484778508Sblueswir1 
50584778508Sblueswir1 #ifdef TARGET_ABI32
50684778508Sblueswir1 #undef ELF_CLASS
50784778508Sblueswir1 #define ELF_CLASS ELFCLASS32
50884778508Sblueswir1 #undef bswaptls
50984778508Sblueswir1 #define bswaptls(ptr) bswap32s(ptr)
51084778508Sblueswir1 #endif
51184778508Sblueswir1 
51284778508Sblueswir1 #include "elf.h"
51384778508Sblueswir1 
51484778508Sblueswir1 struct exec
51584778508Sblueswir1 {
51684778508Sblueswir1   unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
51784778508Sblueswir1   unsigned int a_text;   /* length of text, in bytes */
51884778508Sblueswir1   unsigned int a_data;   /* length of data, in bytes */
51984778508Sblueswir1   unsigned int a_bss;    /* length of uninitialized data area, in bytes */
52084778508Sblueswir1   unsigned int a_syms;   /* length of symbol table data in file, in bytes */
52184778508Sblueswir1   unsigned int a_entry;  /* start address */
52284778508Sblueswir1   unsigned int a_trsize; /* length of relocation info for text, in bytes */
52384778508Sblueswir1   unsigned int a_drsize; /* length of relocation info for data, in bytes */
52484778508Sblueswir1 };
52584778508Sblueswir1 
52684778508Sblueswir1 
52784778508Sblueswir1 #define N_MAGIC(exec) ((exec).a_info & 0xffff)
52884778508Sblueswir1 #define OMAGIC 0407
52984778508Sblueswir1 #define NMAGIC 0410
53084778508Sblueswir1 #define ZMAGIC 0413
53184778508Sblueswir1 #define QMAGIC 0314
53284778508Sblueswir1 
53384778508Sblueswir1 /* max code+data+bss space allocated to elf interpreter */
53484778508Sblueswir1 #define INTERP_MAP_SIZE (32 * 1024 * 1024)
53584778508Sblueswir1 
53684778508Sblueswir1 /* max code+data+bss+brk space allocated to ET_DYN executables */
53784778508Sblueswir1 #define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
53884778508Sblueswir1 
53984778508Sblueswir1 /* Necessary parameters */
54084778508Sblueswir1 #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
54184778508Sblueswir1 #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
54284778508Sblueswir1 #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
54384778508Sblueswir1 
54484778508Sblueswir1 #define INTERPRETER_NONE 0
54584778508Sblueswir1 #define INTERPRETER_AOUT 1
54684778508Sblueswir1 #define INTERPRETER_ELF 2
54784778508Sblueswir1 
54884778508Sblueswir1 #define DLINFO_ITEMS 12
54984778508Sblueswir1 
55084778508Sblueswir1 static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
55184778508Sblueswir1 {
55284778508Sblueswir1         memcpy(to, from, n);
55384778508Sblueswir1 }
55484778508Sblueswir1 
55584778508Sblueswir1 static int load_aout_interp(void * exptr, int interp_fd);
55684778508Sblueswir1 
55784778508Sblueswir1 #ifdef BSWAP_NEEDED
55884778508Sblueswir1 static void bswap_ehdr(struct elfhdr *ehdr)
55984778508Sblueswir1 {
56084778508Sblueswir1     bswap16s(&ehdr->e_type);                    /* Object file type */
56184778508Sblueswir1     bswap16s(&ehdr->e_machine);         /* Architecture */
56284778508Sblueswir1     bswap32s(&ehdr->e_version);         /* Object file version */
56384778508Sblueswir1     bswaptls(&ehdr->e_entry);           /* Entry point virtual address */
56484778508Sblueswir1     bswaptls(&ehdr->e_phoff);           /* Program header table file offset */
56584778508Sblueswir1     bswaptls(&ehdr->e_shoff);           /* Section header table file offset */
56684778508Sblueswir1     bswap32s(&ehdr->e_flags);           /* Processor-specific flags */
56784778508Sblueswir1     bswap16s(&ehdr->e_ehsize);          /* ELF header size in bytes */
56884778508Sblueswir1     bswap16s(&ehdr->e_phentsize);               /* Program header table entry size */
56984778508Sblueswir1     bswap16s(&ehdr->e_phnum);           /* Program header table entry count */
57084778508Sblueswir1     bswap16s(&ehdr->e_shentsize);               /* Section header table entry size */
57184778508Sblueswir1     bswap16s(&ehdr->e_shnum);           /* Section header table entry count */
57284778508Sblueswir1     bswap16s(&ehdr->e_shstrndx);                /* Section header string table index */
57384778508Sblueswir1 }
57484778508Sblueswir1 
57584778508Sblueswir1 static void bswap_phdr(struct elf_phdr *phdr)
57684778508Sblueswir1 {
57784778508Sblueswir1     bswap32s(&phdr->p_type);                    /* Segment type */
57884778508Sblueswir1     bswaptls(&phdr->p_offset);          /* Segment file offset */
57984778508Sblueswir1     bswaptls(&phdr->p_vaddr);           /* Segment virtual address */
58084778508Sblueswir1     bswaptls(&phdr->p_paddr);           /* Segment physical address */
58184778508Sblueswir1     bswaptls(&phdr->p_filesz);          /* Segment size in file */
58284778508Sblueswir1     bswaptls(&phdr->p_memsz);           /* Segment size in memory */
58384778508Sblueswir1     bswap32s(&phdr->p_flags);           /* Segment flags */
58484778508Sblueswir1     bswaptls(&phdr->p_align);           /* Segment alignment */
58584778508Sblueswir1 }
58684778508Sblueswir1 
58784778508Sblueswir1 static void bswap_shdr(struct elf_shdr *shdr)
58884778508Sblueswir1 {
58984778508Sblueswir1     bswap32s(&shdr->sh_name);
59084778508Sblueswir1     bswap32s(&shdr->sh_type);
59184778508Sblueswir1     bswaptls(&shdr->sh_flags);
59284778508Sblueswir1     bswaptls(&shdr->sh_addr);
59384778508Sblueswir1     bswaptls(&shdr->sh_offset);
59484778508Sblueswir1     bswaptls(&shdr->sh_size);
59584778508Sblueswir1     bswap32s(&shdr->sh_link);
59684778508Sblueswir1     bswap32s(&shdr->sh_info);
59784778508Sblueswir1     bswaptls(&shdr->sh_addralign);
59884778508Sblueswir1     bswaptls(&shdr->sh_entsize);
59984778508Sblueswir1 }
60084778508Sblueswir1 
60184778508Sblueswir1 static void bswap_sym(struct elf_sym *sym)
60284778508Sblueswir1 {
60384778508Sblueswir1     bswap32s(&sym->st_name);
60484778508Sblueswir1     bswaptls(&sym->st_value);
60584778508Sblueswir1     bswaptls(&sym->st_size);
60684778508Sblueswir1     bswap16s(&sym->st_shndx);
60784778508Sblueswir1 }
60884778508Sblueswir1 #endif
60984778508Sblueswir1 
61084778508Sblueswir1 /*
61184778508Sblueswir1  * 'copy_elf_strings()' copies argument/envelope strings from user
61284778508Sblueswir1  * memory to free pages in kernel mem. These are in a format ready
61384778508Sblueswir1  * to be put directly into the top of new user memory.
61484778508Sblueswir1  *
61584778508Sblueswir1  */
61684778508Sblueswir1 static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
61784778508Sblueswir1                                   abi_ulong p)
61884778508Sblueswir1 {
61984778508Sblueswir1     char *tmp, *tmp1, *pag = NULL;
62084778508Sblueswir1     int len, offset = 0;
62184778508Sblueswir1 
62284778508Sblueswir1     if (!p) {
62384778508Sblueswir1         return 0;       /* bullet-proofing */
62484778508Sblueswir1     }
62584778508Sblueswir1     while (argc-- > 0) {
62684778508Sblueswir1         tmp = argv[argc];
62784778508Sblueswir1         if (!tmp) {
6289bb93180SPeter Maydell             fprintf(stderr, "VFS: argc is wrong");
62984778508Sblueswir1             exit(-1);
63084778508Sblueswir1         }
63184778508Sblueswir1         tmp1 = tmp;
63284778508Sblueswir1         while (*tmp++);
63384778508Sblueswir1         len = tmp - tmp1;
63484778508Sblueswir1         if (p < len) {  /* this shouldn't happen - 128kB */
63584778508Sblueswir1                 return 0;
63684778508Sblueswir1         }
63784778508Sblueswir1         while (len) {
63884778508Sblueswir1             --p; --tmp; --len;
63984778508Sblueswir1             if (--offset < 0) {
64084778508Sblueswir1                 offset = p % TARGET_PAGE_SIZE;
64184778508Sblueswir1                 pag = (char *)page[p/TARGET_PAGE_SIZE];
64284778508Sblueswir1                 if (!pag) {
643c580dee4SStefan Weil                     pag = g_try_malloc0(TARGET_PAGE_SIZE);
64484778508Sblueswir1                     page[p/TARGET_PAGE_SIZE] = pag;
64584778508Sblueswir1                     if (!pag)
64684778508Sblueswir1                         return 0;
64784778508Sblueswir1                 }
64884778508Sblueswir1             }
64984778508Sblueswir1             if (len == 0 || offset == 0) {
65084778508Sblueswir1                 *(pag + offset) = *tmp;
65184778508Sblueswir1             }
65284778508Sblueswir1             else {
65384778508Sblueswir1               int bytes_to_copy = (len > offset) ? offset : len;
65484778508Sblueswir1               tmp -= bytes_to_copy;
65584778508Sblueswir1               p -= bytes_to_copy;
65684778508Sblueswir1               offset -= bytes_to_copy;
65784778508Sblueswir1               len -= bytes_to_copy;
65884778508Sblueswir1               memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
65984778508Sblueswir1             }
66084778508Sblueswir1         }
66184778508Sblueswir1     }
66284778508Sblueswir1     return p;
66384778508Sblueswir1 }
66484778508Sblueswir1 
66584778508Sblueswir1 static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
66684778508Sblueswir1                                  struct image_info *info)
66784778508Sblueswir1 {
66884778508Sblueswir1     abi_ulong stack_base, size, error;
66984778508Sblueswir1     int i;
67084778508Sblueswir1 
67184778508Sblueswir1     /* Create enough stack to hold everything.  If we don't use
67284778508Sblueswir1      * it for args, we'll use it for something else...
67384778508Sblueswir1      */
67484778508Sblueswir1     size = x86_stack_size;
67584778508Sblueswir1     if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
67684778508Sblueswir1         size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
67784778508Sblueswir1     error = target_mmap(0,
67884778508Sblueswir1                         size + qemu_host_page_size,
67984778508Sblueswir1                         PROT_READ | PROT_WRITE,
68084778508Sblueswir1                         MAP_PRIVATE | MAP_ANON,
68184778508Sblueswir1                         -1, 0);
68284778508Sblueswir1     if (error == -1) {
68384778508Sblueswir1         perror("stk mmap");
68484778508Sblueswir1         exit(-1);
68584778508Sblueswir1     }
68684778508Sblueswir1     /* we reserve one extra page at the top of the stack as guard */
68784778508Sblueswir1     target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
68884778508Sblueswir1 
68984778508Sblueswir1     stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
69084778508Sblueswir1     p += stack_base;
69184778508Sblueswir1 
69284778508Sblueswir1     for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
69384778508Sblueswir1         if (bprm->page[i]) {
69484778508Sblueswir1             info->rss++;
69584778508Sblueswir1             /* FIXME - check return value of memcpy_to_target() for failure */
69684778508Sblueswir1             memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
697c580dee4SStefan Weil             g_free(bprm->page[i]);
69884778508Sblueswir1         }
69984778508Sblueswir1         stack_base += TARGET_PAGE_SIZE;
70084778508Sblueswir1     }
70184778508Sblueswir1     return p;
70284778508Sblueswir1 }
70384778508Sblueswir1 
70484778508Sblueswir1 static void set_brk(abi_ulong start, abi_ulong end)
70584778508Sblueswir1 {
70684778508Sblueswir1         /* page-align the start and end addresses... */
70784778508Sblueswir1         start = HOST_PAGE_ALIGN(start);
70884778508Sblueswir1         end = HOST_PAGE_ALIGN(end);
70984778508Sblueswir1         if (end <= start)
71084778508Sblueswir1                 return;
71184778508Sblueswir1         if(target_mmap(start, end - start,
71284778508Sblueswir1                        PROT_READ | PROT_WRITE | PROT_EXEC,
71384778508Sblueswir1                        MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0) == -1) {
71484778508Sblueswir1             perror("cannot mmap brk");
71584778508Sblueswir1             exit(-1);
71684778508Sblueswir1         }
71784778508Sblueswir1 }
71884778508Sblueswir1 
71984778508Sblueswir1 
72084778508Sblueswir1 /* We need to explicitly zero any fractional pages after the data
72184778508Sblueswir1    section (i.e. bss).  This would contain the junk from the file that
72284778508Sblueswir1    should not be in memory. */
72384778508Sblueswir1 static void padzero(abi_ulong elf_bss, abi_ulong last_bss)
72484778508Sblueswir1 {
72584778508Sblueswir1         abi_ulong nbyte;
72684778508Sblueswir1 
72784778508Sblueswir1         if (elf_bss >= last_bss)
72884778508Sblueswir1                 return;
72984778508Sblueswir1 
73084778508Sblueswir1         /* XXX: this is really a hack : if the real host page size is
73184778508Sblueswir1            smaller than the target page size, some pages after the end
73284778508Sblueswir1            of the file may not be mapped. A better fix would be to
73384778508Sblueswir1            patch target_mmap(), but it is more complicated as the file
73484778508Sblueswir1            size must be known */
73584778508Sblueswir1         if (qemu_real_host_page_size < qemu_host_page_size) {
73684778508Sblueswir1             abi_ulong end_addr, end_addr1;
7370c2d70c4SPaolo Bonzini             end_addr1 = REAL_HOST_PAGE_ALIGN(elf_bss);
73884778508Sblueswir1             end_addr = HOST_PAGE_ALIGN(elf_bss);
73984778508Sblueswir1             if (end_addr1 < end_addr) {
740*3e8f1628SRichard Henderson                 mmap((void *)g2h_untagged(end_addr1), end_addr - end_addr1,
74184778508Sblueswir1                      PROT_READ|PROT_WRITE|PROT_EXEC,
74284778508Sblueswir1                      MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0);
74384778508Sblueswir1             }
74484778508Sblueswir1         }
74584778508Sblueswir1 
74684778508Sblueswir1         nbyte = elf_bss & (qemu_host_page_size-1);
74784778508Sblueswir1         if (nbyte) {
74884778508Sblueswir1             nbyte = qemu_host_page_size - nbyte;
74984778508Sblueswir1             do {
75084778508Sblueswir1                 /* FIXME - what to do if put_user() fails? */
75184778508Sblueswir1                 put_user_u8(0, elf_bss);
75284778508Sblueswir1                 elf_bss++;
75384778508Sblueswir1             } while (--nbyte);
75484778508Sblueswir1         }
75584778508Sblueswir1 }
75684778508Sblueswir1 
75784778508Sblueswir1 
75884778508Sblueswir1 static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
75984778508Sblueswir1                                    struct elfhdr * exec,
76084778508Sblueswir1                                    abi_ulong load_addr,
76184778508Sblueswir1                                    abi_ulong load_bias,
76284778508Sblueswir1                                    abi_ulong interp_load_addr, int ibcs,
76384778508Sblueswir1                                    struct image_info *info)
76484778508Sblueswir1 {
76584778508Sblueswir1         abi_ulong sp;
76684778508Sblueswir1         int size;
76784778508Sblueswir1         abi_ulong u_platform;
76884778508Sblueswir1         const char *k_platform;
76984778508Sblueswir1         const int n = sizeof(elf_addr_t);
77084778508Sblueswir1 
77184778508Sblueswir1         sp = p;
77284778508Sblueswir1         u_platform = 0;
77384778508Sblueswir1         k_platform = ELF_PLATFORM;
77484778508Sblueswir1         if (k_platform) {
77584778508Sblueswir1             size_t len = strlen(k_platform) + 1;
77684778508Sblueswir1             sp -= (len + n - 1) & ~(n - 1);
77784778508Sblueswir1             u_platform = sp;
77884778508Sblueswir1             /* FIXME - check return value of memcpy_to_target() for failure */
77984778508Sblueswir1             memcpy_to_target(sp, k_platform, len);
78084778508Sblueswir1         }
78184778508Sblueswir1         /*
78284778508Sblueswir1          * Force 16 byte _final_ alignment here for generality.
78384778508Sblueswir1          */
78484778508Sblueswir1         sp = sp &~ (abi_ulong)15;
78584778508Sblueswir1         size = (DLINFO_ITEMS + 1) * 2;
78684778508Sblueswir1         if (k_platform)
78784778508Sblueswir1           size += 2;
78884778508Sblueswir1 #ifdef DLINFO_ARCH_ITEMS
78984778508Sblueswir1         size += DLINFO_ARCH_ITEMS * 2;
79084778508Sblueswir1 #endif
79184778508Sblueswir1         size += envc + argc + 2;
79284778508Sblueswir1         size += (!ibcs ? 3 : 1);        /* argc itself */
79384778508Sblueswir1         size *= n;
79484778508Sblueswir1         if (size & 15)
79584778508Sblueswir1             sp -= 16 - (size & 15);
79684778508Sblueswir1 
79784778508Sblueswir1         /* This is correct because Linux defines
79884778508Sblueswir1          * elf_addr_t as Elf32_Off / Elf64_Off
79984778508Sblueswir1          */
80084778508Sblueswir1 #define NEW_AUX_ENT(id, val) do {               \
80184778508Sblueswir1             sp -= n; put_user_ual(val, sp);     \
80284778508Sblueswir1             sp -= n; put_user_ual(id, sp);      \
80384778508Sblueswir1           } while(0)
80484778508Sblueswir1 
80584778508Sblueswir1         NEW_AUX_ENT (AT_NULL, 0);
80684778508Sblueswir1 
80784778508Sblueswir1         /* There must be exactly DLINFO_ITEMS entries here.  */
80884778508Sblueswir1         NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
80984778508Sblueswir1         NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
81084778508Sblueswir1         NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
81184778508Sblueswir1         NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
81284778508Sblueswir1         NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
81384778508Sblueswir1         NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
81484778508Sblueswir1         NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
81584778508Sblueswir1         NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
81684778508Sblueswir1         NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
81784778508Sblueswir1         NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
81884778508Sblueswir1         NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
81984778508Sblueswir1         NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
82084778508Sblueswir1         NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
82184778508Sblueswir1         if (k_platform)
82284778508Sblueswir1             NEW_AUX_ENT(AT_PLATFORM, u_platform);
82384778508Sblueswir1 #ifdef ARCH_DLINFO
82484778508Sblueswir1         /*
82584778508Sblueswir1          * ARCH_DLINFO must come last so platform specific code can enforce
82684778508Sblueswir1          * special alignment requirements on the AUXV if necessary (eg. PPC).
82784778508Sblueswir1          */
82884778508Sblueswir1         ARCH_DLINFO;
82984778508Sblueswir1 #endif
83084778508Sblueswir1 #undef NEW_AUX_ENT
83184778508Sblueswir1 
83284778508Sblueswir1         sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
83384778508Sblueswir1         return sp;
83484778508Sblueswir1 }
83584778508Sblueswir1 
83684778508Sblueswir1 
83784778508Sblueswir1 static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
83884778508Sblueswir1                                  int interpreter_fd,
83984778508Sblueswir1                                  abi_ulong *interp_load_addr)
84084778508Sblueswir1 {
84184778508Sblueswir1         struct elf_phdr *elf_phdata  =  NULL;
84284778508Sblueswir1         struct elf_phdr *eppnt;
84384778508Sblueswir1         abi_ulong load_addr = 0;
84484778508Sblueswir1         int load_addr_set = 0;
84584778508Sblueswir1         int retval;
84684778508Sblueswir1         abi_ulong last_bss, elf_bss;
84784778508Sblueswir1         abi_ulong error;
84884778508Sblueswir1         int i;
84984778508Sblueswir1 
85084778508Sblueswir1         elf_bss = 0;
85184778508Sblueswir1         last_bss = 0;
85284778508Sblueswir1         error = 0;
85384778508Sblueswir1 
85484778508Sblueswir1 #ifdef BSWAP_NEEDED
85584778508Sblueswir1         bswap_ehdr(interp_elf_ex);
85684778508Sblueswir1 #endif
85784778508Sblueswir1         /* First of all, some simple consistency checks */
85884778508Sblueswir1         if ((interp_elf_ex->e_type != ET_EXEC &&
85984778508Sblueswir1              interp_elf_ex->e_type != ET_DYN) ||
86084778508Sblueswir1            !elf_check_arch(interp_elf_ex->e_machine)) {
86184778508Sblueswir1                 return ~((abi_ulong)0UL);
86284778508Sblueswir1         }
86384778508Sblueswir1 
86484778508Sblueswir1 
86584778508Sblueswir1         /* Now read in all of the header information */
86684778508Sblueswir1 
86784778508Sblueswir1         if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
86884778508Sblueswir1             return ~(abi_ulong)0UL;
86984778508Sblueswir1 
87084778508Sblueswir1         elf_phdata =  (struct elf_phdr *)
87184778508Sblueswir1                 malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
87284778508Sblueswir1 
87384778508Sblueswir1         if (!elf_phdata)
87484778508Sblueswir1           return ~((abi_ulong)0UL);
87584778508Sblueswir1 
87684778508Sblueswir1         /*
87784778508Sblueswir1          * If the size of this structure has changed, then punt, since
87884778508Sblueswir1          * we will be doing the wrong thing.
87984778508Sblueswir1          */
88084778508Sblueswir1         if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
88184778508Sblueswir1             free(elf_phdata);
88284778508Sblueswir1             return ~((abi_ulong)0UL);
88384778508Sblueswir1         }
88484778508Sblueswir1 
88584778508Sblueswir1         retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
88684778508Sblueswir1         if(retval >= 0) {
88784778508Sblueswir1             retval = read(interpreter_fd,
88884778508Sblueswir1                            (char *) elf_phdata,
88984778508Sblueswir1                            sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
89084778508Sblueswir1         }
89184778508Sblueswir1         if (retval < 0) {
89284778508Sblueswir1                 perror("load_elf_interp");
89384778508Sblueswir1                 exit(-1);
89484778508Sblueswir1                 free (elf_phdata);
89584778508Sblueswir1                 return retval;
89684778508Sblueswir1         }
89784778508Sblueswir1 #ifdef BSWAP_NEEDED
89884778508Sblueswir1         eppnt = elf_phdata;
89984778508Sblueswir1         for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
90084778508Sblueswir1             bswap_phdr(eppnt);
90184778508Sblueswir1         }
90284778508Sblueswir1 #endif
90384778508Sblueswir1 
90484778508Sblueswir1         if (interp_elf_ex->e_type == ET_DYN) {
90584778508Sblueswir1             /* in order to avoid hardcoding the interpreter load
90684778508Sblueswir1                address in qemu, we allocate a big enough memory zone */
90784778508Sblueswir1             error = target_mmap(0, INTERP_MAP_SIZE,
90884778508Sblueswir1                                 PROT_NONE, MAP_PRIVATE | MAP_ANON,
90984778508Sblueswir1                                 -1, 0);
91084778508Sblueswir1             if (error == -1) {
91184778508Sblueswir1                 perror("mmap");
91284778508Sblueswir1                 exit(-1);
91384778508Sblueswir1             }
91484778508Sblueswir1             load_addr = error;
91584778508Sblueswir1             load_addr_set = 1;
91684778508Sblueswir1         }
91784778508Sblueswir1 
91884778508Sblueswir1         eppnt = elf_phdata;
91984778508Sblueswir1         for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
92084778508Sblueswir1           if (eppnt->p_type == PT_LOAD) {
92184778508Sblueswir1             int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
92284778508Sblueswir1             int elf_prot = 0;
92384778508Sblueswir1             abi_ulong vaddr = 0;
92484778508Sblueswir1             abi_ulong k;
92584778508Sblueswir1 
92684778508Sblueswir1             if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
92784778508Sblueswir1             if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
92884778508Sblueswir1             if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
92984778508Sblueswir1             if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
93084778508Sblueswir1                 elf_type |= MAP_FIXED;
93184778508Sblueswir1                 vaddr = eppnt->p_vaddr;
93284778508Sblueswir1             }
93384778508Sblueswir1             error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
93484778508Sblueswir1                  eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
93584778508Sblueswir1                  elf_prot,
93684778508Sblueswir1                  elf_type,
93784778508Sblueswir1                  interpreter_fd,
93884778508Sblueswir1                  eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
93984778508Sblueswir1 
94084778508Sblueswir1             if (error == -1) {
94184778508Sblueswir1               /* Real error */
94284778508Sblueswir1               close(interpreter_fd);
94384778508Sblueswir1               free(elf_phdata);
94484778508Sblueswir1               return ~((abi_ulong)0UL);
94584778508Sblueswir1             }
94684778508Sblueswir1 
94784778508Sblueswir1             if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
94884778508Sblueswir1               load_addr = error;
94984778508Sblueswir1               load_addr_set = 1;
95084778508Sblueswir1             }
95184778508Sblueswir1 
95284778508Sblueswir1             /*
95384778508Sblueswir1              * Find the end of the file  mapping for this phdr, and keep
95484778508Sblueswir1              * track of the largest address we see for this.
95584778508Sblueswir1              */
95684778508Sblueswir1             k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
95784778508Sblueswir1             if (k > elf_bss) elf_bss = k;
95884778508Sblueswir1 
95984778508Sblueswir1             /*
96084778508Sblueswir1              * Do the same thing for the memory mapping - between
96184778508Sblueswir1              * elf_bss and last_bss is the bss section.
96284778508Sblueswir1              */
96384778508Sblueswir1             k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
96484778508Sblueswir1             if (k > last_bss) last_bss = k;
96584778508Sblueswir1           }
96684778508Sblueswir1 
96784778508Sblueswir1         /* Now use mmap to map the library into memory. */
96884778508Sblueswir1 
96984778508Sblueswir1         close(interpreter_fd);
97084778508Sblueswir1 
97184778508Sblueswir1         /*
97284778508Sblueswir1          * Now fill out the bss section.  First pad the last page up
97384778508Sblueswir1          * to the page boundary, and then perform a mmap to make sure
97484778508Sblueswir1          * that there are zeromapped pages up to and including the last
97584778508Sblueswir1          * bss page.
97684778508Sblueswir1          */
97784778508Sblueswir1         padzero(elf_bss, last_bss);
97884778508Sblueswir1         elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */
97984778508Sblueswir1 
98084778508Sblueswir1         /* Map the last of the bss segment */
98184778508Sblueswir1         if (last_bss > elf_bss) {
98284778508Sblueswir1             target_mmap(elf_bss, last_bss-elf_bss,
98384778508Sblueswir1                         PROT_READ|PROT_WRITE|PROT_EXEC,
98484778508Sblueswir1                         MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0);
98584778508Sblueswir1         }
98684778508Sblueswir1         free(elf_phdata);
98784778508Sblueswir1 
98884778508Sblueswir1         *interp_load_addr = load_addr;
98984778508Sblueswir1         return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
99084778508Sblueswir1 }
99184778508Sblueswir1 
99284778508Sblueswir1 static int symfind(const void *s0, const void *s1)
99384778508Sblueswir1 {
994c7c530cdSStefan Weil     target_ulong addr = *(target_ulong *)s0;
99584778508Sblueswir1     struct elf_sym *sym = (struct elf_sym *)s1;
99684778508Sblueswir1     int result = 0;
997c7c530cdSStefan Weil     if (addr < sym->st_value) {
99884778508Sblueswir1         result = -1;
999c7c530cdSStefan Weil     } else if (addr >= sym->st_value + sym->st_size) {
100084778508Sblueswir1         result = 1;
100184778508Sblueswir1     }
100284778508Sblueswir1     return result;
100384778508Sblueswir1 }
100484778508Sblueswir1 
100584778508Sblueswir1 static const char *lookup_symbolxx(struct syminfo *s, target_ulong orig_addr)
100684778508Sblueswir1 {
100784778508Sblueswir1 #if ELF_CLASS == ELFCLASS32
100884778508Sblueswir1     struct elf_sym *syms = s->disas_symtab.elf32;
100984778508Sblueswir1 #else
101084778508Sblueswir1     struct elf_sym *syms = s->disas_symtab.elf64;
101184778508Sblueswir1 #endif
101284778508Sblueswir1 
101384778508Sblueswir1     // binary search
101484778508Sblueswir1     struct elf_sym *sym;
101584778508Sblueswir1 
1016c7c530cdSStefan Weil     sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms), symfind);
10177cba04f6SBlue Swirl     if (sym != NULL) {
101884778508Sblueswir1         return s->disas_strtab + sym->st_name;
101984778508Sblueswir1     }
102084778508Sblueswir1 
102184778508Sblueswir1     return "";
102284778508Sblueswir1 }
102384778508Sblueswir1 
102484778508Sblueswir1 /* FIXME: This should use elf_ops.h  */
102584778508Sblueswir1 static int symcmp(const void *s0, const void *s1)
102684778508Sblueswir1 {
102784778508Sblueswir1     struct elf_sym *sym0 = (struct elf_sym *)s0;
102884778508Sblueswir1     struct elf_sym *sym1 = (struct elf_sym *)s1;
102984778508Sblueswir1     return (sym0->st_value < sym1->st_value)
103084778508Sblueswir1         ? -1
103184778508Sblueswir1         : ((sym0->st_value > sym1->st_value) ? 1 : 0);
103284778508Sblueswir1 }
103384778508Sblueswir1 
103484778508Sblueswir1 /* Best attempt to load symbols from this ELF object. */
103584778508Sblueswir1 static void load_symbols(struct elfhdr *hdr, int fd)
103684778508Sblueswir1 {
103784778508Sblueswir1     unsigned int i, nsyms;
103884778508Sblueswir1     struct elf_shdr sechdr, symtab, strtab;
103984778508Sblueswir1     char *strings;
104084778508Sblueswir1     struct syminfo *s;
104129718712SStefan Weil     struct elf_sym *syms, *new_syms;
104284778508Sblueswir1 
104384778508Sblueswir1     lseek(fd, hdr->e_shoff, SEEK_SET);
104484778508Sblueswir1     for (i = 0; i < hdr->e_shnum; i++) {
104584778508Sblueswir1         if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
104684778508Sblueswir1             return;
104784778508Sblueswir1 #ifdef BSWAP_NEEDED
104884778508Sblueswir1         bswap_shdr(&sechdr);
104984778508Sblueswir1 #endif
105084778508Sblueswir1         if (sechdr.sh_type == SHT_SYMTAB) {
105184778508Sblueswir1             symtab = sechdr;
105284778508Sblueswir1             lseek(fd, hdr->e_shoff
105384778508Sblueswir1                   + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
105484778508Sblueswir1             if (read(fd, &strtab, sizeof(strtab))
105584778508Sblueswir1                 != sizeof(strtab))
105684778508Sblueswir1                 return;
105784778508Sblueswir1 #ifdef BSWAP_NEEDED
105884778508Sblueswir1             bswap_shdr(&strtab);
105984778508Sblueswir1 #endif
106084778508Sblueswir1             goto found;
106184778508Sblueswir1         }
106284778508Sblueswir1     }
106384778508Sblueswir1     return; /* Shouldn't happen... */
106484778508Sblueswir1 
106584778508Sblueswir1  found:
106684778508Sblueswir1     /* Now know where the strtab and symtab are.  Snarf them. */
106784778508Sblueswir1     s = malloc(sizeof(*s));
106884778508Sblueswir1     syms = malloc(symtab.sh_size);
106929718712SStefan Weil     if (!syms) {
107029718712SStefan Weil         free(s);
107184778508Sblueswir1         return;
107229718712SStefan Weil     }
107384778508Sblueswir1     s->disas_strtab = strings = malloc(strtab.sh_size);
107429718712SStefan Weil     if (!s->disas_strtab) {
107529718712SStefan Weil         free(s);
107629718712SStefan Weil         free(syms);
107784778508Sblueswir1         return;
107829718712SStefan Weil     }
107984778508Sblueswir1 
108084778508Sblueswir1     lseek(fd, symtab.sh_offset, SEEK_SET);
108129718712SStefan Weil     if (read(fd, syms, symtab.sh_size) != symtab.sh_size) {
108229718712SStefan Weil         free(s);
108329718712SStefan Weil         free(syms);
108429718712SStefan Weil         free(strings);
108584778508Sblueswir1         return;
108629718712SStefan Weil     }
108784778508Sblueswir1 
108884778508Sblueswir1     nsyms = symtab.sh_size / sizeof(struct elf_sym);
108984778508Sblueswir1 
109084778508Sblueswir1     i = 0;
109184778508Sblueswir1     while (i < nsyms) {
109284778508Sblueswir1 #ifdef BSWAP_NEEDED
109384778508Sblueswir1         bswap_sym(syms + i);
109484778508Sblueswir1 #endif
109584778508Sblueswir1         // Throw away entries which we do not need.
109684778508Sblueswir1         if (syms[i].st_shndx == SHN_UNDEF ||
109784778508Sblueswir1                 syms[i].st_shndx >= SHN_LORESERVE ||
109884778508Sblueswir1                 ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
109984778508Sblueswir1             nsyms--;
110084778508Sblueswir1             if (i < nsyms) {
110184778508Sblueswir1                 syms[i] = syms[nsyms];
110284778508Sblueswir1             }
110384778508Sblueswir1             continue;
110484778508Sblueswir1         }
110584778508Sblueswir1 #if defined(TARGET_ARM) || defined (TARGET_MIPS)
110684778508Sblueswir1         /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
110784778508Sblueswir1         syms[i].st_value &= ~(target_ulong)1;
110884778508Sblueswir1 #endif
110984778508Sblueswir1         i++;
111084778508Sblueswir1     }
111129718712SStefan Weil 
111229718712SStefan Weil      /* Attempt to free the storage associated with the local symbols
111329718712SStefan Weil         that we threw away.  Whether or not this has any effect on the
111429718712SStefan Weil         memory allocation depends on the malloc implementation and how
111529718712SStefan Weil         many symbols we managed to discard. */
111629718712SStefan Weil     new_syms = realloc(syms, nsyms * sizeof(*syms));
111729718712SStefan Weil     if (new_syms == NULL) {
111829718712SStefan Weil         free(s);
111929718712SStefan Weil         free(syms);
112029718712SStefan Weil         free(strings);
112129718712SStefan Weil         return;
112229718712SStefan Weil     }
112329718712SStefan Weil     syms = new_syms;
112484778508Sblueswir1 
112584778508Sblueswir1     qsort(syms, nsyms, sizeof(*syms), symcmp);
112684778508Sblueswir1 
112784778508Sblueswir1     lseek(fd, strtab.sh_offset, SEEK_SET);
112829718712SStefan Weil     if (read(fd, strings, strtab.sh_size) != strtab.sh_size) {
112929718712SStefan Weil         free(s);
113029718712SStefan Weil         free(syms);
113129718712SStefan Weil         free(strings);
113284778508Sblueswir1         return;
113329718712SStefan Weil     }
113484778508Sblueswir1     s->disas_num_syms = nsyms;
113584778508Sblueswir1 #if ELF_CLASS == ELFCLASS32
113684778508Sblueswir1     s->disas_symtab.elf32 = syms;
1137032e51d7SBlue Swirl     s->lookup_symbol = (lookup_symbol_t)lookup_symbolxx;
113884778508Sblueswir1 #else
113984778508Sblueswir1     s->disas_symtab.elf64 = syms;
1140032e51d7SBlue Swirl     s->lookup_symbol = (lookup_symbol_t)lookup_symbolxx;
114184778508Sblueswir1 #endif
114284778508Sblueswir1     s->next = syminfos;
114384778508Sblueswir1     syminfos = s;
114484778508Sblueswir1 }
114584778508Sblueswir1 
114684778508Sblueswir1 int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
114784778508Sblueswir1                     struct image_info * info)
114884778508Sblueswir1 {
114984778508Sblueswir1     struct elfhdr elf_ex;
115084778508Sblueswir1     struct elfhdr interp_elf_ex;
115184778508Sblueswir1     struct exec interp_ex;
115284778508Sblueswir1     int interpreter_fd = -1; /* avoid warning */
115384778508Sblueswir1     abi_ulong load_addr, load_bias;
115484778508Sblueswir1     int load_addr_set = 0;
115584778508Sblueswir1     unsigned int interpreter_type = INTERPRETER_NONE;
115684778508Sblueswir1     unsigned char ibcs2_interpreter;
115784778508Sblueswir1     int i;
115884778508Sblueswir1     struct elf_phdr * elf_ppnt;
115984778508Sblueswir1     struct elf_phdr *elf_phdata;
116084778508Sblueswir1     abi_ulong elf_bss, k, elf_brk;
116184778508Sblueswir1     int retval;
116284778508Sblueswir1     char * elf_interpreter;
116384778508Sblueswir1     abi_ulong elf_entry, interp_load_addr = 0;
116484778508Sblueswir1     abi_ulong start_code, end_code, start_data, end_data;
116584778508Sblueswir1     abi_ulong reloc_func_desc = 0;
116671025956SPeter Maydell #ifdef LOW_ELF_STACK
116771025956SPeter Maydell     abi_ulong elf_stack = ~((abi_ulong)0UL);
116871025956SPeter Maydell #endif
116984778508Sblueswir1     char passed_fileno[6];
117084778508Sblueswir1 
117184778508Sblueswir1     ibcs2_interpreter = 0;
117284778508Sblueswir1     load_addr = 0;
117384778508Sblueswir1     load_bias = 0;
117484778508Sblueswir1     elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
117584778508Sblueswir1 #ifdef BSWAP_NEEDED
117684778508Sblueswir1     bswap_ehdr(&elf_ex);
117784778508Sblueswir1 #endif
117884778508Sblueswir1 
117984778508Sblueswir1     /* First of all, some simple consistency checks */
118084778508Sblueswir1     if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
118184778508Sblueswir1                                 (! elf_check_arch(elf_ex.e_machine))) {
118284778508Sblueswir1             return -ENOEXEC;
118384778508Sblueswir1     }
118484778508Sblueswir1 
118584778508Sblueswir1     bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
118684778508Sblueswir1     bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
118784778508Sblueswir1     bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
118884778508Sblueswir1     if (!bprm->p) {
118984778508Sblueswir1         retval = -E2BIG;
119084778508Sblueswir1     }
119184778508Sblueswir1 
119284778508Sblueswir1     /* Now read in all of the header information */
119384778508Sblueswir1     elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
119484778508Sblueswir1     if (elf_phdata == NULL) {
119584778508Sblueswir1         return -ENOMEM;
119684778508Sblueswir1     }
119784778508Sblueswir1 
119884778508Sblueswir1     retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
119984778508Sblueswir1     if(retval > 0) {
120084778508Sblueswir1         retval = read(bprm->fd, (char *) elf_phdata,
120184778508Sblueswir1                                 elf_ex.e_phentsize * elf_ex.e_phnum);
120284778508Sblueswir1     }
120384778508Sblueswir1 
120484778508Sblueswir1     if (retval < 0) {
120584778508Sblueswir1         perror("load_elf_binary");
120684778508Sblueswir1         exit(-1);
120784778508Sblueswir1         free (elf_phdata);
120884778508Sblueswir1         return -errno;
120984778508Sblueswir1     }
121084778508Sblueswir1 
121184778508Sblueswir1 #ifdef BSWAP_NEEDED
121284778508Sblueswir1     elf_ppnt = elf_phdata;
121384778508Sblueswir1     for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
121484778508Sblueswir1         bswap_phdr(elf_ppnt);
121584778508Sblueswir1     }
121684778508Sblueswir1 #endif
121784778508Sblueswir1     elf_ppnt = elf_phdata;
121884778508Sblueswir1 
121984778508Sblueswir1     elf_bss = 0;
122084778508Sblueswir1     elf_brk = 0;
122184778508Sblueswir1 
122284778508Sblueswir1 
122384778508Sblueswir1     elf_interpreter = NULL;
122484778508Sblueswir1     start_code = ~((abi_ulong)0UL);
122584778508Sblueswir1     end_code = 0;
122684778508Sblueswir1     start_data = 0;
122784778508Sblueswir1     end_data = 0;
122884778508Sblueswir1     interp_ex.a_info = 0;
122984778508Sblueswir1 
123084778508Sblueswir1     for(i=0;i < elf_ex.e_phnum; i++) {
123184778508Sblueswir1         if (elf_ppnt->p_type == PT_INTERP) {
123284778508Sblueswir1             if ( elf_interpreter != NULL )
123384778508Sblueswir1             {
123484778508Sblueswir1                 free (elf_phdata);
123584778508Sblueswir1                 free(elf_interpreter);
123684778508Sblueswir1                 close(bprm->fd);
123784778508Sblueswir1                 return -EINVAL;
123884778508Sblueswir1             }
123984778508Sblueswir1 
124084778508Sblueswir1             /* This is the program interpreter used for
124184778508Sblueswir1              * shared libraries - for now assume that this
124284778508Sblueswir1              * is an a.out format binary
124384778508Sblueswir1              */
124484778508Sblueswir1 
124584778508Sblueswir1             elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
124684778508Sblueswir1 
124784778508Sblueswir1             if (elf_interpreter == NULL) {
124884778508Sblueswir1                 free (elf_phdata);
124984778508Sblueswir1                 close(bprm->fd);
125084778508Sblueswir1                 return -ENOMEM;
125184778508Sblueswir1             }
125284778508Sblueswir1 
125384778508Sblueswir1             retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
125484778508Sblueswir1             if(retval >= 0) {
125584778508Sblueswir1                 retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
125684778508Sblueswir1             }
125784778508Sblueswir1             if(retval < 0) {
125884778508Sblueswir1                 perror("load_elf_binary2");
125984778508Sblueswir1                 exit(-1);
126084778508Sblueswir1             }
126184778508Sblueswir1 
126284778508Sblueswir1             /* If the program interpreter is one of these two,
126384778508Sblueswir1                then assume an iBCS2 image. Otherwise assume
126484778508Sblueswir1                a native linux image. */
126584778508Sblueswir1 
126684778508Sblueswir1             /* JRP - Need to add X86 lib dir stuff here... */
126784778508Sblueswir1 
126884778508Sblueswir1             if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
126984778508Sblueswir1                 strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
127084778508Sblueswir1               ibcs2_interpreter = 1;
127184778508Sblueswir1             }
127284778508Sblueswir1 
127384778508Sblueswir1 #if 0
1274b7d43d03SPaul Bolle             printf("Using ELF interpreter %s\n", path(elf_interpreter));
127584778508Sblueswir1 #endif
127684778508Sblueswir1             if (retval >= 0) {
127784778508Sblueswir1                 retval = open(path(elf_interpreter), O_RDONLY);
127884778508Sblueswir1                 if(retval >= 0) {
127984778508Sblueswir1                     interpreter_fd = retval;
128084778508Sblueswir1                 }
128184778508Sblueswir1                 else {
128284778508Sblueswir1                     perror(elf_interpreter);
128384778508Sblueswir1                     exit(-1);
128484778508Sblueswir1                     /* retval = -errno; */
128584778508Sblueswir1                 }
128684778508Sblueswir1             }
128784778508Sblueswir1 
128884778508Sblueswir1             if (retval >= 0) {
128984778508Sblueswir1                 retval = lseek(interpreter_fd, 0, SEEK_SET);
129084778508Sblueswir1                 if(retval >= 0) {
129184778508Sblueswir1                     retval = read(interpreter_fd,bprm->buf,128);
129284778508Sblueswir1                 }
129384778508Sblueswir1             }
129484778508Sblueswir1             if (retval >= 0) {
129584778508Sblueswir1                 interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
129684778508Sblueswir1                 interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */
129784778508Sblueswir1             }
129884778508Sblueswir1             if (retval < 0) {
129984778508Sblueswir1                 perror("load_elf_binary3");
130084778508Sblueswir1                 exit(-1);
130184778508Sblueswir1                 free (elf_phdata);
130284778508Sblueswir1                 free(elf_interpreter);
130384778508Sblueswir1                 close(bprm->fd);
130484778508Sblueswir1                 return retval;
130584778508Sblueswir1             }
130684778508Sblueswir1         }
130784778508Sblueswir1         elf_ppnt++;
130884778508Sblueswir1     }
130984778508Sblueswir1 
131084778508Sblueswir1     /* Some simple consistency checks for the interpreter */
131184778508Sblueswir1     if (elf_interpreter){
131284778508Sblueswir1         interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
131384778508Sblueswir1 
131484778508Sblueswir1         /* Now figure out which format our binary is */
131584778508Sblueswir1         if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
131684778508Sblueswir1                 (N_MAGIC(interp_ex) != QMAGIC)) {
131784778508Sblueswir1           interpreter_type = INTERPRETER_ELF;
131884778508Sblueswir1         }
131984778508Sblueswir1 
132084778508Sblueswir1         if (interp_elf_ex.e_ident[0] != 0x7f ||
1321fff2a02fSChristoph Egger                 strncmp((char *)&interp_elf_ex.e_ident[1], "ELF",3) != 0) {
132284778508Sblueswir1             interpreter_type &= ~INTERPRETER_ELF;
132384778508Sblueswir1         }
132484778508Sblueswir1 
132584778508Sblueswir1         if (!interpreter_type) {
132684778508Sblueswir1             free(elf_interpreter);
132784778508Sblueswir1             free(elf_phdata);
132884778508Sblueswir1             close(bprm->fd);
132984778508Sblueswir1             return -ELIBBAD;
133084778508Sblueswir1         }
133184778508Sblueswir1     }
133284778508Sblueswir1 
133384778508Sblueswir1     /* OK, we are done with that, now set up the arg stuff,
133484778508Sblueswir1        and then start this sucker up */
133584778508Sblueswir1 
133684778508Sblueswir1     {
133784778508Sblueswir1         char * passed_p;
133884778508Sblueswir1 
133984778508Sblueswir1         if (interpreter_type == INTERPRETER_AOUT) {
134084778508Sblueswir1             snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
134184778508Sblueswir1             passed_p = passed_fileno;
134284778508Sblueswir1 
134384778508Sblueswir1             if (elf_interpreter) {
134484778508Sblueswir1                 bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p);
134584778508Sblueswir1                 bprm->argc++;
134684778508Sblueswir1             }
134784778508Sblueswir1         }
134884778508Sblueswir1         if (!bprm->p) {
134984778508Sblueswir1             free(elf_interpreter);
135084778508Sblueswir1             free (elf_phdata);
135184778508Sblueswir1             close(bprm->fd);
135284778508Sblueswir1             return -E2BIG;
135384778508Sblueswir1         }
135484778508Sblueswir1     }
135584778508Sblueswir1 
135684778508Sblueswir1     /* OK, This is the point of no return */
135784778508Sblueswir1     info->end_data = 0;
135884778508Sblueswir1     info->end_code = 0;
135984778508Sblueswir1     info->start_mmap = (abi_ulong)ELF_START_MMAP;
136084778508Sblueswir1     info->mmap = 0;
136184778508Sblueswir1     elf_entry = (abi_ulong) elf_ex.e_entry;
136284778508Sblueswir1 
13632fa5d9baSBlue Swirl     /*
13642fa5d9baSBlue Swirl      * In case where user has not explicitly set the guest_base, we
13652fa5d9baSBlue Swirl      * probe here that should we set it automatically.
13662fa5d9baSBlue Swirl      */
13672fa5d9baSBlue Swirl     if (!have_guest_base) {
13682fa5d9baSBlue Swirl         /*
13692fa5d9baSBlue Swirl          * Go through ELF program header table and find out whether
13702fa5d9baSBlue Swirl          * any of the segments drop below our current mmap_min_addr and
13712fa5d9baSBlue Swirl          * in that case set guest_base to corresponding address.
13722fa5d9baSBlue Swirl          */
13732fa5d9baSBlue Swirl         for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum;
13742fa5d9baSBlue Swirl             i++, elf_ppnt++) {
13752fa5d9baSBlue Swirl             if (elf_ppnt->p_type != PT_LOAD)
13762fa5d9baSBlue Swirl                 continue;
13772fa5d9baSBlue Swirl             if (HOST_PAGE_ALIGN(elf_ppnt->p_vaddr) < mmap_min_addr) {
13782fa5d9baSBlue Swirl                 guest_base = HOST_PAGE_ALIGN(mmap_min_addr);
13792fa5d9baSBlue Swirl                 break;
13802fa5d9baSBlue Swirl             }
13812fa5d9baSBlue Swirl         }
13822fa5d9baSBlue Swirl     }
13832fa5d9baSBlue Swirl 
138484778508Sblueswir1     /* Do this so that we can load the interpreter, if need be.  We will
138584778508Sblueswir1        change some of these later */
138684778508Sblueswir1     info->rss = 0;
138784778508Sblueswir1     bprm->p = setup_arg_pages(bprm->p, bprm, info);
138884778508Sblueswir1     info->start_stack = bprm->p;
138984778508Sblueswir1 
139084778508Sblueswir1     /* Now we do a little grungy work by mmaping the ELF image into
139184778508Sblueswir1      * the correct location in memory.  At this point, we assume that
139284778508Sblueswir1      * the image should be loaded at fixed address, not at a variable
139384778508Sblueswir1      * address.
139484778508Sblueswir1      */
139584778508Sblueswir1 
139684778508Sblueswir1     for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
139784778508Sblueswir1         int elf_prot = 0;
139884778508Sblueswir1         int elf_flags = 0;
139984778508Sblueswir1         abi_ulong error;
140084778508Sblueswir1 
140184778508Sblueswir1         if (elf_ppnt->p_type != PT_LOAD)
140284778508Sblueswir1             continue;
140384778508Sblueswir1 
140484778508Sblueswir1         if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
140584778508Sblueswir1         if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
140684778508Sblueswir1         if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
140784778508Sblueswir1         elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
140884778508Sblueswir1         if (elf_ex.e_type == ET_EXEC || load_addr_set) {
140984778508Sblueswir1             elf_flags |= MAP_FIXED;
141084778508Sblueswir1         } else if (elf_ex.e_type == ET_DYN) {
141184778508Sblueswir1             /* Try and get dynamic programs out of the way of the default mmap
141284778508Sblueswir1                base, as well as whatever program they might try to exec.  This
141384778508Sblueswir1                is because the brk will follow the loader, and is not movable.  */
141484778508Sblueswir1             /* NOTE: for qemu, we do a big mmap to get enough space
141584778508Sblueswir1                without hardcoding any address */
141684778508Sblueswir1             error = target_mmap(0, ET_DYN_MAP_SIZE,
141784778508Sblueswir1                                 PROT_NONE, MAP_PRIVATE | MAP_ANON,
141884778508Sblueswir1                                 -1, 0);
141984778508Sblueswir1             if (error == -1) {
142084778508Sblueswir1                 perror("mmap");
142184778508Sblueswir1                 exit(-1);
142284778508Sblueswir1             }
142384778508Sblueswir1             load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
142484778508Sblueswir1         }
142584778508Sblueswir1 
142684778508Sblueswir1         error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
142784778508Sblueswir1                             (elf_ppnt->p_filesz +
142884778508Sblueswir1                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
142984778508Sblueswir1                             elf_prot,
143084778508Sblueswir1                             (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
143184778508Sblueswir1                             bprm->fd,
143284778508Sblueswir1                             (elf_ppnt->p_offset -
143384778508Sblueswir1                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
143484778508Sblueswir1         if (error == -1) {
143584778508Sblueswir1             perror("mmap");
143684778508Sblueswir1             exit(-1);
143784778508Sblueswir1         }
143884778508Sblueswir1 
143984778508Sblueswir1 #ifdef LOW_ELF_STACK
144084778508Sblueswir1         if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
144184778508Sblueswir1             elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr);
144284778508Sblueswir1 #endif
144384778508Sblueswir1 
144484778508Sblueswir1         if (!load_addr_set) {
144584778508Sblueswir1             load_addr_set = 1;
144684778508Sblueswir1             load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
144784778508Sblueswir1             if (elf_ex.e_type == ET_DYN) {
144884778508Sblueswir1                 load_bias += error -
144984778508Sblueswir1                     TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
145084778508Sblueswir1                 load_addr += load_bias;
145184778508Sblueswir1                 reloc_func_desc = load_bias;
145284778508Sblueswir1             }
145384778508Sblueswir1         }
145484778508Sblueswir1         k = elf_ppnt->p_vaddr;
145584778508Sblueswir1         if (k < start_code)
145684778508Sblueswir1             start_code = k;
145784778508Sblueswir1         if (start_data < k)
145884778508Sblueswir1             start_data = k;
145984778508Sblueswir1         k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
146084778508Sblueswir1         if (k > elf_bss)
146184778508Sblueswir1             elf_bss = k;
146284778508Sblueswir1         if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
146384778508Sblueswir1             end_code = k;
146484778508Sblueswir1         if (end_data < k)
146584778508Sblueswir1             end_data = k;
146684778508Sblueswir1         k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
146784778508Sblueswir1         if (k > elf_brk) elf_brk = k;
146884778508Sblueswir1     }
146984778508Sblueswir1 
147084778508Sblueswir1     elf_entry += load_bias;
147184778508Sblueswir1     elf_bss += load_bias;
147284778508Sblueswir1     elf_brk += load_bias;
147384778508Sblueswir1     start_code += load_bias;
147484778508Sblueswir1     end_code += load_bias;
147584778508Sblueswir1     start_data += load_bias;
147684778508Sblueswir1     end_data += load_bias;
147784778508Sblueswir1 
147884778508Sblueswir1     if (elf_interpreter) {
147984778508Sblueswir1         if (interpreter_type & 1) {
148084778508Sblueswir1             elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
148184778508Sblueswir1         }
148284778508Sblueswir1         else if (interpreter_type & 2) {
148384778508Sblueswir1             elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
148484778508Sblueswir1                                             &interp_load_addr);
148584778508Sblueswir1         }
148684778508Sblueswir1         reloc_func_desc = interp_load_addr;
148784778508Sblueswir1 
148884778508Sblueswir1         close(interpreter_fd);
148984778508Sblueswir1         free(elf_interpreter);
149084778508Sblueswir1 
149184778508Sblueswir1         if (elf_entry == ~((abi_ulong)0UL)) {
149284778508Sblueswir1             printf("Unable to load interpreter\n");
149384778508Sblueswir1             free(elf_phdata);
149484778508Sblueswir1             exit(-1);
149584778508Sblueswir1             return 0;
149684778508Sblueswir1         }
149784778508Sblueswir1     }
149884778508Sblueswir1 
149984778508Sblueswir1     free(elf_phdata);
150084778508Sblueswir1 
150193fcfe39Saliguori     if (qemu_log_enabled())
150284778508Sblueswir1         load_symbols(&elf_ex, bprm->fd);
150384778508Sblueswir1 
150484778508Sblueswir1     if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
150584778508Sblueswir1     info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
150684778508Sblueswir1 
150784778508Sblueswir1 #ifdef LOW_ELF_STACK
150884778508Sblueswir1     info->start_stack = bprm->p = elf_stack - 4;
150984778508Sblueswir1 #endif
151084778508Sblueswir1     bprm->p = create_elf_tables(bprm->p,
151184778508Sblueswir1                     bprm->argc,
151284778508Sblueswir1                     bprm->envc,
151384778508Sblueswir1                     &elf_ex,
151484778508Sblueswir1                     load_addr, load_bias,
151584778508Sblueswir1                     interp_load_addr,
151684778508Sblueswir1                     (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
151784778508Sblueswir1                     info);
151884778508Sblueswir1     info->load_addr = reloc_func_desc;
151984778508Sblueswir1     info->start_brk = info->brk = elf_brk;
152084778508Sblueswir1     info->end_code = end_code;
152184778508Sblueswir1     info->start_code = start_code;
152284778508Sblueswir1     info->start_data = start_data;
152384778508Sblueswir1     info->end_data = end_data;
152484778508Sblueswir1     info->start_stack = bprm->p;
152584778508Sblueswir1 
152684778508Sblueswir1     /* Calling set_brk effectively mmaps the pages that we need for the bss and break
152784778508Sblueswir1        sections */
152884778508Sblueswir1     set_brk(elf_bss, elf_brk);
152984778508Sblueswir1 
153084778508Sblueswir1     padzero(elf_bss, elf_brk);
153184778508Sblueswir1 
153284778508Sblueswir1 #if 0
153384778508Sblueswir1     printf("(start_brk) %x\n" , info->start_brk);
153484778508Sblueswir1     printf("(end_code) %x\n" , info->end_code);
153584778508Sblueswir1     printf("(start_code) %x\n" , info->start_code);
153684778508Sblueswir1     printf("(end_data) %x\n" , info->end_data);
153784778508Sblueswir1     printf("(start_stack) %x\n" , info->start_stack);
153884778508Sblueswir1     printf("(brk) %x\n" , info->brk);
153984778508Sblueswir1 #endif
154084778508Sblueswir1 
154184778508Sblueswir1     if ( info->personality == PER_SVR4 )
154284778508Sblueswir1     {
154384778508Sblueswir1             /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
154484778508Sblueswir1                and some applications "depend" upon this behavior.
154584778508Sblueswir1                Since we do not have the power to recompile these, we
154684778508Sblueswir1                emulate the SVr4 behavior.  Sigh.  */
154771025956SPeter Maydell             target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
154884778508Sblueswir1                                       MAP_FIXED | MAP_PRIVATE, -1, 0);
154984778508Sblueswir1     }
155084778508Sblueswir1 
155184778508Sblueswir1     info->entry = elf_entry;
155284778508Sblueswir1 
155384778508Sblueswir1     return 0;
155484778508Sblueswir1 }
155584778508Sblueswir1 
155684778508Sblueswir1 static int load_aout_interp(void * exptr, int interp_fd)
155784778508Sblueswir1 {
155884778508Sblueswir1     printf("a.out interpreter not yet supported\n");
155984778508Sblueswir1     return(0);
156084778508Sblueswir1 }
156184778508Sblueswir1 
156284778508Sblueswir1 void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
156384778508Sblueswir1 {
156484778508Sblueswir1     init_thread(regs, infop);
156584778508Sblueswir1 }
1566