UNPKG

x86

Version:

Generates x86_64 native code from assembly instructions

123 lines (92 loc) 4.06 kB
import * as code from './code'; import * as o from './operand'; import {Definition, IDefinition} from './def'; import * as i from './instruction'; import * as p from './parts'; import {extend} from './util'; export namespace x64 { const defDefaults: IDefinition = { size: 32, addrSize: 64, }; function insdef(defs: IDefinition) { return new Definition(extend<IDefinition>({}, defDefaults, defs)); } const INC = insdef({op: 0xFF, opreg: 0b000}); const DEC = insdef({op: 0xFF, opreg: 0b001}); export class Instruction extends i.Instruction { prefixRex: p.PrefixRex = null; protected writePrefixes(arr: number[]) { super.writePrefixes(arr); if(this.prefixRex) this.prefixRex.write(arr); } protected needsOperandSizeChange() { return (this.def.size == o.SIZE.DOUBLE) && this.hasRegisterOfSize(o.SIZE.QUAD); } protected createPrefixes() { super.createPrefixes(); if(this.def.mandatoryRex || this.needsOperandSizeChange() || this.hasExtendedRegister()) this.prefixRex = this.createRex(); } protected createRex(): p.PrefixRex { var W = 0, R = 0, X = 0, B = 0; if(this.needsOperandSizeChange()) W = 1; var {dst, src} = this.op; if(dst && dst.reg() && (dst.reg() as o.Register).isExtended()) R = 1; if(src && src.reg() && (src.reg() as o.Register).isExtended()) B = 1; var mem: o.Memory = this.getMemoryOperand(); if(mem) { if(mem.base && mem.base.isExtended()) B = 1; if(mem.index && mem.index.isExtended()) X = 1; } // if(!this.regToRegDirectionRegIsDst) [R, B] = [B, R]; return new p.PrefixRex(W, R, X, B); } } export class Code extends code.Code { protected ClassInstruction = Instruction; mode = code.MODE.LONG; incq(operand: o.Register); incq(operand: o.Memory); incq(operand: o.Register|o.Memory) { return this.insert(INC, this.createOperands(operand)); } decq(operand: o.Register); decq(operand: o.Memory); decq(operand: o.Register|o.Memory) { return this.insert(DEC, this.createOperands(operand)); } } // Generates logically equivalent code to `Instruction` but the actual // bytes of the machine code will likely differ, because `FuzzyInstruction` // picks at random one of the possible instructions when multiple instructions // can perform the same operation. Here are some examples: // // - Bits in `REX` prefix are ignored if they don't have an effect on the instruction. // - Register-to-register `MOV` instruction can be encoded in two different ways. // - Up to four prefixes may be added to instruction, if they are not used, they are ignored. // - There can be many different *no-op* instruction that are used to fill in padding, for example: // // mov %rax, %rax // add $0, %rax export class FuzzyInstruction extends Instruction { protected regToRegDirectionRegIsDst = !(Math.random() > 0.5); protected oneOrZero(): number { return Math.random() > 0.5 ? 1 : 0; } // Randomize unused bits in REX byte. protected createRex(dstreg: o.Register, dstmem: o.Memory, srcreg: o.Register, srcmem: o.Memory) { var rex: p.PrefixRex = super.createRex(dstreg, dstmem, srcreg, srcmem); if(!dstmem && !srcmem) { rex.X = this.oneOrZero(); if(!srcreg) rex.B = this.oneOrZero(); } return rex; } } export class FuzzyCode extends Code { protected ClassInstruction = FuzzyInstruction; nop(size = 1) { } } }