Remove all references to hardwired guest state offsets. Instead,

allow definition of a struct containing the guest state (eg,
VexGuestX86State in pub/libvex_guest_x86.h) and derive all offsets
from that struct.



git-svn-id: svn://svn.valgrind.org/vex/trunk@365
This commit is contained in:
Julian Seward
2004-10-19 01:03:46 +00:00
parent 463706e3c1
commit 4244bdabff
4 changed files with 188 additions and 116 deletions

View File

@@ -144,99 +144,6 @@ typedef
}
Condcode;
/*---------------------------------------------------------*/
/*--- Simulated state offsets ---*/
/*---------------------------------------------------------*/
/* Hmm, subregisters. The simulated state is stored in memory in the
host's byte ordering, so we can't say here what the offsets of %ax,
%al, %ah etc are since that depends on the host's byte ordering,
which we don't know. */
#define OFFB_EAX (0*4)
#define OFFB_ECX (1*4)
#define OFFB_EDX (2*4)
#define OFFB_EBX (3*4)
#define OFFB_ESP (4*4)
#define OFFB_EBP (5*4)
#define OFFB_ESI (6*4)
#define OFFB_EDI (7*4)
/* 3-word thunk used to calculate O S Z A C P flags. */
#define OFFB_CC_OP (8*4)
#define OFFB_CC_SRC (9*4)
#define OFFB_CC_DST (10*4)
/* The D flag is stored here, as either -1 or +1 */
#define OFFB_DFLAG (11*4)
/* EIP */
#define OFFB_EIP (12*4)
/* FPU. For now, just simulate 8 64-bit registers, their tags, and
the reg-stack top pointer, of which only the least significant
three bits are relevant.
The model is:
F0 .. F7 are the 8 registers. FTOP[2:0] contains the
index of the current 'stack top' -- pretty meaningless, but
still. FTOP is a 32-bit value. FTOP[31:3] can be anything
(not guaranteed to be zero).
When a value is pushed onto the stack, ftop is first replaced by
(ftop-1) & 7, and then F[ftop] is assigned the value.
When a value is popped off the stack, the value is read from
F[ftop], and then ftop is replaced by (ftop+1) & 7.
In general, a reference to a register ST(i) actually references
F[ (ftop+i) & 7 ].
FTAG0 .. FTAG0+7 are the tags. Each is a byte, zero means empty,
non-zero means non-empty.
The general rule appears to be that a read or modify of a register
gets a stack underflow fault if the register is empty. A write of
a register (only a write, not a modify) gets a stack overflow fault
if the register is full. Note that "over" vs "under" is pretty
meaningless since the FP stack pointer can move around arbitrarily,
so it's really just two different kinds of exceptions:
register-empty and register full.
Naturally Intel (in its infinite wisdom) has seen fit to throw in
some ad-hoc inconsistencies to the fault-generation rules of the
above para, just to complicate everything. Known inconsistencies:
* fxam can read a register in any state without taking an underflow
fault.
* fst from st(0) to st(i) does not take an overflow fault even if the
destination is already full.
FPUCW[15:0] is the FPU's control word. FPUCW[31:16] is unused.
FC3210 contains the C3, C2, C1 and C0 bits in the same place they
are in the FPU's status word. (bits 14, 10, 9, 8 respectively).
All other bits should be zero. The relevant mask to select just
those bits is 0x4700. To select C3, C2 and C0 only, the mask is
0x4500.
*/
#define OFFB_FTOP (13*4)
#define OFFB_F0 (14*4)
#define OFFB_F1 (16*4)
#define OFFB_F2 (18*4)
#define OFFB_F3 (20*4)
#define OFFB_F4 (22*4)
#define OFFB_F5 (24*4)
#define OFFB_F6 (26*4)
#define OFFB_F7 (28*4)
#define OFFB_FTAG0 (30*4) // up to 30*4 + 7
#define OFFB_FPUCW (32*4)
#define OFFB_FC3210 (33*4)
/* Don't forget to keep this up to date. */
#define SIZEOF_X86H_STATE (OFFB_FC3210 + 4)
#endif /* ndef __LIBVEX_X86GUEST_DEFS_H */
/*---------------------------------------------------------------*/

