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