Commit 379f6698d73f476de38682b3ff96ecb226728c43

Authored by Paul Brook
1 parent a9ff9df1

Userspace guest address offsetting

Re-implement GUEST_BASE support.
Offset guest ddress space by default if the guest binary contains
regions below the host mmap_min_addr.
Implement support for i386, x86-64 and arm hosts.

Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
Signed-off-by: Paul Brook <paul@codesourcery.com>
configure
... ... @@ -184,6 +184,7 @@ softmmu=&quot;yes&quot;
184 184 linux_user="no"
185 185 darwin_user="no"
186 186 bsd_user="no"
  187 +guest_base=""
187 188 build_docs="yes"
188 189 uname_release=""
189 190 curses="yes"
... ... @@ -465,6 +466,10 @@ for opt do
465 466 ;;
466 467 --enable-bsd-user) bsd_user="yes"
467 468 ;;
  469 + --enable-guest-base) guest_base="yes"
  470 + ;;
  471 + --disable-guest-base) guest_base="no"
  472 + ;;
468 473 --enable-uname-release=*) uname_release="$optarg"
469 474 ;;
470 475 --sparc_cpu=*)
... ... @@ -544,6 +549,7 @@ fi
544 549 # If cpu ~= sparc and sparc_cpu hasn't been defined, plug in the right
545 550 # ARCH_CFLAGS/ARCH_LDFLAGS (assume sparc_v8plus for 32-bit and sparc_v9 for 64-bit)
546 551 #
  552 +host_guest_base="no"
547 553 case "$cpu" in
548 554 sparc) if test -z "$sparc_cpu" ; then
549 555 ARCH_CFLAGS="-m32 -mcpu=ultrasparc -D__sparc_v8plus__"
... ... @@ -576,13 +582,20 @@ case &quot;$cpu&quot; in
576 582 i386)
577 583 ARCH_CFLAGS="-m32"
578 584 ARCH_LDFLAGS="-m32"
  585 + host_guest_base="yes"
579 586 ;;
580 587 x86_64)
581 588 ARCH_CFLAGS="-m64"
582 589 ARCH_LDFLAGS="-m64"
  590 + host_guest_base="yes"
  591 + ;;
  592 + arm*)
  593 + host_guest_base="yes"
583 594 ;;
584 595 esac
585 596  
  597 +[ -z "$guest_base" ] && guest_base="$host_guest_base"
  598 +
586 599 if test x"$show_help" = x"yes" ; then
587 600 cat << EOF
588 601  
... ... @@ -641,6 +654,9 @@ echo &quot; --enable-darwin-user enable all darwin usermode emulation targets&quot;
641 654 echo " --disable-darwin-user disable all darwin usermode emulation targets"
642 655 echo " --enable-bsd-user enable all BSD usermode emulation targets"
643 656 echo " --disable-bsd-user disable all BSD usermode emulation targets"
  657 +echo " --enable-guest-base enable GUEST_BASE support for usermode"
  658 +echo " emulation targets"
  659 +echo " --disable-guest-base disable GUEST_BASE support"
644 660 echo " --fmod-lib path to FMOD library"
645 661 echo " --fmod-inc path to FMOD includes"
646 662 echo " --oss-lib path to OSS library"
... ... @@ -1446,6 +1462,7 @@ echo &quot;Documentation $build_docs&quot;
1446 1462 [ ! -z "$uname_release" ] && \
1447 1463 echo "uname -r $uname_release"
1448 1464 echo "NPTL support $nptl"
  1465 +echo "GUEST_BASE $guest_base"
1449 1466 echo "vde support $vde"
1450 1467 echo "AIO support $aio"
1451 1468 echo "IO thread $io_thread"
... ... @@ -2070,6 +2087,9 @@ fi
2070 2087 if test "$target_user_only" = "yes" -a "$elfload32" = "yes"; then
2071 2088 echo "TARGET_HAS_ELFLOAD32=y" >> $config_mak
2072 2089 fi
  2090 +if test "$target_user_only" = "yes" -a "$guest_base" = "yes"; then
  2091 + echo "CONFIG_USE_GUEST_BASE=y" >> $config_mak
  2092 +fi
