1 From bf858897b76926b56e948dbe7a1a491b68dccda7 Mon Sep 17 00:00:00 2001
2 From: Richard Henderson <rth@twiddle.net>
3 Date: Tue, 27 Jul 2010 17:25:38 +0000
4 Subject: linux-user: Re-use load_elf_image for the main binary.
6 This requires moving the PT_INTERP extraction and GUEST_BASE
7 handling into load_elf_image. Key this off a non-null pointer
8 argument to receive the interpreter name.
10 Signed-off-by: Richard Henderson <rth@twiddle.net>
11 Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
13 diff --git a/linux-user/elfload.c b/linux-user/elfload.c
14 index 0a3d084..a53285a 100644
15 --- a/linux-user/elfload.c
16 +++ b/linux-user/elfload.c
17 @@ -829,9 +829,6 @@ struct exec
21 -/* max code+data+bss+brk space allocated to ET_DYN executables */
22 -#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
24 /* Necessary parameters */
25 #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
26 #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
27 @@ -1169,7 +1166,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
28 On return: INFO values will be filled in, as necessary or available. */
30 static void load_elf_image(const char *image_name, int image_fd,
31 - struct image_info *info,
32 + struct image_info *info, char **pinterp_name,
33 char bprm_buf[BPRM_BUF_SIZE])
35 struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
36 @@ -1229,6 +1226,67 @@ static void load_elf_image(const char *image_name, int image_fd,
37 if (load_addr == -1) {
40 + } else if (pinterp_name != NULL) {
41 + /* This is the main executable. Make sure that the low
42 + address does not conflict with MMAP_MIN_ADDR or the
43 + QEMU application itself. */
44 +#if defined(CONFIG_USE_GUEST_BASE)
46 + * In case where user has not explicitly set the guest_base, we
47 + * probe here that should we set it automatically.
49 + if (!have_guest_base && !reserved_va) {
50 + unsigned long host_start, real_start, host_size;
52 + /* Round addresses to page boundaries. */
53 + loaddr &= qemu_host_page_mask;
54 + hiaddr = HOST_PAGE_ALIGN(hiaddr);
56 + if (loaddr < mmap_min_addr) {
57 + host_start = HOST_PAGE_ALIGN(mmap_min_addr);
59 + host_start = loaddr;
60 + if (host_start != loaddr) {
61 + errmsg = "Address overflow loading ELF binary";
65 + host_size = hiaddr - loaddr;
67 + /* Do not use mmap_find_vma here because that is limited to the
68 + guest address space. We are going to make the
69 + guest address space fit whatever we're given. */
70 + real_start = (unsigned long)
71 + mmap((void *)host_start, host_size, PROT_NONE,
72 + MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
73 + if (real_start == (unsigned long)-1) {
76 + if (real_start == host_start) {
79 + /* That address didn't work. Unmap and try a different one.
80 + The address the host picked because is typically right at
81 + the top of the host address space and leaves the guest with
82 + no usable address space. Resort to a linear search. We
83 + already compensated for mmap_min_addr, so this should not
84 + happen often. Probably means we got unlucky and host
85 + address space randomization put a shared library somewhere
87 + munmap((void *)real_start, host_size);
88 + host_start += qemu_host_page_size;
89 + if (host_start == loaddr) {
90 + /* Theoretically possible if host doesn't have any suitably
91 + aligned areas. Normally the first mmap will fail. */
92 + errmsg = "Unable to find space for application";
96 + qemu_log("Relocating guest address space from 0x"
97 + TARGET_ABI_FMT_lx " to 0x%lx\n", loaddr, real_start);
98 + guest_base = real_start - loaddr;
102 load_bias = load_addr - loaddr;
104 @@ -1290,6 +1348,33 @@ static void load_elf_image(const char *image_name, int image_fd,
105 info->brk = vaddr_em;
108 + } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
111 + if (*pinterp_name) {
112 + errmsg = "Multiple PT_INTERP entries";
115 + interp_name = malloc(eppnt->p_filesz);
116 + if (!interp_name) {
120 + if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
121 + memcpy(interp_name, bprm_buf + eppnt->p_offset,
124 + retval = pread(image_fd, interp_name, eppnt->p_filesz,
126 + if (retval != eppnt->p_filesz) {
130 + if (interp_name[eppnt->p_filesz - 1] != 0) {
131 + errmsg = "Invalid PT_INTERP entry";
134 + *pinterp_name = interp_name;
138 @@ -1336,7 +1421,7 @@ static void load_elf_interp(const char *filename, struct image_info *info,
139 memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
142 - load_elf_image(filename, fd, info, bprm_buf);
143 + load_elf_image(filename, fd, info, NULL, bprm_buf);
147 @@ -1480,291 +1565,31 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
149 struct image_info interp_info;
150 struct elfhdr elf_ex;
151 - abi_ulong load_addr, load_bias;
152 - int load_addr_set = 0;
154 - struct elf_phdr * elf_ppnt;
155 - struct elf_phdr *elf_phdata;
156 - abi_ulong k, elf_brk;
158 char *elf_interpreter = NULL;
159 - abi_ulong elf_entry;
161 - abi_ulong start_code, end_code, start_data, end_data;
162 - abi_ulong elf_stack;
167 - elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
168 + info->start_mmap = (abi_ulong)ELF_START_MMAP;
172 - /* First of all, some simple consistency checks */
173 - if (!elf_check_ident(&elf_ex)) {
176 - bswap_ehdr(&elf_ex);
177 - if (!elf_check_ehdr(&elf_ex)) {
180 + load_elf_image(bprm->filename, bprm->fd, info,
181 + &elf_interpreter, bprm->buf);
183 + /* ??? We need a copy of the elf header for passing to create_elf_tables.
184 + If we do nothing, we'll have overwritten this when we re-use bprm->buf
185 + when we load the interpreter. */
186 + elf_ex = *(struct elfhdr *)bprm->buf;
188 bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
189 bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
190 bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
195 - /* Now read in all of the header information */
196 - elf_phdata = (struct elf_phdr *)
197 - malloc(elf_ex.e_phnum * sizeof(struct elf_phdr));
198 - if (elf_phdata == NULL) {
202 - i = elf_ex.e_phnum * sizeof(struct elf_phdr);
203 - if (elf_ex.e_phoff + i <= BPRM_BUF_SIZE) {
204 - memcpy(elf_phdata, bprm->buf + elf_ex.e_phoff, i);
206 - retval = pread(bprm->fd, (char *) elf_phdata, i, elf_ex.e_phoff);
208 - perror("load_elf_binary");
212 - bswap_phdr(elf_phdata, elf_ex.e_phnum);
215 - elf_stack = ~((abi_ulong)0UL);
216 - start_code = ~((abi_ulong)0UL);
221 - elf_ppnt = elf_phdata;
222 - for(i=0;i < elf_ex.e_phnum; i++) {
223 - if (elf_ppnt->p_type == PT_INTERP) {
224 - if (elf_ppnt->p_offset + elf_ppnt->p_filesz <= BPRM_BUF_SIZE) {
225 - elf_interpreter = bprm->buf + elf_ppnt->p_offset;
227 - elf_interpreter = alloca(elf_ppnt->p_filesz);
228 - retval = pread(bprm->fd, elf_interpreter, elf_ppnt->p_filesz,
229 - elf_ppnt->p_offset);
230 - if (retval != elf_ppnt->p_filesz) {
231 - perror("load_elf_binary");
239 - /* OK, This is the point of no return */
240 - info->end_data = 0;
241 - info->end_code = 0;
242 - info->start_mmap = (abi_ulong)ELF_START_MMAP;
244 - elf_entry = (abi_ulong) elf_ex.e_entry;
246 -#if defined(CONFIG_USE_GUEST_BASE)
248 - * In case where user has not explicitly set the guest_base, we
249 - * probe here that should we set it automatically.
251 - if (!(have_guest_base || reserved_va)) {
253 - * Go through ELF program header table and find the address
254 - * range used by loadable segments. Check that this is available on
255 - * the host, and if not find a suitable value for guest_base. */
256 - abi_ulong app_start = ~0;
257 - abi_ulong app_end = 0;
259 - unsigned long host_start;
260 - unsigned long real_start;
261 - unsigned long host_size;
262 - for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum;
264 - if (elf_ppnt->p_type != PT_LOAD)
266 - addr = elf_ppnt->p_vaddr;
267 - if (addr < app_start) {
270 - addr += elf_ppnt->p_memsz;
271 - if (addr > app_end) {
276 - /* If we don't have any loadable segments then something
278 - assert(app_start < app_end);
280 - /* Round addresses to page boundaries. */
281 - app_start = app_start & qemu_host_page_mask;
282 - app_end = HOST_PAGE_ALIGN(app_end);
283 - if (app_start < mmap_min_addr) {
284 - host_start = HOST_PAGE_ALIGN(mmap_min_addr);
286 - host_start = app_start;
287 - if (host_start != app_start) {
288 - fprintf(stderr, "qemu: Address overflow loading ELF binary\n");
292 - host_size = app_end - app_start;
294 - /* Do not use mmap_find_vma here because that is limited to the
295 - guest address space. We are going to make the
296 - guest address space fit whatever we're given. */
297 - real_start = (unsigned long)mmap((void *)host_start, host_size,
298 - PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
299 - if (real_start == (unsigned long)-1) {
300 - fprintf(stderr, "qemu: Virtual memory exausted\n");
303 - if (real_start == host_start) {
306 - /* That address didn't work. Unmap and try a different one.
307 - The address the host picked because is typically
308 - right at the top of the host address space and leaves the
309 - guest with no usable address space. Resort to a linear search.
310 - We already compensated for mmap_min_addr, so this should not
311 - happen often. Probably means we got unlucky and host address
312 - space randomization put a shared library somewhere
314 - munmap((void *)real_start, host_size);
315 - host_start += qemu_host_page_size;
316 - if (host_start == app_start) {
317 - /* Theoretically possible if host doesn't have any
318 - suitably aligned areas. Normally the first mmap will
320 - fprintf(stderr, "qemu: Unable to find space for application\n");
324 - qemu_log("Relocating guest address space from 0x" TARGET_ABI_FMT_lx
325 - " to 0x%lx\n", app_start, real_start);
326 - guest_base = real_start - app_start;
327 + fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG));
330 -#endif /* CONFIG_USE_GUEST_BASE */
332 /* Do this so that we can load the interpreter, if need be. We will
333 change some of these later */
335 bprm->p = setup_arg_pages(bprm->p, bprm, info);
336 - info->start_stack = bprm->p;
338 - /* Now we do a little grungy work by mmaping the ELF image into
339 - * the correct location in memory. At this point, we assume that
340 - * the image should be loaded at fixed address, not at a variable
344 - for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
349 - if (elf_ppnt->p_type != PT_LOAD)
352 - if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
353 - if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
354 - if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
355 - elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
356 - if (elf_ex.e_type == ET_EXEC || load_addr_set) {
357 - elf_flags |= MAP_FIXED;
358 - } else if (elf_ex.e_type == ET_DYN) {
359 - /* Try and get dynamic programs out of the way of the default mmap
360 - base, as well as whatever program they might try to exec. This
361 - is because the brk will follow the loader, and is not movable. */
362 - /* NOTE: for qemu, we do a big mmap to get enough space
363 - without hardcoding any address */
364 - error = target_mmap(0, ET_DYN_MAP_SIZE,
365 - PROT_NONE, MAP_PRIVATE | MAP_ANON,
371 - load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
374 - error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
375 - (elf_ppnt->p_filesz +
376 - TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
378 - (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
380 - (elf_ppnt->p_offset -
381 - TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
387 -#ifdef LOW_ELF_STACK
388 - if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
389 - elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr);
392 - if (!load_addr_set) {
394 - load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
395 - if (elf_ex.e_type == ET_DYN) {
396 - load_bias += error -
397 - TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
398 - load_addr += load_bias;
401 - k = elf_ppnt->p_vaddr;
402 - if (k < start_code)
404 - if (start_data < k)
406 - k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
407 - if ((elf_ppnt->p_flags & PF_X) && end_code < k)
411 - k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
413 - elf_brk = TARGET_PAGE_ALIGN(k);
416 - /* If the load segment requests extra zeros (e.g. bss), map it. */
417 - if (elf_ppnt->p_filesz < elf_ppnt->p_memsz) {
418 - abi_ulong base = load_bias + elf_ppnt->p_vaddr;
419 - zero_bss(base + elf_ppnt->p_filesz,
420 - base + elf_ppnt->p_memsz, elf_prot);
424 - elf_entry += load_bias;
425 - elf_brk += load_bias;
426 - start_code += load_bias;
427 - end_code += load_bias;
428 - start_data += load_bias;
429 - end_data += load_bias;
431 - info->load_bias = load_bias;
432 - info->load_addr = load_addr;
433 - info->entry = elf_entry;
434 - info->start_brk = info->brk = elf_brk;
435 - info->end_code = end_code;
436 - info->start_code = start_code;
437 - info->start_data = start_data;
438 - info->end_data = end_data;
439 - info->personality = PER_LINUX;
443 - if (qemu_log_enabled()) {
444 - load_symbols(&elf_ex, bprm->fd, load_bias);
449 if (elf_interpreter) {
450 load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
451 @@ -1796,6 +1621,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
452 if (elf_interpreter) {
453 info->load_addr = interp_info.load_addr;
454 info->entry = interp_info.entry;
455 + free(elf_interpreter);
458 #ifdef USE_ELF_CORE_DUMP