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 4730ac07d4Sbellard #define ELF_START_MMAP 0x80000000 4830ac07d4Sbellard 4930ac07d4Sbellard /* 5030ac07d4Sbellard * This is used to ensure we don't load something for the wrong architecture. 5130ac07d4Sbellard */ 5230ac07d4Sbellard #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) ) 5330ac07d4Sbellard 5430ac07d4Sbellard /* 5530ac07d4Sbellard * These are used to set parameters in the core dumps. 5630ac07d4Sbellard */ 5730ac07d4Sbellard #define ELF_CLASS ELFCLASS32 5830ac07d4Sbellard #define ELF_DATA ELFDATA2LSB 5930ac07d4Sbellard #define ELF_ARCH EM_386 6030ac07d4Sbellard 61e5fe0c52Spbrook static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) 62e5fe0c52Spbrook { 63e5fe0c52Spbrook regs->esp = infop->start_stack; 64e5fe0c52Spbrook regs->eip = infop->entry; 65e5fe0c52Spbrook 6630ac07d4Sbellard /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program 6730ac07d4Sbellard starts %edx contains a pointer to a function which might be 6830ac07d4Sbellard registered using `atexit'. This provides a mean for the 6930ac07d4Sbellard dynamic linker to call DT_FINI functions for shared libraries 7030ac07d4Sbellard that have been loaded before the code runs. 7130ac07d4Sbellard 7230ac07d4Sbellard A value of 0 tells we have no such handler. */ 73e5fe0c52Spbrook regs->edx = 0; 74b346ff46Sbellard } 75b346ff46Sbellard 76b346ff46Sbellard #define USE_ELF_CORE_DUMP 77b346ff46Sbellard #define ELF_EXEC_PAGESIZE 4096 78b346ff46Sbellard 79b346ff46Sbellard #endif 80b346ff46Sbellard 81b346ff46Sbellard #ifdef TARGET_ARM 82b346ff46Sbellard 83b346ff46Sbellard #define ELF_START_MMAP 0x80000000 84b346ff46Sbellard 85b346ff46Sbellard #define elf_check_arch(x) ( (x) == EM_ARM ) 86b346ff46Sbellard 87b346ff46Sbellard #define ELF_CLASS ELFCLASS32 88b346ff46Sbellard #ifdef TARGET_WORDS_BIGENDIAN 89b346ff46Sbellard #define ELF_DATA ELFDATA2MSB 90b346ff46Sbellard #else 91b346ff46Sbellard #define ELF_DATA ELFDATA2LSB 92b346ff46Sbellard #endif 93b346ff46Sbellard #define ELF_ARCH EM_ARM 94b346ff46Sbellard 95b346ff46Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) 96b346ff46Sbellard { 9753a5960aSpbrook target_long stack = infop->start_stack; 98b346ff46Sbellard memset(regs, 0, sizeof(*regs)); 99b346ff46Sbellard regs->ARM_cpsr = 0x10; 1000240ded8Spbrook if (infop->entry & 1) 1010240ded8Spbrook regs->ARM_cpsr |= CPSR_T; 1020240ded8Spbrook regs->ARM_pc = infop->entry & 0xfffffffe; 103b346ff46Sbellard regs->ARM_sp = infop->start_stack; 10453a5960aSpbrook regs->ARM_r2 = tgetl(stack + 8); /* envp */ 10553a5960aSpbrook regs->ARM_r1 = tgetl(stack + 4); /* envp */ 106a1516e92Sbellard /* XXX: it seems that r0 is zeroed after ! */ 107e5fe0c52Spbrook regs->ARM_r0 = 0; 108e5fe0c52Spbrook /* For uClinux PIC binaries. */ 109e5fe0c52Spbrook regs->ARM_r10 = infop->start_data; 110b346ff46Sbellard } 111b346ff46Sbellard 11230ac07d4Sbellard #define USE_ELF_CORE_DUMP 11330ac07d4Sbellard #define ELF_EXEC_PAGESIZE 4096 11430ac07d4Sbellard 115afce2927Sbellard enum 116afce2927Sbellard { 117afce2927Sbellard ARM_HWCAP_ARM_SWP = 1 << 0, 118afce2927Sbellard ARM_HWCAP_ARM_HALF = 1 << 1, 119afce2927Sbellard ARM_HWCAP_ARM_THUMB = 1 << 2, 120afce2927Sbellard ARM_HWCAP_ARM_26BIT = 1 << 3, 121afce2927Sbellard ARM_HWCAP_ARM_FAST_MULT = 1 << 4, 122afce2927Sbellard ARM_HWCAP_ARM_FPA = 1 << 5, 123afce2927Sbellard ARM_HWCAP_ARM_VFP = 1 << 6, 124afce2927Sbellard ARM_HWCAP_ARM_EDSP = 1 << 7, 125afce2927Sbellard }; 126afce2927Sbellard 12715338fd7Sbellard #define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF \ 128afce2927Sbellard | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT \ 129afce2927Sbellard | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP) 130afce2927Sbellard 13130ac07d4Sbellard #endif 13230ac07d4Sbellard 133853d6f7aSbellard #ifdef TARGET_SPARC 134a315a145Sbellard #ifdef TARGET_SPARC64 135853d6f7aSbellard 136853d6f7aSbellard #define ELF_START_MMAP 0x80000000 137853d6f7aSbellard 1385ef54116Sbellard #define elf_check_arch(x) ( (x) == EM_SPARCV9 ) 139853d6f7aSbellard 140a315a145Sbellard #define ELF_CLASS ELFCLASS64 141a315a145Sbellard #define ELF_DATA ELFDATA2MSB 1425ef54116Sbellard #define ELF_ARCH EM_SPARCV9 1435ef54116Sbellard 1445ef54116Sbellard #define STACK_BIAS 2047 145a315a145Sbellard 146a315a145Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) 147a315a145Sbellard { 148a315a145Sbellard regs->tstate = 0; 149a315a145Sbellard regs->pc = infop->entry; 150a315a145Sbellard regs->npc = regs->pc + 4; 151a315a145Sbellard regs->y = 0; 1525ef54116Sbellard regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS; 153a315a145Sbellard } 154a315a145Sbellard 155a315a145Sbellard #else 156a315a145Sbellard #define ELF_START_MMAP 0x80000000 157a315a145Sbellard 158a315a145Sbellard #define elf_check_arch(x) ( (x) == EM_SPARC ) 159a315a145Sbellard 160853d6f7aSbellard #define ELF_CLASS ELFCLASS32 161853d6f7aSbellard #define ELF_DATA ELFDATA2MSB 162853d6f7aSbellard #define ELF_ARCH EM_SPARC 163853d6f7aSbellard 164853d6f7aSbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) 165853d6f7aSbellard { 166f5155289Sbellard regs->psr = 0; 167f5155289Sbellard regs->pc = infop->entry; 168f5155289Sbellard regs->npc = regs->pc + 4; 169f5155289Sbellard regs->y = 0; 170f5155289Sbellard regs->u_regs[14] = infop->start_stack - 16 * 4; 171853d6f7aSbellard } 172853d6f7aSbellard 173853d6f7aSbellard #endif 174a315a145Sbellard #endif 175853d6f7aSbellard 17667867308Sbellard #ifdef TARGET_PPC 17767867308Sbellard 17867867308Sbellard #define ELF_START_MMAP 0x80000000 17967867308Sbellard 18067867308Sbellard #define elf_check_arch(x) ( (x) == EM_PPC ) 18167867308Sbellard 18267867308Sbellard #define ELF_CLASS ELFCLASS32 18367867308Sbellard #ifdef TARGET_WORDS_BIGENDIAN 18467867308Sbellard #define ELF_DATA ELFDATA2MSB 18567867308Sbellard #else 18667867308Sbellard #define ELF_DATA ELFDATA2LSB 18767867308Sbellard #endif 18867867308Sbellard #define ELF_ARCH EM_PPC 18967867308Sbellard 190f5155289Sbellard /* 191f5155289Sbellard * We need to put in some extra aux table entries to tell glibc what 192f5155289Sbellard * the cache block size is, so it can use the dcbz instruction safely. 193f5155289Sbellard */ 194f5155289Sbellard #define AT_DCACHEBSIZE 19 195f5155289Sbellard #define AT_ICACHEBSIZE 20 196f5155289Sbellard #define AT_UCACHEBSIZE 21 197f5155289Sbellard /* A special ignored type value for PPC, for glibc compatibility. */ 198f5155289Sbellard #define AT_IGNOREPPC 22 199f5155289Sbellard /* 200f5155289Sbellard * The requirements here are: 201f5155289Sbellard * - keep the final alignment of sp (sp & 0xf) 202f5155289Sbellard * - make sure the 32-bit value at the first 16 byte aligned position of 203f5155289Sbellard * AUXV is greater than 16 for glibc compatibility. 204f5155289Sbellard * AT_IGNOREPPC is used for that. 205f5155289Sbellard * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC, 206f5155289Sbellard * even if DLINFO_ARCH_ITEMS goes to zero or is undefined. 207f5155289Sbellard */ 2080bccf03dSbellard #define DLINFO_ARCH_ITEMS 5 209f5155289Sbellard #define ARCH_DLINFO \ 210f5155289Sbellard do { \ 2110bccf03dSbellard NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20); \ 2120bccf03dSbellard NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20); \ 2130bccf03dSbellard NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \ 214f5155289Sbellard /* \ 215f5155289Sbellard * Now handle glibc compatibility. \ 216f5155289Sbellard */ \ 2170bccf03dSbellard NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ 2180bccf03dSbellard NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ 219f5155289Sbellard } while (0) 220f5155289Sbellard 22167867308Sbellard static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop) 22267867308Sbellard { 223e5fe0c52Spbrook target_ulong pos = infop->start_stack; 224e5fe0c52Spbrook target_ulong tmp; 225e5fe0c52Spbrook 22667867308Sbellard _regs->msr = 1 << MSR_PR; /* Set user mode */ 22767867308Sbellard _regs->gpr[1] = infop->start_stack; 22867867308Sbellard _regs->nip = infop->entry; 229e5fe0c52Spbrook /* Note that isn't exactly what regular kernel does 230e5fe0c52Spbrook * but this is what the ABI wants and is needed to allow 231e5fe0c52Spbrook * execution of PPC BSD programs. 232e5fe0c52Spbrook */ 233e5fe0c52Spbrook _regs->gpr[3] = tgetl(pos); 234e5fe0c52Spbrook pos += sizeof(target_ulong); 235e5fe0c52Spbrook _regs->gpr[4] = pos; 236e5fe0c52Spbrook for (tmp = 1; tmp != 0; pos += sizeof(target_ulong)) 237e5fe0c52Spbrook tmp = ldl(pos); 238e5fe0c52Spbrook _regs->gpr[5] = pos; 23967867308Sbellard } 24067867308Sbellard 24167867308Sbellard #define USE_ELF_CORE_DUMP 24267867308Sbellard #define ELF_EXEC_PAGESIZE 4096 24367867308Sbellard 24467867308Sbellard #endif 24567867308Sbellard 246048f6b4dSbellard #ifdef TARGET_MIPS 247048f6b4dSbellard 248048f6b4dSbellard #define ELF_START_MMAP 0x80000000 249048f6b4dSbellard 250048f6b4dSbellard #define elf_check_arch(x) ( (x) == EM_MIPS ) 251048f6b4dSbellard 252048f6b4dSbellard #define ELF_CLASS ELFCLASS32 253048f6b4dSbellard #ifdef TARGET_WORDS_BIGENDIAN 254048f6b4dSbellard #define ELF_DATA ELFDATA2MSB 255048f6b4dSbellard #else 256048f6b4dSbellard #define ELF_DATA ELFDATA2LSB 257048f6b4dSbellard #endif 258048f6b4dSbellard #define ELF_ARCH EM_MIPS 259048f6b4dSbellard 260048f6b4dSbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) 261048f6b4dSbellard { 262048f6b4dSbellard regs->cp0_status = CP0St_UM; 263048f6b4dSbellard regs->cp0_epc = infop->entry; 264048f6b4dSbellard regs->regs[29] = infop->start_stack; 265048f6b4dSbellard } 266048f6b4dSbellard 267048f6b4dSbellard #endif /* TARGET_MIPS */ 268048f6b4dSbellard 269fdf9b3e8Sbellard #ifdef TARGET_SH4 270fdf9b3e8Sbellard 271fdf9b3e8Sbellard #define ELF_START_MMAP 0x80000000 272fdf9b3e8Sbellard 273fdf9b3e8Sbellard #define elf_check_arch(x) ( (x) == EM_SH ) 274fdf9b3e8Sbellard 275fdf9b3e8Sbellard #define ELF_CLASS ELFCLASS32 276fdf9b3e8Sbellard #define ELF_DATA ELFDATA2LSB 277fdf9b3e8Sbellard #define ELF_ARCH EM_SH 278fdf9b3e8Sbellard 279fdf9b3e8Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) 280fdf9b3e8Sbellard { 281fdf9b3e8Sbellard /* Check other registers XXXXX */ 282fdf9b3e8Sbellard regs->pc = infop->entry; 283fdf9b3e8Sbellard regs->regs[15] = infop->start_stack - 16 * 4; 284fdf9b3e8Sbellard } 285fdf9b3e8Sbellard 286fdf9b3e8Sbellard #define USE_ELF_CORE_DUMP 287fdf9b3e8Sbellard #define ELF_EXEC_PAGESIZE 4096 288fdf9b3e8Sbellard 289fdf9b3e8Sbellard #endif 290fdf9b3e8Sbellard 291e6e5906bSpbrook #ifdef TARGET_M68K 292e6e5906bSpbrook 293e6e5906bSpbrook #define ELF_START_MMAP 0x80000000 294e6e5906bSpbrook 295e6e5906bSpbrook #define elf_check_arch(x) ( (x) == EM_68K ) 296e6e5906bSpbrook 297e6e5906bSpbrook #define ELF_CLASS ELFCLASS32 298e6e5906bSpbrook #define ELF_DATA ELFDATA2MSB 299e6e5906bSpbrook #define ELF_ARCH EM_68K 300e6e5906bSpbrook 301e6e5906bSpbrook /* ??? Does this need to do anything? 302e6e5906bSpbrook #define ELF_PLAT_INIT(_r) */ 303e6e5906bSpbrook 304e6e5906bSpbrook static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) 305e6e5906bSpbrook { 306e6e5906bSpbrook regs->usp = infop->start_stack; 307e6e5906bSpbrook regs->sr = 0; 308e6e5906bSpbrook regs->pc = infop->entry; 309e6e5906bSpbrook } 310e6e5906bSpbrook 311e6e5906bSpbrook #define USE_ELF_CORE_DUMP 312e6e5906bSpbrook #define ELF_EXEC_PAGESIZE 8192 313e6e5906bSpbrook 314e6e5906bSpbrook #endif 315e6e5906bSpbrook 31615338fd7Sbellard #ifndef ELF_PLATFORM 31715338fd7Sbellard #define ELF_PLATFORM (NULL) 31815338fd7Sbellard #endif 31915338fd7Sbellard 32015338fd7Sbellard #ifndef ELF_HWCAP 32115338fd7Sbellard #define ELF_HWCAP 0 32215338fd7Sbellard #endif 32315338fd7Sbellard 32431e31b8aSbellard #include "elf.h" 32509bfb054Sbellard 32609bfb054Sbellard struct exec 32709bfb054Sbellard { 32809bfb054Sbellard unsigned int a_info; /* Use macros N_MAGIC, etc for access */ 32909bfb054Sbellard unsigned int a_text; /* length of text, in bytes */ 33009bfb054Sbellard unsigned int a_data; /* length of data, in bytes */ 33109bfb054Sbellard unsigned int a_bss; /* length of uninitialized data area, in bytes */ 33209bfb054Sbellard unsigned int a_syms; /* length of symbol table data in file, in bytes */ 33309bfb054Sbellard unsigned int a_entry; /* start address */ 33409bfb054Sbellard unsigned int a_trsize; /* length of relocation info for text, in bytes */ 33509bfb054Sbellard unsigned int a_drsize; /* length of relocation info for data, in bytes */ 33609bfb054Sbellard }; 33709bfb054Sbellard 33809bfb054Sbellard 33909bfb054Sbellard #define N_MAGIC(exec) ((exec).a_info & 0xffff) 34009bfb054Sbellard #define OMAGIC 0407 34109bfb054Sbellard #define NMAGIC 0410 34209bfb054Sbellard #define ZMAGIC 0413 34309bfb054Sbellard #define QMAGIC 0314 34409bfb054Sbellard 34509bfb054Sbellard /* max code+data+bss space allocated to elf interpreter */ 34609bfb054Sbellard #define INTERP_MAP_SIZE (32 * 1024 * 1024) 34709bfb054Sbellard 34809bfb054Sbellard /* max code+data+bss+brk space allocated to ET_DYN executables */ 34909bfb054Sbellard #define ET_DYN_MAP_SIZE (128 * 1024 * 1024) 35009bfb054Sbellard 35109bfb054Sbellard /* from personality.h */ 35209bfb054Sbellard 35309bfb054Sbellard /* Flags for bug emulation. These occupy the top three bytes. */ 35409bfb054Sbellard #define STICKY_TIMEOUTS 0x4000000 35509bfb054Sbellard #define WHOLE_SECONDS 0x2000000 35609bfb054Sbellard 35709bfb054Sbellard /* Personality types. These go in the low byte. Avoid using the top bit, 35809bfb054Sbellard * it will conflict with error returns. 35909bfb054Sbellard */ 36009bfb054Sbellard #define PER_MASK (0x00ff) 36109bfb054Sbellard #define PER_LINUX (0x0000) 36209bfb054Sbellard #define PER_SVR4 (0x0001 | STICKY_TIMEOUTS) 36309bfb054Sbellard #define PER_SVR3 (0x0002 | STICKY_TIMEOUTS) 36409bfb054Sbellard #define PER_SCOSVR3 (0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS) 36509bfb054Sbellard #define PER_WYSEV386 (0x0004 | STICKY_TIMEOUTS) 36609bfb054Sbellard #define PER_ISCR4 (0x0005 | STICKY_TIMEOUTS) 36709bfb054Sbellard #define PER_BSD (0x0006) 36809bfb054Sbellard #define PER_XENIX (0x0007 | STICKY_TIMEOUTS) 36931e31b8aSbellard 37031e31b8aSbellard /* Necessary parameters */ 37154936004Sbellard #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE 37254936004Sbellard #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1)) 37354936004Sbellard #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1)) 37431e31b8aSbellard 37531e31b8aSbellard #define INTERPRETER_NONE 0 37631e31b8aSbellard #define INTERPRETER_AOUT 1 37731e31b8aSbellard #define INTERPRETER_ELF 2 37831e31b8aSbellard 37915338fd7Sbellard #define DLINFO_ITEMS 12 38031e31b8aSbellard 38109bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) 38209bfb054Sbellard { 38309bfb054Sbellard memcpy(to, from, n); 38409bfb054Sbellard } 38509bfb054Sbellard 38631e31b8aSbellard extern unsigned long x86_stack_size; 38731e31b8aSbellard 38831e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd); 38931e31b8aSbellard 39031e31b8aSbellard #ifdef BSWAP_NEEDED 39192a31b1fSbellard static void bswap_ehdr(struct elfhdr *ehdr) 39231e31b8aSbellard { 39331e31b8aSbellard bswap16s(&ehdr->e_type); /* Object file type */ 39431e31b8aSbellard bswap16s(&ehdr->e_machine); /* Architecture */ 39531e31b8aSbellard bswap32s(&ehdr->e_version); /* Object file version */ 39692a31b1fSbellard bswaptls(&ehdr->e_entry); /* Entry point virtual address */ 39792a31b1fSbellard bswaptls(&ehdr->e_phoff); /* Program header table file offset */ 39892a31b1fSbellard bswaptls(&ehdr->e_shoff); /* Section header table file offset */ 39931e31b8aSbellard bswap32s(&ehdr->e_flags); /* Processor-specific flags */ 40031e31b8aSbellard bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ 40131e31b8aSbellard bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ 40231e31b8aSbellard bswap16s(&ehdr->e_phnum); /* Program header table entry count */ 40331e31b8aSbellard bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ 40431e31b8aSbellard bswap16s(&ehdr->e_shnum); /* Section header table entry count */ 40531e31b8aSbellard bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ 40631e31b8aSbellard } 40731e31b8aSbellard 40892a31b1fSbellard static void bswap_phdr(struct elf_phdr *phdr) 40931e31b8aSbellard { 41031e31b8aSbellard bswap32s(&phdr->p_type); /* Segment type */ 41192a31b1fSbellard bswaptls(&phdr->p_offset); /* Segment file offset */ 41292a31b1fSbellard bswaptls(&phdr->p_vaddr); /* Segment virtual address */ 41392a31b1fSbellard bswaptls(&phdr->p_paddr); /* Segment physical address */ 41492a31b1fSbellard bswaptls(&phdr->p_filesz); /* Segment size in file */ 41592a31b1fSbellard bswaptls(&phdr->p_memsz); /* Segment size in memory */ 41631e31b8aSbellard bswap32s(&phdr->p_flags); /* Segment flags */ 41792a31b1fSbellard bswaptls(&phdr->p_align); /* Segment alignment */ 41831e31b8aSbellard } 419689f936fSbellard 42092a31b1fSbellard static void bswap_shdr(struct elf_shdr *shdr) 421689f936fSbellard { 422689f936fSbellard bswap32s(&shdr->sh_name); 423689f936fSbellard bswap32s(&shdr->sh_type); 42492a31b1fSbellard bswaptls(&shdr->sh_flags); 42592a31b1fSbellard bswaptls(&shdr->sh_addr); 42692a31b1fSbellard bswaptls(&shdr->sh_offset); 42792a31b1fSbellard bswaptls(&shdr->sh_size); 428689f936fSbellard bswap32s(&shdr->sh_link); 429689f936fSbellard bswap32s(&shdr->sh_info); 43092a31b1fSbellard bswaptls(&shdr->sh_addralign); 43192a31b1fSbellard bswaptls(&shdr->sh_entsize); 432689f936fSbellard } 433689f936fSbellard 434689f936fSbellard static void bswap_sym(Elf32_Sym *sym) 435689f936fSbellard { 436689f936fSbellard bswap32s(&sym->st_name); 437689f936fSbellard bswap32s(&sym->st_value); 438689f936fSbellard bswap32s(&sym->st_size); 439689f936fSbellard bswap16s(&sym->st_shndx); 440689f936fSbellard } 44131e31b8aSbellard #endif 44231e31b8aSbellard 44331e31b8aSbellard /* 444e5fe0c52Spbrook * 'copy_elf_strings()' copies argument/envelope strings from user 44531e31b8aSbellard * memory to free pages in kernel mem. These are in a format ready 44631e31b8aSbellard * to be put directly into the top of new user memory. 44731e31b8aSbellard * 44831e31b8aSbellard */ 449e5fe0c52Spbrook static unsigned long copy_elf_strings(int argc,char ** argv, void **page, 45031e31b8aSbellard unsigned long p) 45131e31b8aSbellard { 45231e31b8aSbellard char *tmp, *tmp1, *pag = NULL; 45331e31b8aSbellard int len, offset = 0; 45431e31b8aSbellard 45531e31b8aSbellard if (!p) { 45631e31b8aSbellard return 0; /* bullet-proofing */ 45731e31b8aSbellard } 45831e31b8aSbellard while (argc-- > 0) { 459edf779ffSbellard tmp = argv[argc]; 460edf779ffSbellard if (!tmp) { 46131e31b8aSbellard fprintf(stderr, "VFS: argc is wrong"); 46231e31b8aSbellard exit(-1); 46331e31b8aSbellard } 464edf779ffSbellard tmp1 = tmp; 465edf779ffSbellard while (*tmp++); 46631e31b8aSbellard len = tmp - tmp1; 46731e31b8aSbellard if (p < len) { /* this shouldn't happen - 128kB */ 46831e31b8aSbellard return 0; 46931e31b8aSbellard } 47031e31b8aSbellard while (len) { 47131e31b8aSbellard --p; --tmp; --len; 47231e31b8aSbellard if (--offset < 0) { 47354936004Sbellard offset = p % TARGET_PAGE_SIZE; 47444a91caeSbellard pag = (char *)page[p/TARGET_PAGE_SIZE]; 47544a91caeSbellard if (!pag) { 47653a5960aSpbrook pag = (char *)malloc(TARGET_PAGE_SIZE); 47753a5960aSpbrook page[p/TARGET_PAGE_SIZE] = pag; 47844a91caeSbellard if (!pag) 47931e31b8aSbellard return 0; 48031e31b8aSbellard } 48131e31b8aSbellard } 48231e31b8aSbellard if (len == 0 || offset == 0) { 483edf779ffSbellard *(pag + offset) = *tmp; 48431e31b8aSbellard } 48531e31b8aSbellard else { 48631e31b8aSbellard int bytes_to_copy = (len > offset) ? offset : len; 48731e31b8aSbellard tmp -= bytes_to_copy; 48831e31b8aSbellard p -= bytes_to_copy; 48931e31b8aSbellard offset -= bytes_to_copy; 49031e31b8aSbellard len -= bytes_to_copy; 49131e31b8aSbellard memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1); 49231e31b8aSbellard } 49331e31b8aSbellard } 49431e31b8aSbellard } 49531e31b8aSbellard return p; 49631e31b8aSbellard } 49731e31b8aSbellard 49853a5960aSpbrook unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm, 49931e31b8aSbellard struct image_info * info) 50031e31b8aSbellard { 50153a5960aSpbrook target_ulong stack_base, size, error; 50231e31b8aSbellard int i; 50331e31b8aSbellard 50431e31b8aSbellard /* Create enough stack to hold everything. If we don't use 50531e31b8aSbellard * it for args, we'll use it for something else... 50631e31b8aSbellard */ 50709bfb054Sbellard size = x86_stack_size; 50854936004Sbellard if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) 50954936004Sbellard size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; 51054936004Sbellard error = target_mmap(0, 51183fb7adfSbellard size + qemu_host_page_size, 51231e31b8aSbellard PROT_READ | PROT_WRITE, 51309bfb054Sbellard MAP_PRIVATE | MAP_ANONYMOUS, 51409bfb054Sbellard -1, 0); 51509bfb054Sbellard if (error == -1) { 51631e31b8aSbellard perror("stk mmap"); 51731e31b8aSbellard exit(-1); 51831e31b8aSbellard } 51909bfb054Sbellard /* we reserve one extra page at the top of the stack as guard */ 52083fb7adfSbellard target_mprotect(error + size, qemu_host_page_size, PROT_NONE); 52131e31b8aSbellard 52254936004Sbellard stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; 52309bfb054Sbellard p += stack_base; 52409bfb054Sbellard 52531e31b8aSbellard for (i = 0 ; i < MAX_ARG_PAGES ; i++) { 52631e31b8aSbellard if (bprm->page[i]) { 52731e31b8aSbellard info->rss++; 52831e31b8aSbellard 52953a5960aSpbrook memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE); 53053a5960aSpbrook free(bprm->page[i]); 53131e31b8aSbellard } 53254936004Sbellard stack_base += TARGET_PAGE_SIZE; 53331e31b8aSbellard } 53431e31b8aSbellard return p; 53531e31b8aSbellard } 53631e31b8aSbellard 53731e31b8aSbellard static void set_brk(unsigned long start, unsigned long end) 53831e31b8aSbellard { 53931e31b8aSbellard /* page-align the start and end addresses... */ 54054936004Sbellard start = HOST_PAGE_ALIGN(start); 54154936004Sbellard end = HOST_PAGE_ALIGN(end); 54231e31b8aSbellard if (end <= start) 54331e31b8aSbellard return; 54454936004Sbellard if(target_mmap(start, end - start, 54531e31b8aSbellard PROT_READ | PROT_WRITE | PROT_EXEC, 54631e31b8aSbellard MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { 54731e31b8aSbellard perror("cannot mmap brk"); 54831e31b8aSbellard exit(-1); 54931e31b8aSbellard } 55031e31b8aSbellard } 55131e31b8aSbellard 55231e31b8aSbellard 553853d6f7aSbellard /* We need to explicitly zero any fractional pages after the data 554853d6f7aSbellard section (i.e. bss). This would contain the junk from the file that 555853d6f7aSbellard should not be in memory. */ 556*768a4a36Sths static void padzero(unsigned long elf_bss, unsigned long last_bss) 55731e31b8aSbellard { 55831e31b8aSbellard unsigned long nbyte; 55931e31b8aSbellard 560*768a4a36Sths if (elf_bss >= last_bss) 561*768a4a36Sths return; 562*768a4a36Sths 563853d6f7aSbellard /* XXX: this is really a hack : if the real host page size is 564853d6f7aSbellard smaller than the target page size, some pages after the end 565853d6f7aSbellard of the file may not be mapped. A better fix would be to 566853d6f7aSbellard patch target_mmap(), but it is more complicated as the file 567853d6f7aSbellard size must be known */ 56883fb7adfSbellard if (qemu_real_host_page_size < qemu_host_page_size) { 569853d6f7aSbellard unsigned long end_addr, end_addr1; 57083fb7adfSbellard end_addr1 = (elf_bss + qemu_real_host_page_size - 1) & 57183fb7adfSbellard ~(qemu_real_host_page_size - 1); 572853d6f7aSbellard end_addr = HOST_PAGE_ALIGN(elf_bss); 573853d6f7aSbellard if (end_addr1 < end_addr) { 574853d6f7aSbellard mmap((void *)end_addr1, end_addr - end_addr1, 575853d6f7aSbellard PROT_READ|PROT_WRITE|PROT_EXEC, 576853d6f7aSbellard MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 577853d6f7aSbellard } 578853d6f7aSbellard } 579853d6f7aSbellard 58083fb7adfSbellard nbyte = elf_bss & (qemu_host_page_size-1); 58131e31b8aSbellard if (nbyte) { 58283fb7adfSbellard nbyte = qemu_host_page_size - nbyte; 58331e31b8aSbellard do { 58453a5960aSpbrook tput8(elf_bss, 0); 58553a5960aSpbrook elf_bss++; 58631e31b8aSbellard } while (--nbyte); 58731e31b8aSbellard } 58831e31b8aSbellard } 58931e31b8aSbellard 59053a5960aSpbrook 59153a5960aSpbrook static unsigned long create_elf_tables(target_ulong p, int argc, int envc, 59231e31b8aSbellard struct elfhdr * exec, 59331e31b8aSbellard unsigned long load_addr, 59409bfb054Sbellard unsigned long load_bias, 59531e31b8aSbellard unsigned long interp_load_addr, int ibcs, 59631e31b8aSbellard struct image_info *info) 59731e31b8aSbellard { 59853a5960aSpbrook target_ulong sp; 59953a5960aSpbrook int size; 60053a5960aSpbrook target_ulong u_platform; 60115338fd7Sbellard const char *k_platform; 60253a5960aSpbrook const int n = sizeof(target_ulong); 60331e31b8aSbellard 60453a5960aSpbrook sp = p; 60553a5960aSpbrook u_platform = 0; 60615338fd7Sbellard k_platform = ELF_PLATFORM; 60715338fd7Sbellard if (k_platform) { 60815338fd7Sbellard size_t len = strlen(k_platform) + 1; 60953a5960aSpbrook sp -= (len + n - 1) & ~(n - 1); 61053a5960aSpbrook u_platform = sp; 61153a5960aSpbrook memcpy_to_target(sp, k_platform, len); 61215338fd7Sbellard } 61353a5960aSpbrook /* 61453a5960aSpbrook * Force 16 byte _final_ alignment here for generality. 61553a5960aSpbrook */ 61653a5960aSpbrook sp = sp &~ (target_ulong)15; 61753a5960aSpbrook size = (DLINFO_ITEMS + 1) * 2; 61815338fd7Sbellard if (k_platform) 61953a5960aSpbrook size += 2; 620f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS 62153a5960aSpbrook size += DLINFO_ARCH_ITEMS * 2; 622f5155289Sbellard #endif 62353a5960aSpbrook size += envc + argc + 2; 62453a5960aSpbrook size += (!ibcs ? 3 : 1); /* argc itself */ 62553a5960aSpbrook size *= n; 62653a5960aSpbrook if (size & 15) 62753a5960aSpbrook sp -= 16 - (size & 15); 628f5155289Sbellard 62953a5960aSpbrook #define NEW_AUX_ENT(id, val) do { \ 63053a5960aSpbrook sp -= n; tputl(sp, val); \ 63153a5960aSpbrook sp -= n; tputl(sp, id); \ 63253a5960aSpbrook } while(0) 6330bccf03dSbellard NEW_AUX_ENT (AT_NULL, 0); 634f5155289Sbellard 6350bccf03dSbellard /* There must be exactly DLINFO_ITEMS entries here. */ 6360bccf03dSbellard NEW_AUX_ENT(AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); 6370bccf03dSbellard NEW_AUX_ENT(AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); 6380bccf03dSbellard NEW_AUX_ENT(AT_PHNUM, (target_ulong)(exec->e_phnum)); 6390bccf03dSbellard NEW_AUX_ENT(AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE)); 6400bccf03dSbellard NEW_AUX_ENT(AT_BASE, (target_ulong)(interp_load_addr)); 6410bccf03dSbellard NEW_AUX_ENT(AT_FLAGS, (target_ulong)0); 6420bccf03dSbellard NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry); 6430bccf03dSbellard NEW_AUX_ENT(AT_UID, (target_ulong) getuid()); 6440bccf03dSbellard NEW_AUX_ENT(AT_EUID, (target_ulong) geteuid()); 6450bccf03dSbellard NEW_AUX_ENT(AT_GID, (target_ulong) getgid()); 6460bccf03dSbellard NEW_AUX_ENT(AT_EGID, (target_ulong) getegid()); 64715338fd7Sbellard NEW_AUX_ENT(AT_HWCAP, (target_ulong) ELF_HWCAP); 64815338fd7Sbellard if (k_platform) 64953a5960aSpbrook NEW_AUX_ENT(AT_PLATFORM, u_platform); 650f5155289Sbellard #ifdef ARCH_DLINFO 651f5155289Sbellard /* 652f5155289Sbellard * ARCH_DLINFO must come last so platform specific code can enforce 653f5155289Sbellard * special alignment requirements on the AUXV if necessary (eg. PPC). 654f5155289Sbellard */ 655f5155289Sbellard ARCH_DLINFO; 656f5155289Sbellard #endif 657f5155289Sbellard #undef NEW_AUX_ENT 658f5155289Sbellard 659e5fe0c52Spbrook sp = loader_build_argptr(envc, argc, sp, p, !ibcs); 66031e31b8aSbellard return sp; 66131e31b8aSbellard } 66231e31b8aSbellard 66331e31b8aSbellard 66431e31b8aSbellard static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, 66531e31b8aSbellard int interpreter_fd, 66631e31b8aSbellard unsigned long *interp_load_addr) 66731e31b8aSbellard { 66831e31b8aSbellard struct elf_phdr *elf_phdata = NULL; 66931e31b8aSbellard struct elf_phdr *eppnt; 67009bfb054Sbellard unsigned long load_addr = 0; 67131e31b8aSbellard int load_addr_set = 0; 67231e31b8aSbellard int retval; 67331e31b8aSbellard unsigned long last_bss, elf_bss; 67431e31b8aSbellard unsigned long error; 67531e31b8aSbellard int i; 67631e31b8aSbellard 67731e31b8aSbellard elf_bss = 0; 67831e31b8aSbellard last_bss = 0; 67931e31b8aSbellard error = 0; 68031e31b8aSbellard 681644c433cSbellard #ifdef BSWAP_NEEDED 682644c433cSbellard bswap_ehdr(interp_elf_ex); 683644c433cSbellard #endif 68431e31b8aSbellard /* First of all, some simple consistency checks */ 68531e31b8aSbellard if ((interp_elf_ex->e_type != ET_EXEC && 68631e31b8aSbellard interp_elf_ex->e_type != ET_DYN) || 68731e31b8aSbellard !elf_check_arch(interp_elf_ex->e_machine)) { 68831e31b8aSbellard return ~0UL; 68931e31b8aSbellard } 69031e31b8aSbellard 691644c433cSbellard 69231e31b8aSbellard /* Now read in all of the header information */ 69331e31b8aSbellard 69454936004Sbellard if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) 69531e31b8aSbellard return ~0UL; 69631e31b8aSbellard 69731e31b8aSbellard elf_phdata = (struct elf_phdr *) 69831e31b8aSbellard malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); 69931e31b8aSbellard 70031e31b8aSbellard if (!elf_phdata) 70131e31b8aSbellard return ~0UL; 70231e31b8aSbellard 70331e31b8aSbellard /* 70431e31b8aSbellard * If the size of this structure has changed, then punt, since 70531e31b8aSbellard * we will be doing the wrong thing. 70631e31b8aSbellard */ 70709bfb054Sbellard if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { 70831e31b8aSbellard free(elf_phdata); 70931e31b8aSbellard return ~0UL; 71031e31b8aSbellard } 71131e31b8aSbellard 71231e31b8aSbellard retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); 71331e31b8aSbellard if(retval >= 0) { 71431e31b8aSbellard retval = read(interpreter_fd, 71531e31b8aSbellard (char *) elf_phdata, 71631e31b8aSbellard sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); 71731e31b8aSbellard } 71831e31b8aSbellard if (retval < 0) { 71931e31b8aSbellard perror("load_elf_interp"); 72031e31b8aSbellard exit(-1); 72131e31b8aSbellard free (elf_phdata); 72231e31b8aSbellard return retval; 72331e31b8aSbellard } 72431e31b8aSbellard #ifdef BSWAP_NEEDED 72531e31b8aSbellard eppnt = elf_phdata; 72631e31b8aSbellard for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) { 72731e31b8aSbellard bswap_phdr(eppnt); 72831e31b8aSbellard } 72931e31b8aSbellard #endif 73009bfb054Sbellard 73109bfb054Sbellard if (interp_elf_ex->e_type == ET_DYN) { 73209bfb054Sbellard /* in order to avoid harcoding the interpreter load 73309bfb054Sbellard address in qemu, we allocate a big enough memory zone */ 73454936004Sbellard error = target_mmap(0, INTERP_MAP_SIZE, 73509bfb054Sbellard PROT_NONE, MAP_PRIVATE | MAP_ANON, 73609bfb054Sbellard -1, 0); 73709bfb054Sbellard if (error == -1) { 73809bfb054Sbellard perror("mmap"); 73909bfb054Sbellard exit(-1); 74009bfb054Sbellard } 74109bfb054Sbellard load_addr = error; 74209bfb054Sbellard load_addr_set = 1; 74309bfb054Sbellard } 74409bfb054Sbellard 74531e31b8aSbellard eppnt = elf_phdata; 74631e31b8aSbellard for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) 74731e31b8aSbellard if (eppnt->p_type == PT_LOAD) { 74831e31b8aSbellard int elf_type = MAP_PRIVATE | MAP_DENYWRITE; 74931e31b8aSbellard int elf_prot = 0; 75031e31b8aSbellard unsigned long vaddr = 0; 75131e31b8aSbellard unsigned long k; 75231e31b8aSbellard 75331e31b8aSbellard if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; 75431e31b8aSbellard if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; 75531e31b8aSbellard if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; 75631e31b8aSbellard if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { 75731e31b8aSbellard elf_type |= MAP_FIXED; 75831e31b8aSbellard vaddr = eppnt->p_vaddr; 75931e31b8aSbellard } 76054936004Sbellard error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr), 76154936004Sbellard eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr), 76231e31b8aSbellard elf_prot, 76331e31b8aSbellard elf_type, 76431e31b8aSbellard interpreter_fd, 76554936004Sbellard eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); 76631e31b8aSbellard 767e89f07d3Spbrook if (error == -1) { 76831e31b8aSbellard /* Real error */ 76931e31b8aSbellard close(interpreter_fd); 77031e31b8aSbellard free(elf_phdata); 77131e31b8aSbellard return ~0UL; 77231e31b8aSbellard } 77331e31b8aSbellard 77431e31b8aSbellard if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { 77531e31b8aSbellard load_addr = error; 77631e31b8aSbellard load_addr_set = 1; 77731e31b8aSbellard } 77831e31b8aSbellard 77931e31b8aSbellard /* 78031e31b8aSbellard * Find the end of the file mapping for this phdr, and keep 78131e31b8aSbellard * track of the largest address we see for this. 78231e31b8aSbellard */ 78331e31b8aSbellard k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; 78431e31b8aSbellard if (k > elf_bss) elf_bss = k; 78531e31b8aSbellard 78631e31b8aSbellard /* 78731e31b8aSbellard * Do the same thing for the memory mapping - between 78831e31b8aSbellard * elf_bss and last_bss is the bss section. 78931e31b8aSbellard */ 79031e31b8aSbellard k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; 79131e31b8aSbellard if (k > last_bss) last_bss = k; 79231e31b8aSbellard } 79331e31b8aSbellard 79431e31b8aSbellard /* Now use mmap to map the library into memory. */ 79531e31b8aSbellard 79631e31b8aSbellard close(interpreter_fd); 79731e31b8aSbellard 79831e31b8aSbellard /* 79931e31b8aSbellard * Now fill out the bss section. First pad the last page up 80031e31b8aSbellard * to the page boundary, and then perform a mmap to make sure 80131e31b8aSbellard * that there are zeromapped pages up to and including the last 80231e31b8aSbellard * bss page. 80331e31b8aSbellard */ 804*768a4a36Sths padzero(elf_bss, last_bss); 80583fb7adfSbellard elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */ 80631e31b8aSbellard 80731e31b8aSbellard /* Map the last of the bss segment */ 80831e31b8aSbellard if (last_bss > elf_bss) { 80954936004Sbellard target_mmap(elf_bss, last_bss-elf_bss, 81031e31b8aSbellard PROT_READ|PROT_WRITE|PROT_EXEC, 81131e31b8aSbellard MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 81231e31b8aSbellard } 81331e31b8aSbellard free(elf_phdata); 81431e31b8aSbellard 81531e31b8aSbellard *interp_load_addr = load_addr; 81631e31b8aSbellard return ((unsigned long) interp_elf_ex->e_entry) + load_addr; 81731e31b8aSbellard } 81831e31b8aSbellard 819689f936fSbellard /* Best attempt to load symbols from this ELF object. */ 820689f936fSbellard static void load_symbols(struct elfhdr *hdr, int fd) 821689f936fSbellard { 822689f936fSbellard unsigned int i; 823689f936fSbellard struct elf_shdr sechdr, symtab, strtab; 824689f936fSbellard char *strings; 825e80cfcfcSbellard struct syminfo *s; 82631e31b8aSbellard 827689f936fSbellard lseek(fd, hdr->e_shoff, SEEK_SET); 828689f936fSbellard for (i = 0; i < hdr->e_shnum; i++) { 829689f936fSbellard if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) 830689f936fSbellard return; 831689f936fSbellard #ifdef BSWAP_NEEDED 832689f936fSbellard bswap_shdr(&sechdr); 833689f936fSbellard #endif 834689f936fSbellard if (sechdr.sh_type == SHT_SYMTAB) { 835689f936fSbellard symtab = sechdr; 836689f936fSbellard lseek(fd, hdr->e_shoff 837689f936fSbellard + sizeof(sechdr) * sechdr.sh_link, SEEK_SET); 838689f936fSbellard if (read(fd, &strtab, sizeof(strtab)) 839689f936fSbellard != sizeof(strtab)) 840689f936fSbellard return; 841689f936fSbellard #ifdef BSWAP_NEEDED 842689f936fSbellard bswap_shdr(&strtab); 843689f936fSbellard #endif 844689f936fSbellard goto found; 845689f936fSbellard } 846689f936fSbellard } 847689f936fSbellard return; /* Shouldn't happen... */ 848689f936fSbellard 849689f936fSbellard found: 850689f936fSbellard /* Now know where the strtab and symtab are. Snarf them. */ 851e80cfcfcSbellard s = malloc(sizeof(*s)); 852e80cfcfcSbellard s->disas_symtab = malloc(symtab.sh_size); 853e80cfcfcSbellard s->disas_strtab = strings = malloc(strtab.sh_size); 854e80cfcfcSbellard if (!s->disas_symtab || !s->disas_strtab) 855689f936fSbellard return; 856689f936fSbellard 857689f936fSbellard lseek(fd, symtab.sh_offset, SEEK_SET); 858e80cfcfcSbellard if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size) 859689f936fSbellard return; 860689f936fSbellard 861689f936fSbellard #ifdef BSWAP_NEEDED 862689f936fSbellard for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) 863e80cfcfcSbellard bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i); 864689f936fSbellard #endif 865689f936fSbellard 866689f936fSbellard lseek(fd, strtab.sh_offset, SEEK_SET); 867689f936fSbellard if (read(fd, strings, strtab.sh_size) != strtab.sh_size) 868689f936fSbellard return; 869e80cfcfcSbellard s->disas_num_syms = symtab.sh_size / sizeof(struct elf_sym); 870e80cfcfcSbellard s->next = syminfos; 871e80cfcfcSbellard syminfos = s; 872689f936fSbellard } 87331e31b8aSbellard 874e5fe0c52Spbrook int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, 87531e31b8aSbellard struct image_info * info) 87631e31b8aSbellard { 87731e31b8aSbellard struct elfhdr elf_ex; 87831e31b8aSbellard struct elfhdr interp_elf_ex; 87931e31b8aSbellard struct exec interp_ex; 88031e31b8aSbellard int interpreter_fd = -1; /* avoid warning */ 88109bfb054Sbellard unsigned long load_addr, load_bias; 88231e31b8aSbellard int load_addr_set = 0; 88331e31b8aSbellard unsigned int interpreter_type = INTERPRETER_NONE; 88431e31b8aSbellard unsigned char ibcs2_interpreter; 88531e31b8aSbellard int i; 88654936004Sbellard unsigned long mapped_addr; 88731e31b8aSbellard struct elf_phdr * elf_ppnt; 88831e31b8aSbellard struct elf_phdr *elf_phdata; 88931e31b8aSbellard unsigned long elf_bss, k, elf_brk; 89031e31b8aSbellard int retval; 89131e31b8aSbellard char * elf_interpreter; 89231e31b8aSbellard unsigned long elf_entry, interp_load_addr = 0; 89331e31b8aSbellard int status; 89431e31b8aSbellard unsigned long start_code, end_code, end_data; 89531e31b8aSbellard unsigned long elf_stack; 89631e31b8aSbellard char passed_fileno[6]; 89731e31b8aSbellard 89831e31b8aSbellard ibcs2_interpreter = 0; 89931e31b8aSbellard status = 0; 90031e31b8aSbellard load_addr = 0; 90109bfb054Sbellard load_bias = 0; 90231e31b8aSbellard elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ 90331e31b8aSbellard #ifdef BSWAP_NEEDED 90431e31b8aSbellard bswap_ehdr(&elf_ex); 90531e31b8aSbellard #endif 90631e31b8aSbellard 90731e31b8aSbellard /* First of all, some simple consistency checks */ 90831e31b8aSbellard if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || 90931e31b8aSbellard (! elf_check_arch(elf_ex.e_machine))) { 91031e31b8aSbellard return -ENOEXEC; 91131e31b8aSbellard } 91231e31b8aSbellard 913e5fe0c52Spbrook bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p); 914e5fe0c52Spbrook bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p); 915e5fe0c52Spbrook bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p); 916e5fe0c52Spbrook if (!bprm->p) { 917e5fe0c52Spbrook retval = -E2BIG; 918e5fe0c52Spbrook } 919e5fe0c52Spbrook 92031e31b8aSbellard /* Now read in all of the header information */ 92131e31b8aSbellard elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum); 92231e31b8aSbellard if (elf_phdata == NULL) { 92331e31b8aSbellard return -ENOMEM; 92431e31b8aSbellard } 92531e31b8aSbellard 92631e31b8aSbellard retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); 92731e31b8aSbellard if(retval > 0) { 92831e31b8aSbellard retval = read(bprm->fd, (char *) elf_phdata, 92931e31b8aSbellard elf_ex.e_phentsize * elf_ex.e_phnum); 93031e31b8aSbellard } 93131e31b8aSbellard 93231e31b8aSbellard if (retval < 0) { 93331e31b8aSbellard perror("load_elf_binary"); 93431e31b8aSbellard exit(-1); 93531e31b8aSbellard free (elf_phdata); 93631e31b8aSbellard return -errno; 93731e31b8aSbellard } 93831e31b8aSbellard 939b17780d5Sbellard #ifdef BSWAP_NEEDED 940b17780d5Sbellard elf_ppnt = elf_phdata; 941b17780d5Sbellard for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) { 942b17780d5Sbellard bswap_phdr(elf_ppnt); 943b17780d5Sbellard } 944b17780d5Sbellard #endif 94531e31b8aSbellard elf_ppnt = elf_phdata; 94631e31b8aSbellard 94731e31b8aSbellard elf_bss = 0; 94831e31b8aSbellard elf_brk = 0; 94931e31b8aSbellard 95031e31b8aSbellard 95131e31b8aSbellard elf_stack = ~0UL; 95231e31b8aSbellard elf_interpreter = NULL; 95331e31b8aSbellard start_code = ~0UL; 95431e31b8aSbellard end_code = 0; 95531e31b8aSbellard end_data = 0; 95631e31b8aSbellard 95731e31b8aSbellard for(i=0;i < elf_ex.e_phnum; i++) { 95831e31b8aSbellard if (elf_ppnt->p_type == PT_INTERP) { 95931e31b8aSbellard if ( elf_interpreter != NULL ) 96031e31b8aSbellard { 96131e31b8aSbellard free (elf_phdata); 96231e31b8aSbellard free(elf_interpreter); 96331e31b8aSbellard close(bprm->fd); 96431e31b8aSbellard return -EINVAL; 96531e31b8aSbellard } 96631e31b8aSbellard 96731e31b8aSbellard /* This is the program interpreter used for 96831e31b8aSbellard * shared libraries - for now assume that this 96931e31b8aSbellard * is an a.out format binary 97031e31b8aSbellard */ 97131e31b8aSbellard 97232ce6337Sbellard elf_interpreter = (char *)malloc(elf_ppnt->p_filesz); 97331e31b8aSbellard 97431e31b8aSbellard if (elf_interpreter == NULL) { 97531e31b8aSbellard free (elf_phdata); 97631e31b8aSbellard close(bprm->fd); 97731e31b8aSbellard return -ENOMEM; 97831e31b8aSbellard } 97931e31b8aSbellard 98031e31b8aSbellard retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); 98131e31b8aSbellard if(retval >= 0) { 98232ce6337Sbellard retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz); 98331e31b8aSbellard } 98431e31b8aSbellard if(retval < 0) { 98531e31b8aSbellard perror("load_elf_binary2"); 98631e31b8aSbellard exit(-1); 98731e31b8aSbellard } 98831e31b8aSbellard 98931e31b8aSbellard /* If the program interpreter is one of these two, 99031e31b8aSbellard then assume an iBCS2 image. Otherwise assume 99131e31b8aSbellard a native linux image. */ 99231e31b8aSbellard 99331e31b8aSbellard /* JRP - Need to add X86 lib dir stuff here... */ 99431e31b8aSbellard 99531e31b8aSbellard if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || 99631e31b8aSbellard strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) { 99731e31b8aSbellard ibcs2_interpreter = 1; 99831e31b8aSbellard } 99931e31b8aSbellard 100031e31b8aSbellard #if 0 100131e31b8aSbellard printf("Using ELF interpreter %s\n", elf_interpreter); 100231e31b8aSbellard #endif 100331e31b8aSbellard if (retval >= 0) { 100432ce6337Sbellard retval = open(path(elf_interpreter), O_RDONLY); 100531e31b8aSbellard if(retval >= 0) { 100631e31b8aSbellard interpreter_fd = retval; 100731e31b8aSbellard } 100831e31b8aSbellard else { 100931e31b8aSbellard perror(elf_interpreter); 101031e31b8aSbellard exit(-1); 101131e31b8aSbellard /* retval = -errno; */ 101231e31b8aSbellard } 101331e31b8aSbellard } 101431e31b8aSbellard 101531e31b8aSbellard if (retval >= 0) { 101631e31b8aSbellard retval = lseek(interpreter_fd, 0, SEEK_SET); 101731e31b8aSbellard if(retval >= 0) { 101831e31b8aSbellard retval = read(interpreter_fd,bprm->buf,128); 101931e31b8aSbellard } 102031e31b8aSbellard } 102131e31b8aSbellard if (retval >= 0) { 102231e31b8aSbellard interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */ 102331e31b8aSbellard interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */ 102431e31b8aSbellard } 102531e31b8aSbellard if (retval < 0) { 102631e31b8aSbellard perror("load_elf_binary3"); 102731e31b8aSbellard exit(-1); 102831e31b8aSbellard free (elf_phdata); 102931e31b8aSbellard free(elf_interpreter); 103031e31b8aSbellard close(bprm->fd); 103131e31b8aSbellard return retval; 103231e31b8aSbellard } 103331e31b8aSbellard } 103431e31b8aSbellard elf_ppnt++; 103531e31b8aSbellard } 103631e31b8aSbellard 103731e31b8aSbellard /* Some simple consistency checks for the interpreter */ 103831e31b8aSbellard if (elf_interpreter){ 103931e31b8aSbellard interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; 104031e31b8aSbellard 104131e31b8aSbellard /* Now figure out which format our binary is */ 104231e31b8aSbellard if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && 104331e31b8aSbellard (N_MAGIC(interp_ex) != QMAGIC)) { 104431e31b8aSbellard interpreter_type = INTERPRETER_ELF; 104531e31b8aSbellard } 104631e31b8aSbellard 104731e31b8aSbellard if (interp_elf_ex.e_ident[0] != 0x7f || 104831e31b8aSbellard strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) { 104931e31b8aSbellard interpreter_type &= ~INTERPRETER_ELF; 105031e31b8aSbellard } 105131e31b8aSbellard 105231e31b8aSbellard if (!interpreter_type) { 105331e31b8aSbellard free(elf_interpreter); 105431e31b8aSbellard free(elf_phdata); 105531e31b8aSbellard close(bprm->fd); 105631e31b8aSbellard return -ELIBBAD; 105731e31b8aSbellard } 105831e31b8aSbellard } 105931e31b8aSbellard 106031e31b8aSbellard /* OK, we are done with that, now set up the arg stuff, 106131e31b8aSbellard and then start this sucker up */ 106231e31b8aSbellard 1063e5fe0c52Spbrook { 106431e31b8aSbellard char * passed_p; 106531e31b8aSbellard 106631e31b8aSbellard if (interpreter_type == INTERPRETER_AOUT) { 1067eba2af63Sbellard snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd); 106831e31b8aSbellard passed_p = passed_fileno; 106931e31b8aSbellard 107031e31b8aSbellard if (elf_interpreter) { 1071e5fe0c52Spbrook bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p); 107231e31b8aSbellard bprm->argc++; 107331e31b8aSbellard } 107431e31b8aSbellard } 107531e31b8aSbellard if (!bprm->p) { 107631e31b8aSbellard if (elf_interpreter) { 107731e31b8aSbellard free(elf_interpreter); 107831e31b8aSbellard } 107931e31b8aSbellard free (elf_phdata); 108031e31b8aSbellard close(bprm->fd); 108131e31b8aSbellard return -E2BIG; 108231e31b8aSbellard } 108331e31b8aSbellard } 108431e31b8aSbellard 108531e31b8aSbellard /* OK, This is the point of no return */ 108631e31b8aSbellard info->end_data = 0; 108731e31b8aSbellard info->end_code = 0; 108831e31b8aSbellard info->start_mmap = (unsigned long)ELF_START_MMAP; 108931e31b8aSbellard info->mmap = 0; 109031e31b8aSbellard elf_entry = (unsigned long) elf_ex.e_entry; 109131e31b8aSbellard 109231e31b8aSbellard /* Do this so that we can load the interpreter, if need be. We will 109331e31b8aSbellard change some of these later */ 109431e31b8aSbellard info->rss = 0; 109531e31b8aSbellard bprm->p = setup_arg_pages(bprm->p, bprm, info); 109631e31b8aSbellard info->start_stack = bprm->p; 109731e31b8aSbellard 109831e31b8aSbellard /* Now we do a little grungy work by mmaping the ELF image into 109931e31b8aSbellard * the correct location in memory. At this point, we assume that 110031e31b8aSbellard * the image should be loaded at fixed address, not at a variable 110131e31b8aSbellard * address. 110231e31b8aSbellard */ 110331e31b8aSbellard 110431e31b8aSbellard for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { 110531e31b8aSbellard int elf_prot = 0; 110609bfb054Sbellard int elf_flags = 0; 110709bfb054Sbellard unsigned long error; 110809bfb054Sbellard 110909bfb054Sbellard if (elf_ppnt->p_type != PT_LOAD) 111009bfb054Sbellard continue; 111109bfb054Sbellard 111231e31b8aSbellard if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; 111331e31b8aSbellard if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; 111431e31b8aSbellard if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; 111509bfb054Sbellard elf_flags = MAP_PRIVATE | MAP_DENYWRITE; 111609bfb054Sbellard if (elf_ex.e_type == ET_EXEC || load_addr_set) { 111709bfb054Sbellard elf_flags |= MAP_FIXED; 111809bfb054Sbellard } else if (elf_ex.e_type == ET_DYN) { 111909bfb054Sbellard /* Try and get dynamic programs out of the way of the default mmap 112009bfb054Sbellard base, as well as whatever program they might try to exec. This 112109bfb054Sbellard is because the brk will follow the loader, and is not movable. */ 112209bfb054Sbellard /* NOTE: for qemu, we do a big mmap to get enough space 112309bfb054Sbellard without harcoding any address */ 112454936004Sbellard error = target_mmap(0, ET_DYN_MAP_SIZE, 112509bfb054Sbellard PROT_NONE, MAP_PRIVATE | MAP_ANON, 112609bfb054Sbellard -1, 0); 112709bfb054Sbellard if (error == -1) { 112809bfb054Sbellard perror("mmap"); 112909bfb054Sbellard exit(-1); 113009bfb054Sbellard } 113154936004Sbellard load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr); 113209bfb054Sbellard } 113331e31b8aSbellard 113454936004Sbellard error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), 113531e31b8aSbellard (elf_ppnt->p_filesz + 113654936004Sbellard TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), 113731e31b8aSbellard elf_prot, 113831e31b8aSbellard (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), 113931e31b8aSbellard bprm->fd, 114031e31b8aSbellard (elf_ppnt->p_offset - 114154936004Sbellard TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); 114209bfb054Sbellard if (error == -1) { 114331e31b8aSbellard perror("mmap"); 114431e31b8aSbellard exit(-1); 114531e31b8aSbellard } 114631e31b8aSbellard 114731e31b8aSbellard #ifdef LOW_ELF_STACK 114854936004Sbellard if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) 114954936004Sbellard elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr); 115031e31b8aSbellard #endif 115131e31b8aSbellard 115231e31b8aSbellard if (!load_addr_set) { 115331e31b8aSbellard load_addr_set = 1; 115409bfb054Sbellard load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; 115509bfb054Sbellard if (elf_ex.e_type == ET_DYN) { 115609bfb054Sbellard load_bias += error - 115754936004Sbellard TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); 115809bfb054Sbellard load_addr += load_bias; 115909bfb054Sbellard } 116031e31b8aSbellard } 116131e31b8aSbellard k = elf_ppnt->p_vaddr; 116209bfb054Sbellard if (k < start_code) 116309bfb054Sbellard start_code = k; 116431e31b8aSbellard k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; 116509bfb054Sbellard if (k > elf_bss) 116609bfb054Sbellard elf_bss = k; 116731e31b8aSbellard if ((elf_ppnt->p_flags & PF_X) && end_code < k) 116831e31b8aSbellard end_code = k; 116909bfb054Sbellard if (end_data < k) 117009bfb054Sbellard end_data = k; 117131e31b8aSbellard k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; 117231e31b8aSbellard if (k > elf_brk) elf_brk = k; 117331e31b8aSbellard } 117409bfb054Sbellard 117509bfb054Sbellard elf_entry += load_bias; 117609bfb054Sbellard elf_bss += load_bias; 117709bfb054Sbellard elf_brk += load_bias; 117809bfb054Sbellard start_code += load_bias; 117909bfb054Sbellard end_code += load_bias; 118009bfb054Sbellard // start_data += load_bias; 118109bfb054Sbellard end_data += load_bias; 118231e31b8aSbellard 118331e31b8aSbellard if (elf_interpreter) { 118431e31b8aSbellard if (interpreter_type & 1) { 118531e31b8aSbellard elf_entry = load_aout_interp(&interp_ex, interpreter_fd); 118631e31b8aSbellard } 118731e31b8aSbellard else if (interpreter_type & 2) { 118831e31b8aSbellard elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, 118931e31b8aSbellard &interp_load_addr); 119031e31b8aSbellard } 119131e31b8aSbellard 119231e31b8aSbellard close(interpreter_fd); 119331e31b8aSbellard free(elf_interpreter); 119431e31b8aSbellard 119531e31b8aSbellard if (elf_entry == ~0UL) { 119631e31b8aSbellard printf("Unable to load interpreter\n"); 119731e31b8aSbellard free(elf_phdata); 119831e31b8aSbellard exit(-1); 119931e31b8aSbellard return 0; 120031e31b8aSbellard } 120131e31b8aSbellard } 120231e31b8aSbellard 120331e31b8aSbellard free(elf_phdata); 120431e31b8aSbellard 1205689f936fSbellard if (loglevel) 1206689f936fSbellard load_symbols(&elf_ex, bprm->fd); 1207689f936fSbellard 120831e31b8aSbellard if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd); 120931e31b8aSbellard info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX); 121031e31b8aSbellard 121131e31b8aSbellard #ifdef LOW_ELF_STACK 121231e31b8aSbellard info->start_stack = bprm->p = elf_stack - 4; 121331e31b8aSbellard #endif 121453a5960aSpbrook bprm->p = create_elf_tables(bprm->p, 121531e31b8aSbellard bprm->argc, 121631e31b8aSbellard bprm->envc, 1217a1516e92Sbellard &elf_ex, 121809bfb054Sbellard load_addr, load_bias, 121931e31b8aSbellard interp_load_addr, 122031e31b8aSbellard (interpreter_type == INTERPRETER_AOUT ? 0 : 1), 122131e31b8aSbellard info); 122231e31b8aSbellard info->start_brk = info->brk = elf_brk; 122331e31b8aSbellard info->end_code = end_code; 122431e31b8aSbellard info->start_code = start_code; 1225e5fe0c52Spbrook info->start_data = end_code; 122631e31b8aSbellard info->end_data = end_data; 122731e31b8aSbellard info->start_stack = bprm->p; 122831e31b8aSbellard 122931e31b8aSbellard /* Calling set_brk effectively mmaps the pages that we need for the bss and break 123031e31b8aSbellard sections */ 123131e31b8aSbellard set_brk(elf_bss, elf_brk); 123231e31b8aSbellard 1233*768a4a36Sths padzero(elf_bss, elf_brk); 123431e31b8aSbellard 123531e31b8aSbellard #if 0 123631e31b8aSbellard printf("(start_brk) %x\n" , info->start_brk); 123731e31b8aSbellard printf("(end_code) %x\n" , info->end_code); 123831e31b8aSbellard printf("(start_code) %x\n" , info->start_code); 123931e31b8aSbellard printf("(end_data) %x\n" , info->end_data); 124031e31b8aSbellard printf("(start_stack) %x\n" , info->start_stack); 124131e31b8aSbellard printf("(brk) %x\n" , info->brk); 124231e31b8aSbellard #endif 124331e31b8aSbellard 124431e31b8aSbellard if ( info->personality == PER_SVR4 ) 124531e31b8aSbellard { 124631e31b8aSbellard /* Why this, you ask??? Well SVr4 maps page 0 as read-only, 124731e31b8aSbellard and some applications "depend" upon this behavior. 124831e31b8aSbellard Since we do not have the power to recompile these, we 124931e31b8aSbellard emulate the SVr4 behavior. Sigh. */ 125083fb7adfSbellard mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC, 125131e31b8aSbellard MAP_FIXED | MAP_PRIVATE, -1, 0); 125231e31b8aSbellard } 125331e31b8aSbellard 125431e31b8aSbellard info->entry = elf_entry; 125531e31b8aSbellard 125631e31b8aSbellard return 0; 125731e31b8aSbellard } 125831e31b8aSbellard 125931e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd) 126031e31b8aSbellard { 126131e31b8aSbellard printf("a.out interpreter not yet supported\n"); 126231e31b8aSbellard return(0); 126331e31b8aSbellard } 126431e31b8aSbellard 1265e5fe0c52Spbrook void do_init_thread(struct target_pt_regs *regs, struct image_info *infop) 1266e5fe0c52Spbrook { 1267e5fe0c52Spbrook init_thread(regs, infop); 1268e5fe0c52Spbrook } 1269