2073 2093 if test "$target_bsd_user" = "yes" ; then
2074 2094 echo "CONFIG_BSD_USER=y" >> $config_mak
2075 2095 fi
... ...
cpu-all.h
... ... @@ -624,8 +624,13 @@ static inline void stfq_be_p(void *ptr, float64 v)
624 624 /* On some host systems the guest address space is reserved on the host.
625 625 * This allows the guest address space to be offset to a convenient location.
626 626 */
627   -//#define GUEST_BASE 0x20000000
628   -#define GUEST_BASE 0
  627 +#if defined(CONFIG_USE_GUEST_BASE)
  628 +extern unsigned long guest_base;
  629 +extern int have_guest_base;
  630 +#define GUEST_BASE guest_base
  631 +#else
  632 +#define GUEST_BASE 0ul
  633 +#endif
629 634  
630 635 /* All direct uses of g2h and h2g need to go away for usermode softmmu. */
631 636 #define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE))
... ...
linux-user/elfload.c
... ... @@ -1545,6 +1545,29 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
1545 1545 info->mmap = 0;
1546 1546 elf_entry = (abi_ulong) elf_ex.e_entry;
1547 1547  
  1548 +#if defined(CONFIG_USE_GUEST_BASE)
  1549 + /*
  1550 + * In case where user has not explicitly set the guest_base, we
  1551 + * probe here that should we set it automatically.
  1552 + */
  1553 + if (!have_guest_base) {
  1554 + /*
  1555 + * Go through ELF program header table and find out whether
  1556 + * any of the segments drop below our current mmap_min_addr and
  1557 + * in that case set guest_base to corresponding address.
  1558 + */
  1559 + for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum;
  1560 + i++, elf_ppnt++) {
  1561 + if (elf_ppnt->p_type != PT_LOAD)
  1562 + continue;
  1563 + if (HOST_PAGE_ALIGN(elf_ppnt->p_vaddr) < mmap_min_addr) {
  1564 + guest_base = HOST_PAGE_ALIGN(mmap_min_addr);
  1565 + break;
  1566 + }
  1567 + }
  1568 + }
  1569 +#endif /* CONFIG_USE_GUEST_BASE */
  1570 +
1548 1571 /* Do this so that we can load the interpreter, if need be. We will
1549 1572 change some of these later */
1550 1573 info->rss = 0;
... ...
linux-user/main.c
... ... @@ -39,6 +39,11 @@
39 39 char *exec_path;
40 40  
41 41 int singlestep;
  42 +#if defined(CONFIG_USE_GUEST_BASE)
  43 +unsigned long mmap_min_addr;
  44 +unsigned long guest_base;
  45 +int have_guest_base;
  46 +#endif
42 47  
43 48 static const char *interp_prefix = CONFIG_QEMU_PREFIX;
44 49 const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
... ... @@ -2320,6 +2325,9 @@ static void usage(void)
2320 2325 "-E var=value sets/modifies targets environment variable(s)\n"
2321 2326 "-U var unsets targets environment variable(s)\n"
2322 2327 "-0 argv0 forces target process argv[0] to be argv0\n"
  2328 +#if defined(CONFIG_USE_GUEST_BASE)
  2329 + "-B address set guest_base address to address\n"
  2330 +#endif
