summaryrefslogtreecommitdiff
path: root/gen_x86.c
diff options
context:
space:
mode:
Diffstat (limited to 'gen_x86.c')
-rw-r--r--gen_x86.c253
1 files changed, 227 insertions, 26 deletions
diff --git a/gen_x86.c b/gen_x86.c
index 1b0bed9..676debb 100644
--- a/gen_x86.c
+++ b/gen_x86.c
@@ -31,6 +31,8 @@
#define OP_RETN 0xC3
#define OP_MOV_IEA 0xC6
#define OP_CALL 0xE8
+#define OP_JMP 0xE9
+#define OP_JMP_BYTE 0xEB
#define OP_CALL_EA 0xFF
#define OP2_JCC 0x80
@@ -49,12 +51,6 @@
#define BIT_DIR 0x2
#define BIT_SIZE 0x1
-#define M68K_N_REG RBX
-#define M68K_V_REG BH
-#define M68K_Z_REG RDX
-#define M68K_C_REG DH
-
-#define M68K_SCRATCH RCX
enum {
X86_RAX = 0,
@@ -79,13 +75,6 @@ enum {
X86_R15
} x86_regs_enc;
-enum {
- MODE_REG_INDIRECT = 0,
- MODE_REG_DISPLACE8 = 0x40,
- MODE_REG_DIPSLACE32 = 0x80,
- MODE_REG_DIRECT = 0xC0
-} x86_modes;
-
uint8_t * x86_rr_sizedir(uint8_t * out, uint8_t opcode, uint8_t src, uint8_t dst, uint8_t size)
{
//TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix
@@ -160,6 +149,10 @@ uint8_t * x86_rrdisp8_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_
}
*(out++) = opcode | dir;
*(out++) = MODE_REG_DISPLACE8 | base | (reg << 3);
+ if (base == RSP) {
+ //add SIB byte, with no index and RSP as base
+ *(out++) = (RSP << 3) | RSP;
+ }
*(out++) = disp;
return out;
}
@@ -195,6 +188,10 @@ uint8_t * x86_rrind_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_t
}
*(out++) = opcode | dir;
*(out++) = MODE_REG_INDIRECT | base | (reg << 3);
+ if (base == RSP) {
+ //add SIB byte, with no index and RSP as base
+ *(out++) = (RSP << 3) | RSP;
+ }
return out;
}
@@ -251,6 +248,51 @@ uint8_t * x86_ir(uint8_t * out, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode
return out;
}
+uint8_t * x86_irdisp8(uint8_t * out, uint8_t opcode, uint8_t op_ex, int32_t val, uint8_t dst, int8_t disp, uint8_t size)
+{
+ uint8_t sign_extend = 0;
+ if ((size == SZ_D || size == SZ_Q) && val <= 0x7F && val >= -0x80) {
+ sign_extend = 1;
+ opcode |= BIT_DIR;
+ }
+ if (size == SZ_W) {
+ *(out++) = PRE_SIZE;
+ }
+
+ if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) {
+ *out = PRE_REX;
+ if (size == SZ_Q) {
+ *out |= REX_QUAD;
+ }
+ if (dst >= R8) {
+ *out |= REX_RM_FIELD;
+ dst -= (R8 - X86_R8);
+ }
+ out++;
+ }
+ if (dst >= AH && dst <= BH) {
+ dst -= (AH-X86_AH);
+ }
+ if (size != SZ_B) {
+ opcode |= BIT_SIZE;
+ }
+ *(out++) = opcode;
+ *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3);
+ *(out++) = disp;
+ *(out++) = val;
+ if (size != SZ_B && !sign_extend) {
+ val >>= 8;
+ *(out++) = val;
+ if (size != SZ_W) {
+ val >>= 8;
+ *(out++) = val;
+ val >>= 8;
+ *(out++) = val;
+ }
+ }
+ return out;
+}
+
uint8_t * add_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
{
@@ -262,6 +304,21 @@ uint8_t * add_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
return x86_ir(out, OP_IMMED_ARITH, OP_EX_ADDI, OP_ADD, val, dst, size);
}
+uint8_t * add_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ADDI, val, dst_base, disp, size);
+}
+
+uint8_t * add_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_ADD, src, dst_base, disp, size, 0);
+}
+
+uint8_t * add_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_ADD, dst, src_base, disp, size, BIT_DIR);
+}
+
uint8_t * or_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
{
return x86_rr_sizedir(out, OP_OR, src, dst, size);
@@ -271,6 +328,21 @@ uint8_t * or_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
return x86_ir(out, OP_IMMED_ARITH, OP_EX_ORI, OP_OR, val, dst, size);
}
+uint8_t * or_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ORI, val, dst_base, disp, size);
+}
+
+uint8_t * or_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_OR, src, dst_base, disp, size, 0);
+}
+
+uint8_t * or_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_OR, dst, src_base, disp, size, BIT_DIR);
+}
+
uint8_t * and_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
{
return x86_rr_sizedir(out, OP_AND, src, dst, size);
@@ -281,6 +353,21 @@ uint8_t * and_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
return x86_ir(out, OP_IMMED_ARITH, OP_EX_ANDI, OP_AND, val, dst, size);
}
+uint8_t * and_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ANDI, val, dst_base, disp, size);
+}
+
+uint8_t * and_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_AND, src, dst_base, disp, size, 0);
+}
+
+uint8_t * and_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_AND, dst, src_base, disp, size, BIT_DIR);
+}
+
uint8_t * xor_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
{
return x86_rr_sizedir(out, OP_XOR, src, dst, size);
@@ -291,6 +378,21 @@ uint8_t * xor_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
return x86_ir(out, OP_IMMED_ARITH, OP_EX_XORI, OP_XOR, val, dst, size);
}
+uint8_t * xor_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_XORI, val, dst_base, disp, size);
+}
+
+uint8_t * xor_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_XOR, src, dst_base, disp, size, 0);
+}
+
+uint8_t * xor_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_XOR, dst, src_base, disp, size, BIT_DIR);
+}
+
uint8_t * sub_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
{
return x86_rr_sizedir(out, OP_SUB, src, dst, size);
@@ -301,6 +403,21 @@ uint8_t * sub_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
return x86_ir(out, OP_IMMED_ARITH, OP_EX_SUBI, OP_SUB, val, dst, size);
}
+uint8_t * sub_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_SUBI, val, dst_base, disp, size);
+}
+
+uint8_t * sub_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_SUB, src, dst_base, disp, size, 0);
+}
+
+uint8_t * sub_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_SUB, dst, src_base, disp, size, BIT_DIR);
+}
+
uint8_t * cmp_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
{
return x86_rr_sizedir(out, OP_CMP, src, dst, size);
@@ -311,6 +428,21 @@ uint8_t * cmp_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
return x86_ir(out, OP_IMMED_ARITH, OP_EX_CMPI, OP_CMP, val, dst, size);
}
+uint8_t * cmp_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_CMPI, val, dst_base, disp, size);
+}
+
+uint8_t * cmp_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_CMP, src, dst_base, disp, size, 0);
+}
+
+uint8_t * cmp_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_CMP, dst, src_base, disp, size, BIT_DIR);
+}
+
uint8_t * mov_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
{
return x86_rr_sizedir(out, OP_MOV, src, dst, size);
@@ -360,12 +492,12 @@ uint8_t * mov_ir(uint8_t * out, int64_t val, uint8_t dst, uint8_t size)
dst -= (AH-X86_AH);
}
if (size == SZ_B) {
- *(out++) = OP_MOV_I8R;
+ *(out++) = OP_MOV_I8R | dst;
} else if (size == SZ_Q && sign_extend) {
*(out++) = OP_MOV_IEA | BIT_SIZE;
*(out++) = MODE_REG_DIRECT | dst;
} else {
- *(out++) = OP_MOV_IR;
+ *(out++) = OP_MOV_IR | dst;
}
*(out++) = val;
if (size != SZ_B) {
@@ -391,6 +523,43 @@ uint8_t * mov_ir(uint8_t * out, int64_t val, uint8_t dst, uint8_t size)
return out;
}
+uint8_t * mov_irdisp8(uint8_t * out, int32_t val, uint8_t dst, int8_t disp, uint8_t size)
+{
+ if (size == SZ_W) {
+ *(out++) = PRE_SIZE;
+ }
+ if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) {
+ *out = PRE_REX;
+ if (size == SZ_Q) {
+ *out |= REX_QUAD;
+ }
+ if (dst >= R8) {
+ *out |= REX_RM_FIELD;
+ dst -= (R8 - X86_R8);
+ }
+ out++;
+ }
+ if (dst >= AH && dst <= BH) {
+ dst -= (AH-X86_AH);
+ }
+ *(out++) = OP_MOV_IEA | (size == SZ_B ? 0 : BIT_SIZE);
+ *(out++) = MODE_REG_DISPLACE8 | dst;
+ *(out++) = disp;
+
+ *(out++) = val;
+ if (size != SZ_B) {
+ val >>= 8;
+ *(out++) = val;
+ if (size != SZ_W) {
+ val >>= 8;
+ *(out++) = val;
+ val >>= 8;
+ *(out++) = val;
+ }
+ }
+ return out;
+}
+
uint8_t * pushf(uint8_t * out)
{
*(out++) = OP_PUSHF;
@@ -451,21 +620,53 @@ uint8_t * setcc_rind(uint8_t * out, uint8_t cc, uint8_t dst)
return out;
}
-uint8_t * jcc(uint8_t * out, uint8_t cc, int32_t disp)
+uint8_t * jcc(uint8_t * out, uint8_t cc, uint8_t * dest)
{
+ ptrdiff_t disp = dest-(out+2);
if (disp <= 0x7F && disp >= -0x80) {
*(out++) = OP_JCC | cc;
*(out++) = disp;
} else {
- *(out++) = PRE_2BYTE;
- *(out++) = OP2_JCC | cc;
- *(out++) = disp;
- disp >>= 8;
- *(out++) = disp;
- disp >>= 8;
- *(out++) = disp;
- disp >>= 8;
+ disp = dest-(out+6);
+ if (disp <= 0x7FFFFFFF && disp >= -2147483648) {
+ *(out++) = PRE_2BYTE;
+ *(out++) = OP2_JCC | cc;
+ *(out++) = disp;
+ disp >>= 8;
+ *(out++) = disp;
+ disp >>= 8;
+ *(out++) = disp;
+ disp >>= 8;
+ *(out++) = disp;
+ } else {
+ printf("%p - %p = %lX\n", dest, out + 6, disp);
+ return NULL;
+ }
+ }
+ return out;
+}
+
+uint8_t * jmp(uint8_t * out, uint8_t * dest)
+{
+ ptrdiff_t disp = dest-(out+2);
+ if (disp <= 0x7F && disp >= -0x80) {
+ *(out++) = OP_JMP_BYTE;
*(out++) = disp;
+ } else {
+ disp = dest-(out+5);
+ if (disp <= 0x7FFFFFFF && disp >= -2147483648) {
+ *(out++) = OP_JMP;
+ *(out++) = disp;
+ disp >>= 8;
+ *(out++) = disp;
+ disp >>= 8;
+ *(out++) = disp;
+ disp >>= 8;
+ *(out++) = disp;
+ } else {
+ printf("%p - %p = %lX\n", dest, out + 6, disp);
+ return NULL;
+ }
}
return out;
}
@@ -483,8 +684,8 @@ uint8_t * call(uint8_t * out, uint8_t * fun)
disp >>= 8;
*(out++) = disp;
} else {
- //TODO: Implement far call
- printf("%p - %p = %ld, %d, %d, %d\n", fun, out + 5, disp, disp <= 0x7FFFFFFF, disp >= (-2147483648), -2147483648);
+ //TODO: Implement far call???
+ printf("%p - %p = %lX\n", fun, out + 5, disp);
return NULL;
}
return out;