From 4244bdabff56d443c4c882ff89d0ea2aae4c0937 Mon Sep 17 00:00:00 2001 From: Julian Seward Date: Tue, 19 Oct 2004 01:03:46 +0000 Subject: [PATCH] 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 --- VEX/priv/guest-x86/gdefs.h | 93 -------------------------- VEX/priv/guest-x86/ghelpers.c | 62 +++++++++++++---- VEX/priv/guest-x86/toIR.c | 27 ++++++-- VEX/pub/libvex_guest_x86.h | 122 ++++++++++++++++++++++++++++++++-- 4 files changed, 188 insertions(+), 116 deletions(-) diff --git a/VEX/priv/guest-x86/gdefs.h b/VEX/priv/guest-x86/gdefs.h index 521ccf6b5..758fe6837 100644 --- a/VEX/priv/guest-x86/gdefs.h +++ b/VEX/priv/guest-x86/gdefs.h @@ -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 */ /*---------------------------------------------------------------*/ diff --git a/VEX/priv/guest-x86/ghelpers.c b/VEX/priv/guest-x86/ghelpers.c index 13b5cec42..ecc12226b 100644 --- a/VEX/priv/guest-x86/ghelpers.c +++ b/VEX/priv/guest-x86/ghelpers.c @@ -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 ---*/ /*---------------------------------------------------------------*/ diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index 310f30f9b..5b2773d3b 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -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 ); } diff --git a/VEX/pub/libvex_guest_x86.h b/VEX/pub/libvex_guest_x86.h index cf71dc20a..efa64331a 100644 --- a/VEX/pub/libvex_guest_x86.h +++ b/VEX/pub/libvex_guest_x86.h @@ -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 */