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>
This commit is contained in:
Paul Brook 2009-07-17 12:48:08 +01:00
parent a9ff9df188
commit 379f6698d7
13 changed files with 206 additions and 36 deletions

20
configure vendored
View file

@ -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

View file

@ -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))

View file

@ -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;

View file

@ -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);

View file

@ -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. */
/*

View file

@ -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:

View file

@ -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);

View file

@ -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,

View file

@ -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:

View file

@ -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

View file

@ -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);

View file

@ -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();

View file

@ -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