This implements some basic emitters specific to x86-64.

Signed-off-by: Eduard - Gabriel Munteanu <eduard.munte...@linux360.ro>
---
 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
Jatovm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to