From b095aedd386e076d1f5a56b7384b836e653387d1 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Tue, 17 Sep 2019 01:28:55 +0200 Subject: Add support for r8-r15 registers, pass args to registers directly (sys-v) --- executor/x86_64/asm.c | 203 ++++++++++++++++++++++++++++---------------------- 1 file changed, 116 insertions(+), 87 deletions(-) (limited to 'executor/x86_64/asm.c') diff --git a/executor/x86_64/asm.c b/executor/x86_64/asm.c index c633db8..60b1752 100644 --- a/executor/x86_64/asm.c +++ b/executor/x86_64/asm.c @@ -8,7 +8,31 @@ #include -#define REX_W 0x48 +/* REX documentation: https://wiki.osdev.org/X86-64_Instruction_Encoding#Encoding */ +#define REX_W 0x48 /* 0 = 32-bit operand size, 1 = 64-bit operand size - For most operations... */ + +static u8 rex_rr(Reg64 dst, Reg64 src) { + u8 rex = REX_W; + rex |= ((dst & REG64_EXTENDED_REG_BIT) >> 3); /* REX.B */ + rex |= ((src & REG64_EXTENDED_REG_BIT) >> 1); /* REX.R */ + assert(REG64_EXTENDED_REG_BIT == (1<<3)); + return rex; +} + +static u8 rex_sib(Reg64 dst, Reg64 src) { + u8 rex = REX_W; + rex |= ((src & REG64_EXTENDED_REG_BIT) >> 3); /* REX.B */ + rex |= ((dst & REG64_EXTENDED_REG_BIT) >> 2); /* REX.X */ + assert(REG64_EXTENDED_REG_BIT == (1<<3)); + return rex; +} + +static u8 rex_rm(AsmPtr *dst, Reg64 src) { + assert(REG64_EXTENDED_REG_BIT == (1<<3)); + if(dst->index == 0 && (dst->base & REG64_REG_BITS) != RBP) + return rex_rr(dst->base, src); + return rex_sib(dst->base, src); +} #ifdef DEBUG #include @@ -84,6 +108,14 @@ static const char* reg64_to_str(Reg64 reg) { case RBP: return "rbp"; case RSI: return "rsi"; case RDI: return "rdi"; + case R8: return "r8"; + case R9: return "r9"; + case R10: return "r10"; + case R11: return "r11"; + case R12: return "r12"; + case R13: return "r13"; + case R14: return "r14"; + case R15: return "r15"; } assert(bool_false); return NULL; @@ -270,7 +302,7 @@ static void asm_rm(Asm *self, AsmPtr *mem, Reg64 reg) { u8 rm_byte; u8 disp_bytes; assert(asm_get_capacity_left(self) >= 6); - if((int)mem->index != -1) { + if((int)mem->index != -1) { /* SIB */ u8 sib_offset; if(mem->disp == 0) { rm_byte = 0x04; @@ -293,31 +325,33 @@ static void asm_rm(Asm *self, AsmPtr *mem, Reg64 reg) { } #endif assert(mem->base != RBP && "TODO: Implement RBP base for sib byte. RBP is special and requires different logic"); - sib_offset = (mem->scale << 5) + 8*mem->index + mem->base; + assert(mem->index != R13 && "TODO: Implement R13 base for sib byte. R13 is special and requires different logic"); + sib_offset = (mem->scale << 5) + 8*(mem->index & REG64_REG_BITS) + (mem->base & REG64_REG_BITS); *self->code_it++ = rm_byte; *self->code_it++ = sib_offset; } else { + u8 base = (mem->base & REG64_REG_BITS); assert(mem->scale == 0); /* Scale isn't valid without index reg */ if(mem->disp == 0) { - if(mem->base == RBP) { + if(base == RBP) { rm_byte = 0x45; - disp_bytes = 1; + disp_bytes = 1; /* RBP requires use of disp byte, even if it's not used */ } else { - rm_byte = mem->base; + rm_byte = base; disp_bytes = 0; } } else if(abs_i32(mem->disp) <= INT8_MAX) { - rm_byte = 0x40 + mem->base; + rm_byte = 0x40 + base; disp_bytes = 1; } else { - rm_byte = 0x80 + mem->base; + rm_byte = 0x80 + base; disp_bytes = 4; } - *self->code_it++ = (reg << 3) | rm_byte; + *self->code_it++ = ((reg & REG64_REG_BITS) << 3) | rm_byte; /* RSP requires SIB byte */ - if(mem->base == RSP) + if(base == RSP) *self->code_it++ = 0x24; } @@ -328,13 +362,13 @@ static void asm_rm(Asm *self, AsmPtr *mem, Reg64 reg) { /* There has to be at least 1 byte left in the asm buffer before calling this function. */ static void asm_rr(Asm *self, Reg64 dst, Reg64 src) { assert(asm_get_capacity_left(self) >= 1); - *self->code_it++ = 0xC0 + dst + 8*src; + *self->code_it++ = 0xC0 + (dst & REG64_REG_BITS) + 8*(src & REG64_REG_BITS); } /* TODO: Implement 1 and 2 byte immediate? */ void asm_mov_mi(Asm *self, AsmPtr *dst, i32 immediate) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rm(dst, 0); *self->code_it++ = 0xC7; asm_rm(self, dst, 0); am_memcpy(self->code_it, &immediate, sizeof(immediate)); @@ -344,7 +378,7 @@ void asm_mov_mi(Asm *self, AsmPtr *dst, i32 immediate) { void asm_mov_mr(Asm *self, AsmPtr *dst, Reg64 src) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rm(dst, src); *self->code_it++ = 0x89; asm_rm(self, dst, src); ins_end(self, "mov %s, %s", asm_ptr_to_string(dst), reg64_to_str(src)); @@ -352,7 +386,7 @@ void asm_mov_mr(Asm *self, AsmPtr *dst, Reg64 src) { void asm_mov_rm(Asm *self, Reg64 dst, AsmPtr *src) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rm(src, dst); *self->code_it++ = 0x8B; asm_rm(self, src, dst); ins_end(self, "mov %s, %s", reg64_to_str(dst), asm_ptr_to_string(src)); @@ -361,7 +395,7 @@ void asm_mov_rm(Asm *self, Reg64 dst, AsmPtr *src) { /* Note: This shows as instruction movabs in intel assembly format */ void asm_mov_ri(Asm *self, Reg64 dst, i64 immediate) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rr(dst, 0); *self->code_it++ = 0xB8 + dst; am_memcpy(self->code_it, &immediate, sizeof(immediate)); self->code_it += sizeof(immediate); @@ -370,7 +404,7 @@ void asm_mov_ri(Asm *self, Reg64 dst, i64 immediate) { void asm_mov_rr(Asm *self, Reg64 dst, Reg64 src) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rr(dst, src); *self->code_it++ = 0x89; asm_rr(self, dst, src); ins_end(self, "mov %s, %s", reg64_to_str(dst), reg64_to_str(src)); @@ -378,7 +412,7 @@ void asm_mov_rr(Asm *self, Reg64 dst, Reg64 src) { void asm_add_rr(Asm *self, Reg64 dst, Reg64 src) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rr(dst, src); *self->code_it++ = 0x01; asm_rr(self, dst, src); ins_end(self, "add %s, %s", reg64_to_str(dst), reg64_to_str(src)); @@ -386,7 +420,7 @@ void asm_add_rr(Asm *self, Reg64 dst, Reg64 src) { void asm_sub_rr(Asm *self, Reg64 dst, Reg64 src) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rr(dst, src); *self->code_it++ = 0x29; asm_rr(self, dst, src); ins_end(self, "sub %s, %s", reg64_to_str(dst), reg64_to_str(src)); @@ -394,7 +428,7 @@ void asm_sub_rr(Asm *self, Reg64 dst, Reg64 src) { void asm_imul_rr(Asm *self, Reg64 dst, Reg64 src) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rr(dst, src); *self->code_it++ = 0x0F; *self->code_it++ = 0xAF; asm_rr(self, dst, src); @@ -410,7 +444,7 @@ void asm_cqo(Asm *self) { void asm_idiv_rr(Asm *self, Reg64 src) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rr(src, 0); *self->code_it++ = 0xF7; asm_rr(self, src, 0x7); ins_end(self, "idiv %s", reg64_to_str(src)); @@ -430,7 +464,7 @@ void asm_popr(Asm *self, Reg64 reg) { void asm_callr(Asm *self, Reg64 reg) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rr(reg, 0); *self->code_it++ = 0xFF; asm_rr(self, reg, 0x2); ins_end(self, "call %s", reg64_to_str(reg)); @@ -457,7 +491,7 @@ void asm_overwrite_call_rel32(Asm *self, u32 asm_index, i32 new_relative) { void asm_cmp_rm(Asm *self, Reg64 reg1, AsmPtr *reg2) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rm(reg2, reg1); *self->code_it++ = 0x3B; asm_rm(self, reg2, reg1); ins_end(self, "cmp %s, %s", reg64_to_str(reg1), asm_ptr_to_string(reg2)); @@ -546,25 +580,20 @@ void asm_overwrite_jmp_rel32(Asm *self, u32 asm_index, i32 new_relative) { } /* TODO: Remove these !*/ - /* /r */ -#define DEFINE_INS_RM(mnemonic, opcode) \ -void asm_##mnemonic##_rmb(Asm *self, Reg32 dst, Reg32 src) { \ - *self->code_it++ = opcode; \ - *self->code_it++ = 0xC0 + 8*dst + src; \ -} \ - \ -void asm_##mnemonic##_rm32(Asm *self, Reg32 dst, Reg32 src) { \ - ins_start(self); \ - asm_##mnemonic##_rmb(self, (Reg32)dst, (Reg32)src); \ - ins_end(self, #mnemonic" %s, %s", reg32_to_str(dst), reg32_to_str(src)); \ -} \ - \ -void asm_##mnemonic##_rm64(Asm *self, Reg64 dst, Reg64 src) { \ - ins_start(self); \ - *self->code_it++ = REX_W; \ - asm_##mnemonic##_rmb(self, (Reg32)dst, (Reg32)src); \ - ins_end(self, #mnemonic" %s, %s", reg64_to_str(dst), reg64_to_str(src)); \ +#define DEFINE_INS_RM(mnemonic, opcode) \ +void asm_##mnemonic##_rm32(Asm *self, Reg32 dst, Reg32 src) { \ + ins_start(self); \ + *self->code_it++ = opcode; \ + asm_rr(self, (Reg64)src, (Reg64)dst); \ + ins_end(self, #mnemonic" %s, %s", reg32_to_str(dst), reg32_to_str(src)); \ +} \ + \ +void asm_##mnemonic##_rm64(Asm *self, Reg64 dst, Reg64 src) { \ + ins_start(self); \ + *self->code_it++ = opcode; \ + asm_rr(self, src, dst); \ + ins_end(self, #mnemonic" %s, %s", reg64_to_str(dst), reg64_to_str(src)); \ } DEFINE_INS_RM(mov, 0x8B) @@ -581,31 +610,31 @@ DEFINE_INS_RM(cmp, 0x3B) It's a number used to extend the opcode type, since the instruction only uses one register the other register can be encoded for that. */ -#define DEFINE_INS_EXT_IMM(mnemonic, extension) \ -void asm_##mnemonic##_rmb_imm(Asm *self, Reg32 reg, i32 immediate) { \ - if(abs_i32(immediate) <= INT8_MAX) { \ - *self->code_it++ = 0x83; \ - *self->code_it++ = 0xC0 + 8*extension + reg; \ - *self->code_it++ = (u8)immediate; \ - } else { \ - *self->code_it++ = 0x81; \ - *self->code_it++ = 0xC0 + 8*extension + reg; \ - am_memcpy(self->code_it, &immediate, sizeof(immediate)); \ - self->code_it += sizeof(immediate); \ - } \ -} \ - \ -void asm_##mnemonic##_rm32_imm(Asm *self, Reg32 reg, i32 immediate) { \ - ins_start(self); \ - asm_##mnemonic##_rmb_imm(self, (Reg32)reg, immediate); \ - ins_end(self, #mnemonic" %s, 0x%x", reg32_to_str(reg), immediate); \ -}\ - \ -void asm_##mnemonic##_rm64_imm(Asm *self, Reg64 reg, i32 immediate) { \ - ins_start(self); \ - *self->code_it++ = REX_W; \ - asm_##mnemonic##_rmb_imm(self, (Reg32)reg, immediate); \ - ins_end(self, #mnemonic" %s, 0x%x", reg64_to_str(reg), immediate); \ +#define DEFINE_INS_EXT_IMM(mnemonic, extension) \ +void asm_##mnemonic##_rmb_imm(Asm *self, Reg32 reg, i32 immediate) { \ + if(abs_i32(immediate) <= INT8_MAX) { \ + *self->code_it++ = 0x83; \ + asm_rr(self, (Reg64)reg, (Reg64)(extension)); \ + *self->code_it++ = (u8)immediate; \ + } else { \ + *self->code_it++ = 0x81; \ + asm_rr(self, (Reg64)reg, (Reg64)(extension)); \ + am_memcpy(self->code_it, &immediate, sizeof(immediate)); \ + self->code_it += sizeof(immediate); \ + } \ +} \ + \ +void asm_##mnemonic##_rm32_imm(Asm *self, Reg32 reg, i32 immediate) { \ + ins_start(self); \ + asm_##mnemonic##_rmb_imm(self, (Reg32)reg, immediate); \ + ins_end(self, #mnemonic" %s, 0x%x", reg32_to_str(reg), immediate); \ +} \ + \ +void asm_##mnemonic##_rm64_imm(Asm *self, Reg64 reg, i32 immediate) { \ + ins_start(self); \ + *self->code_it++ = rex_rr(reg, 0); \ + asm_##mnemonic##_rmb_imm(self, (Reg32)reg, immediate); \ + ins_end(self, #mnemonic" %s, 0x%x", reg64_to_str(reg), immediate); \ } DEFINE_INS_EXT_IMM(add, 0) @@ -623,28 +652,28 @@ DEFINE_INS_EXT_IMM(cmp, 7) It's a number used to extend the opcode type, since the instruction only uses one register the other register can be encoded for that. */ -#define DEFINE_INS_SHIFT_IMM8(mnemonic, extension) \ -void asm_##mnemonic##_rmb_imm(Asm *self, Reg32 reg, i8 immediate) { \ - if(immediate == 1) { \ - *self->code_it++ = 0xC1; \ - *self->code_it++ = 0xC0 + 8*reg + extension; \ - } else { \ - *self->code_it++ = 0xD1; \ - *self->code_it++ = 0xC0 + 8*reg + extension; \ - *self->code_it++ = immediate; \ - } \ -} \ - \ -void asm_##mnemonic##_rm32_imm(Asm *self, Reg32 reg, i8 immediate) { \ - ins_start(self); \ - ins_end(self, #mnemonic" %s, 0x%x", reg32_to_str(reg), immediate); \ -} \ - \ -void asm_##mnemonic##_rm64_imm(Asm *self, Reg64 reg, i8 immediate) { \ - ins_start(self); \ - *self->code_it++ = REX_W; \ - asm_##mnemonic##_rmb_imm(self, (Reg32)reg, immediate); \ - ins_end(self, #mnemonic" %s, 0x%x", reg64_to_str(reg), immediate); \ +#define DEFINE_INS_SHIFT_IMM8(mnemonic, extension) \ +void asm_##mnemonic##_rmb_imm(Asm *self, Reg32 reg, i8 immediate) { \ + if(immediate == 1) { \ + *self->code_it++ = 0xC1; \ + asm_rr(self, (Reg64)reg, (Reg64)(extension)); \ + } else { \ + *self->code_it++ = 0xD1; \ + asm_rr(self, (Reg64)reg, (Reg64)(extension)); \ + *self->code_it++ = immediate; \ + } \ +} \ + \ +void asm_##mnemonic##_rm32_imm(Asm *self, Reg32 reg, i8 immediate) { \ + ins_start(self); \ + ins_end(self, #mnemonic" %s, 0x%x", reg32_to_str(reg), immediate); \ +} \ + \ +void asm_##mnemonic##_rm64_imm(Asm *self, Reg64 reg, i8 immediate) { \ + ins_start(self); \ + *self->code_it++ = rex_rr(reg, 0); \ + asm_##mnemonic##_rmb_imm(self, (Reg32)reg, immediate); \ + ins_end(self, #mnemonic" %s, 0x%x", reg64_to_str(reg), immediate); \ } DEFINE_INS_SHIFT_IMM8(rol, 0) -- cgit v1.2.3