View File

@@ -1218,12 +1218,13 @@ typedef
/* VISIBLE TO LIBVEX CLIENT */
void x87_to_vex ( /*IN*/UChar* x87_state, /*OUT*/UChar* vex_state )
void x87_to_vex ( /*IN*/UChar* x87_state,
/*OUT*/VexGuestX86State* vex_state )
{
Int r;
UInt tag;
Double* vexRegs = (Double*)(vex_state + OFFB_F0);
UChar* vexTags = (UChar*)(vex_state + OFFB_FTAG0);
Double* vexRegs = (Double*)(&vex_state->guest_FPREG[0]);
UChar* vexTags = (UChar*)(&vex_state->guest_FPTAG[0]);
Fpu_State* x87 = (Fpu_State*)x87_state;
UInt ftop = (x87->env[FP_ENV_STAT] >> 11) & 7;
UInt tagw = x87->env[FP_ENV_TAG];
@@ -1245,32 +1246,33 @@ void x87_to_vex ( /*IN*/UChar* x87_state, /*OUT*/UChar* vex_state )
}
/* stack pointer */
*(UInt*)(vex_state + OFFB_FTOP) = ftop;
vex_state->guest_FTOP = ftop;
/* control word */
*(UInt*)(vex_state + OFFB_FPUCW) = fpucw;
vex_state->guest_FPUCW = fpucw;
/* status word */
*(UInt*)(vex_state + OFFB_FC3210) = c3210;
vex_state->guest_FC3210 = c3210;
}
/* VISIBLE TO LIBVEX CLIENT */
void vex_to_x87 ( /*IN*/UChar* vex_state, /*OUT*/UChar* x87_state )
void vex_to_x87 ( /*IN*/VexGuestX86State* vex_state,
/*OUT*/UChar* x87_state )
{
Int i, r;
UInt tagw;
Double* vexRegs = (Double*)(vex_state + OFFB_F0);
UChar* vexTags = (UChar*)(vex_state + OFFB_FTAG0);
Double* vexRegs = (Double*)(&vex_state->guest_FPREG[0]);
UChar* vexTags = (UChar*)(&vex_state->guest_FPTAG[0]);
Fpu_State* x87 = (Fpu_State*)x87_state;
UInt ftop = *(UInt*)(vex_state + OFFB_FTOP);
UInt c3210 = *(UInt*)(vex_state + OFFB_FC3210);
UInt ftop = vex_state->guest_FTOP;
UInt c3210 = vex_state->guest_FC3210;
for (i = 0; i < 14; i++)
x87->env[i] = 0;
x87->env[1] = x87->env[3] = x87->env[5] = x87->env[13] = 0xFFFF;
x87->env[FP_ENV_CTRL] = (UShort)( *(UInt*)(vex_state + OFFB_FPUCW) );
x87->env[FP_ENV_CTRL] = (UShort)( vex_state->guest_FPUCW );
x87->env[FP_ENV_STAT] = ((ftop & 7) << 11) | (c3210 & 0x4700);
tagw = 0;
@@ -1289,6 +1291,42 @@ void vex_to_x87 ( /*IN*/UChar* vex_state, /*OUT*/UChar* x87_state )
}
/* VISIBLE TO LIBVEX CLIENT */
void eflags_to_vex ( UInt eflags_native,
/*OUT*/VexGuestX86State* vex_state )
{
vex_state->guest_DFLAG
= (eflags_native & (1<<10)) ? 0xFFFFFFFF : 0x00000001;
/* Mask out everything except O S Z A C P. */
eflags_native
&= (CC_MASK_C | CC_MASK_P | CC_MASK_A
| CC_MASK_Z | CC_MASK_S | CC_MASK_O);
vex_state->guest_CC_OP = CC_OP_COPY;
vex_state->guest_CC_DST = 0;
vex_state->guest_CC_DST = eflags_native;
}
/* VISIBLE TO LIBVEX CLIENT */
UInt vex_to_eflags ( /*IN*/VexGuestX86State* vex_state )
{
UInt eflags = calculate_eflags_all(
vex_state->guest_CC_OP,
vex_state->guest_CC_SRC,
vex_state->guest_CC_DST
);
UInt dflag = vex_state->guest_DFLAG;
vassert(dflag == 1 || dflag == 0xFFFFFFFF);
if (dflag == 0xFFFFFFFF)
eflags |= (1<<10);
return eflags;
}
/*---------------------------------------------------------------*/
/*--- end guest-x86/ghelpers.c ---*/
/*---------------------------------------------------------------*/

