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