2323 2331 "\n"
2324 2332 "Debug options:\n"
2325 2333 "-d options activate log (logfile=%s)\n"
... ... @@ -2495,6 +2503,11 @@ int main(int argc, char **argv, char **envp)
2495 2503 #endif
2496 2504 exit(1);
2497 2505 }
  2506 +#if defined(CONFIG_USE_GUEST_BASE)
  2507 + } else if (!strcmp(r, "B")) {
  2508 + guest_base = strtol(argv[optind++], NULL, 0);
  2509 + have_guest_base = 1;
  2510 +#endif
2498 2511 } else if (!strcmp(r, "drop-ld-preload")) {
2499 2512 (void) envlist_unsetenv(envlist, "LD_PRELOAD");
2500 2513 } else if (!strcmp(r, "singlestep")) {
... ... @@ -2572,6 +2585,35 @@ int main(int argc, char **argv, char **envp)
2572 2585 target_environ = envlist_to_environ(envlist, NULL);
2573 2586 envlist_free(envlist);
2574 2587  
  2588 +#if defined(CONFIG_USE_GUEST_BASE)
  2589 + /*
  2590 + * Now that page sizes are configured in cpu_init() we can do
  2591 + * proper page alignment for guest_base.
  2592 + */
  2593 + guest_base = HOST_PAGE_ALIGN(guest_base);
  2594 +
  2595 + /*
  2596 + * Read in mmap_min_addr kernel parameter. This value is used
  2597 + * When loading the ELF image to determine whether guest_base
  2598 + * is needed.
  2599 + *
  2600 + * When user has explicitly set the quest base, we skip this
  2601 + * test.
  2602 + */
  2603 + if (!have_guest_base) {
  2604 + FILE *fp;
  2605 +
  2606 + if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) {
  2607 + unsigned long tmp;
  2608 + if (fscanf(fp, "%lu", &tmp) == 1) {
  2609 + mmap_min_addr = tmp;
  2610 + qemu_log("host mmap_min_addr=0x%lx\n", mmap_min_addr);
  2611 + }
  2612 + fclose(fp);
  2613 + }
  2614 + }
  2615 +#endif /* CONFIG_USE_GUEST_BASE */
  2616 +
2575 2617 /*
2576 2618 * Prepare copy of argv vector for target.
2577 2619 */
... ... @@ -2622,6 +2664,9 @@ int main(int argc, char **argv, char **envp)
2622 2664 free(target_environ);
2623 2665  
2624 2666 if (qemu_log_enabled()) {
  2667 +#if defined(CONFIG_USE_GUEST_BASE)
  2668 + qemu_log("guest_base 0x%lx\n", guest_base);
  2669 +#endif
2625 2670 log_page_dump();
2626 2671  
2627 2672 qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
... ...
linux-user/qemu.h
... ... @@ -133,6 +133,9 @@ void init_task_state(TaskState *ts);
133 133 void task_settid(TaskState *);
134 134 void stop_all_tasks(void);
135 135 extern const char *qemu_uname_release;
  136 +#if defined(CONFIG_USE_GUEST_BASE)
  137 +extern unsigned long mmap_min_addr;
  138 +#endif
136 139  
137 140 /* ??? See if we can avoid exposing so much of the loader internals. */
138 141 /*
... ...
qemu-doc.texi
... ... @@ -2026,7 +2026,7 @@ qemu-i386 /usr/local/qemu-i386/wine/bin/wine \
2026 2026 @subsection Command line options
2027 2027  
2028 2028 @example
2029   -usage: qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g port] program [arguments...]
  2029 +usage: qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g port] [-B offset] program [arguments...]
2030 2030 @end example
2031 2031  
2032 2032 @table @option
... ... @@ -2038,6 +2038,10 @@ Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386)
2038 2038 Set the x86 stack size in bytes (default=524288)
2039 2039 @item -cpu model
2040 2040 Select CPU model (-cpu ? for list and additional feature selection)
  2041 +@item -B offset
  2042 +Offset guest address by the specified number of bytes. This is useful when
  2043 +the address region rewuired by guest applications is reserved on the host.
  2044 +Ths option is currently only supported on some hosts.
2041 2045 @end table
2042 2046  
2043 2047 Debug options:
... ...
tcg/arm/tcg-target.c
... ... @@ -990,7 +990,22 @@ static inline void tcg_out_qemu_ld(TCGContext *s, int cond,
990 990 # endif
991 991  
992 992 *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2;
993   -#else
  993 +#else /* !CONFIG_SOFTMMU */
  994 + if (GUEST_BASE) {
  995 + uint32_t offset = GUEST_BASE;
  996 + int i;
  997 + int rot;
  998 +
  999 + while (offset) {
  1000 + i = ctz32(offset) & ~1;
  1001 + rot = ((32 - i) << 7) & 0xf00;
  1002 +
  1003 + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 8, addr_reg,
  1004 + ((offset >> i) & 0xff) | rot);
  1005 + addr_reg = 8;
  1006 + offset &= ~(0xff << i);
  1007 + }
  1008 + }