View File

@@ -27,6 +27,7 @@
#include "libvex_basictypes.h"
#include "libvex_ir.h"
#include "libvex.h"
#include "libvex_guest_x86.h"
#include "main/vex_util.h"
#include "main/vex_globals.h"
@@ -198,6 +199,24 @@ IRBB* bbToIR_X86Instr ( UChar* x86code,
}
/*------------------------------------------------------------*/
/*--- Offsets of various parts of the x86 guest state. ---*/
/*------------------------------------------------------------*/
#define offsetof(type,memb) ((Int)&((type*)0)->memb)
#define OFFB_FPREGS offsetof(VexGuestX86State,guest_FPREG[0])
#define OFFB_FPTAGS offsetof(VexGuestX86State,guest_FPTAG[0])
#define OFFB_EAX offsetof(VexGuestX86State,guest_EAX)
#define OFFB_CC_OP offsetof(VexGuestX86State,guest_CC_OP)
#define OFFB_CC_SRC offsetof(VexGuestX86State,guest_CC_SRC)
#define OFFB_CC_DST offsetof(VexGuestX86State,guest_CC_DST)
#define OFFB_DFLAG offsetof(VexGuestX86State,guest_DFLAG)
#define OFFB_FTOP offsetof(VexGuestX86State,guest_FTOP)
#define OFFB_FC3210 offsetof(VexGuestX86State,guest_FC3210)
#define OFFB_FPUCW offsetof(VexGuestX86State,guest_FPUCW)
/*------------------------------------------------------------*/
/*--- Helper bits and pieces for deconstructing the ---*/
/*--- x86 insn stream. ---*/
@@ -3217,7 +3236,7 @@ static void put_ST_TAG ( Int i, IRExpr* value )
{
IRArray* descr;
vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_I8);
descr = mkIRArray( OFFB_FTAG0, Ity_I8, 8 );
descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
}
@@ -3226,7 +3245,7 @@ static void put_ST_TAG ( Int i, IRExpr* value )
static IRExpr* get_ST_TAG ( Int i )
{
IRArray* descr = mkIRArray( OFFB_FTAG0, Ity_I8, 8 );
IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
return IRExpr_GetI( descr, get_ftop(), i );
}
@@ -3241,7 +3260,7 @@ static void put_ST_UNCHECKED ( Int i, IRExpr* value )
{
IRArray* descr;
vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_F64);
descr = mkIRArray( OFFB_F0, Ity_F64, 8 );
descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
/* Mark the register as in-use. */
put_ST_TAG(i, mkU8(1));
@@ -3269,7 +3288,7 @@ static void put_ST ( Int i, IRExpr* value )
static IRExpr* get_ST_UNCHECKED ( Int i )
{
IRArray* descr = mkIRArray( OFFB_F0, Ity_F64, 8 );
IRArray* descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
return IRExpr_GetI( descr, get_ftop(), i );
}

View File

