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>
This commit is contained in:
Richard Henderson 2010-07-27 10:25:30 -07:00 committed by Edgar E. Iglesias
parent d97ef72eed
commit 9955ffac9a
3 changed files with 57 additions and 71 deletions

View File

@ -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, static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
int interpreter_fd, 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 *elf_phdata = NULL;
struct elf_phdr *eppnt; struct elf_phdr *eppnt;
@ -1202,17 +1203,15 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
return ~((abi_ulong)0UL); return ~((abi_ulong)0UL);
} }
retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); i = interp_elf_ex->e_phnum * sizeof(struct elf_phdr);
if(retval >= 0) { if (interp_elf_ex->e_phoff + i <= BPRM_BUF_SIZE) {
retval = read(interpreter_fd, memcpy(elf_phdata, bprm_buf + interp_elf_ex->e_phoff, i);
(char *) elf_phdata, } else {
sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); retval = pread(interpreter_fd, elf_phdata, i, interp_elf_ex->e_phoff);
} if (retval != i) {
if (retval < 0) { perror("load_elf_interp");
perror("load_elf_interp"); exit(-1);
exit(-1); }
free (elf_phdata);
return retval;
} }
#ifdef BSWAP_NEEDED #ifdef BSWAP_NEEDED
eppnt = elf_phdata; eppnt = elf_phdata;
@ -1470,17 +1469,15 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
return -ENOMEM; return -ENOMEM;
} }
retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); i = elf_ex.e_phnum * sizeof(struct elf_phdr);
if(retval > 0) { if (elf_ex.e_phoff + i <= BPRM_BUF_SIZE) {
retval = read(bprm->fd, (char *) elf_phdata, memcpy(elf_phdata, bprm->buf + elf_ex.e_phoff, i);
elf_ex.e_phentsize * elf_ex.e_phnum); } else {
} retval = pread(bprm->fd, (char *) elf_phdata, i, elf_ex.e_phoff);
if (retval != i) {
if (retval < 0) { perror("load_elf_binary");
perror("load_elf_binary"); exit(-1);
exit(-1); }
free (elf_phdata);
return -errno;
} }
#ifdef BSWAP_NEEDED #ifdef BSWAP_NEEDED
@ -1524,13 +1521,16 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
return -ENOMEM; return -ENOMEM;
} }
retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); if (elf_ppnt->p_offset + elf_ppnt->p_filesz <= BPRM_BUF_SIZE) {
if(retval >= 0) { memcpy(elf_interpreter, bprm->buf + elf_ppnt->p_offset,
retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz); elf_ppnt->p_filesz);
} } else {
if(retval < 0) { retval = pread(bprm->fd, elf_interpreter, elf_ppnt->p_filesz,
perror("load_elf_binary2"); elf_ppnt->p_offset);
exit(-1); if (retval != elf_ppnt->p_filesz) {
perror("load_elf_binary2");
exit(-1);
}
} }
/* If the program interpreter is one of these two, /* 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; ibcs2_interpreter = 1;
} }
#if 0 retval = open(path(elf_interpreter), O_RDONLY);
printf("Using ELF interpreter %s\n", path(elf_interpreter)); if (retval < 0) {
#endif perror(elf_interpreter);
if (retval >= 0) { exit(-1);
retval = open(path(elf_interpreter), O_RDONLY);
if(retval >= 0) {
interpreter_fd = retval;
}
else {
perror(elf_interpreter);
exit(-1);
/* retval = -errno; */
}
} }
interpreter_fd = retval;
if (retval >= 0) { retval = read(interpreter_fd, bprm->buf, BPRM_BUF_SIZE);
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) { if (retval < 0) {
perror("load_elf_binary3"); perror("load_elf_binary3");
exit(-1); 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++; elf_ppnt++;
} }
@ -1823,10 +1808,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
if (elf_interpreter) { if (elf_interpreter) {
if (interpreter_type & 1) { if (interpreter_type & 1) {
elf_entry = load_aout_interp(&interp_ex, interpreter_fd); 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, elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
&interp_load_addr); &interp_load_addr, bprm->buf);
} }
reloc_func_desc = interp_load_addr; reloc_func_desc = interp_load_addr;

View File

@ -96,18 +96,16 @@ static int prepare_binprm(struct linux_binprm *bprm)
} }
} }
retval = lseek(bprm->fd, 0L, SEEK_SET); retval = read(bprm->fd, bprm->buf, BPRM_BUF_SIZE);
if(retval >= 0) { if (retval < 0) {
retval = read(bprm->fd, bprm->buf, 128);
}
if(retval < 0) {
perror("prepare_binprm"); perror("prepare_binprm");
exit(-1); exit(-1);
/* return(-errno); */
} }
else { if (retval < BPRM_BUF_SIZE) {
return(retval); /* 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. */ /* 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; int i;
bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ memset(bprm->page, 0, sizeof(bprm->page));
bprm->page[i] = NULL;
retval = open(filename, O_RDONLY); retval = open(filename, O_RDONLY);
if (retval < 0) if (retval < 0)
return retval; return retval;

View File

@ -31,6 +31,7 @@
* task_struct fields in the kernel * task_struct fields in the kernel
*/ */
struct image_info { struct image_info {
abi_ulong load_bias;
abi_ulong load_addr; abi_ulong load_addr;
abi_ulong start_code; abi_ulong start_code;
abi_ulong end_code; abi_ulong end_code;
@ -144,12 +145,16 @@ extern unsigned long mmap_min_addr;
*/ */
#define MAX_ARG_PAGES 33 #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 * This structure is used to hold the arguments that are
* used when loading binaries. * used when loading binaries.
*/ */
struct linux_binprm { struct linux_binprm {
char buf[128]; char buf[BPRM_BUF_SIZE] __attribute__((aligned));
void *page[MAX_ARG_PAGES]; void *page[MAX_ARG_PAGES];
abi_ulong p; abi_ulong p;
int fd; int fd;