994 1009 switch (opc) {
995 1010 case 0:
996 1011 tcg_out_ld8_12(s, COND_AL, data_reg, addr_reg, 0);
... ... @@ -1200,7 +1215,22 @@ static inline void tcg_out_qemu_st(TCGContext *s, int cond,
1200 1215 # endif
1201 1216  
1202 1217 *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2;
1203   -#else
  1218 +#else /* !CONFIG_SOFTMMU */
  1219 + if (GUEST_BASE) {
  1220 + uint32_t offset = GUEST_BASE;
  1221 + int i;
  1222 + int rot;
  1223 +
  1224 + while (offset) {
  1225 + i = ctz32(offset) & ~1;
  1226 + rot = ((32 - i) << 7) & 0xf00;
  1227 +
  1228 + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 8, addr_reg,
  1229 + ((offset >> i) & 0xff) | rot);
  1230 + addr_reg = 8;
  1231 + offset &= ~(0xff << i);
  1232 + }
  1233 + }
1204 1234 switch (opc) {
1205 1235 case 0:
1206 1236 tcg_out_st8_12(s, COND_AL, data_reg, addr_reg, 0);
... ...
tcg/arm/tcg-target.h
... ... @@ -60,6 +60,8 @@ enum {
60 60 #define TCG_TARGET_STACK_ALIGN 8
61 61 #define TCG_TARGET_CALL_STACK_OFFSET 0
62 62  
  63 +#define TCG_TARGET_HAS_GUEST_BASE
  64 +
63 65 enum {
64 66 /* Note: must be synced with dyngen-exec.h */
65 67 TCG_AREG0 = TCG_REG_R7,
... ...
tcg/i386/tcg-target.c
... ... @@ -427,6 +427,10 @@ static void *qemu_st_helpers[4] = {
427 427 };
428 428 #endif
429 429  
  430 +#ifndef CONFIG_USER_ONLY
  431 +#define GUEST_BASE 0
  432 +#endif
  433 +
430 434 /* XXX: qemu_ld and qemu_st could be modified to clobber only EDX and
431 435 EAX. It will be useful once fixed registers globals are less
432 436 common. */
... ... @@ -572,15 +576,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
572 576 switch(opc) {
573 577 case 0:
574 578 /* movzbl */
575   - tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, 0);
  579 + tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, GUEST_BASE);
576 580 break;
577 581 case 0 | 4:
578 582 /* movsbl */
579   - tcg_out_modrm_offset(s, 0xbe | P_EXT, data_reg, r0, 0);
  583 + tcg_out_modrm_offset(s, 0xbe | P_EXT, data_reg, r0, GUEST_BASE);
580 584 break;
581 585 case 1:
582 586 /* movzwl */
583   - tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, 0);
  587 + tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, GUEST_BASE);
584 588 if (bswap) {
585 589 /* rolw $8, data_reg */
586 590 tcg_out8(s, 0x66);
... ... @@ -590,7 +594,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
590 594 break;
591 595 case 1 | 4:
592 596 /* movswl */
593   - tcg_out_modrm_offset(s, 0xbf | P_EXT, data_reg, r0, 0);
  597 + tcg_out_modrm_offset(s, 0xbf | P_EXT, data_reg, r0, GUEST_BASE);
594 598 if (bswap) {
595 599 /* rolw $8, data_reg */
596 600 tcg_out8(s, 0x66);
... ... @@ -603,7 +607,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
603 607 break;
604 608 case 2:
605 609 /* movl (r0), data_reg */
606   - tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0);
  610 + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE);
607 611 if (bswap) {
608 612 /* bswap */
609 613 tcg_out_opc(s, (0xc8 + data_reg) | P_EXT);
... ... @@ -619,13 +623,13 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
619 623 r0 = r1;
620 624 }
621 625 if (!bswap) {
622   - tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0);
623   - tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, 4);
  626 + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE);
  627 + tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, GUEST+BASE + 4);
