Commit 09bfb054fb4d7a72b4989141de157cdeda6704bd
1 parent
2677e107
first self virtualizable version
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@89 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
217 additions
and
105 deletions
Makefile
| @@ -105,7 +105,7 @@ qemu-doc.html: qemu-doc.texi | @@ -105,7 +105,7 @@ qemu-doc.html: qemu-doc.texi | ||
| 105 | FILES= \ | 105 | FILES= \ |
| 106 | README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \ | 106 | README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \ |
| 107 | dyngen.c ioctls.h ops_template.h op_string.h syscall_types.h\ | 107 | dyngen.c ioctls.h ops_template.h op_string.h syscall_types.h\ |
| 108 | -Makefile elf.h linux_bin.h segment.h thunk.c\ | 108 | +Makefile elf.h thunk.c\ |
| 109 | elfload.c main.c signal.c thunk.h\ | 109 | elfload.c main.c signal.c thunk.h\ |
| 110 | cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\ | 110 | cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\ |
| 111 | dis-asm.h gen-i386.h syscall.c\ | 111 | dis-asm.h gen-i386.h syscall.c\ |
TODO
| @@ -7,5 +7,6 @@ | @@ -7,5 +7,6 @@ | ||
| 7 | issues, fix 16 bit uid issues) | 7 | issues, fix 16 bit uid issues) |
| 8 | - finish signal handing (fp87 state, more siginfo conversions) | 8 | - finish signal handing (fp87 state, more siginfo conversions) |
| 9 | - verify thread support (clone() and various locks) | 9 | - verify thread support (clone() and various locks) |
| 10 | -- make it self runnable (use same trick as ld.so : include its own relocator and libc) | 10 | +- make it self runnable (handle self modifying code, relocate stack |
| 11 | + and dyn loader) | ||
| 11 | - fix FPU exceptions (in particular: gen_op_fpush not before mem load) | 12 | - fix FPU exceptions (in particular: gen_op_fpush not before mem load) |
linux-user/elfload.c
| @@ -49,9 +49,78 @@ typedef struct user_i387_struct elf_fpregset_t; | @@ -49,9 +49,78 @@ typedef struct user_i387_struct elf_fpregset_t; | ||
| 49 | 49 | ||
| 50 | #endif | 50 | #endif |
| 51 | 51 | ||
| 52 | -#include "linux_bin.h" | ||
| 53 | #include "elf.h" | 52 | #include "elf.h" |
| 54 | -#include "segment.h" | 53 | + |
| 54 | +/* | ||
| 55 | + * MAX_ARG_PAGES defines the number of pages allocated for arguments | ||
| 56 | + * and envelope for the new program. 32 should suffice, this gives | ||
| 57 | + * a maximum env+arg of 128kB w/4KB pages! | ||
| 58 | + */ | ||
| 59 | +#define MAX_ARG_PAGES 32 | ||
| 60 | + | ||
| 61 | +/* | ||
| 62 | + * This structure is used to hold the arguments that are | ||
| 63 | + * used when loading binaries. | ||
| 64 | + */ | ||
| 65 | +struct linux_binprm { | ||
| 66 | + char buf[128]; | ||
| 67 | + unsigned long page[MAX_ARG_PAGES]; | ||
| 68 | + unsigned long p; | ||
| 69 | + int sh_bang; | ||
| 70 | + int fd; | ||
| 71 | + int e_uid, e_gid; | ||
| 72 | + int argc, envc; | ||
| 73 | + char * interp_prefix; /* prefix for interpreter */ | ||
| 74 | + char * filename; /* Name of binary */ | ||
| 75 | + unsigned long loader, exec; | ||
| 76 | + int dont_iput; /* binfmt handler has put inode */ | ||
| 77 | +}; | ||
| 78 | + | ||
| 79 | +struct exec | ||
| 80 | +{ | ||
| 81 | + unsigned int a_info; /* Use macros N_MAGIC, etc for access */ | ||
| 82 | + unsigned int a_text; /* length of text, in bytes */ | ||
| 83 | + unsigned int a_data; /* length of data, in bytes */ | ||
| 84 | + unsigned int a_bss; /* length of uninitialized data area, in bytes */ | ||
| 85 | + unsigned int a_syms; /* length of symbol table data in file, in bytes */ | ||
| 86 | + unsigned int a_entry; /* start address */ | ||
| 87 | + unsigned int a_trsize; /* length of relocation info for text, in bytes */ | ||
| 88 | + unsigned int a_drsize; /* length of relocation info for data, in bytes */ | ||
| 89 | +}; | ||
| 90 | + | ||
| 91 | + | ||
| 92 | +#define N_MAGIC(exec) ((exec).a_info & 0xffff) | ||
| 93 | +#define OMAGIC 0407 | ||
| 94 | +#define NMAGIC 0410 | ||
| 95 | +#define ZMAGIC 0413 | ||
| 96 | +#define QMAGIC 0314 | ||
| 97 | + | ||
| 98 | +#define X86_STACK_TOP 0x7d000000 | ||
| 99 | + | ||
| 100 | +/* max code+data+bss space allocated to elf interpreter */ | ||
| 101 | +#define INTERP_MAP_SIZE (32 * 1024 * 1024) | ||
| 102 | + | ||
| 103 | +/* max code+data+bss+brk space allocated to ET_DYN executables */ | ||
| 104 | +#define ET_DYN_MAP_SIZE (128 * 1024 * 1024) | ||
| 105 | + | ||
| 106 | +/* from personality.h */ | ||
| 107 | + | ||
| 108 | +/* Flags for bug emulation. These occupy the top three bytes. */ | ||
| 109 | +#define STICKY_TIMEOUTS 0x4000000 | ||
| 110 | +#define WHOLE_SECONDS 0x2000000 | ||
| 111 | + | ||
| 112 | +/* Personality types. These go in the low byte. Avoid using the top bit, | ||
| 113 | + * it will conflict with error returns. | ||
| 114 | + */ | ||
| 115 | +#define PER_MASK (0x00ff) | ||
| 116 | +#define PER_LINUX (0x0000) | ||
| 117 | +#define PER_SVR4 (0x0001 | STICKY_TIMEOUTS) | ||
| 118 | +#define PER_SVR3 (0x0002 | STICKY_TIMEOUTS) | ||
| 119 | +#define PER_SCOSVR3 (0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS) | ||
| 120 | +#define PER_WYSEV386 (0x0004 | STICKY_TIMEOUTS) | ||
| 121 | +#define PER_ISCR4 (0x0005 | STICKY_TIMEOUTS) | ||
| 122 | +#define PER_BSD (0x0006) | ||
| 123 | +#define PER_XENIX (0x0007 | STICKY_TIMEOUTS) | ||
| 55 | 124 | ||
| 56 | /* Necessary parameters */ | 125 | /* Necessary parameters */ |
| 57 | #define ALPHA_PAGE_SIZE 4096 | 126 | #define ALPHA_PAGE_SIZE 4096 |
| @@ -78,8 +147,18 @@ typedef struct user_i387_struct elf_fpregset_t; | @@ -78,8 +147,18 @@ typedef struct user_i387_struct elf_fpregset_t; | ||
| 78 | 147 | ||
| 79 | #define DLINFO_ITEMS 12 | 148 | #define DLINFO_ITEMS 12 |
| 80 | 149 | ||
| 81 | -/* Where we find X86 libraries... */ | 150 | +#define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x)) |
| 151 | +#define get_user(ptr) (typeof(*ptr))(*(ptr)) | ||
| 152 | + | ||
| 153 | +static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) | ||
| 154 | +{ | ||
| 155 | + memcpy(to, from, n); | ||
| 156 | +} | ||
| 82 | 157 | ||
| 158 | +static inline void memcpy_tofs(void * to, const void * from, unsigned long n) | ||
| 159 | +{ | ||
| 160 | + memcpy(to, from, n); | ||
| 161 | +} | ||
| 83 | 162 | ||
| 84 | //extern void * mmap4k(); | 163 | //extern void * mmap4k(); |
| 85 | #define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f) | 164 | #define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f) |
| @@ -282,43 +361,35 @@ static int prepare_binprm(struct linux_binprm *bprm) | @@ -282,43 +361,35 @@ static int prepare_binprm(struct linux_binprm *bprm) | ||
| 282 | unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, | 361 | unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, |
| 283 | struct image_info * info) | 362 | struct image_info * info) |
| 284 | { | 363 | { |
| 285 | - unsigned long stack_base; | 364 | + unsigned long stack_base, size, error; |
| 286 | int i; | 365 | int i; |
| 287 | - extern unsigned long stktop; | ||
| 288 | 366 | ||
| 289 | - stack_base = X86_STACK_TOP - MAX_ARG_PAGES*X86_PAGE_SIZE; | 367 | + /* Create enough stack to hold everything. If we don't use |
| 368 | + * it for args, we'll use it for something else... | ||
| 369 | + */ | ||
| 370 | + size = x86_stack_size; | ||
| 371 | + if (size < MAX_ARG_PAGES*X86_PAGE_SIZE) | ||
| 372 | + size = MAX_ARG_PAGES*X86_PAGE_SIZE; | ||
| 373 | + error = (unsigned long)mmap4k(NULL, | ||
| 374 | + size + X86_PAGE_SIZE, | ||
| 375 | + PROT_READ | PROT_WRITE, | ||
| 376 | + MAP_PRIVATE | MAP_ANONYMOUS, | ||
| 377 | + -1, 0); | ||
| 378 | + if (error == -1) { | ||
| 379 | + perror("stk mmap"); | ||
| 380 | + exit(-1); | ||
| 381 | + } | ||
| 382 | + /* we reserve one extra page at the top of the stack as guard */ | ||
| 383 | + mprotect((void *)(error + size), X86_PAGE_SIZE, PROT_NONE); | ||
| 290 | 384 | ||
| 385 | + stack_base = error + size - MAX_ARG_PAGES*X86_PAGE_SIZE; | ||
| 291 | p += stack_base; | 386 | p += stack_base; |
| 387 | + | ||
| 292 | if (bprm->loader) { | 388 | if (bprm->loader) { |
| 293 | bprm->loader += stack_base; | 389 | bprm->loader += stack_base; |
| 294 | } | 390 | } |
| 295 | bprm->exec += stack_base; | 391 | bprm->exec += stack_base; |
| 296 | 392 | ||
| 297 | - /* Create enough stack to hold everything. If we don't use | ||
| 298 | - * it for args, we'll use it for something else... | ||
| 299 | - */ | ||
| 300 | - /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so | ||
| 301 | - we allocate a bigger stack. Need a better solution, for example | ||
| 302 | - by remapping the process stack directly at the right place */ | ||
| 303 | - if(x86_stack_size > MAX_ARG_PAGES*X86_PAGE_SIZE) { | ||
| 304 | - if((long)mmap4k((void *)(X86_STACK_TOP-x86_stack_size), x86_stack_size + X86_PAGE_SIZE, | ||
| 305 | - PROT_READ | PROT_WRITE, | ||
| 306 | - MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { | ||
| 307 | - perror("stk mmap"); | ||
| 308 | - exit(-1); | ||
| 309 | - } | ||
| 310 | - } | ||
| 311 | - else { | ||
| 312 | - if((long)mmap4k((void *)stack_base, (MAX_ARG_PAGES+1)*X86_PAGE_SIZE, | ||
| 313 | - PROT_READ | PROT_WRITE, | ||
| 314 | - MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { | ||
| 315 | - perror("stk mmap"); | ||
| 316 | - exit(-1); | ||
| 317 | - } | ||
| 318 | - } | ||
| 319 | - | ||
| 320 | - stktop = stack_base; | ||
| 321 | - | ||
| 322 | for (i = 0 ; i < MAX_ARG_PAGES ; i++) { | 393 | for (i = 0 ; i < MAX_ARG_PAGES ; i++) { |
| 323 | if (bprm->page[i]) { | 394 | if (bprm->page[i]) { |
| 324 | info->rss++; | 395 | info->rss++; |
| @@ -369,10 +440,11 @@ static void padzero(unsigned long elf_bss) | @@ -369,10 +440,11 @@ static void padzero(unsigned long elf_bss) | ||
| 369 | } | 440 | } |
| 370 | 441 | ||
| 371 | static unsigned int * create_elf_tables(char *p, int argc, int envc, | 442 | static unsigned int * create_elf_tables(char *p, int argc, int envc, |
| 372 | - struct elfhdr * exec, | ||
| 373 | - unsigned long load_addr, | ||
| 374 | - unsigned long interp_load_addr, int ibcs, | ||
| 375 | - struct image_info *info) | 443 | + struct elfhdr * exec, |
| 444 | + unsigned long load_addr, | ||
| 445 | + unsigned long load_bias, | ||
| 446 | + unsigned long interp_load_addr, int ibcs, | ||
| 447 | + struct image_info *info) | ||
| 376 | { | 448 | { |
| 377 | target_ulong *argv, *envp, *dlinfo; | 449 | target_ulong *argv, *envp, *dlinfo; |
| 378 | target_ulong *sp; | 450 | target_ulong *sp; |
| @@ -397,17 +469,17 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, | @@ -397,17 +469,17 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, | ||
| 397 | put_user (tswapl(val), dlinfo++) | 469 | put_user (tswapl(val), dlinfo++) |
| 398 | 470 | ||
| 399 | if (exec) { /* Put this here for an ELF program interpreter */ | 471 | if (exec) { /* Put this here for an ELF program interpreter */ |
| 400 | - NEW_AUX_ENT (AT_PHDR, (unsigned int)(load_addr + exec->e_phoff)); | ||
| 401 | - NEW_AUX_ENT (AT_PHENT, (unsigned int)(sizeof (struct elf_phdr))); | ||
| 402 | - NEW_AUX_ENT (AT_PHNUM, (unsigned int)(exec->e_phnum)); | ||
| 403 | - NEW_AUX_ENT (AT_PAGESZ, (unsigned int)(ALPHA_PAGE_SIZE)); | ||
| 404 | - NEW_AUX_ENT (AT_BASE, (unsigned int)(interp_load_addr)); | ||
| 405 | - NEW_AUX_ENT (AT_FLAGS, (unsigned int)0); | ||
| 406 | - NEW_AUX_ENT (AT_ENTRY, (unsigned int) exec->e_entry); | ||
| 407 | - NEW_AUX_ENT (AT_UID, (unsigned int) getuid()); | ||
| 408 | - NEW_AUX_ENT (AT_EUID, (unsigned int) geteuid()); | ||
| 409 | - NEW_AUX_ENT (AT_GID, (unsigned int) getgid()); | ||
| 410 | - NEW_AUX_ENT (AT_EGID, (unsigned int) getegid()); | 472 | + NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); |
| 473 | + NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); | ||
| 474 | + NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum)); | ||
| 475 | + NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(ALPHA_PAGE_SIZE)); | ||
| 476 | + NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr)); | ||
| 477 | + NEW_AUX_ENT (AT_FLAGS, (target_ulong)0); | ||
| 478 | + NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry); | ||
| 479 | + NEW_AUX_ENT (AT_UID, (target_ulong) getuid()); | ||
| 480 | + NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid()); | ||
| 481 | + NEW_AUX_ENT (AT_GID, (target_ulong) getgid()); | ||
| 482 | + NEW_AUX_ENT (AT_EGID, (target_ulong) getegid()); | ||
| 411 | } | 483 | } |
| 412 | NEW_AUX_ENT (AT_NULL, 0); | 484 | NEW_AUX_ENT (AT_NULL, 0); |
| 413 | #undef NEW_AUX_ENT | 485 | #undef NEW_AUX_ENT |
| @@ -436,7 +508,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, | @@ -436,7 +508,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, | ||
| 436 | { | 508 | { |
| 437 | struct elf_phdr *elf_phdata = NULL; | 509 | struct elf_phdr *elf_phdata = NULL; |
| 438 | struct elf_phdr *eppnt; | 510 | struct elf_phdr *eppnt; |
| 439 | - unsigned long load_addr; | 511 | + unsigned long load_addr = 0; |
| 440 | int load_addr_set = 0; | 512 | int load_addr_set = 0; |
| 441 | int retval; | 513 | int retval; |
| 442 | unsigned long last_bss, elf_bss; | 514 | unsigned long last_bss, elf_bss; |
| @@ -447,17 +519,12 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, | @@ -447,17 +519,12 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, | ||
| 447 | last_bss = 0; | 519 | last_bss = 0; |
| 448 | error = 0; | 520 | error = 0; |
| 449 | 521 | ||
| 450 | - /* We put this here so that mmap will search for the *first* | ||
| 451 | - * available memory... | ||
| 452 | - */ | ||
| 453 | - load_addr = INTERP_LOADADDR; | ||
| 454 | - | ||
| 455 | #ifdef BSWAP_NEEDED | 522 | #ifdef BSWAP_NEEDED |
| 456 | bswap_ehdr(interp_elf_ex); | 523 | bswap_ehdr(interp_elf_ex); |
| 457 | #endif | 524 | #endif |
| 458 | /* First of all, some simple consistency checks */ | 525 | /* First of all, some simple consistency checks */ |
| 459 | if ((interp_elf_ex->e_type != ET_EXEC && | 526 | if ((interp_elf_ex->e_type != ET_EXEC && |
| 460 | - interp_elf_ex->e_type != ET_DYN) || | 527 | + interp_elf_ex->e_type != ET_DYN) || |
| 461 | !elf_check_arch(interp_elf_ex->e_machine)) { | 528 | !elf_check_arch(interp_elf_ex->e_machine)) { |
| 462 | return ~0UL; | 529 | return ~0UL; |
| 463 | } | 530 | } |
| @@ -478,11 +545,10 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, | @@ -478,11 +545,10 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, | ||
| 478 | * If the size of this structure has changed, then punt, since | 545 | * If the size of this structure has changed, then punt, since |
| 479 | * we will be doing the wrong thing. | 546 | * we will be doing the wrong thing. |
| 480 | */ | 547 | */ |
| 481 | - if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) | ||
| 482 | - { | 548 | + if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { |
| 483 | free(elf_phdata); | 549 | free(elf_phdata); |
| 484 | return ~0UL; | 550 | return ~0UL; |
| 485 | - } | 551 | + } |
| 486 | 552 | ||
| 487 | retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); | 553 | retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); |
| 488 | if(retval >= 0) { | 554 | if(retval >= 0) { |
| @@ -502,6 +568,21 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, | @@ -502,6 +568,21 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, | ||
| 502 | bswap_phdr(eppnt); | 568 | bswap_phdr(eppnt); |
| 503 | } | 569 | } |
| 504 | #endif | 570 | #endif |
| 571 | + | ||
| 572 | + if (interp_elf_ex->e_type == ET_DYN) { | ||
| 573 | + /* in order to avoid harcoding the interpreter load | ||
| 574 | + address in qemu, we allocate a big enough memory zone */ | ||
| 575 | + error = (unsigned long)mmap4k(NULL, INTERP_MAP_SIZE, | ||
| 576 | + PROT_NONE, MAP_PRIVATE | MAP_ANON, | ||
| 577 | + -1, 0); | ||
| 578 | + if (error == -1) { | ||
| 579 | + perror("mmap"); | ||
| 580 | + exit(-1); | ||
| 581 | + } | ||
| 582 | + load_addr = error; | ||
| 583 | + load_addr_set = 1; | ||
| 584 | + } | ||
| 585 | + | ||
| 505 | eppnt = elf_phdata; | 586 | eppnt = elf_phdata; |
| 506 | for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) | 587 | for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) |
| 507 | if (eppnt->p_type == PT_LOAD) { | 588 | if (eppnt->p_type == PT_LOAD) { |
| @@ -585,7 +666,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r | @@ -585,7 +666,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r | ||
| 585 | struct elfhdr interp_elf_ex; | 666 | struct elfhdr interp_elf_ex; |
| 586 | struct exec interp_ex; | 667 | struct exec interp_ex; |
| 587 | int interpreter_fd = -1; /* avoid warning */ | 668 | int interpreter_fd = -1; /* avoid warning */ |
| 588 | - unsigned long load_addr; | 669 | + unsigned long load_addr, load_bias; |
| 589 | int load_addr_set = 0; | 670 | int load_addr_set = 0; |
| 590 | unsigned int interpreter_type = INTERPRETER_NONE; | 671 | unsigned int interpreter_type = INTERPRETER_NONE; |
| 591 | unsigned char ibcs2_interpreter; | 672 | unsigned char ibcs2_interpreter; |
| @@ -605,6 +686,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r | @@ -605,6 +686,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r | ||
| 605 | ibcs2_interpreter = 0; | 686 | ibcs2_interpreter = 0; |
| 606 | status = 0; | 687 | status = 0; |
| 607 | load_addr = 0; | 688 | load_addr = 0; |
| 689 | + load_bias = 0; | ||
| 608 | elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ | 690 | elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ |
| 609 | #ifdef BSWAP_NEEDED | 691 | #ifdef BSWAP_NEEDED |
| 610 | bswap_ehdr(&elf_ex); | 692 | bswap_ehdr(&elf_ex); |
| @@ -810,56 +892,86 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r | @@ -810,56 +892,86 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r | ||
| 810 | * address. | 892 | * address. |
| 811 | */ | 893 | */ |
| 812 | 894 | ||
| 813 | - | ||
| 814 | - | ||
| 815 | for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { | 895 | for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { |
| 816 | - if (elf_ppnt->p_type == PT_LOAD) { | ||
| 817 | - int elf_prot = 0; | ||
| 818 | - if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; | ||
| 819 | - if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; | ||
| 820 | - if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; | ||
| 821 | - | ||
| 822 | - mapped_addr = mmap4k(X86_ELF_PAGESTART(elf_ppnt->p_vaddr), | ||
| 823 | - (elf_ppnt->p_filesz + | ||
| 824 | - X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), | ||
| 825 | - elf_prot, | ||
| 826 | - (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), | ||
| 827 | - bprm->fd, | ||
| 828 | - (elf_ppnt->p_offset - | ||
| 829 | - X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); | ||
| 830 | - | ||
| 831 | - if((unsigned long)mapped_addr == 0xffffffffffffffff) { | ||
| 832 | - perror("mmap"); | ||
| 833 | - exit(-1); | ||
| 834 | - } | ||
| 835 | - | ||
| 836 | - | 896 | + int elf_prot = 0; |
| 897 | + int elf_flags = 0; | ||
| 898 | + unsigned long error; | ||
| 899 | + | ||
| 900 | + if (elf_ppnt->p_type != PT_LOAD) | ||
| 901 | + continue; | ||
| 902 | + | ||
| 903 | + if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; | ||
| 904 | + if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; | ||
| 905 | + if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; | ||
| 906 | + elf_flags = MAP_PRIVATE | MAP_DENYWRITE; | ||
| 907 | + if (elf_ex.e_type == ET_EXEC || load_addr_set) { | ||
| 908 | + elf_flags |= MAP_FIXED; | ||
| 909 | + } else if (elf_ex.e_type == ET_DYN) { | ||
| 910 | + /* Try and get dynamic programs out of the way of the default mmap | ||
| 911 | + base, as well as whatever program they might try to exec. This | ||
| 912 | + is because the brk will follow the loader, and is not movable. */ | ||
| 913 | + /* NOTE: for qemu, we do a big mmap to get enough space | ||
| 914 | + without harcoding any address */ | ||
| 915 | + error = (unsigned long)mmap4k(NULL, ET_DYN_MAP_SIZE, | ||
| 916 | + PROT_NONE, MAP_PRIVATE | MAP_ANON, | ||
| 917 | + -1, 0); | ||
| 918 | + if (error == -1) { | ||
| 919 | + perror("mmap"); | ||
| 920 | + exit(-1); | ||
| 921 | + } | ||
| 922 | + load_bias = X86_ELF_PAGESTART(error - elf_ppnt->p_vaddr); | ||
| 923 | + } | ||
| 924 | + | ||
| 925 | + error = (unsigned long)mmap4k( | ||
| 926 | + X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), | ||
| 927 | + (elf_ppnt->p_filesz + | ||
| 928 | + X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), | ||
| 929 | + elf_prot, | ||
| 930 | + (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), | ||
| 931 | + bprm->fd, | ||
| 932 | + (elf_ppnt->p_offset - | ||
| 933 | + X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); | ||
| 934 | + if (error == -1) { | ||
| 935 | + perror("mmap"); | ||
| 936 | + exit(-1); | ||
| 937 | + } | ||
| 837 | 938 | ||
| 838 | #ifdef LOW_ELF_STACK | 939 | #ifdef LOW_ELF_STACK |
| 839 | - if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) | ||
| 840 | - elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr); | 940 | + if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) |
| 941 | + elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr); | ||
| 841 | #endif | 942 | #endif |
| 842 | - | ||
| 843 | - if (!load_addr_set) { | ||
| 844 | - load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; | ||
| 845 | - load_addr_set = 1; | ||
| 846 | - } | ||
| 847 | - k = elf_ppnt->p_vaddr; | ||
| 848 | - if (k < start_code) start_code = k; | ||
| 849 | - k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; | ||
| 850 | - if (k > elf_bss) elf_bss = k; | ||
| 851 | -#if 1 | ||
| 852 | - if ((elf_ppnt->p_flags & PF_X) && end_code < k) | ||
| 853 | -#else | ||
| 854 | - if ( !(elf_ppnt->p_flags & PF_W) && end_code < k) | ||
| 855 | -#endif | ||
| 856 | - end_code = k; | ||
| 857 | - if (end_data < k) end_data = k; | ||
| 858 | - k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; | ||
| 859 | - if (k > elf_brk) elf_brk = k; | ||
| 860 | - } | 943 | + |
| 944 | + if (!load_addr_set) { | ||
| 945 | + load_addr_set = 1; | ||
| 946 | + load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; | ||
| 947 | + if (elf_ex.e_type == ET_DYN) { | ||
| 948 | + load_bias += error - | ||
| 949 | + X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); | ||
| 950 | + load_addr += load_bias; | ||
| 951 | + } | ||
| 952 | + } | ||
| 953 | + k = elf_ppnt->p_vaddr; | ||
| 954 | + if (k < start_code) | ||
| 955 | + start_code = k; | ||
| 956 | + k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; | ||
| 957 | + if (k > elf_bss) | ||
| 958 | + elf_bss = k; | ||
| 959 | + if ((elf_ppnt->p_flags & PF_X) && end_code < k) | ||
| 960 | + end_code = k; | ||
| 961 | + if (end_data < k) | ||
| 962 | + end_data = k; | ||
| 963 | + k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; | ||
| 964 | + if (k > elf_brk) elf_brk = k; | ||
| 861 | } | 965 | } |
| 862 | 966 | ||
| 967 | + elf_entry += load_bias; | ||
| 968 | + elf_bss += load_bias; | ||
| 969 | + elf_brk += load_bias; | ||
| 970 | + start_code += load_bias; | ||
| 971 | + end_code += load_bias; | ||
| 972 | + // start_data += load_bias; | ||
| 973 | + end_data += load_bias; | ||
| 974 | + | ||
| 863 | if (elf_interpreter) { | 975 | if (elf_interpreter) { |
| 864 | if (interpreter_type & 1) { | 976 | if (interpreter_type & 1) { |
| 865 | elf_entry = load_aout_interp(&interp_ex, interpreter_fd); | 977 | elf_entry = load_aout_interp(&interp_ex, interpreter_fd); |
| @@ -893,7 +1005,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r | @@ -893,7 +1005,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r | ||
| 893 | bprm->argc, | 1005 | bprm->argc, |
| 894 | bprm->envc, | 1006 | bprm->envc, |
| 895 | (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), | 1007 | (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), |
| 896 | - load_addr, | 1008 | + load_addr, load_bias, |
| 897 | interp_load_addr, | 1009 | interp_load_addr, |
| 898 | (interpreter_type == INTERPRETER_AOUT ? 0 : 1), | 1010 | (interpreter_type == INTERPRETER_AOUT ? 0 : 1), |
| 899 | info); | 1011 | info); |
linux-user/main.c
| @@ -47,7 +47,6 @@ const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2"; | @@ -47,7 +47,6 @@ const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2"; | ||
| 47 | we allocate a bigger stack. Need a better solution, for example | 47 | we allocate a bigger stack. Need a better solution, for example |
| 48 | by remapping the process stack directly at the right place */ | 48 | by remapping the process stack directly at the right place */ |
| 49 | unsigned long x86_stack_size = 512 * 1024; | 49 | unsigned long x86_stack_size = 512 * 1024; |
| 50 | -unsigned long stktop; | ||
| 51 | 50 | ||
| 52 | void gemu_log(const char *fmt, ...) | 51 | void gemu_log(const char *fmt, ...) |
| 53 | { | 52 | { |