This implements some basic emitters specific to x86-64.
Signed-off-by: Eduard - Gabriel Munteanu <[email protected]>
---
arch/x86/emit-code_64.c | 242 +++++++++++++++++++++++++++++++++--
arch/x86/include/arch/instruction.h | 7 +
2 files changed, 238 insertions(+), 11 deletions(-)
diff --git a/arch/x86/emit-code_64.c b/arch/x86/emit-code_64.c
index 2862ddf..bd49499 100644
--- a/arch/x86/emit-code_64.c
+++ b/arch/x86/emit-code_64.c
@@ -31,30 +31,250 @@
#include <stdlib.h>
-void emit_prolog(struct buffer *buf, unsigned long nr_locals)
+#include "emit-code.c"
+
+#define PREFIX_REX 40
+#define PREFIX_REX_W (PREFIX_REX | 8) /* 64-bit operands */
+#define PREFIX_REX_R (PREFIX_REX | 4) /* ModRM reg extension */
+#define PREFIX_REX_X (PREFIX_REX | 2) /* SIB index extension */
+#define PREFIX_REX_B (PREFIX_REX | 1) /* ModRM r/m extension */
+
+/*
+ * __encode_reg: Encode register to be used in IA-32 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 void __emit64_push_reg(struct buffer *buf, enum machine_reg reg)
{
- abort();
+ emit(buf, PREFIX_REX_W);
+ __emit_push_reg(buf, reg);
}
-void emit_epilog(struct buffer *buf, unsigned long nr_locals)
+static void emit64_push_reg(struct buffer *buf, struct operand *operand)
{
- abort();
+ __emit64_push_reg(buf, mach_reg(&operand->reg));
}
-void emit_branch_rel(struct buffer *buf, unsigned char prefix,
- unsigned char opc, long rel32)
+static void __emit64_pop_reg(struct buffer *buf, enum machine_reg reg)
{
- abort();
+ emit(buf, PREFIX_REX_W);
+ __emit_pop_reg(buf, reg);
}
-void emit_body(struct basic_block *bb, struct buffer *buf)
+static void emit64_pop_reg(struct buffer *buf, struct operand *operand)
{
- abort();
+ __emit64_pop_reg(buf, mach_reg(&operand->reg));
+}
+
+static void __emit64_mov_reg_reg(struct buffer *buf,
+ enum machine_reg src,
+ enum machine_reg dst)
+{
+ emit(buf, PREFIX_REX_W);
+ __emit_mov_reg_reg(buf, src, dst);
+}
+
+static void __emit64_sub_imm_reg(struct buffer *buf,
+ unsigned long imm,
+ enum machine_reg reg)
+{
+ emit(buf, PREFIX_REX_W);
+ __emit_sub_imm_reg(buf, imm, reg);
+}
+
+static void emit64_sub_imm_reg(struct buffer *buf,
+ struct operand *src,
+ struct operand *dst)
+{
+ __emit64_sub_imm_reg(buf, src->imm, mach_reg(&dst->reg));
+}
+
+static struct emitter emitters[] = {
+ GENERIC_X86_EMITTERS,
+ DECL_EMITTER(INSN64_MOV_REG_REG, emit64_push_reg, TWO_OPERANDS),
+ 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),
+};
+
+static inline bool is_imm_32(long imm)
+{
+ return (imm >= -2147483648) && (imm <= 2147483647);
+}
+
+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 emit_imm(struct buffer *buf, long imm)
+{
+ if (is_imm_8(imm))
+ emit(buf, imm);
+ else if (is_imm_32(imm))
+ emit_imm32(buf, imm);
+ else
+ emit_imm64(buf, imm);
+}
+
+static void write_imm64(struct buffer *buf, unsigned long offset, long imm64)
+{
+ unsigned char *buffer;
+ union {
+ int val;
+ unsigned char b[8];
+ } imm_buf;
+
+ buffer = buf->buf;
+ imm_buf.val = imm64;
+
+ buffer[offset] = imm_buf.b[0];
+ buffer[offset + 1] = imm_buf.b[1];
+ buffer[offset + 2] = imm_buf.b[2];
+ buffer[offset + 3] = imm_buf.b[3];
+ buffer[offset + 4] = imm_buf.b[4];
+ buffer[offset + 5] = imm_buf.b[5];
+ buffer[offset + 6] = imm_buf.b[6];
+ buffer[offset + 7] = imm_buf.b[7];
+}
+
+static void backpatch_branch_target(struct buffer *buf,
+ struct insn *insn,
+ unsigned long target_offset)
+{
+ unsigned long backpatch_offset;
+ long relative_addr;
+
+ backpatch_offset = insn->mach_offset + BRANCH_TARGET_OFFSET;
+ if (insn->escaped)
+ backpatch_offset += PREFIX_SIZE;
+
+ relative_addr = branch_rel_addr(insn, target_offset);
+
+ write_imm64(buf, backpatch_offset, relative_addr);
+}
+
+void emit_prolog(struct buffer *buf, unsigned long nr_locals)
+{
+ __emit64_push_reg(buf, REG_RBX);
+ __emit64_push_reg(buf, REG_R12);
+ __emit64_push_reg(buf, REG_R13);
+ __emit64_push_reg(buf, REG_R14);
+ __emit64_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);
+ */
+
+ __emit64_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, unsigned long nr_locals)
+{
+ if (nr_locals)
+ emit(buf, 0xc9);
+ else
+ __emit_pop_reg(buf, REG_RBP);
+
+ /* 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);
+
+ emit_ret(buf);
+}
+
+void emit_branch_rel(struct buffer *buf, unsigned char prefix,
+ unsigned char opc, long rel64)
+{
+ if (prefix)
+ emit(buf, prefix);
+ emit(buf, opc);
+ emit_imm64(buf, rel64);
}
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 ac75e40..cbb3020 100644
--- a/arch/x86/include/arch/instruction.h
+++ b/arch/x86/include/arch/instruction.h
@@ -105,6 +105,13 @@ enum insn_type {
INSN_SUB_REG_REG,
INSN_XOR_MEMBASE_REG,
INSN_XOR_IMM_REG,
+
+#ifdef CONFIG_X86_64
+ INSN64_MOV_REG_REG,
+ INSN64_PUSH_REG,
+ INSN64_POP_REG,
+ INSN64_SUB_IMM_REG,
+#endif
};
struct insn {
--
1.6.0.6
------------------------------------------------------------------------------
Register Now for Creativity and Technology (CaT), June 3rd, NYC. CaT
is a gathering of tech-side developers & brand creativity professionals. Meet
the minds behind Google Creative Lab, Visual Complexity, Processing, &
iPhoneDevCamp asthey present alongside digital heavyweights like Barbarian
Group, R/GA, & Big Spaceship. http://www.creativitycat.com
_______________________________________________
Jatovm-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jatovm-devel