📄 elfload.c
字号:
/* This is the Linux kernel elf-loading code, ported into user space */#include <stdio.h>#include <sys/types.h>#include <fcntl.h>#include <sys/stat.h>#include <errno.h>#include <unistd.h>#include <sys/mman.h>#include <stdlib.h>#include <string.h>#include "qemu.h"#include "disas.h"/* 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;}#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_386 /* 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. */#define ELF_PLAT_INIT(_r) _r->edx = 0static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop){ regs->esp = infop->start_stack; regs->eip = infop->entry;}#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_ARM#define ELF_PLAT_INIT(_r) _r->ARM_r0 = 0static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop){ target_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; regs->ARM_r2 = tgetl(stack + 8); /* envp */ regs->ARM_r1 = tgetl(stack + 4); /* envp */ /* XXX: it seems that r0 is zeroed after ! */ // regs->ARM_r0 = tgetl(stack); /* argc */}#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#define elf_check_arch(x) ( (x) == EM_SPARC )#define ELF_CLASS ELFCLASS64#define ELF_DATA ELFDATA2MSB#define ELF_ARCH EM_SPARC/*XXX*/#define ELF_PLAT_INIT(_r)static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop){ regs->tstate = 0; regs->pc = infop->entry; regs->npc = regs->pc + 4; regs->y = 0; regs->u_regs[14] = infop->start_stack - 16 * 4;}#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_SPARC/*XXX*/#define ELF_PLAT_INIT(_r)static 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#define elf_check_arch(x) ( (x) == EM_PPC )#define ELF_CLASS ELFCLASS32#ifdef TARGET_WORDS_BIGENDIAN#define ELF_DATA ELFDATA2MSB#else#define ELF_DATA ELFDATA2LSB#endif#define ELF_ARCH EM_PPC/* 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. */#define ELF_PLAT_INIT(_r) \do { \ target_ulong *pos = (target_ulong *)bprm->p, tmp = 1; \ _r->gpr[3] = bprm->argc; \ _r->gpr[4] = (unsigned long)++pos; \ for (; tmp != 0; pos++) \ tmp = ldl(pos); \ _r->gpr[5] = (unsigned long)pos; \} while (0)/* * 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){ _regs->msr = 1 << MSR_PR; /* Set user mode */ _regs->gpr[1] = infop->start_stack; _regs->nip = infop->entry;}#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 )#define ELF_CLASS ELFCLASS32#ifdef TARGET_WORDS_BIGENDIAN#define ELF_DATA ELFDATA2MSB#else#define ELF_DATA ELFDATA2LSB#endif#define ELF_ARCH EM_MIPS#define ELF_PLAT_INIT(_r) static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop){ regs->cp0_status = CP0St_UM; regs->cp0_epc = infop->entry; regs->regs[29] = infop->start_stack;}#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_SH#define ELF_PLAT_INIT(_r) /* XXXXX */static 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 - 16 * 4;}#define USE_ELF_CORE_DUMP#define ELF_EXEC_PAGESIZE 4096#endif#ifndef ELF_PLATFORM#define ELF_PLATFORM (NULL)#endif#ifndef ELF_HWCAP#define ELF_HWCAP 0#endif#include "elf.h"/* * MAX_ARG_PAGES defines the number of pages allocated for arguments * and envelope for the new program. 32 should suffice, this gives * a maximum env+arg of 128kB w/4KB pages! */#define MAX_ARG_PAGES 32/* * This structure is used to hold the arguments that are * used when loading binaries. */struct linux_binprm { char buf[128]; void *page[MAX_ARG_PAGES]; unsigned long p; int sh_bang; int fd; int e_uid, e_gid; int argc, envc; char * filename; /* Name of binary */ unsigned long loader, exec; int dont_iput; /* binfmt handler has put inode */};struct exec{ unsigned int a_info; /* Use macros N_MAGIC, etc for access */ unsigned int a_text; /* length of text, in bytes */ unsigned int a_data; /* length of data, in bytes */ unsigned int a_bss; /* length of uninitialized data area, in bytes */ unsigned int a_syms; /* length of symbol table data in file, in bytes */ unsigned int a_entry; /* start address */ unsigned int a_trsize; /* length of relocation info for text, in bytes */ unsigned int a_drsize; /* length of relocation info for data, in bytes */};#define N_MAGIC(exec) ((exec).a_info & 0xffff)#define OMAGIC 0407#define NMAGIC 0410#define ZMAGIC 0413#define QMAGIC 0314/* max code+data+bss space allocated to elf interpreter */#define INTERP_MAP_SIZE (32 * 1024 * 1024)/* max code+data+bss+brk space allocated to ET_DYN executables */#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)/* from personality.h *//* Flags for bug emulation. These occupy the top three bytes. */#define STICKY_TIMEOUTS 0x4000000#define WHOLE_SECONDS 0x2000000/* Personality types. These go in the low byte. Avoid using the top bit, * it will conflict with error returns. */#define PER_MASK (0x00ff)#define PER_LINUX (0x0000)#define PER_SVR4 (0x0001 | STICKY_TIMEOUTS)#define PER_SVR3 (0x0002 | STICKY_TIMEOUTS)#define PER_SCOSVR3 (0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS)#define PER_WYSEV386 (0x0004 | STICKY_TIMEOUTS)#define PER_ISCR4 (0x0005 | STICKY_TIMEOUTS)#define PER_BSD (0x0006)#define PER_XENIX (0x0007 | STICKY_TIMEOUTS)/* Necessary parameters */#define NGROUPS 32#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))#define INTERPRETER_NONE 0#define INTERPRETER_AOUT 1#define INTERPRETER_ELF 2#define DLINFO_ITEMS 12static inline void memcpy_fromfs(void * to, const void * from, unsigned long n){ memcpy(to, from, n);}extern unsigned long x86_stack_size;static int load_aout_interp(void * exptr, int interp_fd);#ifdef BSWAP_NEEDEDstatic void bswap_ehdr(struct elfhdr *ehdr){ bswap16s(&ehdr->e_type); /* Object file type */ bswap16s(&ehdr->e_machine); /* Architecture */ bswap32s(&ehdr->e_version); /* Object file version */ bswaptls(&ehdr->e_entry); /* Entry point virtual address */ bswaptls(&ehdr->e_phoff); /* Program header table file offset */ bswaptls(&ehdr->e_shoff); /* Section header table file offset */ bswap32s(&ehdr->e_flags); /* Processor-specific flags */ bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ bswap16s(&ehdr->e_phnum); /* Program header table entry count */ bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ bswap16s(&ehdr->e_shnum); /* Section header table entry count */ bswap16s(&ehdr->e_shstrndx); /* Section header string table index */}static void bswap_phdr(struct elf_phdr *phdr){ bswap32s(&phdr->p_type); /* Segment type */ bswaptls(&phdr->p_offset); /* Segment file offset */ bswaptls(&phdr->p_vaddr); /* Segment virtual address */ bswaptls(&phdr->p_paddr); /* Segment physical address */ bswaptls(&phdr->p_filesz); /* Segment size in file */ bswaptls(&phdr->p_memsz); /* Segment size in memory */ bswap32s(&phdr->p_flags); /* Segment flags */ bswaptls(&phdr->p_align); /* Segment alignment */}static void bswap_shdr(struct elf_shdr *shdr){ bswap32s(&shdr->sh_name); bswap32s(&shdr->sh_type); bswaptls(&shdr->sh_flags); bswaptls(&shdr->sh_addr); bswaptls(&shdr->sh_offset); bswaptls(&shdr->sh_size); bswap32s(&shdr->sh_link); bswap32s(&shdr->sh_info); bswaptls(&shdr->sh_addralign); bswaptls(&shdr->sh_entsize);}static void bswap_sym(Elf32_Sym *sym){ bswap32s(&sym->st_name); bswap32s(&sym->st_value); bswap32s(&sym->st_size); bswap16s(&sym->st_shndx);}#endif/* * 'copy_string()' copies argument/envelope strings from user * memory to free pages in kernel mem. These are in a format ready * to be put directly into the top of new user memory. * */static unsigned long copy_strings(int argc,char ** argv, void **page, unsigned long p){ char *tmp, *tmp1, *pag = NULL; int len, offset = 0; if (!p) { return 0; /* bullet-proofing */ } while (argc-- > 0) { tmp = argv[argc]; if (!tmp) { fprintf(stderr, "VFS: argc is wrong"); exit(-1); } tmp1 = tmp; while (*tmp++); len = tmp - tmp1; if (p < len) { /* this shouldn't happen - 128kB */ return 0; } while (len) { --p; --tmp; --len; if (--offset < 0) { offset = p % TARGET_PAGE_SIZE; pag = (char *)page[p/TARGET_PAGE_SIZE]; if (!pag) { pag = (char *)malloc(TARGET_PAGE_SIZE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -