summaryrefslogtreecommitdiff
path: root/linux-user/elfload.c
diff options
context:
space:
mode:
authorRichard Henderson <rth@twiddle.net>2010-07-27 10:25:30 -0700
committerEdgar E. Iglesias <edgar.iglesias@gmail.com>2010-07-29 08:32:28 +0200
commit9955ffac9a31aad346fe7f0fcefebe88da7f9df5 (patch)
tree6717fb9286c007302a39846fd6ecb4be088c0f18 /linux-user/elfload.c
parentd97ef72eed202460a13dfe4a92fd95ac9e6ddf11 (diff)
downloadqemu-9955ffac9a31aad346fe7f0fcefebe88da7f9df5.tar.gz
linux-user: Reduce lseek+reads while loading elf files.
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> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Diffstat (limited to 'linux-user/elfload.c')
-rw-r--r--linux-user/elfload.c104
1 files changed, 44 insertions, 60 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 6ea1e8db02..4a48c85720 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1159,7 +1159,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;
@@ -1202,17 +1203,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;
@@ -1470,17 +1469,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
@@ -1524,13 +1521,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,
@@ -1544,39 +1544,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++;
}
@@ -1823,10 +1808,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;