Permalink
Browse files

Initial support for amd64 and REX bytes in the assembler.

  • Loading branch information...
1 parent bb0b3f5 commit d44caec2bedeada9546cc6d29f87cb1d060cba3c @nelhage committed Aug 4, 2012
Showing with 81 additions and 10 deletions.
  1. +81 −10 x86.h
View
91 x86.h
@@ -51,6 +51,12 @@ typedef uint8_t* ccbuff;
typedef uint8_t cc_t;
+#define PFX_REX 0x40
+#define REXW 0x08
+#define REXR 0x04
+#define REXX 0x02
+#define REXB 0x01
+
/*
* Using this as a register argument in the r/m field indicates an SIB
* byte follows (with mod != 3)
@@ -168,6 +174,22 @@ class X86Assembler {
modrm(scale, index, base);
}
+#ifdef __x86_64__
+ void rex(bool w = 0, bool r = 0, bool x = 0, bool b = 0) {
+ if (w || r || x || b)
+ byte(PFX_REX | (!!w << 3) | (!!r << 2) | (!!x << 2) | !!b);
+ }
+#else
+ void rex(bool w = 0, bool r = 0, bool x = 0, bool b = 0) {
+ ASSERT(!w && !r && !x & !b);
+ }
+#endif
+
+ void rex(int lbits, int rbits, bool r = 0, bool x = 0, bool b = 0) {
+ ASSERT(lbits == rbits || !lbits || !rbits);
+ rex((lbits | rbits) == 64, r, x, b);
+ }
+
#define INSTRUCTION(fn, cls) \
template <class Tl, class Tr> \
void fn(Tl lhs, Tr rhs) { \
@@ -250,24 +272,41 @@ struct is_modrm { const static false_type val; };
class X86Register {
public:
int val;
- X86Register(int v) : val(v) {};
+ int bits;
+ X86Register(int v, int b = 0) : val(v), bits(b) {};
+ void rex(X86Assembler *cc, X86Register other) {
+ cc->rex(bits, other.bits);
+ }
void emit(X86Assembler *cc, X86Register reg) {
+ ASSERT(bits == reg.bits);
cc->modrm(MOD_REG, reg.val, val);
}
};
-#define R(name, v) static X86Register X86##name(v);
-R(EAX, 0x00);
-R(ECX, 0x01);
-R(EDX, 0x02);
-R(EBX, 0x03);
-R(ESP, 0x04);
-R(EBP, 0x05);
-R(ESI, 0x06);
-R(EDI, 0x07);
+#ifdef __x86_64__
+#define R(name, v) \
+ static X86Register X86E##name(v, 32); \
+ static X86Register X86R##name(v, 64)
+#else
+#define R(name, v) \
+ static X86Register X86E##name(v, 32)
+#endif
+R(AX, 0x00);
+R(CX, 0x01);
+R(DX, 0x02);
+R(BX, 0x03);
+R(SP, 0x04);
+R(BP, 0x05);
+R(SI, 0x06);
+R(DI, 0x07);
+#undef R
template<> struct is_modrm<X86Register> { const static true_type val; };
struct X86ReferenceIndirect {
X86Register base;
+ void rex(X86Assembler *cc, X86Register other) {
+ cc->rex(other.bits == 64);
+ }
+
void emit(X86Assembler *cc, X86Register reg) {
ASSERT(base.val != REG_DISP32);
ASSERT(base.val != REG_SIB);
@@ -279,6 +318,10 @@ template<> struct is_modrm<X86ReferenceIndirect> { const static true_type val; }
struct X86ReferenceIndirect32 {
X86Register base;
uint32_t offset;
+ void rex(X86Assembler *cc, X86Register other) {
+ cc->rex(other.bits == 64);
+ }
+
void emit(X86Assembler *cc, X86Register reg) {
ASSERT(base.val != REG_SIB);
cc->modrm(MOD_INDIR_DISP32, reg.val, base.val);
@@ -290,6 +333,10 @@ template<> struct is_modrm<X86ReferenceIndirect32> { const static true_type val;
struct X86ReferenceIndirect8 {
X86Register base;
uint8_t offset;
+ void rex(X86Assembler *cc, X86Register other) {
+ cc->rex(other.bits == 64);
+ }
+
void emit(X86Assembler *cc, X86Register reg) {
ASSERT(base.val != REG_SIB);
cc->modrm(MOD_INDIR_DISP8, reg.val, base.val);
@@ -300,6 +347,10 @@ template<> struct is_modrm<X86ReferenceIndirect8> { const static true_type val;
struct X86ReferenceAbs {
uint32_t address;
+ void rex(X86Assembler *cc, X86Register other) {
+ cc->rex(other.bits == 64);
+ }
+
void emit(X86Assembler *cc, X86Register reg) {
cc->modrm(MOD_INDIR, reg.val, REG_DISP32);
cc->word(address);
@@ -311,6 +362,10 @@ struct X86ReferenceSIB {
uint32_t offset;
X86Register base, index;
uint8_t scale;
+ void rex(X86Assembler *cc, X86Register other) {
+ cc->rex(other.bits == 64);
+ }
+
void emit(X86Assembler *cc, X86Register reg) {
uint8_t sv;
switch(scale) {
@@ -365,18 +420,21 @@ FOR_EACH_INT_TYPE(D)
template<class Inst>
inline void X86Emitter<Inst>::emit_imm(X86Assembler *cc, X86Register rhs, none) {
+ cc->rex(rhs.bits == 64);
cc->byte(Inst::op_imm_rm::val);
cc->modrm(MOD_REG, Inst::subop_imm_rm::val, rhs.val);
}
template<class Inst>
inline void X86Emitter<Inst>::emit_imm(X86Assembler *cc, X86Register rhs, uint8_t op_imm_r) {
+ cc->rex(rhs.bits == 64);
cc->byte(Inst::op_imm_r::val + rhs.val);
}
template<class Inst>
template<class Mem>
inline void X86Emitter<Inst>::emit(X86Assembler *cc, uint32_t lhs, Mem rhs) {
+ rhs.rex(cc, X86Register(Inst::subop_imm_rm::val));
cc->byte(Inst::op_imm_rm::val);
rhs.emit(cc, X86Register(Inst::subop_imm_rm::val));
cc->word(lhs);
@@ -390,13 +448,15 @@ inline void X86Emitter<Inst>::emit(X86Assembler *cc, X86Register lhs, X86Regist
template<class Inst>
inline void X86Emitter<Inst>::emit_reg(X86Assembler *cc, X86Register lhs, X86Register rhs,
none) {
+ lhs.rex(cc, rhs);
cc->byte(Inst::op_rm_r::val);
lhs.emit(cc, rhs);
}
template<class Inst>
inline void X86Emitter<Inst>::emit_reg(X86Assembler *cc, X86Register lhs, X86Register rhs,
uint8_t) {
+ rhs.rex(cc, lhs);
cc->byte(Inst::op_r_rm::val);
rhs.emit(cc, lhs);
}
@@ -405,6 +465,7 @@ inline void X86Emitter<Inst>::emit_reg(X86Assembler *cc, X86Register lhs, X86Re
template<class Inst>
template<class Mem>
inline void X86Emitter<Inst>::emit(X86Assembler *cc, X86Register lhs, Mem rhs) {
+ rhs.rex(cc, lhs);
cc->byte(Inst::op_r_rm::val);
rhs.emit(cc, lhs);
}
@@ -413,6 +474,7 @@ inline void X86Emitter<Inst>::emit(X86Assembler *cc, X86Register lhs, Mem rhs)
template<class Inst>
template<class Mem>
inline void X86Emitter<Inst>::emit(X86Assembler *cc, Mem lhs, X86Register rhs) {
+ rhs.rex(cc, rhs);
cc->byte(Inst::op_rm_r::val);
lhs.emit(cc, rhs);
}
@@ -421,13 +483,15 @@ template<class Inst>
template<class Mem>
inline void X86ShiftEmitter<Inst>::emit(X86Assembler *cc, X86Register lhs, Mem rhs) {
ASSERT(lhs.val == X86ECX.val);
+ rhs.rex(cc, X86Register(Inst::subop_cl::val));
cc->byte(Inst::op_cl::val);
rhs.emit(cc, X86Register(Inst::subop_cl::val));
}
template<class Inst>
template<class Mem>
inline void X86ShiftEmitter<Inst>::emit(X86Assembler *cc, uint8_t lhs, Mem rhs) {
+ rhs.rex(cc, X86Register(Inst::subop_cl::val));
cc->byte(Inst::op_imm::val);
rhs.emit(cc, X86Register(Inst::subop_imm::val));
cc->byte(lhs);
@@ -436,13 +500,15 @@ inline void X86ShiftEmitter<Inst>::emit(X86Assembler *cc, uint8_t lhs, Mem rhs)
template <class Mem>
inline void X86Assembler::imul(Mem lhs, X86Register rhs)
{
+ lhs.rex(this, rhs);
byte(0x0f); byte(0xaf);
lhs.emit(this, rhs);
}
template <class Mem>
inline void X86Assembler::imul(uint32_t lhs, Mem rhs, X86Register dst)
{
+ rhs.rex(this, dst);
byte(0x69);
rhs.emit(this, dst);
word(lhs);
@@ -451,6 +517,7 @@ inline void X86Assembler::imul(uint32_t lhs, Mem rhs, X86Register dst)
template<class Mem>
void X86Assembler::idiv(Mem rhs)
{
+ rhs.rex(this, X86Register(0x7));
byte(0xf7);
rhs.emit(this, X86Register(0x7));
}
@@ -473,6 +540,7 @@ inline void X86Assembler::call(Mem target) {
template<class Mem>
inline void X86Assembler::call(Mem target, true_type) {
+ // No REX byte, operand is always 64 bits
byte(0xff);
target.emit(this, X86Register(0x2));
}
@@ -484,6 +552,7 @@ inline void X86Assembler::call(Mem target, false_type) {
template<class Mem>
inline void X86Assembler::inc(Mem target) {
+ target.rex(this, X86Register(0x0));
byte(0xff);
target.emit(this, X86Register(0x0));
}
@@ -505,6 +574,7 @@ inline void X86Assembler::jmp(uint8_t *addr) {
template<class Mem>
inline void X86Assembler::jmp(Mem target) {
+ // No REX byte
byte(0xff);
target.emit(this, X86Register(0x4));
}
@@ -527,6 +597,7 @@ inline void X86Assembler::jcc(cc_t cc, X86Label8 &label) {
template<class Mem>
inline void X86Assembler::setcc(cc_t cc, Mem target) {
+ // No REX byte, always 8 bits
byte(0x0f);
byte(0x90 | cc);
target.emit(this, X86Register(0x0));

0 comments on commit d44caec

Please sign in to comment.