📄 elfload.c.svn-base
字号:
/* This is the Linux kernel elf-loading code, ported into user space */#include <stdio.h>#include <sys/types.h>#include <fcntl.h>#include <errno.h>#include <unistd.h>#include <sys/mman.h>#include <stdlib.h>#include <string.h>#include "qemu.h"#include "disas.h"/* from personality.h *//* * Flags for bug emulation. * * These occupy the top three bytes. */enum { ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization of VA space */ FDPIC_FUNCPTRS = 0x0080000, /* userspace function ptrs point to descriptors * (signal handling) */ MMAP_PAGE_ZERO = 0x0100000, ADDR_COMPAT_LAYOUT = 0x0200000, READ_IMPLIES_EXEC = 0x0400000, ADDR_LIMIT_32BIT = 0x0800000, SHORT_INODE = 0x1000000, WHOLE_SECONDS = 0x2000000, STICKY_TIMEOUTS = 0x4000000, ADDR_LIMIT_3GB = 0x8000000,};/* * Personality types. * * These go in the low byte. Avoid using the top bit, it will * conflict with error returns. */enum { PER_LINUX = 0x0000, PER_LINUX_32BIT = 0x0000 | ADDR_LIMIT_32BIT, PER_LINUX_FDPIC = 0x0000 | FDPIC_FUNCPTRS, PER_SVR4 = 0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, PER_SVR3 = 0x0002 | STICKY_TIMEOUTS | SHORT_INODE, PER_SCOSVR3 = 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE, PER_OSR5 = 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS, PER_WYSEV386 = 0x0004 | STICKY_TIMEOUTS | SHORT_INODE, PER_ISCR4 = 0x0005 | STICKY_TIMEOUTS, PER_BSD = 0x0006, PER_SUNOS = 0x0006 | STICKY_TIMEOUTS, PER_XENIX = 0x0007 | STICKY_TIMEOUTS | SHORT_INODE, PER_LINUX32 = 0x0008, PER_LINUX32_3GB = 0x0008 | ADDR_LIMIT_3GB, PER_IRIX32 = 0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */ PER_IRIXN32 = 0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */ PER_IRIX64 = 0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */ PER_RISCOS = 0x000c, PER_SOLARIS = 0x000d | STICKY_TIMEOUTS, PER_UW7 = 0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, PER_OSF4 = 0x000f, /* OSF/1 v4 */ PER_HPUX = 0x0010, PER_MASK = 0x00ff,};/* * Return the base personality without flags. */#define personality(pers) (pers & PER_MASK)/* this flag is uneffective under linux too, should be deleted */#ifndef MAP_DENYWRITE#define MAP_DENYWRITE 0#endif/* should probably go in elf.h */#ifndef ELIBBAD#define ELIBBAD 80#endif#ifdef TARGET_I386#define ELF_PLATFORM get_elf_platform()static const char *get_elf_platform(void){ static char elf_platform[] = "i386"; int family = (global_env->cpuid_version >> 8) & 0xff; if (family > 6) family = 6; if (family >= 3) elf_platform[1] = '0' + family; return elf_platform;}#define ELF_HWCAP get_elf_hwcap()static uint32_t get_elf_hwcap(void){ return global_env->cpuid_features;}#ifdef TARGET_X86_64#define ELF_START_MMAP 0x2aaaaab000ULL#define elf_check_arch(x) ( ((x) == ELF_ARCH) )#define ELF_CLASS ELFCLASS64#define ELF_DATA ELFDATA2LSB#define ELF_ARCH EM_X86_64static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop){ regs->rax = 0; regs->rsp = infop->start_stack; regs->rip = infop->entry;}#else#define ELF_START_MMAP 0x80000000/* * This is used to ensure we don't load something for the wrong architecture. */#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )/* * These are used to set parameters in the core dumps. */#define ELF_CLASS ELFCLASS32#define ELF_DATA ELFDATA2LSB#define ELF_ARCH EM_386static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop){ regs->esp = infop->start_stack; regs->eip = infop->entry; /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program starts %edx contains a pointer to a function which might be registered using `atexit'. This provides a mean for the dynamic linker to call DT_FINI functions for shared libraries that have been loaded before the code runs. A value of 0 tells we have no such handler. */ regs->edx = 0;}#endif#define USE_ELF_CORE_DUMP#define ELF_EXEC_PAGESIZE 4096#endif#ifdef TARGET_ARM#define ELF_START_MMAP 0x80000000#define elf_check_arch(x) ( (x) == EM_ARM )#define ELF_CLASS ELFCLASS32#ifdef TARGET_WORDS_BIGENDIAN#define ELF_DATA ELFDATA2MSB#else#define ELF_DATA ELFDATA2LSB#endif#define ELF_ARCH EM_ARMstatic inline void init_thread(struct target_pt_regs *regs, struct image_info *infop){ abi_long stack = infop->start_stack; memset(regs, 0, sizeof(*regs)); regs->ARM_cpsr = 0x10; if (infop->entry & 1) regs->ARM_cpsr |= CPSR_T; regs->ARM_pc = infop->entry & 0xfffffffe; regs->ARM_sp = infop->start_stack; /* FIXME - what to for failure of get_user()? */ get_user_ual(regs->ARM_r2, stack + 8); /* envp */ get_user_ual(regs->ARM_r1, stack + 4); /* envp */ /* XXX: it seems that r0 is zeroed after ! */ regs->ARM_r0 = 0; /* For uClinux PIC binaries. */ /* XXX: Linux does this only on ARM with no MMU (do we care ?) */ regs->ARM_r10 = infop->start_data;}#define USE_ELF_CORE_DUMP#define ELF_EXEC_PAGESIZE 4096enum{ ARM_HWCAP_ARM_SWP = 1 << 0, ARM_HWCAP_ARM_HALF = 1 << 1, ARM_HWCAP_ARM_THUMB = 1 << 2, ARM_HWCAP_ARM_26BIT = 1 << 3, ARM_HWCAP_ARM_FAST_MULT = 1 << 4, ARM_HWCAP_ARM_FPA = 1 << 5, ARM_HWCAP_ARM_VFP = 1 << 6, ARM_HWCAP_ARM_EDSP = 1 << 7,};#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF \ | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT \ | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP)#endif#ifdef TARGET_SPARC#ifdef TARGET_SPARC64#define ELF_START_MMAP 0x80000000#ifndef TARGET_ABI32#define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )#else#define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )#endif#define ELF_CLASS ELFCLASS64#define ELF_DATA ELFDATA2MSB#define ELF_ARCH EM_SPARCV9#define STACK_BIAS 2047static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop){#ifndef TARGET_ABI32 regs->tstate = 0;#endif regs->pc = infop->entry; regs->npc = regs->pc + 4; regs->y = 0;#ifdef TARGET_ABI32 regs->u_regs[14] = infop->start_stack - 16 * 4;#else if (personality(infop->personality) == PER_LINUX32) regs->u_regs[14] = infop->start_stack - 16 * 4; else regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;#endif}#else#define ELF_START_MMAP 0x80000000#define elf_check_arch(x) ( (x) == EM_SPARC )#define ELF_CLASS ELFCLASS32#define ELF_DATA ELFDATA2MSB#define ELF_ARCH EM_SPARCstatic inline void init_thread(struct target_pt_regs *regs, struct image_info *infop){ regs->psr = 0; regs->pc = infop->entry; regs->npc = regs->pc + 4; regs->y = 0; regs->u_regs[14] = infop->start_stack - 16 * 4;}#endif#endif#ifdef TARGET_PPC#define ELF_START_MMAP 0x80000000#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)#define elf_check_arch(x) ( (x) == EM_PPC64 )#define ELF_CLASS ELFCLASS64#else#define elf_check_arch(x) ( (x) == EM_PPC )#define ELF_CLASS ELFCLASS32#endif#ifdef TARGET_WORDS_BIGENDIAN#define ELF_DATA ELFDATA2MSB#else#define ELF_DATA ELFDATA2LSB#endif#define ELF_ARCH EM_PPC/* * We need to put in some extra aux table entries to tell glibc what * the cache block size is, so it can use the dcbz instruction safely. */#define AT_DCACHEBSIZE 19#define AT_ICACHEBSIZE 20#define AT_UCACHEBSIZE 21/* A special ignored type value for PPC, for glibc compatibility. */#define AT_IGNOREPPC 22/* * The requirements here are: * - keep the final alignment of sp (sp & 0xf) * - make sure the 32-bit value at the first 16 byte aligned position of * AUXV is greater than 16 for glibc compatibility. * AT_IGNOREPPC is used for that. * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC, * even if DLINFO_ARCH_ITEMS goes to zero or is undefined. */#define DLINFO_ARCH_ITEMS 5#define ARCH_DLINFO \do { \ NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20); \ NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20); \ NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \ /* \ * Now handle glibc compatibility. \ */ \ NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ } while (0)static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop){ abi_ulong pos = infop->start_stack; abi_ulong tmp;#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) abi_ulong entry, toc;#endif _regs->gpr[1] = infop->start_stack;#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) entry = ldq_raw(infop->entry) + infop->load_addr; toc = ldq_raw(infop->entry + 8) + infop->load_addr; _regs->gpr[2] = toc; infop->entry = entry;#endif _regs->nip = infop->entry; /* Note that isn't exactly what regular kernel does * but this is what the ABI wants and is needed to allow * execution of PPC BSD programs. */ /* FIXME - what to for failure of get_user()? */ get_user_ual(_regs->gpr[3], pos); pos += sizeof(abi_ulong); _regs->gpr[4] = pos; for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong)) tmp = ldl(pos); _regs->gpr[5] = pos;}#define USE_ELF_CORE_DUMP#define ELF_EXEC_PAGESIZE 4096#endif#ifdef TARGET_MIPS#define ELF_START_MMAP 0x80000000#define elf_check_arch(x) ( (x) == EM_MIPS )#ifdef TARGET_MIPS64#define ELF_CLASS ELFCLASS64#else#define ELF_CLASS ELFCLASS32#endif#ifdef TARGET_WORDS_BIGENDIAN#define ELF_DATA ELFDATA2MSB#else#define ELF_DATA ELFDATA2LSB#endif#define ELF_ARCH EM_MIPSstatic inline void init_thread(struct target_pt_regs *regs, struct image_info *infop){ regs->cp0_status = 2 << CP0St_KSU; regs->cp0_epc = infop->entry; regs->regs[29] = infop->start_stack;}#define USE_ELF_CORE_DUMP#define ELF_EXEC_PAGESIZE 4096#endif /* TARGET_MIPS */#ifdef TARGET_SH4#define ELF_START_MMAP 0x80000000#define elf_check_arch(x) ( (x) == EM_SH )#define ELF_CLASS ELFCLASS32#define ELF_DATA ELFDATA2LSB#define ELF_ARCH EM_SHstatic inline void init_thread(struct target_pt_regs *regs, struct image_info *infop){ /* Check other registers XXXXX */ regs->pc = infop->entry; regs->regs[15] = infop->start_stack;}#define USE_ELF_CORE_DUMP#define ELF_EXEC_PAGESIZE 4096#endif#ifdef TARGET_CRIS#define ELF_START_MMAP 0x80000000#define elf_check_arch(x) ( (x) == EM_CRIS )#define ELF_CLASS ELFCLASS32#define ELF_DATA ELFDATA2LSB#define ELF_ARCH EM_CRISstatic inline void init_thread(struct target_pt_regs *regs, struct image_info *infop){ regs->erp = infop->entry;}#define USE_ELF_CORE_DUMP#define ELF_EXEC_PAGESIZE 8192#endif#ifdef TARGET_M68K#define ELF_START_MMAP 0x80000000#define elf_check_arch(x) ( (x) == EM_68K )#define ELF_CLASS ELFCLASS32#define ELF_DATA ELFDATA2MSB#define ELF_ARCH EM_68K/* ??? Does this need to do anything?#define ELF_PLAT_INIT(_r) */static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop){ regs->usp = infop->start_stack; regs->sr = 0; regs->pc = infop->entry;}#define USE_ELF_CORE_DUMP#define ELF_EXEC_PAGESIZE 8192#endif#ifdef TARGET_ALPHA#define ELF_START_MMAP (0x30000000000ULL)#define elf_check_arch(x) ( (x) == ELF_ARCH )#define ELF_CLASS ELFCLASS64#define ELF_DATA ELFDATA2MSB#define ELF_ARCH EM_ALPHAstatic inline void init_thread(struct target_pt_regs *regs, struct image_info *infop){ regs->pc = infop->entry; regs->ps = 8; regs->usp = infop->start_stack; regs->unique = infop->start_data; /* ? */ printf("Set unique value to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", regs->unique, infop->start_data);}#define USE_ELF_CORE_DUMP#define ELF_EXEC_PAGESIZE 8192#endif /* TARGET_ALPHA */#ifndef ELF_PLATFORM#define ELF_PLATFORM (NULL)#endif#ifndef ELF_HWCAP#define ELF_HWCAP 0#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -