Class II (shortcut of Intel Instruction ) describes CPU features defined in x86-64 architecture and its object represents a parsed machine instruction with evaluated operands ready to assemble.
Object of II class was allocated by IiAssemble and it was prepared there to be processed by the instruction handler.
Instruction category | Uses registers | Module file | |
---|---|---|---|
all | Machine instruction handlers support | - | ii.htm |
A | Vendor specific (AMD) | RAX..YMM15 | iia.htm |
B | Intel Fused Multiply-Add (FMA) | XMM0..ZMM31 | iib.htm |
C | Vendor-specific (CYRIX) | MM0..MM7 | iic.htm |
D | 3DNow! specific (AMD, D3NOW) | XMM0..XMM15 | iid.htm |
F | Floating-point (FPU) | ST0..ST7 | iif.htm |
G | General instructions | RAX..R15 | iig.htm |
K | Mask-registers manipulation (AVX512) | K0..K7 | iik.htm |
M | Multimedia (MMX) | MM0..MM7 | iim.htm |
P | Packed (SSE) | XMM0..XMM15 | iip.htm |
S | System special (SPEC, UNDOC, PROT, PRIV, MPX, SGX) | special | iis.htm |
T | Transactional & other extensions (TSX, RTM, VMX, SVM) | - | iit.htm |
V | Advanced Vector extension (AVX) | XMM0..YMM15 | iiv.htm |
X | XOP-encodable AMD | XMM0..YMM15 | iix.htm |
Y | Advanced Vector extension (AVX2) | XMM0..YMM15 | iiy.htm |
Z | Advanced Vector extension (AVX512) | XMM0..ZMM31 | iiz.htm |
IiHandlers are represented by procedures called with register convention from IiAssemble. They are responsible for the assembly of actual machine instructions. Each of 2250 instruction mnemonics (suffixed or nonsuffixed) has got its own handler.
Instruction handlers are divided into categories in order to keep the number of handlers per module low.
Header of each module has alphabetical list of its instructions. If you are not sure to which category an instruction belongs, search for it in the global Index.
Description of each machine instruction is available in the header of its handler
in the form of link to [FCx86]
whenever available. Some info was also automatically supplemented from
[Refx86asm].
AVX instructions are supplemented with encoding reference from
[IntelAVX512]
. Encoding was retrieved from CPU-vendor PDF files semiautomatically,
so possible errors and typos may have propagated from documentation to the final code.
In order to introduce a new machine instruction to EuroAssembler
- Select apropriate instruction category ?=A..Z and its source file
ii?.htm,- declare the mnemonic in
%Ii?List
in the source file,- create public procedure of instruction handler,
- create a link to this handler in alphabetical list
%Ii?AList
in the source header,- create test file for the instruction,
- rebuild EuroAssembler.
r32.imm
for instruction ADD EBX,123
. The highest ordinal operand type is in DL.
EDX=0 for operandless instructions.
mem
) in EDX may be Intel-encoded to
m8/m16/m32/m64
before dispatching. This is achieved by
using macro IiDataSize.
RET
.
II
to
Stm.EmitBuffer
and relocations to Stm.RelocBuffer
.
Handlers from all modules use procedures and macros defined here in this common file
ii.htm
.
All those macros preserve contents of all register unchanged. Many macros expect EDX=format, EBX=^STM, EDI=^II.
Abortable macros IiDispatchFormat and IiAbortIf* will break further execution of Ii?Handler and return to it's parent, i.e. to IiAssemble. They may only be used on the same stack level as at Ii?Handler entry.
Job of most Ii* macros is to specify request for emission of instruction component (prefix, opcode, ModR/M, SIB, displacement and immediates) in object II . The actual emission is performed in procedure IiFlush.
EUROASM NOWARN=2101 ii PROGRAM FORMAT=COFF,MODEL=FLAT,WIDTH=32 INCLUDEHEAD "euroasm.htm" ; Interface (structures, symbols and macros) of other modules. INCLUDEHEAD \ ; Include headers of another modules used in this module. ea.htm, \ dict.htm, \ eaopt.htm, \ exp.htm, \ lst.htm, \ msg.htm, \ pgm.htm, \ pgmopt.htm, \ reloc.htm, \ src.htm, \ sss.htm, \ stm.htm, \ sym.htm, \ syswin.htm, \ ;;
ii HEAD ; Start of module interface.
II STRUC ; Parsed machine instruction with evaluated operands. ; EDI+00h. ; Operands of machine instruction evaluated to EXP objects by ExpEval. .Operand1: DS EXP ; Ordinal operand %1. .Operand2: DS EXP ; Ordinal operand %2. .Operand3: DS EXP ; Ordinal operand %3. .Operand4: DS EXP ; Ordinal operand %4. ; EDI+50h. .Align DD D ; 0=unspec, 1=B, 2=W, 4=D, 8=Q, 16=O, 32=Y, 64=Z. ; Explicit and implicit machine-instruction prefixes (other than *VEX) in Prefix encoding. .PfxAllowed DD D ; Prefixes allowed for this instruction, set by macro IiAllowPrefix in handler. .PfxExplicit DD D ; Bitwise OR of all prefixes explicitly specified by programmer inside the statement. .PfxEmitted DD D ; Implicit prefixes required by IiHandlers - SEGxS, REP, OTOGGLE, ATOGGLE, REX. ; EDI+60h. ; General instruction modifiers in general modifier encoding: .MfgAllowed DD D ; Modifiers specified as acceptable for this instruction by instruction handler. .MfgSuffix DD D ; Explicitly specified as suffix of instruction mnemonic, e.g. ADCD [Symbol],1 .MfgExplicit DD D ; Explicitly requested as keywords in machine instruction, e.g. ADC [Symbol],1,DATA=DWORD .MfgImplicit DD D ; Implicitly defined data width by memory-operand type, e.g. ADC [DwordSymbol],1 ; EDI+70h. .MfgEmitted DD D ; Modifiers specifying what is finally emitted. ; AVX instruction modifiers in AVX modifier encoding concerning Advanced Vector Extension prefix. .MfxAllowed DD D ; Modifiers specified as acceptable for this instruction by instruction handler. .MfxExplicit DD D ; Explicitly requested as keywords in machine instruction, e.g. VADDPD ZMM0,ZMM2,[RSI],MASK=K2,ZEROING=No .MfxEmitted DD D ; AVX modifiers actually encoded in emitted *VEX prefix. ; EDI+80h. ; Instruction properties and features. .Ppg DD D ; Properties (general) specifying what is finally emitted. Set by IiHandlers. .Ppx DD D ; Properties (AVX) specifying contents of AVX prefix. Set by IiHandlers. .Cpu DD D ; CPU= and SIMD= values required by the instruction and its registers and prefixes. .Features DD D ; Processor features required by the instruction and its registers and prefixes. ; EDI+90h. ; Assembled instruction code fields ready to flush to Stm.EmitBuffer, described by flags in II.MfgEmitted. .DispLow DD D ; 0..8 bytes of displacement, valid if II.MfgEmitted:iiMfgDISP_Mask is set. .DispHigh DD D .DispRelocSeg DD D ; ^SSS Segment of symbol used in displacement. .DispRelocSym DD D ; ^SYM if symbol was used in displacement. ; EDI+0A0h .ImmLow DD D ; 0..8 bytes of immediate operand. valid if II.MfgEmitted:iiMfgIMM_Mask is set. .ImmHigh DD D .ImmRelocSeg DD D ; ^SSS Segment of symbol used in immediate operand. .ImmRelocSym DD D ; ^SYM if symbol was used in immediate. ; EDI+0B0h. Finally assembled code which is emitted to section. .Opcode DB 16*B ; Operation code of instruction (size is specified by II.Ppg:iiPpgOpcodeSizeMask). ; EDI+0C0h. .ModRM DD D ; ModR/M byte in LSB, sometimes followed with SIB byte. .SIB EQU .ModRM+1 ; Only valid if II.Ppg:iiPpgModRM+iiPpgSIB is set. .Imm2 EQU .ModRM+2 ; Only valid if II.Ppg:iiPpgImm2 is set. .Para EQU .ModRM+2 ; Imm.segment value in direct far JMP/CALL. Only valid if II.Ppg:iiPpgPara is set. .Reloc DD D ; Relocation flags iiReloc* in IiReloc encoding. .SssStatus DD D ; Cache copy of current section status, see sssWidthMask. .PgmoptStatus DD D ; Cache copy of current program options status, see PGMOPT. ; EDI+0D0h. ; Pointers to literal prefix definitions, e.g. =B"VEX.NDS.256.66.0F.WIG". ; String begins with XOP/VEX/MVEX/EVEX and it is NULL-terminated. ; Point-separated definitions will be parsed in IiAssembleAVX. .AvxSrcXOP DD D ; Pointer to XOP definition string. .AvxSrcVEX DD D ; Pointer to VEX definition string. .AvxSrcMVEX DD D ; Pointer to MVEX definition string. .AvxSrcEVEX DD D ; Pointer to EVEX definition string. ;EDI+0E0h. .Disp8EVEX DD D ; Compression bits of disp8*N for OPER=0..7 when prefix EVEX is used. See IiDisp8EVEX. .Disp8MVEX DD D ; Compression bits of disp8*N for OPER=0..7 when prefix MVEX is used. See IiDisp8MVEX. .PfxCode DD 4*B ; Opcodes of 0..4 used explicit prefixes, in Stm order, the first in LSB, NULL padded. .AvxCode DD 4*B ; Assembled AVX prefix in format XOP or *VEX (size 2..4 is specified by II.Ppx:iiPpxAvxSize). ENDSTRUC II
iig.htm,
iif.htmetc.
%IiCategoryList %SET g,s,t,f,m,p,c,d,v,a,b,x,y,z,k
EUROASM CPU=
values, ordered from the highest.%IiCpuList %SET X64,686,586,486,386,286,186,086
EUROASM SIMD=
values, ordered from the highest.%IiSimdList %SET AVX512,AVX2,AVX,SSE4.2,SSE4.1,SSE4,SSSE3,SSE3,SSE2,SSE1,SSE
iiPpg*
describe the emitted code. They are kept in
II.Ppg by instruction handlers and together with
II.MfgEmitted they instruct IiFlush how to encode the instruction.
iiPpgOpcodeSizeMask = 0x0000_000F ; Number of opcode bytes in II.Opcode. iiPpgDispSegDiff = 0x0000_0010 ; Group/segment of displacement differs from current group/segment. iiPpgImmSegDiff = 0x0000_0020 ; Group/segment of immediate operand differs from current group/segment. iiPpgOperSizeBySss = 0x0000_0040 ; If not specified explicitly, use operand-size by segment width. iiPpgOperSizeByReg = 0x0000_0080 ; IiDataSize was determined from operand register width. iiPpgAddrSize = 0x0000_0300 ; Effective address-size 0,1,2,3 = unspecified,16,32,64. Set in IiModRM. iiPpgModRMd = 0x0000_0400 ; ModRM /digit requested. Digit value 0..7 is in iiPpgModDigit. Set by IiModRM. iiPpgModRMr = 0x0000_0800 ; ModRM /r requested. Set by IiModRM. ; = 0x0000_1000 ; Not used. iiPpgSIB = 0x0000_2000 ; II.ModRM+1 byte is valid SIB. iiPpgImm2 = 0x0000_4000 ; II.ModRM+2 byte is valid secondary immediate byte. iiPpgPara = 0x0000_8000 ; II.ModRM+2 word is valid immediate segment-register value (paragraph address). iiPpgNoREX = 0x0001_0000 ; Instruction requires no REX be present (it uses AH,BH,CH,DH). iiPpgMod01 = 0x0002_0000 ; Reset ModRM bit 7 (change mod 11b to 01b) iiPpgMod10 = 0x0004_0000 ; Reset ModRM bit 6 (change mod 11b to 10b) ; = 0x0008_0000 ; Not used. iiPpgVSIB1 = 0x0010_0000 ; Used vector indexregister is XMM or ZMM. iiPpgVSIB2 = 0x0020_0000 ; Used vector indexregister is YMM or ZMM. iiPpgVSIBind = 0x0030_0000 ; VSIB indices (none,XMM,YMM,ZMM) required by handler. Synced with iiPpxVSIBfam. iiPpgVEXvOp = 0x00C0_0000 ; Which operand (none,1,2,3) is encoded in *VEX.vvvv field. iiPpgModRegOp = 0x0300_0000 ; Which operand (none,1,2,3) is encoded in ModRM.RegOpcode field. iiPpgModRMOp = 0x0C00_0000 ; Which operand (none,1,2,3) is encoded in ModRM.R/M field. iiPpgModDigit = 0x7000_0000 ; Auxiliary opcode encoded as ModRM /digit. Valid only if iiPpgModRMd is set. ; = 0x8000_0000 ; Not used.
iiPpx*
describe AVX prefix (XOP/*VEX). They are kept in
II.Ppx by instruction handlers and together with
II.MfxEmitted they instruct IiFlush how to encode the instruction.
iiPpxPpMask = 0x0000_0003 ; Compacted instruction prefix 0,1,2,3=none,66,F3,F2. iiPpxL = 0x0000_0004 ; Vector width XOP.L alias VEX.L. 0,1=128,256. iiPpxW = 0x0000_0008 ; Operation width promotion bit W. iiPpxAvxSize = 0x0000_0070 ; Number of AVX prefix bytes in II.AvxCode (2..4). ; = 0x0000_0080 ; Not used. ; = 0x0000_0100 ; Not used. iiPpxMm3 = 0x0000_0200 ; 3byte opcode prefix 0x0F38 or 0x0F3A. iiPpxMmMask = 0x0000_0300 ; Opcode map. 0,1,2,3=map8,map9,map10,res. if XOP, otherwise none,0F,0F38,0F3A. ; = 0x0000_0C00 ; Not used. iiPpxAssignMask = 0x0000_7000 ; Operand assignments in VEX prefix. See IiModRM. iiPpxNDS = 0x0000_1000 ; VEX.vvvv encodes the first (preserved) source operand. iiPpxNDD = 0x0000_2000 ; VEX.vvvv encodes destination (overwritten) operand. iiPpxDDS = 0x0000_4000 ; VEX.vvvv encodes the second source operand. iiPpxRemoveREX = 0x0000_8000 ; Handler requested not emit empty REX (0x40). iiPpxRemoveREX.W = 0x0001_0000 ; Handler requested not emit REX.W. iiPpxRemoveREX.R = 0x0002_0000 ; Handler requested not emit REX.R. iiPpxR` = 0x0004_0000 ; ModR/M.reg extension 4.bit, M/EVEX.R' for ZMM16..ZMM31. iiPpxV` = 0x0008_0000 ; M/EVEX.vvvv extension 4.bit, M/EVEX.V' for ZMM16..ZMM31. iiPpxVSIB1 = 0x0010_0000 ; Used vector indexregister is XMM or ZMM. iiPpxVSIB2 = 0x0020_0000 ; Used vector indexregister is YMM or ZMM. iiPpxVSIBfam = 0x0030_0000 ; Used vector indexregister adopted by ExpEval. Synced with iiPpgVSIBind. ; 00b=none, 01b=XMM, 10b=YMM, 11b=ZMM. iiPpxNoZEROING = 0x0040_0000 ; Do not allow ZEROING together with MASK. iiPpxNoSwizzle = 0x0080_0000 ; Do not allow swizzle (only MVEX OPER=0 is acceptable when EH=0). iiPpxMEVEXonly = 0x0100_0000 ; Not encodable as XOP/VEX (uses ZMM or YMM16..ZMM31). iiPpxDisp8Allow = 0x0200_0000 ; Disp8*N compression is possible in M/EVEX encoded instruction. iiPpxEH0 = 0x0400_0000 ; MVEX.EH explicitly reset to 0. iiPpxEH1 = 0x0800_0000 ; MVEX.EH explicitly set to 1. iiPpxL0 = 0x1000_0000 ; Vector length XOP.L alias VEX.L explicitly reset to 0. iiPpxL1 = 0x2000_0000 ; Vector length XOP.L alias VEX.L explicitly set to 1. iiPpxLZ = iiPpxL0 ; Vector length XOP.L alias VEX.L explicitly reset to 0. iiPpxW0 = 0x4000_0000 ; Operation width promotion bit W explicitly reset to 0. iiPpxW1 = 0x8000_0000 ; Operation width promotion bit W explicitly set to 1.
ADDR=, CODE=, DATA=, DISP=, DIST=, IMM=, SCALE=
.
iiMfgIMM_None = 0 ; IMM= iiMfgIMM_BYTE = 0x0000_0001 ; Encode immediate operand in 1 byte. iiMfgIMM_WORD = 0x0000_0002 ; Encode immediate operand in 2 bytes. iiMfgIMM_DWORD = 0x0000_0004 ; Encode immediate operand in 4 bytes. iiMfgIMM_QWORD = 0x0000_0008 ; Encode immediate operand in 8 bytes. iiMfgIMM_Mask = iiMfgIMM_BYTE|iiMfgIMM_WORD|iiMfgIMM_DWORD|iiMfgIMM_QWORD iiMfgDISP_None = 0 ; DISP= iiMfgDISP_BYTE = 0x0000_0010 ; Encode displacement in 1 byte. iiMfgDISP_WORD = 0x0000_0020 ; Encode displacement in 2 bytes. iiMfgDISP_DWORD = 0x0000_0040 ; Encode displacement in 4 bytes. iiMfgDISP_QWORD = 0x0000_0080 ; Encode displacement in 8 bytes as ADDR=ABS. iiMfgDISP_Mask = iiMfgDISP_BYTE|iiMfgDISP_WORD|iiMfgDISP_DWORD|iiMfgDISP_QWORD iiMfgDATA_None = 0 ; DATA= iiMfgDATA_BYTE = 0x0000_0100 ; Operand size is 1 byte. See also suffix B. iiMfgDATA_WORD = 0x0000_0200 ; Operand size is 2 bytes. See also suffix W. iiMfgDATA_DWORD = 0x0000_0400 ; Operand size is 4 bytes. See also suffix D. iiMfgDATA_QWORD = 0x0000_0800 ; Operand size is 8 bytes. See also suffix Q. iiMfgDATA_TBYTE = 0x0000_1000 ; Operand size is 10 bytes. iiMfgDATA_OWORD = 0x0000_2000 ; Operand size is 16 bytes. iiMfgDATA_YWORD = 0x0000_4000 ; Operand size is 32 bytes. iiMfgDATA_ZWORD = 0x0000_8000 ; Operand size is 64 bytes. iiMfgDATA_Mask = iiMfgDATA_BYTE|iiMfgDATA_WORD|iiMfgDATA_DWORD|iiMfgDATA_QWORD|iiMfgDATA_TBYTE|iiMfgDATA_OWORD|iiMfgDATA_YWORD|iiMfgDATA_ZWORD iiMfgCODE_None = 0 ; CODE= iiMfgCODE_SHORT = 0x0001_0000 ; Use encoding with shorter or lower opcode (default). iiMfgCODE_LONG = 0x0002_0000 ; Use longer or numericaly higher opcode. iiMfgCODE_Mask = iiMfgCODE_SHORT|iiMfgCODE_LONG iiMfgSCALE_None = 0 ; SCALE= iiMfgSCALE_SMART = 0x0004_0000 ; Optimise encoding for shortest possible code. iiMfgSCALE_VERBATIM = 0x0008_0000 ; Encode scaling exactly as specified in address expression. iiMfgSCALE_Mask = iiMfgSCALE_SMART|iiMfgSCALE_VERBATIM iiMfgADDR_None = 0 ; ADDR= iiMfgADDR_ABS = 0x0010_0000 ; Encode displacement as absolute distance with relocation. iiMfgADDR_REL = 0x0020_0000 ; Encode immediate in 64bit mode as RIP relative distance (default). iiMfgADDR_PLT = 0x0040_0000 ; Encode immediate as PLT item relative distance. iiMfgADDR_GOT = 0x0080_0000 ; Encode immediate as GOT item relative distance. ; = 0x0100_0000 ; Unused. ; = 0x0200_0000 ; Unused. ; = 0x0400_0000 ; Unused. ; = 0x0800_0000 ; Unused. iiMfgADDR_Mask = iiMfgADDR_ABS|iiMfgADDR_REL|iiMfgADDR_PLT|iiMfgADDR_GOT iiMfgDIST_None = 0 ; DIST= iiMfgDIST_SHORT = 0x1000_0000 ; Encode JMP distance as RIP relative in 1 byte. See also suffix S. iiMfgDIST_NEAR = 0x2000_0000 ; Encode JMP/CALL distance as RIP relative in 2 or 4 bytes. See also suffix N. iiMfgDIST_FAR = 0x4000_0000 ; Encode JMP/CALL distance as an absolute segment:offset. See also suffix F. iiMfgDIST_Mask = iiMfgDIST_SHORT|iiMfgDIST_NEAR|iiMfgDIST_FAR iiMfgNESTING_OFF = 0x8000_0000 ; NESTINGCHECK=OFF was specified in the block pseudoinstruction.
BCST=, EH=, MASK=, OPER=, PREFIX=, ROUND=, SAE=, ZEROING=
.
iiMfxMASK_None = 0 ; MASK= iiMfxMASK_K0 = 0x0000_0001 iiMfxMASK_K1 = 0x0000_0002 iiMfxMASK_K2 = 0x0000_0004 iiMfxMASK_K3 = 0x0000_0008 iiMfxMASK_K4 = 0x0000_0010 iiMfxMASK_K5 = 0x0000_0020 iiMfxMASK_K6 = 0x0000_0040 iiMfxMASK_K7 = 0x0000_0080 iiMfxMASK_Mask = 0x0000_00FF iiMfxPREFIX_None = 0 ; PREFIX= iiMfxPREFIX_REX = 0x0000_0100 iiMfxPREFIX_XOP = 0x0000_0200 iiMfxPREFIX_VEX2 = 0x0000_0400 iiMfxPREFIX_VEX3 = 0x0000_0800 iiMfxPREFIX_VEX = iiMfxPREFIX_VEX2 | iiMfxPREFIX_VEX3 iiMfxPREFIX_MVEX = 0x0000_1000 iiMfxPREFIX_EVEX = 0x0000_2000 iiMfxPREFIX_Mask = iiMfxPREFIX_REX|iiMfxPREFIX_XOP|iiMfxPREFIX_VEX|iiMfxPREFIX_MVEX|iiMfxPREFIX_EVEX iiMfxROUND_None = 0 ; ROUND= iiMfxROUND_NEAR = 0x0001_0000 iiMfxROUND_DOWN = 0x0002_0000 iiMfxROUND_UP = 0x0004_0000 iiMfxROUND_ZERO = 0x0008_0000 iiMfxROUND_Mask = iiMfxROUND_NEAR|iiMfxROUND_DOWN|iiMfxROUND_UP|iiMfxROUND_ZERO iiMfxEH_None = 0 ; EH= boolean value. iiMfxEH_0 = 0x0010_0000 iiMfxEH_1 = 0x0020_0000 iiMfxEH_Mask = iiMfxEH_0|iiMfxEH_1 iiMfxZEROING_None = 0 ; ZEROING= iiMfxZEROING_0 = 0x0040_0000 ; Merging. iiMfxZEROING_1 = 0x0080_0000 iiMfxZEROING_Mask = iiMfxZEROING_0|iiMfxZEROING_1 iiMfxSAE_None = 0 ; SAE= iiMfxSAE_0 = 0x0100_0000 iiMfxSAE_1 = 0x0200_0000 iiMfxSAE_Mask = iiMfxSAE_0|iiMfxSAE_1 iiMfxBCST_None = 0 ; BCST= iiMfxBCST_0 = 0x0400_0000 iiMfxBCST_1 = 0x0800_0000 iiMfxBCST_Mask = iiMfxBCST_0|iiMfxBCST_1 iiMfxOPER_None = 0 ; OPER= iiMfxOPER_Mask = 0x7000_0000 ; Synchronized with DWORD EVEX.L'.L.b and MVEX.S2.S1.S0. iiMfxOPER_Used = 0x8000_0000 ; Value 0..7 in iiMfxOPER_Mask is valid.
iiReloc*
describe requests for relocations in the emitted code. They are kept in
II.Reloc. Together with
II.MfgEmitted and II.Ppg they instruct IiFlush
how to encode the instruction. They should be set by the macro IiReloc.
II.Reloc
(00h, 14h, 28h, 3Ch) is valid only with iiRelocExtAttrReq
and it identifies the operand (.Operand1, .Operand2, .Operand3, .Operand4) with possible postponed attribute evaluation.
iiRelocOffsExtAttr = 0x0000_00FF ; Offset of .OperandX
in II (00h, 14h, 28h, 3Ch) with postponed attribute of external symbol.
iiRelocDispAbs = 0x0001_0000 ; Displacement is segment-relocable, create relocAbsVA.
iiRelocDispRel = 0x0002_0000 ; Displacement is self-relocable, create relocRel.
iiRelocDispRIP = 0x0008_0000 ; Displacement needs 64bit-mode RIP-relocation before emit. No RELOC record.
iiRelocImmAbs = 0x0010_0000 ; Immediate is segment-relocable, create RelocAbs.
iiRelocImmRel = 0x0020_0000 ; Immediate is self-relocable, create relocRel.
iiRelocImmRIP = 0x0080_0000 ; Immediate needs rIP relocation before emit. No RELOC record.
iiRelocFar = 0x0100_0000 ; Immediate II.ImmRelocSeg needs relocFar.
iiRelocPara = 0x0200_0000 ; Immediate segment-register value (paragraph address) needs relocPara.
iiRelocExtAttrReq = 0x8000_0000 ; Indication that iiRelocExtAttr is valid.
iiCPU_*
flags describe CPU and SIMD level requested by instruction
and/or by registers used in its operands.
iiCPU_CpuMask
option is required in IiHandlers, but setting it with
EUROASM CPU=?86
will also set all lower options in
EAOPT.Machine:iiEaoptCPU
as well.
iiCPU_SimdMask
option is required in IiHandlers, but setting it with
EUROASM CPU=SSE?
will also set all lower options in
EAOPT.Machine:iiEaoptCPU
as well.
iiCPU_CpuMask = 0x0000_1FC0 ; Required CPU generation controlled byEUROASM CPU=
option. iiCPU_086 = 0x0000_0000 ; CPU=086 for instructions which work on any Intel compatible machine. iiCPU_186 = 0x0000_0040 ; This instruction requires CPU level 186. iiCPU_286 = 0x0000_0080 ; This instruction requires CPU level 286. iiCPU_386 = 0x0000_0100 ; This instruction requires CPU level 386 (32bit processor). iiCPU_486 = 0x0000_0200 ; This instruction requires CPU level 486. iiCPU_586 = 0x0000_0400 ; Alias PENTIUM. iiCPU_686 = 0x0000_0800 ; Alias P6 and later. iiCPU_X64 = 0x0000_1000 ; This instruction requires 64bit processor. iiCPU_SimdMask = 0x007F_E000 ; Required SIMD generation controlled byEUROASM SIMD=
option. iiCPU_SSE = 0x0000_2000 ; This instruction requires SIMD level SSE1. iiCPU_SSE1 = 0x0000_2000 ; This instruction requires SIMD level SSE1. iiCPU_SSE2 = 0x0000_4000 ; This instruction requires SIMD level SSE2. iiCPU_SSE3 = 0x0000_8000 ; This instruction requires SIMD level SSE3. iiCPU_SSSE3 = 0x0001_0000 ; This instruction requires SIMD level SSSE3. iiCPU_SSE4 = 0x0002_0000 ; This instruction requires SIMD level SSE4. iiCPU_SSE4.1 = 0x0004_0000 ; This instruction requires SIMD level SSE4.1. iiCPU_SSE4.2 = 0x0008_0000 ; This instruction requires SIMD level SSE4.2. iiCPU_AVX = 0x0010_0000 ; This instruction requires SIMD level AVX. iiCPU_AVX2 = 0x0020_0000 ; This instruction requires SIMD level AVX2. iiCPU_AVX512 = 0x0040_0000 ; This instruction requires SIMD level AVX512. ; Flags used in DictRegisters to require CPU generation by using a register in instruction: iiCpuDictRegMask = iiCPU_386|iiCPU_X64|iiCPU_SSE1|iiCPU_AVX|iiCPU_AVX512 ; Flags used in DictPrefixes to require CPU generation by using a prefix in instruction: iiCpuDictPfxMask = iiCPU_386|iiCPU_686
iiFea_*
flags specify which special CPU feature is requested by instruction
and/or by registers used in its operands.
iiFeaDictRegMask
in
DictRegisters.Data.
iiFea_PROT = 0x0000_0001 ; Protected mode. iiFea_VMX = 0x0000_0002 ; Virtual Machine Extensions, VMX, SVM. ; = 0x0000_0004 ; iiFea_AES = 0x0000_0008 ; Intel AES instructions. iiFea_SHA = 0x0000_0010 ; Intel SHA instructions. iiFea_LWP = 0x0000_0020 ; LightWeight Profiling extensions (AMD). iiFea_XOP = 0x0000_0040 ; Encoding prefix XOP (AMD). iiFea_MVEX = 0x0000_0080 ; Encoding prefix MVEX (AVX512). iiFea_EVEX = 0x0000_0100 ; Encoding prefix EVEX (AVX512). iiFea_FPU = 0x0000_0200 ; Floating-point unit (math coprocessor). iiFea_TSX = 0x0000_0400 ; Transactional Synchronization Extensions, TSX, RTM. iiFea_MMX = 0x0000_0800 ; MultiMedia extensions. ; = 0x0000_1000 ; iiFea_SGX = 0x0000_2000 ; Software Guard Extensions. ; = 0x0000_4000 ; ; = 0x0000_8000 ; iiFea_ABM = 0x0001_0000 ; Advanced Bit Manipulation, ABM, BMI1, BMI2, TBM. ; = 0x0002_0000 ; iiFea_SVM = 0x0004_0000 ; Shared Virtual Memory iiFea_MPX = 0x0008_0000 ; Memory Protection Extensions. iiFea_CET = 0x0010_0000 ; Control-flow Enforcement Technology. iiFea_PRIV = 0x0020_0000 ; This instruction/register requires privileged mode CPL=0. ; = 0x0040_0000 ; iiFea_UNDOC = 0x0080_0000 ; Undocumented instruction/register. iiFea_AMD = 0x0100_0000 ; Processor made by AMD. iiFea_CYRIX = 0x0200_0000 ; Processor made by CYRIX. iiFea_VIA = 0x0400_0000 ; Processor made by VIA. ; = 0x0800_0000 ; iiFea_D3NOW = 0x1000_0000 ; 3DNow! extensions (AMD). iiFea_FMA = 0x2000_0000 ; Fused Multiply-Add extensions. ; = 0x4000_0000 ; iiFea_SPEC = 0x8000_0000 ; Special feature not mentioned above. ; Flags used in DictRegisters to require CPU feature by using a register in instruction: iiFeaDictRegMask = iiFea_FPU|iiFea_MMX|iiFea_MPX|iiFea_PRIV|iiFea_UNDOC ; Flags used in DictPrefixes to require CPU feature by using a prefix in instruction: iiFeaDictPfxMask = iiFea_TSX
iiPfx_*
describe instruction prefixes other than *VEX. They are used in
DictPrefixes.Data,
II.PfxAllowed, II.PfxExplicit, II.PfxEmitted.
iiPfxCode = 0x0000_00FF ; 8bit operation code of the prefix. iiPfxREX = 0x0000_0040 ; 0x40 iiPfxREX.B = 0x0000_0041 ; 0x41 iiPfxREX.X = 0x0000_0042 ; 0x42 iiPfxREX.R = 0x0000_0044 ; 0x44 iiPfxREX.W = 0x0000_0048 ; 0x48 iiPfxGrpAny = 0x0000_F000 ; Prefix group presence mask. iiPfxGrp1 = 0x0000_1000 iiPfxGrp2 = 0x0000_2000 iiPfxGrp3 = 0x0000_4000 iiPfxGrp4 = 0x0000_8000 iiPfxMask = 0xFFFF_0000 ; Prefix identification. Bit-Nr in iiPfxMask correspondes with warnings number W2356..W2371. iiPfxLOCK = 0x0001_0000 ; 0xF0 iiPfxRepAny = 0x000C_0000 iiPfxREP = 0x0004_0000 ; 0xF3 iiPfxREPE = 0x0004_0000 ; 0xF3 iiPfxREPNE = 0x0008_0000 ; 0xF2 iiPfxSegAny = 0x03F0_0000 iiPfxSegAny086 = 0x00F0_0000 iiPfxSEGES = 0x0010_0000 ; 0x26 iiPfxSEGCS = 0x0020_0000 ; 0x2E iiPfxSEGSS = 0x0040_0000 ; 0x36 iiPfxSEGDS = 0x0080_0000 ; 0x3E iiPfxSEGFS = 0x0100_0000 ; 0x64 iiPfxSEGGS = 0x0200_0000 ; 0x65 iiPfxTsxAny = 0x0C00_0000 iiPfxXACQUIRE = 0x0400_0000 ; 0xF2 iiPfxXRELEASE = 0x0800_0000 ; 0xF3 iiPfxHintAny = 0x3000_0000 iiPfxSELDOM = 0x1000_0000 ; 0x2E iiPfxOFTEN = 0x2000_0000 ; 0x3E iiPfxOTOGGLE = 0x4000_0000 ; 0x66 iiPfxATOGGLE = 0x8000_0000 ; 0x67
iiReg_*
describe each CPU register in 8 bits.
iiReg_R16 + 1 = 0101_0001b
,
iiRegR08 + 10 = 0100_1010b
,
iiRegZMM + 25 = 110_11001b
,
iiRegKRG + 5 = 11100_101b
.iiRegIdMask = 1111_1111b ; Register identification in 8 bits. iiReg_Fam8 = 11111_000b ; Families with max. 8 members: iiReg_Ord8 = 00000_111b ; Register ordinal mask 0..7. iiReg_SEG = 00001_000b ; Segment registers ES,CS,SS,DS,ES,FS,GS,SEGR6,SEGR7. iiReg_FPR = 00010_000b ; Floating-point registers ST0..ST7. iiReg_MMX = 00011_000b ; 64 bit MMX registers MM0..MM7. iiReg_DGR = 00100_000b ; Debug registers DR0..DR7. iiReg_TSR = 00101_000b ; Test registers TR3..TR7. iiReg_CTR = 00110_000b ; Control registers CR0..CR7. iiReg_CT8 = 00111_000b ; Control register CR8. iiReg_Fam16 = 11000_000b ; Families with 16 members: iiReg_Ord16 = 0000_1111b ; Register ordinal mask 0..15. iiReg_R08 = 0100_0000b ; GPR 8 bits AL..R15B. iiReg_R16 = 0101_0000b ; GPR 16 bits AX..R15W. iiReg_R32 = 0110_0000b ; GPR 32 bits EAX..R15D. iiReg_R64 = 0111_0000b ; GPR 64 bits RAX..R15. iiReg_Fam32 = 1000_0000b ; Families with 32 members: iiReg_Ord32 = 000_11111b ; Register ordinal mask 0..31. iiReg_XMM = 100_00000b ; 128 bit SSE registers XMM0..XMM31. iiReg_YMM = 101_00000b ; 256 bit SSE registers YMM0..YMM31. iiReg_ZMM = 110_00000b ; 512 bit SSE registers ZMM0..ZMM31. iiReg_Spec = 111_00000b ; Special families: iiReg_KRG = 11100_000b ; AVX512 mask registers K0..K7. iiReg_BND = 111100_00b ; MPX registers BND0..BND3. ; Register addressing properties. iiRegBase = 0x0000_4000 ; May be base-register. iiRegIndex = 0x0000_8000 ; May be index-register. iiRegSeg = 0x0001_0000 ; Segment register. This will set iiReg_SEG, too. iiRegREX = 0x0002_0000 ; Encoding requires REX/VEX prefix. iiRegNoREX = 0x0004_0000 ; Encoding requires no REX prefix. Flag used in DictRegisters.Data. iiRegPpMask = iiRegBase|iiRegIndex|iiRegSeg|iiRegREX|iiRegNoREX
iiMfsALIGN_Mask = 0x0000_00FF ; 00=unspec, 01=B 02=W 04=D 08=Q 40=Z etc. ; Flags used in macro IiDataSize and IiImmSize. iiOsUseOperand1 = 0x0000_0001 iiOsUseOperand2 = 0x0000_0002 iiOsUseOperand3 = 0x0000_0004 iiOsAllowQword = 0x0000_0008 iiOsDistFar = 0x0000_0008 iiOsSpecifyMemOff = 0x0000_0010 iiOsUseSegment = 0x0000_0020 iiOsAddrRel = 0x0000_0020 iiOsFloatingPoint = 0x0000_0040 iiOsSigned = 0x0000_0040 iiOsStreamingSIMD = 0x0000_0080 iiOsUnsigned = 0x0000_0080 ; Flag used in macro IiStringDestination. iiSdAllowSeg = 0x1000_0000 ; Allow other segment prefix beside ES. ; Flag used in handler IitGroupXstate. iiXs64 = 0x0080_0000 ; Use 64bit version of extended CPU state area.
none = 0000_0000b ; No operand. imm8 = 0000_0001b ; 8bit immediate operand. imm16 = 0000_0010b ; 16bit immediate operand. far = 0000_0011b ; Far pointer in memory. imm32 = 0000_0100b ; 32bit immediate operand. ; = 0000_0101b ; Unused. imm64 = 0000_0110b ; 64bit immediate operand. imm = 0000_0111b ; Immediate operand, unspecified size. Sreg = 0000_1000b ; iiReg_SEG Segment register. STi: = 0001_0000b ; iiReg_FPR Floating-point register. Label needs a colon to avoid collision with instruction STI. mmx = 0001_1000b ; iiReg_MMX MMX register. dgr = 0010_0000b ; iiReg_DGR Debug register. tsr = 0010_1000b ; iiReg_TSR Test register. ctr = 0011_0000b ; iiReg_CTR Control register. ct8 = 0011_1000b ; iiReg_CT8 Control register CR8. r8: = 0100_0000b ; iiReg_R08 8bit general-purpose register. Label needs a colon to avoid collision with register R8. r16 = 0101_0000b ; iiReg_R16 16bit general-purpose register. r32 = 0110_0000b ; iiReg_R32 32bit general-purpose register. r64 = 0111_0000b ; iiReg_R64 64bit general-purpose register. xmm = 1000_0000b ; iiReg_XMM XMM register. ymm = 1010_0000b ; iiReg_YMM YMM register. zmm = 1100_0000b ; iiReg_ZMM ZMM register. krg = 1110_0000b ; iiReg_KRG K0..K7 mask register. bnd = 1111_0000b ; iiReg_BND BND0..BND3 bound register. m8 = 1111_0001b ; 8bit memory variable, DB. m16 = 1111_0010b ; 16bit memory variable, DW. ; = 1111_0011b ; Unused. m32 = 1111_0100b ; 32bit memory variable, DD. ; = 1111_0101b ; Unused. m64 = 1111_0110b ; 64bit memory variable, DQ. m80 = 1111_1000b ; 80bit memory variable, DT. m128 = 1111_1001b ; 128bit memory variable, DO. m256 = 1111_1010b ; 256bit memory variable, DY. m512 = 1111_1011b ; 512bit memory variable, DZ. mem = 1111_1111b ; Memory operand, unspecified size. ; Combinations of operand types which occur in instructions provided to handlers in EDX. ; The last operand is in DL, the last but one in DH etc. ; E.g. the handler for SAL BX,8 is called with EDX = r16.imm = 0x00005007. imm.m16 = imm <<8 + m16 ;>> imm.m32 = imm <<8 + m32 ;>> imm.m64 = imm <<8 + m64 ;>> mem.mem = mem <<8 + mem ;>> mem.Sreg = mem <<8 + Sreg ;>> mem.r8 = mem <<8 + r8: ;>> mem.r16 = mem <<8 + r16 ;>> mem.r32 = mem <<8 + r32 ;>> mem.r64 = mem <<8 + r64 ;>> mem.STi = mem <<8 + STi: ;>> mem.imm = mem <<8 + imm ;>> mem.imm8 = mem <<8 + imm8 ;>> mem.imm16 = mem <<8 + imm16 ;>> mem.imm32 = mem <<8 + imm32 ;>> mem.imm64 = mem <<8 + imm64 ;>> mem.xmm = mem <<8 + xmm ;>> mem.ymm = mem <<8 + ymm ;>> mem.zmm = mem <<8 + zmm ;>> mem.xmm.imm = mem <<16 + xmm<<8 + imm ;>>>> mem.mmx.mmx = mem <<16 + mmx<<8 + mmx ;>>>> mem.xmm.xmm = mem <<16 + xmm<<8 + xmm ;>>>> mem.ymm.imm = mem <<16 + ymm<<8 + imm ;>>>> mem.ymm.ymm = mem <<16 + ymm<<8 + ymm ;>>>> mem.zmm.imm = mem <<16 + zmm<<8 + imm ;>>>> r8.r8 = r8: <<8 + r8: ;>> r8.r16 = r8: <<8 + r16 ;>> r8.imm = r8: <<8 + imm ;>> r8.imm8 = r8: <<8 + imm8 ;>> r8.imm16 = r8: <<8 + imm16 ;>> r8.imm32 = r8: <<8 + imm32 ;>> r8.imm64 = r8: <<8 + imm64 ;>> r8.mem = r8: <<8 + mem ;>> r8.m8 = r8: <<8 + m8 ;>> r8.xmm.imm = r8:<<16 + xmm<<8 + imm ;>> m8.r8 = m8 <<8 + r8: ;>> m8.r16 = m8 <<8 + r16 ;>> m8.r16.r8 = m8 <<16 + r16<<8 + r8: ;>> m8.r16.imm = m8 <<16 + r16<<8 + imm ;>> m8.r32 = m8 <<8 + r32 ;>> m8.r32.r8 = m8 <<16 + r32<<8 + r8: ;>> m8.r32.imm = m8 <<16 + r32<<8 + imm ;>> m8.r64 = m8 <<8 + r64 ;>> m8.r64.r8 = m8 <<16 + r64<<8 + r8: ;>> m8.r64.imm = m8 <<16 + r64<<8 + imm ;>> m8.imm = m8 <<8 + imm ;>> m8.imm8 = m8 <<8 + imm8 ;>> m8.imm16 = m8 <<8 + imm16 ;>> m8.imm32 = m8 <<8 + imm32 ;>> m8.imm64 = m8 <<8 + imm64 ;>> r16.r8 = r16<<8 + r8: ;>> r16.r16 = r16<<8 + r16 ;>> r16.r32 = r16<<8 + r32 ;>> r16.r16.imm = r16<<16 + r16<<8 + imm ;>> r16.r16.r8 = r16<<16 + r16<<8 + r8: ;>> r16.r64 = r16<<8 + r64 ;>> r16.imm = r16<<8 + imm ;>> r16.imm8 = r16<<8 + imm8 ;>> r16.imm16 = r16<<8 + imm16 ;>> r16.imm32 = r16<<8 + imm32 ;>> r16.imm64 = r16<<8 + imm64 ;>> r16.mem = r16<<8 + mem ;>> r16.m8 = r16<<8 + m8 ;>> r16.m16 = r16<<8 + m16 ;>> r16.m32 = r16<<8 + m32 ;>> r16.m64 = r16<<8 + m64 ;>> r16.Sreg = r16<<8 + Sreg ;>> r16.m16.imm = r16<<16 + m16<<8 + imm ;>> r16.mmx.imm = r16<<16 + mmx<<8 + imm ;>> r16.xmm.imm = r16<<16 + xmm<<8 + imm ;>> r16.r16.r8.r16 = r16<<24 + r16<<16 + r8:<<8 + r16 ;>>>>>> mem.r16.r8.r16 = mem<<24 + r16<<16 + r8:<<8 + r16 ;>>>>>> r16.r16.r16.r8 = r16<<24 + r16<<16 + r16<<8 + r8: ;>>>>>> r16.mem.r16.r8 = r16<<24 + mem<<16 + r16<<8 + r8: ;>>>>>> m16.r8 = m16<<8 + r8: ;>> m16.r16 = m16<<8 + r16 ;>> m16.Sreg = m16<<8 + Sreg ;>> m16.r16.r8 = m16<<16 + r16<<8 + r8: ;>> m16.r16.imm = m16<<16 + r16<<8 + imm ;>> m16.r32 = m16<<8 + r32 ;>> m16.r32.imm = m16<<16 + r32<<8 + imm ;>> m16.r32.r8 = m16<<16 + r32<<8 + r8: ;>> m16.r64 = m16<<8 + r64 ;>> m16.r64.r8 = m16<<16 + r64<<8 + r8: ;>> m16.r64.imm = m16<<16 + r64<<8 + imm ;>> m16.STi = m16<<8 + STi ;>> m16.imm = m16<<8 + imm ;>> m16.imm8 = m16<<8 + imm8 ;>> m16.imm16 = m16<<8 + imm16 ;>> m16.imm32 = m16<<8 + imm32 ;>> m16.imm64 = m16<<8 + imm64 ;>> r32.r8 = r32<<8 + r8: ;>> r32.r16 = r32<<8 + r16 ;>> r32.r32 = r32<<8 + r32 ;>> r32.r64 = r32<<8 + r64 ;>> r32.Sreg = r32<<8 + Sreg ;>> r32.r32.imm = r32<<16 + r32<<8 + imm ;>> r32.r32.mem = r32<<16 + r32<<8 + mem ;>> r32.mem.imm = r32<<16 + mem<<8 + imm ;>> r32.r32.r32 = r32<<16 + r32<<8 + r32 ;>> r32.mem.r32 = r32<<16 + mem<<8 + r32 ;>> r32.r32.r8 = r32<<16 + r32<<8 + r8: ;>> r32.imm = r32<<8 + imm ;>> r32.imm8 = r32<<8 + imm8 ;>> r32.imm16 = r32<<8 + imm16 ;>> r32.imm32 = r32<<8 + imm32 ;>> r32.imm64 = r32<<8 + imm64 ;>> r32.mem = r32<<8 + mem ;>> r32.m8 = r32<<8 + m8 ;>> r32.m16 = r32<<8 + m16 ;>> r32.m32 = r32<<8 + m32 ;>> r32.m64 = r32<<8 + m64 ;>> r32.m32.imm = r32<<16 + m32<<8 + imm ;>> r32.mmx.imm = r32<<16 + mmx<<8 + imm ;>> r32.xmm.imm = r32<<16 + xmm<<8 + imm ;>> r32.r32.r32.r32 = r32<<24 + r32<<16 + r32<<8 + r32 ;>>>>>> r32.r32.mem.r32 = r32<<24 + r32<<16 + mem<<8 + r32 ;>>>>>> r32.ymm = r32<<8 + ymm ;>> r32.r32.r8.r32 = r32<<24 + r32<<16 + r8:<<8 + r32 ;>>>>>> mem.r32.r8.r32 = mem<<24 + r32<<16 + r8:<<8 + r32 ;>>>>>> r32.r32.r32.r8 = r32<<24 + r32<<16 + r32<<8 + r8: ;>>>>>> r32.mem.r32.r8 = r32<<24 + mem<<16 + r32<<8 + r8: ;>>>>>> m32.r8 = m32<<8 + r8: ;>> m32.r16 = m32<<8 + r16 ;>> m32.Sreg = m32<<8 + Sreg ;>> m32.r16.r8 = m32<<16 + r16<<8 + r8: ;>> m32.r16.imm = m32<<16 + r16<<8 + imm ;>> m32.r32 = m32<<8 + r32 ;>> m32.r32.r8 = m32<<16 + r32<<8 + r8: ;>> m32.r32.imm = m32<<16 + r32<<8 + imm ;>> m32.r64 = m32<<8 + r64 ;>> m32.r64.r8 = m32<<16 + r64<<8 + r8: ;>> m32.r64.imm = m32<<16 + r64<<8 + imm ;>> m32.STi = m32<<8 + STi ;>> m32.imm = m32<<8 + imm ;>> m32.imm8 = m32<<8 + imm8 ;>> m32.imm16 = m32<<8 + imm16 ;>> m32.imm32 = m32<<8 + imm32 ;>> m32.imm64 = m32<<8 + imm64 ;>> r64.r8 = r64<<8 + r8: ;>> r64.r16 = r64<<8 + r16 ;>> r64.r32 = r64<<8 + r32 ;>> r64.r64 = r64<<8 + r64 ;>> r64.Sreg = r64<<8 + Sreg ;>> r64.r32.imm = r64<<16 + r32<<8 + imm ;>> r64.r64.imm = r64<<16 + r64<<8 + imm ;>> r64.r64.mem = r64<<16 + r64<<8 + mem ;>> r64.mem.imm = r64<<16 + mem<<8 + imm ;>> r64.r64.r64 = r64<<16 + r64<<8 + r64 ;>> r64.mem.r64 = r64<<16 + mem<<8 + r64 ;>> r64.r64.r8 = r64<<16 + r64<<8 + r8: ;>> r64.imm = r64<<8 + imm ;>> r64.imm8 = r64<<8 + imm8 ;>> r64.imm16 = r64<<8 + imm16 ;>> r64.imm32 = r64<<8 + imm32 ;>> r64.imm64 = r64<<8 + imm64 ;>> r64.mem = r64<<8 + mem ;>> r64.m8 = r64<<8 + m8 ;>> r64.m16 = r64<<8 + m16 ;>> r64.m32 = r64<<8 + m32 ;>> r64.m64 = r64<<8 + m64 ;>> r64.m64.imm = r64<<16 + m64<<8 + imm ;>> r64.mmx.imm = r64<<16 + mmx<<8 + imm ;>> r64.xmm.imm = r64<<16 + xmm<<8 + imm ;>> r64.krg.krg = r64<<16 + krg<<8 + krg ;>> r64.ymm = r64<<8 + ymm ;>> r64.r64.r64.r64 = r64<<24 + r64<<16 + r64<<8 + r64 ;>>>>>> r64.r64.mem.r64 = r64<<24 + r64<<16 + mem<<8 + r64 ;>>>>>> m64.r8 = m64<<8 + r8: ;>> m64.r16 = m64<<8 + r16 ;>> m64.Sreg = m64<<8 + Sreg ;>> m64.r32 = m64<<8 + r32 ;>> m64.r16.r8 = m64<<16 + r16<<8 + r8: ;>> m64.r16.imm = m64<<16 + r16<<8 + imm ;>> m64.r32.r8 = m64<<16 + r32<<8 + r8: ;>> m64.r32.imm = m64<<16 + r32<<8 + imm ;>> m64.r64.r8 = m64<<16 + r64<<8 + r8: ;>> m64.r64.imm = m64<<16 + r64<<8 + imm ;>> m64.r64 = m64<<8 + r64 ;>> m64.STi = m64<<8 + STi ;>> m64.imm = m64<<8 + imm ;>> m64.imm8 = m64<<8 + imm8 ;>> m64.imm16 = m64<<8 + imm16 ;>> m64.imm32 = m64<<8 + imm32 ;>> m64.imm64 = m64<<8 + imm64 ;>> m80.STi = m80<<8 + STi ;>> imm.r8 = imm<<8 + r8: ;>> imm.r16 = imm<<8 + r16 ;>> imm.r32 = imm<<8 + r32 ;>> imm.r64 = imm<<8 + r64 ;>> imm.imm = imm<<8 + imm ;>> Sreg.r16 = Sreg<<8 + r16 ;>> Sreg.r32 = Sreg<<8 + r32 ;>> Sreg.r64 = Sreg<<8 + r64 ;>> Sreg.m16 = Sreg<<8 + m16 ;>> Sreg.m32 = Sreg<<8 + m32 ;>> Sreg.m64 = Sreg<<8 + m64 ;>> Sreg.mem = Sreg<<8 + mem ;>> mmx.mmx = mmx<<8 + mmx ;>> mmx.r8.imm = mmx<<16 + r8:<<8 + imm ;>>>> mmx.r16.imm = mmx<<16 + r16<<8 + imm ;>>>> mmx.r32.imm = mmx<<16 + r32<<8 + imm ;>>>> mmx.r64.imm = mmx<<16 + r64<<8 + imm ;>>>> mmx.mem.imm = mmx<<16 + mem<<8 + imm ;>>>> mmx.mmx.imm = mmx<<16 + mmx<<8 + imm ;>>>> mmx.r32 = mmx<<8 + r32 ;>> mmx.r64 = mmx<<8 + r64 ;>> r32.mmx = r32<<8 + mmx ;>> r64.mmx = r64<<8 + mmx ;>> mmx.mem = mmx<<8 + mem ;>> mmx.imm = mmx<<8 + imm ;>> mem.mmx = mem<<8 + mmx ;>> mmx.xmm = mmx<<8 + xmm ;>> xmm.xmm = xmm<<8 + xmm ;>> xmm.mmx = xmm<<8 + mmx ;>> xmm.r8: = xmm<<8 + r8: ;>> xmm.r16 = xmm<<8 + r16 ;>> xmm.r32 = xmm<<8 + r32 ;>> xmm.r64 = xmm<<8 + r64 ;>> r32.xmm = r32<<8 + xmm ;>> r64.xmm = r64<<8 + xmm ;>> xmm.ymm = xmm<<8 + ymm ;>> xmm.zmm = xmm<<8 + zmm ;>> xmm.mem = xmm<<8 + mem ;>> xmm.m32 = xmm<<8 + m32 ;>> xmm.m64 = xmm<<8 + m64 ;>> xmm.krg = xmm<<8 + krg ;>> xmm.xmm.r32 = xmm<<16 + xmm<<8 + r32 ;>>>> xmm.xmm.r64 = xmm<<16 + xmm<<8 + r64 ;>>>> xmm.xmm.imm = xmm<<16 + xmm<<8 + imm ;>>>> xmm.xmm.mem = xmm<<16 + xmm<<8 + mem ;>>>> xmm.mem.imm = xmm<<16 + mem<<8 + imm ;>>>> xmm.r8.imm = xmm<<16 + r8:<<8 + imm ;>>>> xmm.r16.imm = xmm<<16 + r16<<8 + imm ;>>>> xmm.r32.imm = xmm<<16 + r32<<8 + imm ;>>>> xmm.r64.imm = xmm<<16 + r64<<8 + imm ;>>>> xmm.imm = xmm<<8 + imm ;>> xmm.xmm.xmm = xmm<<16 + xmm<<8 + xmm ;>>>> xmm.mem.xmm = xmm<<16 + mem<<8 + xmm ;>>>> xmm.imm.imm = xmm<<16 + imm<<8 + imm ;>>>> xmm.ymm.imm = xmm<<16 + ymm<<8 + imm ;>>>> xmm.zmm.imm = xmm<<16 + zmm<<8 + imm ;>>>> xmm.xmm.imm.imm = xmm<<24 + xmm<<16 + imm<<8 + imm ;>>>>>> xmm.xmm.xmm.imm = xmm<<24 + xmm<<16 + xmm<<8 + imm ;>>>>>> xmm.xmm.xmm.xmm = xmm<<24 + xmm<<16 + xmm<<8 + xmm ;>>>>>> xmm.xmm.mem.xmm = xmm<<24 + xmm<<16 + mem<<8 + xmm ;>>>>>> xmm.xmm.mem.imm = xmm<<24 + xmm<<16 + mem<<8 + imm ;>>>>>> xmm.xmm.xmm.mem = xmm<<24 + xmm<<16 + xmm<<8 + mem ;>>>>>> xmm.xmm.r32.imm = xmm<<24 + xmm<<16 + r32<<8 + imm ;>>>>>> xmm.xmm.r64.imm = xmm<<24 + xmm<<16 + r64<<8 + imm ;>>>>>> ymm.r8: = ymm<<8 + r8: ;>> ymm.r16 = ymm<<8 + r16 ;>> ymm.r32 = ymm<<8 + r32 ;>> ymm.r64 = ymm<<8 + r64 ;>> ymm.mem = ymm<<8 + mem ;>> ymm.xmm = ymm<<8 + xmm ;>> ymm.ymm = ymm<<8 + ymm ;>> ymm.zmm = ymm<<8 + zmm ;>> ymm.krg = ymm<<8 + krg ;>> ymm.ymm.ymm = ymm<<16 + ymm<<8 + ymm ;>>>> ymm.ymm.xmm = ymm<<16 + ymm<<8 + xmm ;>>>> ymm.ymm.mem = ymm<<16 + ymm<<8 + mem ;>>>> ymm.ymm.imm = ymm<<16 + ymm<<8 + imm ;>>>> ymm.ymm.ymm.imm = ymm<<24 + ymm<<16 + ymm<<8 + imm ;>>>>>> ymm.ymm.mem.imm = ymm<<24 + ymm<<16 + mem<<8 + imm ;>>>>>> ymm.ymm.xmm.imm = ymm<<24 + ymm<<16 + xmm<<8 + imm ;>>>>>> ymm.ymm.ymm.ymm = ymm<<24 + ymm<<16 + ymm<<8 + ymm ;>>>>>> ymm.ymm.mem.ymm = ymm<<24 + ymm<<16 + mem<<8 + ymm ;>>>>>> ymm.ymm.ymm.mem = ymm<<24 + ymm<<16 + ymm<<8 + mem ;>>>>>> ymm.mem.ymm = ymm<<16 + mem<<8 + ymm ;>>>> ymm.mem.imm = ymm<<16 + mem<<8 + imm ;>>>> ymm.zmm.imm = ymm<<16 + zmm<<8 + imm ;>>>> zmm.r8: = zmm<<8 + r8: ;>> zmm.r16 = zmm<<8 + r16 ;>> zmm.r32 = zmm<<8 + r32 ;>> zmm.r64 = zmm<<8 + r64 ;>> zmm.xmm = zmm<<8 + xmm ;>> zmm.ymm = zmm<<8 + ymm ;>> zmm.zmm = zmm<<8 + zmm ;>> zmm.mem = zmm<<8 + mem ;>> zmm.krg = zmm<<8 + krg ;>> zmm.zmm.zmm = zmm<<16 + zmm<<8 + zmm ;>>>> zmm.zmm.xmm = zmm<<16 + zmm<<8 + xmm ;>>>> zmm.zmm.mem = zmm<<16 + zmm<<8 + mem ;>>>> zmm.mem.imm = zmm<<16 + mem<<8 + imm ;>>>> zmm.zmm.imm = zmm<<16 + zmm<<8 + imm ;>>>> zmm.krg.zmm = zmm<<16 + krg<<8 + zmm ;>>>> zmm.krg.mem = zmm<<16 + krg<<8 + mem ;>>>> zmm.zmm.zmm.imm = zmm<<24 + zmm<<16 + zmm<<8 + imm ;>>>>>> zmm.zmm.xmm.imm = zmm<<24 + zmm<<16 + xmm<<8 + imm ;>>>>>> zmm.zmm.ymm.imm = zmm<<24 + zmm<<16 + ymm<<8 + imm ;>>>>>> zmm.zmm.mem.imm = zmm<<24 + zmm<<16 + mem<<8 + imm ;>>>>>> krg.krg = krg<<8 + krg ;>> krg.mem = krg<<8 + mem ;>> krg.imm = krg<<8 + imm ;>> mem.krg = mem<<8 + krg ;>> krg.r32 = krg<<8 + r32 ;>> r32.krg = r32<<8 + krg ;>> krg.r64 = krg<<8 + r64 ;>> r64.krg = r64<<8 + krg ;>> krg.xmm = krg<<8 + xmm ;>> krg.ymm = krg<<8 + ymm ;>> krg.zmm = krg<<8 + zmm ;>> krg.krg.krg = krg<<16 + krg<<8 + krg ;>>>> krg.r64.imm = krg<<16 + r64<<8 + imm ;>>>> krg.krg.imm = krg<<16 + krg<<8 + imm ;>>>> krg.xmm.imm = krg<<16 + xmm<<8 + imm ;>>>> krg.ymm.imm = krg<<16 + ymm<<8 + imm ;>>>> krg.zmm.imm = krg<<16 + zmm<<8 + imm ;>>>> krg.mem.imm = krg<<16 + mem<<8 + imm ;>>>> krg.m128.imm = krg<<16 + m128<<8 + imm ;>>>> krg.m256.imm = krg<<16 + m256<<8 + imm ;>>>> krg.m512.imm = krg<<16 + m512<<8 + imm ;>>>> krg.xmm.xmm = krg<<16 + xmm<<8 + xmm ;>>>> krg.xmm.mem = krg<<16 + xmm<<8 + mem ;>>>> krg.ymm.ymm = krg<<16 + ymm<<8 + ymm ;>>>> krg.ymm.mem = krg<<16 + ymm<<8 + mem ;>>>> krg.zmm.zmm = krg<<16 + zmm<<8 + zmm ;>>>> krg.zmm.mem = krg<<16 + zmm<<8 + mem ;>>>> krg.xmm.mem.imm = krg<<24 + xmm<<16 + mem<<8 + imm ;>>>>>> krg.xmm.xmm.imm = krg<<24 + xmm<<16 + xmm<<8 + imm ;>>>>>> krg.ymm.mem.imm = krg<<24 + ymm<<16 + mem<<8 + imm ;>>>>>> krg.ymm.ymm.imm = krg<<24 + ymm<<16 + ymm<<8 + imm ;>>>>>> krg.zmm.mem.imm = krg<<24 + zmm<<16 + mem<<8 + imm ;>>>>>> krg.zmm.zmm.imm = krg<<24 + zmm<<16 + zmm<<8 + imm ;>>>>>> bnd.bnd = bnd<<8 + bnd ;>> bnd.mem = bnd<<8 + mem ;>> bnd.r32 = bnd<<8 + r32 ;>> bnd.r64 = bnd<<8 + r64 ;>> mem.bnd = mem<<8 + bnd ;>> bnd.mem.r32 = bnd<<16 + mem<<8 + r32 ;>>>> bnd.mem.r64 = bnd<<16 + mem<<8 + r64 ;>>>> mem.r32.bnd = mem<<16 + r32<<8 + bnd ;>>>> mem.r64.bnd = mem<<16 + r64<<8 + bnd ;>>>> mem.bnd.r32 = mem<<16 + bnd<<8 + r32 ;>>>> mem.bnd.r64 = mem<<16 + bnd<<8 + r64 ;>>>> r32.ctr = r32<<8 + ctr ;>> r64.ctr = r64<<8 + ctr ;>> ctr.r32 = ctr<<8 + r32 ;>> ctr.r64 = ctr<<8 + r64 ;>> r32.ct8 = r32<<8 + ct8 ;>> r64.ct8 = r64<<8 + ct8 ;>> ct8.r32 = ct8<<8 + r32 ;>> ct8.r64 = ct8<<8 + r64 ;>> r32.dgr = r32<<8 + dgr ;>> r64.dgr = r64<<8 + dgr ;>> dgr.r32 = dgr<<8 + r32 ;>> dgr.r64 = dgr<<8 + r64 ;>> r32.tsr = r32<<8 + tsr ;>> tsr.r32 = tsr<<8 + r32 ;>> STi.STi = STi:<<8 + STi: ;>> STi.mem = STi:<<8 + mem ;>> STi.m16 = STi:<<8 + m16 ;>> STi.m32 = STi:<<8 + m32 ;>> STi.m64 = STi:<<8 + m64 ;>> STi.m80 = STi:<<8 + m80 ;>>
IiAbort %MACRO MsgNr, cc= %IF "%cc"<>"" : J%!cc .IiAbort%.: %ENDIF MOV EAX,%MsgNr JMP IiAbort@RT:: .IiAbort%.: IiAbort@RT:: PROC1 Msg EAX RstSt [EBX+STM.Status],stmOperationPresent ; Invalidate the instruction, do not emit anything. RET ; Abandon the handler, return to IiAssemble. ENDPROC1 IiAbort@RT:: %ENDMACRO IiAbort
IiAbortIf64 %MACRO TESTD [EDI+II.SssStatus],sssWidth64 IiAbort cc=NZ,'6739' %ENDMACRO IiAbortIf64
IiAbortIfNot64 %MACRO TESTD [EDI+II.SssStatus],sssWidth64 IiAbort cc=Z,'6749' %ENDMACRO IiAbortIfNot64
IiAbortIfNotST0 %MACRO CALL IiAbortIfNotST0@RT:: IiAbortIfNotST0@RT:: PROC1 PUSH EAX MOV AL,[EDI+II.Operand1+EXP.Low] MOV AH,[EDI+II.Operand2+EXP.Low] CMP AL,iiReg_FPR+0 JE .10: CMP AH,iiReg_FPR+0 JE .10: Msg '7602' ; At least one operand must be FP register ST0. ADD ESP,8 ; Discard pushed EAX and RET, return to abort parent Iif handler. RET .10:CMP AH,AL POP EAX RET ENDP1 IiAbortIfNotST0@RT:: %ENDMACRO IiAbortIfNotST0
Operand1, Operand2, Operand3, Operand4
.
CL, AX, CX, DX, EAX, ECX, EDX, RAX, RDX, ST0, ST1, XMM0
.
IiAbortIfNot %MACRO OperandNr, Register %IF "%OperandNr[1..7]" !== "Operand" %ERROR Id=5851,'Wrong argument %%1 provided for macro IiAbortIfNot in %^PROC' %EXITMACRO IiAbortIfNot %ENDIF %reg %SETA 0 %IF "%Register" == "CL" %reg %SETA iiReg_R08+1 %ENDIF %IF "%Register" == "AX" %reg %SETA iiReg_R16+0 %ENDIF %IF "%Register" == "CX" %reg %SETA iiReg_R16+1 %ENDIF %IF "%Register" == "DX" %reg %SETA iiReg_R16+2 %ENDIF %IF "%Register" == "EAX" %reg %SETA iiReg_R32+0 %ENDIF %IF "%Register" == "ECX" %reg %SETA iiReg_R32+1 %ENDIF %IF "%Register" == "EDX" %reg %SETA iiReg_R32+2 %ENDIF %IF "%Register" == "RAX" %reg %SETA iiReg_R64+0 %ENDIF %IF "%Register" == "RDX" %reg %SETA iiReg_R64+2 %ENDIF %IF "%Register" == "ST0" %reg %SETA iiReg_FPR+0 %ENDIF %IF "%Register" == "ST1" %reg %SETA iiReg_FPR+1 %ENDIF %IF "%Register" == "XMM0" %reg %SETA iiReg_XMM+0 %ENDIF %IF %reg=0 %ERROR Id=5852,'Unknown register %Register provided for macro IiAbortIfNot in %^PROC.' %EXITMACRO IiAbortIfNot %ENDIF CMPB [EDI+II.%OperandNr+EXP.Low+0],%reg Msg cc=NE,'7610',%OperandNr[8],=B'%Register' ; Only register !2$ is expected as operand !1D. %ENDMACRO IiAbortIfNot
Operand1,Operand2,Operand3,Operand4
with GPR register operand.
IiAbortIfNotCounter %MACRO OperandNr PUSH EAX MOV EAX,[EDI+II.%OperandNr+EXP.Low] AND AL,iiReg_Ord16 CMP AL,1 ; CL/CX/ECX/RCX. POP EAX IiAbort cc=NE,'6756' %ENDMACRO IiAbortIfNotCounter
ALIGN
and NESTINGCHECK
need not be explicitly allowed.
DISP
and SCALE
are implicitly allowed if the handler expands macro
IiModRM.
DATA
is implicitly allowed if the handler expands macro
IiDataSize.
ADDR
, BCST
, CODE
, DATA
, DISP
, DIST
, EH
,
IMM
, MASK
, OPER
, PREFIX
, ROUND
, SAE
,
SCALE
, ZEROING
(in upper case).
IiAllowModifier %MACRO %Mfg %SETA 0 %Mfx %SETA 0 Key %FOR %* %IF TYPE#iiMfg%Key[]_Mask = 'N' ; Decide if %Key is defined as iiMfg or iiMfx. %Mfg %SETA %Mfg | iiMfg%Key[]_Mask %ELSE %Mfx %SETA %Mfx | iiMfx%Key[]_Mask %ENDIF %ENDFOR Key %IF %Mfg SetSt [EDI+II.MfgAllowed],%Mfg %ENDIF %IF %Mfx SetSt [EDI+II.MfxAllowed],%Mfx %ENDIF %ENDMACRO IiAllowModifier
LOCK
is allowed if at least one of specified operands is [memory].
Operand1, Operand2, Operand3, Operand4
.
iiPfxLOCK
is set in
[EDI+II.PfxAllowed].
IiAllowLocking %MACRO %IF %# OperandNr %FOR %* PUSHD [EDI+II.%OperandNr+EXP.Status] CALL IiAllowLocking@RT:: %ENDFOR OperandNr %ELSE %ERROR Id=5853,"IiAllowLocking OpenrandNr missing in %^PROC." %ENDIF IiAllowLocking@RT:: PROC1 PUSH EAX MOV EAX,[ESP+8] Dispatch AL,'M','B','W','D','Q','U','T','O','Y','Z','I' JMP .90: .M: .B: .W: .D: .Q: .U: .T: .I: .O: .Y: .Z: SetSt [EDI+II.PfxAllowed],iiPfxLOCK .90:POP EAX RET 4 ENDP1 IiAllowLocking@RT:: %ENDMACRO IiAllowLocking
MASK=
is allowed in this instruction but modifier
ZEROING=
is not.
iiMfxMASK_Mask
is set in
[EDI+II.MfxAllowed].
iiPpxNoZEROING
is set in [EDI+II.Ppx].
IiAllowMaskMerging %MACRO SetSt [EDI+II.MfxAllowed],iiMfxMASK_Mask RstSt [EDI+II.Ppx],iiPpxNoZEROING %ENDMACRO IiAllowMaskMerging
BCST=
is allowed in this instruction when the last operand is in memory.
DWORD QWORD
under iiMfgDATA_Mask
which will be specified as emitted operand size in
[EDI+II.MfgEmitted] when BCST=ON. Nothing is specified if omitted.
iiMfxBCST_Mask
set in [EDI+II.MfxAllowed].
IiAllowBroadcasting %MACRO Datatype, Operand=DL CMP %Operand,mem ; Broadcasting is possible only if the operand is in memory. JNE iabc%.: ORD [EDI+II.MfxAllowed],iiMfxBCST_Mask %IF "%Datatype" !=== "" JNSt [EDI+II.MfxExplicit],iiMfxBCST_1,iabc%.: ORD [EDI+II.MfgEmitted],iiMfgDATA_%Datatype %ENDIF iabc%.: %ENDMACRO IiAllowBroadcasting
ROUND=
is allowed in this instruction when the specified operand is SSE register.
iiMfxSAE_Mask
is allowed concurrently with iiMfxROUND_Mask
because the use of static rounding implies SAE=ON, i.e. suppressing all exceptions
(but not vice versa).
iiMfxROUND_Mask
set in [EDI+II.MfxAllowed].
IiAllowRounding %MACRO Operand=DL, Register=zmm CMP %Operand,%Register ; Static rounding is possible only in EVEX when the last operand is ZMM register. JNE iar%.: ORD [EDI+II.MfxAllowed],iiMfxROUND_Mask+iiMfxSAE_Mask iar%.: %ENDMACRO IiAllowRounding
OPER=
can only have value 0 when EH=0 in register-register operation.
iiPpxNoSwizzle
set in [EDI+II.Ppx].
IiAllowNoSwizzle %MACRO SetSt [EDI+II.Ppx],iiPpxNoSwizzle %ENDMACRO IiAllowNoSwizzle
SAE=
(suppress all exeptions) is allowed in this instruction when the specified operand is SSE register
and sets iiMfxSAE_Mask in [EDI+II.MfxAllowed].
iiMfxSAE_Mask
set in [EDI+II.MfxAllowed].
IiAllowSuppressing %MACRO Operand=DL, Register=zmm, Swizzle=Yes CMP %Operand,%Register ; Exceptions suppressing is possible only in EVEX when the operand is SSE register. JNE ias%.: SetSt [EDI+II.MfxAllowed],iiMfxSAE_Mask %IF "%Swizzle[1]" !=== "Y" SetSt [EDI+II.Ppx],iiPpxNoSwizzle %ENDIF ias%.: %ENDMACRO IiAllowSuppressing
[EDI+II.PfxAllowed]
and/or [EDI+II.MfxAllowed]
.
ADC*, ADD*, ADDPD, AND*, BTC, BTR, BTS, CMPXCHG, CMPXCHG8B, CMPXCHG16B,
DEC*, INC*, NEG*, NOT*, OR*, SBB*, SUB*, XADD*, XCHG*, XOR*.
The LOCK prefix is only allowed if the FIRST operand is a MEMORY LOCATION.
On registers this prefix is NOT allowed, see
[LockBug],
[PentiumBug].
CMPS*, INS*, LODS*, MOVS*, OUTS*, SCAS*, STOS*
Jcc, LOOPcc
.
iiPfxMask
(without iiPfx
) or in AVX modifiers encoding
(without iiMfxPREFIX_
).
II.PfxAllowed
and/or II.MfxAllowed
are set.
IiAllowPrefix %MACRO AllowedPrefixes %Pfx %SETA 0 %Mfx %SETA 0 %AVXprefixes %SET XOP,VEX,EVEX,MVEX prefix %FOR %* %pftype %SET iiPfx AVXprefix %FOR %AVXprefixes %IF "%prefix" == "%AVXprefix" %pftype %SET iiMfx %ENDIF %ENDFOR AVXprefix %IF "%pftype" == "iiMfx" %Mfx %SETA %Mfx | iiMfxPREFIX_%prefix %ELSE %Pfx %SETA %Pfx | iiPfx%prefix %ENDIF %ENDFOR prefix %IF %Pfx SetSt [EDI+II.PfxAllowed],%Pfx %ENDIF %IF %Mfx SetSt [EDI+II.MfxAllowed],%Mfx %ENDIF %ENDMACRO IiAllowPrefix
[EDI+II]
identified as OperandNr with its assumed default value, if it was empty.
Operand1, Operand2, Operand3, Operand4
.
1, 10, ST0, ST1, Operand1, Operand2, Operand3, Operand4
.
SHL EAXto
SHL EAX,1. IiAssumeEmpty Operand2, Operand1 ; Change
TEST EBXto
TEST EBX,EBX.
IiAssumeEmpty %MACRO OperandNr, DefaultValue %IF "%DefaultValue[1..7]" === "Operand" CMPB [EDI+II.%OperandNr+EXP.Status],0 JNZ .%.: ; Skip if operand is not empty. PUSHD [EDI+II.%DefaultValue+EXP.Status] PUSHD [EDI+II.%DefaultValue+EXP.Seg] PUSHD [EDI+II.%DefaultValue+EXP.Low] PUSHD [EDI+II.%DefaultValue+EXP.High] PUSHD [EDI+II.%DefaultValue+EXP.Sym] POPD [EDI+II.%OperandNr+EXP.Sym] POPD [EDI+II.%OperandNr+EXP.High] POPD [EDI+II.%OperandNr+EXP.Low] POPD [EDI+II.%OperandNr+EXP.Seg] POPD [EDI+II.%OperandNr+EXP.Status] .%.: %EXITMACRO IiAssumeEmpty %ENDIF %IF "%DefaultValue"==="1" || "%DefaultValue"==="10" CMPB [EDI+II.%OperandNr+EXP.Status],0 JNZ .%.: ; Skip if operand is not empty. MOVB [EDI+II.%OperandNr+EXP.Low],%DefaultValue MOVB [EDI+II.%OperandNr+EXP.Status],'N' .%.: %EXITMACRO IiAssumeEmpty %ENDIF %IF "%DefaultValue[1..2]"==="ST" CMPB [EDI+II.%OperandNr+EXP.Status],0 JNZ .%.: ; Skip if operand is not empty. MOVB [EDI+II.%OperandNr+EXP.Low],iiReg_FPR+%DefaultValue[3] MOVB [EDI+II.%OperandNr+EXP.Status],'R' .%.: %EXITMACRO IiAssumeEmpty %ENDIF %ERROR Id=5854,'Unexpected argument "%DefaultValue" provided for macro IiAssumeEmpty in %^PROC.' %ENDMACRO IiAssumeEmpty
[EDI+II]
.
It does not swap their types in EDX.
Operand1, Operand2, Operand3, Operand4
.
IiSwap %MACRO OperandANr, OperandBNr Nr %FOR 1,2,3,4 %IF "%OperandANr"=="Operand%Nr" PUSHD [EDI+II.Operand%Nr+EXP.Sym] PUSHD [EDI+II.Operand%Nr+EXP.High] PUSHD [EDI+II.Operand%Nr+EXP.Low] PUSHD [EDI+II.Operand%Nr+EXP.Seg] PUSHD [EDI+II.Operand%Nr+EXP.Status] %ENDIF %ENDFOR Nr Nr %FOR 1,2,3,4 %IF "%OperandBNr"=="Operand%Nr" PUSHD [EDI+II.Operand%Nr+EXP.Sym] PUSHD [EDI+II.Operand%Nr+EXP.High] PUSHD [EDI+II.Operand%Nr+EXP.Low] PUSHD [EDI+II.Operand%Nr+EXP.Seg] PUSHD [EDI+II.Operand%Nr+EXP.Status] %ENDIF %ENDFOR Nr Nr %FOR 1,2,3,4 %IF "%OperandANr"=="Operand%Nr" POPD [EDI+II.Operand%Nr+EXP.Status] POPD [EDI+II.Operand%Nr+EXP.Seg] POPD [EDI+II.Operand%Nr+EXP.Low] POPD [EDI+II.Operand%Nr+EXP.High] POPD [EDI+II.Operand%Nr+EXP.Sym] %ENDIF %ENDFOR Nr Nr %FOR 1,2,3,4 %IF "%OperandBNr"=="Operand%Nr" POPD [EDI+II.Operand%Nr+EXP.Status] POPD [EDI+II.Operand%Nr+EXP.Seg] POPD [EDI+II.Operand%Nr+EXP.Low] POPD [EDI+II.Operand%Nr+EXP.High] POPD [EDI+II.Operand%Nr+EXP.Sym] %ENDIF %ENDFOR Nr %ENDMACRO IiSwap
[EDI+II.Ppg]:iiPpgVSIBind
.
IiVSIB %MACRO Indices RstSt [EDI+II.Ppg],iiPpgVSIBind %IF "%Indices" !=== "" %VSIBind %SETA 0 %IF "%Indices" == "vm32x" || "%Indices" == "vm64x" %VSIBind %SETA iiPpgVSIB1 %ENDIF %IF "%Indices" == "vm32y" || "%Indices" == "vm64y" %VSIBind %SETA iiPpgVSIB2 %ENDIF %IF "%Indices" == "vm32z" || "%Indices" == "vm64z" %VSIBind %SETA iiPpgVSIB1 | iiPpgVSIB2 %ENDIF %IF %VSIBind SetSt [EDI+II.Ppg],%VSIBind %ELSE %ERROR Id=5855,"Invalid IiVSIB indice '%Indices' in %^PROC." %ENDIF %ENDIF %ENDMACRO IiVSIB
IiDispatchFormat %MACRO format %FOR %* CMP EDX,%format JE .%format: %ENDFOR format JMP IiDispatchFormatFail@RT:: ; JMP instead of CALL will abort the parent PROC when no format matched EDX. IiDispatchFormatFail@RT:: PROC1 ; Prepare and report E7511 Wrong operand combination !1S. ; Input: EDX=format in Intel encoding. If ZF=1, display D1911 instead of E7511. ; EBX=^STM. PUSHFD ; Save ZF. RstSt [EBX+STM.Status],stmOperationPresent ; Invalidate the instruction. Invoke EaBufferReserve::,IiDispatchFormatFail@RT ; Buffer for message parameter !1S. MOV EBX,EAX MOV EDI,4 SUB ECX,ECX %IiEnc2 %SET m8,r8: ; Operand names which have 2 characters. %IiEnc3 %SET m16,m32,m64,m80,mem,r16,r32,r64,ctr,ct8,krg,bnd,dgr,tsr,STi,mmx,xmm,ymm,zmm,far,imm %IiEnc4 %SET m128,m256,m512,Sreg,imm8,none %IiEnc5 %SET imm16,imm32,imm64 ; Operand names which have 5 characters. BSWAP EDX SUB EBP,EBP ; Marker if other than "none" was already stored. .10: CMP EDI,1 ; The last time report "none" anyway. JNE .15: INC EBP .15: CMP DL,none JNE .20: TEST EBP JZ .85: ; Silently ignore leading empty operands. .20: INC EBP MOV CL,2+1 Dispatch DL,%IiEnc2 JMP .30: enc %FOR %IiEnc2 .%enc: MOV ESI,=B"%enc[]," JMP .80: %ENDFOR enc .30: MOV CL,3+1 Dispatch DL,%IiEnc3 JMP .40: enc %FOR %IiEnc3 .%enc: MOV ESI,=B"%enc[]," JMP .80: %ENDFOR enc .40: MOV CL,4+1 Dispatch DL,%IiEnc4 JMP .50: enc %FOR %IiEnc4 .%enc: MOV ESI,=B"%enc[]," JMP .80: %ENDFOR enc .50: MOV CL,5+1 Dispatch DL,%IiEnc5 MOV ESI,=B"unknown," MOV CL,8 JMP .80: enc %FOR %IiEnc5 .%enc: MOV ESI,=B"%enc[]," JMP .80: %ENDFOR enc .80:BufferStore EBX,ESI,ECX .85:ROR EDX,8 ; Switch to the next operand, if any, DEC EDI ; but not more than four times. JNZ .10: BufferRetrieve EBX Invoke EaBufferRelease::,EBX JECXZ .n9: DEC ECX ; Omit the last comma. .n9:POPFD ; Restore input ZF. PUSH ECX,ESI MOV EBX,ESP ; Prepare Msg parameter !1S. Msg cc=NZ,PgmStatus=pgmLastPass,'7511',EBX ; Wrong operand combination !1S. Msg cc=Z,'1911',EBX ; Dispatching operand combination !1S. POP ESI,ECX RET ENDPROC1 IiDispatchFormatFail@RT:: %ENDMACRO IiDispatchFormat
IiDispatchSingleShift %MACRO Target CMPB [EDI+II.Operand2+EXP.Status],'R' ; Is Operand2 a register? JNE %Target CMPB [EDI+II.Operand2+EXP.Low],iiReg_R08+1 ; Is Operand2 register CL? JE %Target %ENDMACRO IiDispatchSingleShift
IiDispatchSuffix %MACRO D=, Q= suffix %FOR D,Q %label %SET2 %%%suffix %IF "%label" !=== "" JSt [EDI+II.MfgSuffix],iiMfgDATA_%suffix[]WORD, %label %ENDIF %ENDFOR suffix %ENDMACRO IiDispatchSuffix
Operand1,Operand2,Operand3,Operand4
.
IiDispatchNotAccum %MACRO OperandNr, Target TESTB [EDI+II.%OperandNr+EXP.Low],iiReg_Ord16 JNZ %Target %ENDMACRO IiDispatchNotAccum
IiDispatchCPU %MACRO CPU_386=, CPU_686=, CPU_X64= %IF "%CPU_386" !=== "" JSt [Ea.Eaopt.Machine::],iiCPU_386, %CPU_386 %ENDIF %IF "%CPU_686" !=== "" JSt [Ea.Eaopt.Machine::],iiCPU_686, %CPU_686 %ENDIF %IF "%CPU_X64" !=== "" JSt [Ea.Eaopt.Machine::],iiCPU_X64, %CPU_X64 %ENDIF %IF %# >0 %ERROR Id=5856,"Unexpected IiDispatchCPU argument %1 in %^PROC." %ENDIF %ENDMACRO IiDispatchCPU
JMP 0x400
, or it may be sssExtern when the target is EXTERN, for instance in instruction JMP ExternTarget::
. In this case the returned distance depends on program model:
JMPF ExternTarget::
with relocFar relocation.
JMPN ExternTarget::
with relocRel relocation.
IiDispatchLocation %MACRO TargetSection, RIP=, NEAR=, FAR= PUSH %TargetSection CALL IiDispatchLocation@RT:: ; Returns CF=1 if FAR, CF=0,ZF=1 if RIP, CF=0,ZF=0 if NEAR. %IF "%FAR" !=== "" JC %FAR %ENDIF %IF "%RIP" !=== "" JE %RIP %ENDIF %IF "%NEAR" !=== "" JA %NEAR %ENDIF IiDispatchLocation@RT:: PROC1 PUSHAD MOV ECX,[ESP+9*4] ; ECX=section of the target. MOV EDX,[EBX+STM.Section] ; EDX=section of the current instruction. It never should be 0. TEST EDX JZ .RIP: ; Something wrong happened. CMP ECX,EDX JE .RIP: ; Return with CF=0, ZF=1. RIP intrasection near or short transfer, resolvable at assembly time. MOV EAX,EDX ; Set EAX>0. ; Distance will be NEAR if both sections belong to the same segment|group. Otherwise it depends on the memory model. JECXZ .Model: MOV ECX,[ECX+SSS.SegmPtr] TEST EDX JZ .RIP: MOV EDX,[EDX+SSS.SegmPtr] CMP ECX,EDX JE .NEAR: ; Return with CF=0, ZF=0. NEAR intrasegment near transfer, resolvable at link time. MOV ECX,[ECX+SSS.GroupPtr] JECXZ .Model: TEST EDX JZ .Model: MOV EDX,[EDX+SSS.GroupPtr] CMP ECX,EDX JE .NEAR: .Model: ; Returned distance depends on program memory model. JSt [EDI+II.PgmoptStatus],pgmoptMEDIUM|pgmoptLARGE|pgmoptHUGE, .FAR: ; If the memory model has many code segments. .NEAR:CMP EAX,0 ; Set CF=0, ZF=0, NEAR intrasegment transfer resolvable at link time, relocRel will be required. JMP .RIP: .FAR: CMP EDX,-1 ; Set CF=1, ZF=0, FAR transfer, relocFar will be required. .RIP:POPAD RET 4 ENDP1 IiDispatchLocation@RT:: %ENDMACRO IiDispatchLocation
IiDispatchCode %MACRO SHORT=, LONG= %IF "%SHORT" !=== "" JSt [EDI+II.MfgExplicit],iiMfgCODE_SHORT, %SHORT %ENDIF %IF "%LONG" !=== "" JSt [EDI+II.MfgExplicit],iiMfgCODE_LONG, %LONG %ENDIF %IF %# >0 %ERROR Id=5857,"Unexpected IiDispatchCode argument %1 in %^PROC." %ENDIF %IF %# >0 %ERROR Id=5858,"Unexpected IiDispatchCode argument %1 in %^PROC." %ENDIF %ENDMACRO IiDispatchCode
IiDispatchData %MACRO BYTE=,WORD=,DWORD=,QWORD= %IF "%BYTE" !=== "" JSt [EDI+II.MfgEmitted],iiMfgDATA_BYTE, %BYTE JSt [EDI+II.MfgSuffix],iiMfgDATA_BYTE, %BYTE %ENDIF %IF "%WORD" !=== "" JSt [EDI+II.MfgEmitted],iiMfgDATA_WORD, %WORD JSt [EDI+II.MfgSuffix],iiMfgDATA_WORD, %WORD %ENDIF %IF "%DWORD" !=== "" JSt [EDI+II.MfgEmitted],iiMfgDATA_DWORD, %DWORD JSt [EDI+II.MfgSuffix],iiMfgDATA_DWORD, %DWORD %ENDIF %IF "%QWORD" !=== "" JSt [EDI+II.MfgEmitted],iiMfgDATA_QWORD, %QWORD JSt [EDI+II.MfgSuffix],iiMfgDATA_QWORD, %QWORD %ENDIF %IF "%BYTE" !=== "" JSt [EDI+II.MfgExplicit],iiMfgDATA_BYTE, %BYTE %ENDIF %IF "%WORD" !=== "" JSt [EDI+II.MfgExplicit],iiMfgDATA_WORD, %WORD %ENDIF %IF "%DWORD" !=== "" JSt [EDI+II.MfgExplicit],iiMfgDATA_DWORD, %DWORD %ENDIF %IF "%QWORD" !=== "" JSt [EDI+II.MfgExplicit],iiMfgDATA_QWORD, %QWORD %ENDIF %IF %# >0 %ERROR Id=5859,"Unexpected IiDispatchData argument %1 in %^PROC." %ENDIF %ENDMACRO IiDispatchData
IiDispatchDisp %MACRO BYTE=,WORD=,DWORD=,QWORD= %IF "%BYTE" !=== "" JSt [EDI+II.MfgExplicit],iiMfgDISP_BYTE, %BYTE %ENDIF %IF "%WORD" !=== "" JSt [EDI+II.MfgExplicit],iiMfgDISP_WORD, %WORD %ENDIF %IF "%DWORD" !=== "" JSt [EDI+II.MfgExplicit],iiMfgDISP_DWORD, %DWORD %ENDIF %IF "%QWORD" !=== "" JSt [EDI+II.MfgExplicit],iiMfgDISP_QWORD, %QWORD %ENDIF %IF %# >0 %ERROR Id=5860,"Unexpected IiDispatchDisp argument %1 in %^PROC." %ENDIF %ENDMACRO IiDispatchDisp
IiDispatchDist %MACRO SHORT=,NEAR=,FAR= %IF "%SHORT" !=== "" JSt [EDI+II.MfgSuffix],iiMfgDIST_SHORT, %SHORT %ENDIF %IF "%NEAR" !=== "" JSt [EDI+II.MfgSuffix],iiMfgDIST_NEAR, %NEAR %ENDIF %IF "%FAR" !=== "" JSt [EDI+II.MfgSuffix],iiMfgDIST_FAR, %FAR %ENDIF %IF "%SHORT" !=== "" JSt [EDI+II.MfgExplicit],iiMfgDIST_SHORT, %SHORT %ENDIF %IF "%NEAR" !=== "" JSt [EDI+II.MfgExplicit],iiMfgDIST_NEAR, %NEAR %ENDIF %IF "%FAR" !=== "" JSt [EDI+II.MfgExplicit],iiMfgDIST_FAR, %FAR %ENDIF %IF %# >0 %ERROR Id=5861,"Unexpected IiDispatchDist argument %1 in %^PROC." %ENDIF %ENDMACRO IiDispatchDist
IiDispatchImm %MACRO BYTE=,WORD=,DWORD=,QWORD= %IF "%BYTE" !=== "" JSt [EDI+II.MfgExplicit],iiMfgIMM_BYTE, %BYTE %ENDIF %IF "%WORD" !=== "" JSt [EDI+II.MfgExplicit],iiMfgIMM_WORD, %WORD %ENDIF %IF "%DWORD" !=== "" JSt [EDI+II.MfgExplicit],iiMfgIMM_DWORD, %DWORD %ENDIF %IF "%QWORD" !=== "" JSt [EDI+II.MfgExplicit],iiMfgIMM_QWORD, %QWORD %ENDIF %IF %# >0 %ERROR Id=5862,"Unexpected IiDispatchImm argument %1 in %^PROC." %ENDIF %ENDMACRO IiDispatchImm
[EDI+II.MfgImplicit]
by previous invocation of macro IiImmSize
and jumps to the coresponding label if it is specified.
IiDispatchImmSize %MACRO BYTE=,WORD=,DWORD=,QWORD= %IF "%BYTE" !=== "" JSt [EDI+II.MfgImplicit],iiMfgIMM_BYTE, %BYTE %ENDIF %IF "%WORD" !=== "" JSt [EDI+II.MfgImplicit],iiMfgIMM_WORD, %WORD %ENDIF %IF "%DWORD" !=== "" JSt [EDI+II.MfgImplicit],iiMfgIMM_DWORD, %DWORD %ENDIF %IF "%QWORD" !=== "" JSt [EDI+II.MfgImplicit],iiMfgIMM_QWORD, %QWORD %ENDIF %IF %# >0 %ERROR Id=5863,"Unexpected IiDispatchImmSize argument %1 in %^PROC." %ENDIF %ENDMACRO IiDispatchImmSize
[EDI+II.MfgExplicit]
or [EDI+II.MfgImplicit]
and jumps to the corresponding label if it is specified.
Otherwise the handler continues below the macro.
IiDispatchDataSize %MACRO DWORD=, QWORD=, OWORD=, YWORD= size %FOR DWORD,QWORD,OWORD,YWORD %label %SET2 %%%size %IF "%label" !=== "" JSt [EDI+II.MfgExplicit],iiMfgDATA_%size, %label %ENDIF %ENDFOR size size %FOR DWORD,QWORD,OWORD,YWORD %label %SET2 %%%size %IF "%label" !=== "" JSt [EDI+II.MfgImplicit],iiMfgDATA_%size, %label %ENDIF %ENDFOR size %ENDMACRO IiDispatchDataSize
[EDI+II.MfxExplicit]
, i.e. if the instruction has explicitly set keyword PREFIX=
, and jumps to the corresponding label if it is specified.
Otherwise the handler continues below the macro.
IiDispatchPrefix %MACRO VEX=, VEX2=, VEX3=, XOP=, MVEX=, EVEX= %IF "%VEX" !=== "" JSt [EDI+II.MfxExplicit],iiMfxPREFIX_VEX, %VEX %ENDIF %IF "%VEX2" !=== "" JSt [EDI+II.MfxExplicit],iiMfxPREFIX_VEX2, %VEX2 %ENDIF %IF "%VEX3" !=== "" JSt [EDI+II.MfxExplicit],iiMfxPREFIX_VEX3, %VEX3 %ENDIF %IF "%XOP" !=== "" JSt [EDI+II.MfxExplicit],iiMfxPREFIX_XOP, %XOP %ENDIF %IF "%MVEX" !=== "" JSt [EDI+II.MfxExplicit],iiMfxPREFIX_MVEX, %MVEX %ENDIF %IF "%EVEX" !=== "" JSt [EDI+II.MfxExplicit],iiMfxPREFIX_EVEX, %EVEX %ENDIF %ENDMACRO IiDispatchPrefix
[EDI+II.SssStatus]
and jumps to the label set in the corresponding keyword, if it is set.
IiDispatchWidth %MACRO BITS16=, BITS32=, BITS64= width %FOR BITS32,BITS64,BITS16 %label %SET2 %%%width %IF "%label" !=== "" JSt [EDI+II.SssStatus],sssWidth%width[5..6], %label %ENDIF %ENDFOR width %IF %# >0 %ERROR Id=5864,"Unexpected IiDispatchWidth argument %1 in %^PROC." %ENDIF %ENDMACRO IiDispatchWidth
moffs
, i.e. one operands is
accumulator register and the other is in memory addressed by offset only (no base, no index).
II.Displacement
.
and relocation segment to II.DispRelocSeg
.
Explicit instruction modifier DISP= is taken into account here, if possible.
II.MfgEmitted:iiMfgDISP_Mask
flags is set and request for absolute relocation
II.Reloc::iiRelocDispAbs
is set.
Operand1, Operand2, which contains [mem].
.
[EDI+II.MfgEmitted]:iiMfgDISP_Mask]
is set. Use short opcode.
IiDispSize %MACRO OperandNr %IF "%OperandNr[1..7]" !== "Operand" %ERROR Id=5865,'Wrong argument provided for macro IiDispSize.' %EXITMACRO IiDispSize %ENDIF PUSHD %OperandNr[8] * SIZE#EXP CALL IiDispSize@RT:: IiDispSize@RT:: PROC1 PUSH EAX,ECX,EDX,ESI MOV EDX,[ESP+20] ; OperandNr offset in II: 20,40,60,80. LEA ESI,[EDI+II.Operand1-SIZE#EXP+EDX] ; ^EXP with evalueted [mem] expression. MOV EAX,[ESI+EXP.Low] MOV EDX,[ESI+EXP.High] MOV ECX,[ESI+EXP.Seg] MOV [EDI+II.DispLow],EAX MOV [EDI+II.DispHigh],EDX MOV [EDI+II.DispRelocSeg],ECX MOV EAX,[ESI+EXP.Status] JSt EAX,expBasePres|expIndexPres, .CodeLong: AND EAX,expDwidth ; AH=0,3,4,5,6,7 = none,0,8,16,32,64 bits. IiDispatchWidth BITS32=.W.32:, BITS64=.W.64: JSt [EDI+II.MfgExplicit],iiMfgCODE_LONG|iiMfgSCALE_VERBATIM, .CodeLong: TEST ECX JNZ .Reloc16: ; Jump if [mem] is not scalar. JSt [EDI+II.MfgExplicit],iiMfgDISP_DWORD,.NorelA32: CMP AH,5 JA .NorelA32: ; If disp32 in 16bit segment and scalar exceeds 16 bits. JMP .Norel16: .W.32: JSt [EDI+II.MfgExplicit],iiMfgCODE_LONG|iiMfgSCALE_VERBATIM, .CodeLong: TEST ECX JNZ .Reloc32: JNSt [EDI+II.MfgExplicit],iiMfgDISP_WORD,.Norel32: ; No reason was found to use short encoding A0..A3 which is longer than ModR/M with DISP=(D)WORD. CMP AH,5 JA .Norel32: JMP .NorelA16: .W.64: TEST EDX ; Check high DWORD of displacement. Disp32 is zero-extended by 32bit addressing mode in 64bit mode. JNZ .Disp64: ; MOV EAX,[-1] in 64bit mode requires DISP=QWORD, A1FFFFFFFFFFFFFFFF. JSt [EDI+II.MfgExplicit],iiMfgDISP_QWORD, .Disp64: ; If explicitly requested 64bit displacement. JSt [EDI+II.MfgExplicit],iiMfgCODE_LONG|iiMfgSCALE_VERBATIM, .CodeLong: TEST ECX JNZ .RelocA32: .NorelA32:SetSt [EDI+II.PfxEmitted],iiPfxATOGGLE .Norel32:SetSt [EDI+II.MfgEmitted],iiMfgDISP_DWORD JMP .Norel: .Reloc16:SetSt [EDI+II.MfgEmitted],iiMfgDISP_WORD JMP .Reloc .RelocA32:SetSt [EDI+II.PfxEmitted],iiPfxATOGGLE .Reloc32:SetSt [EDI+II.MfgEmitted],iiMfgDISP_DWORD .Reloc: SetSt [EDI+II.Reloc],iiRelocDispAbs MOV ECX,[EDI+II.DispRelocSeg] JECXZ .Norel: MOV EAX,[ECX+SSS.SymPtr] MOV [EDI+II.DispRelocSym],EAX JMP .Norel: .NorelA16:SetSt [EDI+II.PfxEmitted],iiPfxATOGGLE .Norel16:SetSt [EDI+II.MfgEmitted],iiMfgDISP_WORD JMP .Norel: .CodeLong:STC ; Abort short encoding, use ModR/M. JMP .End: .Disp64:SetSt [EDI+II.MfgEmitted],iiMfgDISP_QWORD TEST ECX JNZ .Reloc: .Norel: SetSt [EDI+II.MfgEmitted],iiMfgADDR_ABS .End: POP ESI,EDX,ECX,EAX RET 4 ENDPROC1 IiDispSize@RT:: %ENDMACRO IiDispSize
EVEX.L'.L.b
. The actual combination is usually chosen by
registers width (XMM/YMM/ZMM) and by modifiers BCST=, ROUND=, SAE=, OPER=
. Code value x of each 4bit nibble (0..6) represents scaling factor
N=2x and x specifies how many bits (0..6) will CPU
shift-left the encoded disp8 to obtain the effective displacement value.
Special nibble value F signalizes that this combination (OPER= value)
is not permitted and will cause W2450.
If the macro does not appear in instruction handler and if EVEX encoding is used, €ASM will issue warning W2450 The value OPER=!1D is not supported in this MVEX/EVEX instruction , regardless of OPER= value.
Tuple | EVEX.L'.L.b alias OPER= | Code value | |||||||
---|---|---|---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ||
FV32 | 16 | 4 | 32 | 4 | 64 | 4 | - | - | 0x425262FF |
FV64 | 16 | 8 | 32 | 8 | 64 | 8 | - | - | 0x435363FF |
HV32 | 8 | 4 | 16 | 4 | 32 | 4 | - | - | 0x324252FF |
FVM | 16 | - | 32 | - | 64 | - | - | - | 0x4F5F6FFF |
T1S8 | 1 | - | 1 | - | 1 | - | - | - | 0x0F0F0FFF |
T1S16 | 2 | - | 2 | - | 2 | - | - | - | 0x1F1F1FFF |
T1S32 | 4 | - | 4 | - | 4 | - | - | - | 0x2F2F2FFF |
T1S64 | 8 | - | 8 | - | 8 | - | - | - | 0x3F3F3FFF |
T1F32 | 4 | - | 4 | - | 4 | - | - | - | 0x2F2F2FFF |
T1F64 | 8 | - | 8 | - | 8 | - | - | - | 0x3F3F3FFF |
T2F32 | 8 | - | 8 | - | 8 | - | - | - | 0x3F3F3FFF |
T2F64 | - | - | 16 | - | 16 | - | - | - | 0xFF4F4FFF |
T4F32 | - | - | 16 | - | 16 | - | - | - | 0xFF4F4FFF |
T4F64 | - | - | - | - | 32 | - | - | - | 0xFFFF5FFF |
T8F32 | - | - | - | - | 32 | - | - | - | 0xFFFF5FFF |
HVM | 8 | - | 16 | - | 32 | - | - | - | 0x3F4F5FFF |
QVM | 4 | - | 8 | - | 16 | - | - | - | 0x2F3F4FFF |
OVM | 2 | - | 4 | - | 8 | - | - | - | 0x1F2F3FFF |
M128 | 16 | - | 16 | - | 16 | - | - | - | 0x4F4F4FFF |
DUP | 8 | - | 32 | - | 64 | - | - | - | 0x3F5F6FFF |
IiDisp8EVEX %MACRO Tuple %CodeValue %SETA 0 %IF "%Tuple" == "FV32" %CodeValue %SETA 0x425262FF %ENDIF %IF "%Tuple" == "FV64" %CodeValue %SETA 0x435363FF %ENDIF %IF "%Tuple" == "HV32" %CodeValue %SETA 0x324252FF %ENDIF %IF "%Tuple" == "FVM" %CodeValue %SETA 0x4F5F6FFF %ENDIF %IF "%Tuple" == "T1S8" %CodeValue %SETA 0x0F0F0FFF %ENDIF %IF "%Tuple" == "T1S16" %CodeValue %SETA 0x1F1F1FFF %ENDIF %IF "%Tuple" == "T1S32" %CodeValue %SETA 0x2F2F2FFF %ENDIF %IF "%Tuple" == "T1S64" %CodeValue %SETA 0x3F3F3FFF %ENDIF %IF "%Tuple" == "T1F32" %CodeValue %SETA 0x2F2F2FFF %ENDIF %IF "%Tuple" == "T1F64" %CodeValue %SETA 0x3F3F3FFF %ENDIF %IF "%Tuple" == "T2F32" %CodeValue %SETA 0x3F3F3FFF %ENDIF %IF "%Tuple" == "T2F64" %CodeValue %SETA 0xFF4F4FFF %ENDIF %IF "%Tuple" == "T4F32" %CodeValue %SETA 0xFF4F4FFF %ENDIF %IF "%Tuple" == "T4F64" %CodeValue %SETA 0xFFFF5FFF %ENDIF %IF "%Tuple" == "T8F32" %CodeValue %SETA 0xFFFF5FFF %ENDIF %IF "%Tuple" == "HVM" %CodeValue %SETA 0x3F4F5FFF %ENDIF %IF "%Tuple" == "QVM" %CodeValue %SETA 0x2F3F4FFF %ENDIF %IF "%Tuple" == "OVM" %CodeValue %SETA 0x1F2F3FFF %ENDIF %IF "%Tuple" == "M128" %CodeValue %SETA 0x4F4F4FFF %ENDIF %IF "%Tuple" == "DUP" %CodeValue %SETA 0x3F5F6FFF %ENDIF %IF %CodeValue MOV [EDI+II.Disp8EVEX],%CodeValue, DATA=DWORD %ELSE %ERROR Id=5866,"Undefined Disp8EVEX value '%Tuple' in %^PROC." %ENDIF %ENDMACRO IiDisp8EVEX
MVEX.S2.S1.S0
provided as instruction modifier
OPER=
. Code value x of each 4bit nibble (0..6) represents scaling factor
N=2x and x specifies how many bits (0..6) will CPU
shift-left the encoded disp8 to obtain the effective displacement value.
Special nibble value F signalizes that this OPER= value is not permitted and will cause W2450.
If the macro does not appear in instruction handler and if MVEX encoding is used, €ASM will issue warning W2450 The value OPER=!1D is not supported in this MVEX/EVEX instruction , regardless of OPER= value.
Conversion | OPER= MVEX.S2.S1.S0 | Code value | |||||||
---|---|---|---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ||
Di32 | 4 | - | - | - | 1 | 1 | 2 | 2 | 0x2FFF0011 |
Df32 | 4 | - | - | 2 | 1 | 1 | 2 | 2 | 0x2FF10011 |
Sn64 | 8 | - | - | - | - | - | - | - | 0x3FFFFFFF |
Ui32 | 16 | - | - | - | 4 | 4 | 8 | 8 | 0x4FFF2233 |
Sn32 | 16 | - | - | 8 | 4 | 4 | 8 | 8 | 0x4FF32233 |
Si64 | 32 | - | - | - | - | - | - | - | 0x5FFFFFFF |
Sb32 | 32 | 4 | 16 | - | - | - | - | - | 0x524FFFFF |
Di64 | 64 | - | - | - | - | - | - | - | 0x6FFFFFFF |
Un32 | 64 | - | - | - | 16 | 16 | 32 | 32 | 0x6FFF4455 |
Dn32 | 64 | - | - | 32 | 16 | 16 | 32 | 32 | 0x6FF54455 |
Sf32 | 64 | - | 16 | - | - | - | - | - | 0x6F4FFFFF |
Si32 | 64 | 4 | 16 | - | 16 | 16 | 32 | 32 | 0x624F4455 |
Uf32 | 64 | 4 | 16 | 32 | 16 | 16 | 32 | 32 | 0x62454455 |
Us32 | 64 | 4 | 16 | 32 | 16 | - | 32 | 32 | 0x62454F55 |
Ub64 | 64 | 8 | 32 | - | - | - | - | - | 0x635FFFFF |
IiDisp8MVEX %MACRO Conversion %CodeValue %SETA 0 %IF "%Conversion" == "Di32" %CodeValue %SETA 0x2FFF0011 %ENDIF %IF "%Conversion" == "Df32" %CodeValue %SETA 0x2FF10011 %ENDIF %IF "%Conversion" == "Sn64" %CodeValue %SETA 0x3FFFFFFF %ENDIF %IF "%Conversion" == "Ui32" %CodeValue %SETA 0x4FFF2233 %ENDIF %IF "%Conversion" == "Sn32" %CodeValue %SETA 0x4FF32233 %ENDIF %IF "%Conversion" == "Si64" %CodeValue %SETA 0x5FFFFFFF %ENDIF %IF "%Conversion" == "Sb32" %CodeValue %SETA 0x524FFFFF %ENDIF %IF "%Conversion" == "Di64" %CodeValue %SETA 0x6FFFFFFF %ENDIF %IF "%Conversion" == "Un32" %CodeValue %SETA 0x6FFF4455 %ENDIF %IF "%Conversion" == "Dn32" %CodeValue %SETA 0x6FF54455 %ENDIF %IF "%Conversion" == "Sf32" %CodeValue %SETA 0x6F4FFFFF %ENDIF %IF "%Conversion" == "Si32" %CodeValue %SETA 0x624F4455 %ENDIF %IF "%Conversion" == "Uf32" %CodeValue %SETA 0x62454455 %ENDIF %IF "%Conversion" == "Us32" %CodeValue %SETA 0x62454F55 %ENDIF %IF "%Conversion" == "Ub64" %CodeValue %SETA 0x635FFFFF %ENDIF %IF %CodeValue MOV [EDI+II.Disp8MVEX],%CodeValue, DATA=DWORD %ELSE %ERROR Id=5867,"Undefined Disp8MVEX value '%Conversion' in %^PROC." %ENDIF %ENDMACRO IiDisp8MVEX
Macro IiModRM specifies that the ModRM byte should be emitted, optionally followed by SIB and displacement.
The actual ModR/M+SIB byte(s) will be generated later by IiCreateModRM.
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
Mod | Reg/Opcode |
R/M |
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
Scale | Index |
Base |
This macro should always be accompanied by IiOpEn, which declares
which operand is encoded in ModR/M fields Reg/Opcode
and R/M
.
/r /0 /1 /2 /3 /4 /5 /6 /7
or register EAX,EBX,ECX which contains either iiPpgModRMr
or /digit value 0..7 in position iiPpgModDigit combined with
iiPpgModRMd.
[EDI+II.Ppg]
is modified with iiPpgModRMr, iiPpgModRMd, iiPpgModDigit
.
IiModRM %MACRO RegOpcode %IF "%RegOpcode"=="EAX" | "%RegOpcode"=="EBX" | "%RegOpcode"=="ECX" OR [EDI+II.Ppg],%RegOpcode %ELSE %Ppg %SETA 0 %IF "%RegOpcode[2]" == "r" %Ppg %SETA iiPpgModRMr %ELSE ; /digit. %Ppg %SETA %RegOpcode[2] << 28 | iiPpgModRMd ; >> %ENDIF %IF %Ppg && "%RegOpcode[1]" === "/" SetSt [EDI+II.Ppg],%Ppg %ELSE %ERROR Id=5868,"Invalid RegOpcode specificator '%RegOpcode' in %^PROC." %ENDIF %ENDIF %ENDMACRO IiModRM
[EDI+II.Immediate]
and set its size using a flag from [EDI+II.MfgEmitted]:iiMfgIMM_Mask
. This tells
IiFlush to emit immediate value later.
[EDI+II.MfgEmitted]:iiMfgIMM_Mask
to achieve similar functionality.
Operand1
,
Operand2
,Operand3
,Operand4
. Specified operand in
II object must be a plain number type ('N') or address ('A'). Segment of address is ignored.
BYTE, WORD, DWORD, QWORD
.
IiEmitImm %MACRO OperandNr, Datatype, Max=0 %ExpNr %SETA %OperandNr[8] ; 1..4. %IF %ExpNr+0 <1 || %ExpNr+0 >4 %ERROR Id=5869,'Macro IiEmitImm in %^PROC expects 1st argument Operand1,Operand2,Operand3 or Operand4.' %EXITMACRO IiEmitImm %ENDIF %IF "%Datatype"=="" %ERROR Id=5870,'Macro IiEmitImm in %^PROC expects 2nd argument BYTE, WORD, DWORD or QWORD.' %EXITMACRO IiEmitImm %ENDIF PUSHD (%ExpNr-1) * SIZE#EXP | iiMfgIMM_%Datatype<<16 | %Max<<24 ;>>>> CALL IiEmitImm@RT:: IiEmitImm@RT:: PROC1 ; One combined operand is on stack. PUSH EAX,EDX MOV EDX,[ESP+12] ; The operand. AND EDX,0x000000FF ; 00h|14h|28h|3Ch operand index in II. ADD EDX,EDI ; EDX=^EXP. MOV EAX,[EDX+EXP.Low] MOV EDX,[EDX+EXP.High] MOV [EDI+II.ImmLow],EAX MOV [EDI+II.ImmHigh],EDX MOV EAX,[ESP+12] SHR EAX,16 MOV EDX,EAX AND EAX,iiMfgIMM_Mask ; EAX is now one flag of iiMfgIMM_Mask: 1,2,4,8. SHR EDX,8 ; Max value. SetSt [EDI+II.MfgEmitted],EAX TEST EDX JZ .90: CMP EDX,[EDI+II.ImmLow] JAE .90: Msg '2461',[EDI+II.ImmLow],EDX ; W2461 Immediate value !1D should not exceed !2D. .90:POP EDX,EAX RET 4 ENDPROC1 IiEmitImm@RT:: %ENDMACRO IiEmitImm
[EDI+II.Imm2]
and set the flag [EDI+II.Ppg]:iiPpgImm2
. This tells
IiFlush to emit secondary immediate value later.
Operand1
,
Operand2
,Operand3
,Operand4
. Specified operand in
II object must be a plain number type ('N')
and it must be encodable in 8 bits.
IiEmitImm2 %MACRO OperandNr, Max=255 %ExpNr %SETA %OperandNr[8] ; 1..4. %IF %ExpNr+0 <1 || %ExpNr+0 >4 %ERROR Id=5871,'Macro IiEmitImm2 expects 1st argument Operand1,Operand2,Operand3 or Operand4.' %EXITMACRO IiEmitImm2 %ENDIF PUSHD (%ExpNr-1) * SIZE#EXP | %Max<<24 ; >> CALL IiEmitImm2@RT:: IiEmitImm2@RT:: PROC1 ; One combined operand is on stack. PUSH EAX,ECX,EDX MOV EDX,[ESP+16] ; The operand. AND EDX,0x000000FF ; 00h|14h|28h|3Ch operand index in II. ADD EDX,EDI ; EDX=^EXP. CMPB [EDX+EXP.Status],'N' Msg cc=NE,'6746' ; E6746 Secondary immediate operand should be a plain number. MOV EAX,[EDX+EXP.Low] MOV EDX,[EDX+EXP.High] MOV [EDI+II.Imm2],AL SetSt [EDI+II.Ppg],iiPpgImm2 Invoke ExpWidth:: CMP CL,expWidth1B MOV ECX,[ESP+16] ; %1 procedure argument. Msg cc=A,'6747' ; E6747 Secondary immediate operand is too big for 1 byte. SHR ECX,24 ; CL=%Max. CMP AL,CL Msg cc=A,'2461',EAX,ECX ; W2461 Immediate value (!1D) should not exceed !2D. .90:POP EDX,ECX,EAX RET 4 ENDPROC1 IiEmitImm2@RT:: %ENDMACRO IiEmitImm2
II.Reloc
which is the request for relocation
and optionally for attribute evaluation of external symbol postponed to link time.
iiRelocDisp*
or
iiRelocImm*
flags in IiRelocEnc encoding.
Operand1, Operand2, Operand3, Operand4
or omitted.
II.Reloc
.
IiReloc %MACRO IiRelocType, OperandNr %IF %# = 1 SetSt [EDI+II.Reloc],%IiRelocType %ELSE SetSt [EDI+II.Reloc],iiRelocExtAttrReq + %IiRelocType + II.%OperandNr %ENDIF %ENDMACRO IiReloc
[EDI+II.Opcode]
and modifies [EDI+II.MfgEmitted:iiPpgOpcodeSizeMask]
accordingly.
0xF5
, or as 32bit register, e.g. EAX
from which only LSB is used.
IiEmitOpcode %MACRO Operand %FOR %* PUSHD %Operand CALL IiEmitOpcode@RT:: %ENDFOR Operand IiEmitOpcode@RT:: PROC1 ; Input: EDI=^II, Stack=Byte to emit. PUSH EAX,EDX MOV EAX,[ESP+12] ; Operand is now in AL. MOV EDX,[EDI+II.Ppg] ; iiPpgOpcodeSizeMask is in lowest 4 bits. INC EDX MOV [EDI+II.Ppg],EDX AND EDX,iiPpgOpcodeSizeMask JZ .90: ; Out of II.Opcode, this should never happen ; unless IiEmitOpcode is called more than 15 times by mistake. MOV [EDI+II.Opcode+EDX-1],AL .90: POP EDX,EAX RET 4 ENDPROC1 IiEmitOpcode@RT:: %ENDMACRO IiEmitOpcode
[EDI+II.PfxEmitted]
. Specficators applicable on AVX prefix are separated with dot
., they are stored as a pointer to source-specification string into
[EDI+II.AvxSrc*]
. The actual AVX prefix will be parsed from them later by
IiAssembleAVX.
Prefix specificator | Encoding flag | II.member | Applicable on AVX prefix |
---|---|---|---|
LOCK | iiPfxLOCK | II.PfxEmitted | - |
REP | iiPfxREP | II.PfxEmitted | - |
REPE | iiPfxREPE | II.PfxEmitted | - |
REPNE | iiPfxREPNE | II.PfxEmitted | - |
ATOGGLE | iiPfxATOGGLE | II.PfxEmitted | - |
OTOGGLE | iiPfxOTOGGLE | II.PfxEmitted | - |
REX | iiPfxREX | II.PfxEmitted | - |
REX.W | iiPfxREX.W | II.PfxEmitted | - |
REX.R | iiPfxREX.R | II.PfxEmitted | - |
REX.X | iiPfxREX.X | II.PfxEmitted | - |
REX.B | iiPfxREX.B | II.PfxEmitted | - |
128 | iiMfgDATA_OWORD | II.MfgImplicit | XOP,VEX,MVEX,EVEX |
256 | iiMfgDATA_YWORD | II.MfgImplicit | XOP,VEX,MVEX,EVEX |
512 | iiMfgDATA_ZWORD | II.MfgImplicit | MVEX,EVEX |
XOP | iiMfxPREFIX_XOP | II.MfxEmitted | XOP |
VEX | iiMfxPREFIX_VEX | II.MfxEmitted | VEX2,VEX3 |
VEX2 | iiMfxPREFIX_VEX2 | II.MfxEmitted | VEX2 |
VEX3 | iiMfxPREFIX_VEX3 | II.MfxEmitted | VEX3 |
MVEX | iiMfxPREFIX_MVEX | II.MfxEmitted | MVEX |
EVEX | iiMfxPREFIX_EVEX | II.MfxEmitted | EVEX |
NDD | iiPpxNDD | II.Ppx | XOP,VEX,MVEX,EVEX |
NDS | iiPpxNDS | II.Ppx | XOP,VEX,MVEX,EVEX |
DDS | iiPpxDDS | II.Ppx | XOP,VEX,MVEX,EVEX |
W0 | iiPpxW0 | II.Ppx | XOP,VEX,MVEX,EVEX |
W1 | iiPpxW1 | II.Ppx | XOP,VEX3,MVEX,EVEX |
WIG | - | II.Ppx | XOP,VEX,MVEX,EVEX |
LZ | iiPpxL0 | II.Ppx | XOP,VEX,MVEX,EVEX |
L0 | iiPpxL0 | II.Ppx | XOP,VEX,MVEX,EVEX |
L1 | iiPpxL1 | II.Ppx | XOP,VEX,MVEX,EVEX |
LIG | - | II.Ppx | XOP,VEX,MVEX,EVEX |
66 | iiPpxPpMask 01 | II.Ppx | XOP,VEX,MVEX,EVEX |
F2 | iiPpxPpMask 11 | II.Ppx | XOP,VEX,MVEX,EVEX |
F3 | iiPpxPpMask 10 | II.Ppx | XOP,VEX,MVEX,EVEX |
0F | iiPpxMmMask 01 | II.Ppx | VEX,MVEX,EVEX |
0F38 | iiPpxMmMask 10 | II.Ppx | VEX3,MVEX,EVEX |
0F3A | iiPpxMmMask 11 | II.Ppx | VEX3,MVEX,EVEX |
MAP8 | iiPpxMmMask 00 | II.Ppx | XOP |
MAP9 | iiPpxMmMask 01 | II.Ppx | XOP |
MAP10 | iiPpxMmMask 10 | II.Ppx | XOP |
EH0 | iiPpxEH0 | II.Ppx | MVEX |
EH1 | iiPpxEH1 | II.Ppx | MVEX |
IiEmitPrefix %MACRO %AVXprefixes %SET XOP.,VEX.,EVEX,MVEX spec %FOR %* %unknown %SETB TRUE %AVXtype %SETB FALSE AVXprefix %FOR %AVXprefixes %IF "%spec[1..4]" == "%AVXprefix" %AVXtype %SETB TRUE %ENDIF %ENDFOR %IF !%AVXtype SetSt [EDI+II.PfxEmitted],iiPfx%spec %IF "%spec[1..3]" === "REX" RstSt [EDI+II.Ppx],iiPpxRemoveREX+iiPpxRemoveREX.W+iiPpxRemoveREX.R %ENDIF %unknown %SETB FALSE %ELSE ; Otherwise it must be AVX string, e.g. VEX.NDS.256.66.0F.WIG. %avx %SET %spec[1..4] %IF "%avx" === "XOP." MOVD [EDI+II.AvxSrcXOP],=B"%spec" %unknown %SETB FALSE %ENDIF %IF "%avx" === "VEX." MOVD [EDI+II.AvxSrcVEX],=B"%spec" %unknown %SETB FALSE %ENDIF %IF "%avx" === "EVEX" MOVD [EDI+II.AvxSrcEVEX],=B"%spec" %unknown %SETB FALSE %ENDIF %IF "%avx" === "MVEX" MOVD [EDI+II.AvxSrcMVEX],=B"%spec" %unknown %SETB FALSE %ENDIF %ENDIF %IF %unknown %ERROR Id=5872,"Unknown IiEmitPrefix operand '%spec' in '%^PROC'." %ENDIF %ENDFOR spec %ENDMACRO IiEmitPrefix
EUROASM DISPLAYENC=ENABLED
.
MfgEmitted
and MfxEmitted
are set.
IiEncoding %MACRO R32, IMM=None,DISP=None,DATA=None,SCALE=None,DIST=None,ADDR=None,CODE=None, \ BCST=None,MASK=None,OPER=None,ROUND=None,SAE=None,BCST=None,EH=None,ZEROING=None,PREFIX=None %Mfg %SETA iiMfgIMM_%IMM|iiMfgDISP_%DISP|iiMfgDATA_%DATA|iiMfgSCALE_%SCALE|iiMfgDIST_%DIST|iiMfgADDR_%ADDR|iiMfgCODE_%CODE %Mfx %SETA iiMfxMASK_%MASK|iiMfxOPER_%OPER|iiMfxROUND_%ROUND|iiMfxSAE_%SAE|iiMfxBCST_%BCST|iiMfxEH_%EH|iiMfxZEROING_%ZEROING|iiMfxPREFIX_%PREFIX %IF %Mfg SetSt [EDI+II.MfgEmitted],%Mfg %ENDIF %IF %Mfx SetSt [EDI+II.MfxEmitted],%Mfx %ENDIF %IF "%R32"!==="" OR [EDI+II.MfgEmitted],%R32 %ENDIF %ENDMACRO IiEncoding
[EDI+II.Ppg]
as
general properties iiPpgModRegOp, iiPpgModRMOp, iiPpgVEXvOp
.
IiOpEn %MACRO OpEnCode %Ppg %SETA 0 %IF "%OpEnCode" == "RM" %Ppg %SETA 0x0900_0000 %ENDIF %IF "%OpEnCode" == "MR" %Ppg %SETA 0x0600_0000 %ENDIF %IF "%OpEnCode" == "VM" %Ppg %SETA 0x0840_0000 %ENDIF %IF "%OpEnCode" == "RVM" %Ppg %SETA 0x0D80_0000 %ENDIF %IF "%OpEnCode" == "RMV" %Ppg %SETA 0x09C0_0000 %ENDIF %IF "%OpEnCode" == "MVR" %Ppg %SETA 0x0780_0000 %ENDIF %IF "%OpEnCode" == "M" %Ppg %SETA 0x0400_0000 %ENDIF %IF "%OpEnCode" == "V" %Ppg %SETA 0x0040_0000 %ENDIF RstSt [EDI+II.Ppg],iiPpgVEXvOp|iiPpgModRegOp|iiPpgModRMOp %IF %Ppg SetSt [EDI+II.Ppg],%Ppg %ELSE %ERROR Id=5873,"Unknown OpEnCode '%OpEnCode' in %^PROC." %ENDIF %ENDMACRO IiOpEn
Operand1, Operand2, Operand3, Operand4
.
iiPpgImm2
is set and ordinal number of SSE register is encoded in bits 4..7 of
[EDI+II.Imm2]
.
IiIs4 %MACRO OperandNr PUSH EAX Invoke IiGetRegOrdinal::, [EDI+II.%OperandNr+EXP.Low] CMP AL,15 Msg cc=A,'6768' ; Only SSE register 0..15 may be used as 4th operand. JSt [EDI+II.SssStatus],sssWidth64,.is4.%.: CMP AL,7 Msg cc=A,'6767' ; Only SSE register 0..7 may be used as 4th operand. .is4.%.: SAL AL,4 OR [EDI+II.Imm2],AL SetSt [EDI+II.Ppg],iiPpgImm2 POP EAX %ENDMACRO IiIs4
II.Imm
and its section, if any, to II.ImmRelocSeg
.
II.Reloc
, this is the job of IiReloc.
Operand1, Operand2, Operand3, Operand4
.
II.ImmLow, II.ImmHigh, II.ImmRelocSeg, II.ImmRelocSym, II.Para
are updated.
[EDI+II.MfgImplicit]:iiMfgIMM_Mask]
is set.
IiImmSize %MACRO OperandNr %ExpNr %SETA %OperandNr[8] ; 1..4. %IF %ExpNr+0 <1 || %ExpNr+0 >4 %ERROR Id=5874,'Macro IiEmitImm in %^PROC expects 1st argument Operand1,Operand2,Operand3 or Operand4.' %EXITMACRO IiImmSize %ENDIF PUSHD (%ExpNr-1) * SIZE#EXP CALL IiImmSize@RT:: IiImmSize@RT:: PROC1 PUSHAD MOV ESI,[ESP+36] ; Load macroparameter with operand offset in II. ADD ESI,EDI ; ESI=^EXP (expression with immediate operand). SetSt [EDI+II.MfgAllowed],iiMfgIMM_Mask MOV EAX,[ESI+EXP.Low] MOV EDX,[ESI+EXP.High] MOV [EDI+II.ImmLow],EAX MOV [EDI+II.ImmHigh],EDX Invoke ExpWidthSigned:: ; Calculate the width of number EDX:EAX. Dispatch CL,expWidth2B,expWidth4B,expWidth8B ; CL=3,4,5,6,7 for immediate operand width 8,8,16,32,64. .expWidth1B: MOV EBX,iiMfgIMM_BYTE JMP .50: .expWidth2B: MOV EBX,iiMfgIMM_WORD JMP .50: .expWidth8B: MOV EBX,iiMfgIMM_QWORD JMP .50: .expWidth4B: MOV EBX,iiMfgIMM_DWORD .50: MOV EAX,[ESI+EXP.Status] MOV ECX,[ESI+EXP.Seg] MOV EDX,[ESI+EXP.Sym] AND AL,expDataType Dispatch AL,'N','A','F','P' JMP .90: ; Do nothing when the operand is not immediate. .F: ; Operand is direct far immediate, e.g.0040h:0
MOV [EDI+II.Para],CX ; EXP.Seg contains Para value instead of ^SSS. CMP ECX,0x0000FFFF Msg cc=A,'6771',ECX ; Immediate segment value !1Hh is too big for 16 bits. SetSt [EDI+II.Ppg],iiPpgPara ; Request to emit imm Para value after imm offset. JMP .80: .P: ; Operand is a paragraph address, e.g.PARA# Main
. .N: ; Operand is immediate address or number. .A: MOV [EDI+II.ImmRelocSeg],ECX ; Prepare for the case of future relocation. MOV [EDI+II.ImmRelocSym],EDX ; Prepare for the case of future relocation. .80: SetSt [EDI+II.MfgImplicit],EBX .90:POPAD RET 4 ENDPROC1 IiImmSize@RT:: %ENDMACRO IiImmSize
Operand1, Operand2, Operand3, Operand4
.
IiImmCreate %MACRO ImmValue, OpPosition=Operand4 SHL EDX,8 MOV DL,imm MOV [EDI+II.%OpPosition+EXP.Low],%ImmValue MOVB [EDI+II.%OpPosition+EXP.Status],'N' %ENDMACRO IiImmCreate
INC EAX
always operates with 32 bits.II.MfgSuffix:iiMfgDATA_Mask
will be taken into account, if used.
For instance, in instruction INCB [ESI+6]
a BYTE memory variable is incremented.II.MfgExplicit:iiMfgDATA_Mask
, for instance INC [Symbol],DATA=WORD
.INC [DwordSymbol]
32 bit DWORD is incremented, on assumption that
DwordSymbol was defined as DwordSymbol DD value
.
FADD ST0,[DwordSymbol]
, size is determined from that type and not from FP register.
JMPN [ESI]
, and UseSegment=ON,
operand size is adopted from the current segment width.INC [EBX]
.Operand1
asks the macro
to determine operand size from operand 1 only. This happens in instructions like
SHL [WordVar],CL
which have operand size Word, although operand 2 is 8bit register.
[EDI+II.MfgEmitted]:iiMfgDATA_Mask]
is set.
[EDI+II.MfgAllowed:iiMfgDATA_Mask
is set.
[EDI+II.PfxEmitted]
if necessary.
II.MfgImplicit
may be updated, II.PfxEmitted
requested.
[EBX+STM.Status]:stmOperationPresent
is reset on error.
IiDataSize %MACRO Hint, AllowQword=OFF, SpecifyMem=ON, UseSegment=OFF, FloatingPoint=OFF, StreamingSIMD=OFF, %HintValue %SETA 0 ; Combined operand which will be passed to runtime proc. %if "%Hint"=="BYTE"||"%Hint"=="WORD"||"%Hint"=="DWORD"||"%Hint"=="QWORD"||"%Hint"=="OWORD"||"%Hint"=="YWORD"||"%Hint"=="ZWORD" %HintValue %SETA iiMfgDATA_%Hint %ENDIF %IF "%Hint"=="Operand1" %HintValue %SETA %HintValue | iiOsUseOperand1 %ENDIF %IF "%Hint"=="Operand2" %HintValue %SETA %HintValue | iiOsUseOperand2 %ENDIF %IF "%Hint"=="Operand3" %HintValue %SETA %HintValue | iiOsUseOperand3 %ENDIF %IF %HintValue=0 ; If none of the options above applied. %HintValue %SETA iiOsUseOperand1 + iiOsUseOperand2 ; Default. %ENDIF %IF %HintValue=0 && "%Hint" !=== "" %ERROR Id=5875,'Invalid IiDataSize operand "%Hint" in %^PROC.' %ENDIF %IF "%AllowQword" !== "OFF" %HintValue %SETA %HintValue | iiOsAllowQword %ENDIF %IF "%SpecifyMem" !== "ON" %HintValue %SETA %HintValue | iiOsSpecifyMemOff %ENDIF %IF "%UseSegment" !== "OFF" %HintValue %SETA %HintValue | iiOsUseSegment %ENDIF %IF "%FloatingPoint" !== "OFF" %HintValue %SETA %HintValue | iiOsFloatingPoint %ENDIF %IF "%StreamingSIMD" !== "OFF" %HintValue %SETA %HintValue | iiOsStreamingSIMD %ENDIF PUSHD %HintValue CALL IiDataSize@RT: JSt [EBX+STM.Status],stmOperationPresent,.cont%.: RET ; Abort instruction handler when E6730 or E6732 was reported in IiDataSize@RT. .cont%.: IiDataSize@RT: PROC1 PUSH EAX,ECX,ESI,EBP MOV EBP,[ESP+20] ; Load parameter Hint. IiAllowModifier DATA MOV EAX,EBP JSt EAX,iiMfgDATA_Mask,.30: ; If iiMfgDATA_Mask flag determined explicitly by Hint, we're done. JNSt EBP,iiOsUseOperand3,.10: ; Skip getting the size from operand 3. ; Determine operand size from II.Operand3. LEA ESI,[EDI+II.Operand3] CALL .SizeFromOperandESI: JMP .30: ; Operand1 and Operand2 are not consulted when Hint is Operand3. .SizeFromOperandESI PROC1 ; Input: ESI=^EXP with operand, EBP=Hint. MOV ECX,[ESI+EXP.Status] ; Output: EAX=iiMfgDATA_Mask+iiPpgOperSizeByReg+iiPpgOperSizeBySss, ECX=destroyed. XOR EAX,EAX Dispatch CL,'R','M' .Ret: RET ; Operand size cannot be determined by this operand. .M: MOV ECX,[ESI+EXP.Sym] JECXZ .Ret: MOV ECX,[ECX+SYM.Status] Dispatch CL,'B','U','W','D','Q','T','O','Y','Z' RET .R: Invoke IiGetRegFamily::, [ESI+EXP.Low] ; Returns registers family in EAX. MOV ECX,EAX MOV EAX,iiPpgOperSizeBySss CMP CL,iiReg_SEG JE .Ret: ; Segment register does not specify the operand size. JSt EBP,iiOsFloatingPoint,.Ret: ; FPR does not specify the operand size. MOV EAX,iiPpgOperSizeByReg Dispatch CL,iiReg_R08,iiReg_R16,iiReg_R32,iiReg_R64, \ iiReg_FPR, iiReg_XMM, iiReg_YMM, iiReg_ZMM XOR EAX,EAX RET ; Operand size cannot be determined by this register. .iiReg_R08: .B: SetSt EAX,iiMfgDATA_BYTE RET .iiReg_R16: .U: .W: SetSt EAX,iiMfgDATA_WORD RET .iiReg_R32: .D: SetSt EAX,iiMfgDATA_DWORD RET .iiReg_FPR: .T: SetSt EAX,iiMfgDATA_TBYTE RET .iiReg_R64: .Q: SetSt EAX,iiMfgDATA_QWORD RET .iiReg_XMM: .O: SetSt EAX,iiMfgDATA_OWORD RET .iiReg_YMM: .Y: SetSt EAX,iiMfgDATA_YWORD RET .iiReg_ZMM: .Z: SetSt EAX,iiMfgDATA_ZWORD RET ENDP1 .SizeFromOperandESI .10: JNSt EBP,iiOsUseOperand2,.20: ; Skip getting the size from operand 2. ; Determine operand size from II.Operand2. LEA ESI,[EDI+II.Operand2] CALL .SizeFromOperandESI: PUSH EAX RstSt EAX,iiMfgDATA_Mask ; Those bits do not go to II.Ppg. SetSt [EDI+II.Ppg],EAX POP EAX JSt EAX,iiPpgOperSizeByReg,.30: ; If determined by register, we're done. MOV ECX,EAX ; Temporary store operand size by 2. operand. .20: MOV ESI,EBP ; Retrieve Hint again. JNSt ESI,iiOsUseOperand1, .25: ; Skip getting the size from operand 1. ; Determine operand size from II.Operand1. LEA ESI,[EDI+II.Operand1] PUSH ECX ; Keep datasize from Operand2, if any. CALL .SizeFromOperandESI: POP ECX PUSH EAX RstSt EAX,iiMfgDATA_Mask ; Those bits do not go to II.Ppg. SetSt [EDI+II.Ppg],EAX POP EAX JSt EAX,iiPpgOperSizeByReg,.30: ; If size is determined by register, we're done. OR ECX,EAX ; Accumulate flags size hints of first two operands to ECX. .25: MOV EAX,[EDI+II.MfgSuffix] ; If not determined by register, try suffix. JSt EAX,iiMfgDATA_Mask,.30: ; If determined by suffix, we're done. MOV EAX,[EDI+II.MfgExplicit] ; If not determined by register and suffix, try DATA= modifier. JSt EAX,iiMfgDATA_Mask,.30: ; If determined by modifier, we're done. MOV EAX,ECX ; If not determined by the register, suffix, modifier, use memory datatype in ECX. .30: AND EAX,iiMfgDATA_Mask JNZ .35: ; If determined by memory type, we're done. JNSt EBP,iiOsFloatingPoint,.31: ; If FloatingPoint=ON and no operand is [memory], use register width. CMPB [ESI+II.Operand1],'M' JE .31: CMPB [ESI+II.Operand2],'M' JE .31: CMPB [ESI+II.Operand3],'M' JE .31: MOV EAX,iiMfgDATA_TBYTE ; If FloatingPoint=ON, use register width in reg-reg operations. JMP .35: .31: JSt EBP,iiOsUseSegment,.33: ; If not operand size not specified yet, use segment width. .E6730:Msg PgmStatus=pgmLastPass,'6730' ; Operand size could not be determined, please use DATA= modifier. JMPN .Err: .33: MOV ECX,[EDI+II.SssStatus] AND ECX,sssWidthMask SHR ECX,15 ; Convert sssWidthMask to iiMfgDATA_Mask. .34: OR EAX,ECX ; Use segment width as operand size. ; JMP .35: .35: OR [EDI+II.MfgEmitted],EAX ; Effective operand size finally set. MOV ESI,EBP ; Hint. JSt EBP,iiOsFloatingPoint,.60: ; In FP instruction the operand size does not use OTOGGLE and REX.W. JSt [EDI+II.MfgEmitted],iiMfgDATA_TBYTE,.E6730: ; TBYTE is allowed in FP instructions only. ; Require implicit prefixes REX.W and OTOGGLE, if necessary. MOV ECX,[EDI+II.SssStatus] ; Segment width. JNSt ECX,sssWidth64,.40: JSt EAX,iiMfgDATA_QWORD,.REX.W ; 64bit operand in 64bit segment. JSt EAX,iiMfgDATA_WORD,.OTOGGLE ; 16bit operand in 64bit segment. .40: JNSt ECX,sssWidth32,.50: JSt EAX,iiMfgDATA_WORD,.OTOGGLE ; 16bit operand in 32bit segment. JSt ESI,iiOsAllowQword,.60: JSt EAX,iiMfgDATA_QWORD,.E6732: ; 64bit operand in 32bit segment. .50: JNSt ECX,sssWidth16,.60: JSt EAX,iiMfgDATA_DWORD,.OTOGGLE: ; 32bit operand in 16bit segment. JSt ESI,iiOsAllowQword,.60: JSt EAX,iiMfgDATA_QWORD,.E6732: ; 64bit operand in 16bit segment. JMP .60: .E6732:Msg '6732' ; Required operand-size 64 can be used in 64bit segment only. .Err: RstSt [EBX+STM.Status],stmOperationPresent ; Cancel the instruction. JMP .90: .REX.W:SetSt [EDI+II.PfxEmitted],iiPfxREX.W JMP .60: .OTOGGLE:JSt ESI,iiOsStreamingSIMD,.60: SetSt [EDI+II.PfxEmitted],iiPfxOTOGGLE .60: ; EAX is now the effective operand width encoded as iiMfgDATA_Mask. ; EDX may have Intel-encoded memory operand with unspecified width (mem) in some of its bytes. ; mem will be replaced with m8, m16, m32, m64, m80, m128, m256, m512. JSt EBP,iiOsSpecifyMemOff,.90: ; Do not replace mem if SpecifyMem=OFF. MOV ECX,4 ; Number of bytes representing operands in EDX. MOV AL,m32 JSt EAX,iiMfgDATA_DWORD,.70: MOV AL,m16 JSt EAX,iiMfgDATA_WORD,.70: MOV AL,m64 JSt EAX,iiMfgDATA_QWORD,.70: MOV AL,m80 JSt EAX,iiMfgDATA_TBYTE,.70: MOV AL,m8 JSt EAX,iiMfgDATA_BYTE,.70: MOV AL,m128 JSt EAX,iiMfgDATA_OWORD,.70: MOV AL,m256 JSt EAX,iiMfgDATA_YWORD,.70: MOV AL,m512 JSt EAX,iiMfgDATA_ZWORD,.70: MOV AL,mem .70: CMP DL,mem JNE .80: MOV DL,AL .80: ROR EDX,8 DEC ECX JNZ .70: ; Repeat four times. .90: POP EBP,ESI,ECX,EAX RET 4 ENDPROC1 IiDataSize@RT: %ENDMACRO IiDataSize
[EDI+II.PfxEmitted]
.
IiRemoveOTOGGLE %MACRO RstSt [EDI+II.PfxEmitted],iiPfxOTOGGLE %ENDMACRO IiRemoveOTOGGLE
[EDI+II.PfxEmitted]
.
IiRemoveREXR %MACRO ORD [EDI+II.Ppx],iiPpxRemoveREX.R + iiPpxRemoveREX %ENDMACRO IiRemoveREXR
[EDI+II.PfxEmitted]
.
IiRemoveREXW %MACRO ORD [EDI+II.Ppx],iiPpxRemoveREX.W + iiPpxRemoveREX %ENDMACRO IiRemoveREXW
386,586,X64,
SSE,SSE4.2,AVX512,
AMD,PROT,UNDOC
II.Cpu
and II.Features
.
IiRequire %MACRO %IiCpu %SETA 0 %IiFea %SETA 0 %REPEAT %Illegal %SETB 1 cpu %FOR %IiCpuList, %IiSimdList %IF "%1"==="%cpu" %Illegal %SETB 0 %IiCpu %SETA %IiCpu | iiCPU_%cpu %EXITFOR ; Break the further list investigations when item found. %ENDIF %ENDFOR cpu fea %FOR %EaoptFeaList %IF "%1"==="%fea" %Illegal %SETB 0 %IiFea %SETA %IiFea | iiFea_%fea %EXITFOR ; Break the further list investigations when item found. %ENDIF %ENDFOR fea %IF %Illegal %ERROR Id=5876,'Illegal IiRequire option "%1".' %ENDIF %SHIFT ; Take the next macroargument. %UNTIL "%1"==="" %IF %IiCpu OR [EDI+II.Cpu],%IiCpu,DATA=DWORD,IMM=DWORD %ENDIF %IF %IiFea OR [EDI+II.Features],%IiFea,DATA=DWORD,IMM=DWORD %ENDIF %ENDMACRO IiRequire
[ES:DI]
. Only ES can be used as segment override when AllowSeg=OFF.
This macro will request for ATOGGLE if necessary, and for SEGxS when AllowSeg=ON.
Operand1, Operand2
.
IiStringDestination %MACRO OperandNr, AllowSeg=OFF %IF "%OperandNr[1..7]" !== "Operand" %ERROR Id=5877,'Wrong argument provided for macro IiStringDestination.' %EXITMACRO IiStringDestination %ENDIF %IF "%AllowSeg"=="OFF" PUSHD %OperandNr[8] * SIZE#EXP %ELSE PUSHD %OperandNr[8] * SIZE#EXP + iiSdAllowSeg %ENDIF CALL IiStringDestination@RT:: IiStringDestination@RT:: PROC1 %IiSdParam %SET ESP+12 PUSH EAX,EDX MOV EAX,[%IiSdParam] ; 20,40,60,80. AND EAX,0x000000FF ; Mask off iiSdAllowSeg flag, if present. LEA EDX,[EDI+II.Operand1-SIZE#EXP+EAX] ; ^EXP with %OperandNr. Its must be 'M' type. MOV EAX,expAwidth AND EAX,[EDX+EXP.Status] JZ .50: ; If address-size is not specified by base register width, keep default segment width. No ATOGGLE required. SHL EAX JC .20: ; If r64 or r32 used in [mem]. JSt [EDI+II.SssStatus],sssWidth16,.50: JSt [EDI+II.SssStatus],sssWidth32,.ATOGGLE: Msg '6733' ; Required address width 16 cannot be used in 64bit segment. JMP .Abort: .20: SHL EAX JC .30: ; If r64 used in [mem]. JSt [EDI+II.SssStatus],sssWidth16|sssWidth64, .ATOGGLE: JMP .50: .30: JSt [EDI+II.SssStatus],sssWidth64,.50: Msg '6731' ; Required address width 64 can be used in 64bit segment only. .Abort:ADD ESP,16 RET ; Abort the parent handler. .ATOGGLE: SetSt [EDI+II.PfxEmitted],iiPfxATOGGLE .50: MOV EAX,[EDX+EXP.Status] JNSt EAX,expSegmPres,.70: ; Segment register present in operand. JSt [%IiSdParam],iiSdAllowSeg, .55: ; Only ES is allowed. JNSt EAX,expSegm, .70: ; If ordinal=0 (ES), continue. .E6758:Msg '6758' ; Wrong string destination specified. Only [ES:rDI] is acceptable. JMP .Abort: .55: AND EAX,expSegm ; Any segment register is allowed, default is DS. SHR EAX,24 ; EAX is now Sreg ordinal 0..5. CMP AL,3 JE .70: ; Ignore implicit segment-register DS. JNA .60: IiRequire 386 ; FS or GS requires 386. .60: ADD AL,20 ; EAX is now 20..25, i.e. iiPfxSEGES..iiPfxSEGGS. BTS [EDI+II.PfxEmitted],EAX ; Request for segment override. .70: MOV EAX,[EDX+EXP.Status] JSt EAX,expScalePres,.E6758: JNSt EAX,expBasePres, .80: JSt EAX,expIndexPres,.E6758: SHL EAX,4 ; Move base to index position in EXP.Status. JMP .85: .80: JNSt EAX,expIndexPres,.90: .85: AND EAX,expIndex CMP EAX,0x00700000 JNE .E6758: ; If not rDI. .90:POP EDX,EAX RET 4 ENDPROC1 IiStringDestination@RT:: %ENDMACRO IiStringDestination
[ES:SI]
.
This macro will request for segment override and request for ATOGGLE and segment prefix if necessary.
Operand1, Operand2
.
IiStringSource %MACRO OperandNr %IF "%OperandNr[1..7]" !== "Operand" %ERROR Id=5878,'Wrong argument provided for macro IiStringSource.' %EXITMACRO IiStringSource %ENDIF PUSHD %OperandNr[8] * SIZE#EXP CALL IiStringSource@RT:: IiStringSource@RT:: PROC1 PUSH EAX,EDX MOV EAX,[ESP+12] ; 20,40,60,80. LEA EDX,[EDI+II.Operand1-SIZE#EXP+EAX] ; ^EXP with %OperandNr. Its must be 'M' type. MOV EAX,expAwidth AND EAX,[EDX+EXP.Status] JZ .50: ; If address-size is not specified by base register width, keep default segment width. No ATOGGLE required. SHL EAX JC .20: ; If r64 or r32 used in [mem]. JSt [EDI+II.SssStatus],sssWidth16,.50: JSt [EDI+II.SssStatus],sssWidth32,.ATOGGLE: Msg '6733' ; Required address width 16 cannot be used in 64bit segment. JMP .Abort: .20: SHL EAX JC .30: ; If r64 used in [mem]. JSt [EDI+II.SssStatus],sssWidth16|sssWidth64, .ATOGGLE: JMP .50: .30: JSt [EDI+II.SssStatus],sssWidth64,.50: Msg '6731' ; Required address width 64 can be used in 64bit segment only. .Abort:ADD ESP,16 RET ; Abort the parent handler. .E6757:Msg '6757' ; Wrong string source specified. Only [rS:rSI] is acceptable. JMP .Abort .ATOGGLE: SetSt [EDI+II.PfxEmitted],iiPfxATOGGLE .50: MOV EAX,[EDX+EXP.Status] JNSt EAX,expSegmPres,.70: AND EAX,expSegm SHR EAX,24 ; EAX is now Sreg ordinal 0..5. CMP AL,3 JE .70: ; Ignore implicit segment-register DS. JNA .60: IiRequire 386 .60: ADD AL,20 ; EAX is now 20..25, i.e. iiPfxSEGES..iiPfxSEGGS. BTS [EDI+II.PfxEmitted],EAX ; Request for segment override. .70: MOV EAX,[EDX+EXP.Status] JSt EAX,expScalePres,.E6757: JNSt EAX,expBasePres,.80: JSt EAX,expIndexPres,.E6757: SHL EAX,4 ; Move base to index position in EXP.Status. JMP .85: .80: JNSt EAX,expIndexPres,.90: .85: AND EAX,expIndex CMP EAX,0x00600000 JNE .E6757: ; If not rSI. .90:POP EDX,EAX RET 4 ENDPROC1 IiStringSource@RT:: %ENDMACRO IiStringSource
B W D Q
or S N F
.
%IiCategoryList
.
IiSuffixed %MACRO Mnemo, Suffix, Category=g %Flag %SET %IF "%Suffix"==="B" %Flag %SET iiMfgDATA_BYTE %ENDIF %IF "%Suffix"==="W" %Flag %SET iiMfgDATA_WORD %ENDIF %IF "%Suffix"==="D" %Flag %SET iiMfgDATA_DWORD %ENDIF %IF "%Suffix"==="Q" %Flag %SET iiMfgDATA_QWORD %ENDIF %IF "%Suffix"==="S" %Flag %SET iiMfgDIST_SHORT %ENDIF %IF "%Suffix"==="N" %Flag %SET iiMfgDIST_NEAR %ENDIF %IF "%Suffix"==="F" %Flag %SET iiMfgDIST_FAR %ENDIF %IF "%Flag"==="" %ERROR Id=5879,'Invalid %Mnemo suffix "%Suffix".' %ELSE SetSt [EDI+II.MfgSuffix],%Flag JMP Ii%Category%Mnemo:: %ENDIF %ENDMACRO IiSuffixed
ENDHEAD ii ; End of module interface.
Stm.Status:stmOperationPresent
is reset on error.IiAssemble Procedure Stm IiExp LocalVar Size=SIZE#II ; Allocation of II object which will be submitted to instruction handler. IiFormat LocalVar ; Operands specification: 0..4 bytes in Intel encoding submitted to handler in EDX. IiCpuRegProp LocalVar ; CPU requirements requested by registers used in instruction. ; Initialize II object. ClearLocalVar MOV EBX,[%Stm] LEA EDI,[%IiExp] MOVB [EBX+STM.Status],'I' ; TYPE#Symbol, if a label is present in this statement. XOR EAX,EAX NOT EAX MOV [EDI+II.Disp8EVEX],EAX MOV [EDI+II.Disp8MVEX],EAX SetSt [EDI+II.PfxAllowed],iiPfxOTOGGLE+iiPfxATOGGLE ; Get the code section. MOV ESI,[EBX+STM.Section] TEST ESI JZ .05: JNSt [Ea.Eaopt.Status::],eaoptAUTOSEGMENT,.15: JSt [ESI+SSS.Purpose],sssPurposeCODE,.20: ; OK if current section is CODE. .05: Invoke SssGetSegm::,[EBX+STM.Program],sssPurposeCODE JNC .10: Msg '3201',Dict_PurposeCODE:: ; No segment with PURPOSE=!1S found. MOV EAX,[EBX+STM.Section] .10: MOV ESI,EAX ; The new section. SetSt [EBX+STM.Flags],stmtNotBSS .15: Invoke SssCheckPurpose::,ESI,sssPurposeCODE; Warn if not code section. .20: MOV [EBX+STM.Section],ESI TEST ESI JZ .23: MOV EAX,[ESI+SSS.Status] MOV EDX,[EBX+STM.Program] MOV [EDI+II.SssStatus],EAX MOV EAX,[EDX+PGM.Pgmopt.Status] MOV [EDI+II.PgmoptStatus],EAX ; Evaluate modifiers, alignment and aligned offset to the statement EBX. XOR EAX,EAX NOT EAX MOV [EDI+II.MfgAllowed],EAX ; Temporarily allow all instruction modifiers, MOV [EDI+II.MfxAllowed],EAX ; as we don't want any warnings yet. Invoke StmGetIiModifiers::,EBX,EDI XOR EAX,EAX MOV [EDI+II.MfgAllowed],EAX ; Disallow back all modifiers, let the handler allow only relevant ones. MOV [EDI+II.MfxAllowed],EAX MOV EAX,[EDI+II.Align] ; Explicitly specified in an instruction, e.g.XOR EAX,EAX,ALIGN=16
MOV EDX,[ESI+SSS.OrgHigh] MOV ESI,[ESI+SSS.OrgLow] Invoke ExpAlign::,ESI,EAX,0 MOV [EBX+STM.AlignBytes],ECX ADD ESI,ECX ADC EDX,0 MOV [EBX+STM.OffsetLow],ESI ; Aligned statement origin. MOV [EBX+STM.OffsetHigh],EDX .23: ; Evaluate legacy prefixes. MOV ECX,[EBX+STM.NrOfPrefixes] LEA ESI,[EBX+STM.Prefix1Data] LEA EDX,[EDI+II.PfxCode+0] JECXZ .30: .25: MOV EAX,[ESI] MOV [EDX],AL ; Prefix operation code. XOR AL,AL OR [EDI+II.PfxExplicit],EAX AND EAX,iiCpuDictPfxMask SetSt [EDI+II.Cpu],EAX ; CPU generation required by using a prefix. MOV EAX,iiFeaDictPfxMask AND EAX,[ESI] SetSt [EDI+II.Features],EAX ; CPU features required by using a prefix. ADD ESI,12 ; Skip to the next prefix in a statement. INC EDX ; Skip to the next II prefix code. LOOP .25: .30: ; Evaluate ordinal operands. BufferRetrieve [EBX+STM.OrdBuffer] TEST ECX JZ .50: ; ESI,ECX is Ptr+Size of source ordinal operand in statement, e.g.AL
or[EBX+8]
. LEA EDX,[EDI+II.Operand1] ; Expression of the ordinal operand. Start with the first one. .35: PUSHAD ; The loop between .35: and .50: evaluates all nonempty ordinal operands. MOV ECX,[ESI+4] ; Size of source operand. MOV ESI,[ESI+0] Invoke ExpEval::,EDX,ESI,ECX,EBX Msg cc=PE,'2210' ; Precision lost in calculation with FP number rounded to integer. Invoke ExpReportError::,EDX ; If error occured in operand. Invoke ExpConvertToNumber::,EDX ; In case of 'G' (character constant) convert it to number. MOV EAX,[EDX+EXP.Status] ; In case of VSIB addressed memory is the LSB modified by 0x80 (=bit V'). SUB ECX,ECX BTR EAX,7 ; expVbit4 - is vector indexregister above 15 used? JNC .38: SetSt [EDI+II.Ppx],iiPpxV` + iiPpxMEVEXonly MOV [EDX+EXP.Status],EAX ; Remove 7.bit from expression type (for dispatching purpose). .38: Dispatch AL,'R','N','A','M','F','P',0x23 Msg '7510',EAX ; Invalid operand type "!1Z". .0x23: RstSt [EBX+STM.Status],stmOperationPresent ; Invalidate the instruction on error (AL='#'). JMP .45: ; Go to the next operand. .R: ; Operand is a register. MOV ECX,[EDX+EXP.Low] ; DictRegisters.Data MOV EAX,iiCpuDictRegMask AND EAX,ECX SetSt [EDI+II.Cpu],EAX ; Add CPU and SIMD generation required by using the register. JNSt EAX,iiCPU_AVX512,.R3: MOV EAX,iiReg_KRG AND EAX,ECX CMP EAX,iiReg_KRG JE .R3: ; Mask register does not necessarily evocate EVEX/MVEXonly. SetSt [EDI+II.Ppx],iiPpxMEVEXonly .R3: MOV EAX,iiFeaDictRegMask AND EAX,ECX SetSt [EDI+II.Features],EAX ; Add CPU features required by using the register. JNSt ECX,iiRegREX,.R5: SetSt [EDI+II.PfxEmitted],iiPfxREX ; Handle REX registers SPL,BPL, SIL, DIL. .R5: JNSt ECX,iiRegNoREX,.R7: SetSt [EDI+II.Ppg],iiPpgNoREX ; Signalize that REX is not allowed to encode this register. .R7: Invoke IiGetRegFamily, ECX JMP .40: .M: ; Operand is memory variable, e.g.[EBX+4*ESI+Displ]
. MOV EAX,expVSIBfam AND EAX,[EDX+EXP.Status] IiAllowModifier DISP,SCALE SHL EAX,9 ; Convert expVSIBfam to iiPpxVSIBfam. OR [EDI+II.Ppx],EAX MOV AL,mem JMP .40: .F: ; Operand is far immediate, e.g.0040h:0010h
. MOV AL,far JMP .40: .P: ; Operand is paragraph address, e.g.PARA# Main
. .A: .N: ; Operand is immediate (external, far, address or scalar number). MOV AL,imm ;JMP .40: .40: ; Operand is evaluated, its type is in AL. SHL [%IiFormat],8,DATA=DWORD MOV [%IiFormat],AL .45: POPAD ADD EDX,SIZE#EXP ; Shift to EXP of the next operand in II. LEA EAX,[EDI+II.Operand4] CMP EDX,EAX JA .50: ; More than four operands are not expected. ADD ESI,8 SUB ECX,8 JA .35: ; Go to evaluate the next operand. .50: ; Let handler assemble the instruction to II structure. JNSt [EBX+STM.Status],stmOperationPresent,.70: ; Abort assembly when the instruction was invalidated due to error in operands. MOV EDX,[%IiFormat] PUSH EBX,EBP,EDI CALL [EBX+STM.OperationData] ; Call the instruction handler, e.g. IigMOV:. POP EDI,EBP,EBX JNSt [EBX+STM.Status],stmOperationPresent,.70: ; Abort assembly when the instruction was invalidated in handler. ; Flush the emitted code and relocations from statement to section. Invoke IiFlush,EDI,EBX JSt [EBX+STM.Status],stmOperationPresent,.85: ; If not invalidated in IiFlush. .70: ; Abort assembly when the instruction was invalidated. BufferClear [EBX+STM.EmitBuffer] BufferClear [EBX+STM.RelocBuffer] .85: BufferRetrieve [EBX+STM.EmitBuffer] MOV [EBX+STM.Size],ECX JNSt [EBX+STM.Status],stmLabelPresent,.90: ; Create a symbol if the statement was labeled. MOV EAX,stmLabelIsPublic AND EAX,[EBX+STM.Status] OR EAX,symDefined Invoke SymCreate::,EAX,[EBX+STM.LabelPtr],[EBX+STM.LabelSize],EBX .90:EndProcedure IiAssemble
INC*, DEC*, PUSH*, POP*
to IiAssemble one by one
and then links emitted code and relocations to original statement %Stm.
IiAssembleMultiop Procedure Stm
Stm1 LocalVar Size=SIZE#STM ; Temporary statement with only one operand.
moEmitBuffer LocalVar ; Temporary Stm buffers.
moRelocBuffer LocalVar
moMsgBuffer LocalVar
Invoke EaBufferReserve::,IiAssembleMultiop
MOV [%moEmitBuffer],EAX
Invoke EaBufferReserve::,IiAssembleMultiop
MOV [%moRelocBuffer],EAX
Invoke EaBufferReserve::,IiAssembleMultiop
MOV [%moMsgBuffer],EAX
MOV EBX,[%Stm]
LEA EDI,[%Stm1]
MOVB [EBX+STM.Status],'I'
CopyTo EDI,EBX,Size=SIZE#STM
MOVD [EDI+STM.NrOfOrdinals],1
RstSt [EDI+STM.Status],stmLabelPresent
BufferRetrieve [EBX+STM.OrdBuffer]
BufferClear [EDI+STM.OrdBuffer]
BufferStore [EDI+STM.OrdBuffer],ESI,8
Invoke IiAssemble,EDI ; The %1st operand is assembled twice, 1st pass only sets STM.AlignBytes and .Offset.
MOV EAX,[EDI+STM.OffsetLow]
MOV EDX,[EDI+STM.OffsetHigh]
MOV [EBX+STM.OffsetLow],EAX
MOV [EBX+STM.OffsetHigh],EDX
MOV EAX,[EDI+STM.AlignBytes]
MOV [EBX+STM.AlignBytes],EAX
.10:PUSH ECX,ESI ; Loop which handles operands one by one and performs IiAssemble with them.
BufferClear [EDI+STM.EmitBuffer]
BufferClear [EDI+STM.RelocBuffer]
BufferClear [EDI+STM.MsgBuffer]
BufferClear [EDI+STM.OrdBuffer]
BufferStore [EDI+STM.OrdBuffer],ESI,8
SetSt [EDI+STM.Status],stmOperationPresent; Repair status which might have been invalidated by previous operations.
MOV EAX,[EBX+STM.Size] ; Specify size emitted by previous instructions in statement, in case of Multiop.
MOV [EDI+STM.Size],EAX
Invoke IiAssemble,EDI
BufferRetrieve [EDI+STM.RelocBuffer]
CMP CL,SIZE#RELOC
JL .40: ; Skip when there are no absolute relocations in this instruction.
XCHG EAX,ESI ; Temporary save pointer and size of (one or two) RELOC records to EAX,EDX.
MOV EDX,ECX
BufferRetrieve [%moEmitBuffer]
ADD [EAX+RELOC.OrgLow],ECX ; Patch relocation position with datasize of previous multiop instructions.
CMP DL,SIZE#RELOC
JNA .30: ; Skip if not more than one RELOC record.
ADD [EAX+SIZE#RELOC+RELOC.OrgLow],ECX ; Patch 2nd relocation, e.g. in MOVD [$],$
.
.30: BufferStore [%moRelocBuffer],EAX,EDX
.40: BufferRetrieve [EDI+STM.EmitBuffer]
BufferStore [%moEmitBuffer],ESI,ECX
BufferRetrieve [EDI+STM.MsgBuffer]
BufferStore [%moMsgBuffer],ESI,ECX
MOV EAX,[EDI+STM.Size] ; Size of this instruction.
ADD [EBX+STM.Size],EAX
POP ESI,ECX
ADD ESI,8
SUB ECX,8
JNZ .10: ; The next operand.
BufferClear [EBX+STM.EmitBuffer]
BufferRetrieve [%moEmitBuffer]
BufferStore [EBX+STM.EmitBuffer],ESI,ECX
BufferClear [EBX+STM.RelocBuffer]
BufferRetrieve [%moRelocBuffer]
BufferStore [EBX+STM.RelocBuffer],ESI,ECX
BufferClear [EBX+STM.MsgBuffer]
BufferRetrieve [%moMsgBuffer]
BufferStore [EBX+STM.MsgBuffer],ESI,ECX
Invoke EaBufferRelease::,[%moMsgBuffer]
Invoke EaBufferRelease::,[%moRelocBuffer]
Invoke EaBufferRelease::,[%moEmitBuffer]
JNSt [EBX+STM.Status],stmLabelPresent,.90:
MOV EAX,stmLabelIsPublic
AND EAX,[EBX+STM.Status]
OR EAX,symDefined
Invoke SymCreate::,EAX,[EBX+STM.LabelPtr],[EBX+STM.LabelSize],EBX
.90:EndProcedure IiAssembleMultiop
CPU=686,SIMD=SSE4.1,XOP=ENABLED
.IiCpuToKeys Procedure Cpu, Fea, Buffer MOV EBX,[%Buffer] MOV EAX,[%Cpu] cpu %FOR X64,686,586,486,386,286,186 JNSt EAX,iiCPU_%cpu, .EndCpu%cpu: BufferStore EBX,=B"CPU=%cpu,",8 JMP .EndCPU: .EndCpu%cpu: %ENDFOR cpu .EndCPU: simd %FOR AVX512,AVX2,AVX,SSE4.2,SSE4.1,SSE4,SSSE3,SSE3,SSE2,SSE1 JNSt EAX,iiCPU_%simd, .EndCpu%simd: %ValSize %SETS %simd BufferStore EBX,=B"SIMD=%simd,",%ValSize+6 JMP .EndSIMD: .EndCpu%simd: %ENDFOR simd .EndSIMD: MOV EAX,[%Fea] fea %FOR %EaoptFeaList JNSt EAX,iiFea_%fea, .EndFea%fea: %ValSize %SETS %fea BufferStore EBX,=B"%fea=ENABLED,",%ValSize+9 .EndFea%fea: %ENDFOR fea BufferDecrement EBX ; Omit the last comma. EndProcedure IiCpuToKeys
IMM=BYTE,DATA=WORD
.IiModifiersToKeys Procedure IiMfg, IiMfx, Buffer Mval LocalVar MOV EBX,[%Buffer] MOV ECX,[%IiMfx] MOV EDX,[%IiMfg] LEA EDI,[%Mval] IiMf2Keyword %MACRO Prefix,Key,Value ; Internal macro to store text "KEY=VALUE," to buffer EBX if it is set in ECX or EDX. %Val %SET %Value %IF "%Value"=="0" %Val %SET OFF %ENDIF %IF "%Value"=="1" %Val %SET ON %ENDIF %KeySize %SETS %Key %ValSize %SETS %Val %reg %SET ECX %IF "%Prefix" == "iiMfg" %reg %SET EDX %ENDIF JNSt %reg,%Prefix%Key[]_%Value, .Not%Key%Value: BufferStore EBX,=B"%Key=",%KeySize+1 BufferStore EBX,=B"%Val,",%ValSize+1 .Not%Key%Value: %ENDMACRO IiMf2Keyword ; End of internal macro definition. IiMf2Keyword iiMfg,CODE,SHORT IiMf2Keyword iiMfg,CODE,LONG IiMf2Keyword iiMfx,PREFIX,REX IiMf2Keyword iiMfx,PREFIX,XOP IiMf2Keyword iiMfx,PREFIX,VEX2 IiMf2Keyword iiMfx,PREFIX,VEX3 IiMf2Keyword iiMfx,PREFIX,MVEX IiMf2Keyword iiMfx,PREFIX,EVEX IiMf2Keyword iiMfx,EH,0 IiMf2Keyword iiMfx,EH,1 IiMf2Keyword iiMfx,MASK,K0 IiMf2Keyword iiMfx,MASK,K1 IiMf2Keyword iiMfx,MASK,K2 IiMf2Keyword iiMfx,MASK,K3 IiMf2Keyword iiMfx,MASK,K4 IiMf2Keyword iiMfx,MASK,K5 IiMf2Keyword iiMfx,MASK,K6 IiMf2Keyword iiMfx,MASK,K7 IiMf2Keyword iiMfx,ZEROING,0 IiMf2Keyword iiMfx,ZEROING,1 IiMf2Keyword iiMfx,ROUND,NEAR IiMf2Keyword iiMfx,ROUND,DOWN IiMf2Keyword iiMfx,ROUND,UP IiMf2Keyword iiMfx,ROUND,ZERO IiMf2Keyword iiMfx,SAE,0 IiMf2Keyword iiMfx,SAE,1 IiMf2Keyword iiMfg,DATA,BYTE IiMf2Keyword iiMfg,DATA,WORD IiMf2Keyword iiMfg,DATA,DWORD IiMf2Keyword iiMfg,DATA,QWORD IiMf2Keyword iiMfg,DATA,TBYTE IiMf2Keyword iiMfg,DATA,OWORD IiMf2Keyword iiMfg,DATA,YWORD IiMf2Keyword iiMfg,DATA,ZWORD IiMf2Keyword iiMfx,BCST,0 IiMf2Keyword iiMfx,BCST,1 BTR ECX,31 ; (iiMfxOPER_Used) Other ECX contents is no longer necessary. JNC .OPERnotUsed: SHR ECX,28 ; Convert iiMfxOPER_Mask to a number 0..7. BufferStore EBX,=B"OPER=",5 OR CL,'0' MOV CH,',' MOV [EDI],ECX BufferStore EBX,EDI,2 .OPERnotUsed: JNSt EDX,iiMfgNESTING_OFF,.StandardNestingCheck: BufferStore EBX,=B"NESTINGCHECK=,",14 .StandardNestingCheck: IiMf2Keyword iiMfg,DISP,BYTE IiMf2Keyword iiMfg,DISP,WORD IiMf2Keyword iiMfg,DISP,DWORD IiMf2Keyword iiMfg,DISP,QWORD IiMf2Keyword iiMfg,SCALE,SMART IiMf2Keyword iiMfg,SCALE,VERBATIM IiMf2Keyword iiMfg,DIST,SHORT IiMf2Keyword iiMfg,DIST,NEAR IiMf2Keyword iiMfg,DIST,FAR IiMf2Keyword iiMfg,ADDR,ABS IiMf2Keyword iiMfg,ADDR,REL IiMf2Keyword iiMfg,IMM,BYTE IiMf2Keyword iiMfg,IMM,WORD IiMf2Keyword iiMfg,IMM,DWORD IiMf2Keyword iiMfg,IMM,QWORD BufferDecrement EBX ; Omit the last comma. EndProcedure IiModifiersToKeys
iiMfgDATA_Mask + iiMfgIMM_Mask
(Mask is Byte/Word/Dword).IiRelocSizeRIP Procedure Ii, Stm MOV EDI,[%Ii] MOV EBX,[%Stm] ; Calculate instruction size to ESI. MOV ESI,3 ; Opcode of JKnZD is 3 or 4 bytes long. CMPD [EBX+STM.OperationData],IikJKZD:: JE .10: CMPD [EBX+STM.OperationData],IikJKNZD:: JNE .20: .10:JNSt [EDI+II.MfxExplicit],iiMfxPREFIX_VEX3, .40: INC ESI JMP .40: .20:MOV ESI,2 ; Opcode of JMPE is 2 bytes long (0x0FB8). CMPD [EBX+STM.OperationData],IisJMPE:: JE .40: MOV ESI,1 ; Opcode of CALLN, JMPS, JMPN is 1 byte long. .40 ADD ESI,[EBX+STM.NrOfPrefixes] ; No explicit prefixes but OFTEN,SELDOM should be used with JMP, CALL, LOOP, JMPE, JKZD. INC ESI ; First assume Imm encoding as ImmByte (short jump). MOVD [%ReturnEAX],iiMfgIMM_BYTE+iiMfgDATA_BYTE MOV EAX,[EBX+STM.OffsetLow] MOV EDX,[EBX+STM.OffsetHigh] ADD EAX,ESI ADC EDX,0 ; EDX:EAX is now rIP - offset of the following instruction, assuming short jump. NOT EAX NOT EDX ADD EAX,1 ADC EDX,0 ; EDX:EAX is now negated rIP. ADD EAX,[EDI+II.ImmLow] ; Add target to get displacement rel8. ADC EDX,[EDI+II.ImmHigh] Invoke ExpWidthSigned:: CMP CL,expWidth1B ; Does signed displacement fit to 1 byte? JNA .90: INC ESI ; Assume encoding as ImmWord. JNSt [EDI+II.SssStatus],sssWidth32,.60: INC ESI ; Encoding size covers OTOGGLE prefix in 32bit segment. .60:MOVD [%ReturnEAX],iiMfgIMM_WORD+iiMfgDATA_WORD MOV EAX,[EBX+STM.OffsetLow] MOV EDX,[EBX+STM.OffsetHigh] ADD EAX,ESI ADC EDX,0 ; EDX:EAX is now rIP - offset of the following instruction, assuming near word jump/call. NOT EAX NOT EDX ADD EAX,1 ADC EDX,0 ; EDX:EAX is now negated rIP. ADD EAX,[EDI+II.ImmLow] ; Add target to get displacement rel16. ADC EDX,[EDI+II.ImmHigh] Invoke ExpWidthSigned:: CMP CL,expWidth2B ; Does signed displacement fit to 2 bytes? JNA .90: ; Otherwise it requires 32bit relative offset, encoded as ImmDword. MOVD [%ReturnEAX],iiMfgIMM_DWORD+iiMfgDATA_DWORD .90:EndProcedure IiRelocSizeRIP
IiGetRegOrdinal Procedure RegisterCode MOV EAX,[%RegisterCode] MOV ECX,iiReg_Ord32 TEST AL,iiReg_Fam32 JNZ .60: MOV CL,iiReg_Ord16 TEST AL,iiReg_Fam16 JNZ .80: MOV CL,iiReg_Ord8 TEST AL,iiReg_Fam8 JNZ .70: .E9985:Msg '9985' ; IiGetRegOrdinal provided with invalid register encoding. .60:CMP AL,iiReg_Spec JB .80: MOV CL,iiReg_Ord8 .70:CMP AL,iiReg_CT8 JB .80: MOV CL,iiReg_Ord16 .80:AND EAX,ECX MOV [%ReturnEAX],EAX EndProcedure IiGetRegOrdinal
IiGetRegFamily Procedure RegisterCode MOV EAX,[%RegisterCode] MOV ECX,~iiReg_Ord32 TEST AL,iiReg_Fam32 JNZ .60: MOV CL,~iiReg_Ord16 TEST AL,iiReg_Fam16 JNZ .80: MOV CL,~iiReg_Ord8 TEST AL,iiReg_Fam8 JNZ .70: Msg '9985' ; IiGetRegFamily/Ordinal provided with invalid register encoding. .60:CMP AL,iiReg_Spec JB .80: MOV CL,~iiReg_Ord8 .70:CMP AL,iiReg_CT8 JE .90: JB .80: MOV CL,~iiReg_Ord16 .80:AND ECX,0xFF .90:AND EAX,ECX MOV [%ReturnEAX],EAX EndProcedure IiGetRegFamily
II.MfxAllowed
has already specified which types of AVX prefix are acceptable
with current operand combination. Prefix-type selection follows these priorities:
II.Ppx:iiPpxMEVEXonly
constrains the type according to current operands.
If any XMM,YMM above 15, or any ZMM register is used,
the instruction is only encodable with EVEX or MVEX.0F38
or
0F3A
, or width promotion bit W
is set, or
REX.B
or REX.X
is set (addressing by R8..R15),
or if explicitly requested by PREFIX=VEX3
.II.MfxExplicit
is taken into account then.EH=,SAE=,ROUND=,MASK=,ZEROING=,OPER=
is used,
EVEX/MVEX prefix will be selected, unless explicitly requested PREFIX=VEX.PREFIX=
modifier.IiAssembleAVX uses the source prefix notation from II.AvxSrc*
and information from II.MfxAllowed, II.MfgExplicit, II.MfxExplicit
as explicitly requested by instruction modifiers.
It will choose the shortest version and assemble the prefix in
II.AvxCode
. Its size is written to II.Ppg:iiPpxAvxSize
and returned in ECX. The finally selected version of AVX prefix will be set
as the one and only flag in II.MfxEmitted:iiMfxPREFIX_Mask
.
AVX-512 operands | EVEX / MVEX | ModRM byte | (V)SIB byte | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
R | X | B | R' | V' | mod | reg | R/M | scale | index | base | |||||||||||
mem type: Rr, [S * Rx + Rb] | r3 | x3 | b3 | r4 | x4 | 0 | 0 | r2 | r1 | r0 | 1 | 0 | 0 | S1 | S0 | x2 | x1 | x0 | b2 | b1 | b0 |
reg type: Rr, Rb | r3 | b4 | b3 | r4 | 1 | 1 | r2 | r1 | r0 | b2 | b1 | b0 | not used |
IiAssembleAVX Procedure Ii MOV EDI,[%Ii] IiRequire AVX IiAllowModifier PREFIX SUB EAX,EAX JNSt [EDI+II.Ppx],iiPpxMEVEXonly, .05: ; If ZMM used (requires AVX512 prefix). RstSt [EDI+II.MfxAllowed],iiMfxPREFIX_XOP+iiMfxPREFIX_VEX MOV [EDI+II.AvxSrcXOP],EAX MOV [EDI+II.AvxSrcVEX],EAX .05:; Disallow types not defined in Intel doc (no II.AvxSrc* record). CMP EAX,[EDI+II.AvxSrcXOP] JNZ .10: RstSt [EDI+II.MfxAllowed],iiMfxPREFIX_XOP .10:CMP EAX,[EDI+II.AvxSrcVEX] JNZ .12: RstSt [EDI+II.MfxAllowed],iiMfxPREFIX_VEX .12:CMP EAX,[EDI+II.AvxSrcEVEX] JNZ .14: RstSt [EDI+II.MfxAllowed],iiMfxPREFIX_EVEX .14:CMP EAX,[EDI+II.AvxSrcMVEX] JNZ .16: RstSt [EDI+II.MfxAllowed],iiMfxPREFIX_MVEX .16: ; Select prefix by explicit PREFIX modifier. MOV EAX,iiMfxPREFIX_Mask AND EAX,[EDI+II.MfxExplicit] AND EAX,[EDI+II.MfxAllowed] ; Leave only requested encodable types in EAX. JSt EAX,iiMfxPREFIX_VEX, .VEX: JSt EAX,iiMfxPREFIX_EVEX,.EVEX: JSt EAX,iiMfxPREFIX_MVEX,.MVEX: JSt EAX,iiMfxPREFIX_XOP, .XOP: ; If no obeyable explicit PREFIX= request, select prefix by decorators used. ; If instruction uses modifier ROUND=, SAE=, BCST=, OPER=, MASK=, ZEROING=, EH=, then only MVEX or EVEX is possible. JSt [EDI+II.MfxExplicit], \ iiMfxOPER_Used|iiMfxMASK_Mask|iiMfxROUND_Mask|iiMfxSAE_Mask|iiMfxBCST_Mask|iiMfxEH_Mask|iiMfxZEROING_Mask, .20: ; Otherwise try VEX/XOP, if defined. MOV ESI,[EDI+II.AvxSrcVEX] TEST ESI JNZ .VEX: MOV ESI,[EDI+II.AvxSrcXOP] TEST ESI JNZ .XOP: .20:; If EVEX-specific modifier ZEROING= is explicitly requested, use EVEX, if possible. JNSt [EDI+II.MfxExplicit],iiMfxZEROING_Mask,.30: MOV ESI,[EDI+II.AvxSrcEVEX] TEST ESI JNZ .EVEX: .30: ; If MVEX-specific modifier EH= is explicitly requested, use MVEX, if possible. JNSt [EDI+II.MfxExplicit],iiMfxEH_Mask,.40: MOV ESI,[EDI+II.AvxSrcMVEX] TEST ESI JNZ .MVEX: .40:; Otherwise use EVEX or MVEX, in this order. MOV ESI,[EDI+II.AvxSrcEVEX] TEST ESI JNZ .EVEX: MOV ESI,[EDI+II.AvxSrcMVEX] TEST ESI JNZ .MVEX: ; If EVEX/MVEX not defined for this instruction, try VEX/XOP once again (AVX2 modifiers will not be obeyed this time). MOV ESI,[EDI+II.AvxSrcVEX] TEST ESI JNZ .VEX: MOV ESI,[EDI+II.AvxSrcXOP] TEST ESI JNZ .XOP: ; Instruction handler error or SSE instruction called with XMM16..31 etc. LEA EAX,[EBX+STM.OperationPtr] Msg '7517',EAX ; Instruction !1S is not encodable with this operand combination. RstSt [EBX+STM.Status],stmOperationPresent ; Invalidate the instruction, do not emit anything. JMP .90: .MVEX:MOV ESI,[EDI+II.AvxSrcMVEX] CALL .AvxSrcParse: IiEncoding PREFIX=MVEX,DATA=ZWORD ; Emit prefix MVEX. IiRequire AVX512,MVEX IiAllowModifier OPER,EH MOV ESI,0x0000_0062 ; MVEX prefix to LSB. JNSt [EDI+II.MfxAllowed], iiMfxEH_Mask, .M1: JNSt [EDI+II.MfxExplicit],iiMfxEH_1, .M1: ; MVEX.E is eviction hint EH=ON. ; IiEncoding EH=Mask SetSt ESI,0x8000_0000 ; Set MVEX.E if explicitly requested EH=ON. .M1:JNSt [EDI+II.MfxAllowed], iiMfxSAE_Mask, .M2: JNSt [EDI+II.MfxExplicit],iiMfxSAE_1, .M2: SetSt ESI,0x4000_0000 ; MVEX.S2. .M2:JNSt [EDI+II.MfxAllowed], iiMfxROUND_Mask, .M3: MOV EAX,iiMfxROUND_Mask AND EAX,[EDI+II.MfxExplicit] JZ .M3: ; If no rounding explicitly requested. BSF ECX,EAX ; ECX is now 16,17,18,19 for ROUND=NEAR,DOWN,UP,ZERO. SHL ECX,28 ; Convert rounding mode from 10h,11h,12h,13h to MVEX.S1S0. RstSt ESI,0x3000_0000 SetSt ESI,ECX SetSt ESI,0x8000_0000 ; MVEX.E must be set to enable rounding. .M3: ; If OPER= is specified, it overrides previously set bitfields for MVEX.S2.S1.S0. ; JNSt [EDI+II.MfxAllowed],ECX, .E6: ; OPER is always allowed when M/EVEX. JNSt [EDI+II.MfxExplicit],iiMfxOPER_Used, .M6: MOV EAX,iiMfxOPER_Mask AND EAX,[EDI+II.MfxExplicit] RstSt ESI,0x7000_0000 SetSt ESI,EAX ; Overwrite MVEX.S2.S1.S0. .M6:; Set finally used encodings of EH,SAE,ROUND,OPER from ESI to II.MfxEmitted. JNSt [EDI+II.Ppx],iiPpxEH0,.M7: RstSt ESI,0x8000_0000 .M7:JNSt [EDI+II.Ppx],iiPpxEH1,.M8: SetSt ESI,0x8000_0000 .M8:JNSt [EDI+II.MfxAllowed],iiMfxEH_Mask,.ME1: RstSt [EDI+II.MfxEmitted],iiMfxEH_Mask JNSt ESI,0x8000_0000, .ME0: IiEncoding EH=1 JMPS .ME1: .ME0:IiEncoding EH=0 .ME1:RstSt [EDI+II.MfxEmitted],iiMfxSAE_Mask JNSt [EDI+II.MfxAllowed],iiMfxSAE_Mask,.MS1: JNSt ESI,0x4000_0000, .MS0: IiEncoding SAE=1 JMPS .MS1: .MS0:IiEncoding SAE=0 .MS1:RstSt [EDI+II.MfxEmitted],iiMfxROUND_Mask JNSt [EDI+II.MfxAllowed],iiMfxROUND_Mask,.MR1: JNSt ESI,0x8000_0000, .MR1: ; No rounding if MVEX.E is not set. MOV EAX,0x3000_0000 AND EAX,ESI SHR EAX,28 ; EAX is now 0,1,2,3 for ROUND=NEAR,DOWN,UP,ZERO. ADD AL,16 BTS [EDI+II.MfxEmitted],EAX .MR1:MOV EAX,0x7000_0000 AND EAX,ESI SetSt EAX,iiMfxOPER_Used SetSt [EDI+II.MfxEmitted],EAX .EM1: ; Common EVEX and MVEX fields. MOV ECX,[EDI+II.PfxEmitted] ; Copy REX to CL. AND ECX,0000_0111b ; Leave only R,X,B. SHL ECX,13 ; Convert REX.RXB to E/MVEX.RXB. OR ESI,ECX ; E/MVEX.RXB. MOV EAX,iiPpxR` AND EAX,[EDI+II.Ppx] SHR EAX,6 ; Convert iiPpxR` to E/MVEX.R'. OR ESI,EAX ; E/MVEX.R'. MOV EAX,iiPpxMmMask AND EAX,[EDI+II.Ppx] OR ESI,EAX ; E/MVEX.mm. MOV ECX,iiPpxW AND ECX,[EDI+II.Ppx] JNSt [EDI+II.Ppx],iiPpxW1,.EM3: SetSt ECX,iiPpxW .EM3:JNSt [EDI+II.Ppx],iiPpxW0,.EM4: RstSt ECX,iiPpxW .EM4:SHL ECX,20 ; Convert iiPpxW to M/EVEX.W. OR ESI,ECX ; E/MVEX.W. MOV EAX,iiPpxPpMask AND EAX,[EDI+II.Ppx] SHL EAX,16 ; Convert iiPpxPpMask to M.EVEX.pp. OR ESI,EAX ; E/MVEX.pp. CALL .vvvv: OR ESI,EAX ; E/MVEX.V'vvvv. MOV EAX,iiMfxMASK_Mask JNSt [EDI+II.MfxAllowed],EAX, .EM5: AND EAX,[EDI+II.MfxExplicit] JZ .EM5: ; If MASK=K0. SetSt [EDI+II.MfxEmitted],EAX BSF ECX,EAX ; ECX is now 0..7. SHL ECX,24 ; Convert explicit MASK=1..7 to prefix field EVEX.aaa/MVEX.kkk. SetSt ESI,ECX ; Set EVEX.aaa alias MVEX.kkk. .EM5:XOR ESI,0x0878F000 ; Invert encoding of fields V',vvvv,R,X,B,R'. MOV CL,4 JMP .90: .EVEX:MOV ESI,[EDI+II.AvxSrcEVEX] CALL .AvxSrcParse: IiEncoding PREFIX=EVEX ; Emit prefix EVEX. IiRequire AVX512,EVEX IiAllowModifier OPER JNSt [EDI+II.MfxAllowed],iiMfxMASK_Mask,.N1: JSt [EDI+II.Ppx],iiPpxNoZEROING,.N1: IiAllowModifier ZEROING ; If MASK is allowed, allow ZEROING, too. .N1: IiRequire AVX512 MOV ESI,0x0004_0062 ; E/MVEX prefix to LSB + fixed type bit 1=EVEX, 0=MVEX. ; Bitfields EVEX.L'L 00,01,10 specify operand size 128,256,512 by default. ; This can be overriden later when ROUND= or OPER= specifies rounding, broadcast, SAE. MOV EAX,iiMfgDATA_ZWORD+iiMfgDATA_YWORD+iiMfgDATA_OWORD AND EAX,[EDI+II.MfgImplicit] ; EAX is now 0x0000_8000 or 0x0000_4000. SetSt [EDI+II.MfgEmitted],EAX RstSt EAX,iiMfgDATA_OWORD JNSt [EDI+II.Ppx],iiPpxL0,.L0: RstSt EAX,iiMfgDATA_YWORD ; EVEX.L0 .L0:JNSt [EDI+II.Ppx],iiPpxL1,.L1: SetSt EAX,iiMfgDATA_YWORD ; EVEX.L1 .L1:SHL EAX,15 ; EAX is now 0x4000_0000 or 0x2000_0000, i.e. EVEX.512 or EVEX.256. OR ESI,EAX ; EVEX.L'L. Otherwise leave 0, i.e. EVEX.128. JNSt [EDI+II.MfxAllowed],iiMfxZEROING_Mask, .E3: JSt [EDI+II.MfxExplicit],iiMfxZEROING_1, .E2: JSt [EDI+II.MfxExplicit],iiMfxZEROING_0, .E1: JNSt [EDI+II.MfxExplicit],iiMfxMASK_Mask, .E3: .E1:IiEncoding ZEROING=0 ; If MASK= is used, display ZEROING too. JMPS .E3: ; JSt [EDI+II.MfxExplicit],iiMfxZEROING_1, .E3: .E2:IiEncoding ZEROING=1 SetSt ESI,0x8000_0000 ; Set EVEX.z if explicitly requested ZEROING=ON. .E3:JNSt [EDI+II.MfxAllowed],iiMfxBCST_Mask,.E4: JSt [EDI+II.MfxExplicit],iiMfxBCST_1,.E5: ; IiEncoding BCST=1 .E4:JNSt [EDI+II.MfxAllowed],iiMfxSAE_Mask, .E6: JNSt [EDI+II.MfxExplicit],iiMfxSAE_1,.E6: ; IiEncoding SAE=Mask .E5:SetSt ESI,0x1000_0000 ; EVEX.b .E6:JNSt [EDI+II.MfxAllowed],iiMfxROUND_Mask, .E7: MOV EAX,iiMfxROUND_Mask AND EAX,[EDI+II.MfxExplicit] JZ .E7: ; If no rounding explicitly requested. BSF ECX,EAX ; ECX is now 16,17,18,19 for ROUND=NEAR,DOWN,UP,ZERO. SHL ECX,29 ; Convert rounding mode from 0,1,2,3 to EVEX.L'.L. RstSt ESI,0x6000_0000 SetSt ESI,ECX SetSt ESI,0x1000_0000 ; Always set EVEX.b when rounding mode is used. .E7: ; If OPER= is specified, it overrides previously set bitfields for L'L, BCST=, SAE= and ROUND=. MOV ECX,iiMfxOPER_Mask ; JNSt [EDI+II.MfxAllowed],ECX, .E8: ; OPER is always allowed when M/EVEX. JNSt [EDI+II.MfxExplicit],iiMfxOPER_Used, .E8: MOV EAX,iiMfxOPER_Mask AND EAX,[EDI+II.MfxExplicit] RstSt ESI,iiMfxOPER_Mask SetSt ESI,EAX ; Overwrite EVEX.L'.L'b with OPER value. .E8:; Set finally used encodings of BCST,SAE,ROUND,OPER from ESI to II.MfxEmitted. RstSt [EDI+II.MfxEmitted],iiMfxSAE_Mask JNSt [EDI+II.MfxAllowed],iiMfxSAE_Mask,.ES1: JNSt ESI,0x1000_0000, .ES0: ; If actually used EVEX.b=0. IiEncoding SAE=1 JMPS .ES1: .ES0:IiEncoding SAE=0 .ES1:RstSt [EDI+II.MfxEmitted],iiMfxBCST_Mask JNSt [EDI+II.MfxAllowed],iiMfxBCST_Mask,.EB1: JNSt ESI,0x1000_0000, .EB0: ; If actually used EVEX.b=0. IiEncoding BCST=1 JMPS .EB1: .EB0:IiEncoding BCST=0 .EB1:RstSt [EDI+II.MfxEmitted],iiMfxROUND_Mask JNSt [EDI+II.MfxAllowed],iiMfxROUND_Mask,.ER1: JNSt ESI,0x1000_0000, .ER1: ; No rounding if EVEX.b is not set. MOV EAX,0x6000_0000 ; EVEX.L'.L. AND EAX,ESI SHR EAX,29 ; EAX is now 0,1,2,3 for ROUND=NEAR,DOWN,UP,ZERO. ADD AL,16 BTS [EDI+II.MfxEmitted],EAX IiEncoding SAE=1 .ER1:MOV EAX,0x7000_0000 AND EAX,ESI SetSt EAX,iiMfxOPER_Used SetSt [EDI+II.MfxEmitted],EAX .E9:JMP .EM1: ; Continue with common fields for EVEX/MVEX. .XOP: ; Emit prefix XOP. MOV ESI,[EDI+II.AvxSrcXOP] CALL .AvxSrcParse: IiEncoding PREFIX=XOP IiRequire XOP, AMD MOV ESI,0x8F ; XOP prefix to LSB. MOV ECX,iiPpxMmMask ; 0x0000_0300. AND ECX,[EDI+II.Ppx] ; CH is now 0,1,2,3. ADD CH,8 ; Convert MAP8,MAP9,MAP10,reserved to XOP opcode map 8,9,10,11. OR ESI,ECX .XOPVEX3: ; Common continuation for XOP and VEX3. Escape prefix and map_select are already set in ESI. MOV ECX,[EDI+II.PfxEmitted] ; Copy REX to CL. AND ECX,0000_0111b ; XOP/VEX3 bits RXB. SHL ECX,13 ; Position in XOP/VEX3 RXB. OR ESI,ECX MOV EAX,iiPpxW ; XOP/VEX bit W. AND EAX,[EDI+II.Ppx] JNSt [EDI+II.Ppx],iiPpxW0,.XV1: RstSt EAX,iiPpxW .XV1:JNSt [EDI+II.Ppx],iiPpxW1,.XV2: SetSt EAX,iiPpxW .XV2:SHL EAX,20 ; Convert iiPpxW to XOP/VEX.W. SetSt ESI,EAX MOV EAX,iiMfgDATA_YWORD+iiMfgDATA_OWORD AND EAX,[EDI+II.MfgImplicit] SetSt [EDI+II.MfgEmitted],EAX JNSt EAX,iiMfgDATA_YWORD, .XV5: ; XOP/VEX3 bit L. SetSt ESI,0x0004_0000 .XV5:JNSt [EDI+II.Ppx],iiPpxL1,.XV6: SetSt ESI,0x0004_0000 .XV6:JNSt [EDI+II.Ppx],iiPpxL0,.XV7: RstSt ESI,0x0004_0000 .XV7:MOV EAX,iiPpxPpMask ; XOP/VEX3 bits pp. AND EAX,[EDI+II.Ppx] SHL EAX,16 ; Convert iiPpxPpMask to XOP.pp. OR ESI,EAX CALL .vvvv: ; XOP/VEX3 bits vvvv. OR ESI,EAX XOR ESI,0x0078E000 ; XOP/VEX3 inverted bits vvvv,R,X,B. MOV CL,3 JMP .90: .VEX:MOV ESI,[EDI+II.AvxSrcVEX] CALL .AvxSrcParse: ; Choose between VEX2 or VEX3. JSt [EDI+II.Ppx],iiPpxW1|iiPpxW|iiPpxMm3, .VEX3: ; W=1 or if 3byte opcode 0x0F38, 0x0F3A required. JSt [EDI+II.PfxEmitted], (iiPfxREX.B|iiPfxREX.X)^iiPfxREX, .VEX3: ; If REX.B or REX.X is set (addressing by R8..R15). JSt [EDI+II.MfxExplicit],iiMfxPREFIX_VEX2, .VEX2: ; If explicitly requested VEX or VEX2. JSt [EDI+II.MfxExplicit],iiMfxPREFIX_VEX3, .VEX3: ; If explicitly requested longer version VEX3. .VEX2:IiEncoding PREFIX=VEX2 ; Emit prefix VEX2. RstSt [EDI+II.MfxExplicit],iiMfxPREFIX_VEX3 ; In case PREFIX=VEX requested, don't warn that VEX3 disobeyed. MOV ESI,0xC5 ; VEX2 prefix to LSB. MOV ECX,[EDI+II.PfxEmitted] ; Copy REX to CL. AND ECX,0000_0100b ; Leave only R. SHL ECX,13 ; Position in VEX.R. OR ESI,ECX MOV EAX,iiMfgDATA_YWORD+iiMfgDATA_OWORD AND EAX,[EDI+II.MfgImplicit] SetSt [EDI+II.MfgEmitted],EAX JNSt EAX,iiMfgDATA_YWORD, .V1: SetSt ESI,0x0000_0400 ; VEX2.L. .V1: JNSt [EDI+II.Ppx],iiPpxL1,.V2: SetSt ESI,0x0000_0400 .V2: JNSt [EDI+II.Ppx],iiPpxL0,.V3: RstSt ESI,0x0000_0400 .V3: MOV EAX,iiPpxPpMask AND EAX,[EDI+II.Ppx] SHL EAX,8 OR ESI,EAX CALL .vvvv: SHR EAX,8 OR ESI,EAX XOR ESI,0x0000_F800 ; Invert encoding of fields R,vvvv. MOV CL,2 JMP .90: .VEX3:IiEncoding PREFIX=VEX3 ; Emit prefix VEX3. JNSt [EDI+II.MfxExplicit],iiMfxPREFIX_VEX3,.v3: RstSt [EDI+II.MfxExplicit],iiMfxPREFIX_VEX2 ; Don't warn that VEX2 was disobeyed when PREFIX=VEX was requested. .v3:MOV ESI,0xC4 ; VEX3 prefix to LSB. MOV ECX,iiPpxMmMask ; 0x0000_0300. AND ECX,[EDI+II.Ppx] ; CH is now 0,1,2,3 for VEX3 opcode map 0,1,2,3 (reserved,0F,0F38,0F3A). OR ESI,ECX JMP .XOPVEX3: ; Continue as in prefix .XOP: .AvxSrcParse: PROC ; Parse source prefix definition to II. ; Input: EDI=^II, ESI=^ASCIIZ source_string, e.g. "VEX.NDS.128.66.0F.WIG". ; Output: EDI,EBX preserved. MOV AL,'.' .WIG: .LIG: .MAP8: ; Ignored specifiers. .10:CMP AL,0 ; End of prefix source string? JE .90: XOR EDX,EDX MOV ECX,ESI .20:LODSB CMP AL,'.' JE .30: CMP AL,0 JE .30: SHRD EDX,EAX,8 JMP .20: .30:CMP DX,0 JNZ .40: SHR EDX,16 .40:CMP DL,0 JNZ .50: SHR EDX,8 ; EDX now holds the last 4 characters of prefix component, NULL padded. .50:Dispatch EDX,'128','256','512','XOP','VEX','MVEX','EVEX', \ 'NDD','NDS','DDS','W0','W1','WIG','L0','L1','LIG','LZ','66','F2','F3',\ '0F','0F38','0F3A','MAP8','MAP9','AP10','EH0','EH1' LEA EAX,[EBX+STM.OperationPtr] ; Internal handler error. Msg '9982',ECX,EAX ; Invalid token "!1$" in AVX prefix for instruction !2S. JMP .90: .XOP:JSt [EDI+II.Ppx],iiPpxMEVEXonly,.10: SetSt [EDI+II.MfxAllowed],iiMfxPREFIX_XOP JMP .10: .VEX:JSt [EDI+II.Ppx],iiPpxMEVEXonly,.10: SetSt [EDI+II.MfxAllowed],iiMfxPREFIX_VEX JMP .10: .EVEX:SetSt [EDI+II.MfxAllowed],iiMfxPREFIX_EVEX JMP .10: .MVEX:SetSt [EDI+II.MfxAllowed],iiMfxPREFIX_MVEX JMP .10: .128:SetSt [EDI+II.MfgImplicit],iiMfgDATA_OWORD JMP .10: .256:SetSt [EDI+II.MfgImplicit],iiMfgDATA_YWORD JMP .10: .512:SetSt [EDI+II.MfgImplicit],iiMfgDATA_ZWORD JMP .10: ; Specifiers NDS/NDD/DDS are ignored, we use IiEmitModRM key ModRM=OperandX instead. .NDD:SetSt [EDI+II.Ppx],iiPpxNDD JMP .10: .NDS:SetSt [EDI+II.Ppx],iiPpxNDS JMP .10: .DDS:SetSt [EDI+II.Ppx],iiPpxDDS JMP .10: .W0: SetSt [EDI+II.Ppx],iiPpxW0 JMP .10: .W1: SetSt [EDI+II.Ppx],iiPpxW1 JMP .10: .LZ: .L0: SetSt [EDI+II.Ppx],iiPpxL0 JMP .10: .L1: SetSt [EDI+II.Ppx],iiPpxL1 JMP .10: .EH0:SetSt [EDI+II.Ppx],iiPpxEH0 JMP .10: .EH1:SetSt [EDI+II.Ppx],iiPpxEH1 JMP .10: .66: SetSt [EDI+II.Ppx],01b ; Convert to iiPpxPpMask. JMP .10: .F3: SetSt [EDI+II.Ppx],10b JMP .10: .F2: SetSt [EDI+II.Ppx],11b JMP .10: .MAP9: .0F: SetSt [EDI+II.Ppx],01_00000000b ; Convert to iiPpxMmMask. JMP .10: .AP10: .0F38:SetSt [EDI+II.Ppx],10_00000000b JMP .10: .0F3A:SetSt [EDI+II.Ppx],11_00000000b JMP .10: .90: RET ENDP .AvxSrcParse: .vvvv: PROC ; Returns the ordinal number of register which should be encoded in *VEX.vvvv field ; from the operand specified by iiPpxVvMask. ; Input: EDI=^II ; Output: Ordinal bits 0..3 of vvvv are returned in bits 19..22 of EAX. ; Ordinal bit 4 of V'vvvv is returned in bit 27 of EAX (when SSE register 15..31 is used). ; 0000V000_0vvvv000_00000000_00000000b ; Returned bits vvvv are zero if II.AvxImplicit:iiPpxVvMask is 0 (no operand in vvvv) ; but bit 27 may be returned in EAX when II.PpxV was set (VSIB index is SSE register 15..31). MOV EAX,iiPpgVEXvOp AND EAX,[EDI+II.Ppg] JNZ .v3: ; If vvvv operand is used. MOV EAX,iiPpxV` ; Mask for bit V`. AND EAX,[EDI+II.Ppx] SHL EAX,8 ; Convert iiPpxV` to EVEX.27. JMP .v9: .v3:; EAX is now 0x0040_0000, 0x0080_0000, 0x00C0_0000 for operand 1,2,3. SAR EAX,22 ; EAX is now 1,2,3 for operand 1,2,3. PUSH ECX MOV ECX,EAX LEA EAX,[EDI+II.Operand1-SIZE#EXP] .v5: ADD EAX,SIZE#EXP LOOP .v5: POP ECX ; EAX now points to EDI+II.Operand1,2,3. Invoke IiGetRegOrdinal, [EAX+EXP.Low] ; Return ordinal in EAX bits 0..4. BTR EAX,4 JNC .v6: BTS EAX,8 .v6:SHL EAX,19 ; Move reg.ordinal to its position in EVEX. .v9:RET ENDP .vvvv: .90:MOV [EDI+II.AvxCode],ESI ; Prefix from ESI is stored. IiAllowModifier PREFIX ; Allow all prefixes again to get rid of W2400. MOVZX ECX,CL ; Prefix size (2,3,4) in CL is saved and returned in ECX. MOV [%ReturnECX],ECX SAL ECX,4 ; Convert to iiPpxAvxSize mask. OR [EDI+II.Ppx],ECX EndProcedure IiAssembleAVX
II.Ppx:iiPpxDisp8Allow
flag is set (by IiModRM). It provides disp8*N
compression scaling of displacement, if possible, and redefines the result either as
DISP=BYTE compressed, or DISP=DWORD uncompressed.II.Disp, II.ModRM:Mod, II.MfxEmitted:DISP_Mask
.IiCompressDisp8 Procedure Ii, Stm Disp8Reloc LocalVar Size=SIZE#RELOC ClearLocalVar MOV EDI,[%Ii] JNSt [EDI+II.MfgEmitted],iiMfgDISP_Mask,.90: ; If no displacement, leave it as is. MOV EAX,[EDI+II.Disp8EVEX] JSt [EDI+II.MfxEmitted],iiMfxPREFIX_EVEX, .10: MOV EAX,[EDI+II.Disp8MVEX] .10:MOV ECX,iiMfxOPER_Mask AND ECX,[EDI+II.AvxCode] SHR ECX,26 ; ECX is now 0,4,8,12,16,20,24,28 when OPER=0,1,2,3,4,5,6,7. SAL EAX,CL ; Select the corresponding nibble of Disp8*VEX to most-significant nibble. SAR EAX,28 ; Shift it to the least-significant nibble. SHR ECX,2 ; ECX is now OPER= value 0..7. TEST EAX ; EAX is now 0,1,2,3,4,5,6, or -1. JZ .90: Msg cc=S,'2450',ECX ; The value OPER=!1D is not supported in this instruction. JS .50: ; Use disp32/16 when Disp8*N is wrong. XCHG EAX,ECX ; ECX has now the number of compression bits 0..6. MOV EBX,ECX ; Save compression bits 0..6 to BL. MOV EDX,[EDI+II.DispHigh] MOV EAX,[EDI+II.DispLow] JECXZ .35: .30:SAR EDX,1 ; Disp8*N compression. RCR EAX,1 JC .50: ; Unaligned displacement cannot be compressed, use disp32/16. LOOP .30: .35:Invoke ExpWidthSigned:: ; Get width of compressed Qword EDX:EAX to ECX. CMP CL,expWidth1B JA .50: ; Compressed displacement doesn't fit to a byte, use disp32/16 uncompressed. ; Success, disp8*N will be used. MOV [EDI+II.DispLow],EAX ; Rewrite final displacement value with the compressed one. MOV [EDI+II.DispHigh],EDX RstSt [EDI+II.MfgEmitted],iiMfgDISP_Mask SetSt [EDI+II.MfgEmitted],iiMfgDISP_BYTE ANDB [EDI+II.ModRM],0011_1111b ORB [EDI+II.ModRM],0100_0000b ; Change ModRM.Mod to 01 (base+disp8) SAL EBX,28 ; This will be relocDisp8N in RELOC.Status. XCHG EAX,EBX LEA EBX,[%Disp8Reloc] ; Relocation record will be emitted to decorate compressed displacement in dump column of the listing. Clear EBX,Size=SIZE#RELOC MOV [EBX+RELOC.Status],EAX MOV EAX,[%Stm] BufferRetrieve [EAX+STM.EmitBuffer] ; Get number of emitted bytes so far. ; IiCompressDisp8 is invoked from IiFlush when only legacy prefixes were emitted and nothing else. ADD ECX,4+1+1+1 ; Add size of M/EVEX prefix + opcode + ModR/M + disp8. JNSt [EDI+II.Ppg],iiPpgSIB, .40: INC ECX ; Add size of SIB, if present. .40:MOV [EBX+RELOC.OrgLow],ECX ; Disp8 offset relative to the start of statement. BufferStore [EAX+STM.RelocBuffer],EBX,SIZE#RELOC ; Store Disp8 presudorelocation used to decorate disp8 byte. JMPS .90: .50:; Leave uncompressed displacement as disp32/16. MOV EDX,iiMfgDISP_DWORD MOV EAX,[EDI+II.Operand3+EXP.Status] ; Examine effective address-size in [memory] operand. CMP AL,'M' JE .70: MOV EAX,[EDI+II.Operand2+EXP.Status] CMP AL,'M' JE .70: MOV EAX,[EDI+II.Operand1+EXP.Status] CMP AL,'M' JNE .80: .70:SHR EAX,30 ; Isolate EXP.Status:expAwidth (address-size). CMP AL,1 ; 0,1,2,3 = unspecified,16,32,64 bits. JNE .80: MOV EDX,iiMfgDISP_WORD ; Displacement size in 16bit addressing mode. .80:RstSt [EDI+II.MfgEmitted],iiMfgDISP_Mask SetSt [EDI+II.MfgEmitted],EDX ANDB [EDI+II.ModRM],0011_1111b ORB [EDI+II.ModRM],1000_0000b ; Change ModRM.Mod to 10 (base+disp32/16). .90:EndProcedure IiCompressDisp8
iiPpgModRMd | iiPpgModRMr
are set to construct ModRM byte + SIB.IiCreateModRM: Procedure IiAllowPrefix SegAny ; Memory operand is accessed. IiAllowModifier DISP, DIST, SCALE, ADDR ; Construct II.ModRM field RegOpcode. MOV EAX,[EDI+II.Ppg] MOV ECX,EAX SHR EAX,28 ; Convert iiPpgModDigit to 0..7 (if IiModRM /digit was used). JSt ECX,iiPpgModRMd, .20: ; IiModRM /r was used. Find the operand of RegOpcode field. MOV EAX,iiPpgModRegOp ; Mask for operand number. AND EAX,ECX SHR EAX,24 ; EAX is now 0,1,2,3 for Unspec,Operand1,2,3. TEST EAX JZ .F9987: ; Internal error: ModRM fields are not specified in handler (missing IiOpEn). LEA EDX,[EDI+II.Operand1-SIZE#EXP] .05:ADD EDX,SIZE#EXP DEC EAX JNZ .05: Invoke IiGetRegOrdinal, [EDX+EXP.Low] ; EDX points now to the operand going to RegOpcode field. BTR EAX,4 JNC .10: ; If it's not a SSE register above 15. SetSt [EDI+II.Ppx],iiPpxR` .10:BTR EAX,3 JNC .20: ; If it's not a GP or SSE register above 7. SetSt [EDI+II.PfxEmitted],iiPfxREX.R .20:; EAX is RegOpcode field 0..7, higher ordinals bits 3 and 4 were marked in REX.R and VEX.R' and reset. SHL AL,3 OR [EDI+II.ModRM],AL ; ModR/M bitfield Reg/Opcode is finally set. ; Construct II.ModRM fields Mod and R/M. ECX=II.Ppg. MOV EAX,iiPpgModRMOp ; Mask for operand number. AND EAX,ECX SHR EAX,26 ; EAX=0,1,2,3 for Unspec,Operand1,2,3. TEST EAX JNZ .23: .F9987:Msg '9987' ; Internal error: ModRM fields are not specified in handler (missing IiOpEn). JMP .90: .23:LEA EDX,[EDI+II.Operand1-SIZE#EXP] .25:ADD EDX,SIZE#EXP DEC EAX JNZ .25: ; If the operand EDX is register (mod=11b) or based with no SIB present, ; write operand ordinal bits 0..2 to ModRM:R/M, bit 3 to REX.B and bit 4 to REX.X. ; If the operand EDX is [memory] and requires SIB, ; write baseregister ordinal bits 0..2 to SIB.base, bit 3 to REX.B, ; write indexregister ordinal bits 0..2 to SIB.index, bit 3 to REX.X, bit 4 to EVEX.V'. MOV EAX,[EDX+EXP.Status] ; Examine operand type in AL. Dispatch AL,'R','M','B','U','W','D','Q','T','O','Y','Z','I' JMP .90: ; Expected register or memory operand missing, fatal error was reported by failing IiDispatchFormat. .R: ; EDX specifies register operand, Mod will be 11b, no SIB. Invoke IiGetRegOrdinal, [EDX+EXP.Low] ; Return register ordinal in EAX. BTR EAX,4 JNC .R4: ; If not SSE register XMM16..ZMM31. IiEmitPrefix REX.X ; This flag is misused by EVEX prefix instead of nonexisting B'. .R4:BTR EAX,3 JNC .R5: ; If not X64 register R8..R15, XMM8..XMM15 etc. SetSt [EDI+II.PfxEmitted],iiPfxREX.B .R5:OR AL,11000000b ; Set Mod=11b. JNSt [EDI+II.Ppg],iiPpgMod01,.R6: AND AL,0111_1111b ; Short encoding of INC,DEC use ModRM byte as opcode. Mod 11b changed to 01b. .R6:JNSt [EDI+II.Ppg],iiPpgMod10,.R7: AND AL,1011_1111b ; Short encoding of MOV reg,imm use ModRM byte as opcode. Mod 11b changed to 10b. .R7:OR [EDI+II.ModRM],AL JMP .90: .M: .B: .U: .W: .D: .Q: .T: .O: .Y: .Z: .I: ; EDX specifies ^EXP memory operand. Mod will be 00b, 01b or 10b. R/M depends on Index/Base/Displacement. ; Prepare displacement for emit (though it might be not used finally). MOV EAX,[EDX+EXP.Low] MOV ECX,[EDX+EXP.High] MOV [EDI+II.DispLow],EAX MOV [EDI+II.DispHigh],ECX MOV EAX,[EDX+EXP.Sym] MOV ESI,[EDX+EXP.Seg] MOV [EDI+II.DispRelocSym],EAX MOV [EDI+II.DispRelocSeg],ESI ; If segment was used, e.g. [ES:EDI+Displ], ask for segment override prefix. MOV EAX,[EDX+EXP.Status] JNSt EAX,expSegmPres,.40: ; Skip when no segment-override was present. MOV ECX,EAX AND EAX,expSegm SHR EAX,24 ; EAX is now Sreg ordinal 0..5. ADD AL,20 ; EAX is now 20..25, i.e. iiPfxSEGES..iiPfxSEGGS. JNSt ECX,expBasePres, .30: AND ECX,expBase SHR ECX,16 ; ECX is now 0..15, i.e. ordinal number of base register rAX..R15. CMP CL,5 ; rBP? JA .30: CMP CL,4 ; rSP? JB .30: ; Base register is rBP or rSP, default segment is SS. CMP AL,22 ; iiPfxSEGSS? JE .40: ; Do not emit superfluous segment override by SS. JMP .35: .30:; None or other base registers than rBP,rSP default to DS. CMP AL,23 ; iiPfxSEGDS? JE .40: ; Do not emit superfluous segment override by DS. .35:JNSt [EDI+II.SssStatus],sssWidth64,.38: ; Warn that segment override is ignored in 64bit mode. CMP AL,24 ; FS or GS? JAE .38: Msg '2377' ; Segment override is ignored in 64bit mode. .38:BTS [EDI+II.PfxEmitted],EAX ; Request for segment override. .40:; Calculate effective address size. MOV EAX,[EDX+EXP.Status] ; expAwidth is in bits 30..31. MOV ECX,EAX SHR EAX,30 ; Address-size detected by ExpEval: 0,1,2,3 for unspecified,16,32,64. TEST EAX JNZ .55: ; Address-size is not determined by base/index register, e.g. [ES:Displ], so it has to be calculated now. AND ECX,expDwidth ; CH is 0..7 (actual displacement width). INC EAX ; First assume address-size 16bit: EAX=1. JSt [EDI+II.SssStatus],sssWidth64,.45: ; 16bit address mode is not available in 64bit segment. JSt [EDI+II.MfgExplicit],iiMfgDISP_DWORD,.45: ; If explicitly requested, use 32bit addressing. JSt [EDI+II.Ppg],iiPpgVSIBind,.45: ; If instruction requires VSIB, use 32bit addressing. CMP CH,expWidth2B JA .45: ; If displacement magnitude exceeds 16 bits, use 32bit addressing. JSt [EDI+II.MfgExplicit],iiMfgDISP_WORD,.55: ; If explicitly requested, use 16bit addressing. JSt [EDI+II.SssStatus],sssWidth16,.55: ; If DISP= not specified, use segment width. .45:INC EAX ; 16bit is not enough, try 32: EAX=2. JSt [EDI+II.SssStatus],sssWidth64,.50: ; If in 64bit segment, use 64bit addressing mode. ; Warn if explicit ATOGGLE tries to switch 32bit mode to 16bit. JNSt [EDI+II.SssStatus],sssWidth32,.48: TESTD [EDI+II.PfxExplicit],iiPfxATOGGLE Msg cc=NZ,'2371' ; Prefix ATOGGLE: is not expected in this instruction. .48:CMP CH,110b ; expWidth4B. JNA .55: ; If displacement fits to 32 bits. .50:INC EAX ; 32bits is not enough, effective address-size is 64: EAX=3. .55:SHL EAX,8 ; Convert to II.Ppg:iiPpgAddrSize 100h, 200h, 300h for 16,32,64 bits. OR [EDI+II.Ppg],EAX ; Effective address-size is finally determined, AH=1,2,3 for 16,32,64 bits. DEC AH ; EAX=000h,100h,200h. MOV ECX,[EDX+EXP.Status] ; Preload memory variable properties. SHR EAX,6 ; EAX=0,4,8, which is index into the .AddressingTable below. CMP AL,4 JB .80: ; If 16bit mode, require nothing. JE .70: ; If 32bit mode, require 386. IiRequire X64 .70:IiRequire 386 ; Select and perform addressing mode procedure .Addr16:, .Addr32: or .Addr64:. .80:CALL [EAX+.AddressingTable] .90:JMP .99: [.data] ALIGN DWORD .AddressingTable DD IiCreateModRM.Addr16:, IiCreateModRM.Addr32:, IiCreateModRM.Addr64: ; Dispatch addressing mode. .FindRM16Table: ; Used in .Addr16.FindRM16 procedure. DD expIndexPres + 6<<20 + expBasePres + 3<<16 ; >> R/M=000b SI+BX DD expIndexPres + 7<<20 + expBasePres + 3<<16 ; >> R/M=001b DI+BX DD expIndexPres + 6<<20 + expBasePres + 5<<16 ; >> R/M=010b SI+BP DD expIndexPres + 7<<20 + expBasePres + 5<<16 ; >> R/M=011b DI+BP DD expIndexPres + 6<<20 ; >> R/M=100b SI DD expIndexPres + 7<<20 ; >> R/M=101b DI DD expBasePres + 5<<16 ; >> R/M=110b (BP) DD expBasePres + 3<<16 ; >> R/M=111b BX [.text] .Addr16: PROC ; 16bit addressing mode: base BX/BP/-, index SI/DI/-, no scaling, DispB or DispW. ; Input: EDI=^II, EDX=^EXP type mem, ECX=[EDX+EXP.Status]. ; Output: ModR/M, optional SIB and Displacement will be set in II object pointed to by EDI. ; II.ModRM has field Reg/Opcode already set. Field Mod will be 00b, 01b or 10b. TESTD [EDI+II.Ppg],iiPpgVSIBind Msg cc=NZ,'6744' ; This VSIB instruction cannot be used in 16bit addressing mode. JSt [EDI+II.SssStatus],sssWidth16,.10: JNSt [EDI+II.SssStatus],sssWidth64,.05: Msg '6733' ; Required address-size 16 cannot be used in 64bit segment. .05:SetSt [EDI+II.PfxEmitted],iiPfxATOGGLE ; Require address-size prefix to get 16bit addressing mode in 32bit segment. .10:; Prepare displacement and its width. JSt [EDI+II.MfgExplicit],iiMfgDISP_WORD, .12: SetSt [EDI+II.Ppx],iiPpxDisp8Allow ; Using of Disp8*N compression is possible, ; if not explicitly requested DISP=WORD, ; if a displacement BYTE or WORD is used, ; if no displacement relocation is necessary, ; and if base and/or index register is used. .12:MOV EAX,expDwidth ; Memory operand displacement width mask. AND EAX,ECX ; AH is now 0,3,4,5,6,7 = none,zero,8,16,32,64 bits. CMP AH,5 MOV ESI,[EDX+EXP.Low] ; Copy displacement value from operand to II. MOV [EDI+II.DispLow],ESI Msg cc=A,'6741',ESI ; Displacement !1K is too big for 16bit addressing mode. MOV ECX,[EDX+EXP.Seg] JECXZ .15: ; Skip when the operand has scalar displacement, e.g. [BP+8]. SetSt [EDI+II.Reloc],iiRelocDispAbs ; Request for relocation and use disp16. RstSt [EDI+II.Ppx],iiPpxDisp8Allow ; Disp8*N is not possible due to relocation. .15:MOV ECX,[EDX+EXP.Status] JSt ECX,expIndexPres|expBasePres,.20: RstSt [EDI+II.Ppx],iiPpxDisp8Allow ; Disp8*N is not possible due to omitted register. MOV CL,00000110b ; Special case: no base, no index. Mod=00, R/M=6, disp16. SetSt [EDI+II.MfgEmitted],iiMfgDISP_WORD JMP .80: .20:JSt [EDI+II.Reloc],iiRelocDispAbs,.50: JSt ECX,expIndexPres,.40: MOV ESI,expBase AND ESI,ECX CMP ESI,0x00050000 JNE .40: ; If base register is not BP. CMP AH,4 JA .30: ; If displacement does not fit to byte. JSt [EDI+II.MfgExplicit],iiMfgDISP_WORD,.30: ; If explicitly requested DISP=WORD. MOV ECX,[EDX+EXP.Seg] TEST ECX JNZ .28: ; If displacement contains relocation. MOV CL,01000110b ; Special case detected: no index, base=BP, disp8. SetSt [EDI+II.MfgEmitted],iiMfgDISP_BYTE JMP .80: .28:SetSt [EDI+II.Reloc],iiRelocDispAbs MOV [EDI+II.ImmRelocSeg],ECX .30:MOV CL,10000110b ; Special case detected: no index, base=BP, disp16. SetSt [EDI+II.MfgEmitted],iiMfgDISP_WORD JMP .80: .40: ; Index present and/or base<>BP present. JSt [EDI+II.MfgExplicit],iiMfgDISP_WORD,.50: ; If explicitly requested DISP=WORD. CMP AH,4 JA .50: ; ; If displacement does not fit to byte. MOV ECX,[EDX+EXP.Seg] JECXZ .60: ; Skip if displacement does not contain relocation. SetSt [EDI+II.Reloc],iiRelocDispAbs .50:; Mod=10, disp=16. Find R/M by registers combination. CALL IiCreateModRM.FindRM16 OR CL,10000000b ; Mod=10b. IiEncoding DISP=WORD JMP .80: .60: ; Displacement will be byte or none. JSt [EDI+II.MfgExplicit],iiMfgDISP_BYTE,.65: ; If explicitly requested DISP=BYTE. CMP AH,3 JBE .70: ; If displacement zero or missing. .65:; Mod=01b, disp8. CALL IiCreateModRM.FindRM16 OR CL,01000000b ; Mod=01b. IiEncoding DISP=BYTE JMP .80: .70:; Mod=00b, no displacement. CALL IiCreateModRM.FindRM16 .80:OR [EDI+II.ModRM],CL IiEncoding ADDR=ABS ; In 16bit mode is all addressing absolute. .90:RET ENDP .Addr16: .FindRM16 PROC ; Find R/M encoding of ModR/M byte from register combination in 16bit addressing mode. ; Input:EDX=^EXP operand type mem. Output: CL=R/M field in bits 0..2. MOV EAX,expBase+expIndex+expScalePres+expBasePres+expIndexPres AND EAX,[EDX+EXP.Status] MOV ESI,IiCreateModRM.FindRM16Table MOV ECX,8 ; Number of items in the table. XCHG ESI,EDI REPNE SCASD XCHG EDI,ESI ; ECX is now 7..0 for R/M 0..7. NOT ECX AND CL,7 RET ENDP .FindRM16 .Addr32: ; 32bit addressing mode. JSt [EDI+II.SssStatus],sssWidth32, IiCreateModRM.Addr3264: IiEmitPrefix ATOGGLE ; Require addr-size prefix 0x67 in 16bit and 64bit segment. JMP IiCreateModRM.Addr3264: .Addr64: ; 64bit addressing mode. TESTD [EDI+II.SssStatus],sssWidth64 Msg cc=Z,'6731' ; Required address-size 64 can be used in 64bit segment only. ;JMP IiCreateModRM.Addr3264: .Addr3264: PROC ; Common continuation for 32bit and 64bit addressing mode. ; Base r32/r64, index r32/r64 (not ESP/RSP) or xmm/ymm/zmm, scale, Disp8, Disp32. ; Input: EDI=^II, EDX=^EXP of type [mem], ECX=[EDX+EXP.Status]. Field Reg/Opcode is already set. ; Output: Mod, R/M, optional SIB and Displacement are modified in EDI=^II. IiAllowModifier SCALE,ADDR .Step1: ; Optimise scaling, if not disabled by SCALE=VERBATIM. MOV ECX,[EDX+EXP.Status] JSt [EDI+II.MfgExplicit],iiMfgSCALE_VERBATIM, .Step2: JSt [EDI+II.Ppg],iiPpgVSIBind, .Step2: ; If VSIB is required, use SIB. .Rule1: ; If scaling=1*Index, remove scaling. JNSt ECX,expScalePres, .Rule2: JSt ECX,expScale,.Rule3: ; Skip if scale>1. AND ECX,~(expScale+expScalePres) ; Scale=1, remove scaling. MOV [EDX+EXP.Status],ECX .Rule2: ; If no scaling, index present and base not present, swap base with index (shorter encoding). AND ECX,expIndexPres+expBasePres CMP ECX,expIndexPres JNE .19: MOV ECX,expIndex AND ECX,[EDX+EXP.Status] SHR ECX,4 ; Copy expIndex to expBase. OR ECX,expBasePres OR [EDX+EXP.Status],ECX ANDD [EDX+EXP.Status],~(expIndex+expIndexPres) JMPS .19: .Rule3:; If scaling=2*Index and Base not present, use Index+Base instead and remove scaling (shorter encoding). JNSt ECX,expScalePres,.19: JNSt ECX,0x10000000,.19: JSt ECX,expBasePres | 0x20000000, .19: AND ECX,expIndex RstSt [EDX+EXP.Status],expBase+expScale+expScalePres SHR ECX,4 ; Shift expIndex to expBase. OR ECX,expBasePres OR [EDX+EXP.Status],ECX .19:MOV ECX,[EDX+EXP.Status] .Step2: ; Specify displacement encode size 0,1 or 4 bytes and set it to II.MfgEmitted. MOV ESI,iiMfgDISP_DWORD ; First assume disp32. JSt [EDI+II.MfgExplicit],iiMfgDISP_DWORD,.29: ; If explicitly requested, use disp32. CMPD [EDX+EXP.Seg],0 JNZ .29: ; If displacement is not a scalar number, use disp32. JNSt ECX,expBasePres, .29: ; If no base register is present, use disp32. ; Otherwise using of Disp8 compression is theoretically possible. SetSt [EDI+II.Ppx],iiPpxDisp8Allow MOV EAX,expDwidth ; Check displacement numeric magnitude. AND EAX,ECX ; AH is now 0,3,4,5,6,7 = none,zero,8,16,32,64 significant bits actually used in displacement. CMP AH,6 Msg cc=A,'6742',[EDX+EXP.Low] ; Displacement !1K is too big for 32/64bit addressing mode. JAE .29: ; Use disp32, higher bytes truncated. CMP AH,4 ; Not more than eight significant bits are used in displacement. JA .29: ; If displacement does not fit to a byte, use ESI=disp32. ; Displacement fits to 8 bits. Check if 8bit overflow occured (MSbit of 0th and 7th byte are different). MOV AL,[EDX+EXP.High+3] ; Most significant bit of 64bit signed displacement. XOR AL,[EDX+EXP.Low+0] JS .29: ; If LSB overflowed, this would incorrectly sign-extend, therefore use disp32. MOV ESI,iiMfgDISP_BYTE ; Use disp8, which will be sign-extended to 32|64 bits on runtime. CMP AH,3 ; Displacement zero? JA .29: ; If displacement nonzero, use disp8. JSt [EDI+II.MfgExplicit],ESI,.29: ; If requested DISP=BYTE, use disp8 even when no displacement exists. ; Base register EBP, RBP or R13 requires at least disp8 or disp32, too. MOV EAX,0x0007_0000 ; Mask for lower 3 bits of expBase register's ordinal. AND EAX,ECX CMP EAX,0x0005_0000 JE .29: ; If base is EBP, RBP or R13, use disp8. XOR ESI,ESI ; Otherwise no displacement will be emitted. .29:SetSt [EDI+II.MfgEmitted],ESI ; Displacement width is finally set. .Step3: ; Specify if SIB will be used and set II.Ppg:iiPpgSIB if yes. JSt ECX,expScalePres|expIndexPres, .SIB: ; If scaling or index is present, use SIB. MOV EAX,0x0007_0000 ; Mask for lower 3 bits of expBase register's ordinal. AND EAX,ECX CMP EAX,0x0004_0000 JE .SIB: ; If base is ESP, RSP or R12, use SIB. JSt [EDI+II.Ppg],iiPpgVSIBind,.SIB: ; If VSIB is required, use SIB. JSt [EDI+II.MfgExplicit],iiMfgSCALE_VERBATIM,.SIB: ; If SIB was explicitly required. JSt ECX,expBasePres,.NoSIB: ; Other base and no index are encodable without SIB. ; If no index and no base is present, still we may need to emit SIB when ADDR=ABS was requested in 64bit mode ; or when SCALE=VERBATIM was requested in any mode. JSt [EDI+II.MfgExplicit],iiMfgSCALE_VERBATIM,.SIB: JNSt [EDI+II.SssStatus],sssWidth64,.NoSIB: CMPD [EDI+II.DispRelocSeg],0 JZ .SIB: ; Absolute addressing with SIB is necessary for scalar displacement. JSt [EDI+II.MfgExplicit],iiMfgADDR_ABS,.SIB: ; If explicitly requested ADDR=ABS in 64bit mode, use SIB. JSt [EDI+II.MfgExplicit],iiMfgADDR_REL,.NoSIB: ; If explicitly requested ADDR=REL in 64bit mode, do not use SIB. JSt [EDI+II.PfxEmitted],iiPfxSEGFS|iiPfxSEGGS,.SIB: ; If FS or GS used and ADDR not explicitly specified, use SIB (ABS). .NoSIB:IiEncoding SCALE=SMART ; By default prefer ADDR=REL, no SIB in 64bit mode. JMPS .Step4: .SIB:IiEncoding SCALE=VERBATIM SetSt [EDI+II.Ppg],iiPpgSIB .Step4: ; Specify addressing frame as absolute or RIP-relative. JSt ECX,expBasePres|expIndexPres,.ABS: ; When a register is present, frame is absolute. JSt [EDI+II.Ppg],iiPpgSIB,.ABS: ; When SIB is emitted, addressing frame is always absolute. JNSt [EDI+II.SssStatus],sssWidth64,.ABS: ; Frame is always absolute in legacy mode. .REL:IiEncoding ADDR=REL ; Use by default in 64bit mode. JMPS .Step5: .ABS:IiEncoding ADDR=ABS .Step5: ; Specify displacement relocation. MOV EAX,[EDI+II.DispRelocSeg] TEST EAX JZ .Step6: ; Displacement is a scalar value, no relocation. MOV ESI,iiRelocDispAbs JSt [EDI+II.MfgEmitted],iiMfgADDR_ABS,.Reloc: MOV ESI,iiRelocDispRIP CMP EAX,[EBX+STM.Section] ; If Displacement is an address targeting the same section, JE .Reloc: ; it can be resolved in IiFlush. MOV ESI,iiRelocDispRel ; Otherwise use relative relocation. .Reloc:SetSt [EDI+II.Reloc],ESI .Step6:; Construction of (V)SIB byte. (Scaled) index register is present or ADDR=ABS or base is ESP,RSP,R12. JNSt [EDI+II.Ppg],iiPpgSIB,.Step7: ; Skip this step when SIB is not requested. MOV EAX,expScale AND EAX,ECX SHR EAX,22 OR [EDI+II.SIB],AL ; Set SIB scaling bits. MOV EAX,expBase AND EAX,ECX SHR EAX,16 JSt ECX,expBasePres,.62: MOV AL,0101b ; If no base present, set SIB base bits as if it is rBP. .62:BTR EAX,3 JNC .64: IiEmitPrefix REX.B .64:OR [EDI+II.SIB],AL ; Set SIB base bits. MOV EAX,expIndex AND EAX,ECX SHR EAX,17 ; Convert expIndex to ModRM. JSt ECX,expIndexPres,.66: MOV AL,00100000b ; If no index present, set SIB index to ESP or RSP. .66:BTR EAX,6 JNC .68: IiEmitPrefix REX.X .68:OR [EDI+II.SIB],AL ; Set SIB index bits. SIB is completed now. .Step7:; Construction of ModR/M field R/M. MOV AL,00000100b JSt [EDI+II.Ppg],iiPpgSIB,.79: ; If SIB is present, R/M must be 100b. MOV AL,00000101b JNSt ECX,expBasePres,.79: ; If no base is present, R/M must be 101b. MOV EAX,expBase AND EAX,ECX SHR EAX,16 BTR EAX,3 JNC .79: IiEmitPrefix REX.B .79:OR [EDI+II.ModRM],AL ; Set R/M field. .Step8:; Construction of ModR/M field Mod. JNSt ECX,expBasePres,.88: ; If no base is present, Mod must be left on 00b. MOV AL,01000000b ; Mod 01b (disp8). JSt [EDI+II.MfgEmitted],iiMfgDISP_BYTE,.89: MOV AL,10000000b ; Mod 10b (disp32). JSt [EDI+II.MfgEmitted],iiMfgDISP_DWORD,.89: .88:MOV AL,00000000b ; Mod 00b (no displacement). .89:OR [EDI+II.ModRM],AL ; ModRM is completed now. RET ENDP .Addr3264: .99:EndProcedure IiCreateModRM
RELOC.Section
is 0, it will be set in SssEmit.
RELOC.Org
is related to $ (the first byte of this instruction), it will be elevated in
SssEmitIiFlush Procedure Ii, Stm Reloc LocalVar Size=SIZE#RELOC MOV EBX,[%Stm] MOV EDI,[%Ii] JNSt [EDI+II.Ppg],iiPpgModRMr|iiPpgModRMd, .10: ; Construct ModRM+(V)SIB bytes. Invoke IiCreateModRM .10: ; Flush explicit prefixes, e.g. inSEGES MOV AX,[SI]
. MOV ECX,[EBX+STM.NrOfPrefixes] JECXZ .12: LEA ESI,[EDI+II.PfxCode] BufferStore [EBX+STM.EmitBuffer],ESI,ECX ; Store unconditionally all ECX prefixes. .12: ; Flush implicit segment prefixes, if they were not specified explicitly. MOV EAX,iiPfxSegAny AND EAX,[EDI+II.PfxEmitted] ; E.g. inMOV AX,[ES:SI]
. JZ .18: ; If no implicit segment override. JNSt EAX,iiPfxSEGFS|iiPfxSEGGS,.14: IiRequire 386 .14: TEST [EDI+II.PfxExplicit],EAX JNZ .18: ; If implicit segment override was already requested as explicit, ignore. JNSt [EDI+II.PfxExplicit],iiPfxGrp2,.16: ; Different segment override explicitly requested? Msg '2820' ; Illegal combination of prefixes from the same group. .16: BSF EAX,EAX ; EAX=20..25 for ES..GS. SUB EAX,20 ; EAX= 0..5 for ES..GS. SHL EAX,2 ; EAX= 0..20 for ES..GS. LEA ESI,[DictPrefixesGrp2::+DICT.Data+EAX+2*EAX] ; SIZE#DICT=3*4. Let ESI point to prefix code. BufferStore [EBX+STM.EmitBuffer],ESI,1 .18: ; Flush implicit prefixes LOCK, OTOGGLE, ATOGGLE, REPE, REPNE, VEX, REX. JNSt [EDI+II.PfxEmitted],iiPfxLOCK,.20: JSt [EDI+II.PfxExplicit],iiPfxLOCK,.20: ; If LOCK was already requested as explicit prefix. LEA ESI,[DictPrefixLock::+DICT.Data] BufferStore [EBX+STM.EmitBuffer],ESI,1 .20: JNSt [EDI+II.PfxEmitted],iiPfxOTOGGLE,.22: JSt [EDI+II.PfxExplicit],iiPfxOTOGGLE,.22: ; If OTOGGLE was already requested as explicit prefix. LEA ESI,[DictPrefixesGrp3::+DICT.Data] BufferStore [EBX+STM.EmitBuffer],ESI,1 .22: JNSt [EDI+II.PfxEmitted],iiPfxATOGGLE,.24: JSt [EDI+II.PfxExplicit],iiPfxATOGGLE,.24: ; If ATOGGLE was already requested as explicit prefix. LEA ESI,[DictPrefixesGrp4::+DICT.Data] BufferStore [EBX+STM.EmitBuffer],ESI,1 .24: JNSt [EDI+II.PfxEmitted],iiPfxREPE,.26: JSt [EDI+II.PfxExplicit],iiPfxREPE,.26: ; If REPE was already requested as explicit prefix. LEA ESI,[DictPrefixRepe::+DICT.Data] BufferStore [EBX+STM.EmitBuffer],ESI,1 .26: JNSt [EDI+II.PfxEmitted],iiPfxREPNE,.28: JSt [EDI+II.PfxExplicit],iiPfxREPNE,.28: ; If REPNE already requested as explicit prefix. LEA ESI,[DictPrefixRepne::+DICT.Data] BufferStore [EBX+STM.EmitBuffer],ESI,1 .28: ; Flush REX/VEX prefix. MOV EAX,[EDI+II.AvxSrcXOP] OR EAX,[EDI+II.AvxSrcVEX] OR EAX,[EDI+II.AvxSrcEVEX] OR EAX,[EDI+II.AvxSrcMVEX] JZ .32: ; If no AVX prefix is specified, emit REX when it is nonzero. Invoke IiAssembleAVX,EDI ; Returns prefix size (2..4) in ECX. JNSt [EDI+II.MfxEmitted],iiMfxPREFIX_EVEX|iiMfxPREFIX_MVEX,.30: JNSt [EDI+II.MfxEmitted],iiMfxPREFIX_MVEX,.29: JNSt [EDI+II.Ppx],iiPpxNoSwizzle,.29: MOV EAX,[EDI+II.AvxCode] SHR EAX,28 ; AL is now MVEX bits EH.S2.S1.S0. BTR EAX,3 JC .29: ; Skip swizzle check when EH=1. CMPB [EDI+II.Operand3+EXP.Status],'M' JE .29: ; Skip swizzle check if memory-operand3 is present. CMPB [EDI+II.Operand2+EXP.Status],'M' JE .29: ; Skip swizzle check if memory-operand2 is present. TEST AL Msg cc=NZ,'2452',EAX ; Register swizzle (EH=0,OPER=!1D) is not supported in this MVEX instruction. .29: JNSt [EDI+II.Ppx],iiPpxDisp8Allow, .30: Invoke IiCompressDisp8,EDI,EBX .30: LEA ESI,[EDI+II.AvxCode] BufferStore [EBX+STM.EmitBuffer],ESI,ECX JMP .38: ; Skip REX when AVX prefix is used. .32: LEA ESI,[EDI+II.PfxEmitted] ; REX prefix is in LSB. JNSt [EDI+II.Ppx],iiPpxRemoveREX.R, .33: ANDB [ESI],0xFB .33: JNSt [EDI+II.Ppx],iiPpxRemoveREX.W, .34: ANDB [ESI],0xF7 .34: JNSt [EDI+II.Ppx],iiPpxRemoveREX, .36: CMPB [ESI],iiPfxREX JNE .36: MOVB [ESI],0 JMP .38: .36: CMPB [ESI],0 JZ .38: ; Skip when no REX prefix was required. MOV ECX,1 ; Prepare the size of REX prefix. BufferStore [EBX+STM.EmitBuffer],ESI,ECX IiRequire X64 ; REX requires CPU=X64. .38: ; Flush operation code. MOV ECX,[EDI+II.Ppg] AND ECX,iiPpgOpcodeSizeMask ; ECX=size of opcode (1..15). JZ .40: LEA ESI,[EDI+II.Opcode] BufferStore [EBX+STM.EmitBuffer],ESI,ECX .40: ; Flush ModR/M, SIB. MOV CL,1 JNSt [EDI+II.Ppg],iiPpgModRMr|iiPpgModRMd,.42: ; SIB is never emitted without ModR/M. BT [EDI+II.Ppg],13 ; iiPpgSIB=0x0000_2000 = bit 13. ADC ECX,0 ; ECX=2 when SIB is present, otherwise ECX=1. LEA ESI,[EDI+II.ModRM] BufferStore [EBX+STM.EmitBuffer],ESI,ECX ; Emit ModR/M or ModR/M+SIB. .42: ; Create displacement relocations. MOV EAX,[EDI+II.Reloc] JNSt EAX,iiRelocDispAbs|iiRelocDispRel|iiRelocDispRIP,.50: ; Skip when no displacement relocation was requested. BufferRetrieve [EBX+STM.EmitBuffer] ; ECX is now the size of prefixes+opcode+ModRM+SIB emitted so far in this instruction. LEA ESI,[%Reloc] ; Prepare RELOC record. Clear ESI,Size=SIZE#RELOC MOV [ESI+RELOC.OrgLow],ECX ; Temporary RELOC.Org will be elevated later in StmFlush. MOV ECX,[EDI+II.DispRelocSym] MOV [ESI+RELOC.Symbol],ECX JNSt EAX,iiRelocExtAttrReq,.44: JECXZ .44: MOVZX EDX,AL ; II.OperandX offsetiiRelocOffsExtAttr
. EDX=00h|14h|28h|3Ch. MOV EDX,[EDX+EDI+II.Operand1.Status] AND EDX,expExtAttr ; Isolate the attribute identification (dictAttrNONE, dictAttrSEGMENT etc). SetSt [ESI+RELOC.Status],EDX ; Request possible postponed attribute evaluation. .44: MOV EDX,iiMfgDISP_WORD|iiMfgDISP_DWORD|iiMfgDISP_QWORD ; Mask of the width of relocated object. AND EDX,[EDI+II.MfgEmitted] SHL EDX,15 ; Convert iiMfgDISP_Mask to relocWidthMask. SetSt [ESI+RELOC.Status],EDX ; Specify the size of relocated object (2,4,8 bytes). JSt EAX,iiRelocDispRIP, .iiRelocDispRIP JECXZ .46: MOV EDX,[ECX+SYM.Section] TEST EDX JZ .46: MOV ECX,[EDX+SSS.SymPtr] ; Target is relocated by the section's bottom symSe. Symbol's offset is inII.Disp
. MOV [ESI+RELOC.Symbol],ECX .46: JSt EAX,iiRelocDispAbs, .iiRelocDispAbs ; Dispatch by the requested relocation type. JSt EAX,iiRelocDispRel, .iiRelocDispRel JMP .50: .iiRelocDispRIP: ; Intrasection rIP-relative displacement adressing (ADDR=REL) is solved here at asm-time. No RELOC needed. MOV ECX,[EDI+II.MfgEmitted] ; Encoded size of displacement and immediate field (iiMfgDISP_WORD|DWORD|QWORD+iiMfgIMM_WORD|DWORD|QWORD). MOV EAX,iiMfgDISP_Mask XOR EDX,EDX AND EAX,ECX SHR EAX,4 ; Convert iiMfgDISP_Mask to the number of bytes in displacement field (0,1,2,4,8). AND ECX,iiMfgIMM_Mask ;SHR ECX,0 ; Convert iiMfgIMM_Mask to the number of bytes in imm field (0,1,2,4,8). BT [EDI+II.Ppg],14 ; iiPpgImm2 = 0x0000_4000, bit 14. Test the size of Imm2 (0,1). ADC EAX,ECX ; EDX:EAX is now the total size of current instruction. ADD EAX,[ESI+RELOC.OrgLow] ; Add the size of prefixes+opcode+ModRM+SIB emitted so far in this instruction. ADD EAX,[EBX+STM.Size] ; In case of Multiop (PUSH|POP|INC|DEC) add the size of previous STM data. Otherwise Stm.Size=0. ADD EAX,[EBX+STM.OffsetLow] ; Add the offset of$
(origin of this statement). ADC EDX,[EBX+STM.OffsetHigh] ; EDX:EAX is now rIP, i.e. offset of the next instruction. SUB [EDI+II.DispLow],EAX ; Perform the actual relocation in emitted code. SBB [EDI+II.DispHigh],EDX JMP .50: ; Do not create RELOC record. .iiRelocDispRel: ; Store RIP-relative displacement relocation to the symbol ECX which belongs to other section (perhaps external). SetSt [ESI+RELOC.Status],relocRel MOV EAX,[EDI+II.MfgEmitted] ; Encoded size of displacement and immediate field (iiMfgDISP_WORD|DWORD|QWORD+iiMfgIMM_WORD|DWORD|QWORD). MOV EDX,EAX AND EAX,iiMfgDISP_Mask AND EDX,iiMfgIMM_Mask SHR EAX,4 ; Convert iiMfgDISP_Mask to the number of bytes in disp field (0,1,2,4,8). ;SHR EDX,0 ; Convert iiMfgIMM_Mask to the number bytes in imm filed (0,1,2,4,8). BT [EDI+II.Ppg],14 ; iiPpgImm2 = 0x0000_4000, bit 14. Test the size of Imm2 (0,1). ADC EAX,EDX CDQ ; EDX:EAX is now the size of disp+imm+imm2, i.e. rIP (end of instruction) related to RELOC.Org. SUB [ESI+RELOC.AddendLow],EAX SBB [ESI+RELOC.AddendHigh],EDX JMP .48: ; Go to store RELOC ESI. .iiRelocDispAbs: ; Store absolute displacement relocation record. JECXZ .50: ; If there's no symbol in displacement, the target is constant, e.g.MOV EAX,[EBP+40]
. No reloc. SetSt [ESI+RELOC.Status],relocAbsVA .48:BufferStore [EBX+STM.RelocBuffer],ESI,SIZE#RELOC ; Statement EBX requires relocation at combine or link time. .50: ; Flush the displacement. MOV ECX,[EDI+II.MfgEmitted] AND ECX,iiMfgDISP_Mask JZ .55: SHR ECX,4 ; Convert flags in iiMfgDISP_Mask to number of disp bytes 0,1,2,4,8. LEA ESI,[EDI+II.DispLow] BufferStore [EBX+STM.EmitBuffer],ESI,ECX CMP CL,8 JE .55: JNSt [EDI+II.SssStatus],sssWidth64,.55: ; Skip the check if index or base register is used. MOV EAX,[EDI+II.Operand1+EXP.Status] CMP AL,'M' JNE .51: JSt EAX,expBasePres|expIndexPres,.55: .51:MOV EAX,[EDI+II.Operand2+EXP.Status] CMP AL,'M' JNE .53: JSt EAX,expBasePres|expIndexPres,.55: .53:; Check if the displacement is encodable in 32 bits. JSt [EDI+II.MfgEmitted],iiMfgADDR_REL,.55: CMPD [ESI+4],0 ; Test if displacement exceeds 4GB in ADDR=ABS. JZ .55: Msg PgmStatus=pgmLastPass,'3432' ; Displacement above 4 GB is not directly encodable. Use indirect addressing. .55: ; Create relocations of immediate operand. MOV EAX,[EDI+II.Reloc] JNSt EAX,iiRelocImmAbs|iiRelocImmRel|iiRelocImmRIP|iiRelocPara|iiRelocFar,.62: ; Skip when no relocation of imm was requested. BufferRetrieve [EBX+STM.EmitBuffer] ; ECX is now the size of prefixes+opcode+ModRM+SIB+disp emitted so far in this instruction. LEA ESI,[%Reloc] ; Prepare RELOC record. Clear ESI,Size=SIZE#RELOC MOV [ESI+RELOC.OrgLow],ECX ; Temporary RELOC.Org will be elevated later in StmFlush. MOV ECX,[EDI+II.ImmRelocSym] MOV [ESI+RELOC.Symbol],ECX JNSt EAX,iiRelocExtAttrReq,.5C: JECXZ .5C: MOVZX EDX,AL ; II.OperandX offsetiiRelocOffsExtAttr
. EDX=00h|14h|28h|3Ch. MOV EDX,[EDX+EDI+II.Operand1.Status] ; EXP.Status of the relocated operand. AND EDX,expExtAttr ; Isolate the attribute identification (dictAttrNONE, dictAttrSEGMENT etc). SetSt [ESI+RELOC.Status],EDX ; Request possible postponed attribute evaluation. .5C: MOV EDX,iiMfgIMM_WORD|iiMfgIMM_DWORD|iiMfgIMM_QWORD ; Mask of the width of relocated object. AND EDX,[EDI+II.MfgEmitted] SHL EDX,19 ; Convert iiMfgIMM_Mask to relocWidthMask. SetSt [ESI+RELOC.Status],EDX ; Specify the flag relocWidth16,32,64. JSt EAX,iiRelocImmRIP, .iiRelocImmRIP: JSt EAX,iiRelocImmRel, .iiRelocImmRel: JECXZ .5E: MOV EDX,[ECX+SYM.Section] TEST EDX JZ .5E: MOV ECX,[EDX+SSS.SymPtr] ; Target is relocated by the section's bottom symSe. Symbol's offset is inII.Imm
. MOV [ESI+RELOC.Symbol],ECX .5E: JSt EAX,iiRelocImmAbs, .iiRelocImmAbs: ; Dispatch by the requested relocation type. JSt EAX,iiRelocFar, .iiRelocFar: JSt EAX,iiRelocPara, .iiRelocPara: JMP .62: ; Dispatched handlers input: ESI=^RELOC, ECX=^SYM of target (may be 0). .iiRelocImmRIP: ; Intrasection rIP-relative imm addressing (CALL, JMP) is solved here at asm-time. No RELOC needed. MOV EAX,iiMfgIMM_Mask AND EAX,[EDI+II.MfgEmitted] ; Encoded size of immediate field (iiMfgDISP_BYTE|WORD|DWORD|QWORD). XOR EDX,EDX ;SHR EAX,0 ; ConvertiiMfgIMM_Mask
to the number of bytes in imm field (0,1,2,4,8). BT [EDI+II.Ppg],14 ; iiPpgImm2 = 0x0000_4000, bit 14. Test the size of Imm2 (0 or 1). ADC EAX,[ESI+RELOC.OrgLow] ; Add the size of prefixes+opcode+ModRM+SIB+disp emitted so far in this instruction. ADD EAX,[EBX+STM.Size] ; In case of Multiop (PUSH|POP|INC|DEC) add the size of previous STM data. Otherwise Stm.Size=0. ADD EAX,[EBX+STM.OffsetLow] ; Add the offset of$
(origin of this statement). ADC EDX,[EBX+STM.OffsetHigh] ; EDX:EAX is now rIP, i.e. offset of the next instruction. SUB [EDI+II.ImmLow],EAX ; Perform the actual relocation in emitted code. SBB [EDI+II.ImmHigh],EDX JMP .62: ; Do not create RELOC record. .iiRelocImmRel: ; Relative relocation to the target symbol ECX which is in other section or external. SetSt [ESI+RELOC.Status],relocRel MOV EAX,iiMfgIMM_Mask AND EAX,[EDI+II.MfgEmitted] ; Encoded size of immediate field (iiMfgDISP_BYTE|WORD|DWORD|QWORD). ;SHR EAX,0 ; ConvertiiMfgIMM_Mask
to the number of imm bytes (0,1,2,4,8). BT [EDI+II.Ppg],14 ; iiPpgImm2 = 0x0000_4000, bit 14. Test the size of Imm2 (0 or 1). ADC EAX,0 ; Add the size of prefixes+opcode+ModRM+SIB+disp emitted so far in this instruction. CDQ ; Sign-extend EAX to EDX:EAX. SUB [ESI+RELOC.AddendLow],EAX SBB [ESI+RELOC.AddendHigh],EDX JECXZ .57: ; ECX is the target symbol, or 0 when the target is scalar. MOV EDX,[ECX+SYM.Section] TEST EDX JZ .57: .56: MOV ECX,[EDX+SSS.SymPtr] MOV [ESI+RELOC.Symbol],ECX ; symSe which represents the relocatable bottom of target section|segment. .57: BufferStore [EBX+STM.RelocBuffer],ESI,SIZE#RELOC JMP .62: ; Go to store RELOC. .iiRelocImmAbs: ; Absolute immediate relocation record. TEST ECX ; If there's no symbol in immediate operand, the target is constant, JZ .62: ; e.g.MOV EAX,0x40_0000
. No reloc. MOV EAX,[ESI+RELOC.Status] AND EAX,relocExtAttr CMP EAX,dictAttrPARA<<16 ; >> JE .58: SetSt [ESI+RELOC.Status],relocAbsVA JMP .59: .58: SetSt [ESI+RELOC.Status],relocPara .59: BufferStore [EBX+STM.RelocBuffer],ESI,SIZE#RELOC ; Statement EBX requires relocation at combine or link time. JNSt [EDI+II.Reloc],iiRelocPara, .62: ; Both iiRelocAbsVA and iiRelocPara were set when the target is a relocatable FAR address. Second RELOC record will be created. MOV EAX,[ESI+RELOC.Status] AND EAX,relocWidthMask SHR EAX,19 ; EAX is 2 or 4. MOV EDX,relocWidth16+relocPara ADD [ESI+RELOC.OrgLow],EAX MOV [ESI+RELOC.Status],EDX BufferStore [EBX+STM.RelocBuffer],ESI,SIZE#RELOC ; Statement EBX requires relocation at combine or link time. JMP .62: .iiRelocPara: ; Immediate PARA# value relocation (OMF FIXUPP Location=2), e.g.MOV AX,PARA# [DATA]
. SetSt [ESI+RELOC.Status],relocPara+relocWidth16 JECXZ .6R: JMP .6R: .iiRelocFar: ; Immediate far ptr 16:16 or 16:32, e.g.JMPF FarProc
. MOV EAX,relocFar+relocWidth32 ; The first one is an absolute word/dword relocation of offset. JSt [EDI+II.MfgEmitted],iiMfgIMM_DWORD,.60: MOV EAX,relocFar+relocWidth16 .60:MOV [ESI+RELOC.Status],EAX .6R:BufferStore [EBX+STM.RelocBuffer],ESI,SIZE#RELOC .62:; Flush the immediate operand. LEA ESI,[EDI+II.ImmLow] MOV EAX,[ESI+0] MOV EDX,[ESI+4] Invoke ExpWidthBitwise:: SUB CL,4 ; CL is now -1,0,1,2,3 for immediate size 0,byte,word,dword,qword. MOV EAX,1 MOV EDX,[EDI+II.MfgEmitted] JNG .64: SHL EAX,CL ; AL is now 0,1,2,4,8 for immediate value 0,byte,word,dword,qword. .64:AND EDX,iiMfgIMM_Mask JZ .70: ; Skip when no immediate was requested. ;SHR EDX,0 ; Convert iiMfgIMM_Mask flags to the number of imm bytes 0,1,2,4,8. JSt [EDI+II.Reloc],iiRelocImmRIP,.66: ; Do not check overflow when RIP addressing frame is used. CMP EAX,EDX LEA EAX,[EDI+II.ImmLow] Msg cc=A,PgmStatus=pgmLastPass,'6728',EAX,EDX; Immediate value 0x!1Q is too big for !2D bytes. .66:BufferStore [EBX+STM.EmitBuffer],ESI,EDX ; Emit 1..4 bytes of immediate value. .70:JNSt [EDI+II.Ppg],iiPpgPara,.72: ; Flush the 16bit paragraph address (immediate segment value in JMPF/CALLF). LEA ESI,[EDI+II.Para] BufferStore [EBX+STM.EmitBuffer],ESI,2 .72:JNSt [EDI+II.Ppg],iiPpgImm2,.73: ; Flush auxiliary immediate byte. LEA ESI,[EDI+II.Imm2] BufferStore [EBX+STM.EmitBuffer],ESI,1 ; The instruction is now emitted. .73:MOV EAX,iiPpgVSIBind ; VSIB check if vector indexregister is required and used. MOV EDX,[EDI+II.Ppx] MOV ECX,[EDI+II.Ppg] AND EDX,EAX AND ECX,EAX JNZ .74: ; If VSIB is required. TEST EDX Msg cc=NZ,'6284' ; This instruction does not accept vector indexregister. JMP .80: ; If no SSE register was used as index. .GetOrdinal: PROC ; Return ordinal number from 'R' register or 'M' VSIB indexregister in operand EDX. ; Input: EDI=^II, EDX=^EXP. ; Output: EAX=register ordinal 0..31 or -1 when operand is not 'R' or 'M'. MOV EAX,[EDX+EXP.Status] Dispatch AL,'R','M' MOV EAX,-1 RET .R:Invoke IiGetRegOrdinal,[EDX+EXP.Low] RET .M:SHR EAX,20 ; Convert EXP.Status:expIndex to ordinal in AL. AND EAX,iiReg_Ord16 ; Get rid of other status bits. JNSt [EDI+II.Ppx],iiPpxV`, .V: OR AL,0x10 ; Ordinal bit 4. .V:RET ENDP .GetOrdinal: .74: MOV EAX,ECX SHR EAX,20 ; EAX is now 0,1,2,3 for none,vm32x,vm32y,vm32z ADD AL,'X'-1 CMP ECX,EDX JE .75: Msg '6285',EAX ; This instruction requires vector indexregister !1ZMM. RstSt [EBX+STM.Status],stmOperationPresent ; Invalidate the instruction. .75: JNSt [EDI+II.MfxEmitted],iiMfxPREFIX_MVEX|iiMfxPREFIX_EVEX, .76: ; VSIB check if maskregister is used and nonzero.. TESTB [EDI+II.AvxCode+3],0x07 ; Position of mask-register in MVEX/EVEX prefix. Msg cc=Z,'3312' ; No mask was specified, this instruction requires MASK=K1..K7. JNSt [EDI+II.MfxEmitted],iiMfxPREFIX_EVEX, .76: TESTB [EDI+II.AvxCode+3],0x80 ; Position of EVEX.z. Msg cc=NZ,'3313' ; Zeroing is not allowed in this instruction. .76: ; VSIB check if all involved SSE registers are distinct.. LEA EDX,[EDI+II.Operand1] CALL .GetOrdinal: MOV ESI,EAX LEA EDX,[EDI+II.Operand2] CALL .GetOrdinal: MOV ECX,EAX LEA EDX,[EDI+II.Operand3] CALL .GetOrdinal: CMP AL,-1 JE .78: ; Skip when Operand3 was not used. CMP EAX,ESI JE .W3315: CMP EAX,ECX JE .W3315: .78: CMP ECX,ESI JNE .80: .W3315:Msg '3315' ; Destination, vector index register and mask register should be distinct. .80: JNSt [EDI+II.PfxEmitted],iiPfxREX,.82: ; Check if all CPU requirements are granted by EAOPT.Machine. JSt [EDI+II.SssStatus],sssWidth64,.82: Msg '6784' ; Operand requires prefix REX which is supported in 64bit segment only. .82: JNSt [EDI+II.Ppg],iiPpgNoREX,.84: JNSt [EDI+II.PfxEmitted],iiPfxREX,.84: Msg '6785' ; Registers AH,BH,CH,DH cannot be used when instruction requires prefix REX/VEX. .84: MOV ECX,[EDI+II.Cpu] ; CPU generation required by handler/prefix/register. MOV EDX,[Ea.Eaopt.Machine::] ; Granted by CPU=, SIMD= option. AND EDX,ECX ; Not-required flags are irrelevant. XOR EDX,ECX ; Each bit set in ECX should be set in EAOPT.Machine, too. MOV ECX,[EDI+II.Features] ; CPU features required by handler/register. MOV ESI,[Ea.Eaopt.Features::] ; Granted by feature options MMX=, UNDOC= etc. AND ESI,ECX ; Not required flags are irrelevant. XOR ESI,ECX ; Each bit set in ECX should be set in EAOPT.Features, too. MOV EAX,EDX ; EDX has set CPU flag(s) not granted by EUROASM options. OR EAX,ESI ; ESI has set CPU features not granted by EUROASM options. JZ .86: ; If both EDX,ESI are clear, all requested properties were anticipated. Invoke EaBufferReserve::, IiFlush ; Otherwise report W2340. Invoke IiCpuToKeys,EDX,ESI,EAX BufferRetrieve EAX Invoke EaBufferRelease::,EAX PUSH ECX,ESI MOV EAX,ESP Msg '2340',EAX ; This instruction requires option "EUROASM %1S". POP ESI,ECX .86: ; Check if all used prefixes are allowed in this instruction by IiAllowPrefix MOV EAX,[EDI+II.PfxExplicit] ; Prefixes explicitly used in this instruction. MOV EDX,[EDI+II.PfxAllowed] ; Expected prefixes. AND EAX,iiPfxMask AND EDX,EAX ; Prefixes not explicitly used in this instruction are irrelevant. XOR EDX,EAX ; Each bit set in EAX should be set in EDX, too. JZ .88: ; If all prefixes are anticipated. BSF EAX,EDX ; EAX is now 16..29, will be converted to W2356..W2369. MOV CL,10 DIV CL ; AL=1..2, AH=0..9. XCHG AL,AH BSWAP EAX ; Construct the warning identifier. OR EAX,'2340' ; W2356..W2369 Prefix xxx is not expected in this instruction. Msg EAX .88: ; Check if explicit modifiers are allowed. MOV EAX,[EDI+II.MfgExplicit] ; General modifiers explicitly requested for this instruction. MOV EDX,[EDI+II.MfgAllowed] AND EDX,EAX ; Modifiers not explicitly requested in this instruction are irrelevant. XOR EDX,EAX ; Each bit set in EAX should be set in EDX, too. MOV EAX,[EDI+II.MfxExplicit] ; AVX modifiers explicitly requested for this instruction. MOV ECX,[EDI+II.MfxAllowed] RstSt EAX,iiMfxOPER_Used+iiMfxOPER_Mask AND ECX,EAX ; Modifiers not explicitly requested in this instruction are irrelevant. XOR ECX,EAX ; Each bit set in EAX should be set in ECX, too. MOV EAX,EDX ; EDX:ECX should be zero. OR EAX,ECX JZ .90: ; Skip when all modifiers were allowed. Invoke EaBufferReserve::,IiFlush Invoke IiModifiersToKeys,EDX,ECX,EAX BufferRetrieve EAX Invoke EaBufferRelease::,EAX PUSH ECX,ESI MOV EAX,ESP Msg '2400',EAX ; Modifier "!1S" is not applicable in this instruction. POP ESI,ECX .90: ; Display actually used modifiers when EUROASM DISPLAYENC=YES. JNSt [Ea.Eaopt.Status::],eaoptDISPLAYENC,.92: JNSt [EBX+STM.Status],stmOperationPresent,.92: ; Skip display when the instruction was invalidated. BufferRetrieve [EBX+STM.EmitBuffer] MOV EDX,ECX ; Instruction size. Invoke EaBufferReserve::,%^PROC Invoke IiModifiersToKeys,[EDI+II.MfgEmitted],[EDI+II.MfxEmitted],EAX BufferRetrieve EAX Invoke EaBufferRelease::,EAX PUSH ECX,ESI MOV EAX,ESP Msg '1080',EDX,EAX ; Emitted size=!1D!2S. POP ESI,ECX .92: ; Check if explicit modifiers were satisfied. MOV ECX,[EDI+II.MfxExplicit] ; AVX modifiers explicitly requested for this instruction. MOV EAX,[EDI+II.MfxEmitted] ; Modifiers actually used in instruction assembly. RstSt ECX,iiMfxOPER_Mask+iiMfxOPER_Used ; OPER= is always obeyed. AND EAX,ECX ; Modifiers not used in this instruction are irrelevant. XOR ECX,EAX ; Each bit set in ECX should be set in EAX, too. .94: MOV EDX,[EDI+II.MfgExplicit] ; General modifiers explicitly requested for this instruction. MOV EAX,[EDI+II.MfgEmitted] ; Modifiers actually used in instruction assembly. AND EAX,EDX ; Modifiers not used in this instruction are irrelevant. XOR EDX,EAX ; Each bit set in EDX should be set in EAX, too. MOV EAX,EDX ; Test if EDX:ECX=0. OR EAX,ECX JZ .96: ; Skip when all modifiers were obeyed, otherwise W2401. Invoke EaBufferReserve::,IiFlush Invoke IiModifiersToKeys,EDX,ECX,EAX BufferRetrieve EAX Invoke EaBufferRelease::,EAX JECXZ .96: PUSH ECX,ESI MOV EAX,ESP Msg '2401',EAX,PgmStatus=pgmLastPass ; Modifiers "!1S" could not be obeyed in this instruction. POP ESI,ECX .96: ; Check if instruction suffix is not in conflict with effective operand size. MOV EAX,[EDI+II.MfgEmitted] MOV EDX,[EDI+II.MfgSuffix] ; Data width commanded with mnemonic suffix. AND EAX,EDX CMP EAX,EDX JE .99: TEST EDX,iiMfgDATA_Mask Msg cc=NZ,'6740',PgmStatus=pgmLastPass ; Impracticable operand-size requested with mnemonic suffix. Msg cc=Z, '6760',PgmStatus=pgmLastPass ; Impracticable distance requested with mnemonic suffix. .99: EndProcedure IiFlush
ENDPROGRAM ii