624 628 } else {
625   - tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 4);
  629 + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE + 4);
626 630 tcg_out_opc(s, (0xc8 + data_reg) | P_EXT);
627 631  
628   - tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, 0);
  632 + tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, GUEST_BASE);
629 633 /* bswap */
630 634 tcg_out_opc(s, (0xc8 + data_reg2) | P_EXT);
631 635 }
... ... @@ -806,7 +810,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
806 810 switch(opc) {
807 811 case 0:
808 812 /* movb */
809   - tcg_out_modrm_offset(s, 0x88, data_reg, r0, 0);
  813 + tcg_out_modrm_offset(s, 0x88, data_reg, r0, GUEST_BASE);
810 814 break;
811 815 case 1:
812 816 if (bswap) {
... ... @@ -818,7 +822,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
818 822 }
819 823 /* movw */
820 824 tcg_out8(s, 0x66);
821   - tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
  825 + tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE);
822 826 break;
823 827 case 2:
824 828 if (bswap) {
... ... @@ -828,21 +832,21 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
828 832 data_reg = r1;
829 833 }
830 834 /* movl */
831   - tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
  835 + tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE);
832 836 break;
833 837 case 3:
834 838 if (bswap) {
835 839 tcg_out_mov(s, r1, data_reg2);
836 840 /* bswap data_reg */
837 841 tcg_out_opc(s, (0xc8 + r1) | P_EXT);
838   - tcg_out_modrm_offset(s, 0x89, r1, r0, 0);
  842 + tcg_out_modrm_offset(s, 0x89, r1, r0, GUEST_BASE);
839 843 tcg_out_mov(s, r1, data_reg);
840 844 /* bswap data_reg */
841 845 tcg_out_opc(s, (0xc8 + r1) | P_EXT);
842   - tcg_out_modrm_offset(s, 0x89, r1, r0, 4);
  846 + tcg_out_modrm_offset(s, 0x89, r1, r0, GUEST_BASE + 4);
843 847 } else {
844   - tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
845   - tcg_out_modrm_offset(s, 0x89, data_reg2, r0, 4);
  848 + tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE);
  849 + tcg_out_modrm_offset(s, 0x89, data_reg2, r0, GUEST_BASE + 4);
