382 lines
11 KiB
C++
382 lines
11 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
/*
|
|
x86Opcode.h
|
|
|
|
desantis
|
|
simon
|
|
|
|
NOTE:
|
|
This file is being phased out -- please do not add to it without speaking to simon
|
|
*/
|
|
|
|
#ifndef _X86OPCODE
|
|
#define _X86OPCODE
|
|
|
|
#include "CatchAssert.h"
|
|
#include <stdio.h>
|
|
|
|
#include "Fundamentals.h"
|
|
#include "LogModule.h"
|
|
|
|
class x86ArgumentList;
|
|
class x86ArgListInstruction;
|
|
|
|
//================================================================================
|
|
// enums
|
|
enum x86NoArgsCode
|
|
{
|
|
opCdq,
|
|
opBreak,
|
|
opSahf
|
|
};
|
|
|
|
enum x86DoubleOpCode
|
|
{
|
|
opMul,
|
|
opMovSxB,
|
|
opMovSxH,
|
|
opMovZxB,
|
|
opMovZxH
|
|
};
|
|
|
|
enum x86DoubleOpDirCode
|
|
{
|
|
raAdd,
|
|
raAdc,
|
|
raSub,
|
|
raSbb,
|
|
raAnd,
|
|
raOr,
|
|
raXor,
|
|
raCmp,
|
|
|
|
raLoadI,
|
|
raCopyI,
|
|
raStoreI,
|
|
raSaveReg,
|
|
|
|
raStoreB,
|
|
raStoreH
|
|
};
|
|
|
|
// Floating-point instructions in which one operand is a memory location.
|
|
// If there is a second operand, then it is implicitly the top of the FPU stack.
|
|
enum x86FloatMemoryType
|
|
{
|
|
fstp32, // TOS => 32-bit float memory. Pop FPU.
|
|
fstp64, // TOS => 64-bit double memory. Pop FPU.
|
|
fst32, // TOS => 32-bit float memory. (Don't pop FPU stack.)
|
|
fst64, // TOS => 64-bit double memory. (Don't pop FPU stack.)
|
|
fistp32, // Round(TOS) => 32-bit int memory. Pop FPU.
|
|
fistp64, // Round(TOS) => 64-bit long memory. Pop FPU.
|
|
fld32, // 32-bit float memory => Push on FPU stack
|
|
fld64, // 64-bit float memory => Push on FPU stack
|
|
fild32, // 32-bit int memory => convert to FP and push on FPU stack
|
|
fild64, // 64-bit long memory => convert to FP and push on FPU stack
|
|
fadd32, // Add TOS and 32-bit float memory => replace TOS
|
|
fadd64, // Add TOS and 64-bit double memory => replace TOS
|
|
fmul32, // Multiply TOS and 32-bit float memory => replace TOS
|
|
fmul64, // Multiply TOS and 64-bit double memory => replace TOS
|
|
fsub32, // Subtract TOS from 32-bit float memory => replace TOS
|
|
fsub64, // Subtract TOS from 64-bit double memory => replace TOS
|
|
fsubr32, // Subtract 32-bit float memory from TOS => replace TOS
|
|
fsubr64, // Subtract 64-bit double memory from TOS => replace TOS
|
|
fdiv32, // Divide TOS by 32-bit float memory => replace TOS
|
|
fdiv64, // Divide TOS by 64-bit double memory => replace TOS
|
|
fcomp32, // Compare TOS to 32-bit float memory, setting FPU flags, pop TOS
|
|
fcomp64 // Compare TOS to 64-bit double memory, setting FPU flags, pop TOS
|
|
};
|
|
|
|
// enums for the x96 conidtion code
|
|
enum x86ConditionCode
|
|
{
|
|
ccJO = 0x00,
|
|
ccJNO = 0x01,
|
|
ccJB = 0x02,
|
|
ccJNB = 0x03,
|
|
ccJE = 0x04,
|
|
ccJNE = 0x05,
|
|
ccJBE = 0x06,
|
|
ccJNBE = 0x07,
|
|
ccJS = 0x08,
|
|
ccJNS = 0x09,
|
|
ccJP = 0x0a,
|
|
ccJNP = 0x0b,
|
|
ccJL = 0x0c,
|
|
ccJNL = 0x0d,
|
|
ccJLE = 0x0e,
|
|
ccJNLE = 0x0f
|
|
};
|
|
|
|
/*================================================================================
|
|
x86 Opcodes
|
|
- Can be one byte or two bytes in length. If two bytes, the first byte is 0x0f.
|
|
- Can have bits to control:
|
|
- data flow direction(D),
|
|
- sign extension(S) // FIX pete, isn't this 'size' not 'sign'?
|
|
- conditions (cond), and
|
|
- register field
|
|
- opcode extensions (Reg).
|
|
- Can have an alternate (condensed) encoding which allows a single register operand to be encoded in the opcode.
|
|
*/
|
|
|
|
enum x86GPR
|
|
{
|
|
EAX = 0,
|
|
ECX = 1,
|
|
EDX = 2,
|
|
EBX = 3,
|
|
ESP = 4,
|
|
EBP = 5,
|
|
ESI = 6,
|
|
EDI = 7,
|
|
NOT_A_REG = 255
|
|
};
|
|
|
|
// bit masks
|
|
const int kRegfield_Mask = 0x38; // 0b00111000
|
|
const int kIs_Memory_Form_Mask = 0x40; // 0b01000000
|
|
const int kCondition_Code_Mask = 0x0f; // 0b00001111
|
|
const int kCondensed_Op_Mask = 0xf8; // 0b11111000
|
|
const int kIs_2_Byte_Mask = 0x80; // 0b10000000
|
|
const int kIs_16_Bit_Mask = 0x40; // 0b01000000
|
|
const int kExtension_Mask = 0x40; // 0b01000000
|
|
|
|
const int kPrefix_For_16_Bits = 0x66;
|
|
const int kPrefix_For_2_Byte = 0x0f; // 0b00001111
|
|
|
|
/*--------------------------------------------------------------------------------
|
|
Opcode Information
|
|
*/
|
|
struct x86OpcodeInfo
|
|
{
|
|
uint8 oiBaseOpcode; // generally the opcode, but can have additional info
|
|
uint8 oiOpcodeInformation; // additional info about opcode
|
|
char* oiText; // string for fake disassembly
|
|
};
|
|
|
|
extern x86OpcodeInfo iaInfo[];
|
|
enum x86ImmediateArithType
|
|
{
|
|
iaAddImm,
|
|
iaCmpImm,
|
|
iaJmp,
|
|
iaPushImm,
|
|
iaAndImm,
|
|
iaOrImm,
|
|
iaXorImm
|
|
};
|
|
|
|
extern x86OpcodeInfo eInfo[];
|
|
enum x86ExtendedType
|
|
{
|
|
eIDiv,
|
|
eDiv,
|
|
eMul,
|
|
eMoveImm,
|
|
ePush,
|
|
eSarImm,
|
|
eShrImm,
|
|
eShlImm,
|
|
eSar1,
|
|
eShr1,
|
|
eShl1,
|
|
eSarCl,
|
|
eShrCl,
|
|
eShlCl,
|
|
eNeg
|
|
};
|
|
|
|
extern x86OpcodeInfo ceInfo[];
|
|
enum x86CondensableExtendedType
|
|
{
|
|
ceInc,
|
|
ceDec,
|
|
ceMoveImm,
|
|
cePop
|
|
};
|
|
|
|
extern x86OpcodeInfo srmInfo[];
|
|
enum x86SpecialRegMemType
|
|
{
|
|
srmCmpImm0,
|
|
srm1NOTUSED,
|
|
srmMoveImm0,
|
|
srm3NOTUSED
|
|
};
|
|
|
|
//================================================================================
|
|
// Class Declarations
|
|
|
|
/*--------------------------------------------------------------------------------
|
|
x86Opcode -- encodes x86StandardType
|
|
|
|
Basic opcode
|
|
- 8 or 16 bits
|
|
- no toggable bits and
|
|
- does NOT have a register field opcode extension or alternate encoding.
|
|
*/
|
|
class x86Opcode
|
|
{
|
|
public:
|
|
virtual void opPrintPretty(LogModuleObject &f) { UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("%-9s", opInfo->oiText)); }
|
|
virtual uint8 opSize() { return( (opInfo->oiOpcodeInformation >> 7) + 1); }
|
|
virtual void opFormatToMemory(void* inStart, x86ArgumentList& /*inAL*/, x86ArgListInstruction& /*inInsn*/);
|
|
|
|
virtual bool opHasRegFieldExtension( x86ArgumentList& /*inAL*/, x86ArgListInstruction& /*inInsn*/ ) { return (false); }
|
|
virtual uint8 opGetRegFieldExtension() { assert(false); return 0; }
|
|
|
|
virtual bool opRegOperandCanBeCondensed() { return false; }
|
|
|
|
virtual void opReverseOperands() { assert(false); }
|
|
|
|
virtual void opSwitchToRegisterIndirect() { }
|
|
|
|
virtual bool opCanAccept1ByteImmediate() { assert(false); return false; }
|
|
virtual bool opCanAccept4ByteImmediate() { assert(false); return false; }
|
|
|
|
protected:
|
|
x86Opcode() {}
|
|
x86Opcode( x86ImmediateArithType inType ) { opInfo = &(iaInfo[inType]); }
|
|
x86Opcode( x86ExtendedType inType ) { opInfo = &(eInfo[inType]); }
|
|
x86Opcode( x86CondensableExtendedType inType ) { opInfo = &(ceInfo[inType]); }
|
|
x86Opcode( x86SpecialRegMemType inType ) { opInfo = &(srmInfo[inType]); }
|
|
x86OpcodeInfo* opInfo;
|
|
};
|
|
|
|
inline void x86Opcode::
|
|
opFormatToMemory(void* inStart, x86ArgumentList& /*inAL*/, x86ArgListInstruction& /*inInsn*/)
|
|
{
|
|
uint8* start = (uint8*) inStart;
|
|
if(opInfo->oiOpcodeInformation & kIs_2_Byte_Mask)
|
|
*start++ = kPrefix_For_2_Byte;
|
|
*start = opInfo->oiBaseOpcode;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------------
|
|
x86Opcode_Reg -- encodes x86EntendedType
|
|
|
|
- no switchable bits
|
|
- three bit opcode extension (stored in the REG field of the MODR/M byte)
|
|
*/
|
|
class x86Opcode_Reg :
|
|
public virtual x86Opcode
|
|
{
|
|
public:
|
|
x86Opcode_Reg ( x86ExtendedType inInfo ) : x86Opcode(inInfo) { }
|
|
|
|
virtual bool opHasRegFieldExtension( x86ArgumentList& /*inAL*/, x86ArgListInstruction& /*inInsn*/ ) { return true; }
|
|
virtual uint8 opGetRegFieldExtension() { return (kRegfield_Mask & opInfo->oiOpcodeInformation); }
|
|
|
|
virtual bool opCanAccept1ByteImmediate() { return ((0x02 & opInfo->oiOpcodeInformation) == 0x02); }
|
|
virtual bool opCanAccept4ByteImmediate() { return ((0x01 & opInfo->oiOpcodeInformation) == 0x01); }
|
|
|
|
protected:
|
|
x86Opcode_Reg() { }
|
|
};
|
|
|
|
/*--------------------------------------------------------------------------------
|
|
x86Opcode_Condensable_Reg -- encodes x86CondensableExtendedType
|
|
|
|
- no switchable bits
|
|
- three bit opcode extension (stored in the REG field of the MODR/M byte)
|
|
- alternate encoding which has a 5-bit opcode + 3-bit register operand
|
|
*/
|
|
class x86Opcode_Condensable_Reg :
|
|
public x86Opcode
|
|
{
|
|
public:
|
|
x86Opcode_Condensable_Reg ( x86CondensableExtendedType inInfo ) : x86Opcode(inInfo) { }
|
|
|
|
virtual bool opHasRegFieldExtension( x86ArgumentList& inAL, x86ArgListInstruction& inInsn );
|
|
virtual uint8 opGetRegFieldExtension() { return ((0x03 & opInfo->oiOpcodeInformation) << 3); }
|
|
|
|
virtual bool opCanAccept1ByteImmediate() { return false; }
|
|
virtual bool opCanAccept4ByteImmediate() { return true; }
|
|
|
|
virtual bool opRegOperandCanBeCondensed(){ return true; }
|
|
|
|
virtual uint8 opSize() { return 1; }
|
|
virtual void opFormatToMemory(void* inStart, x86ArgumentList& inAL, x86ArgListInstruction& inInsn);
|
|
};
|
|
|
|
/*--------------------------------------------------------------------------------
|
|
x86Opcode_ImmArith -- encodes x86ImmediateArithType
|
|
|
|
- must have sign/size bit which specifies 8 or 32 bits operand
|
|
- _possible_ three bit opcode extension (stored in the REG field of the MODR/M byte)
|
|
*/
|
|
class x86Opcode_ImmArith :
|
|
public x86Opcode
|
|
{
|
|
public:
|
|
x86Opcode_ImmArith( x86ImmediateArithType inInfo ) : x86Opcode( inInfo ) { }
|
|
virtual void opFormatToMemory( void* inStart, x86ArgumentList& /*inAL*/, x86ArgListInstruction& /*inInsn*/);
|
|
|
|
virtual bool opHasRegFieldExtension( x86ArgumentList& /*inAL*/, x86ArgListInstruction& /*inInsn*/ )
|
|
{ return (bool)((opInfo->oiOpcodeInformation >> 6) && 1); }
|
|
virtual uint8 opGetRegFieldExtension()
|
|
{ assert(kExtension_Mask & opInfo->oiOpcodeInformation); return (kRegfield_Mask & opInfo->oiOpcodeInformation); }
|
|
virtual bool opCanAccept1ByteImmediate() { return true; }
|
|
virtual bool opCanAccept4ByteImmediate() { return true; }
|
|
|
|
virtual void opSwitchToRegisterIndirect() { } // FIX can't do this for imul ???
|
|
|
|
protected:
|
|
x86Opcode_ImmArith() { }
|
|
};
|
|
|
|
/*--------------------------------------------------------------------------------
|
|
x86Opcode_SpecialRegMem -- x86SpecialRegMemType
|
|
|
|
- switches between
|
|
x86Opcode_Reg when operand is a memory argument, and
|
|
x86Opcode when operand is a register argument
|
|
*/
|
|
class x86Opcode_SpecialRegMem :
|
|
public x86Opcode_Reg // note not x86Opcode!
|
|
{
|
|
public:
|
|
x86Opcode_SpecialRegMem( x86SpecialRegMemType inType) :
|
|
x86Opcode(inType) { }
|
|
|
|
virtual bool opHasRegFieldExtension( x86ArgumentList& /*inAL*/, x86ArgListInstruction& /*inInsn*/ )
|
|
{
|
|
return((kIs_Memory_Form_Mask & opInfo->oiOpcodeInformation) == kIs_Memory_Form_Mask);
|
|
}
|
|
|
|
virtual uint8 opGetRegFieldExtension()
|
|
{
|
|
assert(kIs_Memory_Form_Mask & opInfo->oiOpcodeInformation);
|
|
return (kRegfield_Mask & opInfo->oiOpcodeInformation);
|
|
}
|
|
|
|
virtual void opSwitchToRegisterIndirect()
|
|
{
|
|
assert(!(kIs_Memory_Form_Mask & opInfo->oiOpcodeInformation));
|
|
opInfo++;
|
|
}
|
|
};
|
|
|
|
#endif // _X86OPCODE
|