[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 12/14] linux-user: Re-use load_elf_image for the
From: |
malc |
Subject: |
Re: [Qemu-devel] [PATCH 12/14] linux-user: Re-use load_elf_image for the main binary. |
Date: |
Mon, 5 Apr 2010 22:14:17 +0400 (MSD) |
User-agent: |
Alpine 2.00 (LNX 1167 2008-08-23) |
On Mon, 5 Apr 2010, Richard Henderson wrote:
> This requires moving the PT_INTERP extraction and GUEST_BASE
> handling into load_elf_image. Key this off a non-null pointer
> argument to receive the interpreter name.
>
> Signed-off-by: Richard Henderson <address@hidden>
> ---
> linux-user/elfload.c | 269
> ++++++++++----------------------------------------
> 1 files changed, 53 insertions(+), 216 deletions(-)
>
> diff --git a/linux-user/elfload.c b/linux-user/elfload.c
> index c58387a..100efdc 100644
> --- a/linux-user/elfload.c
> +++ b/linux-user/elfload.c
> @@ -829,9 +829,6 @@ struct exec
> #define ZMAGIC 0413
> #define QMAGIC 0314
>
> -/* max code+data+bss+brk space allocated to ET_DYN executables */
> -#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
> -
> /* Necessary parameters */
> #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
> #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned
> long)(TARGET_ELF_EXEC_PAGESIZE-1))
> @@ -1168,7 +1165,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int
> argc, int envc,
> On return: INFO values will be filled in, as necessary or available. */
>
> static void load_elf_image(const char *image_name, int image_fd,
> - struct image_info *info,
> + struct image_info *info, char **pinterp_name,
> char bprm_buf[BPRM_BUF_SIZE])
> {
> struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
> @@ -1228,6 +1225,20 @@ static void load_elf_image(const char *image_name, int
> image_fd,
> if (load_addr == -1) {
> goto exit_perror;
> }
> + } else if (pinterp_name != NULL) {
> + /* This is the main executable. Make sure that the low
> + address does not conflict with MMAP_MIN_ADDR. */
> + /* ??? Ideally, we'd check against more than just the
> + minimum mmap address, but also against the QEMU program
> + image itself. I.e. find a range that does not conflict
> + with PAGE_RESERVED entries. Except that we havn't read
> + those in yet, since that code uses the guest_base that
> + we set up here. Blah. */
> +#if defined(CONFIG_USE_GUEST_BASE)
> + if (HOST_PAGE_ALIGN(loaddr) < mmap_min_addr) {
> + guest_base = HOST_PAGE_ALIGN(mmap_min_addr);
> + }
> +#endif
> }
> load_bias = load_addr - loaddr;
>
> @@ -1289,6 +1300,30 @@ static void load_elf_image(const char *image_name, int
> image_fd,
> info->brk = vaddr_em;
> }
> }
> + } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
> + char *interp_name;
> +
> + if (*pinterp_name) {
> + errmsg = "Multiple PT_INTERP entries";
> + goto exit_errmsg;
> + }
> + interp_name = malloc(eppnt->p_filesz);
malloc can fail
> +
> + if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
> + memcpy(interp_name, bprm_buf + eppnt->p_offset,
> + eppnt->p_filesz);
> + } else {
> + retval = pread(image_fd, interp_name, eppnt->p_filesz,
Indentation seems off.
> + eppnt->p_offset);
> + if (retval != eppnt->p_filesz) {
> + goto exit_perror;
> + }
> + }
> + if (interp_name[eppnt->p_filesz - 1] != 0) {
> + errmsg = "Invalid PT_INTERP entry";
> + goto exit_errmsg;
> + }
> + *pinterp_name = interp_name;
> }
> }
>
> @@ -1335,7 +1370,7 @@ static void load_elf_interp(const char *filename,
> struct image_info *info,
> memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
> }
>
> - load_elf_image(filename, fd, info, bprm_buf);
> + load_elf_image(filename, fd, info, NULL, bprm_buf);
> return;
>
> exit_perror:
> @@ -1479,230 +1514,31 @@ int load_elf_binary(struct linux_binprm * bprm,
> struct target_pt_regs * regs,
> {
> struct image_info interp_info;
> struct elfhdr elf_ex;
> - abi_ulong load_addr, load_bias;
> - int load_addr_set = 0;
> - int i;
> - struct elf_phdr * elf_ppnt;
> - struct elf_phdr *elf_phdata;
> - abi_ulong k, elf_brk;
> - int retval;
> char *elf_interpreter = NULL;
> - abi_ulong elf_entry;
> - int status;
> - abi_ulong start_code, end_code, start_data, end_data;
> - abi_ulong elf_stack;
>
> - status = 0;
> - load_addr = 0;
> - load_bias = 0;
> - elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
> + info->start_mmap = (abi_ulong)ELF_START_MMAP;
> + info->mmap = 0;
> + info->rss = 0;
> +
> + load_elf_image(bprm->filename, bprm->fd, info,
> + &elf_interpreter, bprm->buf);
>
> - /* First of all, some simple consistency checks */
> - if (!elf_check_ident(&elf_ex)) {
> - return -ENOEXEC;
> - }
> - bswap_ehdr(&elf_ex);
> - if (!elf_check_ehdr(&elf_ex)) {
> - return -ENOEXEC;
> - }
> + /* ??? We need a copy of the elf header for passing to create_elf_tables.
> + If we do nothing, we'll have overwritten this when we re-use bprm->buf
> + when we load the interpreter. */
> + elf_ex = *(struct elfhdr *)bprm->buf;
>
> bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
> bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
> bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
> if (!bprm->p) {
> - retval = -E2BIG;
> - }
> -
> - /* Now read in all of the header information */
> - elf_phdata = (struct elf_phdr *)
> - malloc(elf_ex.e_phnum * sizeof(struct elf_phdr));
> - if (elf_phdata == NULL) {
> - return -ENOMEM;
> - }
> -
> - i = elf_ex.e_phnum * sizeof(struct elf_phdr);
> - if (elf_ex.e_phoff + i <= BPRM_BUF_SIZE) {
> - memcpy(elf_phdata, bprm->buf + elf_ex.e_phoff, i);
> - } else {
> - retval = pread(bprm->fd, (char *) elf_phdata, i, elf_ex.e_phoff);
> - if (retval != i) {
> - perror("load_elf_binary");
> - exit(-1);
> - }
> - }
> - bswap_phdr(elf_phdata, elf_ex.e_phnum);
> -
> - elf_brk = 0;
> - elf_stack = ~((abi_ulong)0UL);
> - start_code = ~((abi_ulong)0UL);
> - end_code = 0;
> - start_data = 0;
> - end_data = 0;
> -
> - elf_ppnt = elf_phdata;
> - for(i=0;i < elf_ex.e_phnum; i++) {
> - if (elf_ppnt->p_type == PT_INTERP) {
> - if (elf_ppnt->p_offset + elf_ppnt->p_filesz <= BPRM_BUF_SIZE) {
> - elf_interpreter = bprm->buf + elf_ppnt->p_offset;
> - } else {
> - elf_interpreter = alloca(elf_ppnt->p_filesz);
> - retval = pread(bprm->fd, elf_interpreter, elf_ppnt->p_filesz,
> - elf_ppnt->p_offset);
> - if (retval != elf_ppnt->p_filesz) {
> - perror("load_elf_binary");
> - exit(-1);
> - }
> - }
> - }
> - elf_ppnt++;
> - }
> -
> - /* OK, This is the point of no return */
> - info->end_data = 0;
> - info->end_code = 0;
> - info->start_mmap = (abi_ulong)ELF_START_MMAP;
> - info->mmap = 0;
> - elf_entry = (abi_ulong) elf_ex.e_entry;
> -
> -#if defined(CONFIG_USE_GUEST_BASE)
> - /*
> - * In case where user has not explicitly set the guest_base, we
> - * probe here that should we set it automatically.
> - */
> - if (!have_guest_base) {
> - /*
> - * Go through ELF program header table and find out whether
> - * any of the segments drop below our current mmap_min_addr and
> - * in that case set guest_base to corresponding address.
> - */
> - for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum;
> - i++, elf_ppnt++) {
> - if (elf_ppnt->p_type != PT_LOAD)
> - continue;
> - if (HOST_PAGE_ALIGN(elf_ppnt->p_vaddr) < mmap_min_addr) {
> - guest_base = HOST_PAGE_ALIGN(mmap_min_addr);
> - break;
> - }
> - }
> + fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG));
> + exit(-1);
> }
> -#endif /* CONFIG_USE_GUEST_BASE */
>
> /* Do this so that we can load the interpreter, if need be. We will
> change some of these later */
> - info->rss = 0;
> bprm->p = setup_arg_pages(bprm->p, bprm, info);
> - info->start_stack = bprm->p;
> -
> - /* Now we do a little grungy work by mmaping the ELF image into
> - * the correct location in memory. At this point, we assume that
> - * the image should be loaded at fixed address, not at a variable
> - * address.
> - */
> -
> - for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
> - int elf_prot = 0;
> - int elf_flags = 0;
> - abi_ulong error;
> -
> - if (elf_ppnt->p_type != PT_LOAD)
> - continue;
> -
> - if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
> - if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
> - if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
> - elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
> - if (elf_ex.e_type == ET_EXEC || load_addr_set) {
> - elf_flags |= MAP_FIXED;
> - } else if (elf_ex.e_type == ET_DYN) {
> - /* Try and get dynamic programs out of the way of the default
> mmap
> - base, as well as whatever program they might try to exec.
> This
> - is because the brk will follow the loader, and is not
> movable. */
> - /* NOTE: for qemu, we do a big mmap to get enough space
> - without hardcoding any address */
> - error = target_mmap(0, ET_DYN_MAP_SIZE,
> - PROT_NONE, MAP_PRIVATE | MAP_ANON,
> - -1, 0);
> - if (error == -1) {
> - perror("mmap");
> - exit(-1);
> - }
> - load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
> - }
> -
> - error = target_mmap(TARGET_ELF_PAGESTART(load_bias +
> elf_ppnt->p_vaddr),
> - (elf_ppnt->p_filesz +
> - TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
> - elf_prot,
> - (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
> - bprm->fd,
> - (elf_ppnt->p_offset -
> - TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
> - if (error == -1) {
> - perror("mmap");
> - exit(-1);
> - }
> -
> -#ifdef LOW_ELF_STACK
> - if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
> - elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr);
> -#endif
> -
> - if (!load_addr_set) {
> - load_addr_set = 1;
> - load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
> - if (elf_ex.e_type == ET_DYN) {
> - load_bias += error -
> - TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
> - load_addr += load_bias;
> - }
> - }
> - k = elf_ppnt->p_vaddr;
> - if (k < start_code)
> - start_code = k;
> - if (start_data < k)
> - start_data = k;
> - k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
> - if ((elf_ppnt->p_flags & PF_X) && end_code < k)
> - end_code = k;
> - if (end_data < k)
> - end_data = k;
> - k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
> - if (k > elf_brk) {
> - elf_brk = TARGET_PAGE_ALIGN(k);
> - }
> -
> - /* If the load segment requests extra zeros (e.g. bss), map it. */
> - if (elf_ppnt->p_filesz < elf_ppnt->p_memsz) {
> - abi_ulong base = load_bias + elf_ppnt->p_vaddr;
> - zero_bss(base + elf_ppnt->p_filesz,
> - base + elf_ppnt->p_memsz, elf_prot);
> - }
> - }
> -
> - elf_entry += load_bias;
> - elf_brk += load_bias;
> - start_code += load_bias;
> - end_code += load_bias;
> - start_data += load_bias;
> - end_data += load_bias;
> -
> - info->load_bias = load_bias;
> - info->load_addr = load_addr;
> - info->entry = elf_entry;
> - info->start_brk = info->brk = elf_brk;
> - info->end_code = end_code;
> - info->start_code = start_code;
> - info->start_data = start_data;
> - info->end_data = end_data;
> - info->personality = PER_LINUX;
> -
> - free(elf_phdata);
> -
> - if (qemu_log_enabled()) {
> - load_symbols(&elf_ex, bprm->fd, load_bias);
> - }
> -
> - close(bprm->fd);
>
> if (elf_interpreter) {
> load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
> @@ -1734,6 +1570,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct
> target_pt_regs * regs,
> if (elf_interpreter) {
> info->load_addr = interp_info.load_addr;
> info->entry = interp_info.entry;
> + free(elf_interpreter);
> }
>
> #ifdef USE_ELF_CORE_DUMP
>
--
mailto:address@hidden
- [Qemu-devel] [PATCH 03/14] linux-user: Reindent elfload.c., (continued)
- [Qemu-devel] [PATCH 03/14] linux-user: Reindent elfload.c., Richard Henderson, 2010/04/05
- [Qemu-devel] [PATCH 06/14] linux-user: Clean up byte-swapping in elfload.c., Richard Henderson, 2010/04/05
- [Qemu-devel] [PATCH 05/14] linux-user: Fix ELF_DATA for Alpha., Richard Henderson, 2010/04/05
- [Qemu-devel] [PATCH 10/14] linux-user: Remove partial support for a.out interpreters., Richard Henderson, 2010/04/05
- [Qemu-devel] [PATCH 13/14] linux-user: Build vdso for x64., Richard Henderson, 2010/04/05
- [Qemu-devel] [PATCH 04/14] linux-user: Reduce lseek+reads while loading elf files., Richard Henderson, 2010/04/05
- [Qemu-devel] [PATCH 11/14] linux-user: Extract load_elf_image from load_elf_interp., Richard Henderson, 2010/04/05
- [Qemu-devel] [PATCH 09/14] linux-user: Put the stack guard page at the top., Richard Henderson, 2010/04/05
- [Qemu-devel] [PATCH 07/14] linux-user: Load symbols from the interpreter., Richard Henderson, 2010/04/05
- [Qemu-devel] [PATCH 12/14] linux-user: Re-use load_elf_image for the main binary., Richard Henderson, 2010/04/05
- Re: [Qemu-devel] [PATCH 12/14] linux-user: Re-use load_elf_image for the main binary.,
malc <=
- [Qemu-devel] [PATCH 00/14] Implement VDSO for x86-64-linux-user, v2, Richard Henderson, 2010/04/28
- [Qemu-devel] [PATCH 04/14] linux-user: Reduce lseek+reads while loading elf files., Richard Henderson, 2010/04/28
- [Qemu-devel] [PATCH 01/14] linux-user: Handle filesz < memsz for any PT_LOAD segment., Richard Henderson, 2010/04/28
- [Qemu-devel] [PATCH 02/14] Add more DT_* and AT_* constants to qemu's copy of elf.h., Richard Henderson, 2010/04/28
- [Qemu-devel] [PATCH 09/14] linux-user: Put the stack guard page at the top., Richard Henderson, 2010/04/28
- [Qemu-devel] [PATCH 05/14] linux-user: Fix ELF_DATA for Alpha., Richard Henderson, 2010/04/28
- [Qemu-devel] [PATCH 06/14] linux-user: Clean up byte-swapping in elfload.c., Richard Henderson, 2010/04/28
- [Qemu-devel] [PATCH 10/14] linux-user: Remove partial support for a.out interpreters., Richard Henderson, 2010/04/28
- [Qemu-devel] [PATCH 08/14] linux-user: Improve consistency checking in elf headers., Richard Henderson, 2010/04/28