Commit 09bfb054fb4d7a72b4989141de157cdeda6704bd

Authored by bellard
1 parent 2677e107

first self virtualizable version


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@89 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile
... ... @@ -105,7 +105,7 @@ qemu-doc.html: qemu-doc.texi
105 105 FILES= \
106 106 README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \
107 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 109 elfload.c main.c signal.c thunk.h\
110 110 cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\
111 111 dis-asm.h gen-i386.h syscall.c\
... ...
... ... @@ -7,5 +7,6 @@
7 7 issues, fix 16 bit uid issues)
8 8 - finish signal handing (fp87 state, more siginfo conversions)
9 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 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 49  
50 50 #endif
51 51  
52   -#include "linux_bin.h"
53 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 125 /* Necessary parameters */
57 126 #define ALPHA_PAGE_SIZE 4096
... ... @@ -78,8 +147,18 @@ typedef struct user_i387_struct elf_fpregset_t;
78 147  
79 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 163 //extern void * mmap4k();
85 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 361 unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
283 362 struct image_info * info)
284 363 {
285   - unsigned long stack_base;
  364 + unsigned long stack_base, size, error;
286 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 386 p += stack_base;
  387 +
292 388 if (bprm->loader) {
293 389 bprm->loader += stack_base;
294 390 }
295 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 393 for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
323 394 if (bprm->page[i]) {
324 395 info->rss++;
... ... @@ -369,10 +440,11 @@ static void padzero(unsigned long elf_bss)
369 440 }
370 441  
371 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 449 target_ulong *argv, *envp, *dlinfo;
378 450 target_ulong *sp;
... ... @@ -397,17 +469,17 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
397 469 put_user (tswapl(val), dlinfo++)
398 470  
399 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 484 NEW_AUX_ENT (AT_NULL, 0);
413 485 #undef NEW_AUX_ENT
... ... @@ -436,7 +508,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
436 508 {
437 509 struct elf_phdr *elf_phdata = NULL;
438 510 struct elf_phdr *eppnt;
439   - unsigned long load_addr;
  511 + unsigned long load_addr = 0;
440 512 int load_addr_set = 0;
441 513 int retval;
442 514 unsigned long last_bss, elf_bss;
... ... @@ -447,17 +519,12 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
447 519 last_bss = 0;
448 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 522 #ifdef BSWAP_NEEDED
456 523 bswap_ehdr(interp_elf_ex);
457 524 #endif
458 525 /* First of all, some simple consistency checks */
459 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 528 !elf_check_arch(interp_elf_ex->e_machine)) {
462 529 return ~0UL;
463 530 }
... ... @@ -478,11 +545,10 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
478 545 * If the size of this structure has changed, then punt, since
479 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 549 free(elf_phdata);
484 550 return ~0UL;
485   - }
  551 + }
486 552  
487 553 retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
488 554 if(retval >= 0) {
... ... @@ -502,6 +568,21 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
502 568 bswap_phdr(eppnt);
503 569 }
504 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 586 eppnt = elf_phdata;
506 587 for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
507 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 666 struct elfhdr interp_elf_ex;
586 667 struct exec interp_ex;
587 668 int interpreter_fd = -1; /* avoid warning */
588   - unsigned long load_addr;
  669 + unsigned long load_addr, load_bias;
589 670 int load_addr_set = 0;
590 671 unsigned int interpreter_type = INTERPRETER_NONE;
591 672 unsigned char ibcs2_interpreter;
... ... @@ -605,6 +686,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
605 686 ibcs2_interpreter = 0;
606 687 status = 0;
607 688 load_addr = 0;
  689 + load_bias = 0;
608 690 elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
609 691 #ifdef BSWAP_NEEDED
610 692 bswap_ehdr(&elf_ex);
... ... @@ -810,56 +892,86 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
810 892 * address.
811 893 */
812 894  
813   -
814   -
815 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 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 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 975 if (elf_interpreter) {
864 976 if (interpreter_type & 1) {
865 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 1005 bprm->argc,
894 1006 bprm->envc,
895 1007 (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
896   - load_addr,
  1008 + load_addr, load_bias,
897 1009 interp_load_addr,
898 1010 (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
899 1011 info);
... ...
linux-user/main.c
... ... @@ -47,7 +47,6 @@ const char interp[] __attribute__((section(&quot;.interp&quot;))) = &quot;/lib/ld-linux.so.2&quot;;
47 47 we allocate a bigger stack. Need a better solution, for example
48 48 by remapping the process stack directly at the right place */
49 49 unsigned long x86_stack_size = 512 * 1024;
50   -unsigned long stktop;
51 50  
52 51 void gemu_log(const char *fmt, ...)
53 52 {
... ...