提交 379f6698 编写于 作者: P Paul Brook

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: NRiku Voipio <riku.voipio@iki.fi>
Signed-off-by: NPaul Brook <paul@codesourcery.com>
上级 a9ff9df1
......@@ -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))
......
......@@ -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;
......
......@@ -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);
......
......@@ -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. */
/*
......
......@@ -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:
......
......@@ -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);
......
......@@ -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,
......
......@@ -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:
......
......@@ -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);
......
......@@ -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();
......
......@@ -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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册