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, CET) | 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 2254 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?Listin the source file,- create public procedure of the instruction handler,
- create a link to this handler in alphabetical list
%Ii?Listin 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.
ii PROGRAM FORMAT=COFF,MODEL=FLAT,WIDTH=32
INCLUDEHEAD euroasm.htm, \ Interface (structures, symbols and macros) of other modules used in this source.
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
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
CMP DL,r8:
JE .r8:
CMP DL,m8
JE .m8:
JMP .30:
.r8: MOV ESI,=B"r8,"
JMP .80:
.m8: MOV ESI,=B"m8,"
JMP .80:
.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]
Debug3854::
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
SssEmit
IiFlush 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. in SEGES 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. in MOV 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 offset iiRelocOffsExtAttr. 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 in II.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 offset iiRelocOffsExtAttr. 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 in II.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 ; 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 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 ; Convert iiMfgIMM_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