diff options
author | Paul Brook <paul@codesourcery.com> | 2009-07-17 12:48:08 +0100 |
---|---|---|
committer | Paul Brook <paul@codesourcery.com> | 2009-07-17 13:12:41 +0100 |
commit | 379f6698d73f476de38682b3ff96ecb226728c43 (patch) | |
tree | 35ec0c77416322f16fa27d646af50c60363168e3 | |
parent | a9ff9df188615d653a5a904bafbe724d40143e35 (diff) |
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>
-rwxr-xr-x | configure | 20 | ||||
-rw-r--r-- | cpu-all.h | 9 | ||||
-rw-r--r-- | linux-user/elfload.c | 23 | ||||
-rw-r--r-- | linux-user/main.c | 45 | ||||
-rw-r--r-- | linux-user/qemu.h | 3 | ||||
-rw-r--r-- | qemu-doc.texi | 6 | ||||
-rw-r--r-- | tcg/arm/tcg-target.c | 34 | ||||
-rw-r--r-- | tcg/arm/tcg-target.h | 2 | ||||
-rw-r--r-- | tcg/i386/tcg-target.c | 36 | ||||
-rw-r--r-- | tcg/i386/tcg-target.h | 2 | ||||
-rw-r--r-- | tcg/tcg.c | 4 | ||||
-rw-r--r-- | tcg/x86_64/tcg-target.c | 56 | ||||
-rw-r--r-- | tcg/x86_64/tcg-target.h | 2 |
13 files changed, 206 insertions, 36 deletions
@@ -184,6 +184,7 @@ softmmu="yes" linux_user="no" darwin_user="no" bsd_user="no" +guest_base="" build_docs="yes" uname_release="" curses="yes" @@ -465,6 +466,10 @@ for opt do ;; --enable-bsd-user) bsd_user="yes" ;; + --enable-guest-base) guest_base="yes" + ;; + --disable-guest-base) guest_base="no" + ;; --enable-uname-release=*) uname_release="$optarg" ;; --sparc_cpu=*) @@ -544,6 +549,7 @@ fi # If cpu ~= sparc and sparc_cpu hasn't been defined, plug in the right # ARCH_CFLAGS/ARCH_LDFLAGS (assume sparc_v8plus for 32-bit and sparc_v9 for 64-bit) # +host_guest_base="no" case "$cpu" in sparc) if test -z "$sparc_cpu" ; then ARCH_CFLAGS="-m32 -mcpu=ultrasparc -D__sparc_v8plus__" @@ -576,13 +582,20 @@ case "$cpu" in i386) ARCH_CFLAGS="-m32" ARCH_LDFLAGS="-m32" + host_guest_base="yes" ;; x86_64) ARCH_CFLAGS="-m64" ARCH_LDFLAGS="-m64" + host_guest_base="yes" + ;; + arm*) + host_guest_base="yes" ;; esac +[ -z "$guest_base" ] && guest_base="$host_guest_base" + if test x"$show_help" = x"yes" ; then cat << EOF @@ -641,6 +654,9 @@ echo " --enable-darwin-user enable all darwin usermode emulation targets" echo " --disable-darwin-user disable all darwin usermode emulation targets" echo " --enable-bsd-user enable all BSD usermode emulation targets" echo " --disable-bsd-user disable all BSD usermode emulation targets" +echo " --enable-guest-base enable GUEST_BASE support for usermode" +echo " emulation targets" +echo " --disable-guest-base disable GUEST_BASE support" echo " --fmod-lib path to FMOD library" echo " --fmod-inc path to FMOD includes" echo " --oss-lib path to OSS library" @@ -1446,6 +1462,7 @@ echo "Documentation $build_docs" [ ! -z "$uname_release" ] && \ echo "uname -r $uname_release" echo "NPTL support $nptl" +echo "GUEST_BASE $guest_base" echo "vde support $vde" echo "AIO support $aio" echo "IO thread $io_thread" @@ -2070,6 +2087,9 @@ fi if test "$target_user_only" = "yes" -a "$elfload32" = "yes"; then echo "TARGET_HAS_ELFLOAD32=y" >> $config_mak fi +if test "$target_user_only" = "yes" -a "$guest_base" = "yes"; then + echo "CONFIG_USE_GUEST_BASE=y" >> $config_mak +fi if test "$target_bsd_user" = "yes" ; then echo "CONFIG_BSD_USER=y" >> $config_mak fi @@ -624,8 +624,13 @@ static inline void stfq_be_p(void *ptr, float64 v) /* On some host systems the guest address space is reserved on the host. * This allows the guest address space to be offset to a convenient location. */ -//#define GUEST_BASE 0x20000000 -#define GUEST_BASE 0 +#if defined(CONFIG_USE_GUEST_BASE) +extern unsigned long guest_base; +extern int have_guest_base; +#define GUEST_BASE guest_base +#else +#define GUEST_BASE 0ul +#endif /* All direct uses of g2h and h2g need to go away for usermode softmmu. */ #define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE)) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index d31cca71d1..d4c9274206 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1545,6 +1545,29 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, info->mmap = 0; elf_entry = (abi_ulong) elf_ex.e_entry; +#if defined(CONFIG_USE_GUEST_BASE) + /* + * In case where user has not explicitly set the guest_base, we + * probe here that should we set it automatically. + */ + if (!have_guest_base) { + /* + * Go through ELF program header table and find out whether + * any of the segments drop below our current mmap_min_addr and + * in that case set guest_base to corresponding address. + */ + for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; + i++, elf_ppnt++) { + if (elf_ppnt->p_type != PT_LOAD) + continue; + if (HOST_PAGE_ALIGN(elf_ppnt->p_vaddr) < mmap_min_addr) { + guest_base = HOST_PAGE_ALIGN(mmap_min_addr); + break; + } + } + } +#endif /* CONFIG_USE_GUEST_BASE */ + /* Do this so that we can load the interpreter, if need be. We will change some of these later */ info->rss = 0; diff --git a/linux-user/main.c b/linux-user/main.c index 9038b58e7e..4388c04c9a 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -39,6 +39,11 @@ char *exec_path; int singlestep; +#if defined(CONFIG_USE_GUEST_BASE) +unsigned long mmap_min_addr; +unsigned long guest_base; +int have_guest_base; +#endif static const char *interp_prefix = CONFIG_QEMU_PREFIX; const char *qemu_uname_release = CONFIG_UNAME_RELEASE; @@ -2320,6 +2325,9 @@ static void usage(void) "-E var=value sets/modifies targets environment variable(s)\n" "-U var unsets targets environment variable(s)\n" "-0 argv0 forces target process argv[0] to be argv0\n" +#if defined(CONFIG_USE_GUEST_BASE) + "-B address set guest_base address to address\n" +#endif "\n" "Debug options:\n" "-d options activate log (logfile=%s)\n" @@ -2495,6 +2503,11 @@ int main(int argc, char **argv, char **envp) #endif exit(1); } +#if defined(CONFIG_USE_GUEST_BASE) + } else if (!strcmp(r, "B")) { + guest_base = strtol(argv[optind++], NULL, 0); + have_guest_base = 1; +#endif } else if (!strcmp(r, "drop-ld-preload")) { (void) envlist_unsetenv(envlist, "LD_PRELOAD"); } else if (!strcmp(r, "singlestep")) { @@ -2572,6 +2585,35 @@ int main(int argc, char **argv, char **envp) target_environ = envlist_to_environ(envlist, NULL); envlist_free(envlist); +#if defined(CONFIG_USE_GUEST_BASE) + /* + * Now that page sizes are configured in cpu_init() we can do + * proper page alignment for guest_base. + */ + guest_base = HOST_PAGE_ALIGN(guest_base); + + /* + * Read in mmap_min_addr kernel parameter. This value is used + * When loading the ELF image to determine whether guest_base + * is needed. + * + * When user has explicitly set the quest base, we skip this + * test. + */ + if (!have_guest_base) { + FILE *fp; + + if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) { + unsigned long tmp; + if (fscanf(fp, "%lu", &tmp) == 1) { + mmap_min_addr = tmp; + qemu_log("host mmap_min_addr=0x%lx\n", mmap_min_addr); + } + fclose(fp); + } + } +#endif /* CONFIG_USE_GUEST_BASE */ + /* * Prepare copy of argv vector for target. */ @@ -2622,6 +2664,9 @@ int main(int argc, char **argv, char **envp) free(target_environ); if (qemu_log_enabled()) { +#if defined(CONFIG_USE_GUEST_BASE) + qemu_log("guest_base 0x%lx\n", guest_base); +#endif log_page_dump(); qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk); diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 83ad443c23..8e728a3d28 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -133,6 +133,9 @@ void init_task_state(TaskState *ts); void task_settid(TaskState *); void stop_all_tasks(void); extern const char *qemu_uname_release; +#if defined(CONFIG_USE_GUEST_BASE) +extern unsigned long mmap_min_addr; +#endif /* ??? See if we can avoid exposing so much of the loader internals. */ /* diff --git a/qemu-doc.texi b/qemu-doc.texi index 7747e2733d..68a684277b 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2026,7 +2026,7 @@ qemu-i386 /usr/local/qemu-i386/wine/bin/wine \ @subsection Command line options @example -usage: qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g port] program [arguments...] +usage: qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g port] [-B offset] program [arguments...] @end example @table @option @@ -2038,6 +2038,10 @@ Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386) Set the x86 stack size in bytes (default=524288) @item -cpu model Select CPU model (-cpu ? for list and additional feature selection) +@item -B offset +Offset guest address by the specified number of bytes. This is useful when +the address region rewuired by guest applications is reserved on the host. +Ths option is currently only supported on some hosts. @end table Debug options: diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index 1edcd103f3..6cfe1d6670 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -990,7 +990,22 @@ static inline void tcg_out_qemu_ld(TCGContext *s, int cond, # endif *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2; -#else +#else /* !CONFIG_SOFTMMU */ + if (GUEST_BASE) { + uint32_t offset = GUEST_BASE; + int i; + int rot; + + while (offset) { + i = ctz32(offset) & ~1; + rot = ((32 - i) << 7) & 0xf00; + + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 8, addr_reg, + ((offset >> i) & 0xff) | rot); + addr_reg = 8; + offset &= ~(0xff << i); + } + } switch (opc) { case 0: 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, # endif *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2; -#else +#else /* !CONFIG_SOFTMMU */ + if (GUEST_BASE) { + uint32_t offset = GUEST_BASE; + int i; + int rot; + + while (offset) { + i = ctz32(offset) & ~1; + rot = ((32 - i) << 7) & 0xf00; + + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 8, addr_reg, + ((offset >> i) & 0xff) | rot); + addr_reg = 8; + offset &= ~(0xff << i); + } + } switch (opc) { case 0: tcg_out_st8_12(s, COND_AL, data_reg, addr_reg, 0); diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h index 78ab8fd3e5..ffa9ceeca0 100644 --- a/tcg/arm/tcg-target.h +++ b/tcg/arm/tcg-target.h @@ -60,6 +60,8 @@ enum { #define TCG_TARGET_STACK_ALIGN 8 #define TCG_TARGET_CALL_STACK_OFFSET 0 +#define TCG_TARGET_HAS_GUEST_BASE + enum { /* Note: must be synced with dyngen-exec.h */ TCG_AREG0 = TCG_REG_R7, diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index e0fd434620..ed61780e67 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -427,6 +427,10 @@ static void *qemu_st_helpers[4] = { }; #endif +#ifndef CONFIG_USER_ONLY +#define GUEST_BASE 0 +#endif + /* XXX: qemu_ld and qemu_st could be modified to clobber only EDX and EAX. It will be useful once fixed registers globals are less common. */ @@ -572,15 +576,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, switch(opc) { case 0: /* movzbl */ - tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, GUEST_BASE); break; case 0 | 4: /* movsbl */ - tcg_out_modrm_offset(s, 0xbe | P_EXT, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0xbe | P_EXT, data_reg, r0, GUEST_BASE); break; case 1: /* movzwl */ - tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, GUEST_BASE); if (bswap) { /* rolw $8, data_reg */ tcg_out8(s, 0x66); @@ -590,7 +594,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, break; case 1 | 4: /* movswl */ - tcg_out_modrm_offset(s, 0xbf | P_EXT, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0xbf | P_EXT, data_reg, r0, GUEST_BASE); if (bswap) { /* rolw $8, data_reg */ tcg_out8(s, 0x66); @@ -603,7 +607,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, break; case 2: /* movl (r0), data_reg */ - tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE); if (bswap) { /* bswap */ tcg_out_opc(s, (0xc8 + data_reg) | P_EXT); @@ -619,13 +623,13 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, r0 = r1; } if (!bswap) { - tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0); - tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, 4); + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE); + tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, GUEST+BASE + 4); } else { - tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 4); + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE + 4); tcg_out_opc(s, (0xc8 + data_reg) | P_EXT); - tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, 0); + tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, GUEST_BASE); /* bswap */ tcg_out_opc(s, (0xc8 + data_reg2) | P_EXT); } @@ -806,7 +810,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, switch(opc) { case 0: /* movb */ - tcg_out_modrm_offset(s, 0x88, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0x88, data_reg, r0, GUEST_BASE); break; case 1: if (bswap) { @@ -818,7 +822,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, } /* movw */ tcg_out8(s, 0x66); - tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE); break; case 2: if (bswap) { @@ -828,21 +832,21 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, data_reg = r1; } /* movl */ - tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE); break; case 3: if (bswap) { tcg_out_mov(s, r1, data_reg2); /* bswap data_reg */ tcg_out_opc(s, (0xc8 + r1) | P_EXT); - tcg_out_modrm_offset(s, 0x89, r1, r0, 0); + tcg_out_modrm_offset(s, 0x89, r1, r0, GUEST_BASE); tcg_out_mov(s, r1, data_reg); /* bswap data_reg */ tcg_out_opc(s, (0xc8 + r1) | P_EXT); - tcg_out_modrm_offset(s, 0x89, r1, r0, 4); + tcg_out_modrm_offset(s, 0x89, r1, r0, GUEST_BASE + 4); } else { - tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0); - tcg_out_modrm_offset(s, 0x89, data_reg2, r0, 4); + tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE); + tcg_out_modrm_offset(s, 0x89, data_reg2, r0, GUEST_BASE + 4); } break; default: diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index 301a5bf142..461ef315c6 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -53,6 +53,8 @@ enum { #define TCG_TARGET_HAS_ext16s_i32 #define TCG_TARGET_HAS_rot_i32 +#define TCG_TARGET_HAS_GUEST_BASE + /* Note: must be synced with dyngen-exec.h */ #define TCG_AREG0 TCG_REG_EBP #define TCG_AREG1 TCG_REG_EBX @@ -46,6 +46,7 @@ #include "qemu-common.h" #include "cache-utils.h" +#include "host-utils.h" /* Note: the long term plan is to reduce the dependancies on the QEMU CPU definitions. Currently they are used for qemu_ld/st @@ -57,6 +58,9 @@ #include "tcg-op.h" #include "elf.h" +#if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE) +#error GUEST_BASE not supported on this host. +#endif static void patch_reloc(uint8_t *code_ptr, int type, tcg_target_long value, tcg_target_long addend); diff --git a/tcg/x86_64/tcg-target.c b/tcg/x86_64/tcg-target.c index 5378e8510b..9facb01e41 100644 --- a/tcg/x86_64/tcg-target.c +++ b/tcg/x86_64/tcg-target.c @@ -508,6 +508,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) { int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw; + int32_t offset; #if defined(CONFIG_SOFTMMU) uint8_t *label1_ptr, *label2_ptr; #endif @@ -604,8 +605,20 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, /* add x(r1), r0 */ tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_read)); + offset = 0; #else - r0 = addr_reg; + if (GUEST_BASE == (int32_t)GUEST_BASE) { + r0 = addr_reg; + offset = GUEST_BASE; + } else { + offset = 0; + /* movq $GUEST_BASE, r0 */ + tcg_out_opc(s, (0xb8 + (r0 & 7)) | P_REXW, 0, r0, 0); + tcg_out32(s, GUEST_BASE); + tcg_out32(s, GUEST_BASE >> 32); + /* addq addr_reg, r0 */ + tcg_out_modrm(s, 0x01 | P_REXW, addr_reg, r0); + } #endif #ifdef TARGET_WORDS_BIGENDIAN @@ -616,15 +629,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, switch(opc) { case 0: /* movzbl */ - tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, offset); break; case 0 | 4: /* movsbX */ - tcg_out_modrm_offset(s, 0xbe | P_EXT | rexw, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0xbe | P_EXT | rexw, data_reg, r0, offset); break; case 1: /* movzwl */ - tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, offset); if (bswap) { /* rolw $8, data_reg */ tcg_out8(s, 0x66); @@ -635,7 +648,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, case 1 | 4: if (bswap) { /* movzwl */ - tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, offset); /* rolw $8, data_reg */ tcg_out8(s, 0x66); tcg_out_modrm(s, 0xc1, 0, data_reg); @@ -645,12 +658,12 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, tcg_out_modrm(s, 0xbf | P_EXT | rexw, data_reg, data_reg); } else { /* movswX */ - tcg_out_modrm_offset(s, 0xbf | P_EXT | rexw, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0xbf | P_EXT | rexw, data_reg, r0, offset); } break; case 2: /* movl (r0), data_reg */ - tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, offset); if (bswap) { /* bswap */ 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, case 2 | 4: if (bswap) { /* movl (r0), data_reg */ - tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, offset); /* bswap */ tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0); /* movslq */ tcg_out_modrm(s, 0x63 | P_REXW, data_reg, data_reg); } else { /* movslq */ - tcg_out_modrm_offset(s, 0x63 | P_REXW, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0x63 | P_REXW, data_reg, r0, offset); } break; case 3: /* movq (r0), data_reg */ - tcg_out_modrm_offset(s, 0x8b | P_REXW, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0x8b | P_REXW, data_reg, r0, offset); if (bswap) { /* bswap */ 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, int opc) { int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw; + int32_t offset; #if defined(CONFIG_SOFTMMU) uint8_t *label1_ptr, *label2_ptr; #endif @@ -775,8 +789,20 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, /* add x(r1), r0 */ tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_write)); + offset = 0; #else - r0 = addr_reg; + if (GUEST_BASE == (int32_t)GUEST_BASE) { + r0 = addr_reg; + offset = GUEST_BASE; + } else { + offset = 0; + /* movq $GUEST_BASE, r0 */ + tcg_out_opc(s, (0xb8 + (r0 & 7)) | P_REXW, 0, r0, 0); + tcg_out32(s, GUEST_BASE); + tcg_out32(s, GUEST_BASE >> 32); + /* addq addr_reg, r0 */ + tcg_out_modrm(s, 0x01 | P_REXW, addr_reg, r0); + } #endif #ifdef TARGET_WORDS_BIGENDIAN @@ -787,7 +813,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, switch(opc) { case 0: /* movb */ - tcg_out_modrm_offset(s, 0x88 | P_REXB, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0x88 | P_REXB, data_reg, r0, offset); break; case 1: if (bswap) { @@ -799,7 +825,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, } /* movw */ tcg_out8(s, 0x66); - tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0x89, data_reg, r0, offset); break; case 2: if (bswap) { @@ -809,7 +835,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, data_reg = r1; } /* movl */ - tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0x89, data_reg, r0, offset); break; case 3: if (bswap) { @@ -819,7 +845,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, data_reg = r1; } /* movq */ - tcg_out_modrm_offset(s, 0x89 | P_REXW, data_reg, r0, 0); + tcg_out_modrm_offset(s, 0x89 | P_REXW, data_reg, r0, offset); break; default: tcg_abort(); diff --git a/tcg/x86_64/tcg-target.h b/tcg/x86_64/tcg-target.h index 8cb05c6328..8d47e78738 100644 --- a/tcg/x86_64/tcg-target.h +++ b/tcg/x86_64/tcg-target.h @@ -73,6 +73,8 @@ enum { #define TCG_TARGET_HAS_rot_i32 #define TCG_TARGET_HAS_rot_i64 +#define TCG_TARGET_HAS_GUEST_BASE + /* Note: must be synced with dyngen-exec.h */ #define TCG_AREG0 TCG_REG_R14 #define TCG_AREG1 TCG_REG_R15 |