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