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