Comparing version 1.0.2 to 1.0.3
228
code.js
@@ -7,26 +7,2 @@ "use strict"; | ||
var util_1 = require('./util'); | ||
var Symbol = (function () { | ||
function Symbol() { | ||
} | ||
return Symbol; | ||
}()); | ||
exports.Symbol = Symbol; | ||
var Block = (function () { | ||
function Block() { | ||
} | ||
return Block; | ||
}()); | ||
exports.Block = Block; | ||
var Section = (function () { | ||
function Section() { | ||
} | ||
return Section; | ||
}()); | ||
exports.Section = Section; | ||
var Assembler = (function () { | ||
function Assembler() { | ||
} | ||
return Assembler; | ||
}()); | ||
exports.Assembler = Assembler; | ||
var Code = (function () { | ||
@@ -39,11 +15,133 @@ function Code(start) { | ||
this.ClassInstruction = i.Instruction; | ||
this.ClassInstructionSet = i.InstructionSet; | ||
this.ClassOperands = o.Operands; | ||
this.AlignExpression = i.Align; | ||
this.littleEndian = true; | ||
this.methods = {}; | ||
this.label(start); | ||
} | ||
Code.prototype.addMethods = function () { | ||
util_1.extend(this, this.methods); | ||
Code.prototype.matchDefinitions = function (mnemonic, ops, opts) { | ||
var matches = this.table.matchDefinitions(mnemonic, ops, opts); | ||
if (!matches.list.length) | ||
throw Error("Could not match operands to instruction definition " + mnemonic + "."); | ||
return matches; | ||
}; | ||
Code.prototype._ = function (mnemonic, operands, options) { | ||
if (operands === void 0) { operands = []; } | ||
if (options === void 0) { options = { size: o.SIZE.ANY }; } | ||
if (typeof mnemonic !== 'string') | ||
throw TypeError('`mnemonic` argument must be a string.'); | ||
var opts; | ||
if (typeof options === 'number') { | ||
opts = { size: options }; | ||
} | ||
else if (typeof options === 'object') { | ||
opts = options; | ||
} | ||
else | ||
throw TypeError("options must be a number or object."); | ||
if (typeof opts.size === 'undefined') | ||
opts.size = o.SIZE.ANY; | ||
if (!(operands instanceof Array)) | ||
operands = [operands]; | ||
var ops = new this.ClassOperands(operands, opts.size); | ||
ops.normalizeExpressionToRelative(); | ||
var matches = this.matchDefinitions(mnemonic, ops, opts); | ||
var iset = new this.ClassInstructionSet(ops, matches, opts); | ||
this.insert(iset); | ||
var insn = iset.pickShortestInstruction(); | ||
if (insn) { | ||
this.replace(insn, iset.index); | ||
return insn; | ||
} | ||
else | ||
return iset; | ||
}; | ||
Code.prototype._8 = function (mnemonic) { | ||
var operands = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
operands[_i - 1] = arguments[_i]; | ||
} | ||
return this._(mnemonic, operands, 8); | ||
}; | ||
Code.prototype._16 = function (mnemonic) { | ||
var operands = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
operands[_i - 1] = arguments[_i]; | ||
} | ||
return this._(mnemonic, operands, 16); | ||
}; | ||
Code.prototype._32 = function (mnemonic) { | ||
var operands = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
operands[_i - 1] = arguments[_i]; | ||
} | ||
return this._(mnemonic, operands, 32); | ||
}; | ||
Code.prototype._64 = function (mnemonic) { | ||
var operands = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
operands[_i - 1] = arguments[_i]; | ||
} | ||
return this._(mnemonic, operands, 64); | ||
}; | ||
Code.prototype._128 = function (mnemonic) { | ||
var operands = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
operands[_i - 1] = arguments[_i]; | ||
} | ||
return this._(mnemonic, operands, 128); | ||
}; | ||
Code.prototype._256 = function (mnemonic) { | ||
var operands = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
operands[_i - 1] = arguments[_i]; | ||
} | ||
return this._(mnemonic, operands, 256); | ||
}; | ||
Code.prototype._512 = function (mnemonic) { | ||
var operands = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
operands[_i - 1] = arguments[_i]; | ||
} | ||
return this._(mnemonic, operands, 512); | ||
}; | ||
Code.prototype.exportMethods = function (useNumbers, sizes, obj) { | ||
var _this = this; | ||
if (useNumbers === void 0) { useNumbers = false; } | ||
if (sizes === void 0) { sizes = [o.SIZE.B, o.SIZE.W, o.SIZE.D, o.SIZE.Q]; } | ||
if (obj === void 0) { obj = {}; } | ||
var _loop_1 = function(mnemonic) { | ||
obj[mnemonic] = function () { | ||
var operands = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
operands[_i - 0] = arguments[_i]; | ||
} | ||
return _this._(mnemonic, operands); | ||
}; | ||
var _loop_2 = function(size) { | ||
var method = useNumbers ? mnemonic + size : mnemonic + o.SIZE[size].toLowerCase(); | ||
obj[method] = function () { | ||
var operands = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
operands[_i - 0] = arguments[_i]; | ||
} | ||
return _this._(mnemonic, operands, size); | ||
}; | ||
}; | ||
for (var _i = 0, sizes_1 = sizes; _i < sizes_1.length; _i++) { | ||
var size = sizes_1[_i]; | ||
_loop_2(size); | ||
} | ||
}; | ||
for (var mnemonic in this.table.table) { | ||
_loop_1(mnemonic); | ||
} | ||
return obj; | ||
}; | ||
Code.prototype.addMethods = function (useNumbers, sizes, obj) { | ||
if (useNumbers === void 0) { useNumbers = false; } | ||
if (sizes === void 0) { sizes = [o.SIZE.B, o.SIZE.W, o.SIZE.D, o.SIZE.Q]; } | ||
if (obj === void 0) { obj = this.exportMethods(useNumbers, sizes); } | ||
util_1.extend(this, obj); | ||
}; | ||
Code.prototype.getStartLabel = function () { | ||
@@ -65,35 +163,2 @@ return this.expr[0]; | ||
}; | ||
Code.prototype.compile = function () { | ||
this.do2ndPass(); | ||
return this.do3rdPass(); | ||
}; | ||
Code.prototype.do2ndPass = function () { | ||
var last = this.expr[this.expr.length - 1]; | ||
var all_offsets_known = last.offset >= 0; | ||
var all_sizes_known = last.bytes() >= 0; | ||
if (all_offsets_known && all_sizes_known) | ||
return; | ||
var prev = this.expr[0]; | ||
prev.offset = 0; | ||
for (var j = 1; j < this.expr.length; j++) { | ||
var ins = this.expr[j]; | ||
if (ins instanceof i.ExpressionVolatile) { | ||
var fixed = ins.getFixedSizeExpression(); | ||
this.replace(fixed, ins.index); | ||
ins = fixed; | ||
} | ||
ins.calcOffset(); | ||
prev = ins; | ||
} | ||
}; | ||
Code.prototype.do3rdPass = function () { | ||
var code = []; | ||
for (var _i = 0, _a = this.expr; _i < _a.length; _i++) { | ||
var ins = _a[_i]; | ||
if (ins instanceof i.ExpressionVariable) | ||
ins.evaluate(); | ||
code = ins.write(code); | ||
} | ||
return code; | ||
}; | ||
Code.prototype.lbl = function (name) { | ||
@@ -207,4 +272,17 @@ return new instruction_1.Label(name); | ||
if (littleEndian === void 0) { littleEndian = this.littleEndian; } | ||
return this.db(instruction_1.Data.quadsToOctets(quads, littleEndian)); | ||
var tnums; | ||
if (typeof quads === 'number') | ||
tnums = [quads]; | ||
else | ||
tnums = quads; | ||
for (var j = 0; j < tnums.length; j++) { | ||
var num = tnums[j]; | ||
if (typeof num === 'number') | ||
tnums[j] = [util_1.UInt64.lo(num), util_1.UInt64.hi(num)]; | ||
} | ||
return this.db(instruction_1.Data.quadsToOctets(tnums, littleEndian)); | ||
}; | ||
Code.prototype.tpl = function (Clazz, args) { | ||
return this.insert(new Clazz(args)); | ||
}; | ||
Code.prototype.resb = function (length) { | ||
@@ -270,2 +348,30 @@ var data = new instruction_1.DataUninitialized(length); | ||
}; | ||
Code.prototype.compile = function () { | ||
this.do2ndPass(); | ||
return this.do3rdPass(); | ||
}; | ||
Code.prototype.do2ndPass = function () { | ||
var prev = this.expr[0]; | ||
prev.offset = 0; | ||
for (var j = 1; j < this.expr.length; j++) { | ||
var ins = this.expr[j]; | ||
if (ins instanceof i.ExpressionVolatile) { | ||
var fixed = ins.getFixedSizeExpression(); | ||
this.replace(fixed, ins.index); | ||
ins = fixed; | ||
} | ||
ins.calcOffset(); | ||
prev = ins; | ||
} | ||
}; | ||
Code.prototype.do3rdPass = function () { | ||
var code = []; | ||
for (var _i = 0, _a = this.expr; _i < _a.length; _i++) { | ||
var ins = _a[_i]; | ||
if (ins instanceof i.ExpressionVariable) | ||
ins.evaluate(); | ||
code = ins.write(code); | ||
} | ||
return code; | ||
}; | ||
Code.prototype.toString = function (lineNumbers, hex) { | ||
@@ -272,0 +378,0 @@ if (lineNumbers === void 0) { lineNumbers = true; } |
245
code.ts
@@ -9,14 +9,7 @@ import {SIZE, number64, Tnumber, Operands} from './operand'; | ||
export class Symbol {} | ||
export class Block {} | ||
export class Section {} | ||
export class Assembler {} | ||
export interface IInstructionOptions { | ||
size: o.SIZE; | ||
} | ||
// Expressions are compiled in 3 passes: | ||
// | ||
// - *1st pass* -- maximum offset `maxOffset` for each expression is computed, some expression might not know | ||
// their size jet, not all expressions are known, future references. First pass is when user performs insertion of commands. | ||
// - *2nd pass* -- all expressions known now, each expression should pick its right size, exact `offset` is computed for each expression. | ||
// - *3rd pass* -- now we know exact `offset` of each expression, so in this pass we fill in the addresses. | ||
export class Code { | ||
@@ -29,2 +22,3 @@ expr: Expression[] = []; | ||
ClassInstruction = i.Instruction; | ||
ClassInstructionSet = i.InstructionSet; | ||
ClassOperands = o.Operands; | ||
@@ -35,6 +29,3 @@ AlignExpression = i.Align; | ||
// Collection of all assembly instructions: mov, push, ret, retq, etc... | ||
// When needed `addMethods()` adds these funcitons to the `Code` object, | ||
// some segments, for example, data segment may not need these methods. | ||
methods: any = {}; | ||
table: d.DefTable; | ||
@@ -45,85 +36,103 @@ constructor(start: string = 'start') { | ||
addMethods() { | ||
extend(this, this.methods); | ||
protected matchDefinitions(mnemonic: string, ops: o.Operands, opts: IInstructionOptions): d.DefMatchList { | ||
var matches = this.table.matchDefinitions(mnemonic, ops, opts); | ||
if(!matches.list.length) | ||
throw Error(`Could not match operands to instruction definition ${mnemonic}.`); | ||
return matches; | ||
} | ||
getStartLabel(): Label { | ||
return this.expr[0] as Label; | ||
_(mnemonic: string, operands: o.TUiOperand|o.TUiOperand[] = [], options: o.SIZE|IInstructionOptions|any = {size: o.SIZE.ANY}): i.Instruction|i.InstructionSet { | ||
if(typeof mnemonic !== 'string') throw TypeError('`mnemonic` argument must be a string.'); | ||
var opts: IInstructionOptions; | ||
if(typeof options === 'number') { | ||
opts = {size: options as number}; | ||
} else if(typeof options === 'object') { | ||
opts = options; | ||
} else | ||
throw TypeError(`options must be a number or object.`); | ||
if(typeof opts.size === 'undefined') opts.size = o.SIZE.ANY; | ||
if(!(operands instanceof Array)) operands = [operands] as o.TUiOperand[]; | ||
var ops = new this.ClassOperands(operands as o.TUiOperand[], opts.size); | ||
ops.normalizeExpressionToRelative(); | ||
var matches = this.matchDefinitions(mnemonic, ops, opts); | ||
var iset = new this.ClassInstructionSet(ops, matches, opts); | ||
this.insert(iset); | ||
var insn = iset.pickShortestInstruction(); | ||
if(insn) { | ||
this.replace(insn, iset.index); | ||
return insn; | ||
} else | ||
return iset; | ||
} | ||
insert(expr: Expression): Expression { | ||
this.replace(expr, this.expr.length); | ||
expr.build(); | ||
return expr; | ||
// expr.index = index; | ||
// expr.bind(this); | ||
// this.expr[index] = expr; | ||
// expr.calcOffsetMaxAndOffset(); // 1st pass | ||
// expr.build(); | ||
// return expr; | ||
_8(mnemonic: string, ...operands: o.TUiOperand[]) { | ||
return this._(mnemonic, operands, 8); | ||
} | ||
replace(expr: Expression, index = this.expr.length): Expression { | ||
expr.index = index; | ||
expr.bind(this); | ||
this.expr[index] = expr; | ||
expr.calcOffsetMaxAndOffset(); // 1st pass | ||
return expr; | ||
_16(mnemonic: string, ...operands: o.TUiOperand[]) { | ||
return this._(mnemonic, operands, 16); | ||
} | ||
compile(): number[] { | ||
// 1st pass is performed as instructions are `insert`ed, `.offsetMax` is calculated, and possibly `.offset`. | ||
_32(mnemonic: string, ...operands: o.TUiOperand[]) { | ||
return this._(mnemonic, operands, 32); | ||
} | ||
// Instructions without size can now determine their size based on `.offsetMax` and | ||
// calculate their real `.offset`. | ||
this.do2ndPass(); | ||
_64(mnemonic: string, ...operands: o.TUiOperand[]) { | ||
return this._(mnemonic, operands, 64); | ||
} | ||
// Offsets are now know, here we evaluate references. | ||
return this.do3rdPass(); | ||
_128(mnemonic: string, ...operands: o.TUiOperand[]) { | ||
return this._(mnemonic, operands, 128); | ||
} | ||
do2ndPass() { | ||
var last = this.expr[this.expr.length - 1]; | ||
var all_offsets_known = last.offset >= 0; | ||
_256(mnemonic: string, ...operands: o.TUiOperand[]) { | ||
return this._(mnemonic, operands, 256); | ||
} | ||
// Edge case when only the last Expression has variable size. | ||
var all_sizes_known = last.bytes() >= 0; | ||
_512(mnemonic: string, ...operands: o.TUiOperand[]) { | ||
return this._(mnemonic, operands, 512); | ||
} | ||
if(all_offsets_known && all_sizes_known) return; // Skip 2nd pass. | ||
var prev = this.expr[0]; | ||
prev.offset = 0; | ||
for(var j = 1; j < this.expr.length; j++) { | ||
var ins = this.expr[j]; | ||
if(ins instanceof i.ExpressionVolatile) { | ||
var fixed = (ins as i.ExpressionVolatile).getFixedSizeExpression(); | ||
this.replace(fixed, ins.index); | ||
ins = fixed; | ||
// (ins as i.ExpressionVolatile).determineSize(); | ||
exportMethods(useNumbers = false, sizes = [o.SIZE.B, o.SIZE.W, o.SIZE.D, o.SIZE.Q], obj: any = {}) { | ||
for(let mnemonic in this.table.table) { | ||
obj[mnemonic] = (...operands: o.TUiOperand[]) => { | ||
return this._(mnemonic, operands); | ||
}; | ||
for(let size of sizes) { | ||
let method = useNumbers ? mnemonic + size : mnemonic + o.SIZE[size].toLowerCase(); | ||
obj[method] = (...operands: o.TUiOperand[]) => { | ||
return this._(mnemonic, operands, size); | ||
}; | ||
} | ||
} | ||
return obj; | ||
} | ||
// var bytes = prev.bytes(); | ||
// if(bytes === i.SIZE_UNKNOWN) | ||
// throw Error(`Instruction [${j}] does not have size.`); | ||
// ins.offset = prev.offset + bytes; | ||
// Need to call method, as `InstructionSet` contains multiple `Instruction`s, | ||
// that all need offset updated of picked instruction. | ||
ins.calcOffset(); | ||
addMethods(useNumbers = false, sizes = [o.SIZE.B, o.SIZE.W, o.SIZE.D, o.SIZE.Q], obj = this.exportMethods(useNumbers, sizes)) { | ||
extend(this, obj); | ||
} | ||
prev = ins; | ||
} | ||
getStartLabel(): Label { | ||
return this.expr[0] as Label; | ||
} | ||
do3rdPass() { | ||
var code: number[] = []; | ||
for(var ins of this.expr) { | ||
if(ins instanceof i.ExpressionVariable) | ||
(ins as i.ExpressionVariable).evaluate(); | ||
code = ins.write(code); // 3rd pass | ||
} | ||
return code; | ||
insert(expr: Expression): Expression { | ||
this.replace(expr, this.expr.length); | ||
expr.build(); | ||
return expr; | ||
} | ||
replace(expr: Expression, index = this.expr.length): Expression { | ||
expr.index = index; | ||
expr.bind(this); | ||
this.expr[index] = expr; | ||
expr.calcOffsetMaxAndOffset(); // 1st pass | ||
return expr; | ||
} | ||
lbl(name: string): Label { | ||
@@ -154,3 +163,3 @@ return new Label(name); | ||
// DB volatile | ||
// DB variable | ||
dbv(ops: o.Operands, littleEndian: boolean): i.DataVariable; | ||
@@ -188,3 +197,3 @@ dbv(expr: i.Expression, size: number, littleEndian: boolean): i.DataVariable; | ||
db(num: number, times: number): Data; | ||
db(num: number, times?: number): Data; | ||
db(str: string, encoding?: string): Data; | ||
@@ -234,6 +243,19 @@ db(octets: number[]): Data; | ||
dq(quads: Tnumber[], littleEndian = this.littleEndian): Data { | ||
return this.db(Data.quadsToOctets(quads, littleEndian)); | ||
dq(quads: Tnumber|Tnumber[], littleEndian = this.littleEndian): Data { | ||
var tnums: Tnumber[]; | ||
if(typeof quads === 'number') tnums = [quads]; | ||
else tnums = quads as Tnumber[]; | ||
for(var j = 0; j < tnums.length; j++) { | ||
var num = tnums[j]; | ||
if(typeof num === 'number') tnums[j] = [UInt64.lo(num), UInt64.hi(num)]; | ||
} | ||
return this.db(Data.quadsToOctets(tnums, littleEndian)); | ||
} | ||
tpl(Clazz: typeof i.Template, args?: any[]): i.Expression { | ||
return this.insert(new Clazz(args)); | ||
} | ||
resb(length: number): DataUninitialized { | ||
@@ -310,2 +332,65 @@ var data = new DataUninitialized(length); | ||
// Expressions are compiled in 3 passes: | ||
// | ||
// - *1st pass* -- maximum offset `maxOffset` for each expression is computed, some expression might not know | ||
// their size jet, not all expressions are known, future references. First pass is when user performs insertion of commands. | ||
// - *2nd pass* -- all expressions known now, each expression should pick its right size, exact `offset` is computed for each expression. | ||
// - *3rd pass* -- now we know exact `offset` of each expression, so in this pass we fill in the addresses. | ||
compile(): number[] { | ||
// 1st pass is performed as instructions are `insert`ed, `.offsetMax` is calculated, and possibly `.offset`. | ||
// Instructions without size can now determine their size based on `.offsetMax` and | ||
// calculate their real `.offset`. | ||
this.do2ndPass(); | ||
// Offsets are now know, here we evaluate references. | ||
return this.do3rdPass(); | ||
} | ||
do2ndPass() { | ||
// We probably cannot skip this 2nd pass, as instructions might change their sizes after inserted, | ||
// for example, when `.lock()` prefix is added. | ||
// var last = this.expr[this.expr.length - 1]; | ||
// var all_offsets_known = last.offset >= 0; | ||
// | ||
// Edge case when only the last Expression has variable size. | ||
// var all_sizes_known = last.bytes() >= 0; | ||
// | ||
// if(all_offsets_known && all_sizes_known) return; // Skip 2nd pass. | ||
var prev = this.expr[0]; | ||
prev.offset = 0; | ||
for(var j = 1; j < this.expr.length; j++) { | ||
var ins = this.expr[j]; | ||
if(ins instanceof i.ExpressionVolatile) { | ||
var fixed = (ins as i.ExpressionVolatile).getFixedSizeExpression(); | ||
this.replace(fixed, ins.index); | ||
ins = fixed; | ||
// (ins as i.ExpressionVolatile).determineSize(); | ||
} | ||
// var bytes = prev.bytes(); | ||
// if(bytes === i.SIZE_UNKNOWN) | ||
// throw Error(`Instruction [${j}] does not have size.`); | ||
// ins.offset = prev.offset + bytes; | ||
// Need to call method, as `InstructionSet` contains multiple `Instruction`s, | ||
// that all need offset updated of picked instruction. | ||
ins.calcOffset(); | ||
prev = ins; | ||
} | ||
} | ||
do3rdPass() { | ||
var code: number[] = []; | ||
for(var ins of this.expr) { | ||
if(ins instanceof i.ExpressionVariable) | ||
(ins as i.ExpressionVariable).evaluate(); | ||
code = ins.write(code); // 3rd pass | ||
} | ||
return code; | ||
} | ||
toString(lineNumbers = true, hex = true) { | ||
@@ -312,0 +397,0 @@ var lines = []; |
102
def.js
@@ -111,2 +111,6 @@ "use strict"; | ||
Def.prototype.toStringOperand = function (operand) { | ||
if (typeof operand === 'number') | ||
return operand; | ||
if (typeof operand === 'string') | ||
return operand; | ||
if (operand instanceof o.Operand) | ||
@@ -137,2 +141,30 @@ return operand.toString(); | ||
}; | ||
Def.prototype.toJsonOperands = function () { | ||
var ops = []; | ||
for (var _i = 0, _a = this.operands; _i < _a.length; _i++) { | ||
var op_tpl = _a[_i]; | ||
var op_out = []; | ||
for (var _b = 0, op_tpl_1 = op_tpl; _b < op_tpl_1.length; _b++) { | ||
var op = op_tpl_1[_b]; | ||
op_out.push(this.toStringOperand(op)); | ||
} | ||
if (op_out.length > 1) | ||
ops.push(op_out); | ||
else | ||
ops.push(op_out[0]); | ||
} | ||
return ops; | ||
}; | ||
Def.prototype.toJson = function () { | ||
var json = { | ||
opcode: this.opcode, | ||
opcodeHex: this.opcode.toString(16), | ||
}; | ||
if (this.operandSize) | ||
json.operandSize = this.operandSize; | ||
var ops = this.toJsonOperands(); | ||
if (ops.length) | ||
json.operands = ops; | ||
return json; | ||
}; | ||
Def.prototype.toString = function () { | ||
@@ -153,3 +185,6 @@ var opcode = ' ' + (new o.Constant(this.opcode, false)).toString(); | ||
operandsstr = ' ' + operands.join(','); | ||
return this.getMnemonic() + opcode + operandsstr; | ||
var size = ''; | ||
if (this.operandSize > 0) | ||
size = ' ' + this.operandSize + '-bit'; | ||
return this.mnemonic + size + opcode + operandsstr; | ||
}; | ||
@@ -190,2 +225,13 @@ return Def; | ||
}; | ||
DefGroup.prototype.toJson = function () { | ||
var instructions = []; | ||
for (var _i = 0, _a = this.defs; _i < _a.length; _i++) { | ||
var def = _a[_i]; | ||
instructions.push(def.toJson()); | ||
} | ||
return { | ||
mnemonic: this.mnemonic, | ||
definitions: instructions, | ||
}; | ||
}; | ||
DefGroup.prototype.toString = function () { | ||
@@ -203,14 +249,42 @@ var defs = []; | ||
var DefTable = (function () { | ||
function DefTable() { | ||
function DefTable(table, defaults) { | ||
this.DefGroupClass = DefGroup; | ||
this.groups = {}; | ||
this.table = table; | ||
this.defaults = defaults; | ||
} | ||
DefTable.prototype.create = function (table, defaults) { | ||
for (var mnemonic in table) { | ||
var group = new this.DefGroupClass(this, mnemonic); | ||
group.createDefinitions(table[mnemonic], defaults); | ||
this.groups[mnemonic] = group; | ||
DefTable.prototype.getGroup = function (mnemonic) { | ||
if (!this.groups[mnemonic]) { | ||
this.createGroup(mnemonic); | ||
} | ||
return this; | ||
return this.groups[mnemonic]; | ||
}; | ||
DefTable.prototype.createGroup = function (mnemonic) { | ||
var group = new this.DefGroupClass(this, mnemonic); | ||
var definitions = this.table[mnemonic]; | ||
if ((definitions.length === 1) && (typeof definitions[0] === 'string')) | ||
definitions = this.table[definitions[0]]; | ||
group.createDefinitions(definitions, this.defaults); | ||
this.groups[mnemonic] = group; | ||
}; | ||
DefTable.prototype.createAll = function () { | ||
for (var mnemonic in this.table) { | ||
this.getGroup(mnemonic); | ||
} | ||
}; | ||
DefTable.prototype.matchDefinitions = function (mnemonic, ops, opts) { | ||
var group = this.getGroup(mnemonic); | ||
if (!group) | ||
throw Error("No such mnemonic \"" + mnemonic + "\"."); | ||
var matches = new DefMatchList; | ||
matches.matchAll(group.defs, ops, opts); | ||
return matches; | ||
}; | ||
DefTable.prototype.toJson = function () { | ||
var json = {}; | ||
for (var group_name in this.groups) { | ||
json[group_name] = this.groups[group_name].toJson(); | ||
} | ||
return json; | ||
}; | ||
DefTable.prototype.toString = function () { | ||
@@ -238,5 +312,11 @@ var groups = []; | ||
} | ||
DefMatchList.prototype.match = function (def, ops) { | ||
DefMatchList.prototype.match = function (def, ops, opts) { | ||
if (opts.size !== o.SIZE.ANY) { | ||
if (opts.size !== def.operandSize) | ||
return; | ||
} | ||
var tpl = def.matchOperands(ops); | ||
if (tpl) { | ||
if (def.vex && ops.has5bitRegister()) | ||
return; | ||
var match = new DefMatch; | ||
@@ -248,6 +328,6 @@ match.def = def; | ||
}; | ||
DefMatchList.prototype.matchAll = function (defs, ops) { | ||
DefMatchList.prototype.matchAll = function (defs, ops, opts) { | ||
for (var _i = 0, defs_1 = defs; _i < defs_1.length; _i++) { | ||
var def = defs_1[_i]; | ||
this.match(def, ops); | ||
this.match(def, ops, opts); | ||
} | ||
@@ -254,0 +334,0 @@ }; |
126
def.ts
import * as o from './operand'; | ||
import * as t from './table'; | ||
import {extend} from './util'; | ||
import * as c from './code'; | ||
type TInstructionOptions = c.IInstructionOptions; | ||
export class Def { | ||
@@ -108,2 +111,4 @@ group: DefGroup = null; | ||
toStringOperand(operand) { | ||
if(typeof operand === 'number') return operand; | ||
if(typeof operand === 'string') return operand; | ||
if(operand instanceof o.Operand) return operand.toString(); | ||
@@ -126,2 +131,30 @@ else if(typeof operand === 'function') { | ||
toJsonOperands() { | ||
var ops = []; | ||
for(var op_tpl of this.operands) { | ||
var op_out = []; | ||
for(var op of op_tpl) { | ||
op_out.push(this.toStringOperand(op)); | ||
} | ||
if(op_out.length > 1) ops.push(op_out); | ||
else ops.push(op_out[0]); | ||
} | ||
return ops; | ||
} | ||
toJson() { | ||
var json: any = { | ||
opcode: this.opcode, | ||
opcodeHex: this.opcode.toString(16), | ||
// mnemonic: this.mnemonic, | ||
}; | ||
if(this.operandSize) json.operandSize = this.operandSize; | ||
var ops = this.toJsonOperands(); | ||
if(ops.length) json.operands = ops; | ||
return json; | ||
} | ||
toString() { | ||
@@ -141,3 +174,6 @@ var opcode = ' ' + (new o.Constant(this.opcode, false)).toString(); | ||
return this.getMnemonic() + opcode + operandsstr; | ||
var size = ''; | ||
if(this.operandSize > 0) size = ' ' + this.operandSize + '-bit'; | ||
return this.mnemonic + size + opcode + operandsstr; | ||
} | ||
@@ -186,2 +222,13 @@ } | ||
toJson(): any { | ||
var instructions = []; | ||
for(var def of this.defs) { | ||
instructions.push(def.toJson()); | ||
} | ||
return { | ||
mnemonic: this.mnemonic, | ||
definitions: instructions, | ||
}; | ||
} | ||
toString() { | ||
@@ -203,11 +250,62 @@ var defs = []; | ||
create(table: t.TableDefinition, defaults: t.Definition): this { | ||
for(var mnemonic in table) { | ||
var group = new this.DefGroupClass(this, mnemonic); | ||
group.createDefinitions(table[mnemonic], defaults); | ||
this.groups[mnemonic] = group; | ||
table: t.TableDefinition; | ||
defaults: t.Definition; | ||
constructor(table: t.TableDefinition, defaults: t.Definition) { | ||
this.table = table; | ||
this.defaults = defaults; | ||
} | ||
getGroup(mnemonic: string): DefGroup { | ||
if(!this.groups[mnemonic]) { | ||
this.createGroup(mnemonic); | ||
} | ||
return this; | ||
return this.groups[mnemonic]; | ||
} | ||
protected createGroup(mnemonic: string) { | ||
var group = new this.DefGroupClass(this, mnemonic); | ||
var definitions = this.table[mnemonic]; | ||
if((definitions.length === 1) && (typeof definitions[0] === 'string')) | ||
definitions = this.table[definitions[0]]; | ||
group.createDefinitions(definitions, this.defaults); | ||
this.groups[mnemonic] = group; | ||
} | ||
createAll() { | ||
for(var mnemonic in this.table) { | ||
this.getGroup(mnemonic); | ||
} | ||
} | ||
matchDefinitions(mnemonic: string, ops: o.Operands, opts: TInstructionOptions): DefMatchList { | ||
var group = this.getGroup(mnemonic); | ||
if(!group) | ||
throw Error(`No such mnemonic "${mnemonic}".`); | ||
var matches = new DefMatchList; | ||
matches.matchAll(group.defs, ops, opts); | ||
return matches; | ||
} | ||
// create(table: t.TableDefinition, defaults: t.Definition): this { | ||
// for(var mnemonic in table) { | ||
// var group = new this.DefGroupClass(this, mnemonic); | ||
// group.createDefinitions(table[mnemonic], defaults); | ||
// this.groups[mnemonic] = group; | ||
// } | ||
// return this; | ||
// } | ||
toJson() { | ||
var json: any = {}; | ||
for(var group_name in this.groups) { | ||
json[group_name] = this.groups[group_name].toJson(); | ||
} | ||
return json; | ||
} | ||
toString() { | ||
@@ -232,5 +330,13 @@ var groups = []; | ||
match(def: Def, ops: o.Operands) { | ||
match(def: Def, ops: o.Operands, opts: TInstructionOptions) { | ||
if(opts.size !== o.SIZE.ANY) { | ||
if(opts.size !== def.operandSize) return; | ||
} | ||
var tpl = def.matchOperands(ops); | ||
if(tpl) { | ||
// If registers are 5-bit wide, we can encode them only with EVEX, not VEX. | ||
if((def as any).vex && ops.has5bitRegister()) return; | ||
var match = new DefMatch; | ||
@@ -243,5 +349,5 @@ match.def = def; | ||
matchAll(defs: Def[], ops: o.Operands) { | ||
for(var def of defs) this.match(def, ops); | ||
matchAll(defs: Def[], ops: o.Operands, opts: TInstructionOptions) { | ||
for(var def of defs) this.match(def, ops, opts); | ||
} | ||
} |
@@ -276,2 +276,23 @@ "use strict"; | ||
exports.Data = Data; | ||
var Template = (function (_super) { | ||
__extends(Template, _super); | ||
function Template(args) { | ||
if (args === void 0) { args = []; } | ||
_super.call(this); | ||
this.name = 'template'; | ||
this.args = args; | ||
} | ||
Template.prototype.toString = function (margin, comment) { | ||
if (margin === void 0) { margin = ' '; } | ||
if (comment === void 0) { comment = true; } | ||
var expression = this.name + this.args.join(', '); | ||
var cmt = ''; | ||
if (comment) { | ||
cmt = this.bytes() + " bytes"; | ||
} | ||
return this.formatToString(margin, expression, cmt); | ||
}; | ||
return Template; | ||
}(Data)); | ||
exports.Template = Template; | ||
var ExpressionVariable = (function (_super) { | ||
@@ -446,2 +467,3 @@ __extends(ExpressionVariable, _super); | ||
this.def = null; | ||
this.opts = null; | ||
} | ||
@@ -455,8 +477,3 @@ Instruction.prototype.build = function () { | ||
}; | ||
Instruction.prototype.getFixedSizeExpression = function () { | ||
return this; | ||
}; | ||
Instruction.prototype.toString = function (margin, comment) { | ||
if (margin === void 0) { margin = ' '; } | ||
if (comment === void 0) { comment = true; } | ||
Instruction.prototype.toStringExpression = function () { | ||
var parts = []; | ||
@@ -468,12 +485,16 @@ parts.push(this.def.getMnemonic()); | ||
parts.push(this.ops.toString()); | ||
var expression = margin + parts.join(' '); | ||
return parts.join(' '); | ||
}; | ||
Instruction.prototype.toString = function (margin, comment) { | ||
if (margin === void 0) { margin = ' '; } | ||
if (comment === void 0) { comment = true; } | ||
var expression = margin + this.toStringExpression(); | ||
var cmt = ''; | ||
if (comment) { | ||
var spaces = (new Array(1 + Math.max(0, Expression.commentColls - expression.length))).join(' '); | ||
var octets = this.write([]).map(function (byte) { | ||
return byte <= 0xF ? '0' + byte.toString(16).toUpperCase() : byte.toString(16).toUpperCase(); | ||
}); | ||
cmt = spaces + ("; " + this.formatOffset() + " 0x") + octets.join(', 0x'); | ||
cmt = "0x" + octets.join(', 0x') + (" " + this.bytes() + " bytes"); | ||
} | ||
return expression + cmt; | ||
return this.formatToString(margin, expression, cmt); | ||
}; | ||
@@ -485,3 +506,3 @@ return Instruction; | ||
__extends(InstructionSet, _super); | ||
function InstructionSet(ops, matches) { | ||
function InstructionSet(ops, matches, opts) { | ||
_super.call(this, ops); | ||
@@ -491,3 +512,5 @@ this.matches = null; | ||
this.picked = -1; | ||
this.opts = null; | ||
this.matches = matches; | ||
this.opts = opts; | ||
} | ||
@@ -637,2 +660,3 @@ InstructionSet.prototype.write = function (arr) { | ||
insn.def = match.def; | ||
insn.opts = this.opts; | ||
var ops = this.createInstructionOperands(insn, match.opTpl); | ||
@@ -639,0 +663,0 @@ ops.validateSize(); |
@@ -307,3 +307,23 @@ import {Def, DefMatchList} from './def'; | ||
// A pre-filled template with some binary data. | ||
export class Template extends Data { | ||
name = 'template'; | ||
args: any[]; | ||
constructor(args = []) { | ||
super(); | ||
this.args = args; | ||
} | ||
toString(margin = ' ', comment = true) { | ||
var expression = this.name + this.args.join(', '); | ||
var cmt = ''; | ||
if(comment) { | ||
cmt = `${this.bytes()} bytes`; | ||
} | ||
return this.formatToString(margin, expression, cmt); | ||
} | ||
} | ||
// Expressions that have operands, operands might reference (in case of `Relative`) other expressions, which | ||
@@ -432,3 +452,3 @@ // have not been insert into code yet, so we might not know the how those operands evaluate on first two passes. | ||
// If `Expression` can generate different size machine code this method forces it to pick one. | ||
getFixedSizeExpression() { | ||
getFixedSizeExpression(): Expression { | ||
return this; | ||
@@ -512,2 +532,3 @@ } | ||
def: Def = null; // Definition on how to construct this instruction. | ||
opts: c.IInstructionOptions = null; // Instruction options provided by user. | ||
@@ -523,8 +544,3 @@ build(): this { | ||
getFixedSizeExpression() { | ||
return this; | ||
} | ||
toString(margin = ' ', comment = true) { | ||
protected toStringExpression() { | ||
var parts = []; | ||
@@ -534,14 +550,16 @@ parts.push(this.def.getMnemonic()); | ||
if(this.ops.list.length) parts.push(this.ops.toString()); | ||
var expression = margin + parts.join(' '); | ||
return parts.join(' '); | ||
} | ||
toString(margin = ' ', comment = true) { | ||
var expression = margin + this.toStringExpression(); | ||
var cmt = ''; | ||
if(comment) { | ||
var spaces = (new Array(1 + Math.max(0, Expression.commentColls - expression.length))).join(' '); | ||
var octets = this.write([]).map(function(byte) { | ||
return byte <= 0xF ? '0' + byte.toString(16).toUpperCase() : byte.toString(16).toUpperCase(); | ||
}); | ||
cmt = spaces + `; ${this.formatOffset()} 0x` + octets.join(', 0x');// + ' / ' + this.def.toString(); | ||
cmt = `0x` + octets.join(', 0x') + ` ${this.bytes()} bytes`;// + ' / ' + this.def.toString(); | ||
} | ||
return expression + cmt; | ||
return this.formatToString(margin, expression, cmt); | ||
} | ||
@@ -557,6 +575,8 @@ } | ||
picked: number = -1; // Index of instruction that was eventually chosen. | ||
opts: c.IInstructionOptions = null; // Instruction options provided by user. | ||
constructor(ops: o.Operands, matches: DefMatchList) { | ||
constructor(ops: o.Operands, matches: DefMatchList, opts: c.IInstructionOptions) { | ||
super(ops); | ||
this.matches = matches; | ||
this.opts = opts; | ||
} | ||
@@ -715,2 +735,3 @@ | ||
insn.def = match.def; | ||
insn.opts = this.opts; | ||
@@ -720,2 +741,3 @@ var ops = this.createInstructionOperands(insn, match.opTpl); | ||
insn.ops = ops; | ||
insn.bind(this.code); | ||
@@ -722,0 +744,0 @@ insn.build(); |
@@ -20,2 +20,6 @@ "use strict"; | ||
SIZE[SIZE["I"] = 512] = "I"; | ||
SIZE[SIZE["X"] = 128] = "X"; | ||
SIZE[SIZE["Y"] = 256] = "Y"; | ||
SIZE[SIZE["Z"] = 256] = "Z"; | ||
SIZE[SIZE["A"] = 1024] = "A"; | ||
})(exports.SIZE || (exports.SIZE = {})); | ||
@@ -57,10 +61,2 @@ var SIZE = exports.SIZE; | ||
} | ||
function isNumber256(num) { return isNumberOfDoubles(8, num); } | ||
exports.isNumber256 = isNumber256; | ||
function isNumber512(num) { return isNumberOfDoubles(16, num); } | ||
exports.isNumber512 = isNumber512; | ||
function isNumber1024(num) { return isNumberOfDoubles(32, num); } | ||
exports.isNumber1024 = isNumber1024; | ||
function isNumber2048(num) { return isNumberOfDoubles(64, num); } | ||
exports.isNumber2048 = isNumber2048; | ||
function isTnumber(num) { | ||
@@ -71,12 +67,4 @@ if (typeof num === 'number') | ||
return true; | ||
else if (isNumber128(num)) | ||
return true; | ||
else if (isNumber256(num)) | ||
return true; | ||
else if (isNumber512(num)) | ||
return true; | ||
else if (isNumber1024(num)) | ||
return true; | ||
else | ||
return isNumber2048(num); | ||
return isNumber128(num); | ||
} | ||
@@ -402,2 +390,17 @@ exports.isTnumber = isTnumber; | ||
}; | ||
Register.prototype.idSize = function () { | ||
if (this.id < 8) | ||
return 3; | ||
if (this.id < 16) | ||
return 4; | ||
if (this.id < 32) | ||
return 5; | ||
throw Error('Register ID too big.'); | ||
}; | ||
Register.prototype.get3bitId = function () { | ||
return this.id & 7; | ||
}; | ||
Register.prototype.get4bitId = function () { | ||
return this.id & 15; | ||
}; | ||
Register.prototype.toNumber = function () { | ||
@@ -639,2 +642,9 @@ return this.id; | ||
}; | ||
Operands.prototype.getAtIndexOfClass = function (index, Clazz) { | ||
var op = this.list[index]; | ||
if (op instanceof Clazz) | ||
return op; | ||
else | ||
return null; | ||
}; | ||
Operands.prototype.getFirstOfClass = function (Clazz, skip) { | ||
@@ -711,2 +721,14 @@ if (skip === void 0) { skip = 0; } | ||
}; | ||
Operands.prototype.has5bitRegister = function () { | ||
for (var j = 0; j < 4; j++) { | ||
var op = this.list[j]; | ||
if (!op) | ||
break; | ||
if (op instanceof Register) { | ||
if (op.idSize() > 4) | ||
return true; | ||
} | ||
} | ||
return false; | ||
}; | ||
Operands.prototype.toString = function () { | ||
@@ -713,0 +735,0 @@ return this.list.map(function (op) { return op.toString(); }).join(', '); |
@@ -7,12 +7,16 @@ import {UInt64} from './util'; | ||
export enum SIZE { | ||
ANY = -1, // Any size. | ||
NONE = 0, // Either unknown or not specified yet. | ||
B = 8, // byte | ||
W = 16, // word | ||
D = 32, // double word = 2x word | ||
Q = 64, // quad word = 4x word | ||
T = 80, // ten = 10 bytes | ||
O = 128, // octa word = 8x word | ||
H = 256, // hexadeca word = 16x word | ||
I = 512, // dItriaconta word = 32x word | ||
ANY = -1, // Any size. | ||
NONE = 0, // Either unknown or not specified yet. | ||
B = 8, // byte | ||
W = 16, // word | ||
D = 32, // double word = 2x word | ||
Q = 64, // quad word = 4x word | ||
T = 80, // ten = 10 bytes | ||
O = 128, // octa word = 8x word | ||
H = 256, // hexadeca word = 16x word | ||
I = 512, // dItriaconta word = 32x word | ||
X = SIZE.O, // xmm register | ||
Y = SIZE.H, // ymm register | ||
Z = SIZE.Y, // zmm register | ||
A = 1024, // amm register | ||
} | ||
@@ -55,26 +59,28 @@ | ||
// 256-bit numbers | ||
export type number256 = [number, number, number, number, number, number, number, number]; | ||
export function isNumber256(num) { return isNumberOfDoubles(8, num); } | ||
// export type number256 = [number, number, number, number, number, number, number, number]; | ||
// export function isNumber256(num) { return isNumberOfDoubles(8, num); } | ||
// 512-bit numbers | ||
export type number512 = [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number]; | ||
export function isNumber512(num) { return isNumberOfDoubles(16, num); } | ||
// export type number512 = [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number]; | ||
// export function isNumber512(num) { return isNumberOfDoubles(16, num); } | ||
// AVX-512 extension says registers will be "at least" 512 bits, so can be 1024 bits and maybe even 2048 bits. | ||
export type number1024 = [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number]; | ||
export type number2048 = [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number]; | ||
export function isNumber1024(num) { return isNumberOfDoubles(32, num); } | ||
export function isNumber2048(num) { return isNumberOfDoubles(64, num); } | ||
// export type number1024 = [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number]; | ||
// export type number2048 = [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number]; | ||
// export function isNumber1024(num) { return isNumberOfDoubles(32, num); } | ||
// export function isNumber2048(num) { return isNumberOfDoubles(64, num); } | ||
// Combined type of all basic "numbers". | ||
export type Tnumber = number|number64|number128|number256|number512|number1024|number2048; | ||
export type Tnumber = number|number64|number128; | ||
// export type Tnumber = number|number64|number128|number256|number512|number1024|number2048; | ||
export function isTnumber(num) { | ||
if(typeof num === 'number') return true; | ||
else if(isNumber64(num)) return true; | ||
else if(isNumber128(num)) return true; | ||
else if(isNumber256(num)) return true; | ||
else if(isNumber512(num)) return true; | ||
else if(isNumber1024(num)) return true; | ||
else return isNumber2048(num); | ||
// else if(isNumber128(num)) return true; | ||
// else if(isNumber256(num)) return true; | ||
// else if(isNumber512(num)) return true; | ||
// else if(isNumber1024(num)) return true; | ||
// else return isNumber2048(num); | ||
else return isNumber128(num); | ||
} | ||
@@ -386,2 +392,17 @@ | ||
idSize() { // In bits | ||
if(this.id < 0b1000) return 3; | ||
if(this.id < 0b10000) return 4; | ||
if(this.id < 0b100000) return 5; | ||
throw Error('Register ID too big.'); | ||
} | ||
get3bitId() { | ||
return this.id & 0b111; | ||
} | ||
get4bitId() { | ||
return this.id & 0b1111; | ||
} | ||
toNumber() { | ||
@@ -642,2 +663,8 @@ return this.id; | ||
getAtIndexOfClass(index, Clazz) { | ||
var op = this.list[index]; | ||
if(op instanceof Clazz) return op; | ||
else return null; | ||
} | ||
getFirstOfClass(Clazz, skip = 0) { | ||
@@ -712,2 +739,15 @@ for(var op of this.list) { | ||
// EVEX may encode up to 4 operands, 32 registers, so register can be up to 5-bits wide, | ||
// we need to check for that because in that case we cannot use VEX. | ||
has5bitRegister() { | ||
for(var j = 0; j < 4; j++) { | ||
var op = this.list[j]; | ||
if(!op) break; | ||
if(op instanceof Register) { | ||
if((op as Register).idSize() > 4) return true; | ||
} | ||
} | ||
return false; | ||
} | ||
toString() { | ||
@@ -714,0 +754,0 @@ return this.list.map((op) => { return op.toString(); }).join(', '); |
{ | ||
"name": "ass-js", | ||
"description": "Assembler.js", | ||
"version": "1.0.2", | ||
"version": "1.0.3", | ||
"keywords": [ | ||
@@ -6,0 +6,0 @@ "x86", |
@@ -5,7 +5,9 @@ # Assembler.js | ||
> THIS PACKAGE IS IN DEVELOPMENT, THERE ARE BUGS, SOME INSTRUCTIONS ARE MISSING. | ||
```js | ||
import * as ass from 'ass-js'; | ||
var {rax, rbx} = ass.x86; | ||
import {rax, rbx} from 'ass-js/x86/operand'; // x86 registers that we will use. | ||
import {Code} from 'ass-js/x86/x64/code'; // Code object that will `.compile()` our code. | ||
var _ = ass.x86.x64.Code.create(); | ||
var _ = Code.create(); | ||
_.mov(rax, rbx); | ||
@@ -19,5 +21,12 @@ console.log(_.compile()); | ||
```js | ||
console.log(ass.x86.x64.Code.table.toString()); | ||
_.table.createAll(); | ||
console.log(_.table.toString()); | ||
console.log(_.table.toJson()); | ||
``` | ||
Goals: | ||
1. Create a generic assembler, first with `x86` support and then add `ARM` support. | ||
2. Full support for all `x86` instructions, including: *AVX*, *AVX-2* and *AVX-3* instructions. | ||
## Examples | ||
@@ -47,3 +56,3 @@ | ||
```js | ||
var _ = Code.create('hello_world_app'); | ||
var _ = new Code('hello_world_app'); | ||
``` | ||
@@ -55,8 +64,8 @@ | ||
_.db('Hello World!\n'); | ||
_.movq(rax, 1); | ||
_.movq(rdi, 1); | ||
_.lea(rsi, rip.disp(-34)); | ||
_.movq(rdx, 13); | ||
_.syscall(); | ||
_.ret(); | ||
_._('mov', [rax, 1]); | ||
_._('mov', [rdi, 1]); | ||
_._('lea', [rsi, rip.disp(-34)]); | ||
_._('mov', [rdx, 13]); | ||
_._('syscall'); | ||
_._('ret'); | ||
``` | ||
@@ -67,12 +76,12 @@ | ||
- `_.db('Hello World!\n');` -- simply adds `"Hello World!\n"` string to our code. | ||
- `_.movq(rax, 1);` -- stores `1` in `rax` register, which will tell Linux kernel to execute syscall No. 1, which is | ||
- `_._('mov', [rax, 1]);` -- stores `1` in `rax` register, which will tell Linux kernel to execute syscall No. 1, which is | ||
`write` syscall, that writes some data to some file descriptor. | ||
- `_.movq(rdi, 1);` -- stores `1` in `rdi` register, which represents a file descriptor to which Linux kernel will | ||
- `_._('mov', [rdi, 1]);` -- stores `1` in `rdi` register, which represents a file descriptor to which Linux kernel will | ||
write the data, `1` stands for `STDOUT` which will be the console in our case. | ||
- `_.lea(rsi, rip.disp(-34));` -- this expression stores the address of the beginning of our `"Hello World!\n"` string | ||
- `_._('lea', [rsi, rip.disp(-34)]);` -- this expression stores the address of the beginning of our `"Hello World!\n"` string | ||
into the `rsi` register, here we use *"RIP-relative addressing"*, where we basically say that our string actually started | ||
`34` bytes before the end of this instruction. | ||
- `_.movq(rdx, 13);` -- stores `13` in `rdx` register which tells the kernel the length of our string we want to print. | ||
- `_.syscall();` -- this command tells the Linux kernel to execute our system call with the arguments we just provided. | ||
- `_.ret();` -- this command is required by `StaticBuffer` that we will use to execute this code, it will basically stop | ||
- `_._('mov', [rdx, 13]);` -- stores `13` in `rdx` register which tells the kernel the length of our string we want to print. | ||
- `_._('syscall');` -- this command tells the Linux kernel to execute our system call with the arguments we just provided. | ||
- `_._('ret');` -- this command is required by `StaticBuffer` that we will use to execute this code, it will basically stop | ||
executing any further machine instructions and `return` to `JavaScript`. | ||
@@ -114,8 +123,8 @@ | ||
_.db(str); | ||
_.movq(rax, SYS_write); | ||
_.movq(rdi, STDOUT); | ||
_.lea(rsi, rip.disp(-34)); | ||
_.movq(rdx, 13); | ||
_.syscall(); | ||
_.ret(); | ||
_._('mov', [rax, SYS_write]); | ||
_._('mov', [rdi, STDOUT]); | ||
_._('lea', [rsi, rip.disp(-34)]); | ||
_._('mov', [rdx, 13]); | ||
_._('syscall'); | ||
_._('ret'); | ||
``` | ||
@@ -134,8 +143,8 @@ | ||
var db = _.db(str); | ||
_.movq(rax, SYS_write); | ||
_.movq(rdi, STDOUT); | ||
_.lea(rsi, rip.disp(db)); | ||
_.movq(rdx, str.length); | ||
_.syscall(); | ||
_.ret(); | ||
_._('mov', [rax, SYS_write]); | ||
_._('mov', [rdi, STDOUT]); | ||
_._('lea', [rsi, rip.disp(db)]); | ||
_._('mov', [rdx, str.length]); | ||
_._('syscall'); | ||
_._('ret'); | ||
``` | ||
@@ -169,8 +178,8 @@ | ||
_.movq(rax, SYS_write); | ||
_.movq(rdi, STDOUT); | ||
_.lea(rsi, rip.disp(str_lbl)); | ||
_.movq(rdx, str.length); | ||
_.syscall(); | ||
_.ret(); | ||
_._('mov', [rax, SYS_write]); | ||
_._('mov', [rdi, STDOUT]); | ||
_._('lea', [rsi, rip.disp(str_lbl)]); | ||
_._('mov', [rdx, str.length]); | ||
_._('syscall'); | ||
_._('ret'); | ||
``` | ||
@@ -192,8 +201,8 @@ | ||
_.movq(rax, SYS_write); | ||
_.movq(rdi, STDOUT); | ||
_.lea(rsi, rip.disp(str_lbl)); | ||
_.movq(rdx, str.length); | ||
_.syscall(); | ||
_.ret(); | ||
_._('mov', [rax, SYS_write]); | ||
_._('mov', [rdi, STDOUT]); | ||
_._('lea', [rsi, rip.disp(str_lbl)]); | ||
_._('mov', [rdx, str.length]); | ||
_._('syscall'); | ||
_._('ret'); | ||
@@ -200,0 +209,0 @@ _.insert(str_lbl); |
@@ -27,3 +27,3 @@ import {SIZE, Register, Memory, Relative, Relative8, Relative16, Relative32, | ||
export type TOperandTemplate = Register | typeof Register | typeof Memory | | ||
export type TOperandTemplate = number | Register | typeof Register | typeof Memory | | ||
typeof Relative | typeof Relative8 | typeof Relative16 | typeof Relative32 | | ||
@@ -41,5 +41,5 @@ typeof Immediate | typeof Immediate8 | typeof Immediate16 | typeof Immediate32 | typeof Immediate64 | | ||
ops?: (any|TOperandTemplate|TOperandTemplate[])[]; // Operands this instruction accepts. | ||
mns?: string[]; // Other mnemonics for exactly the same instruction, basically proxies. | ||
} | ||
export type GroupDefinition = Definition[]; | ||
export type Tproxy = [string]; // Proxy to some other mnemonic, which have exactly the same definition. | ||
export type GroupDefinition = (Definition|Tproxy)[]; | ||
export type TableDefinition = {[s: string]: GroupDefinition}; | ||
@@ -46,0 +46,0 @@ |
16
util.js
@@ -25,4 +25,2 @@ "use strict"; | ||
hi /= 4294967296; | ||
if ((hi < 0) || (hi >= 1048576)) | ||
throw Error("Not an int52: " + a); | ||
return hi; | ||
@@ -41,4 +39,18 @@ }; | ||
}; | ||
UInt64.toNumber = function (num64) { | ||
var lo = num64[0], hi = num64[1]; | ||
if (lo < 0) | ||
lo += 4294967296; | ||
return hi * 4294967296 + lo; | ||
}; | ||
UInt64.toNumber64 = function (num) { | ||
var lo = num | 0; | ||
if (lo < 0) | ||
lo += 4294967296; | ||
var hi = num - lo; | ||
hi /= 4294967296; | ||
return [lo, hi]; | ||
}; | ||
return UInt64; | ||
}()); | ||
exports.UInt64 = UInt64; |
17
util.ts
@@ -18,3 +18,2 @@ | ||
hi /= 4294967296; | ||
if ((hi < 0) || (hi >= 1048576)) throw Error (`Not an int52: ${a}`); | ||
return hi; | ||
@@ -36,2 +35,18 @@ } | ||
} | ||
static toNumber(num64: [number, number]): number { | ||
var [lo, hi] = num64; | ||
if (lo < 0) lo += 4294967296; | ||
return hi * 4294967296 + lo; | ||
} | ||
static toNumber64(num: number): [number, number] { | ||
var lo = num | 0; | ||
if (lo < 0) lo += 4294967296; | ||
var hi = num - lo; | ||
hi /= 4294967296; | ||
return [lo, hi]; | ||
} | ||
} |
@@ -19,2 +19,3 @@ "use strict"; | ||
this.ClassInstruction = i.Instruction; | ||
this.ClassInstructionSet = i.InstructionSet; | ||
this.AlignExpression = i.Align; | ||
@@ -89,2 +90,19 @@ this.ClassOperands = o.Operands; | ||
}; | ||
Code.prototype.matchDefinitions = function (mnemonic, ops, opts) { | ||
var matches = _super.prototype.matchDefinitions.call(this, mnemonic, ops, opts); | ||
for (var j = matches.list.length - 1; j >= 0; j--) { | ||
var def = matches.list[j].def; | ||
if (!(this.mode & def.mode)) { | ||
matches.list.splice(j, 1); | ||
continue; | ||
} | ||
var needs_evex = opts.mask || (typeof opts.z !== 'undefined'); | ||
if (needs_evex) { | ||
if (!def.evex) | ||
matches.list.splice(j, 1); | ||
continue; | ||
} | ||
} | ||
return matches; | ||
}; | ||
Code.prototype.mem = function (disp) { | ||
@@ -103,6 +121,12 @@ if (typeof disp === 'number') | ||
if (signed === void 0) { signed = true; } | ||
return signed ? new o.Immediate(value) : new o.ImmediateUnsigned(value); | ||
return signed ? new oo.Immediate(value) : new oo.ImmediateUnsigned(value); | ||
}; | ||
Code.prototype.lock = function () { | ||
return this.tpl(i.TemplateLock); | ||
}; | ||
Code.prototype.rex = function (args) { | ||
return this.tpl(i.TemplateRex, args); | ||
}; | ||
return Code; | ||
}(code_1.Code)); | ||
exports.Code = Code; |
import * as oo from '../operand'; | ||
import * as o from './operand'; | ||
import * as c from '../code'; | ||
import {Code as CodeBase} from '../code'; | ||
@@ -11,2 +12,8 @@ import * as t from './table'; | ||
export interface IInstructionOptions extends c.IInstructionOptions { | ||
mask?: o.RegisterK; | ||
z: number|boolean; | ||
} | ||
export class Code extends CodeBase { | ||
@@ -54,3 +61,4 @@ | ||
ClassInstruction: typeof i.Instruction = i.Instruction; | ||
ClassInstruction: any = i.Instruction; | ||
ClassInstructionSet = i.InstructionSet; | ||
AlignExpression = i.Align; | ||
@@ -81,2 +89,26 @@ ClassOperands = o.Operands; | ||
protected matchDefinitions(mnemonic: string, ops: o.Operands, opts: IInstructionOptions): d.DefMatchList { | ||
var matches = super.matchDefinitions(mnemonic, ops, opts); | ||
for(var j = matches.list.length - 1; j >= 0; j--) { | ||
var def = matches.list[j].def as d.Def; | ||
// Check mode of CPU. | ||
if(!(this.mode & def.mode)) { | ||
matches.list.splice(j, 1); | ||
continue; | ||
} | ||
// If EVEX-specific options provided by user, | ||
// remove instruction definition matches that don't have EVEX prefix. | ||
var needs_evex = opts.mask || (typeof opts.z !== 'undefined'); | ||
if(needs_evex) { | ||
if(!def.evex) matches.list.splice(j, 1); | ||
continue; | ||
} | ||
} | ||
return matches; | ||
} | ||
// Displacement is up to 4 bytes in size, and 8 bytes for some specific MOV instructions, AMD64 Vol.2 p.24: | ||
@@ -103,4 +135,17 @@ // | ||
imm(value: Tnumber, signed = true) { | ||
return signed ? new o.Immediate(value) : new o.ImmediateUnsigned(value); | ||
return signed ? new oo.Immediate(value) : new oo.ImmediateUnsigned(value); | ||
} | ||
lock() { | ||
return this.tpl(i.TemplateLock); | ||
} | ||
rex(args: number[]) { | ||
return this.tpl(i.TemplateRex, args); | ||
} | ||
} | ||
export interface Code { | ||
_(mnemonic: string, operands?: oo.TUiOperand|oo.TUiOperand[], options?: oo.SIZE|IInstructionOptions|any): i.Instruction; | ||
} |
123
x86/def.js
@@ -8,5 +8,7 @@ "use strict"; | ||
var d = require('../def'); | ||
var t = require('./table'); | ||
var operand_1 = require("../operand"); | ||
var oo = require('../operand'); | ||
var o = require('./operand'); | ||
var util_1 = require('../util'); | ||
var Def = (function (_super) { | ||
@@ -21,3 +23,3 @@ __extends(Def, _super); | ||
this.opcodeDirectionBit = def.dbit; | ||
this.mandatoryRex = def.rex; | ||
this.rex = def.rex; | ||
this.useModrm = def.mr; | ||
@@ -27,3 +29,54 @@ this.rep = def.rep; | ||
this.prefixes = def.pfx; | ||
this.opEncoding = def.en; | ||
this.mode = def.mod; | ||
this.extensions = def.ext; | ||
if (typeof def.vex === 'string') | ||
this.vex = Def.parseVexString(def.vex); | ||
else | ||
this.vex = def.vex; | ||
if (typeof def.evex === 'string') | ||
this.evex = Def.parseEvexString(def.evex); | ||
else | ||
this.evex = def.evex; | ||
} | ||
Def.parseVexString = function (vstr) { | ||
var vdef = { | ||
vvvv: '', | ||
L: 0, | ||
pp: 0, | ||
mmmmm: 1, | ||
W: 1, | ||
WIG: false, | ||
}; | ||
if (vstr.indexOf('NDS') > -1) | ||
vdef.vvvv = 'NDS'; | ||
else if (vstr.indexOf('NDD') > -1) | ||
vdef.vvvv = 'NDD'; | ||
else if (vstr.indexOf('DDS') > -1) | ||
vdef.vvvv = 'DDS'; | ||
if (vstr.indexOf('256') > -1) | ||
vdef.L = 1; | ||
else if (vstr.indexOf('512') > -1) | ||
vdef.L = 2; | ||
if (vstr.indexOf('.66.') > -1) | ||
vdef.pp = 1; | ||
else if (vstr.indexOf('.F2.') > -1) | ||
vdef.pp = 3; | ||
else if (vstr.indexOf('.F3.') > -1) | ||
vdef.pp = 2; | ||
if (vstr.indexOf('0F38') > -1) | ||
vdef.mmmmm = 2; | ||
else if (vstr.indexOf('0F3A') > -1) | ||
vdef.mmmmm = 3; | ||
else if (vstr.indexOf('0F') > -1) | ||
vdef.mmmmm = 1; | ||
if (vstr.indexOf('W0') > -1) | ||
vdef.W = 0; | ||
if (vstr.indexOf('WIG') > -1) | ||
vdef.WIG = true; | ||
return vdef; | ||
}; | ||
Def.parseEvexString = function (estr) { | ||
return Def.parseVexString(estr); | ||
}; | ||
Def.prototype.matchOperandTemplate = function (tpl, operand) { | ||
@@ -80,2 +133,12 @@ var OperandClass = tpl; | ||
return 'r64'; | ||
if (operand === o.RegisterSegment) | ||
return 'sreg'; | ||
if (operand === o.RegisterMmx) | ||
return 'mmx'; | ||
if (operand === o.RegisterXmm) | ||
return 'xmm'; | ||
if (operand === o.RegisterYmm) | ||
return 'ymm'; | ||
if (operand === o.RegisterZmm) | ||
return 'zmm'; | ||
if (operand === o.Memory) | ||
@@ -103,2 +166,43 @@ return 'm'; | ||
}; | ||
Def.prototype.toJson = function () { | ||
var json = _super.prototype.toJson.call(this); | ||
if (this.opreg > 0) | ||
json.opcodeExtensionInModrm = this.opreg; | ||
if (this.regInOp) | ||
json.registerInOpcode = true; | ||
json.operandEncoding = this.opEncoding; | ||
if (this.lock) | ||
json.lock = true; | ||
if (this.opcodeDirectionBit) | ||
json.setOpcodeDirectionBit = true; | ||
if (this.vex) | ||
json.vex = this.vex; | ||
if (this.evex) | ||
json.evex = this.evex; | ||
if (this.prefixes) | ||
json.extraPrefixes = this.prefixes; | ||
if (this.rep) | ||
json.prefixRep = true; | ||
if (this.repne) | ||
json.prefixRepne = true; | ||
if (this.rex) | ||
json.rex = this.rex; | ||
if (!this.useModrm) | ||
json.skipMorm = true; | ||
if (this.mode) { | ||
json.mode = []; | ||
if (this.mode & t.MODE.X32) | ||
json.mode.push('x32'); | ||
if (this.mode & t.MODE.X64) | ||
json.mode.push('x64'); | ||
} | ||
if (this.extensions) { | ||
json.extensions = []; | ||
for (var _i = 0, _a = this.extensions; _i < _a.length; _i++) { | ||
var ext = _a[_i]; | ||
json.extensions.push(t.EXT[ext]); | ||
} | ||
} | ||
return json; | ||
}; | ||
Def.prototype.toString = function () { | ||
@@ -109,7 +213,9 @@ var opregstr = ''; | ||
var lock = this.lock ? ' LOCK' : ''; | ||
var rex = this.mandatoryRex ? ' REX' : ''; | ||
var rex = this.rex ? ' REX ' + this.rex : ''; | ||
var vex = this.vex ? ' VEX ' + JSON.stringify(this.vex) : ''; | ||
var evex = this.evex ? ' EVEX ' + JSON.stringify(this.evex) : ''; | ||
var dbit = ''; | ||
if (this.opcodeDirectionBit) | ||
dbit = ' d-bit'; | ||
return _super.prototype.toString.call(this) + opregstr + lock + rex + dbit; | ||
return _super.prototype.toString.call(this) + opregstr + lock + rex + vex + evex + dbit; | ||
}; | ||
@@ -125,2 +231,13 @@ return Def; | ||
} | ||
DefGroup.prototype.createDefinitions = function (defs, defaults) { | ||
_super.prototype.createDefinitions.call(this, defs, defaults); | ||
var group_defaults = defs[0]; | ||
group_defaults = util_1.extend({}, defaults, group_defaults); | ||
this.defaultOperandSize = group_defaults.ds; | ||
}; | ||
DefGroup.prototype.toJson = function () { | ||
var json = _super.prototype.toJson.call(this); | ||
json.defaultOperandSize = this.defaultOperandSize; | ||
return json; | ||
}; | ||
return DefGroup; | ||
@@ -127,0 +244,0 @@ }(d.DefGroup)); |
147
x86/def.ts
@@ -7,5 +7,54 @@ import * as d from '../def'; | ||
import * as o from './operand'; | ||
import {extend} from '../util'; | ||
import {IVexDefinition} from "./table"; | ||
export type IVexDefinition = t.IVexDefinition; | ||
export type IEvexDefinition = t.IEvexDefinition; | ||
export class Def extends d.Def { | ||
// 256.66.0F3A.W0 => {L: 1, pp: 1, mmmmm: 1, W: 0} | ||
static parseVexString(vstr: string): IVexDefinition { | ||
var vdef: t.IVexDefinition = { | ||
vvvv: '', | ||
L: 0b0, | ||
pp: 0b00, | ||
mmmmm: 0b00001, // 00000B is reserved, will #UD | ||
W: 0b1, // Inverted, 1 means 2-byte VEX, or ignored. | ||
WIG: false, | ||
}; | ||
// vvvv: NDS, NDD, DDS | ||
if(vstr.indexOf('NDS') > -1) vdef.vvvv = 'NDS'; | ||
else if(vstr.indexOf('NDD') > -1) vdef.vvvv = 'NDD'; | ||
else if(vstr.indexOf('DDS') > -1) vdef.vvvv = 'DDS'; | ||
// L: 128, 256, LIG, LZ | ||
if(vstr.indexOf('256') > -1) vdef.L = 0b1; | ||
else if(vstr.indexOf('512') > -1) vdef.L = 0b10; // EVEX | ||
// pp: 66, F2, F3 | ||
if(vstr.indexOf('.66.') > -1) vdef.pp = 0b01; | ||
else if(vstr.indexOf('.F2.') > -1) vdef.pp = 0b11; | ||
else if(vstr.indexOf('.F3.') > -1) vdef.pp = 0b10; | ||
// mmmmm: 0F, 0F3A, 0F38 | ||
if(vstr.indexOf('0F38') > -1) vdef.mmmmm = 0b00010; | ||
else if(vstr.indexOf('0F3A') > -1) vdef.mmmmm = 0b00011; | ||
else if(vstr.indexOf('0F') > -1) vdef.mmmmm = 0b00001; // Could still be 2-byte VEX prefix | ||
// W: W0, W1 | ||
if(vstr.indexOf('W0') > -1) vdef.W = 0b0; | ||
// WIG | ||
if(vstr.indexOf('WIG') > -1) vdef.WIG = true; | ||
return vdef; | ||
} | ||
static parseEvexString(estr: string): t.IEvexDefinition { | ||
return Def.parseVexString(estr) as t.IEvexDefinition; | ||
} | ||
opreg: number; | ||
@@ -17,3 +66,2 @@ operands: (t.TOperandTemplate[])[]; | ||
opcodeDirectionBit: boolean; | ||
mandatoryRex: boolean; | ||
useModrm: boolean; | ||
@@ -23,2 +71,8 @@ rep: boolean; | ||
prefixes: number[]; | ||
opEncoding: string; | ||
rex: t.TRexDefinition; | ||
vex: t.IVexDefinition; | ||
evex: t.IEvexDefinition; | ||
mode: t.MODE; | ||
extensions: t.EXT[]; | ||
@@ -34,3 +88,3 @@ | ||
this.opcodeDirectionBit = def.dbit; | ||
this.mandatoryRex = def.rex; | ||
this.rex = def.rex; | ||
this.useModrm = def.mr; | ||
@@ -40,2 +94,11 @@ this.rep = def.rep; | ||
this.prefixes = def.pfx; | ||
this.opEncoding = def.en; | ||
this.mode = def.mod; | ||
this.extensions = def.ext; | ||
if(typeof def.vex === 'string') this.vex = Def.parseVexString(def.vex as string); | ||
else this.vex = def.vex as t.IVexDefinition; | ||
if(typeof def.evex === 'string') this.evex = Def.parseEvexString(def.evex as string); | ||
else this.evex = def.evex as t.IEvexDefinition; | ||
} | ||
@@ -61,12 +124,12 @@ | ||
else if(typeof operand === 'function') { | ||
if(operand === oo.Immediate) return 'imm'; | ||
if(operand === oo.Immediate8) return 'imm8'; | ||
if(operand === oo.Immediate16) return 'imm16'; | ||
if(operand === oo.Immediate32) return 'imm32'; | ||
if(operand === oo.Immediate64) return 'imm64'; | ||
if(operand === oo.ImmediateUnsigned) return 'immu'; | ||
if(operand === oo.ImmediateUnsigned8) return 'immu8'; | ||
if(operand === oo.ImmediateUnsigned16) return 'immu16'; | ||
if(operand === oo.ImmediateUnsigned32) return 'immu32'; | ||
if(operand === oo.ImmediateUnsigned64) return 'immu64'; | ||
if(operand === oo.Immediate) return 'imm'; | ||
if(operand === oo.Immediate8) return 'imm8'; | ||
if(operand === oo.Immediate16) return 'imm16'; | ||
if(operand === oo.Immediate32) return 'imm32'; | ||
if(operand === oo.Immediate64) return 'imm64'; | ||
if(operand === oo.ImmediateUnsigned) return 'immu'; | ||
if(operand === oo.ImmediateUnsigned8) return 'immu8'; | ||
if(operand === oo.ImmediateUnsigned16) return 'immu16'; | ||
if(operand === oo.ImmediateUnsigned32) return 'immu32'; | ||
if(operand === oo.ImmediateUnsigned64) return 'immu64'; | ||
if(operand === o.Register) return 'r'; | ||
@@ -77,2 +140,7 @@ if(operand === o.Register8) return 'r8'; | ||
if(operand === o.Register64) return 'r64'; | ||
if(operand === o.RegisterSegment) return 'sreg'; | ||
if(operand === o.RegisterMmx) return 'mmx'; | ||
if(operand === o.RegisterXmm) return 'xmm'; | ||
if(operand === o.RegisterYmm) return 'ymm'; | ||
if(operand === o.RegisterZmm) return 'zmm'; | ||
if(operand === o.Memory) return 'm'; | ||
@@ -90,2 +158,36 @@ if(operand === o.Memory8) return 'm8'; | ||
toJson() { | ||
var json = super.toJson(); | ||
if(this.opreg > 0) json.opcodeExtensionInModrm = this.opreg; | ||
if(this.regInOp) json.registerInOpcode = true; | ||
json.operandEncoding = this.opEncoding; | ||
if(this.lock) json.lock = true; | ||
if(this.opcodeDirectionBit) json.setOpcodeDirectionBit = true; | ||
if(this.vex) json.vex = this.vex; | ||
if(this.evex) json.evex = this.evex; | ||
if(this.prefixes) json.extraPrefixes = this.prefixes; | ||
if(this.rep) json.prefixRep = true; | ||
if(this.repne) json.prefixRepne = true; | ||
if(this.rex) json.rex = this.rex; | ||
if(!this.useModrm) json.skipMorm = true; | ||
if(this.mode) { | ||
json.mode = []; | ||
if(this.mode & t.MODE.X32) json.mode.push('x32'); | ||
if(this.mode & t.MODE.X64) json.mode.push('x64'); | ||
} | ||
if(this.extensions) { | ||
json.extensions = []; | ||
for(var ext of this.extensions) json.extensions.push(t.EXT[ext]); | ||
} | ||
return json; | ||
} | ||
toString() { | ||
@@ -96,3 +198,5 @@ var opregstr = ''; | ||
var lock = this.lock ? ' LOCK' : ''; | ||
var rex = this.mandatoryRex ? ' REX' : ''; | ||
var rex = this.rex ? ' REX ' + this.rex : ''; | ||
var vex = this.vex ? ' VEX ' + JSON.stringify(this.vex) : ''; | ||
var evex = this.evex ? ' EVEX ' + JSON.stringify(this.evex) : ''; | ||
@@ -102,3 +206,3 @@ var dbit = ''; | ||
return super.toString() + opregstr + lock + rex + dbit; | ||
return super.toString() + opregstr + lock + rex + vex + evex + dbit; | ||
} | ||
@@ -110,2 +214,17 @@ } | ||
DefClass = Def; | ||
defaultOperandSize: number; | ||
createDefinitions(defs: t.Definition[], defaults: t.Definition) { | ||
super.createDefinitions(defs, defaults); | ||
var [group_defaults, ] = defs; | ||
group_defaults = extend({}, defaults, group_defaults); | ||
this.defaultOperandSize = group_defaults.ds; | ||
} | ||
toJson() { | ||
var json = super.toJson(); | ||
json.defaultOperandSize = this.defaultOperandSize; | ||
return json; | ||
} | ||
} | ||
@@ -112,0 +231,0 @@ |
@@ -21,2 +21,25 @@ "use strict"; | ||
exports.Expression = Expression; | ||
var TemplateLock = (function (_super) { | ||
__extends(TemplateLock, _super); | ||
function TemplateLock() { | ||
_super.apply(this, arguments); | ||
this.name = 'lock'; | ||
this.octets = [p.PREFIX.LOCK]; | ||
} | ||
return TemplateLock; | ||
}(i.Template)); | ||
exports.TemplateLock = TemplateLock; | ||
var TemplateRex = (function (_super) { | ||
__extends(TemplateRex, _super); | ||
function TemplateRex(args) { | ||
_super.call(this, args); | ||
this.name = 'rex'; | ||
this.args = [0, 0, 0, 0]; | ||
var _a = this.args, W = _a[0], R = _a[1], X = _a[2], B = _a[3]; | ||
var rex = new p.PrefixRex(W, R, X, B); | ||
rex.write(this.octets); | ||
} | ||
return TemplateRex; | ||
}(i.Template)); | ||
exports.TemplateRex = TemplateRex; | ||
var Align = (function (_super) { | ||
@@ -53,2 +76,3 @@ __extends(Align, _super); | ||
this.prefixes = []; | ||
this.pfxEx = null; | ||
this.opcode = new p.Opcode; | ||
@@ -70,2 +94,3 @@ this.modrm = null; | ||
this.prefixes = []; | ||
this.pfxEx = null; | ||
this.opcode = new p.Opcode; | ||
@@ -103,2 +128,4 @@ this.modrm = null; | ||
} | ||
if (this.pfxEx) | ||
this.pfxEx.write(arr); | ||
}; | ||
@@ -163,2 +190,4 @@ Instruction.prototype.write = function (arr) { | ||
this.pfxLock = new p.PrefixLock; | ||
this.length++; | ||
this.lengthMax++; | ||
return this; | ||
@@ -220,12 +249,13 @@ }; | ||
}; | ||
Instruction.prototype.toString = function (margin, hex) { | ||
if (margin === void 0) { margin = ' '; } | ||
if (hex === void 0) { hex = true; } | ||
var parts = []; | ||
Instruction.prototype.toStringExpression = function () { | ||
var expression = _super.prototype.toStringExpression.call(this); | ||
if (this.pfxLock) | ||
parts.push(this.pfxLock.toString()); | ||
expression += " {" + this.pfxLock.toString() + "}"; | ||
if (this.pfxSegment) | ||
parts.push(this.pfxSegment.toString()); | ||
parts.push(_super.prototype.toString.call(this, margin, hex)); | ||
return parts.join(' '); | ||
expression += " {" + this.pfxSegment.toString() + "}"; | ||
if (this.opts.mask) | ||
expression += " {" + this.opts.mask.toString() + "}"; | ||
if (this.opts.z) | ||
expression += " {z}"; | ||
return expression; | ||
}; | ||
@@ -259,2 +289,6 @@ Instruction.prototype.needsOperandSizeOverride = function () { | ||
} | ||
if (this.def.vex) | ||
this.createVexPrefix(); | ||
else if (this.def.evex) | ||
this.createEvexPrefix(); | ||
if (this.def.prefixes) { | ||
@@ -269,2 +303,106 @@ for (var _i = 0, _a = this.def.prefixes; _i < _a.length; _i++) { | ||
}; | ||
Instruction.prototype.createVexPrefix = function () { | ||
var R = 1, X = 1, B = 1, vvvv = 15; | ||
var pos = this.def.opEncoding.indexOf('v'); | ||
if (pos > -1) { | ||
var reg = this.ops.getAtIndexOfClass(pos, o.Register); | ||
if (!reg) | ||
throw Error("Could not find Register operand at position " + pos + " to encode VEX.vvvv"); | ||
vvvv = (~reg.get4bitId()) & 15; | ||
} | ||
pos = this.def.opEncoding.indexOf('r'); | ||
if (pos > -1) { | ||
var reg = this.ops.getAtIndexOfClass(pos, o.Register); | ||
if (!reg) | ||
throw Error("Could not find Register operand at position " + pos + " to encode VEX.R"); | ||
if (reg.idSize() > 3) | ||
R = 0; | ||
} | ||
pos = this.def.opEncoding.indexOf('m'); | ||
if (pos > -1) { | ||
var reg = this.ops.getAtIndexOfClass(pos, o.Register); | ||
if (reg && (reg.idSize() > 3)) | ||
B = 0; | ||
} | ||
var mem = this.ops.getMemoryOperand(); | ||
if (mem) { | ||
if (mem.base && (mem.base.idSize() > 3)) | ||
B = 0; | ||
if (mem.index && (mem.index.idSize() > 3)) | ||
X = 0; | ||
} | ||
this.pfxEx = new p.PrefixVex(this.def.vex, R, X, B, vvvv); | ||
this.length += this.pfxEx.bytes; | ||
this.lengthMax += this.pfxEx.bytes; | ||
}; | ||
Instruction.prototype.createEvexPrefix = function () { | ||
var evex = this.pfxEx = new p.PrefixEvex(this.def.evex); | ||
this.length += 3; | ||
this.lengthMax += 3; | ||
var pos = this.def.opEncoding.indexOf('v'); | ||
if (pos > -1) { | ||
var reg = this.ops.getAtIndexOfClass(pos, o.Register); | ||
if (!reg) | ||
throw Error("Could not find Register operand at position " + pos + " to encode EVEX.vvvv"); | ||
evex.vvvv = (~reg.get4bitId()) & 15; | ||
evex.Vp = reg.id & 16 ? 0 : 1; | ||
} | ||
pos = this.def.opEncoding.indexOf('r'); | ||
if (pos > -1) { | ||
var reg = this.ops.getAtIndexOfClass(pos, o.Register); | ||
if (!reg) | ||
throw Error("Could not find Register operand at position " + pos + " to encode VEX.R"); | ||
var id_size = reg.idSize(); | ||
if (id_size > 3) | ||
evex.R = 0; | ||
if (id_size > 4) { | ||
evex.Rp = 0; | ||
if (reg.id & 8) | ||
evex.R = 0; | ||
else | ||
evex.R = 1; | ||
} | ||
} | ||
pos = this.def.opEncoding.indexOf('m'); | ||
if (pos > -1) { | ||
var reg = this.ops.getAtIndexOfClass(pos, o.Register); | ||
if (reg) { | ||
if (reg.idSize() > 3) | ||
evex.B = 0; | ||
if (reg.idSize() > 4) { | ||
evex.X = 0; | ||
if (reg.id & 8) | ||
evex.B = 0; | ||
else | ||
evex.B = 1; | ||
} | ||
} | ||
} | ||
var mem = this.ops.getMemoryOperand(); | ||
if (mem) { | ||
if (mem.base && (mem.base.idSize() > 3)) | ||
evex.B = 0; | ||
if (mem.index && (mem.index.idSize() > 3)) | ||
evex.X = 0; | ||
} | ||
if (this.opts.mask) | ||
this.mask(this.opts.mask); | ||
if (typeof this.opts.z !== 'undefined') | ||
this.z(this.opts.z); | ||
}; | ||
Instruction.prototype.mask = function (k) { | ||
if (!(this.pfxEx instanceof p.PrefixEvex)) | ||
throw Error('Cannot set mask on non-EVEX instruction.'); | ||
if (k.id === 0) | ||
throw TypeError('Mask register 000 cannot be used as mask.'); | ||
this.pfxEx.aaa = k.get3bitId(); | ||
return this; | ||
}; | ||
Instruction.prototype.z = function (value) { | ||
if (value === void 0) { value = 1; } | ||
if (!(this.pfxEx instanceof p.PrefixEvex)) | ||
throw Error('Cannot set z-bit on non-EVEX instruction.'); | ||
this.pfxEx.z = value ? 1 : 0; | ||
return this; | ||
}; | ||
Instruction.prototype.createOpcode = function () { | ||
@@ -276,4 +414,4 @@ var def = this.def; | ||
if (def.regInOp) { | ||
if (!dst || !dst.isRegister()) | ||
throw TypeError("Operation needs destination register."); | ||
if (!dst || (!dst.isRegister())) | ||
throw TypeError("Operation needs destination Register."); | ||
opcode.op = (opcode.op & p.Opcode.MASK_OP) | dst.get3bitId(); | ||
@@ -305,2 +443,4 @@ } | ||
return; | ||
var encoding = this.def.opEncoding; | ||
var mod = 0, reg = 0, rm = 0; | ||
var _a = this.ops.list, dst = _a[0], src = _a[1]; | ||
@@ -310,4 +450,3 @@ var has_opreg = (this.def.opreg > -1); | ||
if (has_opreg || dst_in_modrm) { | ||
var mod = 0, reg = 0, rm = 0; | ||
var reg_is_dst = !!(this.opcode.op & p.Opcode.DIRECTION.REG_IS_DST); | ||
var reg_is_dst = this.def.opEncoding[0] !== 'm' ? true : false; | ||
if (has_opreg) { | ||
@@ -326,9 +465,41 @@ reg = this.def.opreg; | ||
else { | ||
var r = this.ops.getRegisterOperand(reg_is_dst); | ||
if (r) { | ||
if ((encoding.length === 2) && (dst instanceof o.Register) && (src instanceof o.Register)) { | ||
mod = p.Modrm.MOD.REG_TO_REG; | ||
reg = r.get3bitId(); | ||
var regreg = (reg_is_dst ? dst : src); | ||
var rmreg = (reg_is_dst ? src : dst); | ||
reg = regreg.get3bitId(); | ||
rm = rmreg.get3bitId(); | ||
this.modrm = new p.Modrm(mod, reg, rm); | ||
this.length++; | ||
this.lengthMax++; | ||
return; | ||
} | ||
var rpos = encoding.indexOf('r'); | ||
var rreg; | ||
if ((rpos > -1) && (rreg = this.ops.getAtIndexOfClass(rpos, o.Register))) { | ||
reg = rreg.get3bitId(); | ||
} | ||
else { | ||
var r = this.ops.getRegisterOperand(this.regToRegDirectionRegIsDst ? 0 : 1); | ||
if (!r) | ||
r = this.ops.getRegisterOperand(); | ||
if (r) { | ||
mod = p.Modrm.MOD.REG_TO_REG; | ||
reg = r.get3bitId(); | ||
} | ||
} | ||
} | ||
if (!dst) { | ||
var mpos = encoding.indexOf('m'); | ||
if (mpos > -1) { | ||
var mreg = this.ops.getAtIndexOfClass(mpos, o.Register); | ||
if (mreg) { | ||
mod = p.Modrm.MOD.REG_TO_REG; | ||
rm = mreg.get3bitId(); | ||
this.modrm = new p.Modrm(mod, reg, rm); | ||
this.length++; | ||
this.lengthMax++; | ||
return; | ||
} | ||
} | ||
else { | ||
this.modrm = new p.Modrm(mod, reg, rm); | ||
@@ -339,6 +510,3 @@ this.length++; | ||
} | ||
if ((dst instanceof o.Register) && (src instanceof o.Register)) { | ||
mod = p.Modrm.MOD.REG_TO_REG; | ||
var rmreg = (reg_is_dst ? src : dst); | ||
rm = rmreg.get3bitId(); | ||
if (!dst) { | ||
this.modrm = new p.Modrm(mod, reg, rm); | ||
@@ -345,0 +513,0 @@ this.length++; |
@@ -8,2 +8,3 @@ import {SIZE} from '../operand'; | ||
import * as d from './def'; | ||
import * as c from './code'; | ||
@@ -16,2 +17,20 @@ | ||
export class TemplateLock extends i.Template { | ||
name = 'lock'; | ||
octets = [p.PREFIX.LOCK]; | ||
} | ||
export class TemplateRex extends i.Template { | ||
name = 'rex'; | ||
args = [0, 0, 0, 0]; | ||
constructor(args) { | ||
super(args); | ||
var [W, R, X, B] = this.args; | ||
var rex = new p.PrefixRex(W, R, X, B); | ||
rex.write(this.octets); | ||
} | ||
} | ||
export class Align extends i.Align { | ||
@@ -61,2 +80,3 @@ | ||
ops: o.Operands; | ||
opts: c.IInstructionOptions; | ||
@@ -71,2 +91,3 @@ // Instruction parts. | ||
prefixes: p.PrefixStatic[] = []; | ||
pfxEx: p.PrefixRex|p.PrefixVex|p.PrefixEvex = null; // One of REX, VEX, EVEX prefixes, only one allowed. | ||
opcode: p.Opcode = new p.Opcode; // required | ||
@@ -93,2 +114,3 @@ modrm: p.Modrm = null; | ||
this.prefixes = []; | ||
this.pfxEx = null; | ||
this.opcode = new p.Opcode; // required | ||
@@ -113,9 +135,10 @@ this.modrm = null; | ||
protected writePrefixes(arr: number[]) { | ||
if(this.pfxLock) this.pfxLock.write(arr); | ||
if(this.pfxRep) this.pfxRep.write(arr); | ||
if(this.pfxRepne) this.pfxRepne.write(arr); | ||
if(this.pfxAddrSize) this.pfxAddrSize.write(arr); | ||
if(this.pfxSegment) this.pfxSegment.write(arr); | ||
if(this.pfxOpSize) this.pfxOpSize.write(arr); | ||
if(this.pfxLock) this.pfxLock.write(arr); | ||
if(this.pfxRep) this.pfxRep.write(arr); | ||
if(this.pfxRepne) this.pfxRepne.write(arr); | ||
if(this.pfxAddrSize) this.pfxAddrSize.write(arr); | ||
if(this.pfxSegment) this.pfxSegment.write(arr); | ||
if(this.pfxOpSize) this.pfxOpSize.write(arr); | ||
for(var pfx of this.prefixes) pfx.write(arr); | ||
if(this.pfxEx) this.pfxEx.write(arr); | ||
} | ||
@@ -181,2 +204,4 @@ | ||
this.pfxLock = new p.PrefixLock; | ||
this.length++; | ||
this.lengthMax++; | ||
return this; | ||
@@ -252,8 +277,9 @@ } | ||
toString(margin = ' ', hex = true) { | ||
var parts = []; | ||
if(this.pfxLock) parts.push(this.pfxLock.toString()); | ||
if(this.pfxSegment) parts.push(this.pfxSegment.toString()); | ||
parts.push(super.toString(margin, hex)); | ||
return parts.join(' '); | ||
protected toStringExpression() { | ||
var expression = super.toStringExpression(); | ||
if(this.pfxLock) expression += ` {${this.pfxLock.toString()}}`; | ||
if(this.pfxSegment) expression += ` {${this.pfxSegment.toString()}}`; | ||
if(this.opts.mask) expression += ` {${this.opts.mask.toString()}}`; | ||
if(this.opts.z) expression += ` {z}`; | ||
return expression; | ||
} | ||
@@ -288,2 +314,6 @@ | ||
if(this.def.vex) this.createVexPrefix(); | ||
else if(this.def.evex) this.createEvexPrefix(); | ||
// Mandatory prefixes required by op-code. | ||
@@ -299,2 +329,104 @@ if(this.def.prefixes) { | ||
protected createVexPrefix() { | ||
// These bits in VEX are inverted, so they actually all mean "0" zeros. | ||
var R = 1, X = 1, B = 1, vvvv = 0b1111; | ||
var pos = this.def.opEncoding.indexOf('v'); | ||
if(pos > -1) { | ||
var reg = this.ops.getAtIndexOfClass(pos, o.Register) as o.Register; | ||
if(!reg) throw Error(`Could not find Register operand at position ${pos} to encode VEX.vvvv`); | ||
vvvv = (~reg.get4bitId()) & 0b1111; // Inverted | ||
} | ||
pos = this.def.opEncoding.indexOf('r'); | ||
if(pos > -1) { | ||
var reg = this.ops.getAtIndexOfClass(pos, o.Register) as o.Register; | ||
if(!reg) throw Error(`Could not find Register operand at position ${pos} to encode VEX.R`); | ||
if(reg.idSize() > 3) R = 0; // Inverted | ||
} | ||
pos = this.def.opEncoding.indexOf('m'); | ||
if(pos > -1) { | ||
var reg = this.ops.getAtIndexOfClass(pos, o.Register) as o.Register; | ||
if(reg && (reg.idSize() > 3)) B = 0; // Inverted | ||
} | ||
var mem = this.ops.getMemoryOperand() as o.Memory; | ||
if(mem) { | ||
if (mem.base && (mem.base.idSize() > 3)) B = 0; | ||
if (mem.index && (mem.index.idSize() > 3)) X = 0; | ||
} | ||
this.pfxEx = new p.PrefixVex(this.def.vex, R, X, B, vvvv); | ||
this.length += (this.pfxEx as p.PrefixVex).bytes; | ||
this.lengthMax += (this.pfxEx as p.PrefixVex).bytes; | ||
} | ||
protected createEvexPrefix() { | ||
var evex = this.pfxEx = new p.PrefixEvex(this.def.evex); | ||
this.length += 3; | ||
this.lengthMax += 3; | ||
var pos = this.def.opEncoding.indexOf('v'); | ||
if(pos > -1) { | ||
var reg = this.ops.getAtIndexOfClass(pos, o.Register) as o.Register; | ||
if(!reg) throw Error(`Could not find Register operand at position ${pos} to encode EVEX.vvvv`); | ||
evex.vvvv = (~reg.get4bitId()) & 0b1111; // Inverted | ||
evex.Vp = reg.id & 0b10000 ? 0 : 1; // Inverted | ||
} | ||
pos = this.def.opEncoding.indexOf('r'); | ||
if(pos > -1) { | ||
var reg = this.ops.getAtIndexOfClass(pos, o.Register) as o.Register; | ||
if(!reg) throw Error(`Could not find Register operand at position ${pos} to encode VEX.R`); | ||
var id_size = reg.idSize(); | ||
if(id_size > 3) evex.R = 0; // Inverted | ||
if(id_size > 4) { | ||
evex.Rp = 0; // Inverted | ||
if(reg.id & 0b1000) evex.R = 0; | ||
else evex.R = 1; | ||
} | ||
} | ||
pos = this.def.opEncoding.indexOf('m'); | ||
if(pos > -1) { | ||
var reg = this.ops.getAtIndexOfClass(pos, o.Register) as o.Register; | ||
if(reg) { | ||
if (reg.idSize() > 3) evex.B = 0; // Inverted | ||
if (reg.idSize() > 4) { | ||
evex.X = 0; // Inverted | ||
if(reg.id & 0b1000) evex.B = 0; | ||
else evex.B = 1; | ||
} | ||
} | ||
} | ||
var mem = this.ops.getMemoryOperand() as o.Memory; | ||
if(mem) { | ||
if (mem.base && (mem.base.idSize() > 3)) evex.B = 0; // Inverted | ||
if (mem.index && (mem.index.idSize() > 3)) evex.X = 0; // Inverted | ||
} | ||
if(this.opts.mask) this.mask(this.opts.mask); | ||
if(typeof this.opts.z !== 'undefined') this.z(this.opts.z); | ||
} | ||
// Set mask register for `EVEX` instructions. | ||
mask(k: o.RegisterK): this { | ||
if(!(this.pfxEx instanceof p.PrefixEvex)) | ||
throw Error('Cannot set mask on non-EVEX instruction.'); | ||
if(k.id === 0) | ||
throw TypeError('Mask register 000 cannot be used as mask.'); | ||
(this.pfxEx as p.PrefixEvex).aaa = k.get3bitId(); | ||
return this; | ||
} | ||
// Set `z` bit for `EVEX` instructions. | ||
z(value: number|boolean = 1): this { | ||
if(!(this.pfxEx instanceof p.PrefixEvex)) | ||
throw Error('Cannot set z-bit on non-EVEX instruction.'); | ||
(this.pfxEx as p.PrefixEvex).z = value ? 1 : 0; | ||
return this; | ||
} | ||
protected createOpcode() { | ||
@@ -309,4 +441,4 @@ var def = this.def; | ||
// We have register encoded in op-code here. | ||
if(!dst || !(dst as oo.Operand).isRegister()) | ||
throw TypeError(`Operation needs destination register.`); | ||
if(!dst || (!(dst as oo.Operand).isRegister())) | ||
throw TypeError(`Operation needs destination Register.`); | ||
opcode.op = (opcode.op & p.Opcode.MASK_OP) | (dst as o.Register).get3bitId(); | ||
@@ -347,2 +479,5 @@ } else { | ||
var encoding = this.def.opEncoding; | ||
var mod = 0, reg = 0, rm = 0; | ||
var [dst, src] = this.ops.list; | ||
@@ -352,5 +487,5 @@ var has_opreg = (this.def.opreg > -1); | ||
if(has_opreg || dst_in_modrm) { | ||
var mod = 0, reg = 0, rm = 0; | ||
var reg_is_dst = !!(this.opcode.op & p.Opcode.DIRECTION.REG_IS_DST); | ||
// var reg_is_dst = !!(this.opcode.op & p.Opcode.DIRECTION.REG_IS_DST); | ||
var reg_is_dst = this.def.opEncoding[0] !== 'm' ? true : false; | ||
@@ -360,3 +495,3 @@ if(has_opreg) { | ||
reg = this.def.opreg; | ||
var r: o.Register = this.ops.getRegisterOperand(); | ||
var r: o.Register = this.ops.getRegisterOperand() as o.Register; | ||
if (r) { | ||
@@ -371,11 +506,43 @@ mod = p.Modrm.MOD.REG_TO_REG; | ||
} else { | ||
// var r: o.Register = this.op.getRegisterOperand(this.regToRegDirectionRegIsDst); | ||
var r: o.Register = this.ops.getRegisterOperand(reg_is_dst) as o.Register; | ||
if (r) { | ||
// Reg-to-reg instruction; | ||
if((encoding.length === 2) && (dst instanceof o.Register) && (src instanceof o.Register)) { | ||
mod = p.Modrm.MOD.REG_TO_REG; | ||
reg = r.get3bitId(); | ||
var regreg: o.Register = (reg_is_dst ? dst : src) as o.Register; | ||
var rmreg: o.Register = (reg_is_dst ? src : dst) as o.Register; | ||
reg = regreg.get3bitId(); | ||
rm = rmreg.get3bitId(); | ||
this.modrm = new p.Modrm(mod, reg, rm); | ||
this.length++; | ||
this.lengthMax++; | ||
return; | ||
} | ||
var rpos = encoding.indexOf('r'); | ||
var rreg; | ||
if((rpos > -1) && (rreg = this.ops.getAtIndexOfClass(rpos, o.Register) as o.Register)) { | ||
reg = rreg.get3bitId(); | ||
} else { | ||
// var r: o.Register = this.op.getRegisterOperand(this.regToRegDirectionRegIsDst); | ||
var r: o.Register = this.ops.getRegisterOperand(this.regToRegDirectionRegIsDst ? 0 : 1) as o.Register; | ||
if(!r) r = this.ops.getRegisterOperand() as o.Register; | ||
if(r) { | ||
mod = p.Modrm.MOD.REG_TO_REG; | ||
reg = r.get3bitId(); | ||
} | ||
} | ||
} | ||
if(!dst) { // No destination operand, just opreg. | ||
var mpos = encoding.indexOf('m'); | ||
if(mpos > -1) { | ||
var mreg = this.ops.getAtIndexOfClass(mpos, o.Register) as o.Register; | ||
if(mreg) { | ||
mod = p.Modrm.MOD.REG_TO_REG; | ||
rm = (mreg as o.Register).get3bitId(); | ||
this.modrm = new p.Modrm(mod, reg, rm); | ||
this.length++; | ||
this.lengthMax++; | ||
return; | ||
} | ||
} else { | ||
this.modrm = new p.Modrm(mod, reg, rm); | ||
@@ -387,8 +554,3 @@ this.length++; | ||
// Reg-to-reg instruction; | ||
if((dst instanceof o.Register) && (src instanceof o.Register)) { | ||
mod = p.Modrm.MOD.REG_TO_REG; | ||
// var rmreg: o.Register = (this.regToRegDirectionRegIsDst ? src : dst) as o.Register; | ||
var rmreg: o.Register = (reg_is_dst ? src : dst) as o.Register; | ||
rm = rmreg.get3bitId(); | ||
if(!dst) { // No destination operand, just opreg. | ||
this.modrm = new p.Modrm(mod, reg, rm); | ||
@@ -402,5 +564,7 @@ this.length++; | ||
// that EBP always has displacement value even if 0x00. | ||
// Memory operand can be encoded in only one way (Modrm.rm + SIB) so we | ||
// ignore here `def.opEncoding` field. | ||
var m: o.Memory = this.ops.getMemoryOperand() as o.Memory; | ||
if(!m) { | ||
// throw Error('No Memory reference for Modrm byte.'); | ||
this.modrm = new p.Modrm(mod, reg, rm); | ||
@@ -646,4 +810,1 @@ this.length++; | ||
export interface InstructionSet { | ||
pickShortestInstruction(): Instruction; | ||
} |
@@ -79,8 +79,13 @@ "use strict"; | ||
}; | ||
Register.prototype.get3bitId = function () { | ||
return this.id & 7; | ||
}; | ||
return Register; | ||
}(operand_1.Register)); | ||
exports.Register = Register; | ||
var RegisterGP = (function (_super) { | ||
__extends(RegisterGP, _super); | ||
function RegisterGP() { | ||
_super.apply(this, arguments); | ||
} | ||
return RegisterGP; | ||
}(Register)); | ||
exports.RegisterGP = RegisterGP; | ||
var Register8 = (function (_super) { | ||
@@ -92,3 +97,3 @@ __extends(Register8, _super); | ||
return Register8; | ||
}(Register)); | ||
}(RegisterGP)); | ||
exports.Register8 = Register8; | ||
@@ -117,3 +122,3 @@ var Register8High = (function (_super) { | ||
return Register32; | ||
}(Register)); | ||
}(RegisterGP)); | ||
exports.Register32 = Register32; | ||
@@ -126,3 +131,3 @@ var Register64 = (function (_super) { | ||
return Register64; | ||
}(Register)); | ||
}(RegisterGP)); | ||
exports.Register64 = Register64; | ||
@@ -135,3 +140,3 @@ var Register128 = (function (_super) { | ||
return Register128; | ||
}(Register)); | ||
}(RegisterGP)); | ||
exports.Register128 = Register128; | ||
@@ -144,3 +149,3 @@ var Register256 = (function (_super) { | ||
return Register256; | ||
}(Register)); | ||
}(RegisterGP)); | ||
exports.Register256 = Register256; | ||
@@ -153,3 +158,3 @@ var Register512 = (function (_super) { | ||
return Register512; | ||
}(Register)); | ||
}(RegisterGP)); | ||
exports.Register512 = Register512; | ||
@@ -159,33 +164,66 @@ var RegisterRip = (function (_super) { | ||
function RegisterRip() { | ||
_super.call(this, 0); | ||
_super.call(this, 0, operand_1.SIZE.Q); | ||
this.name = 'rip'; | ||
} | ||
return RegisterRip; | ||
}(Register64)); | ||
}(Register)); | ||
exports.RegisterRip = RegisterRip; | ||
var RegisterSegment = (function (_super) { | ||
__extends(RegisterSegment, _super); | ||
function RegisterSegment() { | ||
_super.apply(this, arguments); | ||
function RegisterSegment(id) { | ||
_super.call(this, id, operand_1.SIZE.W); | ||
} | ||
return RegisterSegment; | ||
}(Register16)); | ||
}(Register)); | ||
exports.RegisterSegment = RegisterSegment; | ||
var RegisterMmx = (function (_super) { | ||
__extends(RegisterMmx, _super); | ||
function RegisterMmx(id) { | ||
_super.call(this, id); | ||
this.name = 'mmx' + id; | ||
var RegisterBounds = (function (_super) { | ||
__extends(RegisterBounds, _super); | ||
function RegisterBounds(id) { | ||
_super.call(this, id, operand_1.SIZE.O); | ||
} | ||
return RegisterMmx; | ||
}(Register128)); | ||
exports.RegisterMmx = RegisterMmx; | ||
return RegisterBounds; | ||
}(Register)); | ||
exports.RegisterBounds = RegisterBounds; | ||
var RegisterFloatingPoint = (function (_super) { | ||
__extends(RegisterFloatingPoint, _super); | ||
function RegisterFloatingPoint() { | ||
_super.apply(this, arguments); | ||
} | ||
return RegisterFloatingPoint; | ||
}(Register)); | ||
exports.RegisterFloatingPoint = RegisterFloatingPoint; | ||
var RegisterMm = (function (_super) { | ||
__extends(RegisterMm, _super); | ||
function RegisterMm(id) { | ||
_super.call(this, id, operand_1.SIZE.O); | ||
this.name = 'mm' + id; | ||
} | ||
return RegisterMm; | ||
}(RegisterFloatingPoint)); | ||
exports.RegisterMm = RegisterMm; | ||
var RegisterSt = (function (_super) { | ||
__extends(RegisterSt, _super); | ||
function RegisterSt(id) { | ||
_super.call(this, id, operand_1.SIZE.T); | ||
this.name = 'st' + id; | ||
} | ||
return RegisterSt; | ||
}(RegisterFloatingPoint)); | ||
exports.RegisterSt = RegisterSt; | ||
var RegisterVector = (function (_super) { | ||
__extends(RegisterVector, _super); | ||
function RegisterVector() { | ||
_super.apply(this, arguments); | ||
} | ||
return RegisterVector; | ||
}(Register)); | ||
exports.RegisterVector = RegisterVector; | ||
var RegisterXmm = (function (_super) { | ||
__extends(RegisterXmm, _super); | ||
function RegisterXmm(id) { | ||
_super.call(this, id); | ||
_super.call(this, id, operand_1.SIZE.O); | ||
this.name = 'xmm' + id; | ||
} | ||
return RegisterXmm; | ||
}(Register128)); | ||
}(RegisterVector)); | ||
exports.RegisterXmm = RegisterXmm; | ||
@@ -195,7 +233,7 @@ var RegisterYmm = (function (_super) { | ||
function RegisterYmm(id) { | ||
_super.call(this, id); | ||
_super.call(this, id, operand_1.SIZE.H); | ||
this.name = 'ymm' + id; | ||
} | ||
return RegisterYmm; | ||
}(Register256)); | ||
}(RegisterVector)); | ||
exports.RegisterYmm = RegisterYmm; | ||
@@ -205,114 +243,35 @@ var RegisterZmm = (function (_super) { | ||
function RegisterZmm(id) { | ||
_super.call(this, id); | ||
_super.call(this, id, operand_1.SIZE.I); | ||
this.name = 'zmm' + id; | ||
} | ||
return RegisterZmm; | ||
}(Register512)); | ||
}(RegisterVector)); | ||
exports.RegisterZmm = RegisterZmm; | ||
function validateRegId(id, min, max, Clazz) { | ||
if (typeof id !== 'number') | ||
throw TypeError(Clazz.name + ' register ID must be a number.'); | ||
if (id < min) | ||
throw TypeError(Clazz.name + " register ID must be at least " + min + "."); | ||
if (id > max) | ||
throw TypeError(Clazz.name + " register ID must be at most " + max + "."); | ||
} | ||
function createRegisterGenerator(Clazz, min_id, max_id) { | ||
if (min_id === void 0) { min_id = 0; } | ||
if (max_id === void 0) { max_id = 15; } | ||
var cache; | ||
return function (id) { | ||
validateRegId(id, min_id, max_id, Clazz); | ||
if (!cache) | ||
cache = new Array(max_id + 1); | ||
if (!cache[id]) | ||
cache[id] = new Clazz(id); | ||
return cache[id]; | ||
}; | ||
} | ||
exports.rb = createRegisterGenerator(Register8, 0, 15); | ||
exports.rw = createRegisterGenerator(Register16, 0, 15); | ||
exports.rd = createRegisterGenerator(Register32, 0, 15); | ||
exports.rq = createRegisterGenerator(Register64, 0, 15); | ||
exports.r = exports.rq; | ||
exports.rs = createRegisterGenerator(RegisterSegment, 0, 15); | ||
exports.mmx = createRegisterGenerator(RegisterMmx, 0, 15); | ||
exports.xmm = createRegisterGenerator(RegisterXmm, 0, 31); | ||
exports.ymm = createRegisterGenerator(RegisterYmm, 0, 31); | ||
exports.zmm = createRegisterGenerator(RegisterZmm, 0, 31); | ||
exports.al = exports.rb(regfile_1.R8.AL); | ||
exports.bl = exports.rb(regfile_1.R8.BL); | ||
exports.cl = exports.rb(regfile_1.R8.CL); | ||
exports.dl = exports.rb(regfile_1.R8.DL); | ||
exports.sil = exports.rb(regfile_1.R8.SIL); | ||
exports.dil = exports.rb(regfile_1.R8.DIL); | ||
exports.bpl = exports.rb(regfile_1.R8.BPL); | ||
exports.spl = exports.rb(regfile_1.R8.SPL); | ||
exports.r8b = exports.rb(regfile_1.R8.R8B); | ||
exports.r9b = exports.rb(regfile_1.R8.R9B); | ||
exports.r10b = exports.rb(regfile_1.R8.R10B); | ||
exports.r11b = exports.rb(regfile_1.R8.R11B); | ||
exports.r12b = exports.rb(regfile_1.R8.R12B); | ||
exports.r13b = exports.rb(regfile_1.R8.R13B); | ||
exports.r14b = exports.rb(regfile_1.R8.R14B); | ||
exports.r15b = exports.rb(regfile_1.R8.R15B); | ||
exports.ah = new Register8High(regfile_1.R8H.AH); | ||
exports.bh = new Register8High(regfile_1.R8H.BH); | ||
exports.ch = new Register8High(regfile_1.R8H.CH); | ||
exports.dh = new Register8High(regfile_1.R8H.DH); | ||
exports.ax = exports.rw(regfile_1.R16.AX); | ||
exports.bx = exports.rw(regfile_1.R16.BX); | ||
exports.cx = exports.rw(regfile_1.R16.CX); | ||
exports.dx = exports.rw(regfile_1.R16.DX); | ||
exports.si = exports.rw(regfile_1.R16.SI); | ||
exports.di = exports.rw(regfile_1.R16.DI); | ||
exports.bp = exports.rw(regfile_1.R16.BP); | ||
exports.sp = exports.rw(regfile_1.R16.SP); | ||
exports.r8w = exports.rw(regfile_1.R16.R8W); | ||
exports.r9w = exports.rw(regfile_1.R16.R9W); | ||
exports.r10w = exports.rw(regfile_1.R16.R10W); | ||
exports.r11w = exports.rw(regfile_1.R16.R11W); | ||
exports.r12w = exports.rw(regfile_1.R16.R12W); | ||
exports.r13w = exports.rw(regfile_1.R16.R13W); | ||
exports.r14w = exports.rw(regfile_1.R16.R14W); | ||
exports.r15w = exports.rw(regfile_1.R16.R15W); | ||
exports.eax = exports.rd(regfile_1.R32.EAX); | ||
exports.ebx = exports.rd(regfile_1.R32.EBX); | ||
exports.ecx = exports.rd(regfile_1.R32.ECX); | ||
exports.edx = exports.rd(regfile_1.R32.EDX); | ||
exports.esi = exports.rd(regfile_1.R32.ESI); | ||
exports.edi = exports.rd(regfile_1.R32.EDI); | ||
exports.ebp = exports.rd(regfile_1.R32.EBP); | ||
exports.esp = exports.rd(regfile_1.R32.ESP); | ||
exports.r8d = exports.rd(regfile_1.R32.R8D); | ||
exports.r9d = exports.rd(regfile_1.R32.R9D); | ||
exports.r10d = exports.rd(regfile_1.R32.R10D); | ||
exports.r11d = exports.rd(regfile_1.R32.R11D); | ||
exports.r12d = exports.rd(regfile_1.R32.R12D); | ||
exports.r13d = exports.rd(regfile_1.R32.R13D); | ||
exports.r14d = exports.rd(regfile_1.R32.R14D); | ||
exports.r15d = exports.rd(regfile_1.R32.R15D); | ||
exports.rax = exports.rq(regfile_1.R64.RAX); | ||
exports.rcx = exports.rq(regfile_1.R64.RCX); | ||
exports.rdx = exports.rq(regfile_1.R64.RDX); | ||
exports.rbx = exports.rq(regfile_1.R64.RBX); | ||
exports.rsp = exports.rq(regfile_1.R64.RSP); | ||
exports.rbp = exports.rq(regfile_1.R64.RBP); | ||
exports.rsi = exports.rq(regfile_1.R64.RSI); | ||
exports.rdi = exports.rq(regfile_1.R64.RDI); | ||
exports.r8 = exports.rq(regfile_1.R64.R8); | ||
exports.r9 = exports.rq(regfile_1.R64.R9); | ||
exports.r10 = exports.rq(regfile_1.R64.R10); | ||
exports.r11 = exports.rq(regfile_1.R64.R11); | ||
exports.r12 = exports.rq(regfile_1.R64.R12); | ||
exports.r13 = exports.rq(regfile_1.R64.R13); | ||
exports.r14 = exports.rq(regfile_1.R64.R14); | ||
exports.r15 = exports.rq(regfile_1.R64.R15); | ||
exports.rip = new RegisterRip; | ||
exports.es = exports.rs(regfile_1.SEG.ES); | ||
exports.cs = exports.rs(regfile_1.SEG.CS); | ||
exports.ss = exports.rs(regfile_1.SEG.SS); | ||
exports.ds = exports.rs(regfile_1.SEG.DS); | ||
exports.fs = exports.rs(regfile_1.SEG.FS); | ||
exports.gs = exports.rs(regfile_1.SEG.GS); | ||
var RegisterK = (function (_super) { | ||
__extends(RegisterK, _super); | ||
function RegisterK(id) { | ||
_super.call(this, id, operand_1.SIZE.Q); | ||
this.name = 'k' + id; | ||
} | ||
return RegisterK; | ||
}(Register)); | ||
exports.RegisterK = RegisterK; | ||
var RegisterCr = (function (_super) { | ||
__extends(RegisterCr, _super); | ||
function RegisterCr(id) { | ||
_super.call(this, id, operand_1.SIZE.Q); | ||
this.name = 'cr' + id; | ||
} | ||
return RegisterCr; | ||
}(Register)); | ||
exports.RegisterCr = RegisterCr; | ||
var RegisterDr = (function (_super) { | ||
__extends(RegisterDr, _super); | ||
function RegisterDr(id) { | ||
_super.call(this, id, operand_1.SIZE.Q); | ||
this.name = 'dr' + id; | ||
} | ||
return RegisterDr; | ||
}(Register)); | ||
exports.RegisterDr = RegisterDr; | ||
var Scale = (function (_super) { | ||
@@ -453,2 +412,29 @@ __extends(Scale, _super); | ||
exports.Memory64 = Memory64; | ||
var Memory128 = (function (_super) { | ||
__extends(Memory128, _super); | ||
function Memory128() { | ||
_super.apply(this, arguments); | ||
this.size = operand_1.SIZE.O; | ||
} | ||
return Memory128; | ||
}(Memory)); | ||
exports.Memory128 = Memory128; | ||
var Memory256 = (function (_super) { | ||
__extends(Memory256, _super); | ||
function Memory256() { | ||
_super.apply(this, arguments); | ||
this.size = operand_1.SIZE.H; | ||
} | ||
return Memory256; | ||
}(Memory)); | ||
exports.Memory256 = Memory256; | ||
var Memory512 = (function (_super) { | ||
__extends(Memory512, _super); | ||
function Memory512() { | ||
_super.apply(this, arguments); | ||
this.size = operand_1.SIZE.I; | ||
} | ||
return Memory512; | ||
}(Memory)); | ||
exports.Memory512 = Memory512; | ||
var Operands = (function (_super) { | ||
@@ -467,20 +453,2 @@ __extends(Operands, _super); | ||
}; | ||
Operands.prototype.getRegisterOperand = function (dst_first) { | ||
if (dst_first === void 0) { dst_first = true; } | ||
var _a = this.list, dst = _a[0], src = _a[1]; | ||
var first, second; | ||
if (dst_first) { | ||
first = dst; | ||
second = src; | ||
} | ||
else { | ||
first = src; | ||
second = dst; | ||
} | ||
if (first instanceof Register) | ||
return first; | ||
if (second instanceof Register) | ||
return second; | ||
return null; | ||
}; | ||
Operands.prototype.hasImmediate = function () { | ||
@@ -490,7 +458,16 @@ return !!this.getImmediate(); | ||
Operands.prototype.hasExtendedRegister = function () { | ||
var _a = this.list, dst = _a[0], src = _a[1]; | ||
if (dst && dst.reg() && dst.reg().isExtended()) | ||
return true; | ||
if (src && src.reg() && src.reg().isExtended()) | ||
return true; | ||
for (var _i = 0, _a = this.list; _i < _a.length; _i++) { | ||
var op = _a[_i]; | ||
if (op instanceof o.Register) { | ||
if (op.idSize() > 3) | ||
return true; | ||
} | ||
else if (op instanceof o.Memory) { | ||
var mem = op; | ||
if (mem.base && (mem.base.idSize() > 3)) | ||
return true; | ||
if (mem.index && (mem.index.idSize() > 3)) | ||
return true; | ||
} | ||
} | ||
return false; | ||
@@ -501,1 +478,112 @@ }; | ||
exports.Operands = Operands; | ||
function validateRegId(id, min, max, Clazz) { | ||
if (typeof id !== 'number') | ||
throw TypeError(Clazz.name + ' register ID must be a number.'); | ||
if (id < min) | ||
throw TypeError(Clazz.name + " register ID must be at least " + min + "."); | ||
if (id > max) | ||
throw TypeError(Clazz.name + " register ID must be at most " + max + "."); | ||
} | ||
function createRegisterGenerator(Clazz, min_id, max_id) { | ||
if (min_id === void 0) { min_id = 0; } | ||
if (max_id === void 0) { max_id = 15; } | ||
var cache; | ||
return function (id) { | ||
validateRegId(id, min_id, max_id, Clazz); | ||
if (!cache) | ||
cache = new Array(max_id + 1); | ||
if (!cache[id]) | ||
cache[id] = new Clazz(id); | ||
return cache[id]; | ||
}; | ||
} | ||
exports.rb = createRegisterGenerator(Register8, 0, 15); | ||
exports.rw = createRegisterGenerator(Register16, 0, 15); | ||
exports.rd = createRegisterGenerator(Register32, 0, 15); | ||
exports.rq = createRegisterGenerator(Register64, 0, 15); | ||
exports.r = exports.rq; | ||
exports.seg = createRegisterGenerator(RegisterSegment, 0, 15); | ||
exports.mm = createRegisterGenerator(RegisterMm, 0, 15); | ||
exports.st = createRegisterGenerator(RegisterSt, 0, 7); | ||
exports.xmm = createRegisterGenerator(RegisterXmm, 0, 31); | ||
exports.ymm = createRegisterGenerator(RegisterYmm, 0, 31); | ||
exports.zmm = createRegisterGenerator(RegisterZmm, 0, 31); | ||
exports.k = createRegisterGenerator(RegisterK, 0, 7); | ||
exports.bnd = createRegisterGenerator(RegisterBounds, 0, 3); | ||
exports.cr = createRegisterGenerator(RegisterCr, 0, 15); | ||
exports.dr = createRegisterGenerator(RegisterDr, 0, 15); | ||
exports.al = exports.rb(regfile_1.R8.AL); | ||
exports.bl = exports.rb(regfile_1.R8.BL); | ||
exports.cl = exports.rb(regfile_1.R8.CL); | ||
exports.dl = exports.rb(regfile_1.R8.DL); | ||
exports.sil = exports.rb(regfile_1.R8.SIL); | ||
exports.dil = exports.rb(regfile_1.R8.DIL); | ||
exports.bpl = exports.rb(regfile_1.R8.BPL); | ||
exports.spl = exports.rb(regfile_1.R8.SPL); | ||
exports.r8b = exports.rb(regfile_1.R8.R8B); | ||
exports.r9b = exports.rb(regfile_1.R8.R9B); | ||
exports.r10b = exports.rb(regfile_1.R8.R10B); | ||
exports.r11b = exports.rb(regfile_1.R8.R11B); | ||
exports.r12b = exports.rb(regfile_1.R8.R12B); | ||
exports.r13b = exports.rb(regfile_1.R8.R13B); | ||
exports.r14b = exports.rb(regfile_1.R8.R14B); | ||
exports.r15b = exports.rb(regfile_1.R8.R15B); | ||
exports.ah = new Register8High(regfile_1.R8H.AH); | ||
exports.bh = new Register8High(regfile_1.R8H.BH); | ||
exports.ch = new Register8High(regfile_1.R8H.CH); | ||
exports.dh = new Register8High(regfile_1.R8H.DH); | ||
exports.ax = exports.rw(regfile_1.R16.AX); | ||
exports.bx = exports.rw(regfile_1.R16.BX); | ||
exports.cx = exports.rw(regfile_1.R16.CX); | ||
exports.dx = exports.rw(regfile_1.R16.DX); | ||
exports.si = exports.rw(regfile_1.R16.SI); | ||
exports.di = exports.rw(regfile_1.R16.DI); | ||
exports.bp = exports.rw(regfile_1.R16.BP); | ||
exports.sp = exports.rw(regfile_1.R16.SP); | ||
exports.r8w = exports.rw(regfile_1.R16.R8W); | ||
exports.r9w = exports.rw(regfile_1.R16.R9W); | ||
exports.r10w = exports.rw(regfile_1.R16.R10W); | ||
exports.r11w = exports.rw(regfile_1.R16.R11W); | ||
exports.r12w = exports.rw(regfile_1.R16.R12W); | ||
exports.r13w = exports.rw(regfile_1.R16.R13W); | ||
exports.r14w = exports.rw(regfile_1.R16.R14W); | ||
exports.r15w = exports.rw(regfile_1.R16.R15W); | ||
exports.eax = exports.rd(regfile_1.R32.EAX); | ||
exports.ebx = exports.rd(regfile_1.R32.EBX); | ||
exports.ecx = exports.rd(regfile_1.R32.ECX); | ||
exports.edx = exports.rd(regfile_1.R32.EDX); | ||
exports.esi = exports.rd(regfile_1.R32.ESI); | ||
exports.edi = exports.rd(regfile_1.R32.EDI); | ||
exports.ebp = exports.rd(regfile_1.R32.EBP); | ||
exports.esp = exports.rd(regfile_1.R32.ESP); | ||
exports.r8d = exports.rd(regfile_1.R32.R8D); | ||
exports.r9d = exports.rd(regfile_1.R32.R9D); | ||
exports.r10d = exports.rd(regfile_1.R32.R10D); | ||
exports.r11d = exports.rd(regfile_1.R32.R11D); | ||
exports.r12d = exports.rd(regfile_1.R32.R12D); | ||
exports.r13d = exports.rd(regfile_1.R32.R13D); | ||
exports.r14d = exports.rd(regfile_1.R32.R14D); | ||
exports.r15d = exports.rd(regfile_1.R32.R15D); | ||
exports.rax = exports.rq(regfile_1.R64.RAX); | ||
exports.rcx = exports.rq(regfile_1.R64.RCX); | ||
exports.rdx = exports.rq(regfile_1.R64.RDX); | ||
exports.rbx = exports.rq(regfile_1.R64.RBX); | ||
exports.rsp = exports.rq(regfile_1.R64.RSP); | ||
exports.rbp = exports.rq(regfile_1.R64.RBP); | ||
exports.rsi = exports.rq(regfile_1.R64.RSI); | ||
exports.rdi = exports.rq(regfile_1.R64.RDI); | ||
exports.r8 = exports.rq(regfile_1.R64.R8); | ||
exports.r9 = exports.rq(regfile_1.R64.R9); | ||
exports.r10 = exports.rq(regfile_1.R64.R10); | ||
exports.r11 = exports.rq(regfile_1.R64.R11); | ||
exports.r12 = exports.rq(regfile_1.R64.R12); | ||
exports.r13 = exports.rq(regfile_1.R64.R13); | ||
exports.r14 = exports.rq(regfile_1.R64.R14); | ||
exports.r15 = exports.rq(regfile_1.R64.R15); | ||
exports.rip = new RegisterRip; | ||
exports.es = exports.seg(regfile_1.SEG.ES); | ||
exports.cs = exports.seg(regfile_1.SEG.CS); | ||
exports.ss = exports.seg(regfile_1.SEG.SS); | ||
exports.ds = exports.seg(regfile_1.SEG.DS); | ||
exports.fs = exports.seg(regfile_1.SEG.FS); | ||
exports.gs = exports.seg(regfile_1.SEG.GS); |
@@ -83,3 +83,3 @@ import {R64, R32, R16, R8, R8H, SEG, X87, XMM, YMM, ZMM} from './regfile'; | ||
disp(value: o.Tvariable): Memory { | ||
disp(value: o.Tvariable|ii.Expression): Memory { | ||
return (new Memory).ref(this).disp(value); | ||
@@ -92,9 +92,7 @@ } | ||
} | ||
get3bitId() { | ||
return this.id & 0b111; | ||
} | ||
} | ||
export class Register8 extends Register { | ||
export class RegisterGP extends Register {} | ||
export class Register8 extends RegisterGP { | ||
constructor(id: number) { | ||
@@ -113,3 +111,3 @@ super(id, SIZE.B); | ||
export class Register32 extends Register { | ||
export class Register32 extends RegisterGP { | ||
constructor(id: number) { | ||
@@ -120,3 +118,3 @@ super(id, SIZE.D); | ||
export class Register64 extends Register { | ||
export class Register64 extends RegisterGP { | ||
constructor(id: number) { | ||
@@ -127,3 +125,3 @@ super(id, SIZE.Q); | ||
export class Register128 extends Register { | ||
export class Register128 extends RegisterGP { | ||
constructor(id: number) { | ||
@@ -134,3 +132,3 @@ super(id, SIZE.O); | ||
export class Register256 extends Register { | ||
export class Register256 extends RegisterGP { | ||
constructor(id: number) { | ||
@@ -141,3 +139,3 @@ super(id, SIZE.H); | ||
export class Register512 extends Register { | ||
export class Register512 extends RegisterGP { | ||
constructor(id: number) { | ||
@@ -148,23 +146,48 @@ super(id, SIZE.I); | ||
export class RegisterRip extends Register64 { | ||
export class RegisterRip extends Register { | ||
name = 'rip'; | ||
constructor() { | ||
super(0); | ||
super(0, SIZE.Q); | ||
} | ||
} | ||
export class RegisterSegment extends Register16 { | ||
export class RegisterSegment extends Register { | ||
constructor(id) { | ||
super(id, SIZE.W); | ||
} | ||
} | ||
export class RegisterBounds extends Register { | ||
constructor(id) { | ||
super(id, SIZE.O); | ||
} | ||
} | ||
export class RegisterMmx extends Register128 { | ||
export class RegisterFloatingPoint extends Register { | ||
} | ||
export class RegisterMm extends RegisterFloatingPoint { | ||
constructor(id: number) { | ||
super(id); | ||
this.name = 'mmx' + id; | ||
super(id, SIZE.O); | ||
this.name = 'mm' + id; | ||
} | ||
} | ||
export class RegisterXmm extends Register128 { | ||
export class RegisterSt extends RegisterFloatingPoint { | ||
constructor(id: number) { | ||
super(id); | ||
super(id, SIZE.T); | ||
this.name = 'st' + id; | ||
} | ||
} | ||
export class RegisterVector extends Register { | ||
} | ||
export class RegisterXmm extends RegisterVector { | ||
constructor(id: number) { | ||
super(id, SIZE.O); | ||
this.name = 'xmm' + id; | ||
@@ -174,5 +197,5 @@ } | ||
export class RegisterYmm extends Register256 { | ||
export class RegisterYmm extends RegisterVector { | ||
constructor(id: number) { | ||
super(id); | ||
super(id, SIZE.H); | ||
this.name = 'ymm' + id; | ||
@@ -182,5 +205,5 @@ } | ||
export class RegisterZmm extends Register512 { | ||
export class RegisterZmm extends RegisterVector { | ||
constructor(id: number) { | ||
super(id); | ||
super(id, SIZE.I); | ||
this.name = 'zmm' + id; | ||
@@ -190,121 +213,24 @@ } | ||
export class RegisterK extends Register { | ||
constructor(id: number) { | ||
super(id, SIZE.Q); | ||
this.name = 'k' + id; | ||
} | ||
} | ||
function validateRegId(id: number, min, max, Clazz) { | ||
if(typeof id !== 'number') throw TypeError(Clazz.name + ' register ID must be a number.'); | ||
if(id < min) throw TypeError(`${Clazz.name} register ID must be at least ${min}.`); | ||
if(id > max) throw TypeError(`${Clazz.name} register ID must be at most ${max}.`); | ||
export class RegisterCr extends Register { // Control registers. | ||
constructor(id: number) { | ||
super(id, SIZE.Q); | ||
this.name = 'cr' + id; | ||
} | ||
} | ||
function createRegisterGenerator<T>(Clazz, min_id = 0, max_id = 15) { | ||
var cache: T[]; | ||
return function(id: number): T { | ||
validateRegId(id, min_id, max_id, Clazz); | ||
if(!cache) cache = new Array(max_id + 1); | ||
if(!cache[id]) cache[id] = new Clazz(id); | ||
return cache[id]; | ||
}; | ||
export class RegisterDr extends Register { // Debug registers. | ||
constructor(id: number) { | ||
super(id, SIZE.Q); | ||
this.name = 'dr' + id; | ||
} | ||
} | ||
export var rb = createRegisterGenerator<Register8>(Register8, 0, 15); | ||
export var rw = createRegisterGenerator<Register16>(Register16, 0, 15); | ||
export var rd = createRegisterGenerator<Register32>(Register32, 0, 15); | ||
export var rq = createRegisterGenerator<Register64>(Register64, 0, 15); | ||
export var r = rq; | ||
export var rs = createRegisterGenerator<RegisterSegment>(RegisterSegment, 0, 15); | ||
// SSE registers are lazy-created when used using function: `xmm(3)`; instead of pre-generated objects: xmm3. | ||
export var mmx = createRegisterGenerator<RegisterMmx>(RegisterMmx, 0, 15); | ||
export var xmm = createRegisterGenerator<RegisterXmm>(RegisterXmm, 0, 31); | ||
export var ymm = createRegisterGenerator<RegisterYmm>(RegisterYmm, 0, 31); | ||
export var zmm = createRegisterGenerator<RegisterZmm>(RegisterZmm, 0, 31); | ||
export var al = rb(R8.AL); | ||
export var bl = rb(R8.BL); | ||
export var cl = rb(R8.CL); | ||
export var dl = rb(R8.DL); | ||
export var sil = rb(R8.SIL); | ||
export var dil = rb(R8.DIL); | ||
export var bpl = rb(R8.BPL); | ||
export var spl = rb(R8.SPL); | ||
export var r8b = rb(R8.R8B); | ||
export var r9b = rb(R8.R9B); | ||
export var r10b = rb(R8.R10B); | ||
export var r11b = rb(R8.R11B); | ||
export var r12b = rb(R8.R12B); | ||
export var r13b = rb(R8.R13B); | ||
export var r14b = rb(R8.R14B); | ||
export var r15b = rb(R8.R15B); | ||
export var ah = new Register8High(R8H.AH); | ||
export var bh = new Register8High(R8H.BH); | ||
export var ch = new Register8High(R8H.CH); | ||
export var dh = new Register8High(R8H.DH); | ||
export var ax = rw(R16.AX); | ||
export var bx = rw(R16.BX); | ||
export var cx = rw(R16.CX); | ||
export var dx = rw(R16.DX); | ||
export var si = rw(R16.SI); | ||
export var di = rw(R16.DI); | ||
export var bp = rw(R16.BP); | ||
export var sp = rw(R16.SP); | ||
export var r8w = rw(R16.R8W); | ||
export var r9w = rw(R16.R9W); | ||
export var r10w = rw(R16.R10W); | ||
export var r11w = rw(R16.R11W); | ||
export var r12w = rw(R16.R12W); | ||
export var r13w = rw(R16.R13W); | ||
export var r14w = rw(R16.R14W); | ||
export var r15w = rw(R16.R15W); | ||
export var eax = rd(R32.EAX); | ||
export var ebx = rd(R32.EBX); | ||
export var ecx = rd(R32.ECX); | ||
export var edx = rd(R32.EDX); | ||
export var esi = rd(R32.ESI); | ||
export var edi = rd(R32.EDI); | ||
export var ebp = rd(R32.EBP); | ||
export var esp = rd(R32.ESP); | ||
export var r8d = rd(R32.R8D); | ||
export var r9d = rd(R32.R9D); | ||
export var r10d = rd(R32.R10D); | ||
export var r11d = rd(R32.R11D); | ||
export var r12d = rd(R32.R12D); | ||
export var r13d = rd(R32.R13D); | ||
export var r14d = rd(R32.R14D); | ||
export var r15d = rd(R32.R15D); | ||
export var rax = rq(R64.RAX); | ||
export var rcx = rq(R64.RCX); | ||
export var rdx = rq(R64.RDX); | ||
export var rbx = rq(R64.RBX); | ||
export var rsp = rq(R64.RSP); | ||
export var rbp = rq(R64.RBP); | ||
export var rsi = rq(R64.RSI); | ||
export var rdi = rq(R64.RDI); | ||
export var r8 = rq(R64.R8); | ||
export var r9 = rq(R64.R9); | ||
export var r10 = rq(R64.R10); | ||
export var r11 = rq(R64.R11); | ||
export var r12 = rq(R64.R12); | ||
export var r13 = rq(R64.R13); | ||
export var r14 = rq(R64.R14); | ||
export var r15 = rq(R64.R15); | ||
export var rip = new RegisterRip; | ||
export var es = rs(SEG.ES); | ||
export var cs = rs(SEG.CS); | ||
export var ss = rs(SEG.SS); | ||
export var ds = rs(SEG.DS); | ||
export var fs = rs(SEG.FS); | ||
export var gs = rs(SEG.GS); | ||
// # Scale | ||
@@ -440,2 +366,14 @@ // | ||
export class Memory128 extends Memory { | ||
size = SIZE.O; | ||
} | ||
export class Memory256 extends Memory { | ||
size = SIZE.H; | ||
} | ||
export class Memory512 extends Memory { | ||
size = SIZE.I; | ||
} | ||
export type TInstructionOperand = Register|Memory|o.Immediate|Relative; // `Tnumber` gets converted to `Immediate` or `Relative` to current instruction. `Relative` is converted to `Immediate`. | ||
@@ -453,16 +391,16 @@ | ||
getRegisterOperand(dst_first = true): Register { | ||
var [dst, src] = this.list; | ||
var first, second; | ||
if(dst_first) { | ||
first = dst; | ||
second = src; | ||
} else { | ||
first = src; | ||
second = dst; | ||
} | ||
if(first instanceof Register) return first as Register; | ||
if(second instanceof Register) return second as Register; | ||
return null; | ||
} | ||
// getRegisterOperand(dst_first = true): Register { | ||
// var [dst, src] = this.list; | ||
// var first, second; | ||
// if(dst_first) { | ||
// first = dst; | ||
// second = src; | ||
// } else { | ||
// first = src; | ||
// second = dst; | ||
// } | ||
// if(first instanceof Register) return first as Register; | ||
// if(second instanceof Register) return second as Register; | ||
// return null; | ||
// } | ||
@@ -474,7 +412,138 @@ hasImmediate(): boolean { | ||
hasExtendedRegister(): boolean { | ||
var [dst, src] = this.list; | ||
if(dst && dst.reg() && (dst.reg() as Register).isExtended()) return true; | ||
if(src && src.reg() && (src.reg() as Register).isExtended()) return true; | ||
for(var op of this.list) { | ||
if(op instanceof o.Register) { | ||
if((op as o.Register).idSize() > 3) return true; | ||
} else if(op instanceof o.Memory) { | ||
var mem = op as Memory; | ||
if(mem.base && (mem.base.idSize() > 3)) return true; | ||
if(mem.index && (mem.index.idSize() > 3)) return true; | ||
} | ||
} | ||
return false; | ||
} | ||
} | ||
// ## Export Registers | ||
function validateRegId(id: number, min, max, Clazz) { | ||
if(typeof id !== 'number') throw TypeError(Clazz.name + ' register ID must be a number.'); | ||
if(id < min) throw TypeError(`${Clazz.name} register ID must be at least ${min}.`); | ||
if(id > max) throw TypeError(`${Clazz.name} register ID must be at most ${max}.`); | ||
} | ||
function createRegisterGenerator<T>(Clazz, min_id = 0, max_id = 15) { | ||
var cache: T[]; | ||
return function(id: number): T { | ||
validateRegId(id, min_id, max_id, Clazz); | ||
if(!cache) cache = new Array(max_id + 1); | ||
if(!cache[id]) cache[id] = new Clazz(id); | ||
return cache[id]; | ||
}; | ||
} | ||
export var rb = createRegisterGenerator<Register8>(Register8, 0, 15); | ||
export var rw = createRegisterGenerator<Register16>(Register16, 0, 15); | ||
export var rd = createRegisterGenerator<Register32>(Register32, 0, 15); | ||
export var rq = createRegisterGenerator<Register64>(Register64, 0, 15); | ||
export var r = rq; | ||
export var seg = createRegisterGenerator<RegisterSegment>(RegisterSegment, 0, 15); | ||
export var mm = createRegisterGenerator<RegisterMm>(RegisterMm, 0, 15); | ||
export var st = createRegisterGenerator<RegisterSt>(RegisterSt, 0, 7); | ||
export var xmm = createRegisterGenerator<RegisterXmm>(RegisterXmm, 0, 31); | ||
export var ymm = createRegisterGenerator<RegisterYmm>(RegisterYmm, 0, 31); | ||
export var zmm = createRegisterGenerator<RegisterZmm>(RegisterZmm, 0, 31); | ||
export var k = createRegisterGenerator<RegisterK>(RegisterK, 0, 7); | ||
export var bnd = createRegisterGenerator<RegisterBounds>(RegisterBounds, 0, 3); | ||
export var cr = createRegisterGenerator<RegisterCr>(RegisterCr, 0, 15); | ||
export var dr = createRegisterGenerator<RegisterDr>(RegisterDr, 0, 15); | ||
export var al = rb(R8.AL); | ||
export var bl = rb(R8.BL); | ||
export var cl = rb(R8.CL); | ||
export var dl = rb(R8.DL); | ||
export var sil = rb(R8.SIL); | ||
export var dil = rb(R8.DIL); | ||
export var bpl = rb(R8.BPL); | ||
export var spl = rb(R8.SPL); | ||
export var r8b = rb(R8.R8B); | ||
export var r9b = rb(R8.R9B); | ||
export var r10b = rb(R8.R10B); | ||
export var r11b = rb(R8.R11B); | ||
export var r12b = rb(R8.R12B); | ||
export var r13b = rb(R8.R13B); | ||
export var r14b = rb(R8.R14B); | ||
export var r15b = rb(R8.R15B); | ||
export var ah = new Register8High(R8H.AH); | ||
export var bh = new Register8High(R8H.BH); | ||
export var ch = new Register8High(R8H.CH); | ||
export var dh = new Register8High(R8H.DH); | ||
export var ax = rw(R16.AX); | ||
export var bx = rw(R16.BX); | ||
export var cx = rw(R16.CX); | ||
export var dx = rw(R16.DX); | ||
export var si = rw(R16.SI); | ||
export var di = rw(R16.DI); | ||
export var bp = rw(R16.BP); | ||
export var sp = rw(R16.SP); | ||
export var r8w = rw(R16.R8W); | ||
export var r9w = rw(R16.R9W); | ||
export var r10w = rw(R16.R10W); | ||
export var r11w = rw(R16.R11W); | ||
export var r12w = rw(R16.R12W); | ||
export var r13w = rw(R16.R13W); | ||
export var r14w = rw(R16.R14W); | ||
export var r15w = rw(R16.R15W); | ||
export var eax = rd(R32.EAX); | ||
export var ebx = rd(R32.EBX); | ||
export var ecx = rd(R32.ECX); | ||
export var edx = rd(R32.EDX); | ||
export var esi = rd(R32.ESI); | ||
export var edi = rd(R32.EDI); | ||
export var ebp = rd(R32.EBP); | ||
export var esp = rd(R32.ESP); | ||
export var r8d = rd(R32.R8D); | ||
export var r9d = rd(R32.R9D); | ||
export var r10d = rd(R32.R10D); | ||
export var r11d = rd(R32.R11D); | ||
export var r12d = rd(R32.R12D); | ||
export var r13d = rd(R32.R13D); | ||
export var r14d = rd(R32.R14D); | ||
export var r15d = rd(R32.R15D); | ||
export var rax = rq(R64.RAX); | ||
export var rcx = rq(R64.RCX); | ||
export var rdx = rq(R64.RDX); | ||
export var rbx = rq(R64.RBX); | ||
export var rsp = rq(R64.RSP); | ||
export var rbp = rq(R64.RBP); | ||
export var rsi = rq(R64.RSI); | ||
export var rdi = rq(R64.RDI); | ||
export var r8 = rq(R64.R8); | ||
export var r9 = rq(R64.R9); | ||
export var r10 = rq(R64.R10); | ||
export var r11 = rq(R64.R11); | ||
export var r12 = rq(R64.R12); | ||
export var r13 = rq(R64.R13); | ||
export var r14 = rq(R64.R14); | ||
export var r15 = rq(R64.R15); | ||
export var rip = new RegisterRip; | ||
export var es = seg(SEG.ES); | ||
export var cs = seg(SEG.CS); | ||
export var ss = seg(SEG.SS); | ||
export var ds = seg(SEG.DS); | ||
export var fs = seg(SEG.FS); | ||
export var gs = seg(SEG.GS); | ||
@@ -126,2 +126,94 @@ "use strict"; | ||
exports.PrefixRex = PrefixRex; | ||
var PrefixVex = (function (_super) { | ||
__extends(PrefixVex, _super); | ||
function PrefixVex(vexdef, R, X, B, vvvv) { | ||
if (R === void 0) { R = 1; } | ||
if (X === void 0) { X = 1; } | ||
if (B === void 0) { B = 1; } | ||
if (vvvv === void 0) { vvvv = 15; } | ||
_super.call(this); | ||
this.bytes = 2; | ||
this.R = 1; | ||
this.X = 1; | ||
this.B = 1; | ||
this.W = 1; | ||
this.vvvv = 15; | ||
this.mmmmm = 0; | ||
this.L = 0; | ||
this.pp = 0; | ||
this.L = vexdef.L; | ||
this.mmmmm = vexdef.mmmmm; | ||
this.pp = vexdef.pp; | ||
this.W = vexdef.W; | ||
if (vexdef.WIG) | ||
this.W = 0; | ||
this.R = R; | ||
this.X = X; | ||
this.B = B; | ||
this.vvvv = vvvv; | ||
if ((this.X === 0) || (this.B === 0) || | ||
((this.W === 0) && !vexdef.WIG) || | ||
(this.mmmmm === PrefixVex.MMMMM.x0F3A) || (this.mmmmm === PrefixVex.MMMMM.x0F38)) | ||
this.promoteTo3bytes(); | ||
} | ||
PrefixVex.prototype.promoteTo3bytes = function () { | ||
this.bytes = 3; | ||
}; | ||
PrefixVex.prototype.write = function (arr) { | ||
if (this.bytes === 2) { | ||
arr.push(197); | ||
arr.push((this.R << 7) | (this.vvvv << 3) | (this.L << 2) | this.pp); | ||
} | ||
else { | ||
arr.push(196); | ||
arr.push((this.R << 7) | (this.X << 6) | (this.B << 5) | this.mmmmm); | ||
arr.push((this.W << 7) | (this.vvvv << 3) | (this.L << 2) | this.pp); | ||
} | ||
return arr; | ||
}; | ||
PrefixVex.PP = { | ||
x66: 1, | ||
xF2: 3, | ||
xF3: 2, | ||
}; | ||
PrefixVex.MMMMM = { | ||
x0F38: 2, | ||
x0F3A: 3, | ||
x0F: 1, | ||
}; | ||
return PrefixVex; | ||
}(Prefix)); | ||
exports.PrefixVex = PrefixVex; | ||
var PrefixEvex = (function (_super) { | ||
__extends(PrefixEvex, _super); | ||
function PrefixEvex(evexdef) { | ||
_super.call(this); | ||
this.R = 1; | ||
this.X = 1; | ||
this.B = 1; | ||
this.W = 1; | ||
this.vvvv = 15; | ||
this.pp = 0; | ||
this.mm = 0; | ||
this.Rp = 1; | ||
this.z = 0; | ||
this.LL = 0; | ||
this.b = 0; | ||
this.Vp = 1; | ||
this.aaa = 0; | ||
this.LL = evexdef.L; | ||
this.mm = evexdef.mmmmm & 3; | ||
this.pp = evexdef.pp; | ||
this.W = evexdef.W; | ||
} | ||
PrefixEvex.prototype.write = function (arr) { | ||
arr.push(0x62); | ||
arr.push((this.R << 7) | (this.X << 6) | (this.B << 5) | (this.Rp << 4) | this.mm); | ||
arr.push((this.W << 7) | (this.vvvv << 3) | 4 | this.pp); | ||
arr.push((this.z << 7) | (this.LL << 5) | (this.b << 4) | (this.Vp << 3) | this.aaa); | ||
return arr; | ||
}; | ||
return PrefixEvex; | ||
}(Prefix)); | ||
exports.PrefixEvex = PrefixEvex; | ||
var Opcode = (function (_super) { | ||
@@ -128,0 +220,0 @@ __extends(Opcode, _super); |
150
x86/parts.ts
import {R64, R32, R16, R8} from './regfile'; | ||
import * as oo from '../operand'; | ||
import * as o from './operand'; | ||
import * as d from './def'; | ||
@@ -149,3 +150,152 @@ | ||
// ### 2-byte VEX: | ||
// 76543210 | ||
// 11000100 | ||
// | ||
// 76543210 | ||
// ||||||pp ---> pp | ||
// |||||L -----> L | ||
// |vvvv ------> vvvv | ||
// R ----------> R | ||
// | ||
// ### 3-byte VEX: | ||
// 76543210 | ||
// 11000101 | ||
// | ||
// 76543210 | ||
// |||mmmmm ---> mmmmm | ||
// ||B --------> B | ||
// |X ---------> X | ||
// R ----------> R | ||
// | ||
// 76543210 | ||
// ||||||pp ---> pp | ||
// |||||L -----> L | ||
// |vvvv ------> vvvv | ||
// W ----------> W | ||
export class PrefixVex extends Prefix { | ||
static PP = { | ||
x66: 0b01, | ||
xF2: 0b11, | ||
xF3: 0b10, | ||
}; | ||
static MMMMM = { | ||
x0F38: 0b00010, | ||
x0F3A: 0b00011, | ||
x0F: 0b00001, | ||
}; | ||
bytes = 2; // VEX can be either 2 or 3 bytes. | ||
// R, X, B, W and vvvv are inverted. | ||
R = 1; // Must be 1, if not used, otherwise wrong instruction. | ||
X = 1; // Must be 1, if not used, otherwise wrong instruction. | ||
B = 1; | ||
W = 1; | ||
vvvv = 0b1111; // must be 0b1111, if not used, otherwise CPU will #UD | ||
mmmmm = 0; | ||
L = 0; | ||
pp = 0; | ||
constructor(vexdef: d.IVexDefinition, R = 1, X = 1, B = 1, vvvv = 0b1111) { | ||
super(); | ||
this.L = vexdef.L; | ||
this.mmmmm = vexdef.mmmmm; | ||
this.pp = vexdef.pp; | ||
this.W = vexdef.W; | ||
if(vexdef.WIG) this.W = 0b0; // When WIG "W ignored", set to "0" to make compatible with GAS. | ||
this.R = R; | ||
this.X = X; | ||
this.B = B; | ||
this.vvvv = vvvv; | ||
if((this.X === 0) || (this.B === 0) || | ||
((this.W === 0) && !vexdef.WIG) || | ||
(this.mmmmm === PrefixVex.MMMMM.x0F3A) || (this.mmmmm === PrefixVex.MMMMM.x0F38)) | ||
this.promoteTo3bytes(); | ||
} | ||
promoteTo3bytes() { | ||
this.bytes = 3; | ||
} | ||
write(arr: number[]): number[] { | ||
if(this.bytes === 2) { // 2-byte VEX | ||
arr.push(0b11000101); // 0xC5 | ||
arr.push((this.R << 7) | (this.vvvv << 3) | (this.L << 2) | this.pp); | ||
} else { // 3-byte VEX | ||
arr.push(0b11000100); // 0xC4 | ||
arr.push((this.R << 7) | (this.X << 6) | (this.B << 5) | this.mmmmm); | ||
arr.push((this.W << 7) | (this.vvvv << 3) | (this.L << 2) | this.pp); | ||
} | ||
return arr; | ||
} | ||
} | ||
// EVEX is 4 bytes: | ||
// 62H | ||
// | ||
// 76543210 | ||
// ||||||mm ---> mm | ||
// ||||00 -----> always 00 | ||
// |||~ -------> R-prime = Rp | ||
// ||B --------> B | ||
// |X ---------> X | ||
// R ----------> R | ||
// | ||
// 76543210 | ||
// ||||||pp ---> pp | ||
// |||||1 -----> always 1 | ||
// |vvvv-------> vvvv | ||
// W ----------> W | ||
// | ||
// 76543210 | ||
// |||||aaa ---> aaa | ||
// ||||~ ------> V-prime = Vp | ||
// |||b -------> b | ||
// |LL --------> LL | ||
// z ----------> z | ||
export class PrefixEvex extends Prefix { | ||
// VEX includes | ||
R = 0b1; // VEX.R - Inverted | ||
X = 0b1; // VEX.X - Inverted | ||
B = 0b1; // VEX.B - Inverted | ||
W = 0b1; // VEX.W - Inverted | ||
vvvv = 0b1111; // VEX.vvvv - Inverted | ||
pp = 0b00; // VEX.pp | ||
mm = 0b00; // Low 2 bits of VEX.mmmmm | ||
// New in EVEX | ||
Rp = 0b1; // REX.R extension - Inverted | ||
z = 0b0; // Zeroing/merging | ||
LL = 0b00; // Like VEX.L but extended to 2 bits. | ||
b = 0b0; // Broadcast/RC/SAE context | ||
Vp = 0b1; // VEX.vvvv exntension - Inverted | ||
aaa = 0b000; // Opmask register ID | ||
constructor(evexdef: d.IEvexDefinition) { | ||
super(); | ||
this.LL = evexdef.L; | ||
this.mm = evexdef.mmmmm & 0b11; | ||
this.pp = evexdef.pp; | ||
this.W = evexdef.W; | ||
} | ||
write(arr: number[]): number[] { | ||
arr.push(0x62); | ||
arr.push((this.R << 7) | (this.X << 6) | (this.B << 5) | (this.Rp << 4) | this.mm); | ||
arr.push((this.W << 7) | (this.vvvv << 3) | 0b00000100 | this.pp); | ||
arr.push((this.z << 7) | (this.LL << 5) | (this.b << 4) | (this.Vp << 3) | this.aaa); | ||
return arr; | ||
} | ||
} | ||
// ## Op-code | ||
@@ -152,0 +302,0 @@ // |
@@ -7,7 +7,64 @@ "use strict"; | ||
(function (MODE) { | ||
MODE[MODE["REAL"] = 0] = "REAL"; | ||
MODE[MODE["COMPAT"] = 1] = "COMPAT"; | ||
MODE[MODE["X64"] = 2] = "X64"; | ||
MODE[MODE["REAL"] = 1] = "REAL"; | ||
MODE[MODE["PROT"] = 2] = "PROT"; | ||
MODE[MODE["COMP"] = 4] = "COMP"; | ||
MODE[MODE["LEG"] = 8] = "LEG"; | ||
MODE[MODE["OLD"] = 12] = "OLD"; | ||
MODE[MODE["X32"] = 16] = "X32"; | ||
MODE[MODE["X64"] = 32] = "X64"; | ||
MODE[MODE["X32_64"] = 48] = "X32_64"; | ||
MODE[MODE["ALL"] = 63] = "ALL"; | ||
})(exports.MODE || (exports.MODE = {})); | ||
var MODE = exports.MODE; | ||
(function (INS) { | ||
INS[INS["NONE"] = 0] = "NONE"; | ||
INS[INS["MMX"] = 1] = "MMX"; | ||
INS[INS["AES_NI"] = 2] = "AES_NI"; | ||
INS[INS["CLMUL"] = 4] = "CLMUL"; | ||
INS[INS["FMA3"] = 8] = "FMA3"; | ||
})(exports.INS || (exports.INS = {})); | ||
var INS = exports.INS; | ||
(function (EXT) { | ||
EXT[EXT["NONE"] = 0] = "NONE"; | ||
EXT[EXT["x86_64"] = 1] = "x86_64"; | ||
EXT[EXT["Intel_64"] = 2] = "Intel_64"; | ||
EXT[EXT["MPX"] = 3] = "MPX"; | ||
EXT[EXT["TXT"] = 4] = "TXT"; | ||
EXT[EXT["TSX"] = 5] = "TSX"; | ||
EXT[EXT["SGX"] = 6] = "SGX"; | ||
EXT[EXT["VT_x"] = 7] = "VT_x"; | ||
EXT[EXT["VT_d"] = 8] = "VT_d"; | ||
EXT[EXT["BMI1"] = 9] = "BMI1"; | ||
EXT[EXT["BMI2"] = 10] = "BMI2"; | ||
EXT[EXT["SHA"] = 11] = "SHA"; | ||
EXT[EXT["AES"] = 12] = "AES"; | ||
EXT[EXT["INVPCID"] = 13] = "INVPCID"; | ||
EXT[EXT["LZCNT"] = 14] = "LZCNT"; | ||
EXT[EXT["MMX"] = 15] = "MMX"; | ||
EXT[EXT["SSE"] = 16] = "SSE"; | ||
EXT[EXT["SSE2"] = 17] = "SSE2"; | ||
EXT[EXT["SSE3"] = 18] = "SSE3"; | ||
EXT[EXT["SSSE3"] = 19] = "SSSE3"; | ||
EXT[EXT["SSE4"] = 20] = "SSE4"; | ||
EXT[EXT["SSE4_1"] = 21] = "SSE4_1"; | ||
EXT[EXT["SSE4_2"] = 22] = "SSE4_2"; | ||
EXT[EXT["ADX"] = 23] = "ADX"; | ||
EXT[EXT["AVX"] = 24] = "AVX"; | ||
EXT[EXT["AVX2"] = 25] = "AVX2"; | ||
EXT[EXT["AVX3"] = 26] = "AVX3"; | ||
EXT[EXT["AVX512F"] = 26] = "AVX512F"; | ||
EXT[EXT["AVX512CDI"] = 27] = "AVX512CDI"; | ||
EXT[EXT["AVX512PFI"] = 28] = "AVX512PFI"; | ||
EXT[EXT["AVX512ERI"] = 29] = "AVX512ERI"; | ||
EXT[EXT["AVX512VL"] = 30] = "AVX512VL"; | ||
EXT[EXT["AVX512VLI"] = 31] = "AVX512VLI"; | ||
EXT[EXT["AVX512BW"] = 32] = "AVX512BW"; | ||
EXT[EXT["AVX512DQ"] = 33] = "AVX512DQ"; | ||
EXT[EXT["AVX512IFMA52"] = 34] = "AVX512IFMA52"; | ||
EXT[EXT["AVX512VBMI"] = 35] = "AVX512VBMI"; | ||
EXT[EXT["FMA3"] = 36] = "FMA3"; | ||
EXT[EXT["FMA4"] = 37] = "FMA4"; | ||
EXT[EXT["CDI"] = 38] = "CDI"; | ||
})(exports.EXT || (exports.EXT = {})); | ||
var EXT = exports.EXT; | ||
exports.M = MODE; | ||
@@ -20,2 +77,10 @@ exports.r = operand_1.Register; | ||
exports.sreg = operand_1.RegisterSegment; | ||
exports.mm = operand_1.RegisterMm; | ||
exports.st = operand_1.RegisterSt; | ||
exports.xmm = operand_1.RegisterXmm; | ||
exports.ymm = operand_1.RegisterYmm; | ||
exports.zmm = operand_1.RegisterZmm; | ||
exports.bnd = operand_1.RegisterBounds; | ||
exports.cr = operand_1.RegisterCr; | ||
exports.dr = operand_1.RegisterDr; | ||
exports.m = operand_1.Memory; | ||
@@ -26,7 +91,20 @@ exports.m8 = operand_1.Memory8; | ||
exports.m64 = operand_1.Memory64; | ||
exports.rm8 = [operand_1.Register8, operand_1.Memory]; | ||
exports.rm16 = [operand_1.Register16, operand_1.Memory]; | ||
exports.rm32 = [operand_1.Register32, operand_1.Memory]; | ||
exports.rm64 = [operand_1.Register64, operand_1.Memory]; | ||
exports.defaults = util_1.extend({}, t.defaults, { ds: table_1.S.D, lock: false, or: -1, r: false, dbit: false, rex: false, mr: true, rep: false, repne: false, pfx: null }); | ||
exports.m128 = operand_1.Memory128; | ||
exports.m256 = operand_1.Memory256; | ||
exports.m512 = operand_1.Memory512; | ||
exports.rm8 = [exports.r8, exports.m]; | ||
exports.rm16 = [exports.r16, exports.m]; | ||
exports.rm32 = [exports.r32, exports.m]; | ||
exports.rm64 = [exports.r64, exports.m]; | ||
exports.xmmm = [exports.xmm, exports.m]; | ||
exports.xmm_xmmm = [exports.xmm, exports.xmmm]; | ||
exports.xmm_xmm_xmmm = [exports.xmm, exports.xmm, exports.xmmm]; | ||
exports.ymmm = [exports.ymm, exports.m]; | ||
exports.ymm_ymmm = [exports.ymm, exports.ymmm]; | ||
exports.ymm_ymm_ymmm = [exports.ymm, exports.ymm, exports.ymmm]; | ||
exports.zmmm = [exports.zmm, exports.m]; | ||
exports.zmm_zmmm = [exports.zmm, exports.zmmm]; | ||
exports.zmm_zmm_zmmm = [exports.zmm, exports.zmm, exports.zmmm]; | ||
exports.defaults = util_1.extend({}, t.defaults, { ds: table_1.S.D, lock: false, or: -1, i: null, r: false, dbit: false, rex: null, mr: true, rep: false, repne: false, | ||
pfx: null, vex: null, evex: null, en: 'rm', mod: exports.M.ALL, ext: null }); | ||
exports.table = { | ||
@@ -33,0 +111,0 @@ cpuid: [{ o: 0x0FA2 }], |
133
x86/table.ts
import {extend} from '../util'; | ||
import {S, rel, rel8, rel16, rel32, imm, imm8, imm16, imm32, imm64, immu, immu8, immu16, immu32, immu64} from '../table'; | ||
import * as t from '../table'; | ||
import {Register, Register8, Register16, Register32, Register64, RegisterSegment, | ||
Memory, Memory8, Memory16, Memory32, Memory64} from './operand'; | ||
import { | ||
Register, Register8, Register16, Register32, Register64, | ||
RegisterMm, RegisterSt, RegisterXmm, RegisterYmm, RegisterZmm, | ||
RegisterSegment, RegisterCr, RegisterDr, RegisterBounds, | ||
Memory, Memory8, Memory16, Memory32, Memory64, Memory128, Memory256, Memory512 | ||
} from './operand'; | ||
export enum MODE { | ||
REAL, | ||
COMPAT, | ||
X64, | ||
REAL = 0b1, | ||
PROT = 0b10, | ||
COMP = 0b100, | ||
LEG = 0b1000, | ||
OLD = MODE.COMP | MODE.LEG, | ||
X32 = 0b10000, | ||
X64 = 0b100000, | ||
X32_64 = MODE.X32 | MODE.X64, | ||
ALL = MODE.REAL | MODE.PROT | MODE.COMP | MODE.LEG | MODE.X32 | MODE.X64, | ||
} | ||
// Instructins | ||
export enum INS { | ||
NONE = 0b0, | ||
MMX = 0b1, | ||
AES_NI = 0b10, | ||
CLMUL = 0b100, | ||
FMA3 = 0b1000, | ||
} | ||
// Extensions | ||
export enum EXT { | ||
NONE, | ||
x86_64, | ||
Intel_64, | ||
MPX, | ||
TXT, | ||
TSX, | ||
SGX, | ||
VT_x, | ||
VT_d, | ||
BMI1, | ||
BMI2, | ||
SHA, | ||
AES, | ||
INVPCID, | ||
LZCNT, | ||
MMX, | ||
SSE, | ||
SSE2, | ||
SSE3, | ||
SSSE3, | ||
SSE4, | ||
SSE4_1, | ||
SSE4_2, | ||
ADX, | ||
AVX, | ||
AVX2, | ||
AVX3, // AVX-512 | ||
AVX512F = EXT.AVX3, // Foundation | ||
AVX512CDI, | ||
AVX512PFI, | ||
AVX512ERI, | ||
AVX512VL, | ||
AVX512VLI, | ||
AVX512BW, | ||
AVX512DQ, | ||
AVX512IFMA52, | ||
AVX512VBMI, | ||
FMA3, | ||
FMA4, | ||
CDI, | ||
} | ||
export var M = MODE; | ||
@@ -23,2 +87,10 @@ | ||
export var sreg = RegisterSegment; | ||
export var mm = RegisterMm; | ||
export var st = RegisterSt; | ||
export var xmm = RegisterXmm; | ||
export var ymm = RegisterYmm; | ||
export var zmm = RegisterZmm; | ||
export var bnd = RegisterBounds; | ||
export var cr = RegisterCr; | ||
export var dr = RegisterDr; | ||
export var m = Memory; | ||
@@ -29,6 +101,18 @@ export var m8 = Memory8; | ||
export var m64 = Memory64; | ||
export var rm8 = [Register8, Memory]; | ||
export var rm16 = [Register16, Memory]; | ||
export var rm32 = [Register32, Memory]; | ||
export var rm64 = [Register64, Memory]; | ||
export var m128 = Memory128; | ||
export var m256 = Memory256; | ||
export var m512 = Memory512; | ||
export var rm8 = [r8, m]; | ||
export var rm16 = [r16, m]; | ||
export var rm32 = [r32, m]; | ||
export var rm64 = [r64, m]; | ||
export var xmmm = [xmm, m]; | ||
export var xmm_xmmm = [xmm, xmmm]; | ||
export var xmm_xmm_xmmm = [xmm, xmm, xmmm]; | ||
export var ymmm = [ymm, m]; | ||
export var ymm_ymmm = [ymm, ymmm]; | ||
export var ymm_ymm_ymmm = [ymm, ymm, ymmm]; | ||
export var zmmm = [zmm, m]; | ||
export var zmm_zmmm = [zmm, zmmm]; | ||
export var zmm_zmm_zmmm = [zmm, zmm, zmmm]; | ||
@@ -38,5 +122,23 @@ | ||
typeof Register8 | typeof Register16 | typeof Register32 | typeof Register64 | | ||
typeof RegisterMm | typeof RegisterSt | | ||
typeof RegisterXmm | typeof RegisterYmm | typeof RegisterZmm | | ||
typeof RegisterSegment | typeof RegisterCr | typeof RegisterDr | | ||
typeof Memory8 | typeof Memory16 | typeof Memory32 | typeof Memory64; | ||
export type TRexDefinition = [number, number, number, number]; | ||
// "VEX.DDS.LIG.66.0F38.W1" => {vvvv: 'DDS', L: 0, pp: 1, mmmmm: 2, W: 1} | ||
export interface IVexDefinition { | ||
L: number; | ||
vvvv: string; | ||
pp: number; | ||
mmmmm: number; | ||
W: number; | ||
WIG: boolean; | ||
} | ||
export interface IEvexDefinition extends IVexDefinition {} | ||
export interface Definition extends t.Definition { | ||
@@ -47,5 +149,5 @@ ds?: number; // Default size, usually 32 bits on x64, some instructions default to 64 bits. | ||
or?: number; // Opreg - 3bit opcode part in modrm.reg field, -1 if none. | ||
i?: number; // Hex octet, when +i provided in x87 floating point operations. | ||
r?: boolean; // 3bit register encoded in lowest opcode bits. | ||
dbit?: boolean; // Whether it is allowed to change `d` bit in opcode. | ||
rex?: boolean; // Whether REX prefix is mandatory for this instruction. | ||
dbit?: boolean; // Whether it is allowed to change `d` bit in opcode. `en` encoding field is ignored then. | ||
mr?: boolean; // Whether to include Mod-REG-R/M byte if deemed necessary. | ||
@@ -55,2 +157,8 @@ rep?: boolean; // REP and REPE/REPZ prefix allowed. | ||
pfx?: number[]; // List of mandatory prefixes. | ||
en?: string; // Operand encoding, e.g. "rvmr" -> (1) modmr.reg; (2) VEX.vvv; (3) modrm.rm; (4) imm8 | ||
mod?: MODE; // CPU mode | ||
rex?: TRexDefinition|boolean; // Whether REX prefix is mandatory for this instruction. Holds array of [W, R, X, B]. | ||
vex?: string|IVexDefinition; // VEX prefix definitions string as it appears in manual, e.g. "256.66.0F3A.W0" | ||
evex?: string|IEvexDefinition; // VEX prefix definitions string as it appears in manual, e.g. "256.66.0F3A.W0" | ||
ext?: EXT[]; // CPUID extensions required to run this instruction. | ||
} | ||
@@ -63,3 +171,4 @@ export type GroupDefinition = Definition[]; | ||
export var defaults: Definition = extend<Definition>({}, t.defaults, | ||
{ds: S.D, lock: false, or: -1, r: false, dbit: false, rex: false, mr: true, rep: false, repne: false, pfx: null}); | ||
{ds: S.D, lock: false, or: -1, i: null, r: false, dbit: false, rex: null, mr: true, rep: false, repne: false, | ||
pfx: null, vex: null, evex: null, en: 'rm', mod: M.ALL, ext: null}); | ||
@@ -66,0 +175,0 @@ |
@@ -12,5 +12,2 @@ "use strict"; | ||
var t = require('./table'); | ||
var util_1 = require('../../util'); | ||
exports.table = (new d.DefTable).create(t.table, t.defaults); | ||
var methods = code.Code.attachMethods({}, exports.table); | ||
var Code = (function (_super) { | ||
@@ -20,3 +17,3 @@ __extends(Code, _super); | ||
_super.apply(this, arguments); | ||
this.methods = methods; | ||
this.table = Code.table; | ||
this.ClassInstruction = instruction_1.Instruction; | ||
@@ -28,10 +25,7 @@ this.operandSize = operand_1.SIZE.D; | ||
if (name === void 0) { name = 'start'; } | ||
if (!Code._methodsAdded) { | ||
util_1.extend(Code.prototype, methods); | ||
Code._methodsAdded = true; | ||
} | ||
var newcode = new Code(name); | ||
newcode.addMethods(); | ||
return newcode; | ||
}; | ||
Code.table = exports.table; | ||
Code.table = new d.DefTable(t.table, t.defaults); | ||
Code._methodsAdded = false; | ||
@@ -38,0 +32,0 @@ return Code; |
@@ -9,9 +9,5 @@ import {SIZE, TUiOperand} from '../../operand'; | ||
export const table = (new d.DefTable).create(t.table, t.defaults); | ||
const methods = code.Code.attachMethods({} as any, table); | ||
export class Code extends code.Code { | ||
static table = table; | ||
static table = new d.DefTable(t.table, t.defaults); | ||
@@ -21,13 +17,8 @@ private static _methodsAdded = false; | ||
static create(name: string = 'start') { | ||
if(!Code._methodsAdded) { | ||
extend(Code.prototype, methods); | ||
Code._methodsAdded = true; | ||
} | ||
var newcode = new Code(name); | ||
// newcode.addMethods(); | ||
newcode.addMethods(); | ||
return newcode; | ||
} | ||
methods = methods; | ||
table = Code.table; | ||
@@ -39,128 +30,1 @@ ClassInstruction = Instruction; | ||
} | ||
export interface Code { | ||
jmp(dst: TUiOperand): Instruction; | ||
jmpq(dst: TUiOperand): Instruction; | ||
ljmp(dst: TUiOperand): Instruction; | ||
ljmpq(dst: TUiOperand): Instruction; | ||
jecxz(rel: TUiOperand): Instruction; | ||
jrcxz(rel: TUiOperand): Instruction; | ||
ja(rel: TUiOperand): Instruction; | ||
jae(rel: TUiOperand): Instruction; | ||
jb(rel: TUiOperand): Instruction; | ||
jbe(rel: TUiOperand): Instruction; | ||
jc(rel: TUiOperand): Instruction; | ||
je(rel: TUiOperand): Instruction; | ||
jg(rel: TUiOperand): Instruction; | ||
jge(rel: TUiOperand): Instruction; | ||
jl(rel: TUiOperand): Instruction; | ||
jle(rel: TUiOperand): Instruction; | ||
jna(rel: TUiOperand): Instruction; | ||
jnae(rel: TUiOperand): Instruction; | ||
jnb(rel: TUiOperand): Instruction; | ||
jnbe(rel: TUiOperand): Instruction; | ||
jnc(rel: TUiOperand): Instruction; | ||
jne(rel: TUiOperand): Instruction; | ||
jng(rel: TUiOperand): Instruction; | ||
jnge(rel: TUiOperand): Instruction; | ||
jnl(rel: TUiOperand): Instruction; | ||
jnle(rel: TUiOperand): Instruction; | ||
jno(rel: TUiOperand): Instruction; | ||
jnp(rel: TUiOperand): Instruction; | ||
jns(rel: TUiOperand): Instruction; | ||
jnz(rel: TUiOperand): Instruction; | ||
jo(rel: TUiOperand): Instruction; | ||
jp(rel: TUiOperand): Instruction; | ||
jpe(rel: TUiOperand): Instruction; | ||
jpo(rel: TUiOperand): Instruction; | ||
js(rel: TUiOperand): Instruction; | ||
jz(rel: TUiOperand): Instruction; | ||
loop(rel: TUiOperand): Instruction; | ||
loope(rel: TUiOperand): Instruction; | ||
loopz(rel: TUiOperand): Instruction; | ||
loopne(rel: TUiOperand): Instruction; | ||
loopnz(rel: TUiOperand): Instruction; | ||
enter(imm16: number, imm8: number): Instruction; | ||
'in'(dst: TUiOperand, src: TUiOperand): Instruction; | ||
inb(dst: TUiOperand, src: TUiOperand): Instruction; | ||
inw(dst: TUiOperand, src: TUiOperand): Instruction; | ||
ind(dst: TUiOperand, src: TUiOperand): Instruction; | ||
out(dst: TUiOperand, src: TUiOperand): Instruction; | ||
outb(dst: TUiOperand, src: TUiOperand): Instruction; | ||
outw(dst: TUiOperand, src: TUiOperand): Instruction; | ||
outd(dst: TUiOperand, src: TUiOperand): Instruction; | ||
insb(): Instruction; | ||
insw(): Instruction; | ||
insd(): Instruction; | ||
outsb(): Instruction; | ||
outsw(): Instruction; | ||
outsd(): Instruction; | ||
// Flag Control | ||
stc(): Instruction; | ||
clc(): Instruction; | ||
cmc(): Instruction; | ||
cld(): Instruction; | ||
std(): Instruction; | ||
pushf(): Instruction; | ||
popf(): Instruction; | ||
sti(): Instruction; | ||
cli(): Instruction; | ||
// Random Number | ||
rdrand(dst: TUiOperand): Instruction; | ||
rdseed(src: TUiOperand): Instruction; | ||
adcx(dst: TUiOperand, src: TUiOperand): Instruction; | ||
adox(dst: TUiOperand, src: TUiOperand): Instruction; | ||
add(dst: TUiOperand, src: TUiOperand): Instruction; | ||
adc(dst: TUiOperand, src: TUiOperand): Instruction; | ||
adcb(dst: TUiOperand, src: TUiOperand): Instruction; | ||
adcw(dst: TUiOperand, src: TUiOperand): Instruction; | ||
adcd(dst: TUiOperand, src: TUiOperand): Instruction; | ||
adcq(dst: TUiOperand, src: TUiOperand): Instruction; | ||
sub(dst: TUiOperand, src: TUiOperand): Instruction; | ||
subb(dst: TUiOperand, src: TUiOperand): Instruction; | ||
subw(dst: TUiOperand, src: TUiOperand): Instruction; | ||
subd(dst: TUiOperand, src: TUiOperand): Instruction; | ||
subq(dst: TUiOperand, src: TUiOperand): Instruction; | ||
sbb(dst: TUiOperand, src: TUiOperand): Instruction; | ||
sbbb(dst: TUiOperand, src: TUiOperand): Instruction; | ||
sbbw(dst: TUiOperand, src: TUiOperand): Instruction; | ||
sbbd(dst: TUiOperand, src: TUiOperand): Instruction; | ||
sbbq(dst: TUiOperand, src: TUiOperand): Instruction; | ||
mul(src: TUiOperand): Instruction; | ||
mulb(src: TUiOperand): Instruction; | ||
mulw(src: TUiOperand): Instruction; | ||
muld(src: TUiOperand): Instruction; | ||
mulq(src: TUiOperand): Instruction; | ||
div(src: TUiOperand): Instruction; | ||
divb(src: TUiOperand): Instruction; | ||
divw(src: TUiOperand): Instruction; | ||
divd(src: TUiOperand): Instruction; | ||
divq(src: TUiOperand): Instruction; | ||
neg(dst: TUiOperand): Instruction; | ||
cmp(dst: TUiOperand, src: TUiOperand): Instruction; | ||
addq(dst: TUiOperand, src: TUiOperand): Instruction; | ||
mov(dst: TUiOperand, src: TUiOperand): Instruction; | ||
movq(dst: TUiOperand, src: TUiOperand): Instruction; | ||
movd(dst: TUiOperand, src: TUiOperand): Instruction; | ||
push(): Instruction; | ||
pushq(): Instruction; | ||
pushd(): Instruction; | ||
pushw(): Instruction; | ||
inc(dst: TUiOperand): Instruction; | ||
incq(dst: TUiOperand): Instruction; | ||
dec(dst: TUiOperand): Instruction; | ||
decq(dst: TUiOperand): Instruction; | ||
lea(dst: TUiOperand, src: TUiOperand): Instruction; | ||
ret(): Instruction; | ||
syscall(): Instruction; | ||
sysenter(): Instruction; | ||
sysexit(): Instruction; | ||
int(value: number): Instruction; | ||
} |
@@ -15,9 +15,3 @@ "use strict"; | ||
_super.apply(this, arguments); | ||
this.pfxRex = null; | ||
} | ||
Instruction.prototype.writePrefixes = function (arr) { | ||
_super.prototype.writePrefixes.call(this, arr); | ||
if (this.pfxRex) | ||
this.pfxRex.write(arr); | ||
}; | ||
Instruction.prototype.needs32To64OperandSizeChange = function () { | ||
@@ -27,3 +21,5 @@ return this.def.operandSize === operand_1.SIZE.Q; | ||
Instruction.prototype.needsRexPrefix = function () { | ||
if (this.def.mandatoryRex) | ||
if (this.pfxEx) | ||
return false; | ||
if (this.def.rex) | ||
return true; | ||
@@ -56,2 +52,12 @@ if (!this.ops.list.length) | ||
W = 1; | ||
var pos = this.def.opEncoding.indexOf('m'); | ||
if (pos > -1) { | ||
var m = this.ops.getMemoryOperand(); | ||
if (m) { | ||
if (m.base && (m.base.idSize() > 3)) | ||
B = 1; | ||
if (m.index && (m.index.idSize() > 3)) | ||
X = 1; | ||
} | ||
} | ||
if ((dst instanceof o.Register) && (src instanceof o.Register)) { | ||
@@ -67,3 +73,3 @@ if (dst.isExtended()) | ||
if (r) { | ||
if (r.isExtended()) | ||
if (r.idSize() > 3) | ||
if (mem) | ||
@@ -74,10 +80,4 @@ R = 1; | ||
} | ||
if (mem) { | ||
if (mem.base && mem.base.isExtended()) | ||
B = 1; | ||
if (mem.index && mem.index.isExtended()) | ||
X = 1; | ||
} | ||
} | ||
this.pfxRex = new p.PrefixRex(W, R, X, B); | ||
this.pfxEx = new p.PrefixRex(W, R, X, B); | ||
this.length++; | ||
@@ -84,0 +84,0 @@ this.lengthMax++; |
@@ -9,9 +9,2 @@ import {SIZE} from '../../operand'; | ||
pfxRex: p.PrefixRex = null; | ||
protected writePrefixes(arr: number[]) { | ||
super.writePrefixes(arr); | ||
if(this.pfxRex) this.pfxRex.write(arr); // REX prefix must precede immediate op-code byte. | ||
} | ||
protected needs32To64OperandSizeChange() { | ||
@@ -23,5 +16,7 @@ // Default operand size in x64 mode is 32 bits. | ||
protected needsRexPrefix() { | ||
if(this.def.mandatoryRex) return true; | ||
if(this.pfxEx) return false; // VEX or EVEX already set | ||
if(this.def.rex) return true; | ||
if(!this.ops.list.length) return false; | ||
// if(!this.ops.hasRegisterOrMemory()) return false; | ||
if(this.ops.hasExtendedRegister()) return true; | ||
@@ -55,2 +50,11 @@ | ||
var pos = this.def.opEncoding.indexOf('m'); | ||
if(pos > -1) { | ||
var m = this.ops.getMemoryOperand() as o.Memory; // Memory operand is only one. | ||
if(m) { | ||
if(m.base && (m.base.idSize() > 3)) B = 1; | ||
if(m.index && (m.index.idSize() > 3)) X = 1; | ||
} | ||
} | ||
if((dst instanceof o.Register) && (src instanceof o.Register)) { | ||
@@ -61,18 +65,13 @@ if((dst as o.Register).isExtended()) R = 1; | ||
var r: o.Register = this.ops.getRegisterOperand(); | ||
var mem: o.Memory = this.ops.getMemoryOperand(); | ||
var r = this.ops.getRegisterOperand(); | ||
var mem: o.Memory = this.ops.getMemoryOperand() as o.Memory; | ||
if(r) { | ||
if(r.isExtended()) | ||
if(r.idSize() > 3) | ||
if(mem) R = 1; | ||
else B = 1; | ||
} | ||
if(mem) { | ||
if(mem.base && mem.base.isExtended()) B = 1; | ||
if(mem.index && mem.index.isExtended()) X = 1; | ||
} | ||
} | ||
this.pfxRex = new p.PrefixRex(W, R, X, B); | ||
this.pfxEx = new p.PrefixRex(W, R, X, B); | ||
this.length++; | ||
@@ -90,3 +89,3 @@ this.lengthMax++; | ||
protected createModrm() { | ||
var mem: o.Memory = this.ops.getMemoryOperand(); | ||
var mem: o.Memory = this.ops.getMemoryOperand() as o.Memory; | ||
if(mem && mem.base && (mem.base instanceof o.RegisterRip)) { | ||
@@ -101,4 +100,4 @@ if(mem.index || mem.scale) | ||
} else { | ||
var r: o.Register = this.ops.getRegisterOperand(); | ||
if (r) reg = r.get3bitId(); | ||
var r = this.ops.getRegisterOperand(); | ||
if(r) reg = r.get3bitId(); | ||
} | ||
@@ -122,3 +121,3 @@ | ||
protected createDisplacement() { | ||
var mem = this.ops.getMemoryOperand(); | ||
var mem = this.ops.getMemoryOperand() as o.Memory; | ||
if(mem && (typeof mem == 'object') && (mem.base instanceof o.RegisterRip)) { | ||
@@ -125,0 +124,0 @@ // RIP-relative addressing has always 4-byte displacement. |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
528694
52
12845
226