x86
Version:
Generates x86_64 native code from assembly instructions
123 lines (92 loc) • 4.06 kB
text/typescript
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) {
}
}
}