This implements basic code emitters on x86-64.
Signed-off-by: Eduard - Gabriel Munteanu <[email protected]>
---
arch/x86/emit-code.c | 419 ++++++++++++++++++++++++++++++++++-
arch/x86/include/arch/instruction.h | 27 +++
2 files changed, 437 insertions(+), 9 deletions(-)
diff --git a/arch/x86/emit-code.c b/arch/x86/emit-code.c
index 8d0d333..f7b629d 100644
--- a/arch/x86/emit-code.c
+++ b/arch/x86/emit-code.c
@@ -1135,25 +1135,426 @@ void emit_trampoline(struct compilation_unit *cu,
* x86-64 code emitters *
************************/
-void emit_prolog(struct buffer *buf, unsigned long nr_locals)
+#define REX 40
+#define REX_W (REX | 8) /* 64-bit operands */
+#define REX_R (REX | 4) /* ModRM reg extension */
+#define REX_X (REX | 2) /* SIB index extension */
+#define REX_B (REX | 1) /* ModRM r/m extension */
+
+/*
+ * __encode_reg: Encode register to be used in x86-64 instruction.
+ * @reg: Register to encode.
+ *
+ * Returns register in r/m or reg/opcode field format of the ModR/M byte.
+ */
+static unsigned char __encode_reg(enum machine_reg reg)
{
- abort();
+ unsigned char ret = 0;
+
+ switch (reg) {
+ case REG_RAX:
+ ret = 0x00;
+ break;
+ case REG_RBX:
+ ret = 0x03;
+ break;
+ case REG_RCX:
+ ret = 0x01;
+ break;
+ case REG_RDX:
+ ret = 0x02;
+ break;
+ case REG_RSI:
+ ret = 0x06;
+ break;
+ case REG_RDI:
+ ret = 0x07;
+ break;
+ case REG_RSP:
+ ret = 0x04;
+ break;
+ case REG_RBP:
+ ret = 0x05;
+ break;
+ case REG_R8:
+ ret = 0x08;
+ break;
+ case REG_R9:
+ ret = 0x09;
+ break;
+ case REG_R10:
+ ret = 0x0A;
+ break;
+ case REG_R11:
+ ret = 0x0B;
+ break;
+ case REG_R12:
+ ret = 0x0C;
+ break;
+ case REG_R13:
+ ret = 0x0D;
+ break;
+ case REG_R14:
+ ret = 0x0E;
+ break;
+ case REG_R15:
+ ret = 0x0F;
+ break;
+ case REG_UNASSIGNED:
+ assert(!"unassigned register in code emission");
+ break;
+ }
+ return ret;
}
-void emit_ret(struct buffer *buf)
+static inline unsigned char reg_low(unsigned char reg)
{
- abort();
+ return (reg & 0x7);
}
-void emit_epilog(struct buffer *buf, unsigned long nr_locals)
+static inline unsigned char reg_high(unsigned char reg)
{
- abort();
+ return (reg & 0x8);
}
-void emit_branch_rel(struct buffer *buf, unsigned char prefix,
- unsigned char opc, long rel32)
+static void __emit_reg(struct buffer *buf,
+ int rex_w,
+ unsigned char opc,
+ enum machine_reg reg)
{
- abort();
+ unsigned char __reg = __encode_reg(reg);
+ unsigned char rex_pfx = 0;
+
+ if (rex_w)
+ rex_pfx |= REX_W;
+ if (reg_high(__reg))
+ rex_pfx |= REX_B;
+
+ if (rex_pfx)
+ emit(buf, rex_pfx);
+ emit(buf, opc + reg_low(__reg));
+}
+
+static void __emit64_push_reg(struct buffer *buf, enum machine_reg reg)
+{
+ __emit_reg(buf, 0, 0x50, reg);
+}
+
+static void emit64_push_reg(struct buffer *buf, struct operand *operand)
+{
+ __emit64_push_reg(buf, mach_reg(&operand->reg));
+}
+
+static void __emit64_pop_reg(struct buffer *buf, enum machine_reg reg)
+{
+ __emit_reg(buf, 0, 0x58, reg);
+}
+
+static void emit64_pop_reg(struct buffer *buf, struct operand *operand)
+{
+ __emit64_pop_reg(buf, mach_reg(&operand->reg));
+}
+
+static void __emit_reg_reg(struct buffer *buf,
+ int rex_w,
+ unsigned char opc,
+ enum machine_reg direct_reg,
+ enum machine_reg rm_reg)
+{
+ unsigned char rex_pfx = 0, mod_rm;
+ unsigned char direct, rm;
+
+ direct = __encode_reg(direct_reg);
+ rm = __encode_reg(rm_reg);
+
+ if (rex_w)
+ rex_pfx |= REX_W;
+ if (reg_high(direct))
+ rex_pfx |= REX_R;
+ if (reg_high(rm))
+ rex_pfx |= REX_B;
+
+ mod_rm = encode_modrm(0x03, direct, rm);
+
+ if (rex_pfx)
+ emit(buf, rex_pfx);
+ emit(buf, opc);
+ emit(buf, mod_rm);
+}
+
+static void emit_reg_reg(struct buffer *buf,
+ int rex_w,
+ unsigned char opc,
+ struct operand *direct,
+ struct operand *rm)
+{
+ enum machine_reg direct_reg, rm_reg;
+
+ direct_reg = mach_reg(&direct->reg);
+ rm_reg = mach_reg(&rm->reg);
+
+ __emit_reg_reg(buf, rex_w, opc, direct_reg, rm_reg);
+}
+
+static void __emit64_mov_reg_reg(struct buffer *buf,
+ enum machine_reg src,
+ enum machine_reg dst)
+{
+ __emit_reg_reg(buf, 1, 0x89, src, dst);
+}
+
+static void emit64_mov_reg_reg(struct buffer *buf,
+ struct operand *src,
+ struct operand *dest)
+{
+ __emit64_mov_reg_reg(buf, mach_reg(&src->reg), mach_reg(&dest->reg));
+}
+
+static void __emit32_mov_reg_reg(struct buffer *buf,
+ enum machine_reg src,
+ enum machine_reg dst)
+{
+ __emit_reg_reg(buf, 0, 0x89, src, dst);
+}
+
+static void emit32_mov_reg_reg(struct buffer *buf,
+ struct operand *src,
+ struct operand *dest)
+{
+ __emit32_mov_reg_reg(buf, mach_reg(&src->reg), mach_reg(&dest->reg));
+}
+
+static void emit_alu_imm_reg(struct buffer *buf,
+ int rex_w,
+ unsigned char opc_ext,
+ long imm,
+ enum machine_reg reg)
+{
+ unsigned char rex_pfx = 0, opc, __reg;
+
+ __reg = __encode_reg(reg);
+
+ if (rex_w)
+ rex_pfx |= REX_W;
+ if (reg_high(__reg))
+ rex_pfx |= REX_B;
+
+ if (is_imm_8(imm))
+ opc = 0x83;
+ else
+ opc = 0x81;
+
+ if (rex_pfx)
+ emit(buf, rex_pfx);
+ emit(buf, opc);
+ emit(buf, encode_modrm(0x3, opc_ext, __reg));
+ emit_imm(buf, imm);
+}
+
+static void __emit64_sub_imm_reg(struct buffer *buf,
+ unsigned long imm,
+ enum machine_reg reg)
+{
+ emit_alu_imm_reg(buf, 1, 0x05, imm, reg);
+}
+
+static void emit64_sub_imm_reg(struct buffer *buf,
+ struct operand *src,
+ struct operand *dest)
+{
+ __emit64_sub_imm_reg(buf, src->imm, mach_reg(&dest->reg));
+}
+
+static void __emit32_sub_imm_reg(struct buffer *buf,
+ unsigned long imm,
+ enum machine_reg reg)
+{
+ emit_alu_imm_reg(buf, 0, 0x05, imm, reg);
+}
+
+static void emit32_sub_imm_reg(struct buffer *buf,
+ struct operand *src,
+ struct operand *dest)
+{
+ __emit32_sub_imm_reg(buf, src->imm, mach_reg(&dest->reg));
+}
+
+static void __emit64_add_imm_reg(struct buffer *buf,
+ long imm,
+ enum machine_reg reg)
+{
+ emit_alu_imm_reg(buf, 1, 0x00, imm, reg);
+}
+
+static void emit64_add_imm_reg(struct buffer *buf,
+ struct operand *src,
+ struct operand *dest)
+{
+ __emit64_add_imm_reg(buf, src->imm, mach_reg(&dest->reg));
+}
+
+static void __emit32_add_imm_reg(struct buffer *buf,
+ long imm,
+ enum machine_reg reg)
+{
+ emit_alu_imm_reg(buf, 0, 0x00, imm, reg);
+}
+
+static void emit32_add_imm_reg(struct buffer *buf,
+ struct operand *src,
+ struct operand *dest)
+{
+ __emit64_add_imm_reg(buf, src->imm, mach_reg(&dest->reg));
+}
+
+static void emit_imm64(struct buffer *buf, int imm)
+{
+ union {
+ int val;
+ unsigned char b[8];
+ } imm_buf;
+
+ imm_buf.val = imm;
+ emit(buf, imm_buf.b[0]);
+ emit(buf, imm_buf.b[1]);
+ emit(buf, imm_buf.b[2]);
+ emit(buf, imm_buf.b[3]);
+ emit(buf, imm_buf.b[4]);
+ emit(buf, imm_buf.b[5]);
+ emit(buf, imm_buf.b[6]);
+ emit(buf, imm_buf.b[7]);
+}
+
+static void emit64_imm(struct buffer *buf, long imm)
+{
+ if (is_imm_8(imm))
+ emit(buf, imm);
+ else
+ emit_imm64(buf, imm);
+}
+
+static void __emit64_push_imm(struct buffer *buf, long imm)
+{
+ unsigned char opc;
+
+ if (is_imm_8(imm))
+ opc = 0x6a;
+ else
+ opc = 0x68;
+
+ emit(buf, opc);
+ emit64_imm(buf, imm);
+}
+
+static void emit64_push_imm(struct buffer *buf, struct operand *operand)
+{
+ __emit64_push_imm(buf, operand->imm);
+}
+
+static void __emit_membase(struct buffer *buf,
+ int rex_w,
+ unsigned char opc,
+ enum machine_reg base_reg,
+ unsigned long disp,
+ unsigned char reg_opcode)
+{
+ unsigned char rex_pfx = 0, mod, rm, mod_rm;
+ unsigned char __base_reg = __encode_reg(base_reg);
+ int needs_sib;
+
+ needs_sib = (base_reg == REG_ESP);
+
+ emit(buf, opc);
+
+ if (needs_sib)
+ rm = 0x04;
+ else
+ rm = __base_reg;
+
+ if (is_imm_8(disp))
+ mod = 0x01;
+ else
+ mod = 0x02;
+
+ if (rex_w)
+ rex_pfx |= REX_W;
+ if (reg_high(reg_opcode))
+ rex_pfx |= REX_R;
+ if (reg_high(__base_reg))
+ rex_pfx |= REX_B;
+
+ if (rex_pfx)
+ emit(buf, rex_pfx);
+
+ mod_rm = encode_modrm(mod, reg_opcode, rm);
+ emit(buf, mod_rm);
+
+ if (needs_sib)
+ emit(buf, encode_sib(0x00, 0x04, __base_reg));
+
+ emit_imm(buf, disp);
+}
+
+static void __emit64_push_membase(struct buffer *buf,
+ enum machine_reg src_reg,
+ unsigned long disp)
+{
+ __emit_membase(buf, 0, 0xff, src_reg, disp, 6);
+}
+
+static void emit_exception_test(struct buffer *buf, enum machine_reg reg)
+{
+ /* FIXME: implement this! */
+}
+
+struct emitter emitters[] = {
+ GENERIC_X86_EMITTERS,
+
+ DECL_EMITTER(INSN64_ADD_IMM_REG, emit64_add_imm_reg, TWO_OPERANDS),
+ DECL_EMITTER(INSN64_MOV_REG_REG, emit64_mov_reg_reg, TWO_OPERANDS),
+ DECL_EMITTER(INSN64_PUSH_IMM, emit64_push_imm, SINGLE_OPERAND),
+ DECL_EMITTER(INSN64_PUSH_REG, emit64_push_reg, SINGLE_OPERAND),
+ DECL_EMITTER(INSN64_POP_REG, emit64_pop_reg, SINGLE_OPERAND),
+ DECL_EMITTER(INSN64_SUB_IMM_REG, emit64_sub_imm_reg, TWO_OPERANDS),
+
+ DECL_EMITTER(INSN32_ADD_IMM_REG, emit32_add_imm_reg, TWO_OPERANDS),
+ DECL_EMITTER(INSN32_MOV_REG_REG, emit32_mov_reg_reg, TWO_OPERANDS),
+ DECL_EMITTER(INSN32_SUB_IMM_REG, emit32_sub_imm_reg, TWO_OPERANDS),
+};
+
+void emit_prolog(struct buffer *buf, unsigned long nr_locals)
+{
+ __emit_push_reg(buf, REG_RBX);
+ __emit_push_reg(buf, REG_R12);
+ __emit_push_reg(buf, REG_R13);
+ __emit_push_reg(buf, REG_R14);
+ __emit_push_reg(buf, REG_R15);
+
+ /*
+ * The ABI requires us to clear DF, but we
+ * don't need to. Though keep this in mind:
+ * emit(buf, 0xFC);
+ */
+
+ __emit_push_reg(buf, REG_RBP);
+ __emit64_mov_reg_reg(buf, REG_RSP, REG_RBP);
+
+ if (nr_locals)
+ __emit64_sub_imm_reg(buf,
+ nr_locals * sizeof(unsigned long),
+ REG_RSP);
+}
+
+void emit_epilog(struct buffer *buf)
+{
+ emit_leave(buf);
+
+ /* Restore callee saved registers */
+ __emit_pop_reg(buf, REG_R15);
+ __emit_pop_reg(buf, REG_R14);
+ __emit_pop_reg(buf, REG_R13);
+ __emit_pop_reg(buf, REG_R12);
+ __emit_pop_reg(buf, REG_RBX);
}
void emit_trampoline(struct compilation_unit *cu, void *call_target,
diff --git a/arch/x86/include/arch/instruction.h
b/arch/x86/include/arch/instruction.h
index 86c8492..72b9698 100644
--- a/arch/x86/include/arch/instruction.h
+++ b/arch/x86/include/arch/instruction.h
@@ -109,6 +109,33 @@ enum insn_type {
INSN_TEST_MEMBASE_REG,
INSN_XOR_MEMBASE_REG,
INSN_XOR_IMM_REG,
+
+#ifdef CONFIG_X86_64
+ INSN64_ADD_IMM_REG,
+ INSN64_MOV_REG_REG,
+ INSN64_PUSH_IMM,
+ INSN64_PUSH_REG,
+ INSN64_POP_REG,
+ INSN64_SUB_IMM_REG,
+
+ INSN32_ADD_IMM_REG,
+ INSN32_MOV_REG_REG,
+ INSN32_PUSH_IMM,
+ INSN32_PUSH_REG,
+ INSN32_POP_REG,
+ INSN32_SUB_IMM_REG,
+
+ /* Aliases for instructions in common code. */
+ INSN64_CALL_REL = INSN_CALL_REL,
+ INSN64_JE_BRANCH = INSN_JE_BRANCH,
+ INSN64_JGE_BRANCH = INSN_JGE_BRANCH,
+ INSN64_JG_BRANCH = INSN_JG_BRANCH,
+ INSN64_JLE_BRANCH = INSN_JLE_BRANCH,
+ INSN64_JL_BRANCH = INSN_JL_BRANCH,
+ INSN64_JMP_BRANCH = INSN_JMP_BRANCH,
+ INSN64_JNE_BRANCH = INSN_JNE_BRANCH,
+ INSN64_RET = INSN_RET,
+#endif
};
struct insn {
--
1.6.0.6
------------------------------------------------------------------------------
Crystal Reports - New Free Runtime and 30 Day Trial
Check out the new simplified licensing option that enables unlimited
royalty-free distribution of the report engine for externally facing
server and web deployment.
http://p.sf.net/sfu/businessobjects
_______________________________________________
Jatovm-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jatovm-devel