* [Qemu-devel] [PATCH 01/14] linux-user: Handle filesz < memsz for any PT_LOAD segment.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
@ 2010-03-31 22:12 ` Richard Henderson
2010-04-04 18:38 ` [Qemu-devel] [PATCH 13/14] linux-user: Build vdso for x64 Richard Henderson
` (26 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-03-31 22:12 UTC (permalink / raw)
To: qemu-devel
I caught padzero not properly initializing the .bss segment
on a statically linked Alpha program. Rather than a minimal
patch, replace the gross code with a single mmap+memset.
Share more code between load_elf_interp and load_elf_binary.
Legally, an ELF program need not have just a single .bss;
and PT_LOAD segment can have memsz > filesz.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 150 ++++++++++++++++++--------------------------------
1 files changed, 54 insertions(+), 96 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 4d3dd89..238e574 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1015,60 +1015,47 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
return p;
}
-static void set_brk(abi_ulong start, abi_ulong end)
-{
- /* page-align the start and end addresses... */
- start = HOST_PAGE_ALIGN(start);
- end = HOST_PAGE_ALIGN(end);
- if (end <= start)
- return;
- if(target_mmap(start, end - start,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
- perror("cannot mmap brk");
- exit(-1);
- }
-}
-
-
-/* We need to explicitly zero any fractional pages after the data
- section (i.e. bss). This would contain the junk from the file that
- should not be in memory. */
-static void padzero(abi_ulong elf_bss, abi_ulong last_bss)
-{
- abi_ulong nbyte;
-
- if (elf_bss >= last_bss)
- return;
-
- /* XXX: this is really a hack : if the real host page size is
- smaller than the target page size, some pages after the end
- of the file may not be mapped. A better fix would be to
- patch target_mmap(), but it is more complicated as the file
- size must be known */
- if (qemu_real_host_page_size < qemu_host_page_size) {
- abi_ulong end_addr, end_addr1;
- end_addr1 = (elf_bss + qemu_real_host_page_size - 1) &
- ~(qemu_real_host_page_size - 1);
- end_addr = HOST_PAGE_ALIGN(elf_bss);
- if (end_addr1 < end_addr) {
- mmap((void *)g2h(end_addr1), end_addr - end_addr1,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
- }
+/* Map and zero the bss. We need to explicitly zero any fractional pages
+ after the data section (i.e. bss). */
+static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
+{
+ uintptr_t host_start, host_map_start, host_end;
+
+ last_bss = TARGET_PAGE_ALIGN(last_bss);
+
+ /* ??? There is confusion between qemu_real_host_page_size and
+ qemu_host_page_size here and elsewhere in target_mmap, which
+ may lead to the end of the data section mapping from the file
+ not being mapped. At least there was an explicit test and
+ comment for that here, suggesting that "the file size must
+ be known". The comment probably pre-dates the introduction
+ of the fstat system call in target_mmap which does in fact
+ find out the size. What isn't clear is if the workaround
+ here is still actually needed. For now, continue with it,
+ but merge it with the "normal" mmap that would allocate the bss. */
+
+ host_start = (uintptr_t) g2h(elf_bss);
+ host_end = (uintptr_t) g2h(last_bss);
+ host_map_start = (host_start + qemu_real_host_page_size - 1);
+ host_map_start &= -qemu_real_host_page_size;
+
+ if (host_map_start < host_end) {
+ void *p = mmap((void *)host_map_start, host_end - host_map_start,
+ prot, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (p == MAP_FAILED) {
+ perror("cannot mmap brk");
+ exit(-1);
}
- nbyte = elf_bss & (qemu_host_page_size-1);
- if (nbyte) {
- nbyte = qemu_host_page_size - nbyte;
- do {
- /* FIXME - what to do if put_user() fails? */
- put_user_u8(0, elf_bss);
- elf_bss++;
- } while (--nbyte);
- }
-}
+ /* Since we didn't use target_mmap, make sure to record
+ the validity of the pages with qemu. */
+ page_set_flags(elf_bss & TARGET_PAGE_MASK, last_bss, prot|PAGE_VALID);
+ }
+ if (host_start < host_map_start) {
+ memset((void *)host_start, 0, host_map_start - host_start);
+ }
+}
static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
struct elfhdr * exec,
@@ -1160,12 +1147,9 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
abi_ulong load_addr = 0;
int load_addr_set = 0;
int retval;
- abi_ulong last_bss, elf_bss;
abi_ulong error;
int i;
- elf_bss = 0;
- last_bss = 0;
error = 0;
#ifdef BSWAP_NEEDED
@@ -1238,7 +1222,6 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
int elf_prot = 0;
abi_ulong vaddr = 0;
- abi_ulong k;
if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
@@ -1266,40 +1249,17 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
load_addr_set = 1;
}
- /*
- * Find the end of the file mapping for this phdr, and keep
- * track of the largest address we see for this.
- */
- k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
- if (k > elf_bss) elf_bss = k;
-
- /*
- * Do the same thing for the memory mapping - between
- * elf_bss and last_bss is the bss section.
- */
- k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
- if (k > last_bss) last_bss = k;
+ /* If the load segment requests extra zeros (e.g. bss), map it. */
+ if (eppnt->p_filesz < eppnt->p_memsz) {
+ abi_ulong base = load_addr + eppnt->p_vaddr;
+ zero_bss(base + eppnt->p_filesz,
+ base + eppnt->p_memsz, elf_prot);
+ }
}
/* Now use mmap to map the library into memory. */
close(interpreter_fd);
-
- /*
- * Now fill out the bss section. First pad the last page up
- * to the page boundary, and then perform a mmap to make sure
- * that there are zeromapped pages up to and including the last
- * bss page.
- */
- padzero(elf_bss, last_bss);
- elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */
-
- /* Map the last of the bss segment */
- if (last_bss > elf_bss) {
- target_mmap(elf_bss, last_bss-elf_bss,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
- }
free(elf_phdata);
*interp_load_addr = load_addr;
@@ -1453,7 +1413,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
abi_ulong mapped_addr;
struct elf_phdr * elf_ppnt;
struct elf_phdr *elf_phdata;
- abi_ulong elf_bss, k, elf_brk;
+ abi_ulong k, elf_brk;
int retval;
char * elf_interpreter;
abi_ulong elf_entry, interp_load_addr = 0;
@@ -1512,10 +1472,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
#endif
elf_ppnt = elf_phdata;
- elf_bss = 0;
elf_brk = 0;
-
elf_stack = ~((abi_ulong)0UL);
elf_interpreter = NULL;
start_code = ~((abi_ulong)0UL);
@@ -1758,18 +1716,24 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
if (start_data < k)
start_data = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
- if (k > elf_bss)
- elf_bss = k;
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 = k;
+ 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_bss += load_bias;
elf_brk += load_bias;
start_code += load_bias;
end_code += load_bias;
@@ -1824,12 +1788,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
info->end_data = end_data;
info->start_stack = bprm->p;
- /* Calling set_brk effectively mmaps the pages that we need for the bss and break
- sections */
- set_brk(elf_bss, elf_brk);
-
- padzero(elf_bss, elf_brk);
-
#if 0
printf("(start_brk) %x\n" , info->start_brk);
printf("(end_code) %x\n" , info->end_code);
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 13/14] linux-user: Build vdso for x64.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
2010-03-31 22:12 ` [Qemu-devel] [PATCH 01/14] linux-user: Handle filesz < memsz for any PT_LOAD segment Richard Henderson
@ 2010-04-04 18:38 ` Richard Henderson
2010-04-04 19:07 ` [Qemu-devel] [PATCH 03/14] linux-user: Reindent elfload.c Richard Henderson
` (25 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-04 18:38 UTC (permalink / raw)
To: qemu-devel
... Well, sortof. The Makefile bits are broken.
Patch to load the vdso into the running program to follow.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
Makefile | 3 +-
pc-bios/Makefile | 5 ++
pc-bios/vdso-linux-x64.S | 102 +++++++++++++++++++++++++++++++++++++++++++++
pc-bios/vdso-linux-x64.ld | 81 +++++++++++++++++++++++++++++++++++
pc-bios/vdso-linux-x64.so | Bin 0 -> 7515 bytes
5 files changed, 190 insertions(+), 1 deletions(-)
create mode 100644 pc-bios/vdso-linux-x64.S
create mode 100644 pc-bios/vdso-linux-x64.ld
create mode 100755 pc-bios/vdso-linux-x64.so
diff --git a/Makefile b/Makefile
index a404fda..8e903ff 100644
--- a/Makefile
+++ b/Makefile
@@ -178,7 +178,8 @@ pxe-e1000.bin \
pxe-ne2k_pci.bin pxe-pcnet.bin \
pxe-rtl8139.bin pxe-virtio.bin \
bamboo.dtb petalogix-s3adsp1800.dtb \
-multiboot.bin linuxboot.bin
+multiboot.bin linuxboot.bin \
+vdso-linux-x64.so
else
BLOBS=
endif
diff --git a/pc-bios/Makefile b/pc-bios/Makefile
index 315288d..70e2485 100644
--- a/pc-bios/Makefile
+++ b/pc-bios/Makefile
@@ -15,5 +15,10 @@ all: $(TARGETS)
%.dtb: %.dts
dtc -I dts -O dtb -o $@ $<
+vdso-linux-x64.so: vdso-linux-x64.o vdso-linux-x64.ld
+ $(CC) -nostdlib -shared -Wl,-T,vdso-linux-x64.ld \
+ -Wl,-h,linux-vdso.so.1 -Wl,--hash-style=both \
+ vdso-linux-x64.o -o $@
+
clean:
rm -f $(TARGETS) *.o *~
diff --git a/pc-bios/vdso-linux-x64.S b/pc-bios/vdso-linux-x64.S
new file mode 100644
index 0000000..e7784c9
--- /dev/null
+++ b/pc-bios/vdso-linux-x64.S
@@ -0,0 +1,102 @@
+/*
+ * x86-64 linux replacement vdso.
+ *
+ * Copyright (c) 2010 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <asm/unistd.h>
+
+ .globl __vdso_clock_gettime
+ .type __vdso_clock_gettime, @function
+ .balign 16
+ .cfi_startproc
+__vdso_clock_gettime:
+ mov $__NR_clock_gettime, %eax
+ syscall
+ ret
+ .cfi_endproc
+ .size __vdso_clock_gettime, . - __vdso_clock_gettime
+
+clock_gettime = __vdso_clock_gettime
+ .weak clock_gettime
+
+
+ .globl __vdso_gettimeofday
+ .type __vdso_gettimeofday, @function
+ .balign 16
+ .cfi_startproc
+__vdso_gettimeofday:
+ mov $__NR_gettimeofday, %eax
+ syscall
+ ret
+ .cfi_endproc
+ .size __vdso_gettimeofday, . - __vdso_gettimeofday
+
+gettimeofday = __vdso_gettimeofday
+ .weak gettimeofday
+
+
+ .globl __vdso_getcpu
+ .type __vdso_getcpu, @function
+ .balign 16
+ .cfi_startproc
+__vdso_getcpu:
+ /* ??? There is no syscall number for this allocated on x64.
+ We can handle this several ways:
+
+ (1) Invent a syscall number for use within qemu.
+ It should be easy enough to pick a number that
+ is well out of the way of the kernel numbers.
+
+ (2) Force the emulated cpu to support the rdtscp insn,
+ and initialize the TSC_AUX value the appropriate value.
+
+ (3) Pretend that we're always running on cpu 0.
+
+ This last is the one that's implemented here, with the
+ tiny bit of extra code to support rdtscp in place. */
+
+ xor %ecx, %ecx /* rdtscp w/ tsc_aux = 0 */
+
+ /* if (cpu != NULL) *cpu = (ecx & 0xfff); */
+ test %rdi, %rdi
+ jz 1f
+ mov %ecx, %eax
+ and $0xfff, %eax
+ mov %eax, (%rdi)
+
+ /* if (node != NULL) *node = (ecx >> 12); */
+1: test %rsi, %rsi
+ jz 2f
+ shr $12, %ecx
+ mov %ecx, (%rsi)
+
+2: xor %eax, %eax
+ ret
+ .cfi_endproc
+ .size __vdso_getcpu, . - __vdso_getcpu
+
+getcpu = __vdso_getcpu
+ .weak getcpu
+
+/* ??? Perhaps add elf notes. E.g.
+
+ #include <linux/elfnote.h>
+ ELFNOTE_START(Linux, 0, "a")
+ .long LINUX_VERSION_CODE
+ ELFNOTE_END
+
+ but what version number would we set for QEMU? */
diff --git a/pc-bios/vdso-linux-x64.ld b/pc-bios/vdso-linux-x64.ld
new file mode 100644
index 0000000..d57d0e7
--- /dev/null
+++ b/pc-bios/vdso-linux-x64.ld
@@ -0,0 +1,81 @@
+/*
+ * Linker script for linux x64 replacement vdso.
+ *
+ * Copyright (c) 2010 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+VERSION {
+ LINUX_2.6 {
+ global:
+ clock_gettime;
+ __vdso_clock_gettime;
+ gettimeofday;
+ __vdso_gettimeofday;
+ getcpu;
+ __vdso_getcpu;
+ local: *;
+ };
+}
+
+PHDRS {
+ phdr PT_PHDR FLAGS(4) PHDRS;
+ data PT_LOAD FLAGS(6) FILEHDR PHDRS;
+ text PT_LOAD FLAGS(5);
+ dynamic PT_DYNAMIC FLAGS(4);
+ note PT_NOTE FLAGS(4);
+ /* ??? Various versions of ld don't know PT_GNU_EH_FRAME. */
+ eh_frame_hdr 0x6474e550;
+}
+
+SECTIONS {
+ /* ??? We can't really prelink to any address without knowing
+ something about the virtual memory space of the host, since
+ that leaks over into the available memory space of the guest. */
+ . = SIZEOF_HEADERS;
+
+ /* The following, including the FILEHDRS and PHDRS, are modified
+ when we relocate the binary. We want them to be initially
+ writable for the relocation; we'll force them read-only after. */
+ .dynamic : { *(.dynamic) } :data :dynamic
+ .dynsym : { *(.dynsym) } :data
+ .data : {
+ /* There ought not be any real read-write data.
+ But since we manipulated the segment layout,
+ we have to put these sections somewhere. */
+ *(.data*)
+ *(.sdata*)
+ *(.got.plt) *(.got)
+ *(.gnu.linkonce.d.*)
+ *(.bss*)
+ *(.dynbss*)
+ *(.gnu.linkonce.b.*)
+ }
+
+ . += 4096;
+ .hash : { *(.hash) } :text
+ .gnu.hash : { *(.gnu.hash) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .note : { *(.note*) } :text :note
+ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
+ .eh_frame : { *(.eh_frame) } :text
+ .rodata : { *(.rodata) }
+
+ . = ALIGN(0x100);
+ .text : { *(.text*) } :text =0x90909090
+}
diff --git a/pc-bios/vdso-linux-x64.so b/pc-bios/vdso-linux-x64.so
new file mode 100755
index 0000000000000000000000000000000000000000..5ebf5959f9dac5065428148e7625f58c722e1cca
GIT binary patch
literal 7515
zcmeHMO>Z1U5Uus%*iM{y6Cwl{#0nW7EEvfVLXjZIcKj8xI3d_l!ezYij=dJ%U9iWI
z%^?^OD>4#Nj&MZWI6#g*@TnkV@(Xf7Z~z1s6b@K90872;dYhfeh7%G(Oxr!L>s3`x
zcTM-~sQUG>!gyOIBP>~YRwC&>#|)Wb$7F~@a#Z%{H7ENOMed0>XrOb2c-p!qcA6eE
zeD78^vQ9%3$wvhI+O=-n8;N(|CvA==(hoGodBw()L^o+QFg?c!AJlga>!k(uIa-LY
zMLGRLSVH?_^GhP_iS#=Vd5cEa74n?#Z-3Tn&}`fM5et-CCNrj2EDn2}TFw~mGrZsM
z_qywE*2ejV$>uIMO@7Yw=Ju~ZR<csIb-@APIXx=fBDOyH+#nuOK9}GhHv1%x#}4~s
zKa<KIlwa!#u`-|%?DN(?`b8Pkit!|QuD8f2y`&LHBalWQjX)ZKGy-V^(g>sxNF$I&
zAdNs8fiwdDs|X;S(WMo63*>s3&(UU7n9pH82KF6Vf#8t0fXy3+^O=!AHo&0|a2IF3
zc~!3WUcG#B^T!9?KVE%n;H&=rtLKBt*~@kD{R^d)nm@Nxn|s+`2*Pl&5|A{pHeV{P
zH*s^Xtjf}2b#?6txO)0OD1{SKGiUuH-cx!%jHvk!Ove7+`|OwfNFhC>mANg9y-oGI
zs~={WUP8VF1+f5!c}`5t$n~E(zYGQjCO+st_x8J=e$+R<aq`<tZ}#cD*^Fvu&uDvE
zaaysYxTMH_Gq0VI%vvtf+uhNLTnu=O1p#Ev2qO3=wcgU2<O|B()XH3sHvjWw`+J>2
zPy4l=M=nKk*`AHdgI`Z>*2Au?oyY1uB3m7ko4aBA7e9Az9T@!lns_Vgm9ThTF<f?7
zW~;PbEmjui#M6daDHg+`cnj54uUuRyJ3d@?%!OciWwBO`34TeuYAp=J3(Efda<LNl
z<&xS{5-$wa!f4R{z@=CFz@EW+Lt(y-h;@R({m8YEb99vdMQ)Y*l=)ZU4YPwkZ0OHC
z?BmMe7Q8?6oJ88GNmS@h#Qwv+=lz*4CLVQe4L$v^&rptN-PK$#{h41T4#7wZ_4IeF
z+k1Q`fnz?J$ow<yEu0i(R9p3?`!nB6JY<%<e-d9%J#yFNXR(pB5IO&3{GFBBX#?+7
z`X}@KeKa&=+(^%B19PJP-SYjkPx@maH~W8Q<0sD2(J&eRi{{Vu$vigkSi+y{mh?ew
zaP5%;9<%)RrDjsw$>-NR_GZ(a2c49&!01avP&t0CYy1Yby8n&nB`xx%>!xu{-oK$}
z(a7p(8~eCPpVg<u{n<q8IPN@WfIh3gO59Iz`}W3pOq}1-*avaGL%6Qvd}m|5#`&(s
z`BR+V+c;l}^ZSJBCeGhJ-yn}TX7qd`86TV*f#>^&_IYizI&blmZ*@+Beb?$72EV1P
z&QD&l{*&i33&tnURjSqx*E!df_@n2hhMzxiT>Oc`sgdD=e`<XE#j$CBdU&KT=1cs$
X=k`~OeHQ)A7f?*40=|k`eoXxZDW(!W
literal 0
HcmV?d00001
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 03/14] linux-user: Reindent elfload.c.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
2010-03-31 22:12 ` [Qemu-devel] [PATCH 01/14] linux-user: Handle filesz < memsz for any PT_LOAD segment Richard Henderson
2010-04-04 18:38 ` [Qemu-devel] [PATCH 13/14] linux-user: Build vdso for x64 Richard Henderson
@ 2010-04-04 19:07 ` Richard Henderson
2010-04-04 19:34 ` [Qemu-devel] [PATCH 04/14] linux-user: Reduce lseek+reads while loading elf files Richard Henderson
` (24 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-04 19:07 UTC (permalink / raw)
To: qemu-devel
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 594 +++++++++++++++++++++++++-------------------------
1 files changed, 301 insertions(+), 293 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index ead22fc..ab741fd 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -35,18 +35,17 @@
* 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,
+ 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,
};
/*
@@ -56,30 +55,29 @@ enum {
* 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,
+ 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,
};
/*
@@ -126,7 +124,7 @@ static const char *get_elf_platform(void)
static uint32_t get_elf_hwcap(void)
{
- return thread_env->cpuid_features;
+ return thread_env->cpuid_features;
}
#ifdef TARGET_X86_64
@@ -201,7 +199,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_386
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
regs->esp = infop->start_stack;
regs->eip = infop->entry;
@@ -267,13 +266,14 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#endif
#define ELF_ARCH EM_ARM
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static 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_cpsr |= CPSR_T;
regs->ARM_pc = infop->entry & 0xfffffffe;
regs->ARM_sp = infop->start_stack;
/* FIXME - what to for failure of get_user()? */
@@ -317,26 +317,26 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
enum
{
- 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,
- ARM_HWCAP_ARM_JAVA = 1 << 8,
- ARM_HWCAP_ARM_IWMMXT = 1 << 9,
- ARM_HWCAP_ARM_THUMBEE = 1 << 10,
- ARM_HWCAP_ARM_NEON = 1 << 11,
- ARM_HWCAP_ARM_VFPv3 = 1 << 12,
- ARM_HWCAP_ARM_VFPv3D16 = 1 << 13,
+ 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,
+ ARM_HWCAP_ARM_JAVA = 1 << 8,
+ ARM_HWCAP_ARM_IWMMXT = 1 << 9,
+ ARM_HWCAP_ARM_THUMBEE = 1 << 10,
+ ARM_HWCAP_ARM_NEON = 1 << 11,
+ ARM_HWCAP_ARM_VFPv3 = 1 << 12,
+ ARM_HWCAP_ARM_VFPv3D16 = 1 << 13,
};
-#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 \
- | ARM_HWCAP_ARM_NEON | ARM_HWCAP_ARM_VFPv3 )
+#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 \
+ | ARM_HWCAP_ARM_NEON | ARM_HWCAP_ARM_VFPv3 )
#endif
@@ -357,7 +357,8 @@ enum
#define STACK_BIAS 2047
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
#ifndef TARGET_ABI32
regs->tstate = 0;
@@ -384,7 +385,8 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_SPARC
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
regs->psr = 0;
regs->pc = infop->entry;
@@ -464,7 +466,7 @@ static uint32_t get_elf_hwcap(void)
/* We don't have to be terribly complete here; the high points are
Altivec/FP/SPE support. Anything else is just a bonus. */
-#define GET_FEATURE(flag, feature) \
+#define GET_FEATURE(flag, feature) \
do {if (e->insns_flags & flag) features |= feature; } while(0)
GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64);
GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU);
@@ -489,17 +491,17 @@ static uint32_t get_elf_hwcap(void)
* 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)
+#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)
{
@@ -559,7 +561,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#endif
#define ELF_ARCH EM_MIPS
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
regs->cp0_status = 2 << CP0St_KSU;
regs->cp0_epc = infop->entry;
@@ -626,7 +629,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_XILINX_MICROBLAZE
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
regs->pc = infop->entry;
regs->r1 = infop->start_stack;
@@ -647,11 +651,12 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_SH
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+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;
+ /* Check other registers XXXXX */
+ regs->pc = infop->entry;
+ regs->regs[15] = infop->start_stack;
}
/* See linux kernel: arch/sh/include/asm/elf.h. */
@@ -669,7 +674,8 @@ enum {
TARGET_REG_SYSCALL = 22
};
-static inline void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
+static inline void elf_core_copy_regs(target_elf_gregset_t *regs,
+ const CPUState *env)
{
int i;
@@ -701,9 +707,10 @@ static inline void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState
#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_CRIS
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
- regs->erp = infop->entry;
+ regs->erp = infop->entry;
}
#define ELF_EXEC_PAGESIZE 8192
@@ -721,9 +728,10 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
#define ELF_ARCH EM_68K
/* ??? Does this need to do anything?
-#define ELF_PLAT_INIT(_r) */
+ #define ELF_PLAT_INIT(_r) */
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
regs->usp = infop->start_stack;
regs->sr = 0;
@@ -773,7 +781,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_ALPHA
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
regs->pc = infop->entry;
regs->ps = 8;
@@ -803,14 +812,14 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
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 */
+ 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 */
};
@@ -839,7 +848,7 @@ struct exec
static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
{
- memcpy(to, from, n);
+ memcpy(to, from, n);
}
static int load_aout_interp(void * exptr, int interp_fd);
@@ -847,7 +856,7 @@ static int load_aout_interp(void * exptr, int interp_fd);
#ifdef BSWAP_NEEDED
static void bswap_ehdr(struct elfhdr *ehdr)
{
- bswap16s(&ehdr->e_type); /* Object file type */
+ 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 */
@@ -855,16 +864,16 @@ static void bswap_ehdr(struct elfhdr *ehdr)
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_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_shentsize); /* Section header table entry size */
bswap16s(&ehdr->e_shnum); /* Section header table entry count */
- bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
+ bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
}
static void bswap_phdr(struct elf_phdr *phdr)
{
- bswap32s(&phdr->p_type); /* Segment type */
+ 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 */
@@ -936,7 +945,7 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
while (*tmp++);
len = tmp - tmp1;
if (p < len) { /* this shouldn't happen - 128kB */
- return 0;
+ return 0;
}
while (len) {
--p; --tmp; --len;
@@ -955,12 +964,12 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
*(pag + offset) = *tmp;
}
else {
- int bytes_to_copy = (len > offset) ? offset : len;
- tmp -= bytes_to_copy;
- p -= bytes_to_copy;
- offset -= bytes_to_copy;
- len -= bytes_to_copy;
- memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
+ int bytes_to_copy = (len > offset) ? offset : len;
+ tmp -= bytes_to_copy;
+ p -= bytes_to_copy;
+ offset -= bytes_to_copy;
+ len -= bytes_to_copy;
+ memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
}
}
}
@@ -1055,77 +1064,77 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
abi_ulong interp_load_addr, int ibcs,
struct image_info *info)
{
- abi_ulong sp;
- int size;
- abi_ulong u_platform;
- const char *k_platform;
- const int n = sizeof(elf_addr_t);
-
- sp = p;
- u_platform = 0;
- k_platform = ELF_PLATFORM;
- if (k_platform) {
- size_t len = strlen(k_platform) + 1;
- sp -= (len + n - 1) & ~(n - 1);
- u_platform = sp;
- /* FIXME - check return value of memcpy_to_target() for failure */
- memcpy_to_target(sp, k_platform, len);
- }
- /*
- * Force 16 byte _final_ alignment here for generality.
- */
- sp = sp &~ (abi_ulong)15;
- size = (DLINFO_ITEMS + 1) * 2;
- if (k_platform)
- size += 2;
+ abi_ulong sp;
+ int size;
+ abi_ulong u_platform;
+ const char *k_platform;
+ const int n = sizeof(elf_addr_t);
+
+ sp = p;
+ u_platform = 0;
+ k_platform = ELF_PLATFORM;
+ if (k_platform) {
+ size_t len = strlen(k_platform) + 1;
+ sp -= (len + n - 1) & ~(n - 1);
+ u_platform = sp;
+ /* FIXME - check return value of memcpy_to_target() for failure */
+ memcpy_to_target(sp, k_platform, len);
+ }
+ /*
+ * Force 16 byte _final_ alignment here for generality.
+ */
+ sp = sp &~ (abi_ulong)15;
+ size = (DLINFO_ITEMS + 1) * 2;
+ if (k_platform)
+ size += 2;
#ifdef DLINFO_ARCH_ITEMS
- size += DLINFO_ARCH_ITEMS * 2;
+ size += DLINFO_ARCH_ITEMS * 2;
#endif
- size += envc + argc + 2;
- size += (!ibcs ? 3 : 1); /* argc itself */
- size *= n;
- if (size & 15)
- sp -= 16 - (size & 15);
-
- /* This is correct because Linux defines
- * elf_addr_t as Elf32_Off / Elf64_Off
- */
+ size += envc + argc + 2;
+ size += (!ibcs ? 3 : 1); /* argc itself */
+ size *= n;
+ if (size & 15)
+ sp -= 16 - (size & 15);
+
+ /* This is correct because Linux defines
+ * elf_addr_t as Elf32_Off / Elf64_Off
+ */
#define NEW_AUX_ENT(id, val) do { \
- sp -= n; put_user_ual(val, sp); \
- sp -= n; put_user_ual(id, sp); \
- } while(0)
-
- NEW_AUX_ENT (AT_NULL, 0);
-
- /* There must be exactly DLINFO_ITEMS entries here. */
- NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
- NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
- NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
- NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
- NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
- NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
- NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
- NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
- NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
- NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
- NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
- NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
- NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
- if (k_platform)
- NEW_AUX_ENT(AT_PLATFORM, u_platform);
+ sp -= n; put_user_ual(val, sp); \
+ sp -= n; put_user_ual(id, sp); \
+ } while(0)
+
+ NEW_AUX_ENT (AT_NULL, 0);
+
+ /* There must be exactly DLINFO_ITEMS entries here. */
+ NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
+ NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
+ NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
+ NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
+ NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
+ NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
+ NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
+ NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
+ NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
+ NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
+ NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
+ NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
+ NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
+ if (k_platform)
+ NEW_AUX_ENT(AT_PLATFORM, u_platform);
#ifdef ARCH_DLINFO
- /*
- * ARCH_DLINFO must come last so platform specific code can enforce
- * special alignment requirements on the AUXV if necessary (eg. PPC).
- */
- ARCH_DLINFO;
+ /*
+ * ARCH_DLINFO must come last so platform specific code can enforce
+ * special alignment requirements on the AUXV if necessary (eg. PPC).
+ */
+ ARCH_DLINFO;
#endif
#undef NEW_AUX_ENT
- info->saved_auxv = sp;
+ info->saved_auxv = sp;
- sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
- return sp;
+ sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
+ return sp;
}
@@ -1133,83 +1142,83 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
int interpreter_fd,
abi_ulong *interp_load_addr)
{
- struct elf_phdr *elf_phdata = NULL;
- struct elf_phdr *eppnt;
- abi_ulong load_addr = 0;
- int load_addr_set = 0;
- int retval;
- abi_ulong error;
- int i;
+ struct elf_phdr *elf_phdata = NULL;
+ struct elf_phdr *eppnt;
+ abi_ulong load_addr = 0;
+ int load_addr_set = 0;
+ int retval;
+ abi_ulong error;
+ int i;
- error = 0;
+ error = 0;
#ifdef BSWAP_NEEDED
- bswap_ehdr(interp_elf_ex);
+ bswap_ehdr(interp_elf_ex);
#endif
- /* First of all, some simple consistency checks */
- if ((interp_elf_ex->e_type != ET_EXEC &&
- interp_elf_ex->e_type != ET_DYN) ||
- !elf_check_arch(interp_elf_ex->e_machine)) {
- return ~((abi_ulong)0UL);
- }
+ /* First of all, some simple consistency checks */
+ if ((interp_elf_ex->e_type != ET_EXEC &&
+ interp_elf_ex->e_type != ET_DYN) ||
+ !elf_check_arch(interp_elf_ex->e_machine)) {
+ return ~((abi_ulong)0UL);
+ }
- /* Now read in all of the header information */
+ /* Now read in all of the header information */
- if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
- return ~(abi_ulong)0UL;
+ if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
+ return ~(abi_ulong)0UL;
- elf_phdata = (struct elf_phdr *)
- malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
+ elf_phdata = (struct elf_phdr *)
+ malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
- if (!elf_phdata)
- return ~((abi_ulong)0UL);
+ if (!elf_phdata)
+ return ~((abi_ulong)0UL);
- /*
- * If the size of this structure has changed, then punt, since
- * we will be doing the wrong thing.
- */
- if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
- free(elf_phdata);
- return ~((abi_ulong)0UL);
- }
+ /*
+ * If the size of this structure has changed, then punt, since
+ * we will be doing the wrong thing.
+ */
+ if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
+ free(elf_phdata);
+ return ~((abi_ulong)0UL);
+ }
- retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
- if(retval >= 0) {
- retval = read(interpreter_fd,
- (char *) elf_phdata,
- sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
- }
- if (retval < 0) {
- perror("load_elf_interp");
- exit(-1);
- free (elf_phdata);
- return retval;
- }
+ retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
+ if(retval >= 0) {
+ retval = read(interpreter_fd,
+ (char *) elf_phdata,
+ sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
+ }
+ if (retval < 0) {
+ perror("load_elf_interp");
+ exit(-1);
+ free (elf_phdata);
+ return retval;
+ }
#ifdef BSWAP_NEEDED
- eppnt = elf_phdata;
- for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
- bswap_phdr(eppnt);
- }
+ eppnt = elf_phdata;
+ for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
+ bswap_phdr(eppnt);
+ }
#endif
- if (interp_elf_ex->e_type == ET_DYN) {
- /* in order to avoid hardcoding the interpreter load
- address in qemu, we allocate a big enough memory zone */
- error = target_mmap(0, INTERP_MAP_SIZE,
- PROT_NONE, MAP_PRIVATE | MAP_ANON,
- -1, 0);
- if (error == -1) {
- perror("mmap");
- exit(-1);
- }
- load_addr = error;
- load_addr_set = 1;
+ if (interp_elf_ex->e_type == ET_DYN) {
+ /* in order to avoid hardcoding the interpreter load
+ address in qemu, we allocate a big enough memory zone */
+ error = target_mmap(0, INTERP_MAP_SIZE,
+ PROT_NONE, MAP_PRIVATE | MAP_ANON,
+ -1, 0);
+ if (error == -1) {
+ perror("mmap");
+ exit(-1);
}
+ load_addr = error;
+ load_addr_set = 1;
+ }
- eppnt = elf_phdata;
- for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
- if (eppnt->p_type == PT_LOAD) {
+ eppnt = elf_phdata;
+ for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
+ if (eppnt->p_type == PT_LOAD) {
int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
int elf_prot = 0;
abi_ulong vaddr = 0;
@@ -1222,22 +1231,22 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
vaddr = eppnt->p_vaddr;
}
error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
- eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
- elf_prot,
- elf_type,
- interpreter_fd,
- eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
+ eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
+ elf_prot,
+ elf_type,
+ interpreter_fd,
+ eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
if (error == -1) {
- /* Real error */
- close(interpreter_fd);
- free(elf_phdata);
- return ~((abi_ulong)0UL);
+ /* Real error */
+ close(interpreter_fd);
+ free(elf_phdata);
+ return ~((abi_ulong)0UL);
}
if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
- load_addr = error;
- load_addr_set = 1;
+ load_addr = error;
+ load_addr_set = 1;
}
/* If the load segment requests extra zeros (e.g. bss), map it. */
@@ -1246,15 +1255,15 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
zero_bss(base + eppnt->p_filesz,
base + eppnt->p_memsz, elf_prot);
}
- }
+ }
- /* Now use mmap to map the library into memory. */
+ /* Now use mmap to map the library into memory. */
- close(interpreter_fd);
- free(elf_phdata);
+ close(interpreter_fd);
+ free(elf_phdata);
- *interp_load_addr = load_addr;
- return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
+ *interp_load_addr = load_addr;
+ return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
}
static int symfind(const void *s0, const void *s1)
@@ -1356,8 +1365,8 @@ static void load_symbols(struct elfhdr *hdr, int fd)
#endif
// Throw away entries which we do not need.
if (syms[i].st_shndx == SHN_UNDEF ||
- syms[i].st_shndx >= SHN_LORESERVE ||
- ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
+ syms[i].st_shndx >= SHN_LORESERVE ||
+ ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
nsyms--;
if (i < nsyms) {
syms[i] = syms[nsyms];
@@ -1425,8 +1434,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
/* First of all, some simple consistency checks */
if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
- (! elf_check_arch(elf_ex.e_machine))) {
- return -ENOEXEC;
+ (! elf_check_arch(elf_ex.e_machine))) {
+ return -ENOEXEC;
}
bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
@@ -1445,7 +1454,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
if(retval > 0) {
retval = read(bprm->fd, (char *) elf_phdata,
- elf_ex.e_phentsize * elf_ex.e_phnum);
+ elf_ex.e_phentsize * elf_ex.e_phnum);
}
if (retval < 0) {
@@ -1513,7 +1522,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
- ibcs2_interpreter = 1;
+ ibcs2_interpreter = 1;
}
#if 0
@@ -1559,8 +1568,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
/* Now figure out which format our binary is */
if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
- (N_MAGIC(interp_ex) != QMAGIC)) {
- interpreter_type = INTERPRETER_ELF;
+ (N_MAGIC(interp_ex) != QMAGIC)) {
+ interpreter_type = INTERPRETER_ELF;
}
if (interp_elf_ex.e_ident[0] != 0x7f ||
@@ -1620,7 +1629,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
* in that case set guest_base to corresponding address.
*/
for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum;
- i++, elf_ppnt++) {
+ i++, elf_ppnt++) {
if (elf_ppnt->p_type != PT_LOAD)
continue;
if (HOST_PAGE_ALIGN(elf_ppnt->p_vaddr) < mmap_min_addr) {
@@ -1737,7 +1746,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
}
else if (interpreter_type & 2) {
elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
- &interp_load_addr);
+ &interp_load_addr);
}
reloc_func_desc = interp_load_addr;
@@ -1764,13 +1773,13 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
info->start_stack = bprm->p = elf_stack - 4;
#endif
bprm->p = create_elf_tables(bprm->p,
- bprm->argc,
- bprm->envc,
- &elf_ex,
- load_addr, load_bias,
- interp_load_addr,
- (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
- info);
+ bprm->argc,
+ bprm->envc,
+ &elf_ex,
+ load_addr, load_bias,
+ interp_load_addr,
+ (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
+ info);
info->load_addr = reloc_func_desc;
info->start_brk = info->brk = elf_brk;
info->end_code = end_code;
@@ -1790,12 +1799,12 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
if ( info->personality == PER_SVR4 )
{
- /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
- and some applications "depend" upon this behavior.
- Since we do not have the power to recompile these, we
- emulate the SVr4 behavior. Sigh. */
- mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE, -1, 0);
+ /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
+ and some applications "depend" upon this behavior.
+ Since we do not have the power to recompile these, we
+ emulate the SVr4 behavior. Sigh. */
+ mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE, -1, 0);
}
info->entry = elf_entry;
@@ -1808,7 +1817,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
}
#ifdef USE_ELF_CORE_DUMP
-
/*
* Definitions to generate Intel SVR4-like core files.
* These mostly have the same names as the SVR4 types with "target_elf_"
@@ -1945,17 +1953,17 @@ struct mm_struct {
static struct mm_struct *vma_init(void);
static void vma_delete(struct mm_struct *);
static int vma_add_mapping(struct mm_struct *, abi_ulong,
- abi_ulong, abi_ulong);
+ abi_ulong, abi_ulong);
static int vma_get_mapping_count(const struct mm_struct *);
static struct vm_area_struct *vma_first(const struct mm_struct *);
static struct vm_area_struct *vma_next(struct vm_area_struct *);
static abi_ulong vma_dump_size(const struct vm_area_struct *);
static int vma_walker(void *priv, abi_ulong start, abi_ulong end,
- unsigned long flags);
+ unsigned long flags);
static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t);
static void fill_note(struct memelfnote *, const char *, int,
- unsigned int, void *);
+ unsigned int, void *);
static void fill_prstatus(struct target_elf_prstatus *, const TaskState *, int);
static int fill_psinfo(struct target_elf_prpsinfo *, const TaskState *);
static void fill_auxv_note(struct memelfnote *, const TaskState *);
@@ -2035,7 +2043,7 @@ static void vma_delete(struct mm_struct *mm)
}
static int vma_add_mapping(struct mm_struct *mm, abi_ulong start,
- abi_ulong end, abi_ulong flags)
+ abi_ulong end, abi_ulong flags)
{
struct vm_area_struct *vma;
@@ -2104,7 +2112,7 @@ static abi_ulong vma_dump_size(const struct vm_area_struct *vma)
}
static int vma_walker(void *priv, abi_ulong start, abi_ulong end,
- unsigned long flags)
+ unsigned long flags)
{
struct mm_struct *mm = (struct mm_struct *)priv;
@@ -2119,7 +2127,7 @@ static int vma_walker(void *priv, abi_ulong start, abi_ulong end,
}
static void fill_note(struct memelfnote *note, const char *name, int type,
- unsigned int sz, void *data)
+ unsigned int sz, void *data)
{
unsigned int namesz;
@@ -2140,7 +2148,7 @@ static void fill_note(struct memelfnote *note, const char *name, int type,
}
static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
- uint32_t flags)
+ uint32_t flags)
{
(void) memset(elf, 0, sizeof(*elf));
@@ -2186,7 +2194,7 @@ static size_t note_size(const struct memelfnote *note)
}
static void fill_prstatus(struct target_elf_prstatus *prstatus,
- const TaskState *ts, int signr)
+ const TaskState *ts, int signr)
{
(void) memset(prstatus, 0, sizeof (*prstatus));
prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
@@ -2227,7 +2235,7 @@ static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
filename = strdup(ts->bprm->filename);
base_filename = strdup(basename(filename));
(void) strncpy(psinfo->pr_fname, base_filename,
- sizeof(psinfo->pr_fname));
+ sizeof(psinfo->pr_fname));
free(base_filename);
free(filename);
@@ -2276,7 +2284,7 @@ static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
* Returns 0 in case of success, -1 otherwise (errno is set).
*/
static int core_dump_filename(const TaskState *ts, char *buf,
- size_t bufsize)
+ size_t bufsize)
{
char timestamp[64];
char *filename = NULL;
@@ -2288,16 +2296,16 @@ static int core_dump_filename(const TaskState *ts, char *buf,
if (gettimeofday(&tv, NULL) < 0) {
(void) fprintf(stderr, "unable to get current timestamp: %s",
- strerror(errno));
+ strerror(errno));
return (-1);
}
filename = strdup(ts->bprm->filename);
base_filename = strdup(basename(filename));
(void) strftime(timestamp, sizeof (timestamp), "%Y%m%d-%H%M%S",
- localtime_r(&tv.tv_sec, &tm));
+ localtime_r(&tv.tv_sec, &tm));
(void) snprintf(buf, bufsize, "qemu_%s_%s_%d.core",
- base_filename, timestamp, (int)getpid());
+ base_filename, timestamp, (int)getpid());
free(base_filename);
free(filename);
@@ -2382,7 +2390,7 @@ static void fill_thread_info(struct elf_note_info *info, const CPUState *env)
fill_prstatus(&ets->prstatus, ts, 0);
elf_core_copy_regs(&ets->prstatus.pr_reg, env);
fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus),
- &ets->prstatus);
+ &ets->prstatus);
QTAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link);
@@ -2390,7 +2398,7 @@ static void fill_thread_info(struct elf_note_info *info, const CPUState *env)
}
static int fill_note_info(struct elf_note_info *info,
- long signr, const CPUState *env)
+ long signr, const CPUState *env)
{
#define NUMNOTES 3
CPUState *cpu = NULL;
@@ -2418,10 +2426,10 @@ static int fill_note_info(struct elf_note_info *info,
fill_prstatus(info->prstatus, ts, signr);
elf_core_copy_regs(&info->prstatus->pr_reg, env);
fill_note(&info->notes[0], "CORE", NT_PRSTATUS,
- sizeof (*info->prstatus), info->prstatus);
+ sizeof (*info->prstatus), info->prstatus);
fill_psinfo(info->psinfo, ts);
fill_note(&info->notes[1], "CORE", NT_PRPSINFO,
- sizeof (*info->psinfo), info->psinfo);
+ sizeof (*info->psinfo), info->psinfo);
fill_auxv_note(&info->notes[2], ts);
info->numnote = 3;
@@ -2468,7 +2476,7 @@ static int write_note_info(struct elf_note_info *info, int fd)
/* write prstatus for each thread */
for (ets = info->thread_list.tqh_first; ets != NULL;
- ets = ets->ets_link.tqe_next) {
+ ets = ets->ets_link.tqe_next) {
if ((error = write_note(&ets->notes[0], fd)) != 0)
return (error);
}
@@ -2536,13 +2544,13 @@ static int elf_core_dump(int signr, const CPUState *env)
errno = 0;
getrlimit(RLIMIT_CORE, &dumpsize);
if (dumpsize.rlim_cur == 0)
- return 0;
+ return 0;
if (core_dump_filename(ts, corefile, sizeof (corefile)) < 0)
return (-errno);
if ((fd = open(corefile, O_WRONLY | O_CREAT,
- S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
return (-errno);
/*
@@ -2631,7 +2639,7 @@ static int elf_core_dump(int signr, const CPUState *env)
end = vma->vma_start + vma_dump_size(vma);
for (addr = vma->vma_start; addr < end;
- addr += TARGET_PAGE_SIZE) {
+ addr += TARGET_PAGE_SIZE) {
char page[TARGET_PAGE_SIZE];
int error;
@@ -2642,7 +2650,7 @@ static int elf_core_dump(int signr, const CPUState *env)
error = copy_from_user(page, addr, sizeof (page));
if (error != 0) {
(void) fprintf(stderr, "unable to dump " TARGET_ABI_FMT_lx "\n",
- addr);
+ addr);
errno = -error;
goto out;
}
@@ -2651,7 +2659,7 @@ static int elf_core_dump(int signr, const CPUState *env)
}
}
-out:
+ out:
free_note_info(&info);
if (mm != NULL)
vma_delete(mm);
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 04/14] linux-user: Reduce lseek+reads while loading elf files.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (2 preceding siblings ...)
2010-04-04 19:07 ` [Qemu-devel] [PATCH 03/14] linux-user: Reindent elfload.c Richard Henderson
@ 2010-04-04 19:34 ` Richard Henderson
2010-04-04 19:35 ` [Qemu-devel] [PATCH 05/14] linux-user: Fix ELF_DATA for Alpha Richard Henderson
` (23 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-04 19:34 UTC (permalink / raw)
To: qemu-devel
Define BPRM_BUF_SIZE to 4k and read that amount initially. If the
data we want from the binary is in this buffer, use it instead of
reading from the file again.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 105 ++++++++++++++++++++---------------------------
linux-user/linuxload.c | 17 +++-----
linux-user/qemu.h | 7 +++-
3 files changed, 58 insertions(+), 71 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index ab741fd..962f9ba 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1140,7 +1140,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
int interpreter_fd,
- abi_ulong *interp_load_addr)
+ abi_ulong *interp_load_addr,
+ char bprm_buf[BPRM_BUF_SIZE])
{
struct elf_phdr *elf_phdata = NULL;
struct elf_phdr *eppnt;
@@ -1183,17 +1184,15 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
return ~((abi_ulong)0UL);
}
- retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
- if(retval >= 0) {
- retval = read(interpreter_fd,
- (char *) elf_phdata,
- sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
- }
- if (retval < 0) {
- perror("load_elf_interp");
- exit(-1);
- free (elf_phdata);
- return retval;
+ i = interp_elf_ex->e_phnum * sizeof(struct elf_phdr);
+ if (interp_elf_ex->e_phoff + i <= BPRM_BUF_SIZE) {
+ memcpy(elf_phdata, bprm_buf + interp_elf_ex->e_phoff, i);
+ } else {
+ retval = pread(interpreter_fd, elf_phdata, i, interp_elf_ex->e_phoff);
+ if (retval != i) {
+ perror("load_elf_interp");
+ exit(-1);
+ }
}
#ifdef BSWAP_NEEDED
eppnt = elf_phdata;
@@ -1451,17 +1450,15 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
return -ENOMEM;
}
- retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
- if(retval > 0) {
- retval = read(bprm->fd, (char *) elf_phdata,
- elf_ex.e_phentsize * elf_ex.e_phnum);
- }
-
- if (retval < 0) {
- perror("load_elf_binary");
- exit(-1);
- free (elf_phdata);
- return -errno;
+ 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);
+ }
}
#ifdef BSWAP_NEEDED
@@ -1505,13 +1502,16 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
return -ENOMEM;
}
- retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
- if(retval >= 0) {
- retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
- }
- if(retval < 0) {
- perror("load_elf_binary2");
- exit(-1);
+ if (elf_ppnt->p_offset + elf_ppnt->p_filesz <= BPRM_BUF_SIZE) {
+ memcpy(elf_interpreter, bprm->buf + elf_ppnt->p_offset,
+ elf_ppnt->p_filesz);
+ } else {
+ retval = pread(bprm->fd, elf_interpreter, elf_ppnt->p_filesz,
+ elf_ppnt->p_offset);
+ if (retval != elf_ppnt->p_filesz) {
+ perror("load_elf_binary2");
+ exit(-1);
+ }
}
/* If the program interpreter is one of these two,
@@ -1525,39 +1525,24 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
ibcs2_interpreter = 1;
}
-#if 0
- printf("Using ELF interpreter %s\n", path(elf_interpreter));
-#endif
- if (retval >= 0) {
- retval = open(path(elf_interpreter), O_RDONLY);
- if(retval >= 0) {
- interpreter_fd = retval;
- }
- else {
- perror(elf_interpreter);
- exit(-1);
- /* retval = -errno; */
- }
- }
+ retval = open(path(elf_interpreter), O_RDONLY);
+ if (retval < 0) {
+ perror(elf_interpreter);
+ exit(-1);
+ }
+ interpreter_fd = retval;
- if (retval >= 0) {
- retval = lseek(interpreter_fd, 0, SEEK_SET);
- if(retval >= 0) {
- retval = read(interpreter_fd,bprm->buf,128);
- }
- }
- if (retval >= 0) {
- interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
- interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */
- }
- if (retval < 0) {
+ retval = read(interpreter_fd, bprm->buf, BPRM_BUF_SIZE);
+ if (retval < 0) {
perror("load_elf_binary3");
exit(-1);
- free (elf_phdata);
- free(elf_interpreter);
- close(bprm->fd);
- return retval;
}
+ if (retval < BPRM_BUF_SIZE) {
+ memset(bprm->buf, 0, BPRM_BUF_SIZE - retval);
+ }
+
+ interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
+ interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */
}
elf_ppnt++;
}
@@ -1746,7 +1731,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
}
else if (interpreter_type & 2) {
elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
- &interp_load_addr);
+ &interp_load_addr, bprm->buf);
}
reloc_func_desc = interp_load_addr;
diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
index 2d778a2..f67ace5 100644
--- a/linux-user/linuxload.c
+++ b/linux-user/linuxload.c
@@ -96,18 +96,16 @@ static int prepare_binprm(struct linux_binprm *bprm)
}
}
- retval = lseek(bprm->fd, 0L, SEEK_SET);
- if(retval >= 0) {
- retval = read(bprm->fd, bprm->buf, 128);
- }
- if(retval < 0) {
+ retval = read(bprm->fd, bprm->buf, BPRM_BUF_SIZE);
+ if (retval < 0) {
perror("prepare_binprm");
exit(-1);
- /* return(-errno); */
}
- else {
- return(retval);
+ if (retval < BPRM_BUF_SIZE) {
+ /* Make sure the rest of the loader won't read garbage. */
+ memset(bprm->buf + retval, 0, BPRM_BUF_SIZE - retval);
}
+ return retval;
}
/* Construct the envp and argv tables on the target stack. */
@@ -163,8 +161,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp,
int i;
bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
- for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
- bprm->page[i] = NULL;
+ memset(bprm->page, 0, sizeof(bprm->page));
retval = open(filename, O_RDONLY);
if (retval < 0)
return retval;
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 47fc686..bcf07bf 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -31,6 +31,7 @@
* task_struct fields in the kernel
*/
struct image_info {
+ abi_ulong load_bias;
abi_ulong load_addr;
abi_ulong start_code;
abi_ulong end_code;
@@ -143,12 +144,16 @@ extern unsigned long mmap_min_addr;
*/
#define MAX_ARG_PAGES 33
+/* Read a good amount of data initially, to hopefully get all the
+ program headers loaded. */
+#define BPRM_BUF_SIZE 4096
+
/*
* This structure is used to hold the arguments that are
* used when loading binaries.
*/
struct linux_binprm {
- char buf[128];
+ char buf[BPRM_BUF_SIZE] __attribute__((aligned));
void *page[MAX_ARG_PAGES];
abi_ulong p;
int fd;
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 05/14] linux-user: Fix ELF_DATA for Alpha.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (3 preceding siblings ...)
2010-04-04 19:34 ` [Qemu-devel] [PATCH 04/14] linux-user: Reduce lseek+reads while loading elf files Richard Henderson
@ 2010-04-04 19:35 ` Richard Henderson
2010-04-04 19:54 ` [Qemu-devel] [PATCH 06/14] linux-user: Clean up byte-swapping in elfload.c Richard Henderson
` (22 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-04 19:35 UTC (permalink / raw)
To: qemu-devel
Alpha is little-endian on Linux.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 962f9ba..5814702 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -778,7 +778,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#define elf_check_arch(x) ( (x) == ELF_ARCH )
#define ELF_CLASS ELFCLASS64
-#define ELF_DATA ELFDATA2MSB
+#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_ALPHA
static inline void init_thread(struct target_pt_regs *regs,
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 06/14] linux-user: Clean up byte-swapping in elfload.c.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (4 preceding siblings ...)
2010-04-04 19:35 ` [Qemu-devel] [PATCH 05/14] linux-user: Fix ELF_DATA for Alpha Richard Henderson
@ 2010-04-04 19:54 ` Richard Henderson
2010-04-04 21:16 ` [Qemu-devel] [PATCH 07/14] linux-user: Load symbols from the interpreter Richard Henderson
` (21 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-04 19:54 UTC (permalink / raw)
To: qemu-devel
Remove ifdefs from code by defining empty inline functions
when byte swapping isn't needed. Push loops over swapping
arrays of structures into the swapping functions.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 119 ++++++++++++++++++++------------------------------
1 files changed, 48 insertions(+), 71 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 5814702..9cf1eeb 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -871,30 +871,36 @@ static void bswap_ehdr(struct elfhdr *ehdr)
bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
}
-static void bswap_phdr(struct elf_phdr *phdr)
+static void bswap_phdr(struct elf_phdr *phdr, int phnum)
{
- 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 */
+ int i;
+ for (i = 0; i < phnum; ++i, ++phdr) {
+ bswap32s(&phdr->p_type); /* Segment type */
+ bswap32s(&phdr->p_flags); /* Segment flags */
+ 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 */
+ bswaptls(&phdr->p_align); /* Segment alignment */
+ }
}
-static void bswap_shdr(struct elf_shdr *shdr)
+static void bswap_shdr(struct elf_shdr *shdr, int shnum)
{
- 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);
+ int i;
+ for (i = 0; i < shnum; ++i, ++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(struct elf_sym *sym)
@@ -904,20 +910,15 @@ static void bswap_sym(struct elf_sym *sym)
bswaptls(&sym->st_size);
bswap16s(&sym->st_shndx);
}
+#else
+static inline void bswap_ehdr(struct elfhdr *ehdr) { }
+static inline void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
+static inline void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
+static inline void bswap_sym(struct elf_sym *sym) { }
#endif
#ifdef USE_ELF_CORE_DUMP
static int elf_core_dump(int, const CPUState *);
-
-#ifdef BSWAP_NEEDED
-static void bswap_note(struct elf_note *en)
-{
- bswap32s(&en->n_namesz);
- bswap32s(&en->n_descsz);
- bswap32s(&en->n_type);
-}
-#endif /* BSWAP_NEEDED */
-
#endif /* USE_ELF_CORE_DUMP */
/*
@@ -1153,9 +1154,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
error = 0;
-#ifdef BSWAP_NEEDED
bswap_ehdr(interp_elf_ex);
-#endif
/* First of all, some simple consistency checks */
if ((interp_elf_ex->e_type != ET_EXEC &&
interp_elf_ex->e_type != ET_DYN) ||
@@ -1194,12 +1193,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
exit(-1);
}
}
-#ifdef BSWAP_NEEDED
- eppnt = elf_phdata;
- for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
- bswap_phdr(eppnt);
- }
-#endif
+ bswap_phdr(elf_phdata, interp_elf_ex->e_phnum);
if (interp_elf_ex->e_type == ET_DYN) {
/* in order to avoid hardcoding the interpreter load
@@ -1323,9 +1317,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
for (i = 0; i < hdr->e_shnum; i++) {
if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
return;
-#ifdef BSWAP_NEEDED
- bswap_shdr(&sechdr);
-#endif
+ bswap_shdr(&sechdr, 1);
if (sechdr.sh_type == SHT_SYMTAB) {
symtab = sechdr;
lseek(fd, hdr->e_shoff
@@ -1333,9 +1325,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
if (read(fd, &strtab, sizeof(strtab))
!= sizeof(strtab))
return;
-#ifdef BSWAP_NEEDED
- bswap_shdr(&strtab);
-#endif
+ bswap_shdr(&strtab, 1);
goto found;
}
}
@@ -1359,9 +1349,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
i = 0;
while (i < nsyms) {
-#ifdef BSWAP_NEEDED
bswap_sym(syms + i);
-#endif
// Throw away entries which we do not need.
if (syms[i].st_shndx == SHN_UNDEF ||
syms[i].st_shndx >= SHN_LORESERVE ||
@@ -1427,9 +1415,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
load_addr = 0;
load_bias = 0;
elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
-#ifdef BSWAP_NEEDED
bswap_ehdr(&elf_ex);
-#endif
/* First of all, some simple consistency checks */
if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
@@ -1460,17 +1446,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
exit(-1);
}
}
-
-#ifdef BSWAP_NEEDED
- elf_ppnt = elf_phdata;
- for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
- bswap_phdr(elf_ppnt);
- }
-#endif
- elf_ppnt = elf_phdata;
+ bswap_phdr(elf_phdata, elf_ex.e_phnum);
elf_brk = 0;
-
elf_stack = ~((abi_ulong)0UL);
elf_interpreter = NULL;
start_code = ~((abi_ulong)0UL);
@@ -1479,6 +1457,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
end_data = 0;
interp_ex.a_info = 0;
+ elf_ppnt = elf_phdata;
for(i=0;i < elf_ex.e_phnum; i++) {
if (elf_ppnt->p_type == PT_INTERP) {
if ( elf_interpreter != NULL )
@@ -1964,9 +1943,6 @@ static int write_note(struct memelfnote *, int);
static int write_note_info(struct elf_note_info *, int);
#ifdef BSWAP_NEEDED
-static void bswap_prstatus(struct target_elf_prstatus *);
-static void bswap_psinfo(struct target_elf_prpsinfo *);
-
static void bswap_prstatus(struct target_elf_prstatus *prstatus)
{
prstatus->pr_info.si_signo = tswapl(prstatus->pr_info.si_signo);
@@ -1994,6 +1970,17 @@ static void bswap_psinfo(struct target_elf_prpsinfo *psinfo)
psinfo->pr_pgrp = tswap32(psinfo->pr_pgrp);
psinfo->pr_sid = tswap32(psinfo->pr_sid);
}
+
+static void bswap_note(struct elf_note *en)
+{
+ bswap32s(&en->n_namesz);
+ bswap32s(&en->n_descsz);
+ bswap32s(&en->n_type);
+}
+#else
+static inline void bswap_prstatus(struct target_elf_prstatus *p) { }
+static inline void bswap_psinfo(struct target_elf_prpsinfo *p) {}
+static inline void bswap_note(struct elf_note *en) { }
#endif /* BSWAP_NEEDED */
/*
@@ -2152,9 +2139,7 @@ static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
elf->e_phentsize = sizeof(struct elf_phdr);
elf->e_phnum = segs;
-#ifdef BSWAP_NEEDED
bswap_ehdr(elf);
-#endif
}
static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
@@ -2168,9 +2153,7 @@ static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
phdr->p_flags = 0;
phdr->p_align = 0;
-#ifdef BSWAP_NEEDED
- bswap_phdr(phdr);
-#endif
+ bswap_phdr(phdr, 1);
}
static size_t note_size(const struct memelfnote *note)
@@ -2188,9 +2171,7 @@ static void fill_prstatus(struct target_elf_prstatus *prstatus,
prstatus->pr_pgrp = getpgrp();
prstatus->pr_sid = getsid(0);
-#ifdef BSWAP_NEEDED
bswap_prstatus(prstatus);
-#endif
}
static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
@@ -2224,9 +2205,7 @@ static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
free(base_filename);
free(filename);
-#ifdef BSWAP_NEEDED
bswap_psinfo(psinfo);
-#endif
return (0);
}
@@ -2351,9 +2330,7 @@ static int write_note(struct memelfnote *men, int fd)
en.n_type = men->type;
en.n_descsz = men->datasz;
-#ifdef BSWAP_NEEDED
bswap_note(&en);
-#endif
if (dump_write(fd, &en, sizeof(en)) != 0)
return (-1);
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 07/14] linux-user: Load symbols from the interpreter.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (5 preceding siblings ...)
2010-04-04 19:54 ` [Qemu-devel] [PATCH 06/14] linux-user: Clean up byte-swapping in elfload.c Richard Henderson
@ 2010-04-04 21:16 ` Richard Henderson
2010-04-04 22:04 ` [Qemu-devel] [PATCH 08/14] linux-user: Improve consistency checking in elf headers Richard Henderson
` (20 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-04 21:16 UTC (permalink / raw)
To: qemu-devel
First, adjust load_symbols to accept a load_bias parameter. At the same
time, read the entire section header table in one go, use pread instead
f lseek+read for the symbol and string tables, and properly free
allocated structures on error exit paths.
Second, adjust load_elf_interp to compute load_bias. This requires
finding out the built-in load addresses. Which allows us to honor a
pre-linked interpreter image when possible, and eliminate the hard-coded
INTERP_MAP_SIZE value.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 189 +++++++++++++++++++++++++++-----------------------
1 files changed, 101 insertions(+), 88 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 9cf1eeb..7e94fe3 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 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)
@@ -920,6 +917,7 @@ static inline void bswap_sym(struct elf_sym *sym) { }
#ifdef USE_ELF_CORE_DUMP
static int elf_core_dump(int, const CPUState *);
#endif /* USE_ELF_CORE_DUMP */
+static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias);
/*
* 'copy_elf_strings()' copies argument/envelope strings from user
@@ -1145,15 +1143,11 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
char bprm_buf[BPRM_BUF_SIZE])
{
struct elf_phdr *elf_phdata = NULL;
- struct elf_phdr *eppnt;
- abi_ulong load_addr = 0;
- int load_addr_set = 0;
+ abi_ulong load_addr, load_bias, loaddr, hiaddr;
int retval;
abi_ulong error;
int i;
- error = 0;
-
bswap_ehdr(interp_elf_ex);
/* First of all, some simple consistency checks */
if ((interp_elf_ex->e_type != ET_EXEC &&
@@ -1162,7 +1156,6 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
return ~((abi_ulong)0UL);
}
-
/* Now read in all of the header information */
if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
@@ -1195,41 +1188,56 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
}
bswap_phdr(elf_phdata, interp_elf_ex->e_phnum);
+ /* Find the maximum size of the image and allocate an appropriate
+ amount of memory to handle that. */
+ loaddr = -1, hiaddr = 0;
+ for (i = 0; i < interp_elf_ex->e_phnum; ++i) {
+ if (elf_phdata[i].p_type == PT_LOAD) {
+ abi_ulong a = elf_phdata[i].p_vaddr;
+ if (a < loaddr) {
+ loaddr = a;
+ }
+ a += elf_phdata[i].p_memsz;
+ if (a > hiaddr) {
+ hiaddr = a;
+ }
+ }
+ }
+
+ load_addr = loaddr;
if (interp_elf_ex->e_type == ET_DYN) {
- /* in order to avoid hardcoding the interpreter load
- address in qemu, we allocate a big enough memory zone */
- error = target_mmap(0, INTERP_MAP_SIZE,
- PROT_NONE, MAP_PRIVATE | MAP_ANON,
- -1, 0);
- if (error == -1) {
+ /* The image indicates that it can be loaded anywhere. Find a
+ location that can hold the memory space required. If the
+ image is pre-linked, LOADDR will be non-zero. Since we do
+ not supply MAP_FIXED here we'll use that address if and
+ only if it remains available. */
+ load_addr = target_mmap(loaddr, hiaddr - loaddr, PROT_NONE,
+ MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
+ -1, 0);
+ if (load_addr == -1) {
perror("mmap");
exit(-1);
}
- load_addr = error;
- load_addr_set = 1;
}
+ load_bias = load_addr - loaddr;
- eppnt = elf_phdata;
- for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
+ for (i = 0; i < interp_elf_ex->e_phnum; i++) {
+ struct elf_phdr *eppnt = elf_phdata + i;
if (eppnt->p_type == PT_LOAD) {
- int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+ abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em;
int elf_prot = 0;
- abi_ulong vaddr = 0;
if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
- if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
- elf_type |= MAP_FIXED;
- vaddr = eppnt->p_vaddr;
- }
- error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
- eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
- elf_prot,
- elf_type,
- interpreter_fd,
- eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
+ vaddr = load_bias + eppnt->p_vaddr;
+ vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
+ vaddr_ps = TARGET_ELF_PAGESTART(vaddr);
+
+ error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
+ elf_prot, MAP_PRIVATE | MAP_FIXED,
+ interpreter_fd, eppnt->p_offset - vaddr_po);
if (error == -1) {
/* Real error */
close(interpreter_fd);
@@ -1237,26 +1245,25 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
return ~((abi_ulong)0UL);
}
- if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
- load_addr = error;
- load_addr_set = 1;
- }
+ vaddr_ef = vaddr + eppnt->p_filesz;
+ vaddr_em = vaddr + eppnt->p_memsz;
/* If the load segment requests extra zeros (e.g. bss), map it. */
- if (eppnt->p_filesz < eppnt->p_memsz) {
- abi_ulong base = load_addr + eppnt->p_vaddr;
- zero_bss(base + eppnt->p_filesz,
- base + eppnt->p_memsz, elf_prot);
+ if (vaddr_ef < vaddr_em) {
+ zero_bss(vaddr_ef, vaddr_em, elf_prot);
}
}
+ }
- /* Now use mmap to map the library into memory. */
+ if (qemu_log_enabled()) {
+ load_symbols(interp_elf_ex, interpreter_fd, load_bias);
+ }
close(interpreter_fd);
free(elf_phdata);
*interp_load_addr = load_addr;
- return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
+ return ((abi_ulong) interp_elf_ex->e_entry) + load_bias;
}
static int symfind(const void *s0, const void *s1)
@@ -1305,82 +1312,87 @@ static int symcmp(const void *s0, const void *s1)
}
/* Best attempt to load symbols from this ELF object. */
-static void load_symbols(struct elfhdr *hdr, int fd)
+static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
{
- unsigned int i, nsyms;
- struct elf_shdr sechdr, symtab, strtab;
+ int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
+ struct elf_shdr *shdr;
char *strings;
struct syminfo *s;
struct elf_sym *syms;
- lseek(fd, hdr->e_shoff, SEEK_SET);
- for (i = 0; i < hdr->e_shnum; i++) {
- if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
- return;
- bswap_shdr(&sechdr, 1);
- if (sechdr.sh_type == SHT_SYMTAB) {
- symtab = sechdr;
- lseek(fd, hdr->e_shoff
- + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
- if (read(fd, &strtab, sizeof(strtab))
- != sizeof(strtab))
- return;
- bswap_shdr(&strtab, 1);
+ shnum = hdr->e_shnum;
+ i = shnum * sizeof(struct elf_shdr);
+ shdr = (struct elf_shdr *)alloca(i);
+ if (pread(fd, shdr, i, hdr->e_shoff) != i) {
+ return;
+ }
+
+ bswap_shdr(shdr, shnum);
+ for (i = 0; i < shnum; ++i) {
+ if (shdr[i].sh_type == SHT_SYMTAB) {
+ sym_idx = i;
+ str_idx = shdr[i].sh_link;
goto found;
}
}
- return; /* Shouldn't happen... */
+
+ /* There will be no symbol table if the file was stripped. */
+ return;
found:
- /* Now know where the strtab and symtab are. Snarf them. */
+ /* Now know where the strtab and symtab are. Snarf them. */
s = malloc(sizeof(*s));
- syms = malloc(symtab.sh_size);
- if (!syms)
- return;
- s->disas_strtab = strings = malloc(strtab.sh_size);
- if (!s->disas_strtab)
+ if (!s) {
return;
+ }
- lseek(fd, symtab.sh_offset, SEEK_SET);
- if (read(fd, syms, symtab.sh_size) != symtab.sh_size)
+ i = shdr[str_idx].sh_size;
+ s->disas_strtab = strings = malloc(i);
+ if (!strings || pread(fd, strings, i, shdr[str_idx].sh_offset) != i) {
+ free(s);
+ free(strings);
return;
+ }
- nsyms = symtab.sh_size / sizeof(struct elf_sym);
+ i = shdr[sym_idx].sh_size;
+ syms = malloc(i);
+ if (!syms || pread(fd, syms, i, shdr[sym_idx].sh_offset) != i) {
+ free(s);
+ free(strings);
+ free(syms);
+ return;
+ }
- i = 0;
- while (i < nsyms) {
+ nsyms = i / sizeof(struct elf_sym);
+ for (i = 0; i < nsyms; ) {
bswap_sym(syms + i);
- // Throw away entries which we do not need.
- if (syms[i].st_shndx == SHN_UNDEF ||
- syms[i].st_shndx >= SHN_LORESERVE ||
- ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
- nsyms--;
- if (i < nsyms) {
+ /* Throw away entries which we do not need. */
+ if (syms[i].st_shndx == SHN_UNDEF
+ || syms[i].st_shndx >= SHN_LORESERVE
+ || ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
+ if (i < --nsyms) {
syms[i] = syms[nsyms];
}
- continue;
- }
+ } else {
#if defined(TARGET_ARM) || defined (TARGET_MIPS)
- /* The bottom address bit marks a Thumb or MIPS16 symbol. */
- syms[i].st_value &= ~(target_ulong)1;
+ /* The bottom address bit marks a Thumb or MIPS16 symbol. */
+ syms[i].st_value &= ~(target_ulong)1;
#endif
- i++;
+ syms[i].st_value += load_bias;
+ i++;
+ }
}
- syms = realloc(syms, nsyms * sizeof(*syms));
+ syms = realloc(syms, nsyms * sizeof(*syms));
qsort(syms, nsyms, sizeof(*syms), symcmp);
- lseek(fd, strtab.sh_offset, SEEK_SET);
- if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
- return;
s->disas_num_syms = nsyms;
#if ELF_CLASS == ELFCLASS32
s->disas_symtab.elf32 = syms;
- s->lookup_symbol = lookup_symbolxx;
#else
s->disas_symtab.elf64 = syms;
- s->lookup_symbol = lookup_symbolxx;
#endif
+ s->lookup_symbol = lookup_symbolxx;
s->next = syminfos;
syminfos = s;
}
@@ -1727,8 +1739,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
free(elf_phdata);
- if (qemu_log_enabled())
- load_symbols(&elf_ex, bprm->fd);
+ if (qemu_log_enabled()) {
+ load_symbols(&elf_ex, bprm->fd, load_bias);
+ }
if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 08/14] linux-user: Improve consistency checking in elf headers.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (6 preceding siblings ...)
2010-04-04 21:16 ` [Qemu-devel] [PATCH 07/14] linux-user: Load symbols from the interpreter Richard Henderson
@ 2010-04-04 22:04 ` Richard Henderson
2010-04-04 22:14 ` [Qemu-devel] [PATCH 09/14] linux-user: Put the stack guard page at the top Richard Henderson
` (19 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-04 22:04 UTC (permalink / raw)
To: qemu-devel
Validate more fields of the elf header. Extract those checks
into two common functions to be used in both load_elf_interp
and load_elf_binary.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 57 +++++++++++++++++++++++++++++---------------------
1 files changed, 33 insertions(+), 24 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 7e94fe3..5853a30 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -919,6 +919,30 @@ static int elf_core_dump(int, const CPUState *);
#endif /* USE_ELF_CORE_DUMP */
static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias);
+/* Verify the portions of EHDR within E_IDENT for the target.
+ This can be performed before bswapping the entire header. */
+static _Bool elf_check_ident(struct elfhdr *ehdr)
+{
+ return (ehdr->e_ident[EI_MAG0] == ELFMAG0
+ && ehdr->e_ident[EI_MAG1] == ELFMAG1
+ && ehdr->e_ident[EI_MAG2] == ELFMAG2
+ && ehdr->e_ident[EI_MAG3] == ELFMAG3
+ && ehdr->e_ident[EI_CLASS] == ELF_CLASS
+ && ehdr->e_ident[EI_DATA] == ELF_DATA
+ && ehdr->e_ident[EI_VERSION] == EV_CURRENT);
+}
+
+/* Verify the portions of EHDR outside of E_IDENT for the target.
+ This has to wait until after bswapping the header. */
+static _Bool elf_check_ehdr(struct elfhdr *ehdr)
+{
+ return (elf_check_arch(ehdr->e_machine)
+ && ehdr->e_ehsize == sizeof(struct elfhdr)
+ && ehdr->e_phentsize == sizeof(struct elf_phdr)
+ && ehdr->e_shentsize == sizeof(struct elf_shdr)
+ && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));
+}
+
/*
* 'copy_elf_strings()' copies argument/envelope strings from user
* memory to free pages in kernel mem. These are in a format ready
@@ -1149,33 +1173,16 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
int i;
bswap_ehdr(interp_elf_ex);
- /* First of all, some simple consistency checks */
- if ((interp_elf_ex->e_type != ET_EXEC &&
- interp_elf_ex->e_type != ET_DYN) ||
- !elf_check_arch(interp_elf_ex->e_machine)) {
+ if (!elf_check_ehdr(interp_elf_ex)) {
return ~((abi_ulong)0UL);
}
/* Now read in all of the header information */
-
- if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
- return ~(abi_ulong)0UL;
-
elf_phdata = (struct elf_phdr *)
malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
-
if (!elf_phdata)
return ~((abi_ulong)0UL);
- /*
- * If the size of this structure has changed, then punt, since
- * we will be doing the wrong thing.
- */
- if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
- free(elf_phdata);
- return ~((abi_ulong)0UL);
- }
-
i = interp_elf_ex->e_phnum * sizeof(struct elf_phdr);
if (interp_elf_ex->e_phoff + i <= BPRM_BUF_SIZE) {
memcpy(elf_phdata, bprm_buf + interp_elf_ex->e_phoff, i);
@@ -1427,11 +1434,13 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
load_addr = 0;
load_bias = 0;
elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
- bswap_ehdr(&elf_ex);
/* First of all, some simple consistency checks */
- if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
- (! elf_check_arch(elf_ex.e_machine))) {
+ if (!elf_check_ident(&elf_ex)) {
+ return -ENOEXEC;
+ }
+ bswap_ehdr(&elf_ex);
+ if (!elf_check_ehdr(&elf_ex)) {
return -ENOEXEC;
}
@@ -1443,7 +1452,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
}
/* Now read in all of the header information */
- elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
+ elf_phdata = (struct elf_phdr *)
+ malloc(elf_ex.e_phnum * sizeof(struct elf_phdr));
if (elf_phdata == NULL) {
return -ENOMEM;
}
@@ -1548,8 +1558,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
interpreter_type = INTERPRETER_ELF;
}
- if (interp_elf_ex.e_ident[0] != 0x7f ||
- strncmp((char *)&interp_elf_ex.e_ident[1], "ELF",3) != 0) {
+ if (!elf_check_ident(&interp_elf_ex)) {
interpreter_type &= ~INTERPRETER_ELF;
}
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 09/14] linux-user: Put the stack guard page at the top.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (7 preceding siblings ...)
2010-04-04 22:04 ` [Qemu-devel] [PATCH 08/14] linux-user: Improve consistency checking in elf headers Richard Henderson
@ 2010-04-04 22:14 ` Richard Henderson
2010-04-04 22:31 ` [Qemu-devel] [PATCH 10/14] linux-user: Remove partial support for a.out interpreters Richard Henderson
` (18 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-04 22:14 UTC (permalink / raw)
To: qemu-devel
There are no supported stack-grows-up targets. We were putting
the guard page at the highest address, i.e. the bottom of the stack.
Use the maximum of host and guest page size for the guard size.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 29 ++++++++++++++++-------------
1 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 5853a30..464160a 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1002,28 +1002,31 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
struct image_info *info)
{
- abi_ulong stack_base, size, error;
+ abi_ulong stack_base, size, error, guard;
int i;
/* Create enough stack to hold everything. If we don't use
- * it for args, we'll use it for something else...
- */
+ it for args, we'll use it for something else. */
size = guest_stack_size;
- if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
+ if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) {
size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
- error = target_mmap(0,
- size + qemu_host_page_size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- -1, 0);
+ }
+ guard = TARGET_PAGE_SIZE;
+ if (guard < qemu_real_host_page_size) {
+ guard = qemu_real_host_page_size;
+ }
+
+ error = target_mmap(0, size + guard, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (error == -1) {
- perror("stk mmap");
+ perror("mmap stack");
exit(-1);
}
- /* we reserve one extra page at the top of the stack as guard */
- target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
- stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
+ /* We reserve one extra page at the top of the stack as guard. */
+ target_mprotect(error, guard, PROT_NONE);
+
+ stack_base = error + guard + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
p += stack_base;
for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 10/14] linux-user: Remove partial support for a.out interpreters.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (8 preceding siblings ...)
2010-04-04 22:14 ` [Qemu-devel] [PATCH 09/14] linux-user: Put the stack guard page at the top Richard Henderson
@ 2010-04-04 22:31 ` Richard Henderson
2010-04-05 0:46 ` [Qemu-devel] [PATCH 11/14] linux-user: Extract load_elf_image from load_elf_interp Richard Henderson
` (17 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-04 22:31 UTC (permalink / raw)
To: qemu-devel
At the bottom of the a.out support was the unimplemented load_aout_interp
function. There were other portions of the support that didn't look
right; when I went to look in the Linux kernel for clarification, I found
that the support for such interpreters has been removed from binfmt_elf.
There doesn't seem to be any reason to keep this broken support in qemu.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 80 +++++--------------------------------------------
1 files changed, 9 insertions(+), 71 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 464160a..2f15b9c 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -837,10 +837,6 @@ struct exec
#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 12
static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
@@ -848,8 +844,6 @@ static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
memcpy(to, from, n);
}
-static int load_aout_interp(void * exptr, int interp_fd);
-
#ifdef BSWAP_NEEDED
static void bswap_ehdr(struct elfhdr *ehdr)
{
@@ -1087,7 +1081,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
struct elfhdr * exec,
abi_ulong load_addr,
abi_ulong load_bias,
- abi_ulong interp_load_addr, int ibcs,
+ abi_ulong interp_load_addr,
struct image_info *info)
{
abi_ulong sp;
@@ -1117,7 +1111,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
size += DLINFO_ARCH_ITEMS * 2;
#endif
size += envc + argc + 2;
- size += (!ibcs ? 3 : 1); /* argc itself */
+ size += 1; /* argc itself */
size *= n;
if (size & 15)
sp -= 16 - (size & 15);
@@ -1159,7 +1153,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
info->saved_auxv = sp;
- sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
+ sp = loader_build_argptr(envc, argc, sp, p, 0);
return sp;
}
@@ -1412,11 +1406,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
{
struct elfhdr elf_ex;
struct elfhdr interp_elf_ex;
- struct exec interp_ex;
int interpreter_fd = -1; /* avoid warning */
abi_ulong load_addr, load_bias;
int load_addr_set = 0;
- unsigned int interpreter_type = INTERPRETER_NONE;
unsigned char ibcs2_interpreter;
int i;
abi_ulong mapped_addr;
@@ -1430,7 +1422,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
abi_ulong start_code, end_code, start_data, end_data;
abi_ulong reloc_func_desc = 0;
abi_ulong elf_stack;
- char passed_fileno[6];
ibcs2_interpreter = 0;
status = 0;
@@ -1480,7 +1471,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
end_code = 0;
start_data = 0;
end_data = 0;
- interp_ex.a_info = 0;
elf_ppnt = elf_phdata;
for(i=0;i < elf_ex.e_phnum; i++) {
@@ -1545,59 +1535,22 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
memset(bprm->buf, 0, BPRM_BUF_SIZE - retval);
}
- interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
- interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */
+ interp_elf_ex = *((struct elfhdr *) bprm->buf);
}
elf_ppnt++;
}
/* Some simple consistency checks for the interpreter */
- if (elf_interpreter){
- interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
-
- /* Now figure out which format our binary is */
- if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
- (N_MAGIC(interp_ex) != QMAGIC)) {
- interpreter_type = INTERPRETER_ELF;
- }
-
+ if (elf_interpreter) {
if (!elf_check_ident(&interp_elf_ex)) {
- interpreter_type &= ~INTERPRETER_ELF;
- }
-
- if (!interpreter_type) {
free(elf_interpreter);
free(elf_phdata);
close(bprm->fd);
+ close(interpreter_fd);
return -ELIBBAD;
}
}
- /* OK, we are done with that, now set up the arg stuff,
- and then start this sucker up */
-
- {
- char * passed_p;
-
- if (interpreter_type == INTERPRETER_AOUT) {
- snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
- passed_p = passed_fileno;
-
- if (elf_interpreter) {
- bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p);
- bprm->argc++;
- }
- }
- if (!bprm->p) {
- if (elf_interpreter) {
- free(elf_interpreter);
- }
- free (elf_phdata);
- close(bprm->fd);
- return -E2BIG;
- }
- }
-
/* OK, This is the point of no return */
info->end_data = 0;
info->end_code = 0;
@@ -1729,16 +1682,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
end_data += load_bias;
if (elf_interpreter) {
- if (interpreter_type & 1) {
- elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
- }
- else if (interpreter_type & 2) {
- elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
- &interp_load_addr, bprm->buf);
- }
+ elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
+ &interp_load_addr, bprm->buf);
reloc_func_desc = interp_load_addr;
-
- close(interpreter_fd);
free(elf_interpreter);
if (elf_entry == ~((abi_ulong)0UL)) {
@@ -1755,7 +1701,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
load_symbols(&elf_ex, bprm->fd, load_bias);
}
- if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
+ close(bprm->fd);
info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
#ifdef LOW_ELF_STACK
@@ -1767,7 +1713,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
&elf_ex,
load_addr, load_bias,
interp_load_addr,
- (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
info);
info->load_addr = reloc_func_desc;
info->start_brk = info->brk = elf_brk;
@@ -2656,15 +2601,8 @@ static int elf_core_dump(int signr, const CPUState *env)
return (-errno);
return (0);
}
-
#endif /* USE_ELF_CORE_DUMP */
-static int load_aout_interp(void * exptr, int interp_fd)
-{
- printf("a.out interpreter not yet supported\n");
- return(0);
-}
-
void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
{
init_thread(regs, infop);
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 11/14] linux-user: Extract load_elf_image from load_elf_interp.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (9 preceding siblings ...)
2010-04-04 22:31 ` [Qemu-devel] [PATCH 10/14] linux-user: Remove partial support for a.out interpreters Richard Henderson
@ 2010-04-05 0:46 ` Richard Henderson
2010-04-05 2:13 ` [Qemu-devel] [PATCH 14/14] linux-user: Load a VDSO for x86-64 Richard Henderson
` (16 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-05 0:46 UTC (permalink / raw)
To: qemu-devel
Moving toward a single copy of the elf binary loading code.
Fill in the details of the loaded image into a struct image_info.
Adjust create_elf_tables to read from such structures instead
of from a collection of passed arguments. Don't return error
values from load_elf_interp; always exit(-1) with a message to
stderr. Collect elf_interpreter handling in load_elf_binary
to a common spot.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 341 ++++++++++++++++++++++++-------------------------
1 files changed, 167 insertions(+), 174 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 2f15b9c..c58387a 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1078,11 +1078,9 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
}
static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
- struct elfhdr * exec,
- abi_ulong load_addr,
- abi_ulong load_bias,
- abi_ulong interp_load_addr,
- struct image_info *info)
+ struct elfhdr *exec,
+ struct image_info *info,
+ struct image_info *interp_info)
{
abi_ulong sp;
int size;
@@ -1127,13 +1125,13 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
NEW_AUX_ENT (AT_NULL, 0);
/* There must be exactly DLINFO_ITEMS entries here. */
- NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
+ NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff));
NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
- NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
+ NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info->load_addr));
NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
- NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
+ NEW_AUX_ENT(AT_ENTRY, info->entry);
NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
@@ -1157,51 +1155,60 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
return sp;
}
+/* Load an ELF image into the address space.
-static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
- int interpreter_fd,
- abi_ulong *interp_load_addr,
- char bprm_buf[BPRM_BUF_SIZE])
+ IMAGE_NAME is the filename of the image, to use in error messages.
+ IMAGE_FD is the open file descriptor for the image.
+
+ BUFPAGE is a copy of the first page of the file; this of course
+ contains the elf file header at offset 0. It is assumed that this
+ buffer is sufficiently aligned to present no problems to the host
+ in accessing data at aligned offsets within the buffer.
+
+ 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,
+ char bprm_buf[BPRM_BUF_SIZE])
{
- struct elf_phdr *elf_phdata = NULL;
- abi_ulong load_addr, load_bias, loaddr, hiaddr;
- int retval;
- abi_ulong error;
- int i;
+ struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
+ struct elf_phdr *phdr;
+ abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
+ int i, retval;
+ const char *errmsg;
- bswap_ehdr(interp_elf_ex);
- if (!elf_check_ehdr(interp_elf_ex)) {
- return ~((abi_ulong)0UL);
+ /* First of all, some simple consistency checks */
+ errmsg = "Invalid ELF image for this architecture";
+ if (!elf_check_ident(ehdr)) {
+ goto exit_errmsg;
+ }
+ bswap_ehdr(ehdr);
+ if (!elf_check_ehdr(ehdr)) {
+ goto exit_errmsg;
}
- /* Now read in all of the header information */
- elf_phdata = (struct elf_phdr *)
- malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
- if (!elf_phdata)
- return ~((abi_ulong)0UL);
-
- i = interp_elf_ex->e_phnum * sizeof(struct elf_phdr);
- if (interp_elf_ex->e_phoff + i <= BPRM_BUF_SIZE) {
- memcpy(elf_phdata, bprm_buf + interp_elf_ex->e_phoff, i);
+ i = ehdr->e_phnum * sizeof(struct elf_phdr);
+ if (ehdr->e_phoff + i <= BPRM_BUF_SIZE) {
+ phdr = (struct elf_phdr *)(bprm_buf + ehdr->e_phoff);
} else {
- retval = pread(interpreter_fd, elf_phdata, i, interp_elf_ex->e_phoff);
+ phdr = (struct elf_phdr *) alloca(i);
+ retval = pread(image_fd, phdr, i, ehdr->e_phoff);
if (retval != i) {
- perror("load_elf_interp");
- exit(-1);
+ goto exit_read;
}
}
- bswap_phdr(elf_phdata, interp_elf_ex->e_phnum);
+ bswap_phdr(phdr, ehdr->e_phnum);
/* Find the maximum size of the image and allocate an appropriate
amount of memory to handle that. */
loaddr = -1, hiaddr = 0;
- for (i = 0; i < interp_elf_ex->e_phnum; ++i) {
- if (elf_phdata[i].p_type == PT_LOAD) {
- abi_ulong a = elf_phdata[i].p_vaddr;
+ for (i = 0; i < ehdr->e_phnum; ++i) {
+ if (phdr[i].p_type == PT_LOAD) {
+ abi_ulong a = phdr[i].p_vaddr;
if (a < loaddr) {
loaddr = a;
}
- a += elf_phdata[i].p_memsz;
+ a += phdr[i].p_memsz;
if (a > hiaddr) {
hiaddr = a;
}
@@ -1209,7 +1216,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
}
load_addr = loaddr;
- if (interp_elf_ex->e_type == ET_DYN) {
+ if (ehdr->e_type == ET_DYN) {
/* The image indicates that it can be loaded anywhere. Find a
location that can hold the memory space required. If the
image is pre-linked, LOADDR will be non-zero. Since we do
@@ -1219,14 +1226,22 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
-1, 0);
if (load_addr == -1) {
- perror("mmap");
- exit(-1);
+ goto exit_perror;
}
}
load_bias = load_addr - loaddr;
- for (i = 0; i < interp_elf_ex->e_phnum; i++) {
- struct elf_phdr *eppnt = elf_phdata + i;
+ info->load_bias = load_bias;
+ info->load_addr = load_addr;
+ info->entry = ehdr->e_entry + load_bias;
+ info->start_code = -1;
+ info->end_code = 0;
+ info->start_data = -1;
+ info->end_data = 0;
+ info->brk = 0;
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ struct elf_phdr *eppnt = phdr + i;
if (eppnt->p_type == PT_LOAD) {
abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em;
int elf_prot = 0;
@@ -1241,12 +1256,9 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
elf_prot, MAP_PRIVATE | MAP_FIXED,
- interpreter_fd, eppnt->p_offset - vaddr_po);
+ image_fd, eppnt->p_offset - vaddr_po);
if (error == -1) {
- /* Real error */
- close(interpreter_fd);
- free(elf_phdata);
- return ~((abi_ulong)0UL);
+ goto exit_perror;
}
vaddr_ef = vaddr + eppnt->p_filesz;
@@ -1256,18 +1268,79 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
if (vaddr_ef < vaddr_em) {
zero_bss(vaddr_ef, vaddr_em, elf_prot);
}
+
+ /* Find the full program boundaries. */
+ if (elf_prot & PROT_EXEC) {
+ if (vaddr < info->start_code) {
+ info->start_code = vaddr;
+ }
+ if (vaddr_ef > info->end_code) {
+ info->end_code = vaddr_ef;
+ }
+ }
+ if (elf_prot & PROT_WRITE) {
+ if (vaddr < info->start_data) {
+ info->start_data = vaddr;
+ }
+ if (vaddr_ef > info->end_data) {
+ info->end_data = vaddr_ef;
+ }
+ if (vaddr_em > info->brk) {
+ info->brk = vaddr_em;
+ }
+ }
}
}
+ if (info->end_data == 0) {
+ info->start_data = info->end_code;
+ info->end_data = info->end_code;
+ info->brk = info->end_code;
+ }
+
if (qemu_log_enabled()) {
- load_symbols(interp_elf_ex, interpreter_fd, load_bias);
+ load_symbols(ehdr, image_fd, load_bias);
}
- close(interpreter_fd);
- free(elf_phdata);
+ close(image_fd);
+ return;
+
+ exit_read:
+ if (retval >= 0) {
+ errmsg = "Incomplete read of file header";
+ goto exit_errmsg;
+ }
+ exit_perror:
+ errmsg = strerror(errno);
+ exit_errmsg:
+ fprintf(stderr, "%s: %s\n", image_name, errmsg);
+ exit(-1);
+}
+
+static void load_elf_interp(const char *filename, struct image_info *info,
+ char bprm_buf[BPRM_BUF_SIZE])
+{
+ int fd, retval;
+
+ fd = open(path(filename), O_RDONLY);
+ if (fd < 0) {
+ goto exit_perror;
+ }
- *interp_load_addr = load_addr;
- return ((abi_ulong) interp_elf_ex->e_entry) + load_bias;
+ retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
+ if (retval < 0) {
+ goto exit_perror;
+ }
+ if (retval < BPRM_BUF_SIZE) {
+ memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
+ }
+
+ load_elf_image(filename, fd, info, bprm_buf);
+ return;
+
+ exit_perror:
+ fprintf(stderr, "%s: %s\n", filename, strerror(errno));
+ exit(-1);
}
static int symfind(const void *s0, const void *s1)
@@ -1404,26 +1477,21 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
struct image_info * info)
{
+ struct image_info interp_info;
struct elfhdr elf_ex;
- struct elfhdr interp_elf_ex;
- int interpreter_fd = -1; /* avoid warning */
abi_ulong load_addr, load_bias;
int load_addr_set = 0;
- unsigned char ibcs2_interpreter;
int i;
- abi_ulong mapped_addr;
struct elf_phdr * elf_ppnt;
struct elf_phdr *elf_phdata;
abi_ulong k, elf_brk;
int retval;
- char * elf_interpreter;
- abi_ulong elf_entry, interp_load_addr = 0;
+ char *elf_interpreter = NULL;
+ abi_ulong elf_entry;
int status;
abi_ulong start_code, end_code, start_data, end_data;
- abi_ulong reloc_func_desc = 0;
abi_ulong elf_stack;
- ibcs2_interpreter = 0;
status = 0;
load_addr = 0;
load_bias = 0;
@@ -1466,7 +1534,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
elf_brk = 0;
elf_stack = ~((abi_ulong)0UL);
- elf_interpreter = NULL;
start_code = ~((abi_ulong)0UL);
end_code = 0;
start_data = 0;
@@ -1475,82 +1542,21 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
elf_ppnt = elf_phdata;
for(i=0;i < elf_ex.e_phnum; i++) {
if (elf_ppnt->p_type == PT_INTERP) {
- if ( elf_interpreter != NULL )
- {
- free (elf_phdata);
- free(elf_interpreter);
- close(bprm->fd);
- return -EINVAL;
- }
-
- /* This is the program interpreter used for
- * shared libraries - for now assume that this
- * is an a.out format binary
- */
-
- elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
-
- if (elf_interpreter == NULL) {
- free (elf_phdata);
- close(bprm->fd);
- return -ENOMEM;
- }
-
if (elf_ppnt->p_offset + elf_ppnt->p_filesz <= BPRM_BUF_SIZE) {
- memcpy(elf_interpreter, bprm->buf + elf_ppnt->p_offset,
- elf_ppnt->p_filesz);
+ 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_binary2");
+ perror("load_elf_binary");
exit(-1);
}
}
-
- /* If the program interpreter is one of these two,
- then assume an iBCS2 image. Otherwise assume
- a native linux image. */
-
- /* JRP - Need to add X86 lib dir stuff here... */
-
- if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
- strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
- ibcs2_interpreter = 1;
- }
-
- retval = open(path(elf_interpreter), O_RDONLY);
- if (retval < 0) {
- perror(elf_interpreter);
- exit(-1);
- }
- interpreter_fd = retval;
-
- retval = read(interpreter_fd, bprm->buf, BPRM_BUF_SIZE);
- if (retval < 0) {
- perror("load_elf_binary3");
- exit(-1);
- }
- if (retval < BPRM_BUF_SIZE) {
- memset(bprm->buf, 0, BPRM_BUF_SIZE - retval);
- }
-
- interp_elf_ex = *((struct elfhdr *) bprm->buf);
}
elf_ppnt++;
}
- /* Some simple consistency checks for the interpreter */
- if (elf_interpreter) {
- if (!elf_check_ident(&interp_elf_ex)) {
- free(elf_interpreter);
- free(elf_phdata);
- close(bprm->fd);
- close(interpreter_fd);
- return -ELIBBAD;
- }
- }
-
/* OK, This is the point of no return */
info->end_data = 0;
info->end_code = 0;
@@ -1648,7 +1654,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
load_bias += error -
TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
load_addr += load_bias;
- reloc_func_desc = load_bias;
}
}
k = elf_ppnt->p_vaddr;
@@ -1681,19 +1686,15 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
start_data += load_bias;
end_data += load_bias;
- if (elf_interpreter) {
- elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
- &interp_load_addr, bprm->buf);
- reloc_func_desc = interp_load_addr;
- free(elf_interpreter);
-
- if (elf_entry == ~((abi_ulong)0UL)) {
- printf("Unable to load interpreter\n");
- free(elf_phdata);
- exit(-1);
- return 0;
- }
- }
+ 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);
@@ -1702,46 +1703,38 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
}
close(bprm->fd);
- info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
-#ifdef LOW_ELF_STACK
- info->start_stack = bprm->p = elf_stack - 4;
-#endif
- bprm->p = create_elf_tables(bprm->p,
- bprm->argc,
- bprm->envc,
- &elf_ex,
- load_addr, load_bias,
- interp_load_addr,
- info);
- info->load_addr = reloc_func_desc;
- 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->start_stack = bprm->p;
+ if (elf_interpreter) {
+ load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
-#if 0
- printf("(start_brk) %x\n" , info->start_brk);
- printf("(end_code) %x\n" , info->end_code);
- printf("(start_code) %x\n" , info->start_code);
- printf("(end_data) %x\n" , info->end_data);
- printf("(start_stack) %x\n" , info->start_stack);
- printf("(brk) %x\n" , info->brk);
-#endif
+ /* If the program interpreter is one of these two, then assume
+ an iBCS2 image. Otherwise assume a native linux image. */
- if ( info->personality == PER_SVR4 )
- {
- /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
- and some applications "depend" upon this behavior.
- Since we do not have the power to recompile these, we
- emulate the SVr4 behavior. Sigh. */
- mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE, -1, 0);
+ if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0
+ || strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) {
+ info->personality = PER_SVR4;
+
+ /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
+ and some applications "depend" upon this behavior. Since
+ we do not have the power to recompile these, we emulate
+ the SVr4 behavior. Sigh. */
+ target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE, -1, 0);
+ }
}
- info->entry = elf_entry;
+ bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &elf_ex,
+ info, (elf_interpreter ? &interp_info : NULL));
+ info->start_stack = bprm->p;
+
+ /* If we have an interpreter, set that as the program's entry point.
+ Copy the load_addr as well, to help PPC64 interpret the entry
+ point as a function descriptor. Do this after creating elf tables
+ so that we copy the original program entry point into the AUXV. */
+ if (elf_interpreter) {
+ info->load_addr = interp_info.load_addr;
+ info->entry = interp_info.entry;
+ }
#ifdef USE_ELF_CORE_DUMP
bprm->core_dump = &elf_core_dump;
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 14/14] linux-user: Load a VDSO for x86-64.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (10 preceding siblings ...)
2010-04-05 0:46 ` [Qemu-devel] [PATCH 11/14] linux-user: Extract load_elf_image from load_elf_interp Richard Henderson
@ 2010-04-05 2:13 ` Richard Henderson
2010-04-05 16:26 ` [Qemu-devel] [PATCH 02/14] Add more DT_* and AT_* constants to qemu's copy of elf.h Richard Henderson
` (15 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-05 2:13 UTC (permalink / raw)
To: qemu-devel
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 193 insertions(+), 8 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 100efdc..7b854e2 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -183,6 +183,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
(*regs)[26] = env->segs[R_GS].selector & 0xffff;
}
+#define VDSO_BASENAME "vdso-linux-x64.so"
+
#else
#define ELF_START_MMAP 0x80000000
@@ -801,6 +803,10 @@ static inline void init_thread(struct target_pt_regs *regs,
#define ELF_HWCAP 0
#endif
+#ifndef VDSO_BASENAME
+#define VDSO_BASENAME NULL
+#endif
+
#ifdef TARGET_ABI32
#undef ELF_CLASS
#define ELF_CLASS ELFCLASS32
@@ -1077,7 +1083,8 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
struct elfhdr *exec,
struct image_info *info,
- struct image_info *interp_info)
+ struct image_info *interp_info,
+ struct image_info *vdso_info)
{
abi_ulong sp;
int size;
@@ -1100,16 +1107,21 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
*/
sp = sp &~ (abi_ulong)15;
size = (DLINFO_ITEMS + 1) * 2;
- if (k_platform)
+ if (k_platform) {
size += 2;
+ }
+ if (vdso_info) {
+ size += 4;
+ }
#ifdef DLINFO_ARCH_ITEMS
size += DLINFO_ARCH_ITEMS * 2;
#endif
size += envc + argc + 2;
size += 1; /* argc itself */
size *= n;
- if (size & 15)
+ if (size & 15) {
sp -= 16 - (size & 15);
+ }
/* This is correct because Linux defines
* elf_addr_t as Elf32_Off / Elf64_Off
@@ -1126,7 +1138,9 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
- NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info->load_addr));
+ if (interp_info) {
+ NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info->load_addr));
+ }
NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
NEW_AUX_ENT(AT_ENTRY, info->entry);
NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
@@ -1135,8 +1149,13 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
- if (k_platform)
+ if (k_platform) {
NEW_AUX_ENT(AT_PLATFORM, u_platform);
+ }
+ if (vdso_info) {
+ NEW_AUX_ENT(AT_SYSINFO, vdso_info->entry);
+ NEW_AUX_ENT(AT_SYSINFO_EHDR, vdso_info->load_addr);
+ }
#ifdef ARCH_DLINFO
/*
* ARCH_DLINFO must come last so platform specific code can enforce
@@ -1378,6 +1397,165 @@ static void load_elf_interp(const char *filename, struct image_info *info,
exit(-1);
}
+static void load_elf_vdso(const char *basename, struct image_info *info,
+ char bprm_buf[BPRM_BUF_SIZE])
+{
+ const char *errmsg;
+ char *filename;
+ int fd, retval, i;
+ abi_ulong load_bias;
+
+ /* ??? What we really need access to is qemu_find_file, but that is
+ only built for system targets at the moment. */
+ filename = alloca(strlen(CONFIG_QEMU_SHAREDIR "/") + strlen(basename) + 1);
+ stpcpy(stpcpy(filename, CONFIG_QEMU_SHAREDIR "/"), basename);
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ goto exit_perror;
+ }
+
+ retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
+ if (retval < 0) {
+ goto exit_perror;
+ }
+ if (retval < BPRM_BUF_SIZE) {
+ memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
+ }
+
+ load_elf_image(basename, fd, info, NULL, bprm_buf);
+ load_bias = info->load_bias;
+
+ /* We most likely need to relocate the VDSO image. The one built into
+ the kernel is built for a fixed address. The one built for QEMU is
+ not, since that requires close control of the guest address space. */
+ if (load_bias) {
+ struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
+ struct elf_phdr *phdr;
+ abi_ulong dynamic_addr = -1;
+ abi_ulong dynsym_addr = -1;
+
+ /* ??? Assume QEMU's VDSO is built "properly", which arranges
+ for the PHDRs, and all the sections manipulated below, to
+ be included with a writable load segment. */
+
+ /* ??? One might think that we'd need to relocate ehdr.e_entry,
+ but for some reason glibc does that one itself, though that
+ is also available via the AT_SYSINFO entry. */
+
+ /* Relocate the program headers. */
+ phdr = (struct elf_phdr *)g2h(info->load_addr + ehdr->e_phoff);
+ bswap_phdr(phdr, ehdr->e_phnum);
+ for (i = 0; i < ehdr->e_phnum; ++i) {
+ phdr[i].p_vaddr += load_bias;
+ phdr[i].p_paddr += load_bias;
+ if (phdr[i].p_type == PT_DYNAMIC) {
+ dynamic_addr = phdr[i].p_vaddr;
+ }
+ }
+ bswap_phdr(phdr, ehdr->e_phnum);
+
+ /* Relocate the DYNAMIC entries. */
+ if (dynamic_addr != -1) {
+ abi_ulong tag, val, *dyn = (abi_ulong *)g2h(dynamic_addr);
+ do {
+ tag = tswapl(dyn[0]);
+ val = tswapl(dyn[1]);
+ switch (tag) {
+ case DT_SYMTAB:
+ dynsym_addr = load_bias + val;
+ dyn[1] = tswapl(dynsym_addr);
+ break;
+ case DT_SYMENT:
+ if (val != sizeof(struct elf_sym)) {
+ errmsg = "VDSO has an unexpected dynamic symbol size";
+ goto exit_errmsg;
+ }
+ break;
+
+ case DT_HASH:
+ case DT_STRTAB:
+ case DT_VERDEF:
+ case DT_VERSYM:
+ case DT_ADDRRNGLO ... DT_ADDRRNGHI:
+ /* These entries store an address in the entry. */
+ dyn[1] = tswapl(load_bias + val);
+ break;
+
+ case DT_NULL:
+ case DT_STRSZ:
+ case DT_SONAME:
+ case DT_DEBUG:
+ case DT_FLAGS:
+ case DT_FLAGS_1:
+ case DT_VERDEFNUM:
+ case DT_VALRNGLO ... DT_VALRNGHI:
+ /* These entries store an integer in the entry. */
+ break;
+
+ case DT_REL:
+ case DT_RELA:
+ /* These entries indicate that the VDSO was built
+ incorrectly. It should not have real relocations. */
+ errmsg = "VDSO has relocations";
+ goto exit_errmsg;
+ case DT_NEEDED:
+ case DT_VERNEED:
+ errmsg = "VDSO has external dependancies";
+ goto exit_errmsg;
+
+ default:
+ /* This is probably something target specific. */
+ errmsg = "VDSO has unknown DYNAMIC entry";
+ goto exit_errmsg;
+ }
+ dyn += 2;
+ } while (tag != DT_NULL);
+ }
+
+ /* Relocate the dynamic symbol table. */
+ if (dynsym_addr != -1) {
+ struct elf_shdr *shdr;
+ struct elf_sym *sym;
+ int dynsym_size = 0;
+
+ /* Read the section headers to find out the size of the
+ dynamic symbol table. */
+ shdr = (struct elf_shdr *)g2h(info->load_addr + ehdr->e_shoff);
+ for (i = 0; i < ehdr->e_shnum; ++i) {
+ abi_ulong addr = tswapl(shdr[i].sh_addr) + load_bias;
+ if (addr == dynsym_addr) {
+ dynsym_size = tswapl(shdr[i].sh_size);
+ break;
+ }
+ }
+
+ sym = (struct elf_sym *)g2h(dynsym_addr);
+ for (i = 0; i < dynsym_size / sizeof(*sym); ++i) {
+ sym[i].st_value = tswapl(tswapl(sym[i].st_value) + load_bias);
+ }
+ }
+ }
+
+ /* Mark the VDSO writable segment read-only. */
+ /* ??? This assumes that the VDSO implementation doesn't actually
+ have any truely writable data. Perhaps we should instead use
+ the PT_GNU_RELRO header to indicate that we really want this. */
+ retval = target_mprotect(info->start_data, info->brk - info->start_data,
+ PROT_READ);
+ if (retval < 0) {
+ goto exit_perror;
+ }
+ return;
+
+ exit_perror:
+ errmsg = strerror(errno);
+ exit_errmsg:
+ fprintf(stderr, "%s: %s\n", filename, errmsg);
+ exit(-1);
+}
+
+
static int symfind(const void *s0, const void *s1)
{
struct elf_sym *key = (struct elf_sym *)s0;
@@ -1512,7 +1690,7 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
struct image_info * info)
{
- struct image_info interp_info;
+ struct image_info interp_info, vdso_info;
struct elfhdr elf_ex;
char *elf_interpreter = NULL;
@@ -1559,8 +1737,15 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
}
}
- bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &elf_ex,
- info, (elf_interpreter ? &interp_info : NULL));
+ /* If we've been given a VDSO to load, do so. */
+ if (VDSO_BASENAME) {
+ load_elf_vdso(VDSO_BASENAME, &vdso_info, bprm->buf);
+ }
+
+ bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc,
+ &elf_ex, info,
+ (elf_interpreter ? &interp_info : NULL),
+ (VDSO_BASENAME ? &vdso_info : NULL));
info->start_stack = bprm->p;
/* If we have an interpreter, set that as the program's entry point.
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 02/14] Add more DT_* and AT_* constants to qemu's copy of elf.h.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (11 preceding siblings ...)
2010-04-05 2:13 ` [Qemu-devel] [PATCH 14/14] linux-user: Load a VDSO for x86-64 Richard Henderson
@ 2010-04-05 16:26 ` Richard Henderson
2010-04-05 16:37 ` [Qemu-devel] [PATCH 12/14] linux-user: Re-use load_elf_image for the main binary Richard Henderson
` (14 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-05 16:26 UTC (permalink / raw)
To: qemu-devel
Moving some PPC AT_* constants from elfload.c at the same time.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
elf.h | 44 ++++++++++++++++++++++++++++++++++++++++++++
linux-user/elfload.c | 9 ---------
2 files changed, 44 insertions(+), 9 deletions(-)
diff --git a/elf.h b/elf.h
index c84c8ab..012532c 100644
--- a/elf.h
+++ b/elf.h
@@ -146,8 +146,37 @@ typedef int64_t Elf64_Sxword;
#define DT_DEBUG 21
#define DT_TEXTREL 22
#define DT_JMPREL 23
+#define DT_BINDNOW 24
+#define DT_INIT_ARRAY 25
+#define DT_FINI_ARRAY 26
+#define DT_INIT_ARRAYSZ 27
+#define DT_FINI_ARRAYSZ 28
+#define DT_RUNPATH 29
+#define DT_FLAGS 30
+#define DT_LOOS 0x6000000d
+#define DT_HIOS 0x6ffff000
#define DT_LOPROC 0x70000000
#define DT_HIPROC 0x7fffffff
+
+/* DT_ entries which fall between DT_VALRNGLO and DT_VALRNDHI use
+ the d_val field of the Elf*_Dyn structure. I.e. they contain scalars. */
+#define DT_VALRNGLO 0x6ffffd00
+#define DT_VALRNGHI 0x6ffffdff
+
+/* DT_ entries which fall between DT_ADDRRNGLO and DT_ADDRRNGHI use
+ the d_ptr field of the Elf*_Dyn structure. I.e. they contain pointers. */
+#define DT_ADDRRNGLO 0x6ffffe00
+#define DT_ADDRRNGHI 0x6ffffeff
+
+#define DT_VERSYM 0x6ffffff0
+#define DT_RELACOUNT 0x6ffffff9
+#define DT_RELCOUNT 0x6ffffffa
+#define DT_FLAGS_1 0x6ffffffb
+#define DT_VERDEF 0x6ffffffc
+#define DT_VERDEFNUM 0x6ffffffd
+#define DT_VERNEED 0x6ffffffe
+#define DT_VERNEEDNUM 0x6fffffff
+
#define DT_MIPS_RLD_VERSION 0x70000001
#define DT_MIPS_TIME_STAMP 0x70000002
#define DT_MIPS_ICHECKSUM 0x70000003
@@ -206,6 +235,21 @@ typedef int64_t Elf64_Sxword;
#define AT_PLATFORM 15 /* string identifying CPU for optimizations */
#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */
#define AT_CLKTCK 17 /* frequency at which times() increments */
+#define AT_FPUCW 18 /* info about fpu initialization by kernel */
+#define AT_DCACHEBSIZE 19 /* data cache block size */
+#define AT_ICACHEBSIZE 20 /* instruction cache block size */
+#define AT_UCACHEBSIZE 21 /* unified cache block size */
+#define AT_IGNOREPPC 22 /* ppc only; entry should be ignored */
+#define AT_SECURE 23 /* boolean, was exec suid-like? */
+#define AT_BASE_PLATFORM 24 /* string identifying real platforms */
+#define AT_RANDOM 25 /* address of 16 random bytes */
+#define AT_EXECFN 31 /* filename of the executable */
+#define AT_SYSINFO 32 /* address of kernel entry point */
+#define AT_SYSINFO_EHDR 33 /* address of kernel vdso */
+#define AT_L1I_CACHESHAPE 34 /* shapes of the caches: */
+#define AT_L1D_CACHESHAPE 35 /* bits 0-3: cache associativity. */
+#define AT_L2_CACHESHAPE 36 /* bits 4-7: log2 of line size. */
+#define AT_L3_CACHESHAPE 37 /* val&~255: cache size. */
typedef struct dynamic{
Elf32_Sword d_tag;
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 238e574..ead22fc 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -480,15 +480,6 @@ static uint32_t get_elf_hwcap(void)
}
/*
- * 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
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 12/14] linux-user: Re-use load_elf_image for the main binary.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (12 preceding siblings ...)
2010-04-05 16:26 ` [Qemu-devel] [PATCH 02/14] Add more DT_* and AT_* constants to qemu's copy of elf.h Richard Henderson
@ 2010-04-05 16:37 ` Richard Henderson
2010-04-05 18:14 ` malc
2010-04-28 19:36 ` [Qemu-devel] [PATCH 00/14] Implement VDSO for x86-64-linux-user, v2 Richard Henderson
` (13 subsequent siblings)
27 siblings, 1 reply; 46+ messages in thread
From: Richard Henderson @ 2010-04-05 16:37 UTC (permalink / raw)
To: qemu-devel
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 <rth@twiddle.net>
---
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);
+
+ 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,
+ 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
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* Re: [Qemu-devel] [PATCH 12/14] linux-user: Re-use load_elf_image for the main binary.
2010-04-05 16:37 ` [Qemu-devel] [PATCH 12/14] linux-user: Re-use load_elf_image for the main binary Richard Henderson
@ 2010-04-05 18:14 ` malc
2010-04-05 18:38 ` Richard Henderson
0 siblings, 1 reply; 46+ messages in thread
From: malc @ 2010-04-05 18:14 UTC (permalink / raw)
To: Richard Henderson; +Cc: qemu-devel
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 <rth@twiddle.net>
> ---
> 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:av1474@comtv.ru
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [Qemu-devel] [PATCH 12/14] linux-user: Re-use load_elf_image for the main binary.
2010-04-05 18:14 ` malc
@ 2010-04-05 18:38 ` Richard Henderson
0 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-05 18:38 UTC (permalink / raw)
To: malc; +Cc: qemu-devel
On 04/05/2010 11:14 AM, malc wrote:
>> + }
>> + 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.
Huh. I suspect that the whitespace fixup patch should have also
eliminated tabs. I don't know how else that could have crept in
there, since I have tab-expansion enabled in emacs.
I'll incorporate the following into the next version.
r~
---
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 7b854e2..e8eca86 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1327,12 +1327,15 @@ static void load_elf_image(const char *image_name, int image_fd,
goto exit_errmsg;
}
interp_name = malloc(eppnt->p_filesz);
+ if (!interp_name) {
+ goto exit_perror;
+ }
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,
+ retval = pread(image_fd, interp_name, eppnt->p_filesz,
eppnt->p_offset);
if (retval != eppnt->p_filesz) {
goto exit_perror;
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 00/14] Implement VDSO for x86-64-linux-user, v2
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (13 preceding siblings ...)
2010-04-05 16:37 ` [Qemu-devel] [PATCH 12/14] linux-user: Re-use load_elf_image for the main binary Richard Henderson
@ 2010-04-28 19:36 ` Richard Henderson
2010-04-28 19:39 ` [Qemu-devel] [PATCH 04/14] linux-user: Reduce lseek+reads while loading elf files Richard Henderson
` (13 more replies)
2010-05-05 18:07 ` [Qemu-devel] [PATCH 00/12] Cleanup linux-user/elfload.c, v2 Richard Henderson
` (12 subsequent siblings)
27 siblings, 14 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-28 19:36 UTC (permalink / raw)
To: qemu-devel
Changes v1->v2
* Formatting bugs pointed out by malc.
r~
Richard Henderson (14):
linux-user: Handle filesz < memsz for any PT_LOAD segment.
Add more DT_* and AT_* constants to qemu's copy of elf.h.
linux-user: Reindent elfload.c.
linux-user: Reduce lseek+reads while loading elf files.
linux-user: Fix ELF_DATA for Alpha.
linux-user: Clean up byte-swapping in elfload.c.
linux-user: Load symbols from the interpreter.
linux-user: Improve consistency checking in elf headers.
linux-user: Put the stack guard page at the top.
linux-user: Remove partial support for a.out interpreters.
linux-user: Extract load_elf_image from load_elf_interp.
linux-user: Re-use load_elf_image for the main binary.
linux-user: Build vdso for x64.
linux-user: Load a VDSO for x86-64.
Makefile | 3 +-
elf.h | 44 ++
linux-user/elfload.c | 1686 +++++++++++++++++++++------------------------
linux-user/linuxload.c | 17 +-
linux-user/qemu.h | 7 +-
pc-bios/Makefile | 5 +
pc-bios/vdso-linux-x64.S | 102 +++
pc-bios/vdso-linux-x64.ld | 81 +++
pc-bios/vdso-linux-x64.so | Bin 0 -> 7515 bytes
9 files changed, 1040 insertions(+), 905 deletions(-)
create mode 100644 pc-bios/vdso-linux-x64.S
create mode 100644 pc-bios/vdso-linux-x64.ld
create mode 100755 pc-bios/vdso-linux-x64.so
^ permalink raw reply [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 04/14] linux-user: Reduce lseek+reads while loading elf files.
2010-04-28 19:36 ` [Qemu-devel] [PATCH 00/14] Implement VDSO for x86-64-linux-user, v2 Richard Henderson
@ 2010-04-28 19:39 ` Richard Henderson
2010-04-28 19:39 ` [Qemu-devel] [PATCH 01/14] linux-user: Handle filesz < memsz for any PT_LOAD segment Richard Henderson
` (12 subsequent siblings)
13 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-28 19:39 UTC (permalink / raw)
To: qemu-devel
Define BPRM_BUF_SIZE to 4k and read that amount initially. If the
data we want from the binary is in this buffer, use it instead of
reading from the file again.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 105 ++++++++++++++++++++---------------------------
linux-user/linuxload.c | 17 +++-----
linux-user/qemu.h | 7 +++-
3 files changed, 58 insertions(+), 71 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index ab741fd..962f9ba 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1140,7 +1140,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
int interpreter_fd,
- abi_ulong *interp_load_addr)
+ abi_ulong *interp_load_addr,
+ char bprm_buf[BPRM_BUF_SIZE])
{
struct elf_phdr *elf_phdata = NULL;
struct elf_phdr *eppnt;
@@ -1183,17 +1184,15 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
return ~((abi_ulong)0UL);
}
- retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
- if(retval >= 0) {
- retval = read(interpreter_fd,
- (char *) elf_phdata,
- sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
- }
- if (retval < 0) {
- perror("load_elf_interp");
- exit(-1);
- free (elf_phdata);
- return retval;
+ i = interp_elf_ex->e_phnum * sizeof(struct elf_phdr);
+ if (interp_elf_ex->e_phoff + i <= BPRM_BUF_SIZE) {
+ memcpy(elf_phdata, bprm_buf + interp_elf_ex->e_phoff, i);
+ } else {
+ retval = pread(interpreter_fd, elf_phdata, i, interp_elf_ex->e_phoff);
+ if (retval != i) {
+ perror("load_elf_interp");
+ exit(-1);
+ }
}
#ifdef BSWAP_NEEDED
eppnt = elf_phdata;
@@ -1451,17 +1450,15 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
return -ENOMEM;
}
- retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
- if(retval > 0) {
- retval = read(bprm->fd, (char *) elf_phdata,
- elf_ex.e_phentsize * elf_ex.e_phnum);
- }
-
- if (retval < 0) {
- perror("load_elf_binary");
- exit(-1);
- free (elf_phdata);
- return -errno;
+ 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);
+ }
}
#ifdef BSWAP_NEEDED
@@ -1505,13 +1502,16 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
return -ENOMEM;
}
- retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
- if(retval >= 0) {
- retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
- }
- if(retval < 0) {
- perror("load_elf_binary2");
- exit(-1);
+ if (elf_ppnt->p_offset + elf_ppnt->p_filesz <= BPRM_BUF_SIZE) {
+ memcpy(elf_interpreter, bprm->buf + elf_ppnt->p_offset,
+ elf_ppnt->p_filesz);
+ } else {
+ retval = pread(bprm->fd, elf_interpreter, elf_ppnt->p_filesz,
+ elf_ppnt->p_offset);
+ if (retval != elf_ppnt->p_filesz) {
+ perror("load_elf_binary2");
+ exit(-1);
+ }
}
/* If the program interpreter is one of these two,
@@ -1525,39 +1525,24 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
ibcs2_interpreter = 1;
}
-#if 0
- printf("Using ELF interpreter %s\n", path(elf_interpreter));
-#endif
- if (retval >= 0) {
- retval = open(path(elf_interpreter), O_RDONLY);
- if(retval >= 0) {
- interpreter_fd = retval;
- }
- else {
- perror(elf_interpreter);
- exit(-1);
- /* retval = -errno; */
- }
- }
+ retval = open(path(elf_interpreter), O_RDONLY);
+ if (retval < 0) {
+ perror(elf_interpreter);
+ exit(-1);
+ }
+ interpreter_fd = retval;
- if (retval >= 0) {
- retval = lseek(interpreter_fd, 0, SEEK_SET);
- if(retval >= 0) {
- retval = read(interpreter_fd,bprm->buf,128);
- }
- }
- if (retval >= 0) {
- interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
- interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */
- }
- if (retval < 0) {
+ retval = read(interpreter_fd, bprm->buf, BPRM_BUF_SIZE);
+ if (retval < 0) {
perror("load_elf_binary3");
exit(-1);
- free (elf_phdata);
- free(elf_interpreter);
- close(bprm->fd);
- return retval;
}
+ if (retval < BPRM_BUF_SIZE) {
+ memset(bprm->buf, 0, BPRM_BUF_SIZE - retval);
+ }
+
+ interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
+ interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */
}
elf_ppnt++;
}
@@ -1746,7 +1731,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
}
else if (interpreter_type & 2) {
elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
- &interp_load_addr);
+ &interp_load_addr, bprm->buf);
}
reloc_func_desc = interp_load_addr;
diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
index 13ad9aa..9ee27c3 100644
--- a/linux-user/linuxload.c
+++ b/linux-user/linuxload.c
@@ -96,18 +96,16 @@ static int prepare_binprm(struct linux_binprm *bprm)
}
}
- retval = lseek(bprm->fd, 0L, SEEK_SET);
- if(retval >= 0) {
- retval = read(bprm->fd, bprm->buf, 128);
- }
- if(retval < 0) {
+ retval = read(bprm->fd, bprm->buf, BPRM_BUF_SIZE);
+ if (retval < 0) {
perror("prepare_binprm");
exit(-1);
- /* return(-errno); */
}
- else {
- return(retval);
+ if (retval < BPRM_BUF_SIZE) {
+ /* Make sure the rest of the loader won't read garbage. */
+ memset(bprm->buf + retval, 0, BPRM_BUF_SIZE - retval);
}
+ return retval;
}
/* Construct the envp and argv tables on the target stack. */
@@ -163,8 +161,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp,
int i;
bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
- for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
- bprm->page[i] = NULL;
+ memset(bprm->page, 0, sizeof(bprm->page));
retval = open(filename, O_RDONLY);
if (retval < 0)
return retval;
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index dab3597..f7c8b65 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -31,6 +31,7 @@
* task_struct fields in the kernel
*/
struct image_info {
+ abi_ulong load_bias;
abi_ulong load_addr;
abi_ulong start_code;
abi_ulong end_code;
@@ -143,12 +144,16 @@ extern unsigned long mmap_min_addr;
*/
#define MAX_ARG_PAGES 33
+/* Read a good amount of data initially, to hopefully get all the
+ program headers loaded. */
+#define BPRM_BUF_SIZE 4096
+
/*
* This structure is used to hold the arguments that are
* used when loading binaries.
*/
struct linux_binprm {
- char buf[128];
+ char buf[BPRM_BUF_SIZE] __attribute__((aligned));
void *page[MAX_ARG_PAGES];
abi_ulong p;
int fd;
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 01/14] linux-user: Handle filesz < memsz for any PT_LOAD segment.
2010-04-28 19:36 ` [Qemu-devel] [PATCH 00/14] Implement VDSO for x86-64-linux-user, v2 Richard Henderson
2010-04-28 19:39 ` [Qemu-devel] [PATCH 04/14] linux-user: Reduce lseek+reads while loading elf files Richard Henderson
@ 2010-04-28 19:39 ` Richard Henderson
2010-04-28 19:39 ` [Qemu-devel] [PATCH 02/14] Add more DT_* and AT_* constants to qemu's copy of elf.h Richard Henderson
` (11 subsequent siblings)
13 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-28 19:39 UTC (permalink / raw)
To: qemu-devel
I caught padzero not properly initializing the .bss segment
on a statically linked Alpha program. Rather than a minimal
patch, replace the gross code with a single mmap+memset.
Share more code between load_elf_interp and load_elf_binary.
Legally, an ELF program need not have just a single .bss;
and PT_LOAD segment can have memsz > filesz.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 150 ++++++++++++++++++--------------------------------
1 files changed, 54 insertions(+), 96 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 4d3dd89..238e574 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1015,60 +1015,47 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
return p;
}
-static void set_brk(abi_ulong start, abi_ulong end)
-{
- /* page-align the start and end addresses... */
- start = HOST_PAGE_ALIGN(start);
- end = HOST_PAGE_ALIGN(end);
- if (end <= start)
- return;
- if(target_mmap(start, end - start,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
- perror("cannot mmap brk");
- exit(-1);
- }
-}
-
-
-/* We need to explicitly zero any fractional pages after the data
- section (i.e. bss). This would contain the junk from the file that
- should not be in memory. */
-static void padzero(abi_ulong elf_bss, abi_ulong last_bss)
-{
- abi_ulong nbyte;
-
- if (elf_bss >= last_bss)
- return;
-
- /* XXX: this is really a hack : if the real host page size is
- smaller than the target page size, some pages after the end
- of the file may not be mapped. A better fix would be to
- patch target_mmap(), but it is more complicated as the file
- size must be known */
- if (qemu_real_host_page_size < qemu_host_page_size) {
- abi_ulong end_addr, end_addr1;
- end_addr1 = (elf_bss + qemu_real_host_page_size - 1) &
- ~(qemu_real_host_page_size - 1);
- end_addr = HOST_PAGE_ALIGN(elf_bss);
- if (end_addr1 < end_addr) {
- mmap((void *)g2h(end_addr1), end_addr - end_addr1,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
- }
+/* Map and zero the bss. We need to explicitly zero any fractional pages
+ after the data section (i.e. bss). */
+static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
+{
+ uintptr_t host_start, host_map_start, host_end;
+
+ last_bss = TARGET_PAGE_ALIGN(last_bss);
+
+ /* ??? There is confusion between qemu_real_host_page_size and
+ qemu_host_page_size here and elsewhere in target_mmap, which
+ may lead to the end of the data section mapping from the file
+ not being mapped. At least there was an explicit test and
+ comment for that here, suggesting that "the file size must
+ be known". The comment probably pre-dates the introduction
+ of the fstat system call in target_mmap which does in fact
+ find out the size. What isn't clear is if the workaround
+ here is still actually needed. For now, continue with it,
+ but merge it with the "normal" mmap that would allocate the bss. */
+
+ host_start = (uintptr_t) g2h(elf_bss);
+ host_end = (uintptr_t) g2h(last_bss);
+ host_map_start = (host_start + qemu_real_host_page_size - 1);
+ host_map_start &= -qemu_real_host_page_size;
+
+ if (host_map_start < host_end) {
+ void *p = mmap((void *)host_map_start, host_end - host_map_start,
+ prot, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (p == MAP_FAILED) {
+ perror("cannot mmap brk");
+ exit(-1);
}
- nbyte = elf_bss & (qemu_host_page_size-1);
- if (nbyte) {
- nbyte = qemu_host_page_size - nbyte;
- do {
- /* FIXME - what to do if put_user() fails? */
- put_user_u8(0, elf_bss);
- elf_bss++;
- } while (--nbyte);
- }
-}
+ /* Since we didn't use target_mmap, make sure to record
+ the validity of the pages with qemu. */
+ page_set_flags(elf_bss & TARGET_PAGE_MASK, last_bss, prot|PAGE_VALID);
+ }
+ if (host_start < host_map_start) {
+ memset((void *)host_start, 0, host_map_start - host_start);
+ }
+}
static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
struct elfhdr * exec,
@@ -1160,12 +1147,9 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
abi_ulong load_addr = 0;
int load_addr_set = 0;
int retval;
- abi_ulong last_bss, elf_bss;
abi_ulong error;
int i;
- elf_bss = 0;
- last_bss = 0;
error = 0;
#ifdef BSWAP_NEEDED
@@ -1238,7 +1222,6 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
int elf_prot = 0;
abi_ulong vaddr = 0;
- abi_ulong k;
if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
@@ -1266,40 +1249,17 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
load_addr_set = 1;
}
- /*
- * Find the end of the file mapping for this phdr, and keep
- * track of the largest address we see for this.
- */
- k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
- if (k > elf_bss) elf_bss = k;
-
- /*
- * Do the same thing for the memory mapping - between
- * elf_bss and last_bss is the bss section.
- */
- k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
- if (k > last_bss) last_bss = k;
+ /* If the load segment requests extra zeros (e.g. bss), map it. */
+ if (eppnt->p_filesz < eppnt->p_memsz) {
+ abi_ulong base = load_addr + eppnt->p_vaddr;
+ zero_bss(base + eppnt->p_filesz,
+ base + eppnt->p_memsz, elf_prot);
+ }
}
/* Now use mmap to map the library into memory. */
close(interpreter_fd);
-
- /*
- * Now fill out the bss section. First pad the last page up
- * to the page boundary, and then perform a mmap to make sure
- * that there are zeromapped pages up to and including the last
- * bss page.
- */
- padzero(elf_bss, last_bss);
- elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */
-
- /* Map the last of the bss segment */
- if (last_bss > elf_bss) {
- target_mmap(elf_bss, last_bss-elf_bss,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
- }
free(elf_phdata);
*interp_load_addr = load_addr;
@@ -1453,7 +1413,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
abi_ulong mapped_addr;
struct elf_phdr * elf_ppnt;
struct elf_phdr *elf_phdata;
- abi_ulong elf_bss, k, elf_brk;
+ abi_ulong k, elf_brk;
int retval;
char * elf_interpreter;
abi_ulong elf_entry, interp_load_addr = 0;
@@ -1512,10 +1472,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
#endif
elf_ppnt = elf_phdata;
- elf_bss = 0;
elf_brk = 0;
-
elf_stack = ~((abi_ulong)0UL);
elf_interpreter = NULL;
start_code = ~((abi_ulong)0UL);
@@ -1758,18 +1716,24 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
if (start_data < k)
start_data = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
- if (k > elf_bss)
- elf_bss = k;
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 = k;
+ 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_bss += load_bias;
elf_brk += load_bias;
start_code += load_bias;
end_code += load_bias;
@@ -1824,12 +1788,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
info->end_data = end_data;
info->start_stack = bprm->p;
- /* Calling set_brk effectively mmaps the pages that we need for the bss and break
- sections */
- set_brk(elf_bss, elf_brk);
-
- padzero(elf_bss, elf_brk);
-
#if 0
printf("(start_brk) %x\n" , info->start_brk);
printf("(end_code) %x\n" , info->end_code);
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 02/14] Add more DT_* and AT_* constants to qemu's copy of elf.h.
2010-04-28 19:36 ` [Qemu-devel] [PATCH 00/14] Implement VDSO for x86-64-linux-user, v2 Richard Henderson
2010-04-28 19:39 ` [Qemu-devel] [PATCH 04/14] linux-user: Reduce lseek+reads while loading elf files Richard Henderson
2010-04-28 19:39 ` [Qemu-devel] [PATCH 01/14] linux-user: Handle filesz < memsz for any PT_LOAD segment Richard Henderson
@ 2010-04-28 19:39 ` Richard Henderson
2010-04-28 19:39 ` [Qemu-devel] [PATCH 09/14] linux-user: Put the stack guard page at the top Richard Henderson
` (10 subsequent siblings)
13 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-28 19:39 UTC (permalink / raw)
To: qemu-devel
Moving some PPC AT_* constants from elfload.c at the same time.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
elf.h | 44 ++++++++++++++++++++++++++++++++++++++++++++
linux-user/elfload.c | 9 ---------
2 files changed, 44 insertions(+), 9 deletions(-)
diff --git a/elf.h b/elf.h
index c84c8ab..012532c 100644
--- a/elf.h
+++ b/elf.h
@@ -146,8 +146,37 @@ typedef int64_t Elf64_Sxword;
#define DT_DEBUG 21
#define DT_TEXTREL 22
#define DT_JMPREL 23
+#define DT_BINDNOW 24
+#define DT_INIT_ARRAY 25
+#define DT_FINI_ARRAY 26
+#define DT_INIT_ARRAYSZ 27
+#define DT_FINI_ARRAYSZ 28
+#define DT_RUNPATH 29
+#define DT_FLAGS 30
+#define DT_LOOS 0x6000000d
+#define DT_HIOS 0x6ffff000
#define DT_LOPROC 0x70000000
#define DT_HIPROC 0x7fffffff
+
+/* DT_ entries which fall between DT_VALRNGLO and DT_VALRNDHI use
+ the d_val field of the Elf*_Dyn structure. I.e. they contain scalars. */
+#define DT_VALRNGLO 0x6ffffd00
+#define DT_VALRNGHI 0x6ffffdff
+
+/* DT_ entries which fall between DT_ADDRRNGLO and DT_ADDRRNGHI use
+ the d_ptr field of the Elf*_Dyn structure. I.e. they contain pointers. */
+#define DT_ADDRRNGLO 0x6ffffe00
+#define DT_ADDRRNGHI 0x6ffffeff
+
+#define DT_VERSYM 0x6ffffff0
+#define DT_RELACOUNT 0x6ffffff9
+#define DT_RELCOUNT 0x6ffffffa
+#define DT_FLAGS_1 0x6ffffffb
+#define DT_VERDEF 0x6ffffffc
+#define DT_VERDEFNUM 0x6ffffffd
+#define DT_VERNEED 0x6ffffffe
+#define DT_VERNEEDNUM 0x6fffffff
+
#define DT_MIPS_RLD_VERSION 0x70000001
#define DT_MIPS_TIME_STAMP 0x70000002
#define DT_MIPS_ICHECKSUM 0x70000003
@@ -206,6 +235,21 @@ typedef int64_t Elf64_Sxword;
#define AT_PLATFORM 15 /* string identifying CPU for optimizations */
#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */
#define AT_CLKTCK 17 /* frequency at which times() increments */
+#define AT_FPUCW 18 /* info about fpu initialization by kernel */
+#define AT_DCACHEBSIZE 19 /* data cache block size */
+#define AT_ICACHEBSIZE 20 /* instruction cache block size */
+#define AT_UCACHEBSIZE 21 /* unified cache block size */
+#define AT_IGNOREPPC 22 /* ppc only; entry should be ignored */
+#define AT_SECURE 23 /* boolean, was exec suid-like? */
+#define AT_BASE_PLATFORM 24 /* string identifying real platforms */
+#define AT_RANDOM 25 /* address of 16 random bytes */
+#define AT_EXECFN 31 /* filename of the executable */
+#define AT_SYSINFO 32 /* address of kernel entry point */
+#define AT_SYSINFO_EHDR 33 /* address of kernel vdso */
+#define AT_L1I_CACHESHAPE 34 /* shapes of the caches: */
+#define AT_L1D_CACHESHAPE 35 /* bits 0-3: cache associativity. */
+#define AT_L2_CACHESHAPE 36 /* bits 4-7: log2 of line size. */
+#define AT_L3_CACHESHAPE 37 /* val&~255: cache size. */
typedef struct dynamic{
Elf32_Sword d_tag;
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 238e574..ead22fc 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -480,15 +480,6 @@ static uint32_t get_elf_hwcap(void)
}
/*
- * 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
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 09/14] linux-user: Put the stack guard page at the top.
2010-04-28 19:36 ` [Qemu-devel] [PATCH 00/14] Implement VDSO for x86-64-linux-user, v2 Richard Henderson
` (2 preceding siblings ...)
2010-04-28 19:39 ` [Qemu-devel] [PATCH 02/14] Add more DT_* and AT_* constants to qemu's copy of elf.h Richard Henderson
@ 2010-04-28 19:39 ` Richard Henderson
2010-04-28 19:39 ` [Qemu-devel] [PATCH 06/14] linux-user: Clean up byte-swapping in elfload.c Richard Henderson
` (9 subsequent siblings)
13 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-28 19:39 UTC (permalink / raw)
To: qemu-devel
There are no supported stack-grows-up targets. We were putting
the guard page at the highest address, i.e. the bottom of the stack.
Use the maximum of host and guest page size for the guard size.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 29 ++++++++++++++++-------------
1 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 5853a30..464160a 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1002,28 +1002,31 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
struct image_info *info)
{
- abi_ulong stack_base, size, error;
+ abi_ulong stack_base, size, error, guard;
int i;
/* Create enough stack to hold everything. If we don't use
- * it for args, we'll use it for something else...
- */
+ it for args, we'll use it for something else. */
size = guest_stack_size;
- if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
+ if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) {
size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
- error = target_mmap(0,
- size + qemu_host_page_size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- -1, 0);
+ }
+ guard = TARGET_PAGE_SIZE;
+ if (guard < qemu_real_host_page_size) {
+ guard = qemu_real_host_page_size;
+ }
+
+ error = target_mmap(0, size + guard, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (error == -1) {
- perror("stk mmap");
+ perror("mmap stack");
exit(-1);
}
- /* we reserve one extra page at the top of the stack as guard */
- target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
- stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
+ /* We reserve one extra page at the top of the stack as guard. */
+ target_mprotect(error, guard, PROT_NONE);
+
+ stack_base = error + guard + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
p += stack_base;
for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 06/14] linux-user: Clean up byte-swapping in elfload.c.
2010-04-28 19:36 ` [Qemu-devel] [PATCH 00/14] Implement VDSO for x86-64-linux-user, v2 Richard Henderson
` (3 preceding siblings ...)
2010-04-28 19:39 ` [Qemu-devel] [PATCH 09/14] linux-user: Put the stack guard page at the top Richard Henderson
@ 2010-04-28 19:39 ` Richard Henderson
2010-04-28 19:39 ` [Qemu-devel] [PATCH 10/14] linux-user: Remove partial support for a.out interpreters Richard Henderson
` (8 subsequent siblings)
13 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-28 19:39 UTC (permalink / raw)
To: qemu-devel
Remove ifdefs from code by defining empty inline functions
when byte swapping isn't needed. Push loops over swapping
arrays of structures into the swapping functions.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 119 ++++++++++++++++++++------------------------------
1 files changed, 48 insertions(+), 71 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 5814702..9cf1eeb 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -871,30 +871,36 @@ static void bswap_ehdr(struct elfhdr *ehdr)
bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
}
-static void bswap_phdr(struct elf_phdr *phdr)
+static void bswap_phdr(struct elf_phdr *phdr, int phnum)
{
- 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 */
+ int i;
+ for (i = 0; i < phnum; ++i, ++phdr) {
+ bswap32s(&phdr->p_type); /* Segment type */
+ bswap32s(&phdr->p_flags); /* Segment flags */
+ 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 */
+ bswaptls(&phdr->p_align); /* Segment alignment */
+ }
}
-static void bswap_shdr(struct elf_shdr *shdr)
+static void bswap_shdr(struct elf_shdr *shdr, int shnum)
{
- 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);
+ int i;
+ for (i = 0; i < shnum; ++i, ++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(struct elf_sym *sym)
@@ -904,20 +910,15 @@ static void bswap_sym(struct elf_sym *sym)
bswaptls(&sym->st_size);
bswap16s(&sym->st_shndx);
}
+#else
+static inline void bswap_ehdr(struct elfhdr *ehdr) { }
+static inline void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
+static inline void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
+static inline void bswap_sym(struct elf_sym *sym) { }
#endif
#ifdef USE_ELF_CORE_DUMP
static int elf_core_dump(int, const CPUState *);
-
-#ifdef BSWAP_NEEDED
-static void bswap_note(struct elf_note *en)
-{
- bswap32s(&en->n_namesz);
- bswap32s(&en->n_descsz);
- bswap32s(&en->n_type);
-}
-#endif /* BSWAP_NEEDED */
-
#endif /* USE_ELF_CORE_DUMP */
/*
@@ -1153,9 +1154,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
error = 0;
-#ifdef BSWAP_NEEDED
bswap_ehdr(interp_elf_ex);
-#endif
/* First of all, some simple consistency checks */
if ((interp_elf_ex->e_type != ET_EXEC &&
interp_elf_ex->e_type != ET_DYN) ||
@@ -1194,12 +1193,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
exit(-1);
}
}
-#ifdef BSWAP_NEEDED
- eppnt = elf_phdata;
- for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
- bswap_phdr(eppnt);
- }
-#endif
+ bswap_phdr(elf_phdata, interp_elf_ex->e_phnum);
if (interp_elf_ex->e_type == ET_DYN) {
/* in order to avoid hardcoding the interpreter load
@@ -1323,9 +1317,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
for (i = 0; i < hdr->e_shnum; i++) {
if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
return;
-#ifdef BSWAP_NEEDED
- bswap_shdr(&sechdr);
-#endif
+ bswap_shdr(&sechdr, 1);
if (sechdr.sh_type == SHT_SYMTAB) {
symtab = sechdr;
lseek(fd, hdr->e_shoff
@@ -1333,9 +1325,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
if (read(fd, &strtab, sizeof(strtab))
!= sizeof(strtab))
return;
-#ifdef BSWAP_NEEDED
- bswap_shdr(&strtab);
-#endif
+ bswap_shdr(&strtab, 1);
goto found;
}
}
@@ -1359,9 +1349,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
i = 0;
while (i < nsyms) {
-#ifdef BSWAP_NEEDED
bswap_sym(syms + i);
-#endif
// Throw away entries which we do not need.
if (syms[i].st_shndx == SHN_UNDEF ||
syms[i].st_shndx >= SHN_LORESERVE ||
@@ -1427,9 +1415,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
load_addr = 0;
load_bias = 0;
elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
-#ifdef BSWAP_NEEDED
bswap_ehdr(&elf_ex);
-#endif
/* First of all, some simple consistency checks */
if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
@@ -1460,17 +1446,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
exit(-1);
}
}
-
-#ifdef BSWAP_NEEDED
- elf_ppnt = elf_phdata;
- for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
- bswap_phdr(elf_ppnt);
- }
-#endif
- elf_ppnt = elf_phdata;
+ bswap_phdr(elf_phdata, elf_ex.e_phnum);
elf_brk = 0;
-
elf_stack = ~((abi_ulong)0UL);
elf_interpreter = NULL;
start_code = ~((abi_ulong)0UL);
@@ -1479,6 +1457,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
end_data = 0;
interp_ex.a_info = 0;
+ elf_ppnt = elf_phdata;
for(i=0;i < elf_ex.e_phnum; i++) {
if (elf_ppnt->p_type == PT_INTERP) {
if ( elf_interpreter != NULL )
@@ -1964,9 +1943,6 @@ static int write_note(struct memelfnote *, int);
static int write_note_info(struct elf_note_info *, int);
#ifdef BSWAP_NEEDED
-static void bswap_prstatus(struct target_elf_prstatus *);
-static void bswap_psinfo(struct target_elf_prpsinfo *);
-
static void bswap_prstatus(struct target_elf_prstatus *prstatus)
{
prstatus->pr_info.si_signo = tswapl(prstatus->pr_info.si_signo);
@@ -1994,6 +1970,17 @@ static void bswap_psinfo(struct target_elf_prpsinfo *psinfo)
psinfo->pr_pgrp = tswap32(psinfo->pr_pgrp);
psinfo->pr_sid = tswap32(psinfo->pr_sid);
}
+
+static void bswap_note(struct elf_note *en)
+{
+ bswap32s(&en->n_namesz);
+ bswap32s(&en->n_descsz);
+ bswap32s(&en->n_type);
+}
+#else
+static inline void bswap_prstatus(struct target_elf_prstatus *p) { }
+static inline void bswap_psinfo(struct target_elf_prpsinfo *p) {}
+static inline void bswap_note(struct elf_note *en) { }
#endif /* BSWAP_NEEDED */
/*
@@ -2152,9 +2139,7 @@ static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
elf->e_phentsize = sizeof(struct elf_phdr);
elf->e_phnum = segs;
-#ifdef BSWAP_NEEDED
bswap_ehdr(elf);
-#endif
}
static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
@@ -2168,9 +2153,7 @@ static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
phdr->p_flags = 0;
phdr->p_align = 0;
-#ifdef BSWAP_NEEDED
- bswap_phdr(phdr);
-#endif
+ bswap_phdr(phdr, 1);
}
static size_t note_size(const struct memelfnote *note)
@@ -2188,9 +2171,7 @@ static void fill_prstatus(struct target_elf_prstatus *prstatus,
prstatus->pr_pgrp = getpgrp();
prstatus->pr_sid = getsid(0);
-#ifdef BSWAP_NEEDED
bswap_prstatus(prstatus);
-#endif
}
static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
@@ -2224,9 +2205,7 @@ static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
free(base_filename);
free(filename);
-#ifdef BSWAP_NEEDED
bswap_psinfo(psinfo);
-#endif
return (0);
}
@@ -2351,9 +2330,7 @@ static int write_note(struct memelfnote *men, int fd)
en.n_type = men->type;
en.n_descsz = men->datasz;
-#ifdef BSWAP_NEEDED
bswap_note(&en);
-#endif
if (dump_write(fd, &en, sizeof(en)) != 0)
return (-1);
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 10/14] linux-user: Remove partial support for a.out interpreters.
2010-04-28 19:36 ` [Qemu-devel] [PATCH 00/14] Implement VDSO for x86-64-linux-user, v2 Richard Henderson
` (4 preceding siblings ...)
2010-04-28 19:39 ` [Qemu-devel] [PATCH 06/14] linux-user: Clean up byte-swapping in elfload.c Richard Henderson
@ 2010-04-28 19:39 ` Richard Henderson
2010-04-28 19:39 ` [Qemu-devel] [PATCH 05/14] linux-user: Fix ELF_DATA for Alpha Richard Henderson
` (7 subsequent siblings)
13 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-28 19:39 UTC (permalink / raw)
To: qemu-devel
At the bottom of the a.out support was the unimplemented load_aout_interp
function. There were other portions of the support that didn't look
right; when I went to look in the Linux kernel for clarification, I found
that the support for such interpreters has been removed from binfmt_elf.
There doesn't seem to be any reason to keep this broken support in qemu.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 80 +++++--------------------------------------------
1 files changed, 9 insertions(+), 71 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 464160a..2f15b9c 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -837,10 +837,6 @@ struct exec
#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 12
static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
@@ -848,8 +844,6 @@ static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
memcpy(to, from, n);
}
-static int load_aout_interp(void * exptr, int interp_fd);
-
#ifdef BSWAP_NEEDED
static void bswap_ehdr(struct elfhdr *ehdr)
{
@@ -1087,7 +1081,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
struct elfhdr * exec,
abi_ulong load_addr,
abi_ulong load_bias,
- abi_ulong interp_load_addr, int ibcs,
+ abi_ulong interp_load_addr,
struct image_info *info)
{
abi_ulong sp;
@@ -1117,7 +1111,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
size += DLINFO_ARCH_ITEMS * 2;
#endif
size += envc + argc + 2;
- size += (!ibcs ? 3 : 1); /* argc itself */
+ size += 1; /* argc itself */
size *= n;
if (size & 15)
sp -= 16 - (size & 15);
@@ -1159,7 +1153,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
info->saved_auxv = sp;
- sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
+ sp = loader_build_argptr(envc, argc, sp, p, 0);
return sp;
}
@@ -1412,11 +1406,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
{
struct elfhdr elf_ex;
struct elfhdr interp_elf_ex;
- struct exec interp_ex;
int interpreter_fd = -1; /* avoid warning */
abi_ulong load_addr, load_bias;
int load_addr_set = 0;
- unsigned int interpreter_type = INTERPRETER_NONE;
unsigned char ibcs2_interpreter;
int i;
abi_ulong mapped_addr;
@@ -1430,7 +1422,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
abi_ulong start_code, end_code, start_data, end_data;
abi_ulong reloc_func_desc = 0;
abi_ulong elf_stack;
- char passed_fileno[6];
ibcs2_interpreter = 0;
status = 0;
@@ -1480,7 +1471,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
end_code = 0;
start_data = 0;
end_data = 0;
- interp_ex.a_info = 0;
elf_ppnt = elf_phdata;
for(i=0;i < elf_ex.e_phnum; i++) {
@@ -1545,59 +1535,22 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
memset(bprm->buf, 0, BPRM_BUF_SIZE - retval);
}
- interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
- interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */
+ interp_elf_ex = *((struct elfhdr *) bprm->buf);
}
elf_ppnt++;
}
/* Some simple consistency checks for the interpreter */
- if (elf_interpreter){
- interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
-
- /* Now figure out which format our binary is */
- if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
- (N_MAGIC(interp_ex) != QMAGIC)) {
- interpreter_type = INTERPRETER_ELF;
- }
-
+ if (elf_interpreter) {
if (!elf_check_ident(&interp_elf_ex)) {
- interpreter_type &= ~INTERPRETER_ELF;
- }
-
- if (!interpreter_type) {
free(elf_interpreter);
free(elf_phdata);
close(bprm->fd);
+ close(interpreter_fd);
return -ELIBBAD;
}
}
- /* OK, we are done with that, now set up the arg stuff,
- and then start this sucker up */
-
- {
- char * passed_p;
-
- if (interpreter_type == INTERPRETER_AOUT) {
- snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
- passed_p = passed_fileno;
-
- if (elf_interpreter) {
- bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p);
- bprm->argc++;
- }
- }
- if (!bprm->p) {
- if (elf_interpreter) {
- free(elf_interpreter);
- }
- free (elf_phdata);
- close(bprm->fd);
- return -E2BIG;
- }
- }
-
/* OK, This is the point of no return */
info->end_data = 0;
info->end_code = 0;
@@ -1729,16 +1682,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
end_data += load_bias;
if (elf_interpreter) {
- if (interpreter_type & 1) {
- elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
- }
- else if (interpreter_type & 2) {
- elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
- &interp_load_addr, bprm->buf);
- }
+ elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
+ &interp_load_addr, bprm->buf);
reloc_func_desc = interp_load_addr;
-
- close(interpreter_fd);
free(elf_interpreter);
if (elf_entry == ~((abi_ulong)0UL)) {
@@ -1755,7 +1701,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
load_symbols(&elf_ex, bprm->fd, load_bias);
}
- if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
+ close(bprm->fd);
info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
#ifdef LOW_ELF_STACK
@@ -1767,7 +1713,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
&elf_ex,
load_addr, load_bias,
interp_load_addr,
- (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
info);
info->load_addr = reloc_func_desc;
info->start_brk = info->brk = elf_brk;
@@ -2656,15 +2601,8 @@ static int elf_core_dump(int signr, const CPUState *env)
return (-errno);
return (0);
}
-
#endif /* USE_ELF_CORE_DUMP */
-static int load_aout_interp(void * exptr, int interp_fd)
-{
- printf("a.out interpreter not yet supported\n");
- return(0);
-}
-
void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
{
init_thread(regs, infop);
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 05/14] linux-user: Fix ELF_DATA for Alpha.
2010-04-28 19:36 ` [Qemu-devel] [PATCH 00/14] Implement VDSO for x86-64-linux-user, v2 Richard Henderson
` (5 preceding siblings ...)
2010-04-28 19:39 ` [Qemu-devel] [PATCH 10/14] linux-user: Remove partial support for a.out interpreters Richard Henderson
@ 2010-04-28 19:39 ` Richard Henderson
2010-04-28 19:39 ` [Qemu-devel] [PATCH 08/14] linux-user: Improve consistency checking in elf headers Richard Henderson
` (6 subsequent siblings)
13 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-28 19:39 UTC (permalink / raw)
To: qemu-devel
Alpha is little-endian on Linux.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 962f9ba..5814702 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -778,7 +778,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#define elf_check_arch(x) ( (x) == ELF_ARCH )
#define ELF_CLASS ELFCLASS64
-#define ELF_DATA ELFDATA2MSB
+#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_ALPHA
static inline void init_thread(struct target_pt_regs *regs,
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 08/14] linux-user: Improve consistency checking in elf headers.
2010-04-28 19:36 ` [Qemu-devel] [PATCH 00/14] Implement VDSO for x86-64-linux-user, v2 Richard Henderson
` (6 preceding siblings ...)
2010-04-28 19:39 ` [Qemu-devel] [PATCH 05/14] linux-user: Fix ELF_DATA for Alpha Richard Henderson
@ 2010-04-28 19:39 ` Richard Henderson
2010-04-28 19:39 ` [Qemu-devel] [PATCH 11/14] linux-user: Extract load_elf_image from load_elf_interp Richard Henderson
` (5 subsequent siblings)
13 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-28 19:39 UTC (permalink / raw)
To: qemu-devel
Validate more fields of the elf header. Extract those checks
into two common functions to be used in both load_elf_interp
and load_elf_binary.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 57 +++++++++++++++++++++++++++++---------------------
1 files changed, 33 insertions(+), 24 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 7e94fe3..5853a30 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -919,6 +919,30 @@ static int elf_core_dump(int, const CPUState *);
#endif /* USE_ELF_CORE_DUMP */
static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias);
+/* Verify the portions of EHDR within E_IDENT for the target.
+ This can be performed before bswapping the entire header. */
+static _Bool elf_check_ident(struct elfhdr *ehdr)
+{
+ return (ehdr->e_ident[EI_MAG0] == ELFMAG0
+ && ehdr->e_ident[EI_MAG1] == ELFMAG1
+ && ehdr->e_ident[EI_MAG2] == ELFMAG2
+ && ehdr->e_ident[EI_MAG3] == ELFMAG3
+ && ehdr->e_ident[EI_CLASS] == ELF_CLASS
+ && ehdr->e_ident[EI_DATA] == ELF_DATA
+ && ehdr->e_ident[EI_VERSION] == EV_CURRENT);
+}
+
+/* Verify the portions of EHDR outside of E_IDENT for the target.
+ This has to wait until after bswapping the header. */
+static _Bool elf_check_ehdr(struct elfhdr *ehdr)
+{
+ return (elf_check_arch(ehdr->e_machine)
+ && ehdr->e_ehsize == sizeof(struct elfhdr)
+ && ehdr->e_phentsize == sizeof(struct elf_phdr)
+ && ehdr->e_shentsize == sizeof(struct elf_shdr)
+ && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));
+}
+
/*
* 'copy_elf_strings()' copies argument/envelope strings from user
* memory to free pages in kernel mem. These are in a format ready
@@ -1149,33 +1173,16 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
int i;
bswap_ehdr(interp_elf_ex);
- /* First of all, some simple consistency checks */
- if ((interp_elf_ex->e_type != ET_EXEC &&
- interp_elf_ex->e_type != ET_DYN) ||
- !elf_check_arch(interp_elf_ex->e_machine)) {
+ if (!elf_check_ehdr(interp_elf_ex)) {
return ~((abi_ulong)0UL);
}
/* Now read in all of the header information */
-
- if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
- return ~(abi_ulong)0UL;
-
elf_phdata = (struct elf_phdr *)
malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
-
if (!elf_phdata)
return ~((abi_ulong)0UL);
- /*
- * If the size of this structure has changed, then punt, since
- * we will be doing the wrong thing.
- */
- if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
- free(elf_phdata);
- return ~((abi_ulong)0UL);
- }
-
i = interp_elf_ex->e_phnum * sizeof(struct elf_phdr);
if (interp_elf_ex->e_phoff + i <= BPRM_BUF_SIZE) {
memcpy(elf_phdata, bprm_buf + interp_elf_ex->e_phoff, i);
@@ -1427,11 +1434,13 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
load_addr = 0;
load_bias = 0;
elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
- bswap_ehdr(&elf_ex);
/* First of all, some simple consistency checks */
- if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
- (! elf_check_arch(elf_ex.e_machine))) {
+ if (!elf_check_ident(&elf_ex)) {
+ return -ENOEXEC;
+ }
+ bswap_ehdr(&elf_ex);
+ if (!elf_check_ehdr(&elf_ex)) {
return -ENOEXEC;
}
@@ -1443,7 +1452,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
}
/* Now read in all of the header information */
- elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
+ elf_phdata = (struct elf_phdr *)
+ malloc(elf_ex.e_phnum * sizeof(struct elf_phdr));
if (elf_phdata == NULL) {
return -ENOMEM;
}
@@ -1548,8 +1558,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
interpreter_type = INTERPRETER_ELF;
}
- if (interp_elf_ex.e_ident[0] != 0x7f ||
- strncmp((char *)&interp_elf_ex.e_ident[1], "ELF",3) != 0) {
+ if (!elf_check_ident(&interp_elf_ex)) {
interpreter_type &= ~INTERPRETER_ELF;
}
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 11/14] linux-user: Extract load_elf_image from load_elf_interp.
2010-04-28 19:36 ` [Qemu-devel] [PATCH 00/14] Implement VDSO for x86-64-linux-user, v2 Richard Henderson
` (7 preceding siblings ...)
2010-04-28 19:39 ` [Qemu-devel] [PATCH 08/14] linux-user: Improve consistency checking in elf headers Richard Henderson
@ 2010-04-28 19:39 ` Richard Henderson
2010-04-28 19:39 ` [Qemu-devel] [PATCH 13/14] linux-user: Build vdso for x64 Richard Henderson
` (4 subsequent siblings)
13 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-28 19:39 UTC (permalink / raw)
To: qemu-devel
Moving toward a single copy of the elf binary loading code.
Fill in the details of the loaded image into a struct image_info.
Adjust create_elf_tables to read from such structures instead
of from a collection of passed arguments. Don't return error
values from load_elf_interp; always exit(-1) with a message to
stderr. Collect elf_interpreter handling in load_elf_binary
to a common spot.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 341 ++++++++++++++++++++++++-------------------------
1 files changed, 167 insertions(+), 174 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 2f15b9c..c58387a 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1078,11 +1078,9 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
}
static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
- struct elfhdr * exec,
- abi_ulong load_addr,
- abi_ulong load_bias,
- abi_ulong interp_load_addr,
- struct image_info *info)
+ struct elfhdr *exec,
+ struct image_info *info,
+ struct image_info *interp_info)
{
abi_ulong sp;
int size;
@@ -1127,13 +1125,13 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
NEW_AUX_ENT (AT_NULL, 0);
/* There must be exactly DLINFO_ITEMS entries here. */
- NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
+ NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff));
NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
- NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
+ NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info->load_addr));
NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
- NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
+ NEW_AUX_ENT(AT_ENTRY, info->entry);
NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
@@ -1157,51 +1155,60 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
return sp;
}
+/* Load an ELF image into the address space.
-static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
- int interpreter_fd,
- abi_ulong *interp_load_addr,
- char bprm_buf[BPRM_BUF_SIZE])
+ IMAGE_NAME is the filename of the image, to use in error messages.
+ IMAGE_FD is the open file descriptor for the image.
+
+ BUFPAGE is a copy of the first page of the file; this of course
+ contains the elf file header at offset 0. It is assumed that this
+ buffer is sufficiently aligned to present no problems to the host
+ in accessing data at aligned offsets within the buffer.
+
+ 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,
+ char bprm_buf[BPRM_BUF_SIZE])
{
- struct elf_phdr *elf_phdata = NULL;
- abi_ulong load_addr, load_bias, loaddr, hiaddr;
- int retval;
- abi_ulong error;
- int i;
+ struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
+ struct elf_phdr *phdr;
+ abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
+ int i, retval;
+ const char *errmsg;
- bswap_ehdr(interp_elf_ex);
- if (!elf_check_ehdr(interp_elf_ex)) {
- return ~((abi_ulong)0UL);
+ /* First of all, some simple consistency checks */
+ errmsg = "Invalid ELF image for this architecture";
+ if (!elf_check_ident(ehdr)) {
+ goto exit_errmsg;
+ }
+ bswap_ehdr(ehdr);
+ if (!elf_check_ehdr(ehdr)) {
+ goto exit_errmsg;
}
- /* Now read in all of the header information */
- elf_phdata = (struct elf_phdr *)
- malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
- if (!elf_phdata)
- return ~((abi_ulong)0UL);
-
- i = interp_elf_ex->e_phnum * sizeof(struct elf_phdr);
- if (interp_elf_ex->e_phoff + i <= BPRM_BUF_SIZE) {
- memcpy(elf_phdata, bprm_buf + interp_elf_ex->e_phoff, i);
+ i = ehdr->e_phnum * sizeof(struct elf_phdr);
+ if (ehdr->e_phoff + i <= BPRM_BUF_SIZE) {
+ phdr = (struct elf_phdr *)(bprm_buf + ehdr->e_phoff);
} else {
- retval = pread(interpreter_fd, elf_phdata, i, interp_elf_ex->e_phoff);
+ phdr = (struct elf_phdr *) alloca(i);
+ retval = pread(image_fd, phdr, i, ehdr->e_phoff);
if (retval != i) {
- perror("load_elf_interp");
- exit(-1);
+ goto exit_read;
}
}
- bswap_phdr(elf_phdata, interp_elf_ex->e_phnum);
+ bswap_phdr(phdr, ehdr->e_phnum);
/* Find the maximum size of the image and allocate an appropriate
amount of memory to handle that. */
loaddr = -1, hiaddr = 0;
- for (i = 0; i < interp_elf_ex->e_phnum; ++i) {
- if (elf_phdata[i].p_type == PT_LOAD) {
- abi_ulong a = elf_phdata[i].p_vaddr;
+ for (i = 0; i < ehdr->e_phnum; ++i) {
+ if (phdr[i].p_type == PT_LOAD) {
+ abi_ulong a = phdr[i].p_vaddr;
if (a < loaddr) {
loaddr = a;
}
- a += elf_phdata[i].p_memsz;
+ a += phdr[i].p_memsz;
if (a > hiaddr) {
hiaddr = a;
}
@@ -1209,7 +1216,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
}
load_addr = loaddr;
- if (interp_elf_ex->e_type == ET_DYN) {
+ if (ehdr->e_type == ET_DYN) {
/* The image indicates that it can be loaded anywhere. Find a
location that can hold the memory space required. If the
image is pre-linked, LOADDR will be non-zero. Since we do
@@ -1219,14 +1226,22 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
-1, 0);
if (load_addr == -1) {
- perror("mmap");
- exit(-1);
+ goto exit_perror;
}
}
load_bias = load_addr - loaddr;
- for (i = 0; i < interp_elf_ex->e_phnum; i++) {
- struct elf_phdr *eppnt = elf_phdata + i;
+ info->load_bias = load_bias;
+ info->load_addr = load_addr;
+ info->entry = ehdr->e_entry + load_bias;
+ info->start_code = -1;
+ info->end_code = 0;
+ info->start_data = -1;
+ info->end_data = 0;
+ info->brk = 0;
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ struct elf_phdr *eppnt = phdr + i;
if (eppnt->p_type == PT_LOAD) {
abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em;
int elf_prot = 0;
@@ -1241,12 +1256,9 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
elf_prot, MAP_PRIVATE | MAP_FIXED,
- interpreter_fd, eppnt->p_offset - vaddr_po);
+ image_fd, eppnt->p_offset - vaddr_po);
if (error == -1) {
- /* Real error */
- close(interpreter_fd);
- free(elf_phdata);
- return ~((abi_ulong)0UL);
+ goto exit_perror;
}
vaddr_ef = vaddr + eppnt->p_filesz;
@@ -1256,18 +1268,79 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
if (vaddr_ef < vaddr_em) {
zero_bss(vaddr_ef, vaddr_em, elf_prot);
}
+
+ /* Find the full program boundaries. */
+ if (elf_prot & PROT_EXEC) {
+ if (vaddr < info->start_code) {
+ info->start_code = vaddr;
+ }
+ if (vaddr_ef > info->end_code) {
+ info->end_code = vaddr_ef;
+ }
+ }
+ if (elf_prot & PROT_WRITE) {
+ if (vaddr < info->start_data) {
+ info->start_data = vaddr;
+ }
+ if (vaddr_ef > info->end_data) {
+ info->end_data = vaddr_ef;
+ }
+ if (vaddr_em > info->brk) {
+ info->brk = vaddr_em;
+ }
+ }
}
}
+ if (info->end_data == 0) {
+ info->start_data = info->end_code;
+ info->end_data = info->end_code;
+ info->brk = info->end_code;
+ }
+
if (qemu_log_enabled()) {
- load_symbols(interp_elf_ex, interpreter_fd, load_bias);
+ load_symbols(ehdr, image_fd, load_bias);
}
- close(interpreter_fd);
- free(elf_phdata);
+ close(image_fd);
+ return;
+
+ exit_read:
+ if (retval >= 0) {
+ errmsg = "Incomplete read of file header";
+ goto exit_errmsg;
+ }
+ exit_perror:
+ errmsg = strerror(errno);
+ exit_errmsg:
+ fprintf(stderr, "%s: %s\n", image_name, errmsg);
+ exit(-1);
+}
+
+static void load_elf_interp(const char *filename, struct image_info *info,
+ char bprm_buf[BPRM_BUF_SIZE])
+{
+ int fd, retval;
+
+ fd = open(path(filename), O_RDONLY);
+ if (fd < 0) {
+ goto exit_perror;
+ }
- *interp_load_addr = load_addr;
- return ((abi_ulong) interp_elf_ex->e_entry) + load_bias;
+ retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
+ if (retval < 0) {
+ goto exit_perror;
+ }
+ if (retval < BPRM_BUF_SIZE) {
+ memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
+ }
+
+ load_elf_image(filename, fd, info, bprm_buf);
+ return;
+
+ exit_perror:
+ fprintf(stderr, "%s: %s\n", filename, strerror(errno));
+ exit(-1);
}
static int symfind(const void *s0, const void *s1)
@@ -1404,26 +1477,21 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
struct image_info * info)
{
+ struct image_info interp_info;
struct elfhdr elf_ex;
- struct elfhdr interp_elf_ex;
- int interpreter_fd = -1; /* avoid warning */
abi_ulong load_addr, load_bias;
int load_addr_set = 0;
- unsigned char ibcs2_interpreter;
int i;
- abi_ulong mapped_addr;
struct elf_phdr * elf_ppnt;
struct elf_phdr *elf_phdata;
abi_ulong k, elf_brk;
int retval;
- char * elf_interpreter;
- abi_ulong elf_entry, interp_load_addr = 0;
+ char *elf_interpreter = NULL;
+ abi_ulong elf_entry;
int status;
abi_ulong start_code, end_code, start_data, end_data;
- abi_ulong reloc_func_desc = 0;
abi_ulong elf_stack;
- ibcs2_interpreter = 0;
status = 0;
load_addr = 0;
load_bias = 0;
@@ -1466,7 +1534,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
elf_brk = 0;
elf_stack = ~((abi_ulong)0UL);
- elf_interpreter = NULL;
start_code = ~((abi_ulong)0UL);
end_code = 0;
start_data = 0;
@@ -1475,82 +1542,21 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
elf_ppnt = elf_phdata;
for(i=0;i < elf_ex.e_phnum; i++) {
if (elf_ppnt->p_type == PT_INTERP) {
- if ( elf_interpreter != NULL )
- {
- free (elf_phdata);
- free(elf_interpreter);
- close(bprm->fd);
- return -EINVAL;
- }
-
- /* This is the program interpreter used for
- * shared libraries - for now assume that this
- * is an a.out format binary
- */
-
- elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
-
- if (elf_interpreter == NULL) {
- free (elf_phdata);
- close(bprm->fd);
- return -ENOMEM;
- }
-
if (elf_ppnt->p_offset + elf_ppnt->p_filesz <= BPRM_BUF_SIZE) {
- memcpy(elf_interpreter, bprm->buf + elf_ppnt->p_offset,
- elf_ppnt->p_filesz);
+ 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_binary2");
+ perror("load_elf_binary");
exit(-1);
}
}
-
- /* If the program interpreter is one of these two,
- then assume an iBCS2 image. Otherwise assume
- a native linux image. */
-
- /* JRP - Need to add X86 lib dir stuff here... */
-
- if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
- strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
- ibcs2_interpreter = 1;
- }
-
- retval = open(path(elf_interpreter), O_RDONLY);
- if (retval < 0) {
- perror(elf_interpreter);
- exit(-1);
- }
- interpreter_fd = retval;
-
- retval = read(interpreter_fd, bprm->buf, BPRM_BUF_SIZE);
- if (retval < 0) {
- perror("load_elf_binary3");
- exit(-1);
- }
- if (retval < BPRM_BUF_SIZE) {
- memset(bprm->buf, 0, BPRM_BUF_SIZE - retval);
- }
-
- interp_elf_ex = *((struct elfhdr *) bprm->buf);
}
elf_ppnt++;
}
- /* Some simple consistency checks for the interpreter */
- if (elf_interpreter) {
- if (!elf_check_ident(&interp_elf_ex)) {
- free(elf_interpreter);
- free(elf_phdata);
- close(bprm->fd);
- close(interpreter_fd);
- return -ELIBBAD;
- }
- }
-
/* OK, This is the point of no return */
info->end_data = 0;
info->end_code = 0;
@@ -1648,7 +1654,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
load_bias += error -
TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
load_addr += load_bias;
- reloc_func_desc = load_bias;
}
}
k = elf_ppnt->p_vaddr;
@@ -1681,19 +1686,15 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
start_data += load_bias;
end_data += load_bias;
- if (elf_interpreter) {
- elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
- &interp_load_addr, bprm->buf);
- reloc_func_desc = interp_load_addr;
- free(elf_interpreter);
-
- if (elf_entry == ~((abi_ulong)0UL)) {
- printf("Unable to load interpreter\n");
- free(elf_phdata);
- exit(-1);
- return 0;
- }
- }
+ 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);
@@ -1702,46 +1703,38 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
}
close(bprm->fd);
- info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
-#ifdef LOW_ELF_STACK
- info->start_stack = bprm->p = elf_stack - 4;
-#endif
- bprm->p = create_elf_tables(bprm->p,
- bprm->argc,
- bprm->envc,
- &elf_ex,
- load_addr, load_bias,
- interp_load_addr,
- info);
- info->load_addr = reloc_func_desc;
- 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->start_stack = bprm->p;
+ if (elf_interpreter) {
+ load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
-#if 0
- printf("(start_brk) %x\n" , info->start_brk);
- printf("(end_code) %x\n" , info->end_code);
- printf("(start_code) %x\n" , info->start_code);
- printf("(end_data) %x\n" , info->end_data);
- printf("(start_stack) %x\n" , info->start_stack);
- printf("(brk) %x\n" , info->brk);
-#endif
+ /* If the program interpreter is one of these two, then assume
+ an iBCS2 image. Otherwise assume a native linux image. */
- if ( info->personality == PER_SVR4 )
- {
- /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
- and some applications "depend" upon this behavior.
- Since we do not have the power to recompile these, we
- emulate the SVr4 behavior. Sigh. */
- mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE, -1, 0);
+ if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0
+ || strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) {
+ info->personality = PER_SVR4;
+
+ /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
+ and some applications "depend" upon this behavior. Since
+ we do not have the power to recompile these, we emulate
+ the SVr4 behavior. Sigh. */
+ target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE, -1, 0);
+ }
}
- info->entry = elf_entry;
+ bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &elf_ex,
+ info, (elf_interpreter ? &interp_info : NULL));
+ info->start_stack = bprm->p;
+
+ /* If we have an interpreter, set that as the program's entry point.
+ Copy the load_addr as well, to help PPC64 interpret the entry
+ point as a function descriptor. Do this after creating elf tables
+ so that we copy the original program entry point into the AUXV. */
+ if (elf_interpreter) {
+ info->load_addr = interp_info.load_addr;
+ info->entry = interp_info.entry;
+ }
#ifdef USE_ELF_CORE_DUMP
bprm->core_dump = &elf_core_dump;
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 13/14] linux-user: Build vdso for x64.
2010-04-28 19:36 ` [Qemu-devel] [PATCH 00/14] Implement VDSO for x86-64-linux-user, v2 Richard Henderson
` (8 preceding siblings ...)
2010-04-28 19:39 ` [Qemu-devel] [PATCH 11/14] linux-user: Extract load_elf_image from load_elf_interp Richard Henderson
@ 2010-04-28 19:39 ` Richard Henderson
2010-04-28 19:39 ` [Qemu-devel] [PATCH 14/14] linux-user: Load a VDSO for x86-64 Richard Henderson
` (3 subsequent siblings)
13 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-28 19:39 UTC (permalink / raw)
To: qemu-devel
... Well, sortof. The Makefile bits are broken.
Patch to load the vdso into the running program to follow.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
Makefile | 3 +-
pc-bios/Makefile | 5 ++
pc-bios/vdso-linux-x64.S | 102 +++++++++++++++++++++++++++++++++++++++++++++
pc-bios/vdso-linux-x64.ld | 81 +++++++++++++++++++++++++++++++++++
pc-bios/vdso-linux-x64.so | Bin 0 -> 7515 bytes
5 files changed, 190 insertions(+), 1 deletions(-)
create mode 100644 pc-bios/vdso-linux-x64.S
create mode 100644 pc-bios/vdso-linux-x64.ld
create mode 100755 pc-bios/vdso-linux-x64.so
diff --git a/Makefile b/Makefile
index 18e7368..c6d1de5 100644
--- a/Makefile
+++ b/Makefile
@@ -180,7 +180,8 @@ pxe-e1000.bin \
pxe-ne2k_pci.bin pxe-pcnet.bin \
pxe-rtl8139.bin pxe-virtio.bin \
bamboo.dtb petalogix-s3adsp1800.dtb \
-multiboot.bin linuxboot.bin
+multiboot.bin linuxboot.bin \
+vdso-linux-x64.so
else
BLOBS=
endif
diff --git a/pc-bios/Makefile b/pc-bios/Makefile
index 315288d..70e2485 100644
--- a/pc-bios/Makefile
+++ b/pc-bios/Makefile
@@ -15,5 +15,10 @@ all: $(TARGETS)
%.dtb: %.dts
dtc -I dts -O dtb -o $@ $<
+vdso-linux-x64.so: vdso-linux-x64.o vdso-linux-x64.ld
+ $(CC) -nostdlib -shared -Wl,-T,vdso-linux-x64.ld \
+ -Wl,-h,linux-vdso.so.1 -Wl,--hash-style=both \
+ vdso-linux-x64.o -o $@
+
clean:
rm -f $(TARGETS) *.o *~
diff --git a/pc-bios/vdso-linux-x64.S b/pc-bios/vdso-linux-x64.S
new file mode 100644
index 0000000..e7784c9
--- /dev/null
+++ b/pc-bios/vdso-linux-x64.S
@@ -0,0 +1,102 @@
+/*
+ * x86-64 linux replacement vdso.
+ *
+ * Copyright (c) 2010 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <asm/unistd.h>
+
+ .globl __vdso_clock_gettime
+ .type __vdso_clock_gettime, @function
+ .balign 16
+ .cfi_startproc
+__vdso_clock_gettime:
+ mov $__NR_clock_gettime, %eax
+ syscall
+ ret
+ .cfi_endproc
+ .size __vdso_clock_gettime, . - __vdso_clock_gettime
+
+clock_gettime = __vdso_clock_gettime
+ .weak clock_gettime
+
+
+ .globl __vdso_gettimeofday
+ .type __vdso_gettimeofday, @function
+ .balign 16
+ .cfi_startproc
+__vdso_gettimeofday:
+ mov $__NR_gettimeofday, %eax
+ syscall
+ ret
+ .cfi_endproc
+ .size __vdso_gettimeofday, . - __vdso_gettimeofday
+
+gettimeofday = __vdso_gettimeofday
+ .weak gettimeofday
+
+
+ .globl __vdso_getcpu
+ .type __vdso_getcpu, @function
+ .balign 16
+ .cfi_startproc
+__vdso_getcpu:
+ /* ??? There is no syscall number for this allocated on x64.
+ We can handle this several ways:
+
+ (1) Invent a syscall number for use within qemu.
+ It should be easy enough to pick a number that
+ is well out of the way of the kernel numbers.
+
+ (2) Force the emulated cpu to support the rdtscp insn,
+ and initialize the TSC_AUX value the appropriate value.
+
+ (3) Pretend that we're always running on cpu 0.
+
+ This last is the one that's implemented here, with the
+ tiny bit of extra code to support rdtscp in place. */
+
+ xor %ecx, %ecx /* rdtscp w/ tsc_aux = 0 */
+
+ /* if (cpu != NULL) *cpu = (ecx & 0xfff); */
+ test %rdi, %rdi
+ jz 1f
+ mov %ecx, %eax
+ and $0xfff, %eax
+ mov %eax, (%rdi)
+
+ /* if (node != NULL) *node = (ecx >> 12); */
+1: test %rsi, %rsi
+ jz 2f
+ shr $12, %ecx
+ mov %ecx, (%rsi)
+
+2: xor %eax, %eax
+ ret
+ .cfi_endproc
+ .size __vdso_getcpu, . - __vdso_getcpu
+
+getcpu = __vdso_getcpu
+ .weak getcpu
+
+/* ??? Perhaps add elf notes. E.g.
+
+ #include <linux/elfnote.h>
+ ELFNOTE_START(Linux, 0, "a")
+ .long LINUX_VERSION_CODE
+ ELFNOTE_END
+
+ but what version number would we set for QEMU? */
diff --git a/pc-bios/vdso-linux-x64.ld b/pc-bios/vdso-linux-x64.ld
new file mode 100644
index 0000000..d57d0e7
--- /dev/null
+++ b/pc-bios/vdso-linux-x64.ld
@@ -0,0 +1,81 @@
+/*
+ * Linker script for linux x64 replacement vdso.
+ *
+ * Copyright (c) 2010 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+VERSION {
+ LINUX_2.6 {
+ global:
+ clock_gettime;
+ __vdso_clock_gettime;
+ gettimeofday;
+ __vdso_gettimeofday;
+ getcpu;
+ __vdso_getcpu;
+ local: *;
+ };
+}
+
+PHDRS {
+ phdr PT_PHDR FLAGS(4) PHDRS;
+ data PT_LOAD FLAGS(6) FILEHDR PHDRS;
+ text PT_LOAD FLAGS(5);
+ dynamic PT_DYNAMIC FLAGS(4);
+ note PT_NOTE FLAGS(4);
+ /* ??? Various versions of ld don't know PT_GNU_EH_FRAME. */
+ eh_frame_hdr 0x6474e550;
+}
+
+SECTIONS {
+ /* ??? We can't really prelink to any address without knowing
+ something about the virtual memory space of the host, since
+ that leaks over into the available memory space of the guest. */
+ . = SIZEOF_HEADERS;
+
+ /* The following, including the FILEHDRS and PHDRS, are modified
+ when we relocate the binary. We want them to be initially
+ writable for the relocation; we'll force them read-only after. */
+ .dynamic : { *(.dynamic) } :data :dynamic
+ .dynsym : { *(.dynsym) } :data
+ .data : {
+ /* There ought not be any real read-write data.
+ But since we manipulated the segment layout,
+ we have to put these sections somewhere. */
+ *(.data*)
+ *(.sdata*)
+ *(.got.plt) *(.got)
+ *(.gnu.linkonce.d.*)
+ *(.bss*)
+ *(.dynbss*)
+ *(.gnu.linkonce.b.*)
+ }
+
+ . += 4096;
+ .hash : { *(.hash) } :text
+ .gnu.hash : { *(.gnu.hash) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .note : { *(.note*) } :text :note
+ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
+ .eh_frame : { *(.eh_frame) } :text
+ .rodata : { *(.rodata) }
+
+ . = ALIGN(0x100);
+ .text : { *(.text*) } :text =0x90909090
+}
diff --git a/pc-bios/vdso-linux-x64.so b/pc-bios/vdso-linux-x64.so
new file mode 100755
index 0000000000000000000000000000000000000000..5ebf5959f9dac5065428148e7625f58c722e1cca
GIT binary patch
literal 7515
zcmeHMO>Z1U5Uus%*iM{y6Cwl{#0nW7EEvfVLXjZIcKj8xI3d_l!ezYij=dJ%U9iWI
z%^?^OD>4#Nj&MZWI6#g*@TnkV@(Xf7Z~z1s6b@K90872;dYhfeh7%G(Oxr!L>s3`x
zcTM-~sQUG>!gyOIBP>~YRwC&>#|)Wb$7F~@a#Z%{H7ENOMed0>XrOb2c-p!qcA6eE
zeD78^vQ9%3$wvhI+O=-n8;N(|CvA==(hoGodBw()L^o+QFg?c!AJlga>!k(uIa-LY
zMLGRLSVH?_^GhP_iS#=Vd5cEa74n?#Z-3Tn&}`fM5et-CCNrj2EDn2}TFw~mGrZsM
z_qywE*2ejV$>uIMO@7Yw=Ju~ZR<csIb-@APIXx=fBDOyH+#nuOK9}GhHv1%x#}4~s
zKa<KIlwa!#u`-|%?DN(?`b8Pkit!|QuD8f2y`&LHBalWQjX)ZKGy-V^(g>sxNF$I&
zAdNs8fiwdDs|X;S(WMo63*>s3&(UU7n9pH82KF6Vf#8t0fXy3+^O=!AHo&0|a2IF3
zc~!3WUcG#B^T!9?KVE%n;H&=rtLKBt*~@kD{R^d)nm@Nxn|s+`2*Pl&5|A{pHeV{P
zH*s^Xtjf}2b#?6txO)0OD1{SKGiUuH-cx!%jHvk!Ove7+`|OwfNFhC>mANg9y-oGI
zs~={WUP8VF1+f5!c}`5t$n~E(zYGQjCO+st_x8J=e$+R<aq`<tZ}#cD*^Fvu&uDvE
zaaysYxTMH_Gq0VI%vvtf+uhNLTnu=O1p#Ev2qO3=wcgU2<O|B()XH3sHvjWw`+J>2
zPy4l=M=nKk*`AHdgI`Z>*2Au?oyY1uB3m7ko4aBA7e9Az9T@!lns_Vgm9ThTF<f?7
zW~;PbEmjui#M6daDHg+`cnj54uUuRyJ3d@?%!OciWwBO`34TeuYAp=J3(Efda<LNl
z<&xS{5-$wa!f4R{z@=CFz@EW+Lt(y-h;@R({m8YEb99vdMQ)Y*l=)ZU4YPwkZ0OHC
z?BmMe7Q8?6oJ88GNmS@h#Qwv+=lz*4CLVQe4L$v^&rptN-PK$#{h41T4#7wZ_4IeF
z+k1Q`fnz?J$ow<yEu0i(R9p3?`!nB6JY<%<e-d9%J#yFNXR(pB5IO&3{GFBBX#?+7
z`X}@KeKa&=+(^%B19PJP-SYjkPx@maH~W8Q<0sD2(J&eRi{{Vu$vigkSi+y{mh?ew
zaP5%;9<%)RrDjsw$>-NR_GZ(a2c49&!01avP&t0CYy1Yby8n&nB`xx%>!xu{-oK$}
z(a7p(8~eCPpVg<u{n<q8IPN@WfIh3gO59Iz`}W3pOq}1-*avaGL%6Qvd}m|5#`&(s
z`BR+V+c;l}^ZSJBCeGhJ-yn}TX7qd`86TV*f#>^&_IYizI&blmZ*@+Beb?$72EV1P
z&QD&l{*&i33&tnURjSqx*E!df_@n2hhMzxiT>Oc`sgdD=e`<XE#j$CBdU&KT=1cs$
X=k`~OeHQ)A7f?*40=|k`eoXxZDW(!W
literal 0
HcmV?d00001
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 14/14] linux-user: Load a VDSO for x86-64.
2010-04-28 19:36 ` [Qemu-devel] [PATCH 00/14] Implement VDSO for x86-64-linux-user, v2 Richard Henderson
` (9 preceding siblings ...)
2010-04-28 19:39 ` [Qemu-devel] [PATCH 13/14] linux-user: Build vdso for x64 Richard Henderson
@ 2010-04-28 19:39 ` Richard Henderson
2010-04-28 19:39 ` [Qemu-devel] [PATCH 07/14] linux-user: Load symbols from the interpreter Richard Henderson
` (2 subsequent siblings)
13 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-28 19:39 UTC (permalink / raw)
To: qemu-devel
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 193 insertions(+), 8 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 5771344..e8eca86 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -183,6 +183,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
(*regs)[26] = env->segs[R_GS].selector & 0xffff;
}
+#define VDSO_BASENAME "vdso-linux-x64.so"
+
#else
#define ELF_START_MMAP 0x80000000
@@ -801,6 +803,10 @@ static inline void init_thread(struct target_pt_regs *regs,
#define ELF_HWCAP 0
#endif
+#ifndef VDSO_BASENAME
+#define VDSO_BASENAME NULL
+#endif
+
#ifdef TARGET_ABI32
#undef ELF_CLASS
#define ELF_CLASS ELFCLASS32
@@ -1077,7 +1083,8 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
struct elfhdr *exec,
struct image_info *info,
- struct image_info *interp_info)
+ struct image_info *interp_info,
+ struct image_info *vdso_info)
{
abi_ulong sp;
int size;
@@ -1100,16 +1107,21 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
*/
sp = sp &~ (abi_ulong)15;
size = (DLINFO_ITEMS + 1) * 2;
- if (k_platform)
+ if (k_platform) {
size += 2;
+ }
+ if (vdso_info) {
+ size += 4;
+ }
#ifdef DLINFO_ARCH_ITEMS
size += DLINFO_ARCH_ITEMS * 2;
#endif
size += envc + argc + 2;
size += 1; /* argc itself */
size *= n;
- if (size & 15)
+ if (size & 15) {
sp -= 16 - (size & 15);
+ }
/* This is correct because Linux defines
* elf_addr_t as Elf32_Off / Elf64_Off
@@ -1126,7 +1138,9 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
- NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info->load_addr));
+ if (interp_info) {
+ NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info->load_addr));
+ }
NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
NEW_AUX_ENT(AT_ENTRY, info->entry);
NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
@@ -1135,8 +1149,13 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
- if (k_platform)
+ if (k_platform) {
NEW_AUX_ENT(AT_PLATFORM, u_platform);
+ }
+ if (vdso_info) {
+ NEW_AUX_ENT(AT_SYSINFO, vdso_info->entry);
+ NEW_AUX_ENT(AT_SYSINFO_EHDR, vdso_info->load_addr);
+ }
#ifdef ARCH_DLINFO
/*
* ARCH_DLINFO must come last so platform specific code can enforce
@@ -1381,6 +1400,165 @@ static void load_elf_interp(const char *filename, struct image_info *info,
exit(-1);
}
+static void load_elf_vdso(const char *basename, struct image_info *info,
+ char bprm_buf[BPRM_BUF_SIZE])
+{
+ const char *errmsg;
+ char *filename;
+ int fd, retval, i;
+ abi_ulong load_bias;
+
+ /* ??? What we really need access to is qemu_find_file, but that is
+ only built for system targets at the moment. */
+ filename = alloca(strlen(CONFIG_QEMU_SHAREDIR "/") + strlen(basename) + 1);
+ stpcpy(stpcpy(filename, CONFIG_QEMU_SHAREDIR "/"), basename);
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ goto exit_perror;
+ }
+
+ retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
+ if (retval < 0) {
+ goto exit_perror;
+ }
+ if (retval < BPRM_BUF_SIZE) {
+ memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
+ }
+
+ load_elf_image(basename, fd, info, NULL, bprm_buf);
+ load_bias = info->load_bias;
+
+ /* We most likely need to relocate the VDSO image. The one built into
+ the kernel is built for a fixed address. The one built for QEMU is
+ not, since that requires close control of the guest address space. */
+ if (load_bias) {
+ struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
+ struct elf_phdr *phdr;
+ abi_ulong dynamic_addr = -1;
+ abi_ulong dynsym_addr = -1;
+
+ /* ??? Assume QEMU's VDSO is built "properly", which arranges
+ for the PHDRs, and all the sections manipulated below, to
+ be included with a writable load segment. */
+
+ /* ??? One might think that we'd need to relocate ehdr.e_entry,
+ but for some reason glibc does that one itself, though that
+ is also available via the AT_SYSINFO entry. */
+
+ /* Relocate the program headers. */
+ phdr = (struct elf_phdr *)g2h(info->load_addr + ehdr->e_phoff);
+ bswap_phdr(phdr, ehdr->e_phnum);
+ for (i = 0; i < ehdr->e_phnum; ++i) {
+ phdr[i].p_vaddr += load_bias;
+ phdr[i].p_paddr += load_bias;
+ if (phdr[i].p_type == PT_DYNAMIC) {
+ dynamic_addr = phdr[i].p_vaddr;
+ }
+ }
+ bswap_phdr(phdr, ehdr->e_phnum);
+
+ /* Relocate the DYNAMIC entries. */
+ if (dynamic_addr != -1) {
+ abi_ulong tag, val, *dyn = (abi_ulong *)g2h(dynamic_addr);
+ do {
+ tag = tswapl(dyn[0]);
+ val = tswapl(dyn[1]);
+ switch (tag) {
+ case DT_SYMTAB:
+ dynsym_addr = load_bias + val;
+ dyn[1] = tswapl(dynsym_addr);
+ break;
+ case DT_SYMENT:
+ if (val != sizeof(struct elf_sym)) {
+ errmsg = "VDSO has an unexpected dynamic symbol size";
+ goto exit_errmsg;
+ }
+ break;
+
+ case DT_HASH:
+ case DT_STRTAB:
+ case DT_VERDEF:
+ case DT_VERSYM:
+ case DT_ADDRRNGLO ... DT_ADDRRNGHI:
+ /* These entries store an address in the entry. */
+ dyn[1] = tswapl(load_bias + val);
+ break;
+
+ case DT_NULL:
+ case DT_STRSZ:
+ case DT_SONAME:
+ case DT_DEBUG:
+ case DT_FLAGS:
+ case DT_FLAGS_1:
+ case DT_VERDEFNUM:
+ case DT_VALRNGLO ... DT_VALRNGHI:
+ /* These entries store an integer in the entry. */
+ break;
+
+ case DT_REL:
+ case DT_RELA:
+ /* These entries indicate that the VDSO was built
+ incorrectly. It should not have real relocations. */
+ errmsg = "VDSO has relocations";
+ goto exit_errmsg;
+ case DT_NEEDED:
+ case DT_VERNEED:
+ errmsg = "VDSO has external dependancies";
+ goto exit_errmsg;
+
+ default:
+ /* This is probably something target specific. */
+ errmsg = "VDSO has unknown DYNAMIC entry";
+ goto exit_errmsg;
+ }
+ dyn += 2;
+ } while (tag != DT_NULL);
+ }
+
+ /* Relocate the dynamic symbol table. */
+ if (dynsym_addr != -1) {
+ struct elf_shdr *shdr;
+ struct elf_sym *sym;
+ int dynsym_size = 0;
+
+ /* Read the section headers to find out the size of the
+ dynamic symbol table. */
+ shdr = (struct elf_shdr *)g2h(info->load_addr + ehdr->e_shoff);
+ for (i = 0; i < ehdr->e_shnum; ++i) {
+ abi_ulong addr = tswapl(shdr[i].sh_addr) + load_bias;
+ if (addr == dynsym_addr) {
+ dynsym_size = tswapl(shdr[i].sh_size);
+ break;
+ }
+ }
+
+ sym = (struct elf_sym *)g2h(dynsym_addr);
+ for (i = 0; i < dynsym_size / sizeof(*sym); ++i) {
+ sym[i].st_value = tswapl(tswapl(sym[i].st_value) + load_bias);
+ }
+ }
+ }
+
+ /* Mark the VDSO writable segment read-only. */
+ /* ??? This assumes that the VDSO implementation doesn't actually
+ have any truely writable data. Perhaps we should instead use
+ the PT_GNU_RELRO header to indicate that we really want this. */
+ retval = target_mprotect(info->start_data, info->brk - info->start_data,
+ PROT_READ);
+ if (retval < 0) {
+ goto exit_perror;
+ }
+ return;
+
+ exit_perror:
+ errmsg = strerror(errno);
+ exit_errmsg:
+ fprintf(stderr, "%s: %s\n", filename, errmsg);
+ exit(-1);
+}
+
+
static int symfind(const void *s0, const void *s1)
{
struct elf_sym *key = (struct elf_sym *)s0;
@@ -1515,7 +1693,7 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
struct image_info * info)
{
- struct image_info interp_info;
+ struct image_info interp_info, vdso_info;
struct elfhdr elf_ex;
char *elf_interpreter = NULL;
@@ -1562,8 +1740,15 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
}
}
- bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &elf_ex,
- info, (elf_interpreter ? &interp_info : NULL));
+ /* If we've been given a VDSO to load, do so. */
+ if (VDSO_BASENAME) {
+ load_elf_vdso(VDSO_BASENAME, &vdso_info, bprm->buf);
+ }
+
+ bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc,
+ &elf_ex, info,
+ (elf_interpreter ? &interp_info : NULL),
+ (VDSO_BASENAME ? &vdso_info : NULL));
info->start_stack = bprm->p;
/* If we have an interpreter, set that as the program's entry point.
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 07/14] linux-user: Load symbols from the interpreter.
2010-04-28 19:36 ` [Qemu-devel] [PATCH 00/14] Implement VDSO for x86-64-linux-user, v2 Richard Henderson
` (10 preceding siblings ...)
2010-04-28 19:39 ` [Qemu-devel] [PATCH 14/14] linux-user: Load a VDSO for x86-64 Richard Henderson
@ 2010-04-28 19:39 ` Richard Henderson
2010-04-28 19:39 ` [Qemu-devel] [PATCH 03/14] linux-user: Reindent elfload.c Richard Henderson
2010-04-28 19:39 ` [Qemu-devel] [PATCH 12/14] linux-user: Re-use load_elf_image for the main binary Richard Henderson
13 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-28 19:39 UTC (permalink / raw)
To: qemu-devel
First, adjust load_symbols to accept a load_bias parameter. At the same
time, read the entire section header table in one go, use pread instead
f lseek+read for the symbol and string tables, and properly free
allocated structures on error exit paths.
Second, adjust load_elf_interp to compute load_bias. This requires
finding out the built-in load addresses. Which allows us to honor a
pre-linked interpreter image when possible, and eliminate the hard-coded
INTERP_MAP_SIZE value.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 189 +++++++++++++++++++++++++++-----------------------
1 files changed, 101 insertions(+), 88 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 9cf1eeb..7e94fe3 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 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)
@@ -920,6 +917,7 @@ static inline void bswap_sym(struct elf_sym *sym) { }
#ifdef USE_ELF_CORE_DUMP
static int elf_core_dump(int, const CPUState *);
#endif /* USE_ELF_CORE_DUMP */
+static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias);
/*
* 'copy_elf_strings()' copies argument/envelope strings from user
@@ -1145,15 +1143,11 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
char bprm_buf[BPRM_BUF_SIZE])
{
struct elf_phdr *elf_phdata = NULL;
- struct elf_phdr *eppnt;
- abi_ulong load_addr = 0;
- int load_addr_set = 0;
+ abi_ulong load_addr, load_bias, loaddr, hiaddr;
int retval;
abi_ulong error;
int i;
- error = 0;
-
bswap_ehdr(interp_elf_ex);
/* First of all, some simple consistency checks */
if ((interp_elf_ex->e_type != ET_EXEC &&
@@ -1162,7 +1156,6 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
return ~((abi_ulong)0UL);
}
-
/* Now read in all of the header information */
if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
@@ -1195,41 +1188,56 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
}
bswap_phdr(elf_phdata, interp_elf_ex->e_phnum);
+ /* Find the maximum size of the image and allocate an appropriate
+ amount of memory to handle that. */
+ loaddr = -1, hiaddr = 0;
+ for (i = 0; i < interp_elf_ex->e_phnum; ++i) {
+ if (elf_phdata[i].p_type == PT_LOAD) {
+ abi_ulong a = elf_phdata[i].p_vaddr;
+ if (a < loaddr) {
+ loaddr = a;
+ }
+ a += elf_phdata[i].p_memsz;
+ if (a > hiaddr) {
+ hiaddr = a;
+ }
+ }
+ }
+
+ load_addr = loaddr;
if (interp_elf_ex->e_type == ET_DYN) {
- /* in order to avoid hardcoding the interpreter load
- address in qemu, we allocate a big enough memory zone */
- error = target_mmap(0, INTERP_MAP_SIZE,
- PROT_NONE, MAP_PRIVATE | MAP_ANON,
- -1, 0);
- if (error == -1) {
+ /* The image indicates that it can be loaded anywhere. Find a
+ location that can hold the memory space required. If the
+ image is pre-linked, LOADDR will be non-zero. Since we do
+ not supply MAP_FIXED here we'll use that address if and
+ only if it remains available. */
+ load_addr = target_mmap(loaddr, hiaddr - loaddr, PROT_NONE,
+ MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
+ -1, 0);
+ if (load_addr == -1) {
perror("mmap");
exit(-1);
}
- load_addr = error;
- load_addr_set = 1;
}
+ load_bias = load_addr - loaddr;
- eppnt = elf_phdata;
- for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
+ for (i = 0; i < interp_elf_ex->e_phnum; i++) {
+ struct elf_phdr *eppnt = elf_phdata + i;
if (eppnt->p_type == PT_LOAD) {
- int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+ abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em;
int elf_prot = 0;
- abi_ulong vaddr = 0;
if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
- if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
- elf_type |= MAP_FIXED;
- vaddr = eppnt->p_vaddr;
- }
- error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
- eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
- elf_prot,
- elf_type,
- interpreter_fd,
- eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
+ vaddr = load_bias + eppnt->p_vaddr;
+ vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
+ vaddr_ps = TARGET_ELF_PAGESTART(vaddr);
+
+ error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
+ elf_prot, MAP_PRIVATE | MAP_FIXED,
+ interpreter_fd, eppnt->p_offset - vaddr_po);
if (error == -1) {
/* Real error */
close(interpreter_fd);
@@ -1237,26 +1245,25 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
return ~((abi_ulong)0UL);
}
- if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
- load_addr = error;
- load_addr_set = 1;
- }
+ vaddr_ef = vaddr + eppnt->p_filesz;
+ vaddr_em = vaddr + eppnt->p_memsz;
/* If the load segment requests extra zeros (e.g. bss), map it. */
- if (eppnt->p_filesz < eppnt->p_memsz) {
- abi_ulong base = load_addr + eppnt->p_vaddr;
- zero_bss(base + eppnt->p_filesz,
- base + eppnt->p_memsz, elf_prot);
+ if (vaddr_ef < vaddr_em) {
+ zero_bss(vaddr_ef, vaddr_em, elf_prot);
}
}
+ }
- /* Now use mmap to map the library into memory. */
+ if (qemu_log_enabled()) {
+ load_symbols(interp_elf_ex, interpreter_fd, load_bias);
+ }
close(interpreter_fd);
free(elf_phdata);
*interp_load_addr = load_addr;
- return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
+ return ((abi_ulong) interp_elf_ex->e_entry) + load_bias;
}
static int symfind(const void *s0, const void *s1)
@@ -1305,82 +1312,87 @@ static int symcmp(const void *s0, const void *s1)
}
/* Best attempt to load symbols from this ELF object. */
-static void load_symbols(struct elfhdr *hdr, int fd)
+static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
{
- unsigned int i, nsyms;
- struct elf_shdr sechdr, symtab, strtab;
+ int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
+ struct elf_shdr *shdr;
char *strings;
struct syminfo *s;
struct elf_sym *syms;
- lseek(fd, hdr->e_shoff, SEEK_SET);
- for (i = 0; i < hdr->e_shnum; i++) {
- if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
- return;
- bswap_shdr(&sechdr, 1);
- if (sechdr.sh_type == SHT_SYMTAB) {
- symtab = sechdr;
- lseek(fd, hdr->e_shoff
- + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
- if (read(fd, &strtab, sizeof(strtab))
- != sizeof(strtab))
- return;
- bswap_shdr(&strtab, 1);
+ shnum = hdr->e_shnum;
+ i = shnum * sizeof(struct elf_shdr);
+ shdr = (struct elf_shdr *)alloca(i);
+ if (pread(fd, shdr, i, hdr->e_shoff) != i) {
+ return;
+ }
+
+ bswap_shdr(shdr, shnum);
+ for (i = 0; i < shnum; ++i) {
+ if (shdr[i].sh_type == SHT_SYMTAB) {
+ sym_idx = i;
+ str_idx = shdr[i].sh_link;
goto found;
}
}
- return; /* Shouldn't happen... */
+
+ /* There will be no symbol table if the file was stripped. */
+ return;
found:
- /* Now know where the strtab and symtab are. Snarf them. */
+ /* Now know where the strtab and symtab are. Snarf them. */
s = malloc(sizeof(*s));
- syms = malloc(symtab.sh_size);
- if (!syms)
- return;
- s->disas_strtab = strings = malloc(strtab.sh_size);
- if (!s->disas_strtab)
+ if (!s) {
return;
+ }
- lseek(fd, symtab.sh_offset, SEEK_SET);
- if (read(fd, syms, symtab.sh_size) != symtab.sh_size)
+ i = shdr[str_idx].sh_size;
+ s->disas_strtab = strings = malloc(i);
+ if (!strings || pread(fd, strings, i, shdr[str_idx].sh_offset) != i) {
+ free(s);
+ free(strings);
return;
+ }
- nsyms = symtab.sh_size / sizeof(struct elf_sym);
+ i = shdr[sym_idx].sh_size;
+ syms = malloc(i);
+ if (!syms || pread(fd, syms, i, shdr[sym_idx].sh_offset) != i) {
+ free(s);
+ free(strings);
+ free(syms);
+ return;
+ }
- i = 0;
- while (i < nsyms) {
+ nsyms = i / sizeof(struct elf_sym);
+ for (i = 0; i < nsyms; ) {
bswap_sym(syms + i);
- // Throw away entries which we do not need.
- if (syms[i].st_shndx == SHN_UNDEF ||
- syms[i].st_shndx >= SHN_LORESERVE ||
- ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
- nsyms--;
- if (i < nsyms) {
+ /* Throw away entries which we do not need. */
+ if (syms[i].st_shndx == SHN_UNDEF
+ || syms[i].st_shndx >= SHN_LORESERVE
+ || ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
+ if (i < --nsyms) {
syms[i] = syms[nsyms];
}
- continue;
- }
+ } else {
#if defined(TARGET_ARM) || defined (TARGET_MIPS)
- /* The bottom address bit marks a Thumb or MIPS16 symbol. */
- syms[i].st_value &= ~(target_ulong)1;
+ /* The bottom address bit marks a Thumb or MIPS16 symbol. */
+ syms[i].st_value &= ~(target_ulong)1;
#endif
- i++;
+ syms[i].st_value += load_bias;
+ i++;
+ }
}
- syms = realloc(syms, nsyms * sizeof(*syms));
+ syms = realloc(syms, nsyms * sizeof(*syms));
qsort(syms, nsyms, sizeof(*syms), symcmp);
- lseek(fd, strtab.sh_offset, SEEK_SET);
- if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
- return;
s->disas_num_syms = nsyms;
#if ELF_CLASS == ELFCLASS32
s->disas_symtab.elf32 = syms;
- s->lookup_symbol = lookup_symbolxx;
#else
s->disas_symtab.elf64 = syms;
- s->lookup_symbol = lookup_symbolxx;
#endif
+ s->lookup_symbol = lookup_symbolxx;
s->next = syminfos;
syminfos = s;
}
@@ -1727,8 +1739,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
free(elf_phdata);
- if (qemu_log_enabled())
- load_symbols(&elf_ex, bprm->fd);
+ if (qemu_log_enabled()) {
+ load_symbols(&elf_ex, bprm->fd, load_bias);
+ }
if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 03/14] linux-user: Reindent elfload.c.
2010-04-28 19:36 ` [Qemu-devel] [PATCH 00/14] Implement VDSO for x86-64-linux-user, v2 Richard Henderson
` (11 preceding siblings ...)
2010-04-28 19:39 ` [Qemu-devel] [PATCH 07/14] linux-user: Load symbols from the interpreter Richard Henderson
@ 2010-04-28 19:39 ` Richard Henderson
2010-04-28 19:39 ` [Qemu-devel] [PATCH 12/14] linux-user: Re-use load_elf_image for the main binary Richard Henderson
13 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-28 19:39 UTC (permalink / raw)
To: qemu-devel
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 594 +++++++++++++++++++++++++-------------------------
1 files changed, 301 insertions(+), 293 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index ead22fc..ab741fd 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -35,18 +35,17 @@
* 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,
+ 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,
};
/*
@@ -56,30 +55,29 @@ enum {
* 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,
+ 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,
};
/*
@@ -126,7 +124,7 @@ static const char *get_elf_platform(void)
static uint32_t get_elf_hwcap(void)
{
- return thread_env->cpuid_features;
+ return thread_env->cpuid_features;
}
#ifdef TARGET_X86_64
@@ -201,7 +199,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_386
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
regs->esp = infop->start_stack;
regs->eip = infop->entry;
@@ -267,13 +266,14 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#endif
#define ELF_ARCH EM_ARM
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static 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_cpsr |= CPSR_T;
regs->ARM_pc = infop->entry & 0xfffffffe;
regs->ARM_sp = infop->start_stack;
/* FIXME - what to for failure of get_user()? */
@@ -317,26 +317,26 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
enum
{
- 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,
- ARM_HWCAP_ARM_JAVA = 1 << 8,
- ARM_HWCAP_ARM_IWMMXT = 1 << 9,
- ARM_HWCAP_ARM_THUMBEE = 1 << 10,
- ARM_HWCAP_ARM_NEON = 1 << 11,
- ARM_HWCAP_ARM_VFPv3 = 1 << 12,
- ARM_HWCAP_ARM_VFPv3D16 = 1 << 13,
+ 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,
+ ARM_HWCAP_ARM_JAVA = 1 << 8,
+ ARM_HWCAP_ARM_IWMMXT = 1 << 9,
+ ARM_HWCAP_ARM_THUMBEE = 1 << 10,
+ ARM_HWCAP_ARM_NEON = 1 << 11,
+ ARM_HWCAP_ARM_VFPv3 = 1 << 12,
+ ARM_HWCAP_ARM_VFPv3D16 = 1 << 13,
};
-#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 \
- | ARM_HWCAP_ARM_NEON | ARM_HWCAP_ARM_VFPv3 )
+#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 \
+ | ARM_HWCAP_ARM_NEON | ARM_HWCAP_ARM_VFPv3 )
#endif
@@ -357,7 +357,8 @@ enum
#define STACK_BIAS 2047
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
#ifndef TARGET_ABI32
regs->tstate = 0;
@@ -384,7 +385,8 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_SPARC
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
regs->psr = 0;
regs->pc = infop->entry;
@@ -464,7 +466,7 @@ static uint32_t get_elf_hwcap(void)
/* We don't have to be terribly complete here; the high points are
Altivec/FP/SPE support. Anything else is just a bonus. */
-#define GET_FEATURE(flag, feature) \
+#define GET_FEATURE(flag, feature) \
do {if (e->insns_flags & flag) features |= feature; } while(0)
GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64);
GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU);
@@ -489,17 +491,17 @@ static uint32_t get_elf_hwcap(void)
* 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)
+#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)
{
@@ -559,7 +561,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#endif
#define ELF_ARCH EM_MIPS
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
regs->cp0_status = 2 << CP0St_KSU;
regs->cp0_epc = infop->entry;
@@ -626,7 +629,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_XILINX_MICROBLAZE
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
regs->pc = infop->entry;
regs->r1 = infop->start_stack;
@@ -647,11 +651,12 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_SH
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+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;
+ /* Check other registers XXXXX */
+ regs->pc = infop->entry;
+ regs->regs[15] = infop->start_stack;
}
/* See linux kernel: arch/sh/include/asm/elf.h. */
@@ -669,7 +674,8 @@ enum {
TARGET_REG_SYSCALL = 22
};
-static inline void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
+static inline void elf_core_copy_regs(target_elf_gregset_t *regs,
+ const CPUState *env)
{
int i;
@@ -701,9 +707,10 @@ static inline void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState
#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_CRIS
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
- regs->erp = infop->entry;
+ regs->erp = infop->entry;
}
#define ELF_EXEC_PAGESIZE 8192
@@ -721,9 +728,10 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
#define ELF_ARCH EM_68K
/* ??? Does this need to do anything?
-#define ELF_PLAT_INIT(_r) */
+ #define ELF_PLAT_INIT(_r) */
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
regs->usp = infop->start_stack;
regs->sr = 0;
@@ -773,7 +781,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_ALPHA
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
regs->pc = infop->entry;
regs->ps = 8;
@@ -803,14 +812,14 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
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 */
+ 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 */
};
@@ -839,7 +848,7 @@ struct exec
static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
{
- memcpy(to, from, n);
+ memcpy(to, from, n);
}
static int load_aout_interp(void * exptr, int interp_fd);
@@ -847,7 +856,7 @@ static int load_aout_interp(void * exptr, int interp_fd);
#ifdef BSWAP_NEEDED
static void bswap_ehdr(struct elfhdr *ehdr)
{
- bswap16s(&ehdr->e_type); /* Object file type */
+ 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 */
@@ -855,16 +864,16 @@ static void bswap_ehdr(struct elfhdr *ehdr)
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_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_shentsize); /* Section header table entry size */
bswap16s(&ehdr->e_shnum); /* Section header table entry count */
- bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
+ bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
}
static void bswap_phdr(struct elf_phdr *phdr)
{
- bswap32s(&phdr->p_type); /* Segment type */
+ 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 */
@@ -936,7 +945,7 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
while (*tmp++);
len = tmp - tmp1;
if (p < len) { /* this shouldn't happen - 128kB */
- return 0;
+ return 0;
}
while (len) {
--p; --tmp; --len;
@@ -955,12 +964,12 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
*(pag + offset) = *tmp;
}
else {
- int bytes_to_copy = (len > offset) ? offset : len;
- tmp -= bytes_to_copy;
- p -= bytes_to_copy;
- offset -= bytes_to_copy;
- len -= bytes_to_copy;
- memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
+ int bytes_to_copy = (len > offset) ? offset : len;
+ tmp -= bytes_to_copy;
+ p -= bytes_to_copy;
+ offset -= bytes_to_copy;
+ len -= bytes_to_copy;
+ memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
}
}
}
@@ -1055,77 +1064,77 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
abi_ulong interp_load_addr, int ibcs,
struct image_info *info)
{
- abi_ulong sp;
- int size;
- abi_ulong u_platform;
- const char *k_platform;
- const int n = sizeof(elf_addr_t);
-
- sp = p;
- u_platform = 0;
- k_platform = ELF_PLATFORM;
- if (k_platform) {
- size_t len = strlen(k_platform) + 1;
- sp -= (len + n - 1) & ~(n - 1);
- u_platform = sp;
- /* FIXME - check return value of memcpy_to_target() for failure */
- memcpy_to_target(sp, k_platform, len);
- }
- /*
- * Force 16 byte _final_ alignment here for generality.
- */
- sp = sp &~ (abi_ulong)15;
- size = (DLINFO_ITEMS + 1) * 2;
- if (k_platform)
- size += 2;
+ abi_ulong sp;
+ int size;
+ abi_ulong u_platform;
+ const char *k_platform;
+ const int n = sizeof(elf_addr_t);
+
+ sp = p;
+ u_platform = 0;
+ k_platform = ELF_PLATFORM;
+ if (k_platform) {
+ size_t len = strlen(k_platform) + 1;
+ sp -= (len + n - 1) & ~(n - 1);
+ u_platform = sp;
+ /* FIXME - check return value of memcpy_to_target() for failure */
+ memcpy_to_target(sp, k_platform, len);
+ }
+ /*
+ * Force 16 byte _final_ alignment here for generality.
+ */
+ sp = sp &~ (abi_ulong)15;
+ size = (DLINFO_ITEMS + 1) * 2;
+ if (k_platform)
+ size += 2;
#ifdef DLINFO_ARCH_ITEMS
- size += DLINFO_ARCH_ITEMS * 2;
+ size += DLINFO_ARCH_ITEMS * 2;
#endif
- size += envc + argc + 2;
- size += (!ibcs ? 3 : 1); /* argc itself */
- size *= n;
- if (size & 15)
- sp -= 16 - (size & 15);
-
- /* This is correct because Linux defines
- * elf_addr_t as Elf32_Off / Elf64_Off
- */
+ size += envc + argc + 2;
+ size += (!ibcs ? 3 : 1); /* argc itself */
+ size *= n;
+ if (size & 15)
+ sp -= 16 - (size & 15);
+
+ /* This is correct because Linux defines
+ * elf_addr_t as Elf32_Off / Elf64_Off
+ */
#define NEW_AUX_ENT(id, val) do { \
- sp -= n; put_user_ual(val, sp); \
- sp -= n; put_user_ual(id, sp); \
- } while(0)
-
- NEW_AUX_ENT (AT_NULL, 0);
-
- /* There must be exactly DLINFO_ITEMS entries here. */
- NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
- NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
- NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
- NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
- NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
- NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
- NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
- NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
- NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
- NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
- NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
- NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
- NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
- if (k_platform)
- NEW_AUX_ENT(AT_PLATFORM, u_platform);
+ sp -= n; put_user_ual(val, sp); \
+ sp -= n; put_user_ual(id, sp); \
+ } while(0)
+
+ NEW_AUX_ENT (AT_NULL, 0);
+
+ /* There must be exactly DLINFO_ITEMS entries here. */
+ NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
+ NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
+ NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
+ NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
+ NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
+ NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
+ NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
+ NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
+ NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
+ NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
+ NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
+ NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
+ NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
+ if (k_platform)
+ NEW_AUX_ENT(AT_PLATFORM, u_platform);
#ifdef ARCH_DLINFO
- /*
- * ARCH_DLINFO must come last so platform specific code can enforce
- * special alignment requirements on the AUXV if necessary (eg. PPC).
- */
- ARCH_DLINFO;
+ /*
+ * ARCH_DLINFO must come last so platform specific code can enforce
+ * special alignment requirements on the AUXV if necessary (eg. PPC).
+ */
+ ARCH_DLINFO;
#endif
#undef NEW_AUX_ENT
- info->saved_auxv = sp;
+ info->saved_auxv = sp;
- sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
- return sp;
+ sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
+ return sp;
}
@@ -1133,83 +1142,83 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
int interpreter_fd,
abi_ulong *interp_load_addr)
{
- struct elf_phdr *elf_phdata = NULL;
- struct elf_phdr *eppnt;
- abi_ulong load_addr = 0;
- int load_addr_set = 0;
- int retval;
- abi_ulong error;
- int i;
+ struct elf_phdr *elf_phdata = NULL;
+ struct elf_phdr *eppnt;
+ abi_ulong load_addr = 0;
+ int load_addr_set = 0;
+ int retval;
+ abi_ulong error;
+ int i;
- error = 0;
+ error = 0;
#ifdef BSWAP_NEEDED
- bswap_ehdr(interp_elf_ex);
+ bswap_ehdr(interp_elf_ex);
#endif
- /* First of all, some simple consistency checks */
- if ((interp_elf_ex->e_type != ET_EXEC &&
- interp_elf_ex->e_type != ET_DYN) ||
- !elf_check_arch(interp_elf_ex->e_machine)) {
- return ~((abi_ulong)0UL);
- }
+ /* First of all, some simple consistency checks */
+ if ((interp_elf_ex->e_type != ET_EXEC &&
+ interp_elf_ex->e_type != ET_DYN) ||
+ !elf_check_arch(interp_elf_ex->e_machine)) {
+ return ~((abi_ulong)0UL);
+ }
- /* Now read in all of the header information */
+ /* Now read in all of the header information */
- if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
- return ~(abi_ulong)0UL;
+ if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
+ return ~(abi_ulong)0UL;
- elf_phdata = (struct elf_phdr *)
- malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
+ elf_phdata = (struct elf_phdr *)
+ malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
- if (!elf_phdata)
- return ~((abi_ulong)0UL);
+ if (!elf_phdata)
+ return ~((abi_ulong)0UL);
- /*
- * If the size of this structure has changed, then punt, since
- * we will be doing the wrong thing.
- */
- if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
- free(elf_phdata);
- return ~((abi_ulong)0UL);
- }
+ /*
+ * If the size of this structure has changed, then punt, since
+ * we will be doing the wrong thing.
+ */
+ if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
+ free(elf_phdata);
+ return ~((abi_ulong)0UL);
+ }
- retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
- if(retval >= 0) {
- retval = read(interpreter_fd,
- (char *) elf_phdata,
- sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
- }
- if (retval < 0) {
- perror("load_elf_interp");
- exit(-1);
- free (elf_phdata);
- return retval;
- }
+ retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
+ if(retval >= 0) {
+ retval = read(interpreter_fd,
+ (char *) elf_phdata,
+ sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
+ }
+ if (retval < 0) {
+ perror("load_elf_interp");
+ exit(-1);
+ free (elf_phdata);
+ return retval;
+ }
#ifdef BSWAP_NEEDED
- eppnt = elf_phdata;
- for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
- bswap_phdr(eppnt);
- }
+ eppnt = elf_phdata;
+ for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
+ bswap_phdr(eppnt);
+ }
#endif
- if (interp_elf_ex->e_type == ET_DYN) {
- /* in order to avoid hardcoding the interpreter load
- address in qemu, we allocate a big enough memory zone */
- error = target_mmap(0, INTERP_MAP_SIZE,
- PROT_NONE, MAP_PRIVATE | MAP_ANON,
- -1, 0);
- if (error == -1) {
- perror("mmap");
- exit(-1);
- }
- load_addr = error;
- load_addr_set = 1;
+ if (interp_elf_ex->e_type == ET_DYN) {
+ /* in order to avoid hardcoding the interpreter load
+ address in qemu, we allocate a big enough memory zone */
+ error = target_mmap(0, INTERP_MAP_SIZE,
+ PROT_NONE, MAP_PRIVATE | MAP_ANON,
+ -1, 0);
+ if (error == -1) {
+ perror("mmap");
+ exit(-1);
}
+ load_addr = error;
+ load_addr_set = 1;
+ }
- eppnt = elf_phdata;
- for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
- if (eppnt->p_type == PT_LOAD) {
+ eppnt = elf_phdata;
+ for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
+ if (eppnt->p_type == PT_LOAD) {
int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
int elf_prot = 0;
abi_ulong vaddr = 0;
@@ -1222,22 +1231,22 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
vaddr = eppnt->p_vaddr;
}
error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
- eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
- elf_prot,
- elf_type,
- interpreter_fd,
- eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
+ eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
+ elf_prot,
+ elf_type,
+ interpreter_fd,
+ eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
if (error == -1) {
- /* Real error */
- close(interpreter_fd);
- free(elf_phdata);
- return ~((abi_ulong)0UL);
+ /* Real error */
+ close(interpreter_fd);
+ free(elf_phdata);
+ return ~((abi_ulong)0UL);
}
if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
- load_addr = error;
- load_addr_set = 1;
+ load_addr = error;
+ load_addr_set = 1;
}
/* If the load segment requests extra zeros (e.g. bss), map it. */
@@ -1246,15 +1255,15 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
zero_bss(base + eppnt->p_filesz,
base + eppnt->p_memsz, elf_prot);
}
- }
+ }
- /* Now use mmap to map the library into memory. */
+ /* Now use mmap to map the library into memory. */
- close(interpreter_fd);
- free(elf_phdata);
+ close(interpreter_fd);
+ free(elf_phdata);
- *interp_load_addr = load_addr;
- return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
+ *interp_load_addr = load_addr;
+ return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
}
static int symfind(const void *s0, const void *s1)
@@ -1356,8 +1365,8 @@ static void load_symbols(struct elfhdr *hdr, int fd)
#endif
// Throw away entries which we do not need.
if (syms[i].st_shndx == SHN_UNDEF ||
- syms[i].st_shndx >= SHN_LORESERVE ||
- ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
+ syms[i].st_shndx >= SHN_LORESERVE ||
+ ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
nsyms--;
if (i < nsyms) {
syms[i] = syms[nsyms];
@@ -1425,8 +1434,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
/* First of all, some simple consistency checks */
if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
- (! elf_check_arch(elf_ex.e_machine))) {
- return -ENOEXEC;
+ (! elf_check_arch(elf_ex.e_machine))) {
+ return -ENOEXEC;
}
bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
@@ -1445,7 +1454,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
if(retval > 0) {
retval = read(bprm->fd, (char *) elf_phdata,
- elf_ex.e_phentsize * elf_ex.e_phnum);
+ elf_ex.e_phentsize * elf_ex.e_phnum);
}
if (retval < 0) {
@@ -1513,7 +1522,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
- ibcs2_interpreter = 1;
+ ibcs2_interpreter = 1;
}
#if 0
@@ -1559,8 +1568,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
/* Now figure out which format our binary is */
if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
- (N_MAGIC(interp_ex) != QMAGIC)) {
- interpreter_type = INTERPRETER_ELF;
+ (N_MAGIC(interp_ex) != QMAGIC)) {
+ interpreter_type = INTERPRETER_ELF;
}
if (interp_elf_ex.e_ident[0] != 0x7f ||
@@ -1620,7 +1629,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
* in that case set guest_base to corresponding address.
*/
for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum;
- i++, elf_ppnt++) {
+ i++, elf_ppnt++) {
if (elf_ppnt->p_type != PT_LOAD)
continue;
if (HOST_PAGE_ALIGN(elf_ppnt->p_vaddr) < mmap_min_addr) {
@@ -1737,7 +1746,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
}
else if (interpreter_type & 2) {
elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
- &interp_load_addr);
+ &interp_load_addr);
}
reloc_func_desc = interp_load_addr;
@@ -1764,13 +1773,13 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
info->start_stack = bprm->p = elf_stack - 4;
#endif
bprm->p = create_elf_tables(bprm->p,
- bprm->argc,
- bprm->envc,
- &elf_ex,
- load_addr, load_bias,
- interp_load_addr,
- (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
- info);
+ bprm->argc,
+ bprm->envc,
+ &elf_ex,
+ load_addr, load_bias,
+ interp_load_addr,
+ (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
+ info);
info->load_addr = reloc_func_desc;
info->start_brk = info->brk = elf_brk;
info->end_code = end_code;
@@ -1790,12 +1799,12 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
if ( info->personality == PER_SVR4 )
{
- /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
- and some applications "depend" upon this behavior.
- Since we do not have the power to recompile these, we
- emulate the SVr4 behavior. Sigh. */
- mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE, -1, 0);
+ /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
+ and some applications "depend" upon this behavior.
+ Since we do not have the power to recompile these, we
+ emulate the SVr4 behavior. Sigh. */
+ mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE, -1, 0);
}
info->entry = elf_entry;
@@ -1808,7 +1817,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
}
#ifdef USE_ELF_CORE_DUMP
-
/*
* Definitions to generate Intel SVR4-like core files.
* These mostly have the same names as the SVR4 types with "target_elf_"
@@ -1945,17 +1953,17 @@ struct mm_struct {
static struct mm_struct *vma_init(void);
static void vma_delete(struct mm_struct *);
static int vma_add_mapping(struct mm_struct *, abi_ulong,
- abi_ulong, abi_ulong);
+ abi_ulong, abi_ulong);
static int vma_get_mapping_count(const struct mm_struct *);
static struct vm_area_struct *vma_first(const struct mm_struct *);
static struct vm_area_struct *vma_next(struct vm_area_struct *);
static abi_ulong vma_dump_size(const struct vm_area_struct *);
static int vma_walker(void *priv, abi_ulong start, abi_ulong end,
- unsigned long flags);
+ unsigned long flags);
static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t);
static void fill_note(struct memelfnote *, const char *, int,
- unsigned int, void *);
+ unsigned int, void *);
static void fill_prstatus(struct target_elf_prstatus *, const TaskState *, int);
static int fill_psinfo(struct target_elf_prpsinfo *, const TaskState *);
static void fill_auxv_note(struct memelfnote *, const TaskState *);
@@ -2035,7 +2043,7 @@ static void vma_delete(struct mm_struct *mm)
}
static int vma_add_mapping(struct mm_struct *mm, abi_ulong start,
- abi_ulong end, abi_ulong flags)
+ abi_ulong end, abi_ulong flags)
{
struct vm_area_struct *vma;
@@ -2104,7 +2112,7 @@ static abi_ulong vma_dump_size(const struct vm_area_struct *vma)
}
static int vma_walker(void *priv, abi_ulong start, abi_ulong end,
- unsigned long flags)
+ unsigned long flags)
{
struct mm_struct *mm = (struct mm_struct *)priv;
@@ -2119,7 +2127,7 @@ static int vma_walker(void *priv, abi_ulong start, abi_ulong end,
}
static void fill_note(struct memelfnote *note, const char *name, int type,
- unsigned int sz, void *data)
+ unsigned int sz, void *data)
{
unsigned int namesz;
@@ -2140,7 +2148,7 @@ static void fill_note(struct memelfnote *note, const char *name, int type,
}
static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
- uint32_t flags)
+ uint32_t flags)
{
(void) memset(elf, 0, sizeof(*elf));
@@ -2186,7 +2194,7 @@ static size_t note_size(const struct memelfnote *note)
}
static void fill_prstatus(struct target_elf_prstatus *prstatus,
- const TaskState *ts, int signr)
+ const TaskState *ts, int signr)
{
(void) memset(prstatus, 0, sizeof (*prstatus));
prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
@@ -2227,7 +2235,7 @@ static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
filename = strdup(ts->bprm->filename);
base_filename = strdup(basename(filename));
(void) strncpy(psinfo->pr_fname, base_filename,
- sizeof(psinfo->pr_fname));
+ sizeof(psinfo->pr_fname));
free(base_filename);
free(filename);
@@ -2276,7 +2284,7 @@ static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
* Returns 0 in case of success, -1 otherwise (errno is set).
*/
static int core_dump_filename(const TaskState *ts, char *buf,
- size_t bufsize)
+ size_t bufsize)
{
char timestamp[64];
char *filename = NULL;
@@ -2288,16 +2296,16 @@ static int core_dump_filename(const TaskState *ts, char *buf,
if (gettimeofday(&tv, NULL) < 0) {
(void) fprintf(stderr, "unable to get current timestamp: %s",
- strerror(errno));
+ strerror(errno));
return (-1);
}
filename = strdup(ts->bprm->filename);
base_filename = strdup(basename(filename));
(void) strftime(timestamp, sizeof (timestamp), "%Y%m%d-%H%M%S",
- localtime_r(&tv.tv_sec, &tm));
+ localtime_r(&tv.tv_sec, &tm));
(void) snprintf(buf, bufsize, "qemu_%s_%s_%d.core",
- base_filename, timestamp, (int)getpid());
+ base_filename, timestamp, (int)getpid());
free(base_filename);
free(filename);
@@ -2382,7 +2390,7 @@ static void fill_thread_info(struct elf_note_info *info, const CPUState *env)
fill_prstatus(&ets->prstatus, ts, 0);
elf_core_copy_regs(&ets->prstatus.pr_reg, env);
fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus),
- &ets->prstatus);
+ &ets->prstatus);
QTAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link);
@@ -2390,7 +2398,7 @@ static void fill_thread_info(struct elf_note_info *info, const CPUState *env)
}
static int fill_note_info(struct elf_note_info *info,
- long signr, const CPUState *env)
+ long signr, const CPUState *env)
{
#define NUMNOTES 3
CPUState *cpu = NULL;
@@ -2418,10 +2426,10 @@ static int fill_note_info(struct elf_note_info *info,
fill_prstatus(info->prstatus, ts, signr);
elf_core_copy_regs(&info->prstatus->pr_reg, env);
fill_note(&info->notes[0], "CORE", NT_PRSTATUS,
- sizeof (*info->prstatus), info->prstatus);
+ sizeof (*info->prstatus), info->prstatus);
fill_psinfo(info->psinfo, ts);
fill_note(&info->notes[1], "CORE", NT_PRPSINFO,
- sizeof (*info->psinfo), info->psinfo);
+ sizeof (*info->psinfo), info->psinfo);
fill_auxv_note(&info->notes[2], ts);
info->numnote = 3;
@@ -2468,7 +2476,7 @@ static int write_note_info(struct elf_note_info *info, int fd)
/* write prstatus for each thread */
for (ets = info->thread_list.tqh_first; ets != NULL;
- ets = ets->ets_link.tqe_next) {
+ ets = ets->ets_link.tqe_next) {
if ((error = write_note(&ets->notes[0], fd)) != 0)
return (error);
}
@@ -2536,13 +2544,13 @@ static int elf_core_dump(int signr, const CPUState *env)
errno = 0;
getrlimit(RLIMIT_CORE, &dumpsize);
if (dumpsize.rlim_cur == 0)
- return 0;
+ return 0;
if (core_dump_filename(ts, corefile, sizeof (corefile)) < 0)
return (-errno);
if ((fd = open(corefile, O_WRONLY | O_CREAT,
- S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
return (-errno);
/*
@@ -2631,7 +2639,7 @@ static int elf_core_dump(int signr, const CPUState *env)
end = vma->vma_start + vma_dump_size(vma);
for (addr = vma->vma_start; addr < end;
- addr += TARGET_PAGE_SIZE) {
+ addr += TARGET_PAGE_SIZE) {
char page[TARGET_PAGE_SIZE];
int error;
@@ -2642,7 +2650,7 @@ static int elf_core_dump(int signr, const CPUState *env)
error = copy_from_user(page, addr, sizeof (page));
if (error != 0) {
(void) fprintf(stderr, "unable to dump " TARGET_ABI_FMT_lx "\n",
- addr);
+ addr);
errno = -error;
goto out;
}
@@ -2651,7 +2659,7 @@ static int elf_core_dump(int signr, const CPUState *env)
}
}
-out:
+ out:
free_note_info(&info);
if (mm != NULL)
vma_delete(mm);
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 12/14] linux-user: Re-use load_elf_image for the main binary.
2010-04-28 19:36 ` [Qemu-devel] [PATCH 00/14] Implement VDSO for x86-64-linux-user, v2 Richard Henderson
` (12 preceding siblings ...)
2010-04-28 19:39 ` [Qemu-devel] [PATCH 03/14] linux-user: Reindent elfload.c Richard Henderson
@ 2010-04-28 19:39 ` Richard Henderson
13 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-04-28 19:39 UTC (permalink / raw)
To: qemu-devel
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 <rth@twiddle.net>
---
linux-user/elfload.c | 272 ++++++++++---------------------------------------
1 files changed, 56 insertions(+), 216 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index c58387a..5771344 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,33 @@ 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);
+ if (!interp_name) {
+ goto exit_perror;
+ }
+
+ 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,
+ 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 +1373,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 +1517,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;
- /* 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;
- }
+ load_elf_image(bprm->filename, bprm->fd, info,
+ &elf_interpreter, bprm->buf);
+
+ /* ??? 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 +1573,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
--
1.6.6.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 00/12] Cleanup linux-user/elfload.c, v2
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (14 preceding siblings ...)
2010-04-28 19:36 ` [Qemu-devel] [PATCH 00/14] Implement VDSO for x86-64-linux-user, v2 Richard Henderson
@ 2010-05-05 18:07 ` Richard Henderson
2010-05-05 18:07 ` [Qemu-devel] [PATCH 01/12] linux-user: Handle filesz < memsz for any PT_LOAD segment Richard Henderson
` (11 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-05-05 18:07 UTC (permalink / raw)
To: qemu-devel; +Cc: paul
Changes v1->v2:
* Drop VDSO loading for the moment; let's concentrate on getting the
basic elf loading in shape first.
* Fix SH4-EB ELF_DATA definition
* Re-base after pbrook's guest_base changes for the main executable.
r~
Richard Henderson (12):
linux-user: Handle filesz < memsz for any PT_LOAD segment.
Add more DT_* and AT_* constants to qemu's copy of elf.h.
linux-user: Reindent elfload.c.
linux-user: Reduce lseek+reads while loading elf files.
linux-user: Define ELF_DATA generically.
linux-user: Clean up byte-swapping in elfload.c.
linux-user: Load symbols from the interpreter.
linux-user: Improve consistency checking in elf headers.
linux-user: Put the stack guard page at the top.
linux-user: Remove partial support for a.out interpreters.
linux-user: Extract load_elf_image from load_elf_interp.
linux-user: Re-use load_elf_image for the main binary.
elf.h | 44 ++
linux-user/elfload.c | 1789 ++++++++++++++++++++----------------------------
linux-user/linuxload.c | 17 +-
linux-user/qemu.h | 7 +-
4 files changed, 793 insertions(+), 1064 deletions(-)
^ permalink raw reply [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 01/12] linux-user: Handle filesz < memsz for any PT_LOAD segment.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (15 preceding siblings ...)
2010-05-05 18:07 ` [Qemu-devel] [PATCH 00/12] Cleanup linux-user/elfload.c, v2 Richard Henderson
@ 2010-05-05 18:07 ` Richard Henderson
2010-05-05 18:07 ` [Qemu-devel] [PATCH 02/12] Add more DT_* and AT_* constants to qemu's copy of elf.h Richard Henderson
` (10 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-05-05 18:07 UTC (permalink / raw)
To: qemu-devel; +Cc: paul
I caught padzero not properly initializing the .bss segment
on a statically linked Alpha program. Rather than a minimal
patch, replace the gross code with a single mmap+memset.
Share more code between load_elf_interp and load_elf_binary.
Legally, an ELF program need not have just a single .bss;
and PT_LOAD segment can have memsz > filesz.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 150 ++++++++++++++++++--------------------------------
1 files changed, 54 insertions(+), 96 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 4ef77bc..58728ff 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1015,60 +1015,47 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
return p;
}
-static void set_brk(abi_ulong start, abi_ulong end)
-{
- /* page-align the start and end addresses... */
- start = HOST_PAGE_ALIGN(start);
- end = HOST_PAGE_ALIGN(end);
- if (end <= start)
- return;
- if(target_mmap(start, end - start,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
- perror("cannot mmap brk");
- exit(-1);
- }
-}
-
-
-/* We need to explicitly zero any fractional pages after the data
- section (i.e. bss). This would contain the junk from the file that
- should not be in memory. */
-static void padzero(abi_ulong elf_bss, abi_ulong last_bss)
-{
- abi_ulong nbyte;
-
- if (elf_bss >= last_bss)
- return;
-
- /* XXX: this is really a hack : if the real host page size is
- smaller than the target page size, some pages after the end
- of the file may not be mapped. A better fix would be to
- patch target_mmap(), but it is more complicated as the file
- size must be known */
- if (qemu_real_host_page_size < qemu_host_page_size) {
- abi_ulong end_addr, end_addr1;
- end_addr1 = (elf_bss + qemu_real_host_page_size - 1) &
- ~(qemu_real_host_page_size - 1);
- end_addr = HOST_PAGE_ALIGN(elf_bss);
- if (end_addr1 < end_addr) {
- mmap((void *)g2h(end_addr1), end_addr - end_addr1,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
- }
+/* Map and zero the bss. We need to explicitly zero any fractional pages
+ after the data section (i.e. bss). */
+static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
+{
+ uintptr_t host_start, host_map_start, host_end;
+
+ last_bss = TARGET_PAGE_ALIGN(last_bss);
+
+ /* ??? There is confusion between qemu_real_host_page_size and
+ qemu_host_page_size here and elsewhere in target_mmap, which
+ may lead to the end of the data section mapping from the file
+ not being mapped. At least there was an explicit test and
+ comment for that here, suggesting that "the file size must
+ be known". The comment probably pre-dates the introduction
+ of the fstat system call in target_mmap which does in fact
+ find out the size. What isn't clear is if the workaround
+ here is still actually needed. For now, continue with it,
+ but merge it with the "normal" mmap that would allocate the bss. */
+
+ host_start = (uintptr_t) g2h(elf_bss);
+ host_end = (uintptr_t) g2h(last_bss);
+ host_map_start = (host_start + qemu_real_host_page_size - 1);
+ host_map_start &= -qemu_real_host_page_size;
+
+ if (host_map_start < host_end) {
+ void *p = mmap((void *)host_map_start, host_end - host_map_start,
+ prot, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (p == MAP_FAILED) {
+ perror("cannot mmap brk");
+ exit(-1);
}
- nbyte = elf_bss & (qemu_host_page_size-1);
- if (nbyte) {
- nbyte = qemu_host_page_size - nbyte;
- do {
- /* FIXME - what to do if put_user() fails? */
- put_user_u8(0, elf_bss);
- elf_bss++;
- } while (--nbyte);
- }
-}
+ /* Since we didn't use target_mmap, make sure to record
+ the validity of the pages with qemu. */
+ page_set_flags(elf_bss & TARGET_PAGE_MASK, last_bss, prot|PAGE_VALID);
+ }
+ if (host_start < host_map_start) {
+ memset((void *)host_start, 0, host_map_start - host_start);
+ }
+}
static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
struct elfhdr * exec,
@@ -1160,12 +1147,9 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
abi_ulong load_addr = 0;
int load_addr_set = 0;
int retval;
- abi_ulong last_bss, elf_bss;
abi_ulong error;
int i;
- elf_bss = 0;
- last_bss = 0;
error = 0;
#ifdef BSWAP_NEEDED
@@ -1238,7 +1222,6 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
int elf_prot = 0;
abi_ulong vaddr = 0;
- abi_ulong k;
if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
@@ -1266,40 +1249,17 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
load_addr_set = 1;
}
- /*
- * Find the end of the file mapping for this phdr, and keep
- * track of the largest address we see for this.
- */
- k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
- if (k > elf_bss) elf_bss = k;
-
- /*
- * Do the same thing for the memory mapping - between
- * elf_bss and last_bss is the bss section.
- */
- k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
- if (k > last_bss) last_bss = k;
+ /* If the load segment requests extra zeros (e.g. bss), map it. */
+ if (eppnt->p_filesz < eppnt->p_memsz) {
+ abi_ulong base = load_addr + eppnt->p_vaddr;
+ zero_bss(base + eppnt->p_filesz,
+ base + eppnt->p_memsz, elf_prot);
+ }
}
/* Now use mmap to map the library into memory. */
close(interpreter_fd);
-
- /*
- * Now fill out the bss section. First pad the last page up
- * to the page boundary, and then perform a mmap to make sure
- * that there are zeromapped pages up to and including the last
- * bss page.
- */
- padzero(elf_bss, last_bss);
- elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */
-
- /* Map the last of the bss segment */
- if (last_bss > elf_bss) {
- target_mmap(elf_bss, last_bss-elf_bss,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
- }
free(elf_phdata);
*interp_load_addr = load_addr;
@@ -1453,7 +1413,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
abi_ulong mapped_addr;
struct elf_phdr * elf_ppnt;
struct elf_phdr *elf_phdata;
- abi_ulong elf_bss, k, elf_brk;
+ abi_ulong k, elf_brk;
int retval;
char * elf_interpreter;
abi_ulong elf_entry, interp_load_addr = 0;
@@ -1512,10 +1472,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
#endif
elf_ppnt = elf_phdata;
- elf_bss = 0;
elf_brk = 0;
-
elf_stack = ~((abi_ulong)0UL);
elf_interpreter = NULL;
start_code = ~((abi_ulong)0UL);
@@ -1819,18 +1777,24 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
if (start_data < k)
start_data = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
- if (k > elf_bss)
- elf_bss = k;
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 = k;
+ 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_bss += load_bias;
elf_brk += load_bias;
start_code += load_bias;
end_code += load_bias;
@@ -1885,12 +1849,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
info->end_data = end_data;
info->start_stack = bprm->p;
- /* Calling set_brk effectively mmaps the pages that we need for the bss and break
- sections */
- set_brk(elf_bss, elf_brk);
-
- padzero(elf_bss, elf_brk);
-
#if 0
printf("(start_brk) %x\n" , info->start_brk);
printf("(end_code) %x\n" , info->end_code);
--
1.7.0.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 02/12] Add more DT_* and AT_* constants to qemu's copy of elf.h.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (16 preceding siblings ...)
2010-05-05 18:07 ` [Qemu-devel] [PATCH 01/12] linux-user: Handle filesz < memsz for any PT_LOAD segment Richard Henderson
@ 2010-05-05 18:07 ` Richard Henderson
2010-05-05 18:07 ` [Qemu-devel] [PATCH 03/12] linux-user: Reindent elfload.c Richard Henderson
` (9 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-05-05 18:07 UTC (permalink / raw)
To: qemu-devel; +Cc: paul
Moving some PPC AT_* constants from elfload.c at the same time.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
elf.h | 44 ++++++++++++++++++++++++++++++++++++++++++++
linux-user/elfload.c | 9 ---------
2 files changed, 44 insertions(+), 9 deletions(-)
diff --git a/elf.h b/elf.h
index c84c8ab..012532c 100644
--- a/elf.h
+++ b/elf.h
@@ -146,8 +146,37 @@ typedef int64_t Elf64_Sxword;
#define DT_DEBUG 21
#define DT_TEXTREL 22
#define DT_JMPREL 23
+#define DT_BINDNOW 24
+#define DT_INIT_ARRAY 25
+#define DT_FINI_ARRAY 26
+#define DT_INIT_ARRAYSZ 27
+#define DT_FINI_ARRAYSZ 28
+#define DT_RUNPATH 29
+#define DT_FLAGS 30
+#define DT_LOOS 0x6000000d
+#define DT_HIOS 0x6ffff000
#define DT_LOPROC 0x70000000
#define DT_HIPROC 0x7fffffff
+
+/* DT_ entries which fall between DT_VALRNGLO and DT_VALRNDHI use
+ the d_val field of the Elf*_Dyn structure. I.e. they contain scalars. */
+#define DT_VALRNGLO 0x6ffffd00
+#define DT_VALRNGHI 0x6ffffdff
+
+/* DT_ entries which fall between DT_ADDRRNGLO and DT_ADDRRNGHI use
+ the d_ptr field of the Elf*_Dyn structure. I.e. they contain pointers. */
+#define DT_ADDRRNGLO 0x6ffffe00
+#define DT_ADDRRNGHI 0x6ffffeff
+
+#define DT_VERSYM 0x6ffffff0
+#define DT_RELACOUNT 0x6ffffff9
+#define DT_RELCOUNT 0x6ffffffa
+#define DT_FLAGS_1 0x6ffffffb
+#define DT_VERDEF 0x6ffffffc
+#define DT_VERDEFNUM 0x6ffffffd
+#define DT_VERNEED 0x6ffffffe
+#define DT_VERNEEDNUM 0x6fffffff
+
#define DT_MIPS_RLD_VERSION 0x70000001
#define DT_MIPS_TIME_STAMP 0x70000002
#define DT_MIPS_ICHECKSUM 0x70000003
@@ -206,6 +235,21 @@ typedef int64_t Elf64_Sxword;
#define AT_PLATFORM 15 /* string identifying CPU for optimizations */
#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */
#define AT_CLKTCK 17 /* frequency at which times() increments */
+#define AT_FPUCW 18 /* info about fpu initialization by kernel */
+#define AT_DCACHEBSIZE 19 /* data cache block size */
+#define AT_ICACHEBSIZE 20 /* instruction cache block size */
+#define AT_UCACHEBSIZE 21 /* unified cache block size */
+#define AT_IGNOREPPC 22 /* ppc only; entry should be ignored */
+#define AT_SECURE 23 /* boolean, was exec suid-like? */
+#define AT_BASE_PLATFORM 24 /* string identifying real platforms */
+#define AT_RANDOM 25 /* address of 16 random bytes */
+#define AT_EXECFN 31 /* filename of the executable */
+#define AT_SYSINFO 32 /* address of kernel entry point */
+#define AT_SYSINFO_EHDR 33 /* address of kernel vdso */
+#define AT_L1I_CACHESHAPE 34 /* shapes of the caches: */
+#define AT_L1D_CACHESHAPE 35 /* bits 0-3: cache associativity. */
+#define AT_L2_CACHESHAPE 36 /* bits 4-7: log2 of line size. */
+#define AT_L3_CACHESHAPE 37 /* val&~255: cache size. */
typedef struct dynamic{
Elf32_Sword d_tag;
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 58728ff..edd852f 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -480,15 +480,6 @@ static uint32_t get_elf_hwcap(void)
}
/*
- * 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
--
1.7.0.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 03/12] linux-user: Reindent elfload.c.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (17 preceding siblings ...)
2010-05-05 18:07 ` [Qemu-devel] [PATCH 02/12] Add more DT_* and AT_* constants to qemu's copy of elf.h Richard Henderson
@ 2010-05-05 18:07 ` Richard Henderson
2010-05-05 18:07 ` [Qemu-devel] [PATCH 04/12] linux-user: Reduce lseek+reads while loading elf files Richard Henderson
` (8 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-05-05 18:07 UTC (permalink / raw)
To: qemu-devel; +Cc: paul
Nothing excepting whitespace changes here. This reduces the number
of changes elsewhere in the patch series.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 1028 +++++++++++++++++++++++++-------------------------
1 files changed, 518 insertions(+), 510 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index edd852f..ac118f2 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -35,18 +35,17 @@
* 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,
+ 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,
};
/*
@@ -56,36 +55,35 @@ enum {
* 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,
+ 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)
+#define personality(pers) (pers & PER_MASK)
/* this flag is uneffective under linux too, should be deleted */
#ifndef MAP_DENYWRITE
@@ -97,15 +95,15 @@ enum {
#define ELIBBAD 80
#endif
-typedef target_ulong target_elf_greg_t;
+typedef target_ulong target_elf_greg_t;
#ifdef USE_UID16
-typedef uint16_t target_uid_t;
-typedef uint16_t target_gid_t;
+typedef uint16_t target_uid_t;
+typedef uint16_t target_gid_t;
#else
-typedef uint32_t target_uid_t;
-typedef uint32_t target_gid_t;
+typedef uint32_t target_uid_t;
+typedef uint32_t target_gid_t;
#endif
-typedef int32_t target_pid_t;
+typedef int32_t target_pid_t;
#ifdef TARGET_I386
@@ -126,7 +124,7 @@ static const char *get_elf_platform(void)
static uint32_t get_elf_hwcap(void)
{
- return thread_env->cpuid_features;
+ return thread_env->cpuid_features;
}
#ifdef TARGET_X86_64
@@ -197,11 +195,12 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
/*
* These are used to set parameters in the core dumps.
*/
-#define ELF_CLASS ELFCLASS32
-#define ELF_DATA ELFDATA2LSB
-#define ELF_ARCH EM_386
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_386
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
regs->esp = infop->start_stack;
regs->eip = infop->entry;
@@ -249,7 +248,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#endif
#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 4096
+#define ELF_EXEC_PAGESIZE 4096
#endif
@@ -259,21 +258,22 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#define elf_check_arch(x) ( (x) == EM_ARM )
-#define ELF_CLASS ELFCLASS32
+#define ELF_CLASS ELFCLASS32
#ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA ELFDATA2MSB
+#define ELF_DATA ELFDATA2MSB
#else
-#define ELF_DATA ELFDATA2LSB
+#define ELF_DATA ELFDATA2LSB
#endif
-#define ELF_ARCH EM_ARM
+#define ELF_ARCH EM_ARM
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static 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_cpsr |= CPSR_T;
regs->ARM_pc = infop->entry & 0xfffffffe;
regs->ARM_sp = infop->start_stack;
/* FIXME - what to for failure of get_user()? */
@@ -313,30 +313,30 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
}
#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 4096
+#define ELF_EXEC_PAGESIZE 4096
enum
{
- 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,
- ARM_HWCAP_ARM_JAVA = 1 << 8,
- ARM_HWCAP_ARM_IWMMXT = 1 << 9,
- ARM_HWCAP_ARM_THUMBEE = 1 << 10,
- ARM_HWCAP_ARM_NEON = 1 << 11,
- ARM_HWCAP_ARM_VFPv3 = 1 << 12,
- ARM_HWCAP_ARM_VFPv3D16 = 1 << 13,
+ 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,
+ ARM_HWCAP_ARM_JAVA = 1 << 8,
+ ARM_HWCAP_ARM_IWMMXT = 1 << 9,
+ ARM_HWCAP_ARM_THUMBEE = 1 << 10,
+ ARM_HWCAP_ARM_NEON = 1 << 11,
+ ARM_HWCAP_ARM_VFPv3 = 1 << 12,
+ ARM_HWCAP_ARM_VFPv3D16 = 1 << 13,
};
-#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 \
- | ARM_HWCAP_ARM_NEON | ARM_HWCAP_ARM_VFPv3 )
+#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 \
+ | ARM_HWCAP_ARM_NEON | ARM_HWCAP_ARM_VFPv3 )
#endif
@@ -355,9 +355,10 @@ enum
#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_SPARCV9
-#define STACK_BIAS 2047
+#define STACK_BIAS 2047
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
#ifndef TARGET_ABI32
regs->tstate = 0;
@@ -384,7 +385,8 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_SPARC
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
regs->psr = 0;
regs->pc = infop->entry;
@@ -404,22 +406,22 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
#define elf_check_arch(x) ( (x) == EM_PPC64 )
-#define ELF_CLASS ELFCLASS64
+#define ELF_CLASS ELFCLASS64
#else
#define elf_check_arch(x) ( (x) == EM_PPC )
-#define ELF_CLASS ELFCLASS32
+#define ELF_CLASS ELFCLASS32
#endif
#ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA ELFDATA2MSB
+#define ELF_DATA ELFDATA2MSB
#else
-#define ELF_DATA ELFDATA2LSB
+#define ELF_DATA ELFDATA2LSB
#endif
-#define ELF_ARCH EM_PPC
+#define ELF_ARCH EM_PPC
/* Feature masks for the Aux Vector Hardware Capabilities (AT_HWCAP).
See arch/powerpc/include/asm/cputable.h. */
@@ -464,7 +466,7 @@ static uint32_t get_elf_hwcap(void)
/* We don't have to be terribly complete here; the high points are
Altivec/FP/SPE support. Anything else is just a bonus. */
-#define GET_FEATURE(flag, feature) \
+#define GET_FEATURE(flag, feature) \
do {if (e->insns_flags & flag) features |= feature; } while(0)
GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64);
GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU);
@@ -489,17 +491,17 @@ static uint32_t get_elf_hwcap(void)
* 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)
+#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)
{
@@ -537,7 +539,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
}
#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 4096
+#define ELF_EXEC_PAGESIZE 4096
#endif
@@ -553,13 +555,14 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#define ELF_CLASS ELFCLASS32
#endif
#ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA ELFDATA2MSB
+#define ELF_DATA ELFDATA2MSB
#else
-#define ELF_DATA ELFDATA2LSB
+#define ELF_DATA ELFDATA2LSB
#endif
#define ELF_ARCH EM_MIPS
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
regs->cp0_status = 2 << CP0St_KSU;
regs->cp0_epc = infop->entry;
@@ -623,10 +626,11 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#define elf_check_arch(x) ( (x) == EM_XILINX_MICROBLAZE )
#define ELF_CLASS ELFCLASS32
-#define ELF_DATA ELFDATA2MSB
+#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_XILINX_MICROBLAZE
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
regs->pc = infop->entry;
regs->r1 = infop->start_stack;
@@ -647,11 +651,12 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_SH
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+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;
+ /* Check other registers XXXXX */
+ regs->pc = infop->entry;
+ regs->regs[15] = infop->start_stack;
}
/* See linux kernel: arch/sh/include/asm/elf.h. */
@@ -669,7 +674,8 @@ enum {
TARGET_REG_SYSCALL = 22
};
-static inline void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
+static inline void elf_core_copy_regs(target_elf_gregset_t *regs,
+ const CPUState *env)
{
int i;
@@ -701,9 +707,10 @@ static inline void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState
#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_CRIS
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
- regs->erp = infop->entry;
+ regs->erp = infop->entry;
}
#define ELF_EXEC_PAGESIZE 8192
@@ -716,14 +723,15 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
#define elf_check_arch(x) ( (x) == EM_68K )
-#define ELF_CLASS ELFCLASS32
-#define ELF_DATA ELFDATA2MSB
-#define ELF_ARCH 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) */
+ #define ELF_PLAT_INIT(_r) */
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
regs->usp = infop->start_stack;
regs->sr = 0;
@@ -759,7 +767,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
}
#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 8192
+#define ELF_EXEC_PAGESIZE 8192
#endif
@@ -773,7 +781,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_ALPHA
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
{
regs->pc = infop->entry;
regs->ps = 8;
@@ -803,14 +812,14 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
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 */
+ 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 */
};
@@ -839,7 +848,7 @@ struct exec
static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
{
- memcpy(to, from, n);
+ memcpy(to, from, n);
}
static int load_aout_interp(void * exptr, int interp_fd);
@@ -847,31 +856,31 @@ static int load_aout_interp(void * exptr, int interp_fd);
#ifdef BSWAP_NEEDED
static 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 */
+ 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 */
+ 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)
@@ -924,24 +933,24 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
int len, offset = 0;
if (!p) {
- return 0; /* bullet-proofing */
+ return 0; /* bullet-proofing */
}
while (argc-- > 0) {
tmp = argv[argc];
if (!tmp) {
- fprintf(stderr, "VFS: argc is wrong");
- exit(-1);
- }
+ 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;
+ 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);
@@ -949,20 +958,20 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
page[p/TARGET_PAGE_SIZE] = pag;
if (!pag)
return 0;
- }
- }
- if (len == 0 || offset == 0) {
- *(pag + offset) = *tmp;
- }
- else {
- int bytes_to_copy = (len > offset) ? offset : len;
- tmp -= bytes_to_copy;
- p -= bytes_to_copy;
- offset -= bytes_to_copy;
- len -= bytes_to_copy;
- memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
- }
- }
+ }
+ }
+ if (len == 0 || offset == 0) {
+ *(pag + offset) = *tmp;
+ }
+ else {
+ int bytes_to_copy = (len > offset) ? offset : len;
+ tmp -= bytes_to_copy;
+ p -= bytes_to_copy;
+ offset -= bytes_to_copy;
+ len -= bytes_to_copy;
+ memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
+ }
+ }
}
return p;
}
@@ -995,12 +1004,12 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
p += stack_base;
for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
- if (bprm->page[i]) {
- info->rss++;
+ if (bprm->page[i]) {
+ info->rss++;
/* FIXME - check return value of memcpy_to_target() for failure */
- memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
- free(bprm->page[i]);
- }
+ memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
+ free(bprm->page[i]);
+ }
stack_base += TARGET_PAGE_SIZE;
}
return p;
@@ -1055,77 +1064,77 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
abi_ulong interp_load_addr, int ibcs,
struct image_info *info)
{
- abi_ulong sp;
- int size;
- abi_ulong u_platform;
- const char *k_platform;
- const int n = sizeof(elf_addr_t);
-
- sp = p;
- u_platform = 0;
- k_platform = ELF_PLATFORM;
- if (k_platform) {
- size_t len = strlen(k_platform) + 1;
- sp -= (len + n - 1) & ~(n - 1);
- u_platform = sp;
- /* FIXME - check return value of memcpy_to_target() for failure */
- memcpy_to_target(sp, k_platform, len);
- }
- /*
- * Force 16 byte _final_ alignment here for generality.
- */
- sp = sp &~ (abi_ulong)15;
- size = (DLINFO_ITEMS + 1) * 2;
- if (k_platform)
- size += 2;
+ abi_ulong sp;
+ int size;
+ abi_ulong u_platform;
+ const char *k_platform;
+ const int n = sizeof(elf_addr_t);
+
+ sp = p;
+ u_platform = 0;
+ k_platform = ELF_PLATFORM;
+ if (k_platform) {
+ size_t len = strlen(k_platform) + 1;
+ sp -= (len + n - 1) & ~(n - 1);
+ u_platform = sp;
+ /* FIXME - check return value of memcpy_to_target() for failure */
+ memcpy_to_target(sp, k_platform, len);
+ }
+ /*
+ * Force 16 byte _final_ alignment here for generality.
+ */
+ sp = sp &~ (abi_ulong)15;
+ size = (DLINFO_ITEMS + 1) * 2;
+ if (k_platform)
+ size += 2;
#ifdef DLINFO_ARCH_ITEMS
- size += DLINFO_ARCH_ITEMS * 2;
+ size += DLINFO_ARCH_ITEMS * 2;
#endif
- size += envc + argc + 2;
- size += (!ibcs ? 3 : 1); /* argc itself */
- size *= n;
- if (size & 15)
- sp -= 16 - (size & 15);
-
- /* This is correct because Linux defines
- * elf_addr_t as Elf32_Off / Elf64_Off
- */
-#define NEW_AUX_ENT(id, val) do { \
- sp -= n; put_user_ual(val, sp); \
- sp -= n; put_user_ual(id, sp); \
- } while(0)
-
- NEW_AUX_ENT (AT_NULL, 0);
-
- /* There must be exactly DLINFO_ITEMS entries here. */
- NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
- NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
- NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
- NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
- NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
- NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
- NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
- NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
- NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
- NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
- NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
- NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
- NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
- if (k_platform)
- NEW_AUX_ENT(AT_PLATFORM, u_platform);
+ size += envc + argc + 2;
+ size += (!ibcs ? 3 : 1); /* argc itself */
+ size *= n;
+ if (size & 15)
+ sp -= 16 - (size & 15);
+
+ /* This is correct because Linux defines
+ * elf_addr_t as Elf32_Off / Elf64_Off
+ */
+#define NEW_AUX_ENT(id, val) do { \
+ sp -= n; put_user_ual(val, sp); \
+ sp -= n; put_user_ual(id, sp); \
+ } while(0)
+
+ NEW_AUX_ENT (AT_NULL, 0);
+
+ /* There must be exactly DLINFO_ITEMS entries here. */
+ NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
+ NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
+ NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
+ NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
+ NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
+ NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
+ NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
+ NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
+ NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
+ NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
+ NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
+ NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
+ NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
+ if (k_platform)
+ NEW_AUX_ENT(AT_PLATFORM, u_platform);
#ifdef ARCH_DLINFO
- /*
- * ARCH_DLINFO must come last so platform specific code can enforce
- * special alignment requirements on the AUXV if necessary (eg. PPC).
- */
- ARCH_DLINFO;
+ /*
+ * ARCH_DLINFO must come last so platform specific code can enforce
+ * special alignment requirements on the AUXV if necessary (eg. PPC).
+ */
+ ARCH_DLINFO;
#endif
#undef NEW_AUX_ENT
- info->saved_auxv = sp;
+ info->saved_auxv = sp;
- sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
- return sp;
+ sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
+ return sp;
}
@@ -1133,112 +1142,112 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
int interpreter_fd,
abi_ulong *interp_load_addr)
{
- struct elf_phdr *elf_phdata = NULL;
- struct elf_phdr *eppnt;
- abi_ulong load_addr = 0;
- int load_addr_set = 0;
- int retval;
- abi_ulong error;
- int i;
+ struct elf_phdr *elf_phdata = NULL;
+ struct elf_phdr *eppnt;
+ abi_ulong load_addr = 0;
+ int load_addr_set = 0;
+ int retval;
+ abi_ulong error;
+ int i;
- error = 0;
+ error = 0;
#ifdef BSWAP_NEEDED
- bswap_ehdr(interp_elf_ex);
+ bswap_ehdr(interp_elf_ex);
#endif
- /* First of all, some simple consistency checks */
- if ((interp_elf_ex->e_type != ET_EXEC &&
- interp_elf_ex->e_type != ET_DYN) ||
- !elf_check_arch(interp_elf_ex->e_machine)) {
- return ~((abi_ulong)0UL);
- }
+ /* First of all, some simple consistency checks */
+ if ((interp_elf_ex->e_type != ET_EXEC &&
+ interp_elf_ex->e_type != ET_DYN) ||
+ !elf_check_arch(interp_elf_ex->e_machine)) {
+ return ~((abi_ulong)0UL);
+ }
- /* Now read in all of the header information */
+ /* Now read in all of the header information */
- if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
- return ~(abi_ulong)0UL;
+ if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
+ return ~(abi_ulong)0UL;
- elf_phdata = (struct elf_phdr *)
- malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
+ elf_phdata = (struct elf_phdr *)
+ malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
- if (!elf_phdata)
- return ~((abi_ulong)0UL);
+ if (!elf_phdata)
+ return ~((abi_ulong)0UL);
- /*
- * If the size of this structure has changed, then punt, since
- * we will be doing the wrong thing.
- */
- if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
- free(elf_phdata);
- return ~((abi_ulong)0UL);
- }
+ /*
+ * If the size of this structure has changed, then punt, since
+ * we will be doing the wrong thing.
+ */
+ if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
+ free(elf_phdata);
+ return ~((abi_ulong)0UL);
+ }
- retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
- if(retval >= 0) {
- retval = read(interpreter_fd,
- (char *) elf_phdata,
- sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
- }
- if (retval < 0) {
- perror("load_elf_interp");
- exit(-1);
- free (elf_phdata);
- return retval;
- }
+ retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
+ if(retval >= 0) {
+ retval = read(interpreter_fd,
+ (char *) elf_phdata,
+ sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
+ }
+ if (retval < 0) {
+ perror("load_elf_interp");
+ exit(-1);
+ free (elf_phdata);
+ return retval;
+ }
#ifdef BSWAP_NEEDED
- eppnt = elf_phdata;
- for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
- bswap_phdr(eppnt);
- }
+ eppnt = elf_phdata;
+ for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
+ bswap_phdr(eppnt);
+ }
#endif
- if (interp_elf_ex->e_type == ET_DYN) {
- /* in order to avoid hardcoding the interpreter load
- address in qemu, we allocate a big enough memory zone */
- error = target_mmap(0, INTERP_MAP_SIZE,
- PROT_NONE, MAP_PRIVATE | MAP_ANON,
- -1, 0);
+ if (interp_elf_ex->e_type == ET_DYN) {
+ /* in order to avoid hardcoding the interpreter load
+ address in qemu, we allocate a big enough memory zone */
+ error = target_mmap(0, INTERP_MAP_SIZE,
+ PROT_NONE, MAP_PRIVATE | MAP_ANON,
+ -1, 0);
+ if (error == -1) {
+ perror("mmap");
+ exit(-1);
+ }
+ load_addr = error;
+ load_addr_set = 1;
+ }
+
+ eppnt = elf_phdata;
+ for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
+ if (eppnt->p_type == PT_LOAD) {
+ int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+ int elf_prot = 0;
+ abi_ulong vaddr = 0;
+
+ if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
+ if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
+ if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
+ if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
+ elf_type |= MAP_FIXED;
+ vaddr = eppnt->p_vaddr;
+ }
+ error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
+ eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
+ elf_prot,
+ elf_type,
+ interpreter_fd,
+ eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
+
if (error == -1) {
- perror("mmap");
- exit(-1);
+ /* Real error */
+ close(interpreter_fd);
+ free(elf_phdata);
+ return ~((abi_ulong)0UL);
}
- load_addr = error;
- load_addr_set = 1;
- }
- eppnt = elf_phdata;
- for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
- if (eppnt->p_type == PT_LOAD) {
- int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
- int elf_prot = 0;
- abi_ulong vaddr = 0;
-
- if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
- if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
- if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
- if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
- elf_type |= MAP_FIXED;
- vaddr = eppnt->p_vaddr;
- }
- error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
- eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
- elf_prot,
- elf_type,
- interpreter_fd,
- eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
-
- if (error == -1) {
- /* Real error */
- close(interpreter_fd);
- free(elf_phdata);
- return ~((abi_ulong)0UL);
- }
-
- if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
- load_addr = error;
- load_addr_set = 1;
- }
+ if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
+ load_addr = error;
+ load_addr_set = 1;
+ }
/* If the load segment requests extra zeros (e.g. bss), map it. */
if (eppnt->p_filesz < eppnt->p_memsz) {
@@ -1246,15 +1255,15 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
zero_bss(base + eppnt->p_filesz,
base + eppnt->p_memsz, elf_prot);
}
- }
+ }
- /* Now use mmap to map the library into memory. */
+ /* Now use mmap to map the library into memory. */
- close(interpreter_fd);
- free(elf_phdata);
+ close(interpreter_fd);
+ free(elf_phdata);
- *interp_load_addr = load_addr;
- return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
+ *interp_load_addr = load_addr;
+ return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
}
static int symfind(const void *s0, const void *s1)
@@ -1356,8 +1365,8 @@ static void load_symbols(struct elfhdr *hdr, int fd)
#endif
// Throw away entries which we do not need.
if (syms[i].st_shndx == SHN_UNDEF ||
- syms[i].st_shndx >= SHN_LORESERVE ||
- ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
+ syms[i].st_shndx >= SHN_LORESERVE ||
+ ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
nsyms--;
if (i < nsyms) {
syms[i] = syms[nsyms];
@@ -1425,8 +1434,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
/* First of all, some simple consistency checks */
if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
- (! elf_check_arch(elf_ex.e_machine))) {
- return -ENOEXEC;
+ (! elf_check_arch(elf_ex.e_machine))) {
+ return -ENOEXEC;
}
bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
@@ -1439,20 +1448,20 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
/* Now read in all of the header information */
elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
if (elf_phdata == NULL) {
- return -ENOMEM;
+ return -ENOMEM;
}
retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
if(retval > 0) {
- retval = read(bprm->fd, (char *) elf_phdata,
- elf_ex.e_phentsize * elf_ex.e_phnum);
+ retval = read(bprm->fd, (char *) elf_phdata,
+ elf_ex.e_phentsize * elf_ex.e_phnum);
}
if (retval < 0) {
- perror("load_elf_binary");
- exit(-1);
- free (elf_phdata);
- return -errno;
+ perror("load_elf_binary");
+ exit(-1);
+ free (elf_phdata);
+ return -errno;
}
#ifdef BSWAP_NEEDED
@@ -1474,131 +1483,131 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
interp_ex.a_info = 0;
for(i=0;i < elf_ex.e_phnum; i++) {
- if (elf_ppnt->p_type == PT_INTERP) {
- if ( elf_interpreter != NULL )
- {
- free (elf_phdata);
- free(elf_interpreter);
- close(bprm->fd);
- return -EINVAL;
- }
-
- /* This is the program interpreter used for
- * shared libraries - for now assume that this
- * is an a.out format binary
- */
-
- elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
-
- if (elf_interpreter == NULL) {
- free (elf_phdata);
- close(bprm->fd);
- return -ENOMEM;
- }
-
- retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
- if(retval >= 0) {
- retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
- }
- if(retval < 0) {
- perror("load_elf_binary2");
- exit(-1);
- }
-
- /* If the program interpreter is one of these two,
- then assume an iBCS2 image. Otherwise assume
- a native linux image. */
-
- /* JRP - Need to add X86 lib dir stuff here... */
-
- if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
- strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
- ibcs2_interpreter = 1;
- }
+ if (elf_ppnt->p_type == PT_INTERP) {
+ if ( elf_interpreter != NULL )
+ {
+ free (elf_phdata);
+ free(elf_interpreter);
+ close(bprm->fd);
+ return -EINVAL;
+ }
+
+ /* This is the program interpreter used for
+ * shared libraries - for now assume that this
+ * is an a.out format binary
+ */
+
+ elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
+
+ if (elf_interpreter == NULL) {
+ free (elf_phdata);
+ close(bprm->fd);
+ return -ENOMEM;
+ }
+
+ retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
+ if(retval >= 0) {
+ retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
+ }
+ if(retval < 0) {
+ perror("load_elf_binary2");
+ exit(-1);
+ }
+
+ /* If the program interpreter is one of these two,
+ then assume an iBCS2 image. Otherwise assume
+ a native linux image. */
+
+ /* JRP - Need to add X86 lib dir stuff here... */
+
+ if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
+ strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
+ ibcs2_interpreter = 1;
+ }
#if 0
- printf("Using ELF interpreter %s\n", path(elf_interpreter));
+ printf("Using ELF interpreter %s\n", path(elf_interpreter));
#endif
- if (retval >= 0) {
- retval = open(path(elf_interpreter), O_RDONLY);
- if(retval >= 0) {
- interpreter_fd = retval;
- }
- else {
- perror(elf_interpreter);
- exit(-1);
- /* retval = -errno; */
- }
- }
-
- if (retval >= 0) {
- retval = lseek(interpreter_fd, 0, SEEK_SET);
- if(retval >= 0) {
- retval = read(interpreter_fd,bprm->buf,128);
- }
- }
- if (retval >= 0) {
- interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
- interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */
- }
- if (retval < 0) {
- perror("load_elf_binary3");
- exit(-1);
- free (elf_phdata);
- free(elf_interpreter);
- close(bprm->fd);
- return retval;
- }
- }
- elf_ppnt++;
+ if (retval >= 0) {
+ retval = open(path(elf_interpreter), O_RDONLY);
+ if(retval >= 0) {
+ interpreter_fd = retval;
+ }
+ else {
+ perror(elf_interpreter);
+ exit(-1);
+ /* retval = -errno; */
+ }
+ }
+
+ if (retval >= 0) {
+ retval = lseek(interpreter_fd, 0, SEEK_SET);
+ if(retval >= 0) {
+ retval = read(interpreter_fd,bprm->buf,128);
+ }
+ }
+ if (retval >= 0) {
+ interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
+ interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */
+ }
+ if (retval < 0) {
+ perror("load_elf_binary3");
+ exit(-1);
+ free (elf_phdata);
+ free(elf_interpreter);
+ close(bprm->fd);
+ return retval;
+ }
+ }
+ elf_ppnt++;
}
/* Some simple consistency checks for the interpreter */
if (elf_interpreter){
- interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
+ interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
- /* Now figure out which format our binary is */
- if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
- (N_MAGIC(interp_ex) != QMAGIC)) {
- interpreter_type = INTERPRETER_ELF;
- }
+ /* Now figure out which format our binary is */
+ if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
+ (N_MAGIC(interp_ex) != QMAGIC)) {
+ interpreter_type = INTERPRETER_ELF;
+ }
- if (interp_elf_ex.e_ident[0] != 0x7f ||
+ if (interp_elf_ex.e_ident[0] != 0x7f ||
strncmp((char *)&interp_elf_ex.e_ident[1], "ELF",3) != 0) {
- interpreter_type &= ~INTERPRETER_ELF;
- }
-
- if (!interpreter_type) {
- free(elf_interpreter);
- free(elf_phdata);
- close(bprm->fd);
- return -ELIBBAD;
- }
+ interpreter_type &= ~INTERPRETER_ELF;
+ }
+
+ if (!interpreter_type) {
+ free(elf_interpreter);
+ free(elf_phdata);
+ close(bprm->fd);
+ return -ELIBBAD;
+ }
}
/* OK, we are done with that, now set up the arg stuff,
and then start this sucker up */
{
- char * passed_p;
-
- if (interpreter_type == INTERPRETER_AOUT) {
- snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
- passed_p = passed_fileno;
-
- if (elf_interpreter) {
- bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p);
- bprm->argc++;
- }
- }
- if (!bprm->p) {
- if (elf_interpreter) {
- free(elf_interpreter);
- }
- free (elf_phdata);
- close(bprm->fd);
- return -E2BIG;
- }
+ char * passed_p;
+
+ if (interpreter_type == INTERPRETER_AOUT) {
+ snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
+ passed_p = passed_fileno;
+
+ if (elf_interpreter) {
+ bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p);
+ bprm->argc++;
+ }
+ }
+ if (!bprm->p) {
+ if (elf_interpreter) {
+ free(elf_interpreter);
+ }
+ free (elf_phdata);
+ close(bprm->fd);
+ return -E2BIG;
+ }
}
/* OK, This is the point of no return */
@@ -1625,7 +1634,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
unsigned long real_start;
unsigned long host_size;
for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum;
- i++, elf_ppnt++) {
+ i++, elf_ppnt++) {
if (elf_ppnt->p_type != PT_LOAD)
continue;
addr = elf_ppnt->p_vaddr;
@@ -1709,7 +1718,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
int elf_flags = 0;
abi_ulong error;
- if (elf_ppnt->p_type != PT_LOAD)
+ if (elf_ppnt->p_type != PT_LOAD)
continue;
if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
@@ -1793,30 +1802,30 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
end_data += load_bias;
if (elf_interpreter) {
- if (interpreter_type & 1) {
- elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
- }
- else if (interpreter_type & 2) {
- elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
- &interp_load_addr);
- }
+ if (interpreter_type & 1) {
+ elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
+ }
+ else if (interpreter_type & 2) {
+ elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
+ &interp_load_addr);
+ }
reloc_func_desc = interp_load_addr;
- close(interpreter_fd);
- free(elf_interpreter);
+ close(interpreter_fd);
+ free(elf_interpreter);
- if (elf_entry == ~((abi_ulong)0UL)) {
- printf("Unable to load interpreter\n");
- free(elf_phdata);
- exit(-1);
- return 0;
- }
+ if (elf_entry == ~((abi_ulong)0UL)) {
+ printf("Unable to load interpreter\n");
+ free(elf_phdata);
+ exit(-1);
+ return 0;
+ }
}
free(elf_phdata);
if (qemu_log_enabled())
- load_symbols(&elf_ex, bprm->fd);
+ load_symbols(&elf_ex, bprm->fd);
if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
@@ -1825,13 +1834,13 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
info->start_stack = bprm->p = elf_stack - 4;
#endif
bprm->p = create_elf_tables(bprm->p,
- bprm->argc,
- bprm->envc,
- &elf_ex,
- load_addr, load_bias,
- interp_load_addr,
- (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
- info);
+ bprm->argc,
+ bprm->envc,
+ &elf_ex,
+ load_addr, load_bias,
+ interp_load_addr,
+ (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
+ info);
info->load_addr = reloc_func_desc;
info->start_brk = info->brk = elf_brk;
info->end_code = end_code;
@@ -1851,12 +1860,12 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
if ( info->personality == PER_SVR4 )
{
- /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
- and some applications "depend" upon this behavior.
- Since we do not have the power to recompile these, we
- emulate the SVr4 behavior. Sigh. */
- mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE, -1, 0);
+ /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
+ and some applications "depend" upon this behavior.
+ Since we do not have the power to recompile these, we
+ emulate the SVr4 behavior. Sigh. */
+ mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE, -1, 0);
}
info->entry = elf_entry;
@@ -1869,7 +1878,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
}
#ifdef USE_ELF_CORE_DUMP
-
/*
* Definitions to generate Intel SVR4-like core files.
* These mostly have the same names as the SVR4 types with "target_elf_"
@@ -2006,17 +2014,17 @@ struct mm_struct {
static struct mm_struct *vma_init(void);
static void vma_delete(struct mm_struct *);
static int vma_add_mapping(struct mm_struct *, abi_ulong,
- abi_ulong, abi_ulong);
+ abi_ulong, abi_ulong);
static int vma_get_mapping_count(const struct mm_struct *);
static struct vm_area_struct *vma_first(const struct mm_struct *);
static struct vm_area_struct *vma_next(struct vm_area_struct *);
static abi_ulong vma_dump_size(const struct vm_area_struct *);
static int vma_walker(void *priv, abi_ulong start, abi_ulong end,
- unsigned long flags);
+ unsigned long flags);
static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t);
static void fill_note(struct memelfnote *, const char *, int,
- unsigned int, void *);
+ unsigned int, void *);
static void fill_prstatus(struct target_elf_prstatus *, const TaskState *, int);
static int fill_psinfo(struct target_elf_prpsinfo *, const TaskState *);
static void fill_auxv_note(struct memelfnote *, const TaskState *);
@@ -2096,7 +2104,7 @@ static void vma_delete(struct mm_struct *mm)
}
static int vma_add_mapping(struct mm_struct *mm, abi_ulong start,
- abi_ulong end, abi_ulong flags)
+ abi_ulong end, abi_ulong flags)
{
struct vm_area_struct *vma;
@@ -2165,7 +2173,7 @@ static abi_ulong vma_dump_size(const struct vm_area_struct *vma)
}
static int vma_walker(void *priv, abi_ulong start, abi_ulong end,
- unsigned long flags)
+ unsigned long flags)
{
struct mm_struct *mm = (struct mm_struct *)priv;
@@ -2174,7 +2182,7 @@ static int vma_walker(void *priv, abi_ulong start, abi_ulong end,
}
static void fill_note(struct memelfnote *note, const char *name, int type,
- unsigned int sz, void *data)
+ unsigned int sz, void *data)
{
unsigned int namesz;
@@ -2195,7 +2203,7 @@ static void fill_note(struct memelfnote *note, const char *name, int type,
}
static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
- uint32_t flags)
+ uint32_t flags)
{
(void) memset(elf, 0, sizeof(*elf));
@@ -2241,7 +2249,7 @@ static size_t note_size(const struct memelfnote *note)
}
static void fill_prstatus(struct target_elf_prstatus *prstatus,
- const TaskState *ts, int signr)
+ const TaskState *ts, int signr)
{
(void) memset(prstatus, 0, sizeof (*prstatus));
prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
@@ -2282,7 +2290,7 @@ static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
filename = strdup(ts->bprm->filename);
base_filename = strdup(basename(filename));
(void) strncpy(psinfo->pr_fname, base_filename,
- sizeof(psinfo->pr_fname));
+ sizeof(psinfo->pr_fname));
free(base_filename);
free(filename);
@@ -2331,7 +2339,7 @@ static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
* Returns 0 in case of success, -1 otherwise (errno is set).
*/
static int core_dump_filename(const TaskState *ts, char *buf,
- size_t bufsize)
+ size_t bufsize)
{
char timestamp[64];
char *filename = NULL;
@@ -2343,16 +2351,16 @@ static int core_dump_filename(const TaskState *ts, char *buf,
if (gettimeofday(&tv, NULL) < 0) {
(void) fprintf(stderr, "unable to get current timestamp: %s",
- strerror(errno));
+ strerror(errno));
return (-1);
}
filename = strdup(ts->bprm->filename);
base_filename = strdup(basename(filename));
(void) strftime(timestamp, sizeof (timestamp), "%Y%m%d-%H%M%S",
- localtime_r(&tv.tv_sec, &tm));
+ localtime_r(&tv.tv_sec, &tm));
(void) snprintf(buf, bufsize, "qemu_%s_%s_%d.core",
- base_filename, timestamp, (int)getpid());
+ base_filename, timestamp, (int)getpid());
free(base_filename);
free(filename);
@@ -2437,7 +2445,7 @@ static void fill_thread_info(struct elf_note_info *info, const CPUState *env)
fill_prstatus(&ets->prstatus, ts, 0);
elf_core_copy_regs(&ets->prstatus.pr_reg, env);
fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus),
- &ets->prstatus);
+ &ets->prstatus);
QTAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link);
@@ -2445,7 +2453,7 @@ static void fill_thread_info(struct elf_note_info *info, const CPUState *env)
}
static int fill_note_info(struct elf_note_info *info,
- long signr, const CPUState *env)
+ long signr, const CPUState *env)
{
#define NUMNOTES 3
CPUState *cpu = NULL;
@@ -2473,10 +2481,10 @@ static int fill_note_info(struct elf_note_info *info,
fill_prstatus(info->prstatus, ts, signr);
elf_core_copy_regs(&info->prstatus->pr_reg, env);
fill_note(&info->notes[0], "CORE", NT_PRSTATUS,
- sizeof (*info->prstatus), info->prstatus);
+ sizeof (*info->prstatus), info->prstatus);
fill_psinfo(info->psinfo, ts);
fill_note(&info->notes[1], "CORE", NT_PRPSINFO,
- sizeof (*info->psinfo), info->psinfo);
+ sizeof (*info->psinfo), info->psinfo);
fill_auxv_note(&info->notes[2], ts);
info->numnote = 3;
@@ -2523,7 +2531,7 @@ static int write_note_info(struct elf_note_info *info, int fd)
/* write prstatus for each thread */
for (ets = info->thread_list.tqh_first; ets != NULL;
- ets = ets->ets_link.tqe_next) {
+ ets = ets->ets_link.tqe_next) {
if ((error = write_note(&ets->notes[0], fd)) != 0)
return (error);
}
@@ -2591,13 +2599,13 @@ static int elf_core_dump(int signr, const CPUState *env)
errno = 0;
getrlimit(RLIMIT_CORE, &dumpsize);
if (dumpsize.rlim_cur == 0)
- return 0;
+ return 0;
if (core_dump_filename(ts, corefile, sizeof (corefile)) < 0)
return (-errno);
if ((fd = open(corefile, O_WRONLY | O_CREAT,
- S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
return (-errno);
/*
@@ -2686,7 +2694,7 @@ static int elf_core_dump(int signr, const CPUState *env)
end = vma->vma_start + vma_dump_size(vma);
for (addr = vma->vma_start; addr < end;
- addr += TARGET_PAGE_SIZE) {
+ addr += TARGET_PAGE_SIZE) {
char page[TARGET_PAGE_SIZE];
int error;
@@ -2697,7 +2705,7 @@ static int elf_core_dump(int signr, const CPUState *env)
error = copy_from_user(page, addr, sizeof (page));
if (error != 0) {
(void) fprintf(stderr, "unable to dump " TARGET_ABI_FMT_lx "\n",
- addr);
+ addr);
errno = -error;
goto out;
}
@@ -2706,7 +2714,7 @@ static int elf_core_dump(int signr, const CPUState *env)
}
}
-out:
+ out:
free_note_info(&info);
if (mm != NULL)
vma_delete(mm);
--
1.7.0.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 04/12] linux-user: Reduce lseek+reads while loading elf files.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (18 preceding siblings ...)
2010-05-05 18:07 ` [Qemu-devel] [PATCH 03/12] linux-user: Reindent elfload.c Richard Henderson
@ 2010-05-05 18:07 ` Richard Henderson
2010-05-05 18:07 ` [Qemu-devel] [PATCH 05/12] linux-user: Define ELF_DATA generically Richard Henderson
` (7 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-05-05 18:07 UTC (permalink / raw)
To: qemu-devel; +Cc: paul
Define BPRM_BUF_SIZE to 1k and read that amount initially. If the
data we want from the binary is in this buffer, use it instead of
reading from the file again.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 104 ++++++++++++++++++++---------------------------
linux-user/linuxload.c | 17 +++-----
linux-user/qemu.h | 7 +++-
3 files changed, 57 insertions(+), 71 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index ac118f2..dec86d6 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1140,7 +1140,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
int interpreter_fd,
- abi_ulong *interp_load_addr)
+ abi_ulong *interp_load_addr,
+ char bprm_buf[BPRM_BUF_SIZE])
{
struct elf_phdr *elf_phdata = NULL;
struct elf_phdr *eppnt;
@@ -1183,17 +1184,15 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
return ~((abi_ulong)0UL);
}
- retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
- if(retval >= 0) {
- retval = read(interpreter_fd,
- (char *) elf_phdata,
- sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
- }
- if (retval < 0) {
- perror("load_elf_interp");
- exit(-1);
- free (elf_phdata);
- return retval;
+ i = interp_elf_ex->e_phnum * sizeof(struct elf_phdr);
+ if (interp_elf_ex->e_phoff + i <= BPRM_BUF_SIZE) {
+ memcpy(elf_phdata, bprm_buf + interp_elf_ex->e_phoff, i);
+ } else {
+ retval = pread(interpreter_fd, elf_phdata, i, interp_elf_ex->e_phoff);
+ if (retval != i) {
+ perror("load_elf_interp");
+ exit(-1);
+ }
}
#ifdef BSWAP_NEEDED
eppnt = elf_phdata;
@@ -1451,17 +1450,15 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
return -ENOMEM;
}
- retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
- if(retval > 0) {
- retval = read(bprm->fd, (char *) elf_phdata,
- elf_ex.e_phentsize * elf_ex.e_phnum);
- }
-
- if (retval < 0) {
- perror("load_elf_binary");
- exit(-1);
- free (elf_phdata);
- return -errno;
+ 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);
+ }
}
#ifdef BSWAP_NEEDED
@@ -1505,13 +1502,16 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
return -ENOMEM;
}
- retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
- if(retval >= 0) {
- retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
- }
- if(retval < 0) {
- perror("load_elf_binary2");
- exit(-1);
+ if (elf_ppnt->p_offset + elf_ppnt->p_filesz <= BPRM_BUF_SIZE) {
+ memcpy(elf_interpreter, bprm->buf + elf_ppnt->p_offset,
+ elf_ppnt->p_filesz);
+ } else {
+ retval = pread(bprm->fd, elf_interpreter, elf_ppnt->p_filesz,
+ elf_ppnt->p_offset);
+ if (retval != elf_ppnt->p_filesz) {
+ perror("load_elf_binary2");
+ exit(-1);
+ }
}
/* If the program interpreter is one of these two,
@@ -1525,39 +1525,24 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
ibcs2_interpreter = 1;
}
-#if 0
- printf("Using ELF interpreter %s\n", path(elf_interpreter));
-#endif
- if (retval >= 0) {
- retval = open(path(elf_interpreter), O_RDONLY);
- if(retval >= 0) {
- interpreter_fd = retval;
- }
- else {
- perror(elf_interpreter);
- exit(-1);
- /* retval = -errno; */
- }
+ retval = open(path(elf_interpreter), O_RDONLY);
+ if (retval < 0) {
+ perror(elf_interpreter);
+ exit(-1);
}
+ interpreter_fd = retval;
- if (retval >= 0) {
- retval = lseek(interpreter_fd, 0, SEEK_SET);
- if(retval >= 0) {
- retval = read(interpreter_fd,bprm->buf,128);
- }
- }
- if (retval >= 0) {
- interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
- interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */
- }
+ retval = read(interpreter_fd, bprm->buf, BPRM_BUF_SIZE);
if (retval < 0) {
perror("load_elf_binary3");
exit(-1);
- free (elf_phdata);
- free(elf_interpreter);
- close(bprm->fd);
- return retval;
}
+ if (retval < BPRM_BUF_SIZE) {
+ memset(bprm->buf, 0, BPRM_BUF_SIZE - retval);
+ }
+
+ interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
+ interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */
}
elf_ppnt++;
}
@@ -1804,10 +1789,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
if (elf_interpreter) {
if (interpreter_type & 1) {
elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
- }
- else if (interpreter_type & 2) {
+ } else if (interpreter_type & 2) {
elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
- &interp_load_addr);
+ &interp_load_addr, bprm->buf);
}
reloc_func_desc = interp_load_addr;
diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
index 13ad9aa..9ee27c3 100644
--- a/linux-user/linuxload.c
+++ b/linux-user/linuxload.c
@@ -96,18 +96,16 @@ static int prepare_binprm(struct linux_binprm *bprm)
}
}
- retval = lseek(bprm->fd, 0L, SEEK_SET);
- if(retval >= 0) {
- retval = read(bprm->fd, bprm->buf, 128);
- }
- if(retval < 0) {
+ retval = read(bprm->fd, bprm->buf, BPRM_BUF_SIZE);
+ if (retval < 0) {
perror("prepare_binprm");
exit(-1);
- /* return(-errno); */
}
- else {
- return(retval);
+ if (retval < BPRM_BUF_SIZE) {
+ /* Make sure the rest of the loader won't read garbage. */
+ memset(bprm->buf + retval, 0, BPRM_BUF_SIZE - retval);
}
+ return retval;
}
/* Construct the envp and argv tables on the target stack. */
@@ -163,8 +161,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp,
int i;
bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
- for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
- bprm->page[i] = NULL;
+ memset(bprm->page, 0, sizeof(bprm->page));
retval = open(filename, O_RDONLY);
if (retval < 0)
return retval;
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index dab3597..a60fcdd 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -31,6 +31,7 @@
* task_struct fields in the kernel
*/
struct image_info {
+ abi_ulong load_bias;
abi_ulong load_addr;
abi_ulong start_code;
abi_ulong end_code;
@@ -143,12 +144,16 @@ extern unsigned long mmap_min_addr;
*/
#define MAX_ARG_PAGES 33
+/* Read a good amount of data initially, to hopefully get all the
+ program headers loaded. */
+#define BPRM_BUF_SIZE 1024
+
/*
* This structure is used to hold the arguments that are
* used when loading binaries.
*/
struct linux_binprm {
- char buf[128];
+ char buf[BPRM_BUF_SIZE] __attribute__((aligned));
void *page[MAX_ARG_PAGES];
abi_ulong p;
int fd;
--
1.7.0.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 05/12] linux-user: Define ELF_DATA generically.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (19 preceding siblings ...)
2010-05-05 18:07 ` [Qemu-devel] [PATCH 04/12] linux-user: Reduce lseek+reads while loading elf files Richard Henderson
@ 2010-05-05 18:07 ` Richard Henderson
2010-05-05 18:07 ` [Qemu-devel] [PATCH 06/12] linux-user: Clean up byte-swapping in elfload.c Richard Henderson
` (6 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-05-05 18:07 UTC (permalink / raw)
To: qemu-devel; +Cc: paul
The only consideration on this value is the target endianness.
The existing defines were incorrect for alpha and sh4eb.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 30 ++++++------------------------
1 files changed, 6 insertions(+), 24 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index dec86d6..8732bc0 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -95,6 +95,12 @@ enum {
#define ELIBBAD 80
#endif
+#ifdef TARGET_WORDS_BIGENDIAN
+#define ELF_DATA ELFDATA2MSB
+#else
+#define ELF_DATA ELFDATA2LSB
+#endif
+
typedef target_ulong target_elf_greg_t;
#ifdef USE_UID16
typedef uint16_t target_uid_t;
@@ -132,7 +138,6 @@ static uint32_t get_elf_hwcap(void)
#define elf_check_arch(x) ( ((x) == ELF_ARCH) )
#define ELF_CLASS ELFCLASS64
-#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_X86_64
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
@@ -196,7 +201,6 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
* These are used to set parameters in the core dumps.
*/
#define ELF_CLASS ELFCLASS32
-#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_386
static inline void init_thread(struct target_pt_regs *regs,
@@ -259,11 +263,6 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#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
static inline void init_thread(struct target_pt_regs *regs,
@@ -352,7 +351,6 @@ enum
#endif
#define ELF_CLASS ELFCLASS64
-#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_SPARCV9
#define STACK_BIAS 2047
@@ -382,7 +380,6 @@ static inline void init_thread(struct target_pt_regs *regs,
#define elf_check_arch(x) ( (x) == EM_SPARC )
#define ELF_CLASS ELFCLASS32
-#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_SPARC
static inline void init_thread(struct target_pt_regs *regs,
@@ -416,11 +413,6 @@ static inline void init_thread(struct target_pt_regs *regs,
#endif
-#ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA ELFDATA2MSB
-#else
-#define ELF_DATA ELFDATA2LSB
-#endif
#define ELF_ARCH EM_PPC
/* Feature masks for the Aux Vector Hardware Capabilities (AT_HWCAP).
@@ -554,11 +546,6 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#else
#define ELF_CLASS ELFCLASS32
#endif
-#ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA ELFDATA2MSB
-#else
-#define ELF_DATA ELFDATA2LSB
-#endif
#define ELF_ARCH EM_MIPS
static inline void init_thread(struct target_pt_regs *regs,
@@ -626,7 +613,6 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#define elf_check_arch(x) ( (x) == EM_XILINX_MICROBLAZE )
#define ELF_CLASS ELFCLASS32
-#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_XILINX_MICROBLAZE
static inline void init_thread(struct target_pt_regs *regs,
@@ -648,7 +634,6 @@ static inline void init_thread(struct target_pt_regs *regs,
#define elf_check_arch(x) ( (x) == EM_SH )
#define ELF_CLASS ELFCLASS32
-#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_SH
static inline void init_thread(struct target_pt_regs *regs,
@@ -704,7 +689,6 @@ static inline void elf_core_copy_regs(target_elf_gregset_t *regs,
#define elf_check_arch(x) ( (x) == EM_CRIS )
#define ELF_CLASS ELFCLASS32
-#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_CRIS
static inline void init_thread(struct target_pt_regs *regs,
@@ -724,7 +708,6 @@ static inline void init_thread(struct target_pt_regs *regs,
#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?
@@ -778,7 +761,6 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
#define elf_check_arch(x) ( (x) == ELF_ARCH )
#define ELF_CLASS ELFCLASS64
-#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_ALPHA
static inline void init_thread(struct target_pt_regs *regs,
--
1.7.0.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 06/12] linux-user: Clean up byte-swapping in elfload.c.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (20 preceding siblings ...)
2010-05-05 18:07 ` [Qemu-devel] [PATCH 05/12] linux-user: Define ELF_DATA generically Richard Henderson
@ 2010-05-05 18:07 ` Richard Henderson
2010-05-05 18:07 ` [Qemu-devel] [PATCH 07/12] linux-user: Load symbols from the interpreter Richard Henderson
` (5 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-05-05 18:07 UTC (permalink / raw)
To: qemu-devel; +Cc: paul
Remove ifdefs from code by defining empty inline functions
when byte swapping isn't needed. Push loops over swapping
arrays of structures into the swapping functions.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 119 ++++++++++++++++++++------------------------------
1 files changed, 48 insertions(+), 71 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 8732bc0..f12161c 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -853,30 +853,36 @@ static void bswap_ehdr(struct elfhdr *ehdr)
bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
}
-static void bswap_phdr(struct elf_phdr *phdr)
+static void bswap_phdr(struct elf_phdr *phdr, int phnum)
{
- 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 */
+ int i;
+ for (i = 0; i < phnum; ++i, ++phdr) {
+ bswap32s(&phdr->p_type); /* Segment type */
+ bswap32s(&phdr->p_flags); /* Segment flags */
+ 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 */
+ bswaptls(&phdr->p_align); /* Segment alignment */
+ }
}
-static void bswap_shdr(struct elf_shdr *shdr)
+static void bswap_shdr(struct elf_shdr *shdr, int shnum)
{
- 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);
+ int i;
+ for (i = 0; i < shnum; ++i, ++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(struct elf_sym *sym)
@@ -886,20 +892,15 @@ static void bswap_sym(struct elf_sym *sym)
bswaptls(&sym->st_size);
bswap16s(&sym->st_shndx);
}
+#else
+static inline void bswap_ehdr(struct elfhdr *ehdr) { }
+static inline void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
+static inline void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
+static inline void bswap_sym(struct elf_sym *sym) { }
#endif
#ifdef USE_ELF_CORE_DUMP
static int elf_core_dump(int, const CPUState *);
-
-#ifdef BSWAP_NEEDED
-static void bswap_note(struct elf_note *en)
-{
- bswap32s(&en->n_namesz);
- bswap32s(&en->n_descsz);
- bswap32s(&en->n_type);
-}
-#endif /* BSWAP_NEEDED */
-
#endif /* USE_ELF_CORE_DUMP */
/*
@@ -1135,9 +1136,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
error = 0;
-#ifdef BSWAP_NEEDED
bswap_ehdr(interp_elf_ex);
-#endif
/* First of all, some simple consistency checks */
if ((interp_elf_ex->e_type != ET_EXEC &&
interp_elf_ex->e_type != ET_DYN) ||
@@ -1176,12 +1175,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
exit(-1);
}
}
-#ifdef BSWAP_NEEDED
- eppnt = elf_phdata;
- for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
- bswap_phdr(eppnt);
- }
-#endif
+ bswap_phdr(elf_phdata, interp_elf_ex->e_phnum);
if (interp_elf_ex->e_type == ET_DYN) {
/* in order to avoid hardcoding the interpreter load
@@ -1305,9 +1299,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
for (i = 0; i < hdr->e_shnum; i++) {
if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
return;
-#ifdef BSWAP_NEEDED
- bswap_shdr(&sechdr);
-#endif
+ bswap_shdr(&sechdr, 1);
if (sechdr.sh_type == SHT_SYMTAB) {
symtab = sechdr;
lseek(fd, hdr->e_shoff
@@ -1315,9 +1307,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
if (read(fd, &strtab, sizeof(strtab))
!= sizeof(strtab))
return;
-#ifdef BSWAP_NEEDED
- bswap_shdr(&strtab);
-#endif
+ bswap_shdr(&strtab, 1);
goto found;
}
}
@@ -1341,9 +1331,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
i = 0;
while (i < nsyms) {
-#ifdef BSWAP_NEEDED
bswap_sym(syms + i);
-#endif
// Throw away entries which we do not need.
if (syms[i].st_shndx == SHN_UNDEF ||
syms[i].st_shndx >= SHN_LORESERVE ||
@@ -1409,9 +1397,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
load_addr = 0;
load_bias = 0;
elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
-#ifdef BSWAP_NEEDED
bswap_ehdr(&elf_ex);
-#endif
/* First of all, some simple consistency checks */
if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
@@ -1442,17 +1428,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
exit(-1);
}
}
-
-#ifdef BSWAP_NEEDED
- elf_ppnt = elf_phdata;
- for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
- bswap_phdr(elf_ppnt);
- }
-#endif
- elf_ppnt = elf_phdata;
+ bswap_phdr(elf_phdata, elf_ex.e_phnum);
elf_brk = 0;
-
elf_stack = ~((abi_ulong)0UL);
elf_interpreter = NULL;
start_code = ~((abi_ulong)0UL);
@@ -1461,6 +1439,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
end_data = 0;
interp_ex.a_info = 0;
+ elf_ppnt = elf_phdata;
for(i=0;i < elf_ex.e_phnum; i++) {
if (elf_ppnt->p_type == PT_INTERP) {
if ( elf_interpreter != NULL )
@@ -2006,9 +1985,6 @@ static int write_note(struct memelfnote *, int);
static int write_note_info(struct elf_note_info *, int);
#ifdef BSWAP_NEEDED
-static void bswap_prstatus(struct target_elf_prstatus *);
-static void bswap_psinfo(struct target_elf_prpsinfo *);
-
static void bswap_prstatus(struct target_elf_prstatus *prstatus)
{
prstatus->pr_info.si_signo = tswapl(prstatus->pr_info.si_signo);
@@ -2036,6 +2012,17 @@ static void bswap_psinfo(struct target_elf_prpsinfo *psinfo)
psinfo->pr_pgrp = tswap32(psinfo->pr_pgrp);
psinfo->pr_sid = tswap32(psinfo->pr_sid);
}
+
+static void bswap_note(struct elf_note *en)
+{
+ bswap32s(&en->n_namesz);
+ bswap32s(&en->n_descsz);
+ bswap32s(&en->n_type);
+}
+#else
+static inline void bswap_prstatus(struct target_elf_prstatus *p) { }
+static inline void bswap_psinfo(struct target_elf_prpsinfo *p) {}
+static inline void bswap_note(struct elf_note *en) { }
#endif /* BSWAP_NEEDED */
/*
@@ -2188,9 +2175,7 @@ static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
elf->e_phentsize = sizeof(struct elf_phdr);
elf->e_phnum = segs;
-#ifdef BSWAP_NEEDED
bswap_ehdr(elf);
-#endif
}
static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
@@ -2204,9 +2189,7 @@ static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
phdr->p_flags = 0;
phdr->p_align = 0;
-#ifdef BSWAP_NEEDED
- bswap_phdr(phdr);
-#endif
+ bswap_phdr(phdr, 1);
}
static size_t note_size(const struct memelfnote *note)
@@ -2224,9 +2207,7 @@ static void fill_prstatus(struct target_elf_prstatus *prstatus,
prstatus->pr_pgrp = getpgrp();
prstatus->pr_sid = getsid(0);
-#ifdef BSWAP_NEEDED
bswap_prstatus(prstatus);
-#endif
}
static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
@@ -2260,9 +2241,7 @@ static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
free(base_filename);
free(filename);
-#ifdef BSWAP_NEEDED
bswap_psinfo(psinfo);
-#endif
return (0);
}
@@ -2387,9 +2366,7 @@ static int write_note(struct memelfnote *men, int fd)
en.n_type = men->type;
en.n_descsz = men->datasz;
-#ifdef BSWAP_NEEDED
bswap_note(&en);
-#endif
if (dump_write(fd, &en, sizeof(en)) != 0)
return (-1);
--
1.7.0.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 07/12] linux-user: Load symbols from the interpreter.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (21 preceding siblings ...)
2010-05-05 18:07 ` [Qemu-devel] [PATCH 06/12] linux-user: Clean up byte-swapping in elfload.c Richard Henderson
@ 2010-05-05 18:07 ` Richard Henderson
2010-05-05 18:07 ` [Qemu-devel] [PATCH 08/12] linux-user: Improve consistency checking in elf headers Richard Henderson
` (4 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-05-05 18:07 UTC (permalink / raw)
To: qemu-devel; +Cc: paul
First, adjust load_symbols to accept a load_bias parameter. At the same
time, read the entire section header table in one go, use pread instead
f lseek+read for the symbol and string tables, and properly free
allocated structures on error exit paths.
Second, adjust load_elf_interp to compute load_bias. This requires
finding out the built-in load addresses. Which allows us to honor a
pre-linked interpreter image when possible, and eliminate the hard-coded
INTERP_MAP_SIZE value.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 189 +++++++++++++++++++++++++++-----------------------
1 files changed, 101 insertions(+), 88 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index f12161c..723e956 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -811,9 +811,6 @@ struct exec
#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)
@@ -902,6 +899,7 @@ static inline void bswap_sym(struct elf_sym *sym) { }
#ifdef USE_ELF_CORE_DUMP
static int elf_core_dump(int, const CPUState *);
#endif /* USE_ELF_CORE_DUMP */
+static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias);
/*
* 'copy_elf_strings()' copies argument/envelope strings from user
@@ -1127,15 +1125,11 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
char bprm_buf[BPRM_BUF_SIZE])
{
struct elf_phdr *elf_phdata = NULL;
- struct elf_phdr *eppnt;
- abi_ulong load_addr = 0;
- int load_addr_set = 0;
+ abi_ulong load_addr, load_bias, loaddr, hiaddr;
int retval;
abi_ulong error;
int i;
- error = 0;
-
bswap_ehdr(interp_elf_ex);
/* First of all, some simple consistency checks */
if ((interp_elf_ex->e_type != ET_EXEC &&
@@ -1144,7 +1138,6 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
return ~((abi_ulong)0UL);
}
-
/* Now read in all of the header information */
if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
@@ -1177,41 +1170,56 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
}
bswap_phdr(elf_phdata, interp_elf_ex->e_phnum);
+ /* Find the maximum size of the image and allocate an appropriate
+ amount of memory to handle that. */
+ loaddr = -1, hiaddr = 0;
+ for (i = 0; i < interp_elf_ex->e_phnum; ++i) {
+ if (elf_phdata[i].p_type == PT_LOAD) {
+ abi_ulong a = elf_phdata[i].p_vaddr;
+ if (a < loaddr) {
+ loaddr = a;
+ }
+ a += elf_phdata[i].p_memsz;
+ if (a > hiaddr) {
+ hiaddr = a;
+ }
+ }
+ }
+
+ load_addr = loaddr;
if (interp_elf_ex->e_type == ET_DYN) {
- /* in order to avoid hardcoding the interpreter load
- address in qemu, we allocate a big enough memory zone */
- error = target_mmap(0, INTERP_MAP_SIZE,
- PROT_NONE, MAP_PRIVATE | MAP_ANON,
- -1, 0);
- if (error == -1) {
+ /* The image indicates that it can be loaded anywhere. Find a
+ location that can hold the memory space required. If the
+ image is pre-linked, LOADDR will be non-zero. Since we do
+ not supply MAP_FIXED here we'll use that address if and
+ only if it remains available. */
+ load_addr = target_mmap(loaddr, hiaddr - loaddr, PROT_NONE,
+ MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
+ -1, 0);
+ if (load_addr == -1) {
perror("mmap");
exit(-1);
}
- load_addr = error;
- load_addr_set = 1;
}
+ load_bias = load_addr - loaddr;
- eppnt = elf_phdata;
- for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
+ for (i = 0; i < interp_elf_ex->e_phnum; i++) {
+ struct elf_phdr *eppnt = elf_phdata + i;
if (eppnt->p_type == PT_LOAD) {
- int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+ abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em;
int elf_prot = 0;
- abi_ulong vaddr = 0;
if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
- if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
- elf_type |= MAP_FIXED;
- vaddr = eppnt->p_vaddr;
- }
- error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
- eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
- elf_prot,
- elf_type,
- interpreter_fd,
- eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
+ vaddr = load_bias + eppnt->p_vaddr;
+ vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
+ vaddr_ps = TARGET_ELF_PAGESTART(vaddr);
+
+ error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
+ elf_prot, MAP_PRIVATE | MAP_FIXED,
+ interpreter_fd, eppnt->p_offset - vaddr_po);
if (error == -1) {
/* Real error */
close(interpreter_fd);
@@ -1219,26 +1227,25 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
return ~((abi_ulong)0UL);
}
- if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
- load_addr = error;
- load_addr_set = 1;
- }
+ vaddr_ef = vaddr + eppnt->p_filesz;
+ vaddr_em = vaddr + eppnt->p_memsz;
/* If the load segment requests extra zeros (e.g. bss), map it. */
- if (eppnt->p_filesz < eppnt->p_memsz) {
- abi_ulong base = load_addr + eppnt->p_vaddr;
- zero_bss(base + eppnt->p_filesz,
- base + eppnt->p_memsz, elf_prot);
+ if (vaddr_ef < vaddr_em) {
+ zero_bss(vaddr_ef, vaddr_em, elf_prot);
}
}
+ }
- /* Now use mmap to map the library into memory. */
+ if (qemu_log_enabled()) {
+ load_symbols(interp_elf_ex, interpreter_fd, load_bias);
+ }
close(interpreter_fd);
free(elf_phdata);
*interp_load_addr = load_addr;
- return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
+ return ((abi_ulong) interp_elf_ex->e_entry) + load_bias;
}
static int symfind(const void *s0, const void *s1)
@@ -1287,82 +1294,87 @@ static int symcmp(const void *s0, const void *s1)
}
/* Best attempt to load symbols from this ELF object. */
-static void load_symbols(struct elfhdr *hdr, int fd)
+static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
{
- unsigned int i, nsyms;
- struct elf_shdr sechdr, symtab, strtab;
+ int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
+ struct elf_shdr *shdr;
char *strings;
struct syminfo *s;
struct elf_sym *syms;
- lseek(fd, hdr->e_shoff, SEEK_SET);
- for (i = 0; i < hdr->e_shnum; i++) {
- if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
- return;
- bswap_shdr(&sechdr, 1);
- if (sechdr.sh_type == SHT_SYMTAB) {
- symtab = sechdr;
- lseek(fd, hdr->e_shoff
- + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
- if (read(fd, &strtab, sizeof(strtab))
- != sizeof(strtab))
- return;
- bswap_shdr(&strtab, 1);
+ shnum = hdr->e_shnum;
+ i = shnum * sizeof(struct elf_shdr);
+ shdr = (struct elf_shdr *)alloca(i);
+ if (pread(fd, shdr, i, hdr->e_shoff) != i) {
+ return;
+ }
+
+ bswap_shdr(shdr, shnum);
+ for (i = 0; i < shnum; ++i) {
+ if (shdr[i].sh_type == SHT_SYMTAB) {
+ sym_idx = i;
+ str_idx = shdr[i].sh_link;
goto found;
}
}
- return; /* Shouldn't happen... */
+
+ /* There will be no symbol table if the file was stripped. */
+ return;
found:
- /* Now know where the strtab and symtab are. Snarf them. */
+ /* Now know where the strtab and symtab are. Snarf them. */
s = malloc(sizeof(*s));
- syms = malloc(symtab.sh_size);
- if (!syms)
- return;
- s->disas_strtab = strings = malloc(strtab.sh_size);
- if (!s->disas_strtab)
+ if (!s) {
return;
+ }
- lseek(fd, symtab.sh_offset, SEEK_SET);
- if (read(fd, syms, symtab.sh_size) != symtab.sh_size)
+ i = shdr[str_idx].sh_size;
+ s->disas_strtab = strings = malloc(i);
+ if (!strings || pread(fd, strings, i, shdr[str_idx].sh_offset) != i) {
+ free(s);
+ free(strings);
return;
+ }
- nsyms = symtab.sh_size / sizeof(struct elf_sym);
+ i = shdr[sym_idx].sh_size;
+ syms = malloc(i);
+ if (!syms || pread(fd, syms, i, shdr[sym_idx].sh_offset) != i) {
+ free(s);
+ free(strings);
+ free(syms);
+ return;
+ }
- i = 0;
- while (i < nsyms) {
+ nsyms = i / sizeof(struct elf_sym);
+ for (i = 0; i < nsyms; ) {
bswap_sym(syms + i);
- // Throw away entries which we do not need.
- if (syms[i].st_shndx == SHN_UNDEF ||
- syms[i].st_shndx >= SHN_LORESERVE ||
- ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
- nsyms--;
- if (i < nsyms) {
+ /* Throw away entries which we do not need. */
+ if (syms[i].st_shndx == SHN_UNDEF
+ || syms[i].st_shndx >= SHN_LORESERVE
+ || ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
+ if (i < --nsyms) {
syms[i] = syms[nsyms];
}
- continue;
- }
+ } else {
#if defined(TARGET_ARM) || defined (TARGET_MIPS)
- /* The bottom address bit marks a Thumb or MIPS16 symbol. */
- syms[i].st_value &= ~(target_ulong)1;
+ /* The bottom address bit marks a Thumb or MIPS16 symbol. */
+ syms[i].st_value &= ~(target_ulong)1;
#endif
- i++;
+ syms[i].st_value += load_bias;
+ i++;
+ }
}
- syms = realloc(syms, nsyms * sizeof(*syms));
+ syms = realloc(syms, nsyms * sizeof(*syms));
qsort(syms, nsyms, sizeof(*syms), symcmp);
- lseek(fd, strtab.sh_offset, SEEK_SET);
- if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
- return;
s->disas_num_syms = nsyms;
#if ELF_CLASS == ELFCLASS32
s->disas_symtab.elf32 = syms;
- s->lookup_symbol = lookup_symbolxx;
#else
s->disas_symtab.elf64 = syms;
- s->lookup_symbol = lookup_symbolxx;
#endif
+ s->lookup_symbol = lookup_symbolxx;
s->next = syminfos;
syminfos = s;
}
@@ -1769,8 +1781,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
free(elf_phdata);
- if (qemu_log_enabled())
- load_symbols(&elf_ex, bprm->fd);
+ if (qemu_log_enabled()) {
+ load_symbols(&elf_ex, bprm->fd, load_bias);
+ }
if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
--
1.7.0.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 08/12] linux-user: Improve consistency checking in elf headers.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (22 preceding siblings ...)
2010-05-05 18:07 ` [Qemu-devel] [PATCH 07/12] linux-user: Load symbols from the interpreter Richard Henderson
@ 2010-05-05 18:07 ` Richard Henderson
2010-05-05 18:07 ` [Qemu-devel] [PATCH 09/12] linux-user: Put the stack guard page at the top Richard Henderson
` (3 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-05-05 18:07 UTC (permalink / raw)
To: qemu-devel; +Cc: paul
Validate more fields of the elf header. Extract those checks
into two common functions to be used in both load_elf_interp
and load_elf_binary.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 57 +++++++++++++++++++++++++++++---------------------
1 files changed, 33 insertions(+), 24 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 723e956..fb03687 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -901,6 +901,30 @@ static int elf_core_dump(int, const CPUState *);
#endif /* USE_ELF_CORE_DUMP */
static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias);
+/* Verify the portions of EHDR within E_IDENT for the target.
+ This can be performed before bswapping the entire header. */
+static _Bool elf_check_ident(struct elfhdr *ehdr)
+{
+ return (ehdr->e_ident[EI_MAG0] == ELFMAG0
+ && ehdr->e_ident[EI_MAG1] == ELFMAG1
+ && ehdr->e_ident[EI_MAG2] == ELFMAG2
+ && ehdr->e_ident[EI_MAG3] == ELFMAG3
+ && ehdr->e_ident[EI_CLASS] == ELF_CLASS
+ && ehdr->e_ident[EI_DATA] == ELF_DATA
+ && ehdr->e_ident[EI_VERSION] == EV_CURRENT);
+}
+
+/* Verify the portions of EHDR outside of E_IDENT for the target.
+ This has to wait until after bswapping the header. */
+static _Bool elf_check_ehdr(struct elfhdr *ehdr)
+{
+ return (elf_check_arch(ehdr->e_machine)
+ && ehdr->e_ehsize == sizeof(struct elfhdr)
+ && ehdr->e_phentsize == sizeof(struct elf_phdr)
+ && ehdr->e_shentsize == sizeof(struct elf_shdr)
+ && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));
+}
+
/*
* 'copy_elf_strings()' copies argument/envelope strings from user
* memory to free pages in kernel mem. These are in a format ready
@@ -1131,33 +1155,16 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
int i;
bswap_ehdr(interp_elf_ex);
- /* First of all, some simple consistency checks */
- if ((interp_elf_ex->e_type != ET_EXEC &&
- interp_elf_ex->e_type != ET_DYN) ||
- !elf_check_arch(interp_elf_ex->e_machine)) {
+ if (!elf_check_ehdr(interp_elf_ex)) {
return ~((abi_ulong)0UL);
}
/* Now read in all of the header information */
-
- if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
- return ~(abi_ulong)0UL;
-
elf_phdata = (struct elf_phdr *)
malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
-
if (!elf_phdata)
return ~((abi_ulong)0UL);
- /*
- * If the size of this structure has changed, then punt, since
- * we will be doing the wrong thing.
- */
- if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
- free(elf_phdata);
- return ~((abi_ulong)0UL);
- }
-
i = interp_elf_ex->e_phnum * sizeof(struct elf_phdr);
if (interp_elf_ex->e_phoff + i <= BPRM_BUF_SIZE) {
memcpy(elf_phdata, bprm_buf + interp_elf_ex->e_phoff, i);
@@ -1409,11 +1416,13 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
load_addr = 0;
load_bias = 0;
elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
- bswap_ehdr(&elf_ex);
/* First of all, some simple consistency checks */
- if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
- (! elf_check_arch(elf_ex.e_machine))) {
+ if (!elf_check_ident(&elf_ex)) {
+ return -ENOEXEC;
+ }
+ bswap_ehdr(&elf_ex);
+ if (!elf_check_ehdr(&elf_ex)) {
return -ENOEXEC;
}
@@ -1425,7 +1434,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
}
/* Now read in all of the header information */
- elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
+ elf_phdata = (struct elf_phdr *)
+ malloc(elf_ex.e_phnum * sizeof(struct elf_phdr));
if (elf_phdata == NULL) {
return -ENOMEM;
}
@@ -1530,8 +1540,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
interpreter_type = INTERPRETER_ELF;
}
- if (interp_elf_ex.e_ident[0] != 0x7f ||
- strncmp((char *)&interp_elf_ex.e_ident[1], "ELF",3) != 0) {
+ if (!elf_check_ident(&interp_elf_ex)) {
interpreter_type &= ~INTERPRETER_ELF;
}
--
1.7.0.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 09/12] linux-user: Put the stack guard page at the top.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (23 preceding siblings ...)
2010-05-05 18:07 ` [Qemu-devel] [PATCH 08/12] linux-user: Improve consistency checking in elf headers Richard Henderson
@ 2010-05-05 18:07 ` Richard Henderson
2010-05-05 18:07 ` [Qemu-devel] [PATCH 10/12] linux-user: Remove partial support for a.out interpreters Richard Henderson
` (2 subsequent siblings)
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-05-05 18:07 UTC (permalink / raw)
To: qemu-devel; +Cc: paul
There are no supported stack-grows-up targets. We were putting
the guard page at the highest address, i.e. the bottom of the stack.
Use the maximum of host and guest page size for the guard size.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 29 ++++++++++++++++-------------
1 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index fb03687..bd4b8fc 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -984,28 +984,31 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
struct image_info *info)
{
- abi_ulong stack_base, size, error;
+ abi_ulong stack_base, size, error, guard;
int i;
/* Create enough stack to hold everything. If we don't use
- * it for args, we'll use it for something else...
- */
+ it for args, we'll use it for something else. */
size = guest_stack_size;
- if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
+ if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) {
size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
- error = target_mmap(0,
- size + qemu_host_page_size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- -1, 0);
+ }
+ guard = TARGET_PAGE_SIZE;
+ if (guard < qemu_real_host_page_size) {
+ guard = qemu_real_host_page_size;
+ }
+
+ error = target_mmap(0, size + guard, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (error == -1) {
- perror("stk mmap");
+ perror("mmap stack");
exit(-1);
}
- /* we reserve one extra page at the top of the stack as guard */
- target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
- stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
+ /* We reserve one extra page at the top of the stack as guard. */
+ target_mprotect(error, guard, PROT_NONE);
+
+ stack_base = error + guard + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
p += stack_base;
for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
--
1.7.0.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 10/12] linux-user: Remove partial support for a.out interpreters.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (24 preceding siblings ...)
2010-05-05 18:07 ` [Qemu-devel] [PATCH 09/12] linux-user: Put the stack guard page at the top Richard Henderson
@ 2010-05-05 18:07 ` Richard Henderson
2010-05-05 18:07 ` [Qemu-devel] [PATCH 11/12] linux-user: Extract load_elf_image from load_elf_interp Richard Henderson
2010-05-05 18:07 ` [Qemu-devel] [PATCH 12/12] linux-user: Re-use load_elf_image for the main binary Richard Henderson
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-05-05 18:07 UTC (permalink / raw)
To: qemu-devel; +Cc: paul
At the bottom of the a.out support was the unimplemented load_aout_interp
function. There were other portions of the support that didn't look
right; when I went to look in the Linux kernel for clarification, I found
that the support for such interpreters has been removed from binfmt_elf.
There doesn't seem to be any reason to keep this broken support in qemu.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 79 ++++++--------------------------------------------
1 files changed, 9 insertions(+), 70 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index bd4b8fc..77267a4 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -819,10 +819,6 @@ struct exec
#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 12
static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
@@ -830,8 +826,6 @@ static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
memcpy(to, from, n);
}
-static int load_aout_interp(void * exptr, int interp_fd);
-
#ifdef BSWAP_NEEDED
static void bswap_ehdr(struct elfhdr *ehdr)
{
@@ -1069,7 +1063,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
struct elfhdr * exec,
abi_ulong load_addr,
abi_ulong load_bias,
- abi_ulong interp_load_addr, int ibcs,
+ abi_ulong interp_load_addr,
struct image_info *info)
{
abi_ulong sp;
@@ -1099,7 +1093,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
size += DLINFO_ARCH_ITEMS * 2;
#endif
size += envc + argc + 2;
- size += (!ibcs ? 3 : 1); /* argc itself */
+ size += 1; /* argc itself */
size *= n;
if (size & 15)
sp -= 16 - (size & 15);
@@ -1141,7 +1135,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
info->saved_auxv = sp;
- sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
+ sp = loader_build_argptr(envc, argc, sp, p, 0);
return sp;
}
@@ -1394,11 +1388,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
{
struct elfhdr elf_ex;
struct elfhdr interp_elf_ex;
- struct exec interp_ex;
int interpreter_fd = -1; /* avoid warning */
abi_ulong load_addr, load_bias;
int load_addr_set = 0;
- unsigned int interpreter_type = INTERPRETER_NONE;
unsigned char ibcs2_interpreter;
int i;
abi_ulong mapped_addr;
@@ -1412,7 +1404,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
abi_ulong start_code, end_code, start_data, end_data;
abi_ulong reloc_func_desc = 0;
abi_ulong elf_stack;
- char passed_fileno[6];
ibcs2_interpreter = 0;
status = 0;
@@ -1462,7 +1453,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
end_code = 0;
start_data = 0;
end_data = 0;
- interp_ex.a_info = 0;
elf_ppnt = elf_phdata;
for(i=0;i < elf_ex.e_phnum; i++) {
@@ -1527,59 +1517,22 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
memset(bprm->buf, 0, BPRM_BUF_SIZE - retval);
}
- interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
- interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */
+ interp_elf_ex = *((struct elfhdr *) bprm->buf);
}
elf_ppnt++;
}
/* Some simple consistency checks for the interpreter */
- if (elf_interpreter){
- interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
-
- /* Now figure out which format our binary is */
- if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
- (N_MAGIC(interp_ex) != QMAGIC)) {
- interpreter_type = INTERPRETER_ELF;
- }
-
+ if (elf_interpreter) {
if (!elf_check_ident(&interp_elf_ex)) {
- interpreter_type &= ~INTERPRETER_ELF;
- }
-
- if (!interpreter_type) {
free(elf_interpreter);
free(elf_phdata);
close(bprm->fd);
+ close(interpreter_fd);
return -ELIBBAD;
}
}
- /* OK, we are done with that, now set up the arg stuff,
- and then start this sucker up */
-
- {
- char * passed_p;
-
- if (interpreter_type == INTERPRETER_AOUT) {
- snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
- passed_p = passed_fileno;
-
- if (elf_interpreter) {
- bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p);
- bprm->argc++;
- }
- }
- if (!bprm->p) {
- if (elf_interpreter) {
- free(elf_interpreter);
- }
- free (elf_phdata);
- close(bprm->fd);
- return -E2BIG;
- }
- }
-
/* OK, This is the point of no return */
info->end_data = 0;
info->end_code = 0;
@@ -1772,15 +1725,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
end_data += load_bias;
if (elf_interpreter) {
- if (interpreter_type & 1) {
- elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
- } else if (interpreter_type & 2) {
- elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
- &interp_load_addr, bprm->buf);
- }
+ elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
+ &interp_load_addr, bprm->buf);
reloc_func_desc = interp_load_addr;
-
- close(interpreter_fd);
free(elf_interpreter);
if (elf_entry == ~((abi_ulong)0UL)) {
@@ -1797,7 +1744,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
load_symbols(&elf_ex, bprm->fd, load_bias);
}
- if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
+ close(bprm->fd);
info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
#ifdef LOW_ELF_STACK
@@ -1809,7 +1756,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
&elf_ex,
load_addr, load_bias,
interp_load_addr,
- (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
info);
info->load_addr = reloc_func_desc;
info->start_brk = info->brk = elf_brk;
@@ -2692,15 +2638,8 @@ static int elf_core_dump(int signr, const CPUState *env)
return (-errno);
return (0);
}
-
#endif /* USE_ELF_CORE_DUMP */
-static int load_aout_interp(void * exptr, int interp_fd)
-{
- printf("a.out interpreter not yet supported\n");
- return(0);
-}
-
void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
{
init_thread(regs, infop);
--
1.7.0.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 11/12] linux-user: Extract load_elf_image from load_elf_interp.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (25 preceding siblings ...)
2010-05-05 18:07 ` [Qemu-devel] [PATCH 10/12] linux-user: Remove partial support for a.out interpreters Richard Henderson
@ 2010-05-05 18:07 ` Richard Henderson
2010-05-05 18:07 ` [Qemu-devel] [PATCH 12/12] linux-user: Re-use load_elf_image for the main binary Richard Henderson
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-05-05 18:07 UTC (permalink / raw)
To: qemu-devel; +Cc: paul
Moving toward a single copy of the elf binary loading code.
Fill in the details of the loaded image into a struct image_info.
Adjust create_elf_tables to read from such structures instead
of from a collection of passed arguments. Don't return error
values from load_elf_interp; always exit(-1) with a message to
stderr. Collect elf_interpreter handling in load_elf_binary
to a common spot.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/elfload.c | 341 ++++++++++++++++++++++++-------------------------
1 files changed, 167 insertions(+), 174 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 77267a4..0167414 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1060,11 +1060,9 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
}
static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
- struct elfhdr * exec,
- abi_ulong load_addr,
- abi_ulong load_bias,
- abi_ulong interp_load_addr,
- struct image_info *info)
+ struct elfhdr *exec,
+ struct image_info *info,
+ struct image_info *interp_info)
{
abi_ulong sp;
int size;
@@ -1109,13 +1107,13 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
NEW_AUX_ENT (AT_NULL, 0);
/* There must be exactly DLINFO_ITEMS entries here. */
- NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
+ NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff));
NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
- NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
+ NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info->load_addr));
NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
- NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
+ NEW_AUX_ENT(AT_ENTRY, info->entry);
NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
@@ -1139,51 +1137,60 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
return sp;
}
+/* Load an ELF image into the address space.
-static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
- int interpreter_fd,
- abi_ulong *interp_load_addr,
- char bprm_buf[BPRM_BUF_SIZE])
+ IMAGE_NAME is the filename of the image, to use in error messages.
+ IMAGE_FD is the open file descriptor for the image.
+
+ BPRM_BUF is a copy of the beginning of the file; this of course
+ contains the elf file header at offset 0. It is assumed that this
+ buffer is sufficiently aligned to present no problems to the host
+ in accessing data at aligned offsets within the buffer.
+
+ 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,
+ char bprm_buf[BPRM_BUF_SIZE])
{
- struct elf_phdr *elf_phdata = NULL;
- abi_ulong load_addr, load_bias, loaddr, hiaddr;
- int retval;
- abi_ulong error;
- int i;
+ struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
+ struct elf_phdr *phdr;
+ abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
+ int i, retval;
+ const char *errmsg;
- bswap_ehdr(interp_elf_ex);
- if (!elf_check_ehdr(interp_elf_ex)) {
- return ~((abi_ulong)0UL);
+ /* First of all, some simple consistency checks */
+ errmsg = "Invalid ELF image for this architecture";
+ if (!elf_check_ident(ehdr)) {
+ goto exit_errmsg;
+ }
+ bswap_ehdr(ehdr);
+ if (!elf_check_ehdr(ehdr)) {
+ goto exit_errmsg;
}
- /* Now read in all of the header information */
- elf_phdata = (struct elf_phdr *)
- malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
- if (!elf_phdata)
- return ~((abi_ulong)0UL);
-
- i = interp_elf_ex->e_phnum * sizeof(struct elf_phdr);
- if (interp_elf_ex->e_phoff + i <= BPRM_BUF_SIZE) {
- memcpy(elf_phdata, bprm_buf + interp_elf_ex->e_phoff, i);
+ i = ehdr->e_phnum * sizeof(struct elf_phdr);
+ if (ehdr->e_phoff + i <= BPRM_BUF_SIZE) {
+ phdr = (struct elf_phdr *)(bprm_buf + ehdr->e_phoff);
} else {
- retval = pread(interpreter_fd, elf_phdata, i, interp_elf_ex->e_phoff);
+ phdr = (struct elf_phdr *) alloca(i);
+ retval = pread(image_fd, phdr, i, ehdr->e_phoff);
if (retval != i) {
- perror("load_elf_interp");
- exit(-1);
+ goto exit_read;
}
}
- bswap_phdr(elf_phdata, interp_elf_ex->e_phnum);
+ bswap_phdr(phdr, ehdr->e_phnum);
/* Find the maximum size of the image and allocate an appropriate
amount of memory to handle that. */
loaddr = -1, hiaddr = 0;
- for (i = 0; i < interp_elf_ex->e_phnum; ++i) {
- if (elf_phdata[i].p_type == PT_LOAD) {
- abi_ulong a = elf_phdata[i].p_vaddr;
+ for (i = 0; i < ehdr->e_phnum; ++i) {
+ if (phdr[i].p_type == PT_LOAD) {
+ abi_ulong a = phdr[i].p_vaddr;
if (a < loaddr) {
loaddr = a;
}
- a += elf_phdata[i].p_memsz;
+ a += phdr[i].p_memsz;
if (a > hiaddr) {
hiaddr = a;
}
@@ -1191,7 +1198,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
}
load_addr = loaddr;
- if (interp_elf_ex->e_type == ET_DYN) {
+ if (ehdr->e_type == ET_DYN) {
/* The image indicates that it can be loaded anywhere. Find a
location that can hold the memory space required. If the
image is pre-linked, LOADDR will be non-zero. Since we do
@@ -1201,14 +1208,22 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
-1, 0);
if (load_addr == -1) {
- perror("mmap");
- exit(-1);
+ goto exit_perror;
}
}
load_bias = load_addr - loaddr;
- for (i = 0; i < interp_elf_ex->e_phnum; i++) {
- struct elf_phdr *eppnt = elf_phdata + i;
+ info->load_bias = load_bias;
+ info->load_addr = load_addr;
+ info->entry = ehdr->e_entry + load_bias;
+ info->start_code = -1;
+ info->end_code = 0;
+ info->start_data = -1;
+ info->end_data = 0;
+ info->brk = 0;
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ struct elf_phdr *eppnt = phdr + i;
if (eppnt->p_type == PT_LOAD) {
abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em;
int elf_prot = 0;
@@ -1223,12 +1238,9 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
elf_prot, MAP_PRIVATE | MAP_FIXED,
- interpreter_fd, eppnt->p_offset - vaddr_po);
+ image_fd, eppnt->p_offset - vaddr_po);
if (error == -1) {
- /* Real error */
- close(interpreter_fd);
- free(elf_phdata);
- return ~((abi_ulong)0UL);
+ goto exit_perror;
}
vaddr_ef = vaddr + eppnt->p_filesz;
@@ -1238,18 +1250,79 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
if (vaddr_ef < vaddr_em) {
zero_bss(vaddr_ef, vaddr_em, elf_prot);
}
+
+ /* Find the full program boundaries. */
+ if (elf_prot & PROT_EXEC) {
+ if (vaddr < info->start_code) {
+ info->start_code = vaddr;
+ }
+ if (vaddr_ef > info->end_code) {
+ info->end_code = vaddr_ef;
+ }
+ }
+ if (elf_prot & PROT_WRITE) {
+ if (vaddr < info->start_data) {
+ info->start_data = vaddr;
+ }
+ if (vaddr_ef > info->end_data) {
+ info->end_data = vaddr_ef;
+ }
+ if (vaddr_em > info->brk) {
+ info->brk = vaddr_em;
+ }
+ }
}
}
+ if (info->end_data == 0) {
+ info->start_data = info->end_code;
+ info->end_data = info->end_code;
+ info->brk = info->end_code;
+ }
+
if (qemu_log_enabled()) {
- load_symbols(interp_elf_ex, interpreter_fd, load_bias);
+ load_symbols(ehdr, image_fd, load_bias);
}
- close(interpreter_fd);
- free(elf_phdata);
+ close(image_fd);
+ return;
+
+ exit_read:
+ if (retval >= 0) {
+ errmsg = "Incomplete read of file header";
+ goto exit_errmsg;
+ }
+ exit_perror:
+ errmsg = strerror(errno);
+ exit_errmsg:
+ fprintf(stderr, "%s: %s\n", image_name, errmsg);
+ exit(-1);
+}
+
+static void load_elf_interp(const char *filename, struct image_info *info,
+ char bprm_buf[BPRM_BUF_SIZE])
+{
+ int fd, retval;
+
+ fd = open(path(filename), O_RDONLY);
+ if (fd < 0) {
+ goto exit_perror;
+ }
+
+ retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
+ if (retval < 0) {
+ goto exit_perror;
+ }
+ if (retval < BPRM_BUF_SIZE) {
+ memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
+ }
+
+ load_elf_image(filename, fd, info, bprm_buf);
+ return;
- *interp_load_addr = load_addr;
- return ((abi_ulong) interp_elf_ex->e_entry) + load_bias;
+ exit_perror:
+ fprintf(stderr, "%s: %s\n", filename, strerror(errno));
+ exit(-1);
}
static int symfind(const void *s0, const void *s1)
@@ -1386,26 +1459,21 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
struct image_info * info)
{
+ struct image_info interp_info;
struct elfhdr elf_ex;
- struct elfhdr interp_elf_ex;
- int interpreter_fd = -1; /* avoid warning */
abi_ulong load_addr, load_bias;
int load_addr_set = 0;
- unsigned char ibcs2_interpreter;
int i;
- abi_ulong mapped_addr;
struct elf_phdr * elf_ppnt;
struct elf_phdr *elf_phdata;
abi_ulong k, elf_brk;
int retval;
- char * elf_interpreter;
- abi_ulong elf_entry, interp_load_addr = 0;
+ char *elf_interpreter = NULL;
+ abi_ulong elf_entry;
int status;
abi_ulong start_code, end_code, start_data, end_data;
- abi_ulong reloc_func_desc = 0;
abi_ulong elf_stack;
- ibcs2_interpreter = 0;
status = 0;
load_addr = 0;
load_bias = 0;
@@ -1448,7 +1516,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
elf_brk = 0;
elf_stack = ~((abi_ulong)0UL);
- elf_interpreter = NULL;
start_code = ~((abi_ulong)0UL);
end_code = 0;
start_data = 0;
@@ -1457,82 +1524,21 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
elf_ppnt = elf_phdata;
for(i=0;i < elf_ex.e_phnum; i++) {
if (elf_ppnt->p_type == PT_INTERP) {
- if ( elf_interpreter != NULL )
- {
- free (elf_phdata);
- free(elf_interpreter);
- close(bprm->fd);
- return -EINVAL;
- }
-
- /* This is the program interpreter used for
- * shared libraries - for now assume that this
- * is an a.out format binary
- */
-
- elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
-
- if (elf_interpreter == NULL) {
- free (elf_phdata);
- close(bprm->fd);
- return -ENOMEM;
- }
-
if (elf_ppnt->p_offset + elf_ppnt->p_filesz <= BPRM_BUF_SIZE) {
- memcpy(elf_interpreter, bprm->buf + elf_ppnt->p_offset,
- elf_ppnt->p_filesz);
+ 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_binary2");
+ perror("load_elf_binary");
exit(-1);
}
}
-
- /* If the program interpreter is one of these two,
- then assume an iBCS2 image. Otherwise assume
- a native linux image. */
-
- /* JRP - Need to add X86 lib dir stuff here... */
-
- if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
- strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
- ibcs2_interpreter = 1;
- }
-
- retval = open(path(elf_interpreter), O_RDONLY);
- if (retval < 0) {
- perror(elf_interpreter);
- exit(-1);
- }
- interpreter_fd = retval;
-
- retval = read(interpreter_fd, bprm->buf, BPRM_BUF_SIZE);
- if (retval < 0) {
- perror("load_elf_binary3");
- exit(-1);
- }
- if (retval < BPRM_BUF_SIZE) {
- memset(bprm->buf, 0, BPRM_BUF_SIZE - retval);
- }
-
- interp_elf_ex = *((struct elfhdr *) bprm->buf);
}
elf_ppnt++;
}
- /* Some simple consistency checks for the interpreter */
- if (elf_interpreter) {
- if (!elf_check_ident(&interp_elf_ex)) {
- free(elf_interpreter);
- free(elf_phdata);
- close(bprm->fd);
- close(interpreter_fd);
- return -ELIBBAD;
- }
- }
-
/* OK, This is the point of no return */
info->end_data = 0;
info->end_code = 0;
@@ -1691,7 +1697,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
load_bias += error -
TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
load_addr += load_bias;
- reloc_func_desc = load_bias;
}
}
k = elf_ppnt->p_vaddr;
@@ -1724,19 +1729,15 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
start_data += load_bias;
end_data += load_bias;
- if (elf_interpreter) {
- elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
- &interp_load_addr, bprm->buf);
- reloc_func_desc = interp_load_addr;
- free(elf_interpreter);
-
- if (elf_entry == ~((abi_ulong)0UL)) {
- printf("Unable to load interpreter\n");
- free(elf_phdata);
- exit(-1);
- return 0;
- }
- }
+ 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);
@@ -1745,46 +1746,38 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
}
close(bprm->fd);
- info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
-#ifdef LOW_ELF_STACK
- info->start_stack = bprm->p = elf_stack - 4;
-#endif
- bprm->p = create_elf_tables(bprm->p,
- bprm->argc,
- bprm->envc,
- &elf_ex,
- load_addr, load_bias,
- interp_load_addr,
- info);
- info->load_addr = reloc_func_desc;
- 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->start_stack = bprm->p;
+ if (elf_interpreter) {
+ load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
-#if 0
- printf("(start_brk) %x\n" , info->start_brk);
- printf("(end_code) %x\n" , info->end_code);
- printf("(start_code) %x\n" , info->start_code);
- printf("(end_data) %x\n" , info->end_data);
- printf("(start_stack) %x\n" , info->start_stack);
- printf("(brk) %x\n" , info->brk);
-#endif
+ /* If the program interpreter is one of these two, then assume
+ an iBCS2 image. Otherwise assume a native linux image. */
+
+ if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0
+ || strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) {
+ info->personality = PER_SVR4;
- if ( info->personality == PER_SVR4 )
- {
- /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
- and some applications "depend" upon this behavior.
- Since we do not have the power to recompile these, we
- emulate the SVr4 behavior. Sigh. */
- mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE, -1, 0);
+ /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
+ and some applications "depend" upon this behavior. Since
+ we do not have the power to recompile these, we emulate
+ the SVr4 behavior. Sigh. */
+ target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE, -1, 0);
+ }
}
- info->entry = elf_entry;
+ bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &elf_ex,
+ info, (elf_interpreter ? &interp_info : NULL));
+ info->start_stack = bprm->p;
+
+ /* If we have an interpreter, set that as the program's entry point.
+ Copy the load_addr as well, to help PPC64 interpret the entry
+ point as a function descriptor. Do this after creating elf tables
+ so that we copy the original program entry point into the AUXV. */
+ if (elf_interpreter) {
+ info->load_addr = interp_info.load_addr;
+ info->entry = interp_info.entry;
+ }
#ifdef USE_ELF_CORE_DUMP
bprm->core_dump = &elf_core_dump;
--
1.7.0.1
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [Qemu-devel] [PATCH 12/12] linux-user: Re-use load_elf_image for the main binary.
2010-04-05 16:47 [Qemu-devel] [PATCH 00/14] Implement VDSO for x86_64-linux-user Richard Henderson
` (26 preceding siblings ...)
2010-05-05 18:07 ` [Qemu-devel] [PATCH 11/12] linux-user: Extract load_elf_image from load_elf_interp Richard Henderson
@ 2010-05-05 18:07 ` Richard Henderson
27 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2010-05-05 18:07 UTC (permalink / raw)
To: qemu-devel; +Cc: paul
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 <rth@twiddle.net>
---
linux-user/elfload.c | 380 ++++++++++++++------------------------------------
1 files changed, 103 insertions(+), 277 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 0167414..d435564 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -811,9 +811,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))
@@ -1150,7 +1147,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;
@@ -1210,6 +1207,67 @@ 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 or the
+ QEMU application itself. */
+#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) {
+ unsigned long host_start, real_start, host_size;
+
+ /* Round addresses to page boundaries. */
+ loaddr &= qemu_host_page_mask;
+ hiaddr = HOST_PAGE_ALIGN(hiaddr);
+
+ if (loaddr < mmap_min_addr) {
+ host_start = HOST_PAGE_ALIGN(mmap_min_addr);
+ } else {
+ host_start = loaddr;
+ if (host_start != loaddr) {
+ errmsg = "Address overflow loading ELF binary";
+ goto exit_errmsg;
+ }
+ }
+ host_size = hiaddr - loaddr;
+ while (1) {
+ /* Do not use mmap_find_vma here because that is limited to the
+ guest address space. We are going to make the
+ guest address space fit whatever we're given. */
+ real_start = (unsigned long)
+ mmap((void *)host_start, host_size, PROT_NONE,
+ MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
+ if (real_start == (unsigned long)-1) {
+ goto exit_perror;
+ }
+ if (real_start == host_start) {
+ break;
+ }
+ /* That address didn't work. Unmap and try a different one.
+ The address the host picked because is typically right at
+ the top of the host address space and leaves the guest with
+ no usable address space. Resort to a linear search. We
+ already compensated for mmap_min_addr, so this should not
+ happen often. Probably means we got unlucky and host
+ address space randomization put a shared library somewhere
+ inconvenient. */
+ munmap((void *)real_start, host_size);
+ host_start += qemu_host_page_size;
+ if (host_start == loaddr) {
+ /* Theoretically possible if host doesn't have any suitably
+ aligned areas. Normally the first mmap will fail. */
+ errmsg = "Unable to find space for application";
+ goto exit_errmsg;
+ }
+ }
+ qemu_log("Relocating guest address space from 0x"
+ TARGET_ABI_FMT_lx " to 0x%lx\n", loaddr, real_start);
+ guest_base = real_start - loaddr;
+ }
+#endif
}
load_bias = load_addr - loaddr;
@@ -1271,6 +1329,33 @@ 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);
+ if (!interp_name) {
+ goto exit_perror;
+ }
+
+ 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,
+ 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;
}
}
@@ -1317,7 +1402,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:
@@ -1461,291 +1546,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;
- /* 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;
- }
+ load_elf_image(bprm->filename, bprm->fd, info,
+ &elf_interpreter, bprm->buf);
+
+ /* ??? 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 the address
- * range used by loadable segments. Check that this is available on
- * the host, and if not find a suitable value for guest_base. */
- abi_ulong app_start = ~0;
- abi_ulong app_end = 0;
- abi_ulong addr;
- unsigned long host_start;
- unsigned long real_start;
- unsigned long host_size;
- for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum;
- i++, elf_ppnt++) {
- if (elf_ppnt->p_type != PT_LOAD)
- continue;
- addr = elf_ppnt->p_vaddr;
- if (addr < app_start) {
- app_start = addr;
- }
- addr += elf_ppnt->p_memsz;
- if (addr > app_end) {
- app_end = addr;
- }
- }
-
- /* If we don't have any loadable segments then something
- is very wrong. */
- assert(app_start < app_end);
-
- /* Round addresses to page boundaries. */
- app_start = app_start & qemu_host_page_mask;
- app_end = HOST_PAGE_ALIGN(app_end);
- if (app_start < mmap_min_addr) {
- host_start = HOST_PAGE_ALIGN(mmap_min_addr);
- } else {
- host_start = app_start;
- if (host_start != app_start) {
- fprintf(stderr, "qemu: Address overflow loading ELF binary\n");
- abort();
- }
- }
- host_size = app_end - app_start;
- while (1) {
- /* Do not use mmap_find_vma here because that is limited to the
- guest address space. We are going to make the
- guest address space fit whatever we're given. */
- real_start = (unsigned long)mmap((void *)host_start, host_size,
- PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
- if (real_start == (unsigned long)-1) {
- fprintf(stderr, "qemu: Virtual memory exausted\n");
- abort();
- }
- if (real_start == host_start) {
- break;
- }
- /* That address didn't work. Unmap and try a different one.
- The address the host picked because is typically
- right at the top of the host address space and leaves the
- guest with no usable address space. Resort to a linear search.
- We already compensated for mmap_min_addr, so this should not
- happen often. Probably means we got unlucky and host address
- space randomization put a shared library somewhere
- inconvenient. */
- munmap((void *)real_start, host_size);
- host_start += qemu_host_page_size;
- if (host_start == app_start) {
- /* Theoretically possible if host doesn't have any
- suitably aligned areas. Normally the first mmap will
- fail. */
- fprintf(stderr, "qemu: Unable to find space for application\n");
- abort();
- }
- }
- qemu_log("Relocating guest address space from 0x" TARGET_ABI_FMT_lx
- " to 0x%lx\n", app_start, real_start);
- guest_base = real_start - app_start;
+ 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);
@@ -1777,6 +1602,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
--
1.7.0.1
^ permalink raw reply related [flat|nested] 46+ messages in thread