x86
Version:
Generates x86_64 native code from assembly instructions
378 lines (377 loc) • 13.3 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var util_1 = require('./util');
// # General operand used in our assembly "language".
var Operand = (function () {
function Operand() {
}
// Convenience method to get `Register` associated with `Register` or `Memory`.
Operand.prototype.reg = function () {
return null;
};
Operand.prototype.isRegister = function () {
return this instanceof Register;
};
Operand.prototype.isMemory = function () {
return this instanceof Memory;
};
Operand.prototype.toString = function () {
return '[operand]';
};
return Operand;
}());
exports.Operand = Operand;
var Constant = (function (_super) {
__extends(Constant, _super);
function Constant(value) {
_super.call(this);
// Size in bits.
this.size = 32;
this.value = 0;
// Each byte as a `number` in reverse order.
this.octets = [];
this.Value = value;
}
Constant.sizeClass = function (value) {
if ((value <= 0x7f) && (value >= -0x80))
return 8 /* BYTE */;
if ((value <= 0x7fff) && (value >= -0x8000))
return 16 /* WORD */;
if ((value <= 0x7fffffff) && (value >= -0x80000000))
return 32 /* DOUBLE */;
return 64 /* QUAD */;
};
Object.defineProperty(Constant.prototype, "Value", {
set: function (value) {
if (value instanceof Array) {
if (value.length !== 2)
throw TypeError('number64 must be a 2-tuple, given: ' + value);
this.setValue64(value);
}
else if (typeof value === 'number') {
/* JS integers are 53-bit, so split here `number`s over 32 bits into [number, number]. */
if (Constant.sizeClass(value) === 64 /* QUAD */)
this.setValue64([util_1.UInt64.lo(value), util_1.UInt64.hi(value)]);
else
this.setValue32(value);
}
else
throw TypeError('Constant value must be of type number|number64.');
},
enumerable: true,
configurable: true
});
Constant.prototype.setValue32 = function (value) {
var size = Constant.sizeClass(value);
this.size = size;
this.value = value;
this.octets = [];
this.octets[0] = value & 0xFF;
if (size > 8 /* BYTE */)
this.octets[1] = (value >> 8) & 0xFF;
if (size > 16 /* WORD */) {
this.octets[2] = (value >> 16) & 0xFF;
this.octets[3] = (value >> 24) & 0xFF;
}
};
Constant.prototype.setValue64 = function (value) {
this.size = 64;
this.value = value;
this.octets = [];
var lo = value[0], hi = value[1];
this.octets[0] = (lo) & 0xFF;
this.octets[1] = (lo >> 8) & 0xFF;
this.octets[2] = (lo >> 16) & 0xFF;
this.octets[3] = (lo >> 24) & 0xFF;
this.octets[4] = (hi) & 0xFF;
this.octets[5] = (hi >> 8) & 0xFF;
this.octets[6] = (hi >> 16) & 0xFF;
this.octets[7] = (hi >> 24) & 0xFF;
};
Constant.prototype.zeroExtend = function (size) {
if (this.size > size)
throw Error("Already larger than " + size + " bits, cannot zero-extend.");
var missing_bytes = (size - this.size) / 8;
this.size = size;
for (var i = 0; i < missing_bytes; i++)
this.octets.push(0);
};
Constant.prototype.toString = function () {
return "const[" + this.size + "]: " + this.value;
};
return Constant;
}(Operand));
exports.Constant = Constant;
var ImmediateValue = (function (_super) {
__extends(ImmediateValue, _super);
function ImmediateValue() {
_super.apply(this, arguments);
}
return ImmediateValue;
}(Constant));
exports.ImmediateValue = ImmediateValue;
var DisplacementValue = (function (_super) {
__extends(DisplacementValue, _super);
function DisplacementValue(value) {
_super.call(this, value);
this.size = DisplacementValue.SIZE.DISP8;
}
DisplacementValue.prototype.setValue32 = function (value) {
_super.prototype.setValue32.call(this, value);
/* Make sure `Displacement` is 1 or 4 bytes, not 2. */
if (this.size > DisplacementValue.SIZE.DISP8)
this.zeroExtend(DisplacementValue.SIZE.DISP32);
};
DisplacementValue.prototype.setValue64 = function () {
throw TypeError("Displacement can be only of these sizes: " + DisplacementValue.SIZE.DISP8 + " and " + DisplacementValue.SIZE.DISP32 + ".");
};
DisplacementValue.SIZE = {
DISP8: 8 /* BYTE */,
DISP32: 32 /* DOUBLE */,
};
return DisplacementValue;
}(Constant));
exports.DisplacementValue = DisplacementValue;
// # Scale
//
// `Scale` used in SIB byte in two bit `SCALE` field.
var Scale = (function (_super) {
__extends(Scale, _super);
function Scale(scale) {
if (scale === void 0) { scale = 1; }
_super.call(this);
if (Scale.VALUES.indexOf(scale) < 0)
throw TypeError("Scale must be one of [1, 2, 4, 8].");
this.value = scale;
}
Scale.prototype.toString = function () {
return '' + this.value;
};
Scale.VALUES = [1, 2, 4, 8];
return Scale;
}(Operand));
exports.Scale = Scale;
// ## Registers
//
// `Register` represents one of `%rax`, `%rbx`, etc. registers.
(function (R64) {
R64[R64["RAX"] = 0] = "RAX";
R64[R64["RCX"] = 1] = "RCX";
R64[R64["RDX"] = 2] = "RDX";
R64[R64["RBX"] = 3] = "RBX";
R64[R64["RSP"] = 4] = "RSP";
R64[R64["RBP"] = 5] = "RBP";
R64[R64["RSI"] = 6] = "RSI";
R64[R64["RDI"] = 7] = "RDI";
R64[R64["R8"] = 8] = "R8";
R64[R64["R9"] = 9] = "R9";
R64[R64["R10"] = 10] = "R10";
R64[R64["R11"] = 11] = "R11";
R64[R64["R12"] = 12] = "R12";
R64[R64["R13"] = 13] = "R13";
R64[R64["R14"] = 14] = "R14";
R64[R64["R15"] = 15] = "R15";
})(exports.R64 || (exports.R64 = {}));
var R64 = exports.R64;
(function (R32) {
R32[R32["EAX"] = 0] = "EAX";
R32[R32["ECX"] = 1] = "ECX";
R32[R32["EDX"] = 2] = "EDX";
R32[R32["EBX"] = 3] = "EBX";
R32[R32["ESP"] = 4] = "ESP";
R32[R32["EBP"] = 5] = "EBP";
R32[R32["ESI"] = 6] = "ESI";
R32[R32["EDI"] = 7] = "EDI";
R32[R32["R8D"] = 8] = "R8D";
R32[R32["R9D"] = 9] = "R9D";
R32[R32["R10D"] = 10] = "R10D";
R32[R32["R11D"] = 11] = "R11D";
R32[R32["R12D"] = 12] = "R12D";
R32[R32["R13D"] = 13] = "R13D";
R32[R32["R14D"] = 14] = "R14D";
R32[R32["R15D"] = 15] = "R15D";
})(exports.R32 || (exports.R32 = {}));
var R32 = exports.R32;
(function (R8) {
R8[R8["AL"] = 0] = "AL";
R8[R8["CL"] = 1] = "CL";
R8[R8["DL"] = 2] = "DL";
R8[R8["BL"] = 3] = "BL";
R8[R8["SPL"] = 4] = "SPL";
R8[R8["BPL"] = 5] = "BPL";
R8[R8["SIL"] = 6] = "SIL";
R8[R8["DIL"] = 7] = "DIL";
R8[R8["R8B"] = 8] = "R8B";
R8[R8["R9B"] = 9] = "R9B";
R8[R8["R10B"] = 10] = "R10B";
R8[R8["R11B"] = 11] = "R11B";
R8[R8["R12B"] = 12] = "R12B";
R8[R8["R13B"] = 13] = "R13B";
R8[R8["R14B"] = 14] = "R14B";
R8[R8["R15B"] = 15] = "R15B";
})(exports.R8 || (exports.R8 = {}));
var R8 = exports.R8;
var Register = (function (_super) {
__extends(Register, _super);
function Register(id, size) {
_super.call(this);
this.id = 0; // Number value of register.
this.size = 64 /* QUAD */; // Size in bits
this.id = id;
this.size = size;
}
Register.prototype.reg = function () {
return this;
};
Register.prototype.ref = function () {
return (new Memory).ref(this);
};
Register.prototype.disp = function (value) {
return (new Memory).ref(this).disp(value);
};
// Whether the register is one of `%r8`, `%r9`, etc. extended registers.
Register.prototype.isExtended = function () {
return this.id > 7;
};
Register.prototype.get3bitId = function () {
return this.id & 7;
};
Register.prototype.getName = function () {
switch (this.size) {
case 64 /* QUAD */: return R64[this.id].toLowerCase();
case 32 /* DOUBLE */: return R32[this.id].toLowerCase();
case 8 /* BYTE */: return R8[this.id].toLowerCase();
default: return 'unknown';
}
};
Register.prototype.toString = function () {
return '%' + this.getName();
};
return Register;
}(Operand));
exports.Register = Register;
var Register64 = (function (_super) {
__extends(Register64, _super);
function Register64(id) {
_super.call(this, id, 64 /* QUAD */);
}
return Register64;
}(Register));
exports.Register64 = Register64;
var Register32 = (function (_super) {
__extends(Register32, _super);
function Register32(id) {
_super.call(this, id, 32 /* DOUBLE */);
}
return Register32;
}(Register));
exports.Register32 = Register32;
var Register16 = (function (_super) {
__extends(Register16, _super);
function Register16(id) {
_super.call(this, id, 16 /* WORD */);
}
return Register16;
}(Register));
exports.Register16 = Register16;
var Register8 = (function (_super) {
__extends(Register8, _super);
function Register8(id) {
_super.call(this, id, 8 /* BYTE */);
}
return Register8;
}(Register));
exports.Register8 = Register8;
exports.rax = new Register64(R64.RAX);
exports.rbx = new Register64(R64.RBX);
exports.rcx = new Register64(R64.RCX);
exports.rdx = new Register64(R64.RDX);
exports.rsi = new Register64(R64.RSI);
exports.rdi = new Register64(R64.RDI);
exports.rbp = new Register64(R64.RBP);
exports.rsp = new Register64(R64.RSP);
exports.r8 = new Register64(R64.R8);
exports.r9 = new Register64(R64.R9);
exports.r10 = new Register64(R64.R10);
exports.r11 = new Register64(R64.R11);
exports.r12 = new Register64(R64.R12);
exports.r13 = new Register64(R64.R13);
exports.r14 = new Register64(R64.R14);
exports.r15 = new Register64(R64.R15);
exports.eax = new Register32(R32.EAX);
exports.ebx = new Register32(R32.EBX);
exports.ecx = new Register32(R32.ECX);
exports.edx = new Register32(R32.EDX);
exports.esi = new Register32(R32.ESI);
exports.edi = new Register32(R32.EDI);
exports.ebp = new Register32(R32.EBP);
exports.esp = new Register32(R32.ESP);
exports.r8d = new Register32(R32.R8D);
exports.r9d = new Register32(R32.R9D);
exports.r10d = new Register32(R32.R10D);
exports.r11d = new Register32(R32.R11D);
exports.r12d = new Register32(R32.R12D);
exports.r13d = new Register32(R32.R13D);
exports.r14d = new Register32(R32.R14D);
exports.r15d = new Register32(R32.R15D);
exports.al = new Register8(R8.AL);
exports.bl = new Register8(R8.BL);
exports.cl = new Register8(R8.CL);
exports.dl = new Register8(R8.DL);
exports.sil = new Register8(R8.SIL);
exports.dil = new Register8(R8.DIL);
exports.bpl = new Register8(R8.BPL);
exports.spl = new Register8(R8.SPL);
exports.r8b = new Register8(R8.R8B);
exports.r9b = new Register8(R8.R9B);
exports.r10b = new Register8(R8.R10B);
exports.r11b = new Register8(R8.R11B);
exports.r12b = new Register8(R8.R12B);
exports.r13b = new Register8(R8.R13B);
exports.r14b = new Register8(R8.R14B);
exports.r15b = new Register8(R8.R15B);
// ## Memory
//
// `Memory` is RAM addresses which `Register`s can *dereference*.
var Memory = (function (_super) {
__extends(Memory, _super);
function Memory() {
_super.apply(this, arguments);
this.base = null;
this.index = null;
this.scale = null;
this.displacement = null;
}
Memory.prototype.reg = function () {
if (this.base)
return this.base;
if (this.index)
return this.index;
// throw Error('No backing register.');
return null;
};
Memory.prototype.needsSib = function () {
return !!this.index || !!this.scale;
};
Memory.prototype.ref = function (base) {
this.base = base;
return this;
};
Memory.prototype.disp = function (value) {
this.displacement = new DisplacementValue(value);
return this;
};
Memory.prototype.toString = function () {
var base = this.base ? this.base.toString() : '';
var index = this.index ? this.index.toString() : '';
var scale = this.scale ? this.scale.toString() : '';
var disp = this.disp ? this.disp.toString() : '';
return "[%" + base + " + %{index} * " + scale + " + " + disp + "]";
};
return Memory;
}(Operand));
exports.Memory = Memory;