Commit 379f6698d73f476de38682b3ff96ecb226728c43
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>
Showing
13 changed files
with
206 additions
and
36 deletions
configure
... | ... | @@ -184,6 +184,7 @@ softmmu="yes" |
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 "$cpu" 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 " --enable-darwin-user enable all darwin usermode emulation targets" |
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 "Documentation $build_docs" |
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
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
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