12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724 |
- // Copyright 2014 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // Table-driven decoding of x86 instructions.
- package x86asm
- import (
- "encoding/binary"
- "errors"
- "fmt"
- "runtime"
- )
- // Set trace to true to cause the decoder to print the PC sequence
- // of the executed instruction codes. This is typically only useful
- // when you are running a test of a single input case.
- const trace = false
- // A decodeOp is a single instruction in the decoder bytecode program.
- //
- // The decodeOps correspond to consuming and conditionally branching
- // on input bytes, consuming additional fields, and then interpreting
- // consumed data as instruction arguments. The names of the xRead and xArg
- // operations are taken from the Intel manual conventions, for example
- // Volume 2, Section 3.1.1, page 487 of
- // http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf
- //
- // The actual decoding program is generated by ../x86map.
- //
- // TODO(rsc): We may be able to merge various of the memory operands
- // since we don't care about, say, the distinction between m80dec and m80bcd.
- // Similarly, mm and mm1 have identical meaning, as do xmm and xmm1.
- type decodeOp uint16
- const (
- xFail decodeOp = iota // invalid instruction (return)
- xMatch // completed match
- xJump // jump to pc
- xCondByte // switch on instruction byte value
- xCondSlashR // read and switch on instruction /r value
- xCondPrefix // switch on presence of instruction prefix
- xCondIs64 // switch on 64-bit processor mode
- xCondDataSize // switch on operand size
- xCondAddrSize // switch on address size
- xCondIsMem // switch on memory vs register argument
- xSetOp // set instruction opcode
- xReadSlashR // read /r
- xReadIb // read ib
- xReadIw // read iw
- xReadId // read id
- xReadIo // read io
- xReadCb // read cb
- xReadCw // read cw
- xReadCd // read cd
- xReadCp // read cp
- xReadCm // read cm
- xArg1 // arg 1
- xArg3 // arg 3
- xArgAL // arg AL
- xArgAX // arg AX
- xArgCL // arg CL
- xArgCR0dashCR7 // arg CR0-CR7
- xArgCS // arg CS
- xArgDR0dashDR7 // arg DR0-DR7
- xArgDS // arg DS
- xArgDX // arg DX
- xArgEAX // arg EAX
- xArgEDX // arg EDX
- xArgES // arg ES
- xArgFS // arg FS
- xArgGS // arg GS
- xArgImm16 // arg imm16
- xArgImm32 // arg imm32
- xArgImm64 // arg imm64
- xArgImm8 // arg imm8
- xArgImm8u // arg imm8 but record as unsigned
- xArgImm16u // arg imm8 but record as unsigned
- xArgM // arg m
- xArgM128 // arg m128
- xArgM256 // arg m256
- xArgM1428byte // arg m14/28byte
- xArgM16 // arg m16
- xArgM16and16 // arg m16&16
- xArgM16and32 // arg m16&32
- xArgM16and64 // arg m16&64
- xArgM16colon16 // arg m16:16
- xArgM16colon32 // arg m16:32
- xArgM16colon64 // arg m16:64
- xArgM16int // arg m16int
- xArgM2byte // arg m2byte
- xArgM32 // arg m32
- xArgM32and32 // arg m32&32
- xArgM32fp // arg m32fp
- xArgM32int // arg m32int
- xArgM512byte // arg m512byte
- xArgM64 // arg m64
- xArgM64fp // arg m64fp
- xArgM64int // arg m64int
- xArgM8 // arg m8
- xArgM80bcd // arg m80bcd
- xArgM80dec // arg m80dec
- xArgM80fp // arg m80fp
- xArgM94108byte // arg m94/108byte
- xArgMm // arg mm
- xArgMm1 // arg mm1
- xArgMm2 // arg mm2
- xArgMm2M64 // arg mm2/m64
- xArgMmM32 // arg mm/m32
- xArgMmM64 // arg mm/m64
- xArgMem // arg mem
- xArgMoffs16 // arg moffs16
- xArgMoffs32 // arg moffs32
- xArgMoffs64 // arg moffs64
- xArgMoffs8 // arg moffs8
- xArgPtr16colon16 // arg ptr16:16
- xArgPtr16colon32 // arg ptr16:32
- xArgR16 // arg r16
- xArgR16op // arg r16 with +rw in opcode
- xArgR32 // arg r32
- xArgR32M16 // arg r32/m16
- xArgR32M8 // arg r32/m8
- xArgR32op // arg r32 with +rd in opcode
- xArgR64 // arg r64
- xArgR64M16 // arg r64/m16
- xArgR64op // arg r64 with +rd in opcode
- xArgR8 // arg r8
- xArgR8op // arg r8 with +rb in opcode
- xArgRAX // arg RAX
- xArgRDX // arg RDX
- xArgRM // arg r/m
- xArgRM16 // arg r/m16
- xArgRM32 // arg r/m32
- xArgRM64 // arg r/m64
- xArgRM8 // arg r/m8
- xArgReg // arg reg
- xArgRegM16 // arg reg/m16
- xArgRegM32 // arg reg/m32
- xArgRegM8 // arg reg/m8
- xArgRel16 // arg rel16
- xArgRel32 // arg rel32
- xArgRel8 // arg rel8
- xArgSS // arg SS
- xArgST // arg ST, aka ST(0)
- xArgSTi // arg ST(i) with +i in opcode
- xArgSreg // arg Sreg
- xArgTR0dashTR7 // arg TR0-TR7
- xArgXmm // arg xmm
- xArgXMM0 // arg <XMM0>
- xArgXmm1 // arg xmm1
- xArgXmm2 // arg xmm2
- xArgXmm2M128 // arg xmm2/m128
- xArgYmm2M256 // arg ymm2/m256
- xArgXmm2M16 // arg xmm2/m16
- xArgXmm2M32 // arg xmm2/m32
- xArgXmm2M64 // arg xmm2/m64
- xArgXmmM128 // arg xmm/m128
- xArgXmmM32 // arg xmm/m32
- xArgXmmM64 // arg xmm/m64
- xArgYmm1 // arg ymm1
- xArgRmf16 // arg r/m16 but force mod=3
- xArgRmf32 // arg r/m32 but force mod=3
- xArgRmf64 // arg r/m64 but force mod=3
- )
- // instPrefix returns an Inst describing just one prefix byte.
- // It is only used if there is a prefix followed by an unintelligible
- // or invalid instruction byte sequence.
- func instPrefix(b byte, mode int) (Inst, error) {
- // When tracing it is useful to see what called instPrefix to report an error.
- if trace {
- _, file, line, _ := runtime.Caller(1)
- fmt.Printf("%s:%d\n", file, line)
- }
- p := Prefix(b)
- switch p {
- case PrefixDataSize:
- if mode == 16 {
- p = PrefixData32
- } else {
- p = PrefixData16
- }
- case PrefixAddrSize:
- if mode == 32 {
- p = PrefixAddr16
- } else {
- p = PrefixAddr32
- }
- }
- // Note: using composite literal with Prefix key confuses 'bundle' tool.
- inst := Inst{Len: 1}
- inst.Prefix = Prefixes{p}
- return inst, nil
- }
- // truncated reports a truncated instruction.
- // For now we use instPrefix but perhaps later we will return
- // a specific error here.
- func truncated(src []byte, mode int) (Inst, error) {
- if len(src) == 0 {
- return Inst{}, ErrTruncated
- }
- return instPrefix(src[0], mode) // too long
- }
- // These are the errors returned by Decode.
- var (
- ErrInvalidMode = errors.New("invalid x86 mode in Decode")
- ErrTruncated = errors.New("truncated instruction")
- ErrUnrecognized = errors.New("unrecognized instruction")
- )
- // decoderCover records coverage information for which parts
- // of the byte code have been executed.
- var decoderCover []bool
- // Decode decodes the leading bytes in src as a single instruction.
- // The mode arguments specifies the assumed processor mode:
- // 16, 32, or 64 for 16-, 32-, and 64-bit execution modes.
- func Decode(src []byte, mode int) (inst Inst, err error) {
- return decode1(src, mode, false)
- }
- // decode1 is the implementation of Decode but takes an extra
- // gnuCompat flag to cause it to change its behavior to mimic
- // bugs (or at least unique features) of GNU libopcodes as used
- // by objdump. We don't believe that logic is the right thing to do
- // in general, but when testing against libopcodes it simplifies the
- // comparison if we adjust a few small pieces of logic.
- // The affected logic is in the conditional branch for "mandatory" prefixes,
- // case xCondPrefix.
- func decode1(src []byte, mode int, gnuCompat bool) (Inst, error) {
- switch mode {
- case 16, 32, 64:
- // ok
- // TODO(rsc): 64-bit mode not tested, probably not working.
- default:
- return Inst{}, ErrInvalidMode
- }
- // Maximum instruction size is 15 bytes.
- // If we need to read more, return 'truncated instruction.
- if len(src) > 15 {
- src = src[:15]
- }
- var (
- // prefix decoding information
- pos = 0 // position reading src
- nprefix = 0 // number of prefixes
- lockIndex = -1 // index of LOCK prefix in src and inst.Prefix
- repIndex = -1 // index of REP/REPN prefix in src and inst.Prefix
- segIndex = -1 // index of Group 2 prefix in src and inst.Prefix
- dataSizeIndex = -1 // index of Group 3 prefix in src and inst.Prefix
- addrSizeIndex = -1 // index of Group 4 prefix in src and inst.Prefix
- rex Prefix // rex byte if present (or 0)
- rexUsed Prefix // bits used in rex byte
- rexIndex = -1 // index of rex byte
- vex Prefix // use vex encoding
- vexIndex = -1 // index of vex prefix
- addrMode = mode // address mode (width in bits)
- dataMode = mode // operand mode (width in bits)
- // decoded ModR/M fields
- haveModrm bool
- modrm int
- mod int
- regop int
- rm int
- // if ModR/M is memory reference, Mem form
- mem Mem
- haveMem bool
- // decoded SIB fields
- haveSIB bool
- sib int
- scale int
- index int
- base int
- displen int
- dispoff int
- // decoded immediate values
- imm int64
- imm8 int8
- immc int64
- immcpos int
- // output
- opshift int
- inst Inst
- narg int // number of arguments written to inst
- )
- if mode == 64 {
- dataMode = 32
- }
- // Prefixes are certainly the most complex and underspecified part of
- // decoding x86 instructions. Although the manuals say things like
- // up to four prefixes, one from each group, nearly everyone seems to
- // agree that in practice as many prefixes as possible, including multiple
- // from a particular group or repetitions of a given prefix, can be used on
- // an instruction, provided the total instruction length including prefixes
- // does not exceed the agreed-upon maximum of 15 bytes.
- // Everyone also agrees that if one of these prefixes is the LOCK prefix
- // and the instruction is not one of the instructions that can be used with
- // the LOCK prefix or if the destination is not a memory operand,
- // then the instruction is invalid and produces the #UD exception.
- // However, that is the end of any semblance of agreement.
- //
- // What happens if prefixes are given that conflict with other prefixes?
- // For example, the memory segment overrides CS, DS, ES, FS, GS, SS
- // conflict with each other: only one segment can be in effect.
- // Disassemblers seem to agree that later prefixes take priority over
- // earlier ones. I have not taken the time to write assembly programs
- // to check to see if the hardware agrees.
- //
- // What happens if prefixes are given that have no meaning for the
- // specific instruction to which they are attached? It depends.
- // If they really have no meaning, they are ignored. However, a future
- // processor may assign a different meaning. As a disassembler, we
- // don't really know whether we're seeing a meaningless prefix or one
- // whose meaning we simply haven't been told yet.
- //
- // Combining the two questions, what happens when conflicting
- // extension prefixes are given? No one seems to know for sure.
- // For example, MOVQ is 66 0F D6 /r, MOVDQ2Q is F2 0F D6 /r,
- // and MOVQ2DQ is F3 0F D6 /r. What is '66 F2 F3 0F D6 /r'?
- // Which prefix wins? See the xCondPrefix prefix for more.
- //
- // Writing assembly test cases to divine which interpretation the
- // CPU uses might clarify the situation, but more likely it would
- // make the situation even less clear.
- // Read non-REX prefixes.
- ReadPrefixes:
- for ; pos < len(src); pos++ {
- p := Prefix(src[pos])
- switch p {
- default:
- nprefix = pos
- break ReadPrefixes
- // Group 1 - lock and repeat prefixes
- // According to Intel, there should only be one from this set,
- // but according to AMD both can be present.
- case 0xF0:
- if lockIndex >= 0 {
- inst.Prefix[lockIndex] |= PrefixIgnored
- }
- lockIndex = pos
- case 0xF2, 0xF3:
- if repIndex >= 0 {
- inst.Prefix[repIndex] |= PrefixIgnored
- }
- repIndex = pos
- // Group 2 - segment override / branch hints
- case 0x26, 0x2E, 0x36, 0x3E:
- if mode == 64 {
- p |= PrefixIgnored
- break
- }
- fallthrough
- case 0x64, 0x65:
- if segIndex >= 0 {
- inst.Prefix[segIndex] |= PrefixIgnored
- }
- segIndex = pos
- // Group 3 - operand size override
- case 0x66:
- if mode == 16 {
- dataMode = 32
- p = PrefixData32
- } else {
- dataMode = 16
- p = PrefixData16
- }
- if dataSizeIndex >= 0 {
- inst.Prefix[dataSizeIndex] |= PrefixIgnored
- }
- dataSizeIndex = pos
- // Group 4 - address size override
- case 0x67:
- if mode == 32 {
- addrMode = 16
- p = PrefixAddr16
- } else {
- addrMode = 32
- p = PrefixAddr32
- }
- if addrSizeIndex >= 0 {
- inst.Prefix[addrSizeIndex] |= PrefixIgnored
- }
- addrSizeIndex = pos
- //Group 5 - Vex encoding
- case 0xC5:
- if pos == 0 && pos+1 < len(src) && (mode == 64 || (mode == 32 && src[pos+1]&0xc0 == 0xc0)) {
- vex = p
- vexIndex = pos
- inst.Prefix[pos] = p
- inst.Prefix[pos+1] = Prefix(src[pos+1])
- pos += 1
- continue
- } else {
- nprefix = pos
- break ReadPrefixes
- }
- case 0xC4:
- if pos == 0 && pos+2 < len(src) && (mode == 64 || (mode == 32 && src[pos+1]&0xc0 == 0xc0)) {
- vex = p
- vexIndex = pos
- inst.Prefix[pos] = p
- inst.Prefix[pos+1] = Prefix(src[pos+1])
- inst.Prefix[pos+2] = Prefix(src[pos+2])
- pos += 2
- continue
- } else {
- nprefix = pos
- break ReadPrefixes
- }
- }
- if pos >= len(inst.Prefix) {
- return instPrefix(src[0], mode) // too long
- }
- inst.Prefix[pos] = p
- }
- // Read REX prefix.
- if pos < len(src) && mode == 64 && Prefix(src[pos]).IsREX() && vex == 0 {
- rex = Prefix(src[pos])
- rexIndex = pos
- if pos >= len(inst.Prefix) {
- return instPrefix(src[0], mode) // too long
- }
- inst.Prefix[pos] = rex
- pos++
- if rex&PrefixREXW != 0 {
- dataMode = 64
- if dataSizeIndex >= 0 {
- inst.Prefix[dataSizeIndex] |= PrefixIgnored
- }
- }
- }
- // Decode instruction stream, interpreting decoding instructions.
- // opshift gives the shift to use when saving the next
- // opcode byte into inst.Opcode.
- opshift = 24
- // Decode loop, executing decoder program.
- var oldPC, prevPC int
- Decode:
- for pc := 1; ; { // TODO uint
- oldPC = prevPC
- prevPC = pc
- if trace {
- println("run", pc)
- }
- x := decoder[pc]
- if decoderCover != nil {
- decoderCover[pc] = true
- }
- pc++
- // Read and decode ModR/M if needed by opcode.
- switch decodeOp(x) {
- case xCondSlashR, xReadSlashR:
- if haveModrm {
- return Inst{Len: pos}, errInternal
- }
- haveModrm = true
- if pos >= len(src) {
- return truncated(src, mode)
- }
- modrm = int(src[pos])
- pos++
- if opshift >= 0 {
- inst.Opcode |= uint32(modrm) << uint(opshift)
- opshift -= 8
- }
- mod = modrm >> 6
- regop = (modrm >> 3) & 07
- rm = modrm & 07
- if rex&PrefixREXR != 0 {
- rexUsed |= PrefixREXR
- regop |= 8
- }
- if addrMode == 16 {
- // 16-bit modrm form
- if mod != 3 {
- haveMem = true
- mem = addr16[rm]
- if rm == 6 && mod == 0 {
- mem.Base = 0
- }
- // Consume disp16 if present.
- if mod == 0 && rm == 6 || mod == 2 {
- if pos+2 > len(src) {
- return truncated(src, mode)
- }
- mem.Disp = int64(binary.LittleEndian.Uint16(src[pos:]))
- pos += 2
- }
- // Consume disp8 if present.
- if mod == 1 {
- if pos >= len(src) {
- return truncated(src, mode)
- }
- mem.Disp = int64(int8(src[pos]))
- pos++
- }
- }
- } else {
- haveMem = mod != 3
- // 32-bit or 64-bit form
- // Consume SIB encoding if present.
- if rm == 4 && mod != 3 {
- haveSIB = true
- if pos >= len(src) {
- return truncated(src, mode)
- }
- sib = int(src[pos])
- pos++
- if opshift >= 0 {
- inst.Opcode |= uint32(sib) << uint(opshift)
- opshift -= 8
- }
- scale = sib >> 6
- index = (sib >> 3) & 07
- base = sib & 07
- if rex&PrefixREXB != 0 || vex == 0xC4 && inst.Prefix[vexIndex+1]&0x20 == 0 {
- rexUsed |= PrefixREXB
- base |= 8
- }
- if rex&PrefixREXX != 0 || vex == 0xC4 && inst.Prefix[vexIndex+1]&0x40 == 0 {
- rexUsed |= PrefixREXX
- index |= 8
- }
- mem.Scale = 1 << uint(scale)
- if index == 4 {
- // no mem.Index
- } else {
- mem.Index = baseRegForBits(addrMode) + Reg(index)
- }
- if base&7 == 5 && mod == 0 {
- // no mem.Base
- } else {
- mem.Base = baseRegForBits(addrMode) + Reg(base)
- }
- } else {
- if rex&PrefixREXB != 0 {
- rexUsed |= PrefixREXB
- rm |= 8
- }
- if mod == 0 && rm&7 == 5 || rm&7 == 4 {
- // base omitted
- } else if mod != 3 {
- mem.Base = baseRegForBits(addrMode) + Reg(rm)
- }
- }
- // Consume disp32 if present.
- if mod == 0 && (rm&7 == 5 || haveSIB && base&7 == 5) || mod == 2 {
- if pos+4 > len(src) {
- return truncated(src, mode)
- }
- dispoff = pos
- displen = 4
- mem.Disp = int64(binary.LittleEndian.Uint32(src[pos:]))
- pos += 4
- }
- // Consume disp8 if present.
- if mod == 1 {
- if pos >= len(src) {
- return truncated(src, mode)
- }
- dispoff = pos
- displen = 1
- mem.Disp = int64(int8(src[pos]))
- pos++
- }
- // In 64-bit, mod=0 rm=5 is PC-relative instead of just disp.
- // See Vol 2A. Table 2-7.
- if mode == 64 && mod == 0 && rm&7 == 5 {
- if addrMode == 32 {
- mem.Base = EIP
- } else {
- mem.Base = RIP
- }
- }
- }
- if segIndex >= 0 {
- mem.Segment = prefixToSegment(inst.Prefix[segIndex])
- }
- }
- // Execute single opcode.
- switch decodeOp(x) {
- default:
- println("bad op", x, "at", pc-1, "from", oldPC)
- return Inst{Len: pos}, errInternal
- case xFail:
- inst.Op = 0
- break Decode
- case xMatch:
- break Decode
- case xJump:
- pc = int(decoder[pc])
- // Conditional branches.
- case xCondByte:
- if pos >= len(src) {
- return truncated(src, mode)
- }
- b := src[pos]
- n := int(decoder[pc])
- pc++
- for i := 0; i < n; i++ {
- xb, xpc := decoder[pc], int(decoder[pc+1])
- pc += 2
- if b == byte(xb) {
- pc = xpc
- pos++
- if opshift >= 0 {
- inst.Opcode |= uint32(b) << uint(opshift)
- opshift -= 8
- }
- continue Decode
- }
- }
- // xCondByte is the only conditional with a fall through,
- // so that it can be used to pick off special cases before
- // an xCondSlash. If the fallthrough instruction is xFail,
- // advance the position so that the decoded instruction
- // size includes the byte we just compared against.
- if decodeOp(decoder[pc]) == xJump {
- pc = int(decoder[pc+1])
- }
- if decodeOp(decoder[pc]) == xFail {
- pos++
- }
- case xCondIs64:
- if mode == 64 {
- pc = int(decoder[pc+1])
- } else {
- pc = int(decoder[pc])
- }
- case xCondIsMem:
- mem := haveMem
- if !haveModrm {
- if pos >= len(src) {
- return instPrefix(src[0], mode) // too long
- }
- mem = src[pos]>>6 != 3
- }
- if mem {
- pc = int(decoder[pc+1])
- } else {
- pc = int(decoder[pc])
- }
- case xCondDataSize:
- switch dataMode {
- case 16:
- if dataSizeIndex >= 0 {
- inst.Prefix[dataSizeIndex] |= PrefixImplicit
- }
- pc = int(decoder[pc])
- case 32:
- if dataSizeIndex >= 0 {
- inst.Prefix[dataSizeIndex] |= PrefixImplicit
- }
- pc = int(decoder[pc+1])
- case 64:
- rexUsed |= PrefixREXW
- pc = int(decoder[pc+2])
- }
- case xCondAddrSize:
- switch addrMode {
- case 16:
- if addrSizeIndex >= 0 {
- inst.Prefix[addrSizeIndex] |= PrefixImplicit
- }
- pc = int(decoder[pc])
- case 32:
- if addrSizeIndex >= 0 {
- inst.Prefix[addrSizeIndex] |= PrefixImplicit
- }
- pc = int(decoder[pc+1])
- case 64:
- pc = int(decoder[pc+2])
- }
- case xCondPrefix:
- // Conditional branch based on presence or absence of prefixes.
- // The conflict cases here are completely undocumented and
- // differ significantly between GNU libopcodes and Intel xed.
- // I have not written assembly code to divine what various CPUs
- // do, but it wouldn't surprise me if they are not consistent either.
- //
- // The basic idea is to switch on the presence of a prefix, so that
- // for example:
- //
- // xCondPrefix, 4
- // 0xF3, 123,
- // 0xF2, 234,
- // 0x66, 345,
- // 0, 456
- //
- // branch to 123 if the F3 prefix is present, 234 if the F2 prefix
- // is present, 66 if the 345 prefix is present, and 456 otherwise.
- // The prefixes are given in descending order so that the 0 will be last.
- //
- // It is unclear what should happen if multiple conditions are
- // satisfied: what if F2 and F3 are both present, or if 66 and F2
- // are present, or if all three are present? The one chosen becomes
- // part of the opcode and the others do not. Perhaps the answer
- // depends on the specific opcodes in question.
- //
- // The only clear example is that CRC32 is F2 0F 38 F1 /r, and
- // it comes in 16-bit and 32-bit forms based on the 66 prefix,
- // so 66 F2 0F 38 F1 /r should be treated as F2 taking priority,
- // with the 66 being only an operand size override, and probably
- // F2 66 0F 38 F1 /r should be treated the same.
- // Perhaps that rule is specific to the case of CRC32, since no
- // 66 0F 38 F1 instruction is defined (today) (that we know of).
- // However, both libopcodes and xed seem to generalize this
- // example and choose F2/F3 in preference to 66, and we
- // do the same.
- //
- // Next, what if both F2 and F3 are present? Which wins?
- // The Intel xed rule, and ours, is that the one that occurs last wins.
- // The GNU libopcodes rule, which we implement only in gnuCompat mode,
- // is that F3 beats F2 unless F3 has no special meaning, in which
- // case F3 can be a modified on an F2 special meaning.
- //
- // Concretely,
- // 66 0F D6 /r is MOVQ
- // F2 0F D6 /r is MOVDQ2Q
- // F3 0F D6 /r is MOVQ2DQ.
- //
- // F2 66 0F D6 /r is 66 + MOVDQ2Q always.
- // 66 F2 0F D6 /r is 66 + MOVDQ2Q always.
- // F3 66 0F D6 /r is 66 + MOVQ2DQ always.
- // 66 F3 0F D6 /r is 66 + MOVQ2DQ always.
- // F2 F3 0F D6 /r is F2 + MOVQ2DQ always.
- // F3 F2 0F D6 /r is F3 + MOVQ2DQ in Intel xed, but F2 + MOVQ2DQ in GNU libopcodes.
- // Adding 66 anywhere in the prefix section of the
- // last two cases does not change the outcome.
- //
- // Finally, what if there is a variant in which 66 is a mandatory
- // prefix rather than an operand size override, but we know of
- // no corresponding F2/F3 form, and we see both F2/F3 and 66.
- // Does F2/F3 still take priority, so that the result is an unknown
- // instruction, or does the 66 take priority, so that the extended
- // 66 instruction should be interpreted as having a REP/REPN prefix?
- // Intel xed does the former and GNU libopcodes does the latter.
- // We side with Intel xed, unless we are trying to match libopcodes
- // more closely during the comparison-based test suite.
- //
- // In 64-bit mode REX.W is another valid prefix to test for, but
- // there is less ambiguity about that. When present, REX.W is
- // always the first entry in the table.
- n := int(decoder[pc])
- pc++
- sawF3 := false
- for j := 0; j < n; j++ {
- prefix := Prefix(decoder[pc+2*j])
- if prefix.IsREX() {
- rexUsed |= prefix
- if rex&prefix == prefix {
- pc = int(decoder[pc+2*j+1])
- continue Decode
- }
- continue
- }
- ok := false
- if prefix == 0 {
- ok = true
- } else if prefix.IsREX() {
- rexUsed |= prefix
- if rex&prefix == prefix {
- ok = true
- }
- } else if prefix == 0xC5 || prefix == 0xC4 {
- if vex == prefix {
- ok = true
- }
- } else if vex != 0 && (prefix == 0x0F || prefix == 0x0F38 || prefix == 0x0F3A ||
- prefix == 0x66 || prefix == 0xF2 || prefix == 0xF3) {
- var vexM, vexP Prefix
- if vex == 0xC5 {
- vexM = 1 // 2 byte vex always implies 0F
- vexP = inst.Prefix[vexIndex+1]
- } else {
- vexM = inst.Prefix[vexIndex+1]
- vexP = inst.Prefix[vexIndex+2]
- }
- switch prefix {
- case 0x66:
- ok = vexP&3 == 1
- case 0xF3:
- ok = vexP&3 == 2
- case 0xF2:
- ok = vexP&3 == 3
- case 0x0F:
- ok = vexM&3 == 1
- case 0x0F38:
- ok = vexM&3 == 2
- case 0x0F3A:
- ok = vexM&3 == 3
- }
- } else {
- if prefix == 0xF3 {
- sawF3 = true
- }
- switch prefix {
- case PrefixLOCK:
- if lockIndex >= 0 {
- inst.Prefix[lockIndex] |= PrefixImplicit
- ok = true
- }
- case PrefixREP, PrefixREPN:
- if repIndex >= 0 && inst.Prefix[repIndex]&0xFF == prefix {
- inst.Prefix[repIndex] |= PrefixImplicit
- ok = true
- }
- if gnuCompat && !ok && prefix == 0xF3 && repIndex >= 0 && (j+1 >= n || decoder[pc+2*(j+1)] != 0xF2) {
- // Check to see if earlier prefix F3 is present.
- for i := repIndex - 1; i >= 0; i-- {
- if inst.Prefix[i]&0xFF == prefix {
- inst.Prefix[i] |= PrefixImplicit
- ok = true
- }
- }
- }
- if gnuCompat && !ok && prefix == 0xF2 && repIndex >= 0 && !sawF3 && inst.Prefix[repIndex]&0xFF == 0xF3 {
- // Check to see if earlier prefix F2 is present.
- for i := repIndex - 1; i >= 0; i-- {
- if inst.Prefix[i]&0xFF == prefix {
- inst.Prefix[i] |= PrefixImplicit
- ok = true
- }
- }
- }
- case PrefixCS, PrefixDS, PrefixES, PrefixFS, PrefixGS, PrefixSS:
- if segIndex >= 0 && inst.Prefix[segIndex]&0xFF == prefix {
- inst.Prefix[segIndex] |= PrefixImplicit
- ok = true
- }
- case PrefixDataSize:
- // Looking for 66 mandatory prefix.
- // The F2/F3 mandatory prefixes take priority when both are present.
- // If we got this far in the xCondPrefix table and an F2/F3 is present,
- // it means the table didn't have any entry for that prefix. But if 66 has
- // special meaning, perhaps F2/F3 have special meaning that we don't know.
- // Intel xed works this way, treating the F2/F3 as inhibiting the 66.
- // GNU libopcodes allows the 66 to match. We do what Intel xed does
- // except in gnuCompat mode.
- if repIndex >= 0 && !gnuCompat {
- inst.Op = 0
- break Decode
- }
- if dataSizeIndex >= 0 {
- inst.Prefix[dataSizeIndex] |= PrefixImplicit
- ok = true
- }
- case PrefixAddrSize:
- if addrSizeIndex >= 0 {
- inst.Prefix[addrSizeIndex] |= PrefixImplicit
- ok = true
- }
- }
- }
- if ok {
- pc = int(decoder[pc+2*j+1])
- continue Decode
- }
- }
- inst.Op = 0
- break Decode
- case xCondSlashR:
- pc = int(decoder[pc+regop&7])
- // Input.
- case xReadSlashR:
- // done above
- case xReadIb:
- if pos >= len(src) {
- return truncated(src, mode)
- }
- imm8 = int8(src[pos])
- pos++
- case xReadIw:
- if pos+2 > len(src) {
- return truncated(src, mode)
- }
- imm = int64(binary.LittleEndian.Uint16(src[pos:]))
- pos += 2
- case xReadId:
- if pos+4 > len(src) {
- return truncated(src, mode)
- }
- imm = int64(binary.LittleEndian.Uint32(src[pos:]))
- pos += 4
- case xReadIo:
- if pos+8 > len(src) {
- return truncated(src, mode)
- }
- imm = int64(binary.LittleEndian.Uint64(src[pos:]))
- pos += 8
- case xReadCb:
- if pos >= len(src) {
- return truncated(src, mode)
- }
- immcpos = pos
- immc = int64(src[pos])
- pos++
- case xReadCw:
- if pos+2 > len(src) {
- return truncated(src, mode)
- }
- immcpos = pos
- immc = int64(binary.LittleEndian.Uint16(src[pos:]))
- pos += 2
- case xReadCm:
- immcpos = pos
- if addrMode == 16 {
- if pos+2 > len(src) {
- return truncated(src, mode)
- }
- immc = int64(binary.LittleEndian.Uint16(src[pos:]))
- pos += 2
- } else if addrMode == 32 {
- if pos+4 > len(src) {
- return truncated(src, mode)
- }
- immc = int64(binary.LittleEndian.Uint32(src[pos:]))
- pos += 4
- } else {
- if pos+8 > len(src) {
- return truncated(src, mode)
- }
- immc = int64(binary.LittleEndian.Uint64(src[pos:]))
- pos += 8
- }
- case xReadCd:
- immcpos = pos
- if pos+4 > len(src) {
- return truncated(src, mode)
- }
- immc = int64(binary.LittleEndian.Uint32(src[pos:]))
- pos += 4
- case xReadCp:
- immcpos = pos
- if pos+6 > len(src) {
- return truncated(src, mode)
- }
- w := binary.LittleEndian.Uint32(src[pos:])
- w2 := binary.LittleEndian.Uint16(src[pos+4:])
- immc = int64(w2)<<32 | int64(w)
- pos += 6
- // Output.
- case xSetOp:
- inst.Op = Op(decoder[pc])
- pc++
- case xArg1,
- xArg3,
- xArgAL,
- xArgAX,
- xArgCL,
- xArgCS,
- xArgDS,
- xArgDX,
- xArgEAX,
- xArgEDX,
- xArgES,
- xArgFS,
- xArgGS,
- xArgRAX,
- xArgRDX,
- xArgSS,
- xArgST,
- xArgXMM0:
- inst.Args[narg] = fixedArg[x]
- narg++
- case xArgImm8:
- inst.Args[narg] = Imm(imm8)
- narg++
- case xArgImm8u:
- inst.Args[narg] = Imm(uint8(imm8))
- narg++
- case xArgImm16:
- inst.Args[narg] = Imm(int16(imm))
- narg++
- case xArgImm16u:
- inst.Args[narg] = Imm(uint16(imm))
- narg++
- case xArgImm32:
- inst.Args[narg] = Imm(int32(imm))
- narg++
- case xArgImm64:
- inst.Args[narg] = Imm(imm)
- narg++
- case xArgM,
- xArgM128,
- xArgM256,
- xArgM1428byte,
- xArgM16,
- xArgM16and16,
- xArgM16and32,
- xArgM16and64,
- xArgM16colon16,
- xArgM16colon32,
- xArgM16colon64,
- xArgM16int,
- xArgM2byte,
- xArgM32,
- xArgM32and32,
- xArgM32fp,
- xArgM32int,
- xArgM512byte,
- xArgM64,
- xArgM64fp,
- xArgM64int,
- xArgM8,
- xArgM80bcd,
- xArgM80dec,
- xArgM80fp,
- xArgM94108byte,
- xArgMem:
- if !haveMem {
- inst.Op = 0
- break Decode
- }
- inst.Args[narg] = mem
- inst.MemBytes = int(memBytes[decodeOp(x)])
- if mem.Base == RIP {
- inst.PCRel = displen
- inst.PCRelOff = dispoff
- }
- narg++
- case xArgPtr16colon16:
- inst.Args[narg] = Imm(immc >> 16)
- inst.Args[narg+1] = Imm(immc & (1<<16 - 1))
- narg += 2
- case xArgPtr16colon32:
- inst.Args[narg] = Imm(immc >> 32)
- inst.Args[narg+1] = Imm(immc & (1<<32 - 1))
- narg += 2
- case xArgMoffs8, xArgMoffs16, xArgMoffs32, xArgMoffs64:
- // TODO(rsc): Can address be 64 bits?
- mem = Mem{Disp: int64(immc)}
- if segIndex >= 0 {
- mem.Segment = prefixToSegment(inst.Prefix[segIndex])
- inst.Prefix[segIndex] |= PrefixImplicit
- }
- inst.Args[narg] = mem
- inst.MemBytes = int(memBytes[decodeOp(x)])
- if mem.Base == RIP {
- inst.PCRel = displen
- inst.PCRelOff = dispoff
- }
- narg++
- case xArgYmm1:
- base := baseReg[x]
- index := Reg(regop)
- if inst.Prefix[vexIndex+1]&0x80 == 0 {
- index += 8
- }
- inst.Args[narg] = base + index
- narg++
- case xArgR8, xArgR16, xArgR32, xArgR64, xArgXmm, xArgXmm1, xArgDR0dashDR7:
- base := baseReg[x]
- index := Reg(regop)
- if rex != 0 && base == AL && index >= 4 {
- rexUsed |= PrefixREX
- index -= 4
- base = SPB
- }
- inst.Args[narg] = base + index
- narg++
- case xArgMm, xArgMm1, xArgTR0dashTR7:
- inst.Args[narg] = baseReg[x] + Reg(regop&7)
- narg++
- case xArgCR0dashCR7:
- // AMD documents an extension that the LOCK prefix
- // can be used in place of a REX prefix in order to access
- // CR8 from 32-bit mode. The LOCK prefix is allowed in
- // all modes, provided the corresponding CPUID bit is set.
- if lockIndex >= 0 {
- inst.Prefix[lockIndex] |= PrefixImplicit
- regop += 8
- }
- inst.Args[narg] = CR0 + Reg(regop)
- narg++
- case xArgSreg:
- regop &= 7
- if regop >= 6 {
- inst.Op = 0
- break Decode
- }
- inst.Args[narg] = ES + Reg(regop)
- narg++
- case xArgRmf16, xArgRmf32, xArgRmf64:
- base := baseReg[x]
- index := Reg(modrm & 07)
- if rex&PrefixREXB != 0 {
- rexUsed |= PrefixREXB
- index += 8
- }
- inst.Args[narg] = base + index
- narg++
- case xArgR8op, xArgR16op, xArgR32op, xArgR64op, xArgSTi:
- n := inst.Opcode >> uint(opshift+8) & 07
- base := baseReg[x]
- index := Reg(n)
- if rex&PrefixREXB != 0 && decodeOp(x) != xArgSTi {
- rexUsed |= PrefixREXB
- index += 8
- }
- if rex != 0 && base == AL && index >= 4 {
- rexUsed |= PrefixREX
- index -= 4
- base = SPB
- }
- inst.Args[narg] = base + index
- narg++
- case xArgRM8, xArgRM16, xArgRM32, xArgRM64, xArgR32M16, xArgR32M8, xArgR64M16,
- xArgMmM32, xArgMmM64, xArgMm2M64,
- xArgXmm2M16, xArgXmm2M32, xArgXmm2M64, xArgXmmM64, xArgXmmM128, xArgXmmM32, xArgXmm2M128,
- xArgYmm2M256:
- if haveMem {
- inst.Args[narg] = mem
- inst.MemBytes = int(memBytes[decodeOp(x)])
- if mem.Base == RIP {
- inst.PCRel = displen
- inst.PCRelOff = dispoff
- }
- } else {
- base := baseReg[x]
- index := Reg(rm)
- switch decodeOp(x) {
- case xArgMmM32, xArgMmM64, xArgMm2M64:
- // There are only 8 MMX registers, so these ignore the REX.X bit.
- index &= 7
- case xArgRM8:
- if rex != 0 && index >= 4 {
- rexUsed |= PrefixREX
- index -= 4
- base = SPB
- }
- case xArgYmm2M256:
- if vex == 0xC4 && inst.Prefix[vexIndex+1]&0x40 == 0x40 {
- index += 8
- }
- }
- inst.Args[narg] = base + index
- }
- narg++
- case xArgMm2: // register only; TODO(rsc): Handle with tag modrm_regonly tag
- if haveMem {
- inst.Op = 0
- break Decode
- }
- inst.Args[narg] = baseReg[x] + Reg(rm&7)
- narg++
- case xArgXmm2: // register only; TODO(rsc): Handle with tag modrm_regonly tag
- if haveMem {
- inst.Op = 0
- break Decode
- }
- inst.Args[narg] = baseReg[x] + Reg(rm)
- narg++
- case xArgRel8:
- inst.PCRelOff = immcpos
- inst.PCRel = 1
- inst.Args[narg] = Rel(int8(immc))
- narg++
- case xArgRel16:
- inst.PCRelOff = immcpos
- inst.PCRel = 2
- inst.Args[narg] = Rel(int16(immc))
- narg++
- case xArgRel32:
- inst.PCRelOff = immcpos
- inst.PCRel = 4
- inst.Args[narg] = Rel(int32(immc))
- narg++
- }
- }
- if inst.Op == 0 {
- // Invalid instruction.
- if nprefix > 0 {
- return instPrefix(src[0], mode) // invalid instruction
- }
- return Inst{Len: pos}, ErrUnrecognized
- }
- // Matched! Hooray!
- // 90 decodes as XCHG EAX, EAX but is NOP.
- // 66 90 decodes as XCHG AX, AX and is NOP too.
- // 48 90 decodes as XCHG RAX, RAX and is NOP too.
- // 43 90 decodes as XCHG R8D, EAX and is *not* NOP.
- // F3 90 decodes as REP XCHG EAX, EAX but is PAUSE.
- // It's all too special to handle in the decoding tables, at least for now.
- if inst.Op == XCHG && inst.Opcode>>24 == 0x90 {
- if inst.Args[0] == RAX || inst.Args[0] == EAX || inst.Args[0] == AX {
- inst.Op = NOP
- if dataSizeIndex >= 0 {
- inst.Prefix[dataSizeIndex] &^= PrefixImplicit
- }
- inst.Args[0] = nil
- inst.Args[1] = nil
- }
- if repIndex >= 0 && inst.Prefix[repIndex] == 0xF3 {
- inst.Prefix[repIndex] |= PrefixImplicit
- inst.Op = PAUSE
- inst.Args[0] = nil
- inst.Args[1] = nil
- } else if gnuCompat {
- for i := nprefix - 1; i >= 0; i-- {
- if inst.Prefix[i]&0xFF == 0xF3 {
- inst.Prefix[i] |= PrefixImplicit
- inst.Op = PAUSE
- inst.Args[0] = nil
- inst.Args[1] = nil
- break
- }
- }
- }
- }
- // defaultSeg returns the default segment for an implicit
- // memory reference: the final override if present, or else DS.
- defaultSeg := func() Reg {
- if segIndex >= 0 {
- inst.Prefix[segIndex] |= PrefixImplicit
- return prefixToSegment(inst.Prefix[segIndex])
- }
- return DS
- }
- // Add implicit arguments not present in the tables.
- // Normally we shy away from making implicit arguments explicit,
- // following the Intel manuals, but adding the arguments seems
- // the best way to express the effect of the segment override prefixes.
- // TODO(rsc): Perhaps add these to the tables and
- // create bytecode instructions for them.
- usedAddrSize := false
- switch inst.Op {
- case INSB, INSW, INSD:
- inst.Args[0] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX}
- inst.Args[1] = DX
- usedAddrSize = true
- case OUTSB, OUTSW, OUTSD:
- inst.Args[0] = DX
- inst.Args[1] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + SI - AX}
- usedAddrSize = true
- case MOVSB, MOVSW, MOVSD, MOVSQ:
- inst.Args[0] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX}
- inst.Args[1] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + SI - AX}
- usedAddrSize = true
- case CMPSB, CMPSW, CMPSD, CMPSQ:
- inst.Args[0] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + SI - AX}
- inst.Args[1] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX}
- usedAddrSize = true
- case LODSB, LODSW, LODSD, LODSQ:
- switch inst.Op {
- case LODSB:
- inst.Args[0] = AL
- case LODSW:
- inst.Args[0] = AX
- case LODSD:
- inst.Args[0] = EAX
- case LODSQ:
- inst.Args[0] = RAX
- }
- inst.Args[1] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + SI - AX}
- usedAddrSize = true
- case STOSB, STOSW, STOSD, STOSQ:
- inst.Args[0] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX}
- switch inst.Op {
- case STOSB:
- inst.Args[1] = AL
- case STOSW:
- inst.Args[1] = AX
- case STOSD:
- inst.Args[1] = EAX
- case STOSQ:
- inst.Args[1] = RAX
- }
- usedAddrSize = true
- case SCASB, SCASW, SCASD, SCASQ:
- inst.Args[1] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX}
- switch inst.Op {
- case SCASB:
- inst.Args[0] = AL
- case SCASW:
- inst.Args[0] = AX
- case SCASD:
- inst.Args[0] = EAX
- case SCASQ:
- inst.Args[0] = RAX
- }
- usedAddrSize = true
- case XLATB:
- inst.Args[0] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + BX - AX}
- usedAddrSize = true
- }
- // If we used the address size annotation to construct the
- // argument list, mark that prefix as implicit: it doesn't need
- // to be shown when printing the instruction.
- if haveMem || usedAddrSize {
- if addrSizeIndex >= 0 {
- inst.Prefix[addrSizeIndex] |= PrefixImplicit
- }
- }
- // Similarly, if there's some memory operand, the segment
- // will be shown there and doesn't need to be shown as an
- // explicit prefix.
- if haveMem {
- if segIndex >= 0 {
- inst.Prefix[segIndex] |= PrefixImplicit
- }
- }
- // Branch predict prefixes are overloaded segment prefixes,
- // since segment prefixes don't make sense on conditional jumps.
- // Rewrite final instance to prediction prefix.
- // The set of instructions to which the prefixes apply (other then the
- // Jcc conditional jumps) is not 100% clear from the manuals, but
- // the disassemblers seem to agree about the LOOP and JCXZ instructions,
- // so we'll follow along.
- // TODO(rsc): Perhaps this instruction class should be derived from the CSV.
- if isCondJmp[inst.Op] || isLoop[inst.Op] || inst.Op == JCXZ || inst.Op == JECXZ || inst.Op == JRCXZ {
- PredictLoop:
- for i := nprefix - 1; i >= 0; i-- {
- p := inst.Prefix[i]
- switch p & 0xFF {
- case PrefixCS:
- inst.Prefix[i] = PrefixPN
- break PredictLoop
- case PrefixDS:
- inst.Prefix[i] = PrefixPT
- break PredictLoop
- }
- }
- }
- // The BND prefix is part of the Intel Memory Protection Extensions (MPX).
- // A REPN applied to certain control transfers is a BND prefix to bound
- // the range of possible destinations. There's surprisingly little documentation
- // about this, so we just do what libopcodes and xed agree on.
- // In particular, it's unclear why a REPN applied to LOOP or JCXZ instructions
- // does not turn into a BND.
- // TODO(rsc): Perhaps this instruction class should be derived from the CSV.
- if isCondJmp[inst.Op] || inst.Op == JMP || inst.Op == CALL || inst.Op == RET {
- for i := nprefix - 1; i >= 0; i-- {
- p := inst.Prefix[i]
- if p&^PrefixIgnored == PrefixREPN {
- inst.Prefix[i] = PrefixBND
- break
- }
- }
- }
- // The LOCK prefix only applies to certain instructions, and then only
- // to instances of the instruction with a memory destination.
- // Other uses of LOCK are invalid and cause a processor exception,
- // in contrast to the "just ignore it" spirit applied to all other prefixes.
- // Mark invalid lock prefixes.
- hasLock := false
- if lockIndex >= 0 && inst.Prefix[lockIndex]&PrefixImplicit == 0 {
- switch inst.Op {
- // TODO(rsc): Perhaps this instruction class should be derived from the CSV.
- case ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCHG8B, CMPXCHG16B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, XCHG:
- if isMem(inst.Args[0]) {
- hasLock = true
- break
- }
- fallthrough
- default:
- inst.Prefix[lockIndex] |= PrefixInvalid
- }
- }
- // In certain cases, all of which require a memory destination,
- // the REPN and REP prefixes are interpreted as XACQUIRE and XRELEASE
- // from the Intel Transactional Synchroniation Extensions (TSX).
- //
- // The specific rules are:
- // (1) Any instruction with a valid LOCK prefix can have XACQUIRE or XRELEASE.
- // (2) Any XCHG, which always has an implicit LOCK, can have XACQUIRE or XRELEASE.
- // (3) Any 0x88-, 0x89-, 0xC6-, or 0xC7-opcode MOV can have XRELEASE.
- if isMem(inst.Args[0]) {
- if inst.Op == XCHG {
- hasLock = true
- }
- for i := len(inst.Prefix) - 1; i >= 0; i-- {
- p := inst.Prefix[i] &^ PrefixIgnored
- switch p {
- case PrefixREPN:
- if hasLock {
- inst.Prefix[i] = inst.Prefix[i]&PrefixIgnored | PrefixXACQUIRE
- }
- case PrefixREP:
- if hasLock {
- inst.Prefix[i] = inst.Prefix[i]&PrefixIgnored | PrefixXRELEASE
- }
- if inst.Op == MOV {
- op := (inst.Opcode >> 24) &^ 1
- if op == 0x88 || op == 0xC6 {
- inst.Prefix[i] = inst.Prefix[i]&PrefixIgnored | PrefixXRELEASE
- }
- }
- }
- }
- }
- // If REP is used on a non-REP-able instruction, mark the prefix as ignored.
- if repIndex >= 0 {
- switch inst.Prefix[repIndex] {
- case PrefixREP, PrefixREPN:
- switch inst.Op {
- // According to the manuals, the REP/REPE prefix applies to all of these,
- // while the REPN applies only to some of them. However, both libopcodes
- // and xed show both prefixes explicitly for all instructions, so we do the same.
- // TODO(rsc): Perhaps this instruction class should be derived from the CSV.
- case INSB, INSW, INSD,
- MOVSB, MOVSW, MOVSD, MOVSQ,
- OUTSB, OUTSW, OUTSD,
- LODSB, LODSW, LODSD, LODSQ,
- CMPSB, CMPSW, CMPSD, CMPSQ,
- SCASB, SCASW, SCASD, SCASQ,
- STOSB, STOSW, STOSD, STOSQ:
- // ok
- default:
- inst.Prefix[repIndex] |= PrefixIgnored
- }
- }
- }
- // If REX was present, mark implicit if all the 1 bits were consumed.
- if rexIndex >= 0 {
- if rexUsed != 0 {
- rexUsed |= PrefixREX
- }
- if rex&^rexUsed == 0 {
- inst.Prefix[rexIndex] |= PrefixImplicit
- }
- }
- inst.DataSize = dataMode
- inst.AddrSize = addrMode
- inst.Mode = mode
- inst.Len = pos
- return inst, nil
- }
- var errInternal = errors.New("internal error")
- // addr16 records the eight 16-bit addressing modes.
- var addr16 = [8]Mem{
- {Base: BX, Scale: 1, Index: SI},
- {Base: BX, Scale: 1, Index: DI},
- {Base: BP, Scale: 1, Index: SI},
- {Base: BP, Scale: 1, Index: DI},
- {Base: SI},
- {Base: DI},
- {Base: BP},
- {Base: BX},
- }
- // baseRegForBits returns the base register for a given register size in bits.
- func baseRegForBits(bits int) Reg {
- switch bits {
- case 8:
- return AL
- case 16:
- return AX
- case 32:
- return EAX
- case 64:
- return RAX
- }
- return 0
- }
- // baseReg records the base register for argument types that specify
- // a range of registers indexed by op, regop, or rm.
- var baseReg = [...]Reg{
- xArgDR0dashDR7: DR0,
- xArgMm1: M0,
- xArgMm2: M0,
- xArgMm2M64: M0,
- xArgMm: M0,
- xArgMmM32: M0,
- xArgMmM64: M0,
- xArgR16: AX,
- xArgR16op: AX,
- xArgR32: EAX,
- xArgR32M16: EAX,
- xArgR32M8: EAX,
- xArgR32op: EAX,
- xArgR64: RAX,
- xArgR64M16: RAX,
- xArgR64op: RAX,
- xArgR8: AL,
- xArgR8op: AL,
- xArgRM16: AX,
- xArgRM32: EAX,
- xArgRM64: RAX,
- xArgRM8: AL,
- xArgRmf16: AX,
- xArgRmf32: EAX,
- xArgRmf64: RAX,
- xArgSTi: F0,
- xArgTR0dashTR7: TR0,
- xArgXmm1: X0,
- xArgYmm1: X0,
- xArgXmm2: X0,
- xArgXmm2M128: X0,
- xArgYmm2M256: X0,
- xArgXmm2M16: X0,
- xArgXmm2M32: X0,
- xArgXmm2M64: X0,
- xArgXmm: X0,
- xArgXmmM128: X0,
- xArgXmmM32: X0,
- xArgXmmM64: X0,
- }
- // prefixToSegment returns the segment register
- // corresponding to a particular segment prefix.
- func prefixToSegment(p Prefix) Reg {
- switch p &^ PrefixImplicit {
- case PrefixCS:
- return CS
- case PrefixDS:
- return DS
- case PrefixES:
- return ES
- case PrefixFS:
- return FS
- case PrefixGS:
- return GS
- case PrefixSS:
- return SS
- }
- return 0
- }
- // fixedArg records the fixed arguments corresponding to the given bytecodes.
- var fixedArg = [...]Arg{
- xArg1: Imm(1),
- xArg3: Imm(3),
- xArgAL: AL,
- xArgAX: AX,
- xArgDX: DX,
- xArgEAX: EAX,
- xArgEDX: EDX,
- xArgRAX: RAX,
- xArgRDX: RDX,
- xArgCL: CL,
- xArgCS: CS,
- xArgDS: DS,
- xArgES: ES,
- xArgFS: FS,
- xArgGS: GS,
- xArgSS: SS,
- xArgST: F0,
- xArgXMM0: X0,
- }
- // memBytes records the size of the memory pointed at
- // by a memory argument of the given form.
- var memBytes = [...]int8{
- xArgM128: 128 / 8,
- xArgM256: 256 / 8,
- xArgM16: 16 / 8,
- xArgM16and16: (16 + 16) / 8,
- xArgM16colon16: (16 + 16) / 8,
- xArgM16colon32: (16 + 32) / 8,
- xArgM16int: 16 / 8,
- xArgM2byte: 2,
- xArgM32: 32 / 8,
- xArgM32and32: (32 + 32) / 8,
- xArgM32fp: 32 / 8,
- xArgM32int: 32 / 8,
- xArgM64: 64 / 8,
- xArgM64fp: 64 / 8,
- xArgM64int: 64 / 8,
- xArgMm2M64: 64 / 8,
- xArgMmM32: 32 / 8,
- xArgMmM64: 64 / 8,
- xArgMoffs16: 16 / 8,
- xArgMoffs32: 32 / 8,
- xArgMoffs64: 64 / 8,
- xArgMoffs8: 8 / 8,
- xArgR32M16: 16 / 8,
- xArgR32M8: 8 / 8,
- xArgR64M16: 16 / 8,
- xArgRM16: 16 / 8,
- xArgRM32: 32 / 8,
- xArgRM64: 64 / 8,
- xArgRM8: 8 / 8,
- xArgXmm2M128: 128 / 8,
- xArgYmm2M256: 256 / 8,
- xArgXmm2M16: 16 / 8,
- xArgXmm2M32: 32 / 8,
- xArgXmm2M64: 64 / 8,
- xArgXmm: 128 / 8,
- xArgXmmM128: 128 / 8,
- xArgXmmM32: 32 / 8,
- xArgXmmM64: 64 / 8,
- }
- // isCondJmp records the conditional jumps.
- var isCondJmp = [maxOp + 1]bool{
- JA: true,
- JAE: true,
- JB: true,
- JBE: true,
- JE: true,
- JG: true,
- JGE: true,
- JL: true,
- JLE: true,
- JNE: true,
- JNO: true,
- JNP: true,
- JNS: true,
- JO: true,
- JP: true,
- JS: true,
- }
- // isLoop records the loop operators.
- var isLoop = [maxOp + 1]bool{
- LOOP: true,
- LOOPE: true,
- LOOPNE: true,
- JECXZ: true,
- JRCXZ: true,
- }
|