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,6 +184,7 @@ softmmu="yes" | ||
184 | linux_user="no" | 184 | linux_user="no" |
185 | darwin_user="no" | 185 | darwin_user="no" |
186 | bsd_user="no" | 186 | bsd_user="no" |
187 | +guest_base="" | ||
187 | build_docs="yes" | 188 | build_docs="yes" |
188 | uname_release="" | 189 | uname_release="" |
189 | curses="yes" | 190 | curses="yes" |
@@ -465,6 +466,10 @@ for opt do | @@ -465,6 +466,10 @@ for opt do | ||
465 | ;; | 466 | ;; |
466 | --enable-bsd-user) bsd_user="yes" | 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 | --enable-uname-release=*) uname_release="$optarg" | 473 | --enable-uname-release=*) uname_release="$optarg" |
469 | ;; | 474 | ;; |
470 | --sparc_cpu=*) | 475 | --sparc_cpu=*) |
@@ -544,6 +549,7 @@ fi | @@ -544,6 +549,7 @@ fi | ||
544 | # If cpu ~= sparc and sparc_cpu hasn't been defined, plug in the right | 549 | # If cpu ~= sparc and sparc_cpu hasn't been defined, plug in the right |
545 | # ARCH_CFLAGS/ARCH_LDFLAGS (assume sparc_v8plus for 32-bit and sparc_v9 for 64-bit) | 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 | case "$cpu" in | 553 | case "$cpu" in |
548 | sparc) if test -z "$sparc_cpu" ; then | 554 | sparc) if test -z "$sparc_cpu" ; then |
549 | ARCH_CFLAGS="-m32 -mcpu=ultrasparc -D__sparc_v8plus__" | 555 | ARCH_CFLAGS="-m32 -mcpu=ultrasparc -D__sparc_v8plus__" |
@@ -576,13 +582,20 @@ case "$cpu" in | @@ -576,13 +582,20 @@ case "$cpu" in | ||
576 | i386) | 582 | i386) |
577 | ARCH_CFLAGS="-m32" | 583 | ARCH_CFLAGS="-m32" |
578 | ARCH_LDFLAGS="-m32" | 584 | ARCH_LDFLAGS="-m32" |
585 | + host_guest_base="yes" | ||
579 | ;; | 586 | ;; |
580 | x86_64) | 587 | x86_64) |
581 | ARCH_CFLAGS="-m64" | 588 | ARCH_CFLAGS="-m64" |
582 | ARCH_LDFLAGS="-m64" | 589 | ARCH_LDFLAGS="-m64" |
590 | + host_guest_base="yes" | ||
591 | + ;; | ||
592 | + arm*) | ||
593 | + host_guest_base="yes" | ||
583 | ;; | 594 | ;; |
584 | esac | 595 | esac |
585 | 596 | ||
597 | +[ -z "$guest_base" ] && guest_base="$host_guest_base" | ||
598 | + | ||
586 | if test x"$show_help" = x"yes" ; then | 599 | if test x"$show_help" = x"yes" ; then |
587 | cat << EOF | 600 | cat << EOF |
588 | 601 | ||
@@ -641,6 +654,9 @@ echo " --enable-darwin-user enable all darwin usermode emulation targets" | @@ -641,6 +654,9 @@ echo " --enable-darwin-user enable all darwin usermode emulation targets" | ||
641 | echo " --disable-darwin-user disable all darwin usermode emulation targets" | 654 | echo " --disable-darwin-user disable all darwin usermode emulation targets" |
642 | echo " --enable-bsd-user enable all BSD usermode emulation targets" | 655 | echo " --enable-bsd-user enable all BSD usermode emulation targets" |
643 | echo " --disable-bsd-user disable all BSD usermode emulation targets" | 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 | echo " --fmod-lib path to FMOD library" | 660 | echo " --fmod-lib path to FMOD library" |
645 | echo " --fmod-inc path to FMOD includes" | 661 | echo " --fmod-inc path to FMOD includes" |
646 | echo " --oss-lib path to OSS library" | 662 | echo " --oss-lib path to OSS library" |
@@ -1446,6 +1462,7 @@ echo "Documentation $build_docs" | @@ -1446,6 +1462,7 @@ echo "Documentation $build_docs" | ||
1446 | [ ! -z "$uname_release" ] && \ | 1462 | [ ! -z "$uname_release" ] && \ |
1447 | echo "uname -r $uname_release" | 1463 | echo "uname -r $uname_release" |
1448 | echo "NPTL support $nptl" | 1464 | echo "NPTL support $nptl" |
1465 | +echo "GUEST_BASE $guest_base" | ||
1449 | echo "vde support $vde" | 1466 | echo "vde support $vde" |
1450 | echo "AIO support $aio" | 1467 | echo "AIO support $aio" |
1451 | echo "IO thread $io_thread" | 1468 | echo "IO thread $io_thread" |
@@ -2070,6 +2087,9 @@ fi | @@ -2070,6 +2087,9 @@ fi | ||
2070 | if test "$target_user_only" = "yes" -a "$elfload32" = "yes"; then | 2087 | if test "$target_user_only" = "yes" -a "$elfload32" = "yes"; then |
2071 | echo "TARGET_HAS_ELFLOAD32=y" >> $config_mak | 2088 | echo "TARGET_HAS_ELFLOAD32=y" >> $config_mak |
2072 | fi | 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 | if test "$target_bsd_user" = "yes" ; then | 2093 | if test "$target_bsd_user" = "yes" ; then |
2074 | echo "CONFIG_BSD_USER=y" >> $config_mak | 2094 | echo "CONFIG_BSD_USER=y" >> $config_mak |
2075 | fi | 2095 | fi |
cpu-all.h
@@ -624,8 +624,13 @@ static inline void stfq_be_p(void *ptr, float64 v) | @@ -624,8 +624,13 @@ static inline void stfq_be_p(void *ptr, float64 v) | ||
624 | /* On some host systems the guest address space is reserved on the host. | 624 | /* On some host systems the guest address space is reserved on the host. |
625 | * This allows the guest address space to be offset to a convenient location. | 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 | /* All direct uses of g2h and h2g need to go away for usermode softmmu. */ | 635 | /* All direct uses of g2h and h2g need to go away for usermode softmmu. */ |
631 | #define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE)) | 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,6 +1545,29 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, | ||
1545 | info->mmap = 0; | 1545 | info->mmap = 0; |
1546 | elf_entry = (abi_ulong) elf_ex.e_entry; | 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 | /* Do this so that we can load the interpreter, if need be. We will | 1571 | /* Do this so that we can load the interpreter, if need be. We will |
1549 | change some of these later */ | 1572 | change some of these later */ |
1550 | info->rss = 0; | 1573 | info->rss = 0; |
linux-user/main.c
@@ -39,6 +39,11 @@ | @@ -39,6 +39,11 @@ | ||
39 | char *exec_path; | 39 | char *exec_path; |
40 | 40 | ||
41 | int singlestep; | 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 | static const char *interp_prefix = CONFIG_QEMU_PREFIX; | 48 | static const char *interp_prefix = CONFIG_QEMU_PREFIX; |
44 | const char *qemu_uname_release = CONFIG_UNAME_RELEASE; | 49 | const char *qemu_uname_release = CONFIG_UNAME_RELEASE; |
@@ -2320,6 +2325,9 @@ static void usage(void) | @@ -2320,6 +2325,9 @@ static void usage(void) | ||
2320 | "-E var=value sets/modifies targets environment variable(s)\n" | 2325 | "-E var=value sets/modifies targets environment variable(s)\n" |
2321 | "-U var unsets targets environment variable(s)\n" | 2326 | "-U var unsets targets environment variable(s)\n" |
2322 | "-0 argv0 forces target process argv[0] to be argv0\n" | 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 | "\n" | 2331 | "\n" |
2324 | "Debug options:\n" | 2332 | "Debug options:\n" |
2325 | "-d options activate log (logfile=%s)\n" | 2333 | "-d options activate log (logfile=%s)\n" |
@@ -2495,6 +2503,11 @@ int main(int argc, char **argv, char **envp) | @@ -2495,6 +2503,11 @@ int main(int argc, char **argv, char **envp) | ||
2495 | #endif | 2503 | #endif |
2496 | exit(1); | 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 | } else if (!strcmp(r, "drop-ld-preload")) { | 2511 | } else if (!strcmp(r, "drop-ld-preload")) { |
2499 | (void) envlist_unsetenv(envlist, "LD_PRELOAD"); | 2512 | (void) envlist_unsetenv(envlist, "LD_PRELOAD"); |
2500 | } else if (!strcmp(r, "singlestep")) { | 2513 | } else if (!strcmp(r, "singlestep")) { |
@@ -2572,6 +2585,35 @@ int main(int argc, char **argv, char **envp) | @@ -2572,6 +2585,35 @@ int main(int argc, char **argv, char **envp) | ||
2572 | target_environ = envlist_to_environ(envlist, NULL); | 2585 | target_environ = envlist_to_environ(envlist, NULL); |
2573 | envlist_free(envlist); | 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 | * Prepare copy of argv vector for target. | 2618 | * Prepare copy of argv vector for target. |
2577 | */ | 2619 | */ |
@@ -2622,6 +2664,9 @@ int main(int argc, char **argv, char **envp) | @@ -2622,6 +2664,9 @@ int main(int argc, char **argv, char **envp) | ||
2622 | free(target_environ); | 2664 | free(target_environ); |
2623 | 2665 | ||
2624 | if (qemu_log_enabled()) { | 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 | log_page_dump(); | 2670 | log_page_dump(); |
2626 | 2671 | ||
2627 | qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk); | 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,6 +133,9 @@ void init_task_state(TaskState *ts); | ||
133 | void task_settid(TaskState *); | 133 | void task_settid(TaskState *); |
134 | void stop_all_tasks(void); | 134 | void stop_all_tasks(void); |
135 | extern const char *qemu_uname_release; | 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 | /* ??? See if we can avoid exposing so much of the loader internals. */ | 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,7 +2026,7 @@ qemu-i386 /usr/local/qemu-i386/wine/bin/wine \ | ||
2026 | @subsection Command line options | 2026 | @subsection Command line options |
2027 | 2027 | ||
2028 | @example | 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 | @end example | 2030 | @end example |
2031 | 2031 | ||
2032 | @table @option | 2032 | @table @option |
@@ -2038,6 +2038,10 @@ Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386) | @@ -2038,6 +2038,10 @@ Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386) | ||
2038 | Set the x86 stack size in bytes (default=524288) | 2038 | Set the x86 stack size in bytes (default=524288) |
2039 | @item -cpu model | 2039 | @item -cpu model |
2040 | Select CPU model (-cpu ? for list and additional feature selection) | 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 | @end table | 2045 | @end table |
2042 | 2046 | ||
2043 | Debug options: | 2047 | Debug options: |
tcg/arm/tcg-target.c
@@ -990,7 +990,22 @@ static inline void tcg_out_qemu_ld(TCGContext *s, int cond, | @@ -990,7 +990,22 @@ static inline void tcg_out_qemu_ld(TCGContext *s, int cond, | ||
990 | # endif | 990 | # endif |
991 | 991 | ||
992 | *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2; | 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 | switch (opc) { | 1009 | switch (opc) { |
995 | case 0: | 1010 | case 0: |
996 | tcg_out_ld8_12(s, COND_AL, data_reg, addr_reg, 0); | 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,7 +1215,22 @@ static inline void tcg_out_qemu_st(TCGContext *s, int cond, | ||
1200 | # endif | 1215 | # endif |
1201 | 1216 | ||
1202 | *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2; | 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 | switch (opc) { | 1234 | switch (opc) { |
1205 | case 0: | 1235 | case 0: |
1206 | tcg_out_st8_12(s, COND_AL, data_reg, addr_reg, 0); | 1236 | tcg_out_st8_12(s, COND_AL, data_reg, addr_reg, 0); |
tcg/arm/tcg-target.h
@@ -60,6 +60,8 @@ enum { | @@ -60,6 +60,8 @@ enum { | ||
60 | #define TCG_TARGET_STACK_ALIGN 8 | 60 | #define TCG_TARGET_STACK_ALIGN 8 |
61 | #define TCG_TARGET_CALL_STACK_OFFSET 0 | 61 | #define TCG_TARGET_CALL_STACK_OFFSET 0 |
62 | 62 | ||
63 | +#define TCG_TARGET_HAS_GUEST_BASE | ||
64 | + | ||
63 | enum { | 65 | enum { |
64 | /* Note: must be synced with dyngen-exec.h */ | 66 | /* Note: must be synced with dyngen-exec.h */ |
65 | TCG_AREG0 = TCG_REG_R7, | 67 | TCG_AREG0 = TCG_REG_R7, |
tcg/i386/tcg-target.c
@@ -427,6 +427,10 @@ static void *qemu_st_helpers[4] = { | @@ -427,6 +427,10 @@ static void *qemu_st_helpers[4] = { | ||
427 | }; | 427 | }; |
428 | #endif | 428 | #endif |
429 | 429 | ||
430 | +#ifndef CONFIG_USER_ONLY | ||
431 | +#define GUEST_BASE 0 | ||
432 | +#endif | ||
433 | + | ||
430 | /* XXX: qemu_ld and qemu_st could be modified to clobber only EDX and | 434 | /* XXX: qemu_ld and qemu_st could be modified to clobber only EDX and |
431 | EAX. It will be useful once fixed registers globals are less | 435 | EAX. It will be useful once fixed registers globals are less |
432 | common. */ | 436 | common. */ |
@@ -572,15 +576,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, | @@ -572,15 +576,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, | ||
572 | switch(opc) { | 576 | switch(opc) { |
573 | case 0: | 577 | case 0: |
574 | /* movzbl */ | 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 | break; | 580 | break; |
577 | case 0 | 4: | 581 | case 0 | 4: |
578 | /* movsbl */ | 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 | break; | 584 | break; |
581 | case 1: | 585 | case 1: |
582 | /* movzwl */ | 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 | if (bswap) { | 588 | if (bswap) { |
585 | /* rolw $8, data_reg */ | 589 | /* rolw $8, data_reg */ |
586 | tcg_out8(s, 0x66); | 590 | tcg_out8(s, 0x66); |
@@ -590,7 +594,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, | @@ -590,7 +594,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, | ||
590 | break; | 594 | break; |
591 | case 1 | 4: | 595 | case 1 | 4: |
592 | /* movswl */ | 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 | if (bswap) { | 598 | if (bswap) { |
595 | /* rolw $8, data_reg */ | 599 | /* rolw $8, data_reg */ |
596 | tcg_out8(s, 0x66); | 600 | tcg_out8(s, 0x66); |
@@ -603,7 +607,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, | @@ -603,7 +607,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, | ||
603 | break; | 607 | break; |
604 | case 2: | 608 | case 2: |
605 | /* movl (r0), data_reg */ | 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 | if (bswap) { | 611 | if (bswap) { |
608 | /* bswap */ | 612 | /* bswap */ |
609 | tcg_out_opc(s, (0xc8 + data_reg) | P_EXT); | 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,13 +623,13 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, | ||
619 | r0 = r1; | 623 | r0 = r1; |
620 | } | 624 | } |
621 | if (!bswap) { | 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 | } else { | 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 | tcg_out_opc(s, (0xc8 + data_reg) | P_EXT); | 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 | /* bswap */ | 633 | /* bswap */ |
630 | tcg_out_opc(s, (0xc8 + data_reg2) | P_EXT); | 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,7 +810,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, | ||
806 | switch(opc) { | 810 | switch(opc) { |
807 | case 0: | 811 | case 0: |
808 | /* movb */ | 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 | break; | 814 | break; |
811 | case 1: | 815 | case 1: |
812 | if (bswap) { | 816 | if (bswap) { |
@@ -818,7 +822,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, | @@ -818,7 +822,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, | ||
818 | } | 822 | } |
819 | /* movw */ | 823 | /* movw */ |
820 | tcg_out8(s, 0x66); | 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 | break; | 826 | break; |
823 | case 2: | 827 | case 2: |
824 | if (bswap) { | 828 | if (bswap) { |
@@ -828,21 +832,21 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, | @@ -828,21 +832,21 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, | ||
828 | data_reg = r1; | 832 | data_reg = r1; |
829 | } | 833 | } |
830 | /* movl */ | 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 | break; | 836 | break; |
833 | case 3: | 837 | case 3: |
834 | if (bswap) { | 838 | if (bswap) { |
835 | tcg_out_mov(s, r1, data_reg2); | 839 | tcg_out_mov(s, r1, data_reg2); |
836 | /* bswap data_reg */ | 840 | /* bswap data_reg */ |
837 | tcg_out_opc(s, (0xc8 + r1) | P_EXT); | 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 | tcg_out_mov(s, r1, data_reg); | 843 | tcg_out_mov(s, r1, data_reg); |
840 | /* bswap data_reg */ | 844 | /* bswap data_reg */ |
841 | tcg_out_opc(s, (0xc8 + r1) | P_EXT); | 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 | } else { | 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 | break; | 851 | break; |
848 | default: | 852 | default: |
tcg/i386/tcg-target.h
@@ -53,6 +53,8 @@ enum { | @@ -53,6 +53,8 @@ enum { | ||
53 | #define TCG_TARGET_HAS_ext16s_i32 | 53 | #define TCG_TARGET_HAS_ext16s_i32 |
54 | #define TCG_TARGET_HAS_rot_i32 | 54 | #define TCG_TARGET_HAS_rot_i32 |
55 | 55 | ||
56 | +#define TCG_TARGET_HAS_GUEST_BASE | ||
57 | + | ||
56 | /* Note: must be synced with dyngen-exec.h */ | 58 | /* Note: must be synced with dyngen-exec.h */ |
57 | #define TCG_AREG0 TCG_REG_EBP | 59 | #define TCG_AREG0 TCG_REG_EBP |
58 | #define TCG_AREG1 TCG_REG_EBX | 60 | #define TCG_AREG1 TCG_REG_EBX |
tcg/tcg.c
@@ -46,6 +46,7 @@ | @@ -46,6 +46,7 @@ | ||
46 | 46 | ||
47 | #include "qemu-common.h" | 47 | #include "qemu-common.h" |
48 | #include "cache-utils.h" | 48 | #include "cache-utils.h" |
49 | +#include "host-utils.h" | ||
49 | 50 | ||
50 | /* Note: the long term plan is to reduce the dependancies on the QEMU | 51 | /* Note: the long term plan is to reduce the dependancies on the QEMU |
51 | CPU definitions. Currently they are used for qemu_ld/st | 52 | CPU definitions. Currently they are used for qemu_ld/st |
@@ -57,6 +58,9 @@ | @@ -57,6 +58,9 @@ | ||
57 | #include "tcg-op.h" | 58 | #include "tcg-op.h" |
58 | #include "elf.h" | 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 | static void patch_reloc(uint8_t *code_ptr, int type, | 65 | static void patch_reloc(uint8_t *code_ptr, int type, |
62 | tcg_target_long value, tcg_target_long addend); | 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,6 +508,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, | ||
508 | int opc) | 508 | int opc) |
509 | { | 509 | { |
510 | int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw; | 510 | int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw; |
511 | + int32_t offset; | ||
511 | #if defined(CONFIG_SOFTMMU) | 512 | #if defined(CONFIG_SOFTMMU) |
512 | uint8_t *label1_ptr, *label2_ptr; | 513 | uint8_t *label1_ptr, *label2_ptr; |
513 | #endif | 514 | #endif |
@@ -604,8 +605,20 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, | @@ -604,8 +605,20 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, | ||
604 | /* add x(r1), r0 */ | 605 | /* add x(r1), r0 */ |
605 | tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) - | 606 | tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) - |
606 | offsetof(CPUTLBEntry, addr_read)); | 607 | offsetof(CPUTLBEntry, addr_read)); |
608 | + offset = 0; | ||
607 | #else | 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 | #endif | 622 | #endif |
610 | 623 | ||
611 | #ifdef TARGET_WORDS_BIGENDIAN | 624 | #ifdef TARGET_WORDS_BIGENDIAN |
@@ -616,15 +629,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, | @@ -616,15 +629,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, | ||
616 | switch(opc) { | 629 | switch(opc) { |
617 | case 0: | 630 | case 0: |
618 | /* movzbl */ | 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 | break; | 633 | break; |
621 | case 0 | 4: | 634 | case 0 | 4: |
622 | /* movsbX */ | 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 | break; | 637 | break; |
625 | case 1: | 638 | case 1: |
626 | /* movzwl */ | 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 | if (bswap) { | 641 | if (bswap) { |
629 | /* rolw $8, data_reg */ | 642 | /* rolw $8, data_reg */ |
630 | tcg_out8(s, 0x66); | 643 | tcg_out8(s, 0x66); |
@@ -635,7 +648,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, | @@ -635,7 +648,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, | ||
635 | case 1 | 4: | 648 | case 1 | 4: |
636 | if (bswap) { | 649 | if (bswap) { |
637 | /* movzwl */ | 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 | /* rolw $8, data_reg */ | 652 | /* rolw $8, data_reg */ |
640 | tcg_out8(s, 0x66); | 653 | tcg_out8(s, 0x66); |
641 | tcg_out_modrm(s, 0xc1, 0, data_reg); | 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,12 +658,12 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, | ||
645 | tcg_out_modrm(s, 0xbf | P_EXT | rexw, data_reg, data_reg); | 658 | tcg_out_modrm(s, 0xbf | P_EXT | rexw, data_reg, data_reg); |
646 | } else { | 659 | } else { |
647 | /* movswX */ | 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 | break; | 663 | break; |
651 | case 2: | 664 | case 2: |
652 | /* movl (r0), data_reg */ | 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 | if (bswap) { | 667 | if (bswap) { |
655 | /* bswap */ | 668 | /* bswap */ |
656 | tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0); | 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,19 +672,19 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, | ||
659 | case 2 | 4: | 672 | case 2 | 4: |
660 | if (bswap) { | 673 | if (bswap) { |
661 | /* movl (r0), data_reg */ | 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 | /* bswap */ | 676 | /* bswap */ |
664 | tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0); | 677 | tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0); |
665 | /* movslq */ | 678 | /* movslq */ |
666 | tcg_out_modrm(s, 0x63 | P_REXW, data_reg, data_reg); | 679 | tcg_out_modrm(s, 0x63 | P_REXW, data_reg, data_reg); |
667 | } else { | 680 | } else { |
668 | /* movslq */ | 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 | break; | 684 | break; |
672 | case 3: | 685 | case 3: |
673 | /* movq (r0), data_reg */ | 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 | if (bswap) { | 688 | if (bswap) { |
676 | /* bswap */ | 689 | /* bswap */ |
677 | tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT | P_REXW, 0, data_reg, 0); | 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,6 +704,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, | ||
691 | int opc) | 704 | int opc) |
692 | { | 705 | { |
693 | int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw; | 706 | int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw; |
707 | + int32_t offset; | ||
694 | #if defined(CONFIG_SOFTMMU) | 708 | #if defined(CONFIG_SOFTMMU) |
695 | uint8_t *label1_ptr, *label2_ptr; | 709 | uint8_t *label1_ptr, *label2_ptr; |
696 | #endif | 710 | #endif |
@@ -775,8 +789,20 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, | @@ -775,8 +789,20 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, | ||
775 | /* add x(r1), r0 */ | 789 | /* add x(r1), r0 */ |
776 | tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) - | 790 | tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) - |
777 | offsetof(CPUTLBEntry, addr_write)); | 791 | offsetof(CPUTLBEntry, addr_write)); |
792 | + offset = 0; | ||
778 | #else | 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 | #endif | 806 | #endif |
781 | 807 | ||
782 | #ifdef TARGET_WORDS_BIGENDIAN | 808 | #ifdef TARGET_WORDS_BIGENDIAN |
@@ -787,7 +813,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, | @@ -787,7 +813,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, | ||
787 | switch(opc) { | 813 | switch(opc) { |
788 | case 0: | 814 | case 0: |
789 | /* movb */ | 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 | break; | 817 | break; |
792 | case 1: | 818 | case 1: |
793 | if (bswap) { | 819 | if (bswap) { |
@@ -799,7 +825,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, | @@ -799,7 +825,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, | ||
799 | } | 825 | } |
800 | /* movw */ | 826 | /* movw */ |
801 | tcg_out8(s, 0x66); | 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 | break; | 829 | break; |
804 | case 2: | 830 | case 2: |
805 | if (bswap) { | 831 | if (bswap) { |
@@ -809,7 +835,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, | @@ -809,7 +835,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, | ||
809 | data_reg = r1; | 835 | data_reg = r1; |
810 | } | 836 | } |
811 | /* movl */ | 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 | break; | 839 | break; |
814 | case 3: | 840 | case 3: |
815 | if (bswap) { | 841 | if (bswap) { |
@@ -819,7 +845,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, | @@ -819,7 +845,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, | ||
819 | data_reg = r1; | 845 | data_reg = r1; |
820 | } | 846 | } |
821 | /* movq */ | 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 | break; | 849 | break; |
824 | default: | 850 | default: |
825 | tcg_abort(); | 851 | tcg_abort(); |
tcg/x86_64/tcg-target.h
@@ -73,6 +73,8 @@ enum { | @@ -73,6 +73,8 @@ enum { | ||
73 | #define TCG_TARGET_HAS_rot_i32 | 73 | #define TCG_TARGET_HAS_rot_i32 |
74 | #define TCG_TARGET_HAS_rot_i64 | 74 | #define TCG_TARGET_HAS_rot_i64 |
75 | 75 | ||
76 | +#define TCG_TARGET_HAS_GUEST_BASE | ||
77 | + | ||
76 | /* Note: must be synced with dyngen-exec.h */ | 78 | /* Note: must be synced with dyngen-exec.h */ |
77 | #define TCG_AREG0 TCG_REG_R14 | 79 | #define TCG_AREG0 TCG_REG_R14 |
78 | #define TCG_AREG1 TCG_REG_R15 | 80 | #define TCG_AREG1 TCG_REG_R15 |