@@ -11,19 +11,127 @@
#include "libvex_basictypes.h"
/*---------------------------------------------------------------*/
/*--- Vex's representation of the x86 CPU state. ---*/
/*---------------------------------------------------------------*/
/* The integer parts should be pretty straightforward. */
/* Hmm, subregisters. The simulated state is stored in memory in the
host's byte ordering, so we can't say here what the offsets of %ax,
%al, %ah etc are since that depends on the host's byte ordering,
which we don't know. */
/* FPU. For now, just simulate 8 64-bit registers, their tags, and
the reg-stack top pointer, of which only the least significant
three bits are relevant.
The model is:
F0 .. F7 are the 8 registers. FTOP[2:0] contains the
index of the current 'stack top' -- pretty meaningless, but
still. FTOP is a 32-bit value. FTOP[31:3] can be anything
(not guaranteed to be zero).
When a value is pushed onto the stack, ftop is first replaced by
(ftop-1) & 7, and then F[ftop] is assigned the value.
When a value is popped off the stack, the value is read from
F[ftop], and then ftop is replaced by (ftop+1) & 7.
In general, a reference to a register ST(i) actually references
F[ (ftop+i) & 7 ].
FTAG0 .. FTAG0+7 are the tags. Each is a byte, zero means empty,
non-zero means non-empty.
The general rule appears to be that a read or modify of a register
gets a stack underflow fault if the register is empty. A write of
a register (only a write, not a modify) gets a stack overflow fault
if the register is full. Note that "over" vs "under" is pretty
meaningless since the FP stack pointer can move around arbitrarily,
so it's really just two different kinds of exceptions:
register-empty and register full.
Naturally Intel (in its infinite wisdom) has seen fit to throw in
some ad-hoc inconsistencies to the fault-generation rules of the
above para, just to complicate everything. Known inconsistencies:
* fxam can read a register in any state without taking an underflow
fault.
* fst from st(0) to st(i) does not take an overflow fault even if the
destination is already full.
FPUCW[15:0] is the FPU's control word. FPUCW[31:16] is unused.
FC3210 contains the C3, C2, C1 and C0 bits in the same place they
are in the FPU's status word. (bits 14, 10, 9, 8 respectively).
All other bits should be zero. The relevant mask to select just
those bits is 0x4700. To select C3, C2 and C0 only, the mask is
0x4500.
*/
typedef
struct {
UInt guest_EAX;
UInt guest_ECX;
UInt guest_EDX;
UInt guest_EBX;
UInt guest_ESP;
UInt guest_EBP;
UInt guest_ESI;
UInt guest_EDI;
/* 3-word thunk used to calculate O S Z A C P flags. */
UInt guest_CC_OP;
UInt guest_CC_SRC;
UInt guest_CC_DST;
/* The D flag is stored here, as either -1 or +1 */
UInt guest_DFLAG;
/* EIP */
UInt guest_EIP;
/* FPU */
UInt guest_FTOP;
ULong guest_FPREG[8];
UChar guest_FPTAG[8];
UInt guest_FPUCW;
UInt guest_FC3210;
}
VexGuestX86State;
/*---------------------------------------------------------------*/
/*--- Utility functions for x86 guest stuff. ---*/
/*---------------------------------------------------------------*/
/* Convert a saved x87 FPU image (as created by fsave) into the
equivalent vex representation.
/* Convert a saved x87 FPU image (as created by fsave) and write it
into the supplied VexGuestX86State structure. The non-FP parts of
said structure are left unchanged.
*/
extern void x87_to_vex ( /*IN*/UChar* x87_state,
/*OUT*/UChar* vex_state );
extern
void x87_to_vex ( /*IN*/UChar* x87_state,
/*OUT*/VexGuestX86State* vex_state );
/* Extract from the supplied VexGuestX86State structure, an x87 FPU
image. */
extern
void vex_to_x87 ( /*IN*/VexGuestX86State* vex_state,
/*OUT*/UChar* x87_state );
/* Given a 32-bit word containing native x86 %eflags values, set the
eflag-related fields in the supplied VexGuestX86State accordingly.
All other fields are left unchanged. */
extern
void eflags_to_vex ( UInt eflags_native,
/*OUT*/VexGuestX86State* vex_state );
/* Extract from the supplied VexGuestX86State structure the
corresponding native %eflags value. */
extern
UInt vex_to_eflags ( /*IN*/VexGuestX86State* vex_state );
/* Extract from the vex representation, an x87 FPU image. */
extern void vex_to_x87 ( /*IN*/UChar* vex_state,
/*OUT*/UChar* x87_state );
#endif /* ndef __LIBVEX_PUB_GUEST_X86_H */