846 850 }
847 851 break;
848 852 default:
... ...
tcg/i386/tcg-target.h
... ... @@ -53,6 +53,8 @@ enum {
53 53 #define TCG_TARGET_HAS_ext16s_i32
54 54 #define TCG_TARGET_HAS_rot_i32
55 55  
  56 +#define TCG_TARGET_HAS_GUEST_BASE
  57 +
56 58 /* Note: must be synced with dyngen-exec.h */
57 59 #define TCG_AREG0 TCG_REG_EBP
58 60 #define TCG_AREG1 TCG_REG_EBX
... ...
tcg/tcg.c
... ... @@ -46,6 +46,7 @@
46 46  
47 47 #include "qemu-common.h"
48 48 #include "cache-utils.h"
  49 +#include "host-utils.h"
49 50  
50 51 /* Note: the long term plan is to reduce the dependancies on the QEMU
51 52 CPU definitions. Currently they are used for qemu_ld/st
... ... @@ -57,6 +58,9 @@
57 58 #include "tcg-op.h"
58 59 #include "elf.h"
59 60  
  61 +#if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
  62 +#error GUEST_BASE not supported on this host.
  63 +#endif
60 64  
61 65 static void patch_reloc(uint8_t *code_ptr, int type,
62 66 tcg_target_long value, tcg_target_long addend);
... ...
tcg/x86_64/tcg-target.c
... ... @@ -508,6 +508,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
508 508 int opc)
509 509 {
510 510 int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw;
  511 + int32_t offset;
511 512 #if defined(CONFIG_SOFTMMU)
512 513 uint8_t *label1_ptr, *label2_ptr;
513 514 #endif
... ... @@ -604,8 +605,20 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
604 605 /* add x(r1), r0 */
605 606 tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) -
606 607 offsetof(CPUTLBEntry, addr_read));
  608 + offset = 0;
607 609 #else
608   - r0 = addr_reg;
  610 + if (GUEST_BASE == (int32_t)GUEST_BASE) {
  611 + r0 = addr_reg;
  612 + offset = GUEST_BASE;
  613 + } else {
  614 + offset = 0;
  615 + /* movq $GUEST_BASE, r0 */
  616 + tcg_out_opc(s, (0xb8 + (r0 & 7)) | P_REXW, 0, r0, 0);
  617 + tcg_out32(s, GUEST_BASE);
  618 + tcg_out32(s, GUEST_BASE >> 32);
  619 + /* addq addr_reg, r0 */
  620 + tcg_out_modrm(s, 0x01 | P_REXW, addr_reg, r0);
  621 + }
609 622 #endif
610 623  
611 624 #ifdef TARGET_WORDS_BIGENDIAN
... ... @@ -616,15 +629,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
616 629 switch(opc) {
617 630 case 0:
618 631 /* movzbl */
619   - tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, 0);
  632 + tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, offset);
620 633 break;
621 634 case 0 | 4:
622 635 /* movsbX */
623   - tcg_out_modrm_offset(s, 0xbe | P_EXT | rexw, data_reg, r0, 0);
  636 + tcg_out_modrm_offset(s, 0xbe | P_EXT | rexw, data_reg, r0, offset);
624 637 break;
625 638 case 1:
626 639 /* movzwl */
627   - tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, 0);
  640 + tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, offset);
628 641 if (bswap) {
629 642 /* rolw $8, data_reg */
630 643 tcg_out8(s, 0x66);
... ... @@ -635,7 +648,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
635 648 case 1 | 4:
636 649 if (bswap) {
637 650 /* movzwl */
638   - tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, 0);
  651 + tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, offset);
639 652 /* rolw $8, data_reg */
640 653 tcg_out8(s, 0x66);
641 654 tcg_out_modrm(s, 0xc1, 0, data_reg);
... ... @@ -645,12 +658,12 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
645 658 tcg_out_modrm(s, 0xbf | P_EXT | rexw, data_reg, data_reg);
646 659 } else {
647 660 /* movswX */
648   - tcg_out_modrm_offset(s, 0xbf | P_EXT | rexw, data_reg, r0, 0);
  661 + tcg_out_modrm_offset(s, 0xbf | P_EXT | rexw, data_reg, r0, offset);
649 662 }
650 663 break;
651 664 case 2:
652 665 /* movl (r0), data_reg */
653   - tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0);
  666 + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, offset);
654 667 if (bswap) {
655 668 /* bswap */
656 669 tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0);
... ... @@ -659,19 +672,19 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
659 672 case 2 | 4:
660 673 if (bswap) {
661 674 /* movl (r0), data_reg */
662   - tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0);
  675 + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, offset);
663 676 /* bswap */
664 677 tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0);
665 678 /* movslq */
666 679 tcg_out_modrm(s, 0x63 | P_REXW, data_reg, data_reg);
667 680 } else {
668 681 /* movslq */
669   - tcg_out_modrm_offset(s, 0x63 | P_REXW, data_reg, r0, 0);
  682 + tcg_out_modrm_offset(s, 0x63 | P_REXW, data_reg, r0, offset);
670 683 }
671 684 break;
672 685 case 3:
673 686 /* movq (r0), data_reg */
674   - tcg_out_modrm_offset(s, 0x8b | P_REXW, data_reg, r0, 0);
  687 + tcg_out_modrm_offset(s, 0x8b | P_REXW, data_reg, r0, offset);
675 688 if (bswap) {
676 689 /* bswap */
677 690 tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT | P_REXW, 0, data_reg, 0);
... ... @@ -691,6 +704,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
691 704 int opc)
692 705 {
693 706 int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw;
  707 + int32_t offset;
694 708 #if defined(CONFIG_SOFTMMU)
695 709 uint8_t *label1_ptr, *label2_ptr;
696 710 #endif
... ... @@ -775,8 +789,20 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
775 789 /* add x(r1), r0 */
776 790 tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) -
777 791 offsetof(CPUTLBEntry, addr_write));
  792 + offset = 0;
778 793 #else
779   - r0 = addr_reg;
  794 + if (GUEST_BASE == (int32_t)GUEST_BASE) {
  795 + r0 = addr_reg;
  796 + offset = GUEST_BASE;
  797 + } else {
  798 + offset = 0;
  799 + /* movq $GUEST_BASE, r0 */
  800 + tcg_out_opc(s, (0xb8 + (r0 & 7)) | P_REXW, 0, r0, 0);
  801 + tcg_out32(s, GUEST_BASE);
  802 + tcg_out32(s, GUEST_BASE >> 32);
  803 + /* addq addr_reg, r0 */
  804 + tcg_out_modrm(s, 0x01 | P_REXW, addr_reg, r0);
  805 + }
780 806 #endif
781 807  
782 808 #ifdef TARGET_WORDS_BIGENDIAN
... ... @@ -787,7 +813,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
787 813 switch(opc) {
788 814 case 0:
789 815 /* movb */
790   - tcg_out_modrm_offset(s, 0x88 | P_REXB, data_reg, r0, 0);
  816 + tcg_out_modrm_offset(s, 0x88 | P_REXB, data_reg, r0, offset);
791 817 break;
792 818 case 1:
793 819 if (bswap) {
... ... @@ -799,7 +825,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
799 825 }
800 826 /* movw */
801 827 tcg_out8(s, 0x66);
802   - tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
  828 + tcg_out_modrm_offset(s, 0x89, data_reg, r0, offset);
803 829 break;
804 830 case 2:
805 831 if (bswap) {
... ... @@ -809,7 +835,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
809 835 data_reg = r1;
810 836 }
811 837 /* movl */
812   - tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
  838 + tcg_out_modrm_offset(s, 0x89, data_reg, r0, offset);
813 839 break;
814 840 case 3:
815 841 if (bswap) {
... ... @@ -819,7 +845,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
819 845 data_reg = r1;
820 846 }
821 847 /* movq */
822   - tcg_out_modrm_offset(s, 0x89 | P_REXW, data_reg, r0, 0);
  848 + tcg_out_modrm_offset(s, 0x89 | P_REXW, data_reg, r0, offset);
823 849 break;
824 850 default:
825 851 tcg_abort();
... ...
tcg/x86_64/tcg-target.h
... ... @@ -73,6 +73,8 @@ enum {
73 73 #define TCG_TARGET_HAS_rot_i32
74 74 #define TCG_TARGET_HAS_rot_i64
75 75  
  76 +#define TCG_TARGET_HAS_GUEST_BASE
  77 +
76 78 /* Note: must be synced with dyngen-exec.h */
77 79 #define TCG_AREG0 TCG_REG_R14
78 80 #define TCG_AREG1 TCG_REG_R15
... ...