/* * ___ _ _ * ___ / _ \| |_ ___ ___ | | * / _ \ (_) | __/ _ \ / _ \| | * | __/\__, | || (_) | (_) | | * \___| /_/ \__\___/ \___/|_| * * Copyright (C) 2021 National University of Singapore * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <cassert> #include <cstdint> #include <cstdio> #include "e9codegen.h" #include "e9tool.h" #include "e9types.h" using namespace e9tool; /* * Get argument register index. */ int getArgRegIdx(bool sysv, int argno) { switch (argno) { case 0: return (sysv? RDI_IDX: RCX_IDX); case 1: return (sysv? RSI_IDX: RDX_IDX); case 2: return (sysv? RDX_IDX: R8_IDX); case 3: return (sysv? RCX_IDX: R9_IDX); case 4: return (sysv? R8_IDX: R10_IDX); case 5: return (sysv? R9_IDX: R11_IDX); case 6: return (sysv? R10_IDX: -1); case 7: return (sysv? R11_IDX: -1); default: return -1; } } /* * Convert a register number into a register. */ Register getReg(int regno) { switch (regno) { case RDI_IDX: return REGISTER_RDI; case RSI_IDX: return REGISTER_RSI; case RDX_IDX: return REGISTER_RDX; case RCX_IDX: return REGISTER_RCX; case R8_IDX: return REGISTER_R8; case R9_IDX: return REGISTER_R9; case RFLAGS_IDX: return REGISTER_EFLAGS; case RAX_IDX: return REGISTER_RAX; case R10_IDX: return REGISTER_R10; case R11_IDX: return REGISTER_R11; case RBX_IDX: return REGISTER_RBX; case RBP_IDX: return REGISTER_RBP; case R12_IDX: return REGISTER_R12; case R13_IDX: return REGISTER_R13; case R14_IDX: return REGISTER_R14; case R15_IDX: return REGISTER_R15; case RSP_IDX: return REGISTER_RSP; case RIP_IDX: return REGISTER_RIP; default: return REGISTER_INVALID; } } /* * Convert a register into a register index. */ int getRegIdx(Register reg) { switch (reg) { case REGISTER_DI: case REGISTER_DIL: case REGISTER_EDI: case REGISTER_RDI: return RDI_IDX; case REGISTER_SI: case REGISTER_SIL: case REGISTER_ESI: case REGISTER_RSI: return RSI_IDX; case REGISTER_DH: case REGISTER_DL: case REGISTER_DX: case REGISTER_EDX: case REGISTER_RDX: return RDX_IDX; case REGISTER_CH: case REGISTER_CL: case REGISTER_CX: case REGISTER_ECX: case REGISTER_RCX: return RCX_IDX; case REGISTER_R8B: case REGISTER_R8W: case REGISTER_R8D: case REGISTER_R8: return R8_IDX; case REGISTER_R9B: case REGISTER_R9W: case REGISTER_R9D: case REGISTER_R9: return R9_IDX; case REGISTER_AH: case REGISTER_AL: case REGISTER_AX: case REGISTER_EAX: case REGISTER_RAX: return RAX_IDX; case REGISTER_R10B: case REGISTER_R10W: case REGISTER_R10D: case REGISTER_R10: return R10_IDX; case REGISTER_R11B: case REGISTER_R11W: case REGISTER_R11D: case REGISTER_R11: return R11_IDX; case REGISTER_BH: case REGISTER_BL: case REGISTER_BX: case REGISTER_EBX: case REGISTER_RBX: return RBX_IDX; case REGISTER_BP: case REGISTER_BPL: case REGISTER_EBP: case REGISTER_RBP: return RBP_IDX; case REGISTER_R12B: case REGISTER_R12W: case REGISTER_R12D: case REGISTER_R12: return R12_IDX; case REGISTER_R13B: case REGISTER_R13W: case REGISTER_R13D: case REGISTER_R13: return R13_IDX; case REGISTER_R14B: case REGISTER_R14W: case REGISTER_R14D: case REGISTER_R14: return R14_IDX; case REGISTER_R15B: case REGISTER_R15W: case REGISTER_R15D: case REGISTER_R15: return R15_IDX; case REGISTER_SP: case REGISTER_SPL: case REGISTER_ESP: case REGISTER_RSP: return RSP_IDX; default: return -1; } } /* * Convert a register into a canonical register. */ Register getCanonicalReg(Register reg) { switch (reg) { case REGISTER_DI: case REGISTER_DIL: case REGISTER_EDI: case REGISTER_RDI: return REGISTER_RDI; case REGISTER_SI: case REGISTER_SIL: case REGISTER_ESI: case REGISTER_RSI: return REGISTER_RSI; case REGISTER_DH: case REGISTER_DL: case REGISTER_DX: case REGISTER_EDX: case REGISTER_RDX: return REGISTER_RDX; case REGISTER_CH: case REGISTER_CL: case REGISTER_CX: case REGISTER_ECX: case REGISTER_RCX: return REGISTER_RCX; case REGISTER_R8B: case REGISTER_R8W: case REGISTER_R8D: case REGISTER_R8: return REGISTER_R8; case REGISTER_R9B: case REGISTER_R9W: case REGISTER_R9D: case REGISTER_R9: return REGISTER_R9; case REGISTER_AH: case REGISTER_AL: case REGISTER_AX: case REGISTER_EAX: case REGISTER_RAX: return REGISTER_RAX; case REGISTER_R10B: case REGISTER_R10W: case REGISTER_R10D: case REGISTER_R10: return REGISTER_R10; case REGISTER_R11B: case REGISTER_R11W: case REGISTER_R11D: case REGISTER_R11: return REGISTER_R11; case REGISTER_BH: case REGISTER_BL: case REGISTER_BX: case REGISTER_EBX: case REGISTER_RBX: return REGISTER_RBX; case REGISTER_BP: case REGISTER_BPL: case REGISTER_EBP: case REGISTER_RBP: return REGISTER_RBP; case REGISTER_R12B: case REGISTER_R12W: case REGISTER_R12D: case REGISTER_R12: return REGISTER_R12; case REGISTER_R13B: case REGISTER_R13W: case REGISTER_R13D: case REGISTER_R13: return REGISTER_R13; case REGISTER_R14B: case REGISTER_R14W: case REGISTER_R14D: case REGISTER_R14: return REGISTER_R14; case REGISTER_R15B: case REGISTER_R15W: case REGISTER_R15D: case REGISTER_R15: return REGISTER_R15; case REGISTER_SP: case REGISTER_SPL: case REGISTER_ESP: case REGISTER_RSP: return REGISTER_RSP; case REGISTER_IP: case REGISTER_EIP: case REGISTER_RIP: return REGISTER_RIP; default: return reg; } } /* * Get the storage size of a register. */ int32_t getRegSize(Register reg) { switch (reg) { case REGISTER_AH: case REGISTER_AL: case REGISTER_BH: case REGISTER_BL: case REGISTER_CH: case REGISTER_CL: case REGISTER_BPL: case REGISTER_DIL: case REGISTER_DL: case REGISTER_DH: case REGISTER_SIL: case REGISTER_SPL: case REGISTER_R8B: case REGISTER_R9B: case REGISTER_R10B: case REGISTER_R11B: case REGISTER_R12B: case REGISTER_R13B: case REGISTER_R14B: case REGISTER_R15B: return sizeof(int8_t); case REGISTER_EFLAGS: case REGISTER_AX: case REGISTER_BP: case REGISTER_BX: case REGISTER_CX: case REGISTER_DX: case REGISTER_DI: case REGISTER_IP: case REGISTER_SI: case REGISTER_SP: case REGISTER_R8W: case REGISTER_R9W: case REGISTER_R10W: case REGISTER_R11W: case REGISTER_R12W: case REGISTER_R13W: case REGISTER_R14W: case REGISTER_R15W: return sizeof(int16_t); case REGISTER_EAX: case REGISTER_EBP: case REGISTER_EBX: case REGISTER_ECX: case REGISTER_EDI: case REGISTER_EDX: case REGISTER_EIP: case REGISTER_ESI: case REGISTER_ESP: case REGISTER_R8D: case REGISTER_R9D: case REGISTER_R10D: case REGISTER_R11D: case REGISTER_R12D: case REGISTER_R13D: case REGISTER_R14D: case REGISTER_R15D: return sizeof(int32_t); case REGISTER_RAX: case REGISTER_RBP: case REGISTER_RBX: case REGISTER_RCX: case REGISTER_RDI: case REGISTER_RDX: case REGISTER_RIP: case REGISTER_RSI: case REGISTER_RSP: case REGISTER_R8: case REGISTER_R9: case REGISTER_R10: case REGISTER_R11: case REGISTER_R12: case REGISTER_R13: case REGISTER_R14: case REGISTER_R15: return sizeof(int64_t); case REGISTER_XMM0: case REGISTER_XMM1: case REGISTER_XMM2: case REGISTER_XMM3: case REGISTER_XMM4: case REGISTER_XMM5: case REGISTER_XMM6: case REGISTER_XMM7: case REGISTER_XMM8: case REGISTER_XMM9: case REGISTER_XMM10: case REGISTER_XMM11: case REGISTER_XMM12: case REGISTER_XMM13: case REGISTER_XMM14: case REGISTER_XMM15: case REGISTER_XMM16: case REGISTER_XMM17: case REGISTER_XMM18: case REGISTER_XMM19: case REGISTER_XMM20: case REGISTER_XMM21: case REGISTER_XMM22: case REGISTER_XMM23: case REGISTER_XMM24: case REGISTER_XMM25: case REGISTER_XMM26: case REGISTER_XMM27: case REGISTER_XMM28: case REGISTER_XMM29: case REGISTER_XMM30: case REGISTER_XMM31: return 2 * sizeof(int64_t); case REGISTER_YMM0: case REGISTER_YMM1: case REGISTER_YMM2: case REGISTER_YMM3: case REGISTER_YMM4: case REGISTER_YMM5: case REGISTER_YMM6: case REGISTER_YMM7: case REGISTER_YMM8: case REGISTER_YMM9: case REGISTER_YMM10: case REGISTER_YMM11: case REGISTER_YMM12: case REGISTER_YMM13: case REGISTER_YMM14: case REGISTER_YMM15: case REGISTER_YMM16: case REGISTER_YMM17: case REGISTER_YMM18: case REGISTER_YMM19: case REGISTER_YMM20: case REGISTER_YMM21: case REGISTER_YMM22: case REGISTER_YMM23: case REGISTER_YMM24: case REGISTER_YMM25: case REGISTER_YMM26: case REGISTER_YMM27: case REGISTER_YMM28: case REGISTER_YMM29: case REGISTER_YMM30: case REGISTER_YMM31: return 4 * sizeof(int64_t); case REGISTER_ZMM0: case REGISTER_ZMM1: case REGISTER_ZMM2: case REGISTER_ZMM3: case REGISTER_ZMM4: case REGISTER_ZMM5: case REGISTER_ZMM6: case REGISTER_ZMM7: case REGISTER_ZMM8: case REGISTER_ZMM9: case REGISTER_ZMM10: case REGISTER_ZMM11: case REGISTER_ZMM12: case REGISTER_ZMM13: case REGISTER_ZMM14: case REGISTER_ZMM15: case REGISTER_ZMM16: case REGISTER_ZMM17: case REGISTER_ZMM18: case REGISTER_ZMM19: case REGISTER_ZMM20: case REGISTER_ZMM21: case REGISTER_ZMM22: case REGISTER_ZMM23: case REGISTER_ZMM24: case REGISTER_ZMM25: case REGISTER_ZMM26: case REGISTER_ZMM27: case REGISTER_ZMM28: case REGISTER_ZMM29: case REGISTER_ZMM30: case REGISTER_ZMM31: return 8 * sizeof(int64_t); case REGISTER_ES: case REGISTER_CS: case REGISTER_DS: case REGISTER_FS: case REGISTER_GS: case REGISTER_SS: case REGISTER_CR0: case REGISTER_CR1: case REGISTER_CR2: case REGISTER_CR3: case REGISTER_CR4: case REGISTER_CR5: case REGISTER_CR6: case REGISTER_CR7: case REGISTER_CR8: case REGISTER_CR9: case REGISTER_CR10: case REGISTER_CR11: case REGISTER_CR12: case REGISTER_CR13: case REGISTER_CR14: case REGISTER_CR15: case REGISTER_DR0: case REGISTER_DR1: case REGISTER_DR2: case REGISTER_DR3: case REGISTER_DR4: case REGISTER_DR5: case REGISTER_DR6: case REGISTER_DR7: case REGISTER_DR8: case REGISTER_DR9: case REGISTER_DR10: case REGISTER_DR11: case REGISTER_DR12: case REGISTER_DR13: case REGISTER_DR14: case REGISTER_DR15: case REGISTER_K0: case REGISTER_K1: case REGISTER_K2: case REGISTER_K3: case REGISTER_K4: case REGISTER_K5: case REGISTER_K6: case REGISTER_K7: case REGISTER_MM0: case REGISTER_MM1: case REGISTER_MM2: case REGISTER_MM3: case REGISTER_MM4: case REGISTER_MM5: case REGISTER_MM6: case REGISTER_MM7: case REGISTER_ST0: case REGISTER_ST1: case REGISTER_ST2: case REGISTER_ST3: case REGISTER_ST4: case REGISTER_ST5: case REGISTER_ST6: case REGISTER_ST7: return 0; case REGISTER_INVALID: default: return 0; } } /* * Get the type of a register. */ Type getRegType(Register reg) { switch (reg) { case REGISTER_AH: case REGISTER_AL: case REGISTER_BH: case REGISTER_BL: case REGISTER_CH: case REGISTER_CL: case REGISTER_BPL: case REGISTER_DIL: case REGISTER_DL: case REGISTER_DH: case REGISTER_SIL: case REGISTER_SPL: case REGISTER_R8B: case REGISTER_R9B: case REGISTER_R10B: case REGISTER_R11B: case REGISTER_R12B: case REGISTER_R13B: case REGISTER_R14B: case REGISTER_R15B: return TYPE_INT8; case REGISTER_EFLAGS: case REGISTER_AX: case REGISTER_BP: case REGISTER_BX: case REGISTER_CX: case REGISTER_DX: case REGISTER_DI: case REGISTER_IP: case REGISTER_SI: case REGISTER_SP: case REGISTER_R8W: case REGISTER_R9W: case REGISTER_R10W: case REGISTER_R11W: case REGISTER_R12W: case REGISTER_R13W: case REGISTER_R14W: case REGISTER_R15W: return TYPE_INT16; case REGISTER_EAX: case REGISTER_EBP: case REGISTER_EBX: case REGISTER_ECX: case REGISTER_EDI: case REGISTER_EDX: case REGISTER_EIP: case REGISTER_ESI: case REGISTER_ESP: case REGISTER_R8D: case REGISTER_R9D: case REGISTER_R10D: case REGISTER_R11D: case REGISTER_R12D: case REGISTER_R13D: case REGISTER_R14D: case REGISTER_R15D: return TYPE_INT32; case REGISTER_RAX: case REGISTER_RBP: case REGISTER_RBX: case REGISTER_RCX: case REGISTER_RDI: case REGISTER_RDX: case REGISTER_RIP: case REGISTER_RSI: case REGISTER_RSP: case REGISTER_R8: case REGISTER_R9: case REGISTER_R10: case REGISTER_R11: case REGISTER_R12: case REGISTER_R13: case REGISTER_R14: case REGISTER_R15: return TYPE_INT64; case REGISTER_XMM0: case REGISTER_XMM1: case REGISTER_XMM2: case REGISTER_XMM3: case REGISTER_XMM4: case REGISTER_XMM5: case REGISTER_XMM6: case REGISTER_XMM7: case REGISTER_XMM8: case REGISTER_XMM9: case REGISTER_XMM10: case REGISTER_XMM11: case REGISTER_XMM12: case REGISTER_XMM13: case REGISTER_XMM14: case REGISTER_XMM15: case REGISTER_XMM16: case REGISTER_XMM17: case REGISTER_XMM18: case REGISTER_XMM19: case REGISTER_XMM20: case REGISTER_XMM21: case REGISTER_XMM22: case REGISTER_XMM23: case REGISTER_XMM24: case REGISTER_XMM25: case REGISTER_XMM26: case REGISTER_XMM27: case REGISTER_XMM28: case REGISTER_XMM29: case REGISTER_XMM30: case REGISTER_XMM31: return TYPE_NULL_PTR; case REGISTER_YMM0: case REGISTER_YMM1: case REGISTER_YMM2: case REGISTER_YMM3: case REGISTER_YMM4: case REGISTER_YMM5: case REGISTER_YMM6: case REGISTER_YMM7: case REGISTER_YMM8: case REGISTER_YMM9: case REGISTER_YMM10: case REGISTER_YMM11: case REGISTER_YMM12: case REGISTER_YMM13: case REGISTER_YMM14: case REGISTER_YMM15: case REGISTER_YMM16: case REGISTER_YMM17: case REGISTER_YMM18: case REGISTER_YMM19: case REGISTER_YMM20: case REGISTER_YMM21: case REGISTER_YMM22: case REGISTER_YMM23: case REGISTER_YMM24: case REGISTER_YMM25: case REGISTER_YMM26: case REGISTER_YMM27: case REGISTER_YMM28: case REGISTER_YMM29: case REGISTER_YMM30: case REGISTER_YMM31: return TYPE_NULL_PTR; case REGISTER_ZMM0: case REGISTER_ZMM1: case REGISTER_ZMM2: case REGISTER_ZMM3: case REGISTER_ZMM4: case REGISTER_ZMM5: case REGISTER_ZMM6: case REGISTER_ZMM7: case REGISTER_ZMM8: case REGISTER_ZMM9: case REGISTER_ZMM10: case REGISTER_ZMM11: case REGISTER_ZMM12: case REGISTER_ZMM13: case REGISTER_ZMM14: case REGISTER_ZMM15: case REGISTER_ZMM16: case REGISTER_ZMM17: case REGISTER_ZMM18: case REGISTER_ZMM19: case REGISTER_ZMM20: case REGISTER_ZMM21: case REGISTER_ZMM22: case REGISTER_ZMM23: case REGISTER_ZMM24: case REGISTER_ZMM25: case REGISTER_ZMM26: case REGISTER_ZMM27: case REGISTER_ZMM28: case REGISTER_ZMM29: case REGISTER_ZMM30: case REGISTER_ZMM31: return TYPE_NULL_PTR; case REGISTER_ES: case REGISTER_CS: case REGISTER_DS: case REGISTER_FS: case REGISTER_GS: case REGISTER_SS: case REGISTER_CR0: case REGISTER_CR1: case REGISTER_CR2: case REGISTER_CR3: case REGISTER_CR4: case REGISTER_CR5: case REGISTER_CR6: case REGISTER_CR7: case REGISTER_CR8: case REGISTER_CR9: case REGISTER_CR10: case REGISTER_CR11: case REGISTER_CR12: case REGISTER_CR13: case REGISTER_CR14: case REGISTER_CR15: case REGISTER_DR0: case REGISTER_DR1: case REGISTER_DR2: case REGISTER_DR3: case REGISTER_DR4: case REGISTER_DR5: case REGISTER_DR6: case REGISTER_DR7: case REGISTER_DR8: case REGISTER_DR9: case REGISTER_DR10: case REGISTER_DR11: case REGISTER_DR12: case REGISTER_DR13: case REGISTER_DR14: case REGISTER_DR15: case REGISTER_K0: case REGISTER_K1: case REGISTER_K2: case REGISTER_K3: case REGISTER_K4: case REGISTER_K5: case REGISTER_K6: case REGISTER_K7: case REGISTER_MM0: case REGISTER_MM1: case REGISTER_MM2: case REGISTER_MM3: case REGISTER_MM4: case REGISTER_MM5: case REGISTER_MM6: case REGISTER_MM7: case REGISTER_ST0: case REGISTER_ST1: case REGISTER_ST2: case REGISTER_ST3: case REGISTER_ST4: case REGISTER_ST5: case REGISTER_ST6: case REGISTER_ST7: return TYPE_NULL_PTR; case REGISTER_INVALID: default: return TYPE_NULL_PTR; } } /* * Return `true' for high-byte registers. */ bool isHighReg(Register reg) { switch (reg) { case REGISTER_AH: case REGISTER_BH: case REGISTER_CH: case REGISTER_DH: return true; default: return false; } } /* * Get a register name. */ const char *e9tool::getRegName(Register reg) { switch (reg) { case REGISTER_AH: return "%ah"; case REGISTER_AL: return "%al"; case REGISTER_BH: return "%bh"; case REGISTER_BL: return "%bl"; case REGISTER_CH: return "%ch"; case REGISTER_CL: return "%cl"; case REGISTER_BPL: return "%bpl"; case REGISTER_DIL: return "%dil"; case REGISTER_DL: return "%dl"; case REGISTER_DH: return "%dh"; case REGISTER_SIL: return "%sil"; case REGISTER_SPL: return "%spl"; case REGISTER_R8B: return "%r8b"; case REGISTER_R9B: return "%r9b"; case REGISTER_R10B: return "%r10b"; case REGISTER_R11B: return "%r11b"; case REGISTER_R12B: return "%r12b"; case REGISTER_R13B: return "%r13b"; case REGISTER_R14B: return "%r14b"; case REGISTER_R15B: return "%r15b"; case REGISTER_EFLAGS: return "%rflags"; case REGISTER_AX: return "%ax"; case REGISTER_BP: return "%bp"; case REGISTER_BX: return "%bx"; case REGISTER_CX: return "%cx"; case REGISTER_DX: return "%dx"; case REGISTER_DI: return "%di"; case REGISTER_IP: return "%ip"; case REGISTER_SI: return "%si"; case REGISTER_SP: return "%sp"; case REGISTER_R8W: return "%r8w"; case REGISTER_R9W: return "%r9w"; case REGISTER_R10W: return "%r10w"; case REGISTER_R11W: return "%r11w"; case REGISTER_R12W: return "%r12w"; case REGISTER_R13W: return "%r13w"; case REGISTER_R14W: return "%r14w"; case REGISTER_R15W: return "%r15w"; case REGISTER_EAX: return "%eax"; case REGISTER_EBP: return "%ebp"; case REGISTER_EBX: return "%ebx"; case REGISTER_ECX: return "%ecx"; case REGISTER_EDI: return "%edi"; case REGISTER_EDX: return "%edx"; case REGISTER_EIP: return "%eip"; case REGISTER_ESI: return "%esi"; case REGISTER_ESP: return "%esp"; case REGISTER_R8D: return "%r8d"; case REGISTER_R9D: return "%r9d"; case REGISTER_R10D: return "%r10d"; case REGISTER_R11D: return "%r11d"; case REGISTER_R12D: return "%r12d"; case REGISTER_R13D: return "%r13d"; case REGISTER_R14D: return "%r14d"; case REGISTER_R15D: return "%r15d"; case REGISTER_RAX: return "%rax"; case REGISTER_RBP: return "%rbp"; case REGISTER_RBX: return "%rbx"; case REGISTER_RCX: return "%rcx"; case REGISTER_RDI: return "%rdi"; case REGISTER_RDX: return "%rdx"; case REGISTER_RIP: return "%rip"; case REGISTER_RSI: return "%rsi"; case REGISTER_RSP: return "%rsp"; case REGISTER_R8: return "%r8"; case REGISTER_R9: return "%r9"; case REGISTER_R10: return "%r10"; case REGISTER_R11: return "%r11"; case REGISTER_R12: return "%r12"; case REGISTER_R13: return "%r13"; case REGISTER_R14: return "%r14"; case REGISTER_R15: return "%r15"; case REGISTER_XMM0: return "%xmm0"; case REGISTER_XMM1: return "%xmm1"; case REGISTER_XMM2: return "%xmm2"; case REGISTER_XMM3: return "%xmm3"; case REGISTER_XMM4: return "%xmm4"; case REGISTER_XMM5: return "%xmm5"; case REGISTER_XMM6: return "%xmm6"; case REGISTER_XMM7: return "%xmm7"; case REGISTER_XMM8: return "%xmm8"; case REGISTER_XMM9: return "%xmm9"; case REGISTER_XMM10: return "%xmm10"; case REGISTER_XMM11: return "%xmm11"; case REGISTER_XMM12: return "%xmm12"; case REGISTER_XMM13: return "%xmm13"; case REGISTER_XMM14: return "%xmm14"; case REGISTER_XMM15: return "%xmm15"; case REGISTER_XMM16: return "%xmm16"; case REGISTER_XMM17: return "%xmm17"; case REGISTER_XMM18: return "%xmm18"; case REGISTER_XMM19: return "%xmm19"; case REGISTER_XMM20: return "%xmm20"; case REGISTER_XMM21: return "%xmm21"; case REGISTER_XMM22: return "%xmm22"; case REGISTER_XMM23: return "%xmm23"; case REGISTER_XMM24: return "%xmm24"; case REGISTER_XMM25: return "%xmm25"; case REGISTER_XMM26: return "%xmm26"; case REGISTER_XMM27: return "%xmm27"; case REGISTER_XMM28: return "%xmm28"; case REGISTER_XMM29: return "%xmm29"; case REGISTER_XMM30: return "%xmm30"; case REGISTER_XMM31: return "%xmm31"; case REGISTER_YMM0: return "%ymm0"; case REGISTER_YMM1: return "%ymm1"; case REGISTER_YMM2: return "%ymm2"; case REGISTER_YMM3: return "%ymm3"; case REGISTER_YMM4: return "%ymm4"; case REGISTER_YMM5: return "%ymm5"; case REGISTER_YMM6: return "%ymm6"; case REGISTER_YMM7: return "%ymm7"; case REGISTER_YMM8: return "%ymm8"; case REGISTER_YMM9: return "%ymm9"; case REGISTER_YMM10: return "%ymm10"; case REGISTER_YMM11: return "%ymm11"; case REGISTER_YMM12: return "%ymm12"; case REGISTER_YMM13: return "%ymm13"; case REGISTER_YMM14: return "%ymm14"; case REGISTER_YMM15: return "%ymm15"; case REGISTER_YMM16: return "%ymm16"; case REGISTER_YMM17: return "%ymm17"; case REGISTER_YMM18: return "%ymm18"; case REGISTER_YMM19: return "%ymm19"; case REGISTER_YMM20: return "%ymm20"; case REGISTER_YMM21: return "%ymm21"; case REGISTER_YMM22: return "%ymm22"; case REGISTER_YMM23: return "%ymm23"; case REGISTER_YMM24: return "%ymm24"; case REGISTER_YMM25: return "%ymm25"; case REGISTER_YMM26: return "%ymm26"; case REGISTER_YMM27: return "%ymm27"; case REGISTER_YMM28: return "%ymm28"; case REGISTER_YMM29: return "%ymm29"; case REGISTER_YMM30: return "%ymm30"; case REGISTER_YMM31: return "%ymm31"; case REGISTER_ZMM0: return "%zmm0"; case REGISTER_ZMM1: return "%zmm1"; case REGISTER_ZMM2: return "%zmm2"; case REGISTER_ZMM3: return "%zmm3"; case REGISTER_ZMM4: return "%zmm4"; case REGISTER_ZMM5: return "%zmm5"; case REGISTER_ZMM6: return "%zmm6"; case REGISTER_ZMM7: return "%zmm7"; case REGISTER_ZMM8: return "%zmm8"; case REGISTER_ZMM9: return "%zmm9"; case REGISTER_ZMM10: return "%zmm10"; case REGISTER_ZMM11: return "%zmm11"; case REGISTER_ZMM12: return "%zmm12"; case REGISTER_ZMM13: return "%zmm13"; case REGISTER_ZMM14: return "%zmm14"; case REGISTER_ZMM15: return "%zmm15"; case REGISTER_ZMM16: return "%zmm16"; case REGISTER_ZMM17: return "%zmm17"; case REGISTER_ZMM18: return "%zmm18"; case REGISTER_ZMM19: return "%zmm19"; case REGISTER_ZMM20: return "%zmm20"; case REGISTER_ZMM21: return "%zmm21"; case REGISTER_ZMM22: return "%zmm22"; case REGISTER_ZMM23: return "%zmm23"; case REGISTER_ZMM24: return "%zmm24"; case REGISTER_ZMM25: return "%zmm25"; case REGISTER_ZMM26: return "%zmm26"; case REGISTER_ZMM27: return "%zmm27"; case REGISTER_ZMM28: return "%zmm28"; case REGISTER_ZMM29: return "%zmm29"; case REGISTER_ZMM30: return "%zmm30"; case REGISTER_ZMM31: return "%zmm31"; case REGISTER_ES: return "%es"; case REGISTER_CS: return "%cs"; case REGISTER_DS: return "%ds"; case REGISTER_FS: return "%fs"; case REGISTER_GS: return "%gs"; case REGISTER_SS: return "%ss"; case REGISTER_CR0: return "%cr0"; case REGISTER_CR1: return "%cr1"; case REGISTER_CR2: return "%cr2"; case REGISTER_CR3: return "%cr3"; case REGISTER_CR4: return "%cr4"; case REGISTER_CR5: return "%cr5"; case REGISTER_CR6: return "%cr6"; case REGISTER_CR7: return "%cr7"; case REGISTER_CR8: return "%cr8"; case REGISTER_CR9: return "%cr9"; case REGISTER_CR10: return "%cr10"; case REGISTER_CR11: return "%cr11"; case REGISTER_CR12: return "%cr12"; case REGISTER_CR13: return "%cr13"; case REGISTER_CR14: return "%cr14"; case REGISTER_CR15: return "%cr15"; case REGISTER_DR0: return "%dr0"; case REGISTER_DR1: return "%dr1"; case REGISTER_DR2: return "%dr2"; case REGISTER_DR3: return "%dr3"; case REGISTER_DR4: return "%dr4"; case REGISTER_DR5: return "%dr5"; case REGISTER_DR6: return "%dr6"; case REGISTER_DR7: return "%dr7"; case REGISTER_DR8: return "%dr8"; case REGISTER_DR9: return "%dr9"; case REGISTER_DR10: return "%dr10"; case REGISTER_DR11: return "%dr11"; case REGISTER_DR12: return "%dr12"; case REGISTER_DR13: return "%dr13"; case REGISTER_DR14: return "%dr14"; case REGISTER_DR15: return "%dr15"; case REGISTER_K0: return "%k0"; case REGISTER_K1: return "%k1"; case REGISTER_K2: return "%k2"; case REGISTER_K3: return "%k3"; case REGISTER_K4: return "%k4"; case REGISTER_K5: return "%k5"; case REGISTER_K6: return "%k6"; case REGISTER_K7: return "%k7"; case REGISTER_MM0: return "%mm0"; case REGISTER_MM1: return "%mm1"; case REGISTER_MM2: return "%mm2"; case REGISTER_MM3: return "%mm3"; case REGISTER_MM4: return "%mm4"; case REGISTER_MM5: return "%mm5"; case REGISTER_MM6: return "%mm6"; case REGISTER_MM7: return "%mm7"; case REGISTER_ST0: return "%st0"; case REGISTER_ST1: return "%st1"; case REGISTER_ST2: return "%st2"; case REGISTER_ST3: return "%st3"; case REGISTER_ST4: return "%st4"; case REGISTER_ST5: return "%st5"; case REGISTER_ST6: return "%st6"; case REGISTER_ST7: return "%st7"; case REGISTER_INVALID: return "???"; default: return "???"; } } /* * Get all callee-save registers. */ const int *getCallerSaveRegs(bool sysv, bool clean, bool state, bool conditional, size_t num_args) { // If "state", then we must save the entire register state: static const int state_save[] = { RAX_IDX, RCX_IDX, RDX_IDX, RBX_IDX, RBP_IDX, RSI_IDX, RDI_IDX, R8_IDX, R9_IDX, R10_IDX, R11_IDX, R12_IDX, R13_IDX, R14_IDX, R15_IDX, RFLAGS_IDX, RSP_IDX, RIP_IDX, -1 }; if (state) return state_save; // For clean calls, we must save all caller save registers according // to the corresponding ABI. Notes: // - To support `conditional', %rcx must be saved first. // - %rax must be saved before %rflags. static const int clean_sysv_save[] = { RCX_IDX, RAX_IDX, RFLAGS_IDX, R11_IDX, R10_IDX, R9_IDX, R8_IDX, RDX_IDX, RSI_IDX, RDI_IDX, -1 }; static const int clean_win64_save[] = { RCX_IDX, RAX_IDX, RFLAGS_IDX, R11_IDX, R10_IDX, R9_IDX, R8_IDX, RDX_IDX, -1 }; const int *clean_save = (sysv? clean_sysv_save: clean_win64_save); if (clean) return clean_save; // For `naked' calls, we only save the number of registers actually used // by args. static const int naked_sysv_save[] = { R11_IDX, R10_IDX, R9_IDX, R8_IDX, RCX_IDX, RDX_IDX, RSI_IDX, RDI_IDX, -1 }; static const int naked_win64_save[] = { R11_IDX, R10_IDX, R9_IDX, R8_IDX, RDX_IDX, RCX_IDX, -1 }; const int *naked_save = (sysv? naked_sysv_save: naked_win64_save); unsigned naked_len = (sysv? 8: 6); if (!conditional) return naked_save + (naked_len - num_args); // For `conditional+naked' calls. %rax must be saved first: if (sysv) { static const int conditional_save[][10] = { {RAX_IDX, -1}, {RAX_IDX, RDI_IDX, -1}, {RAX_IDX, RSI_IDX, RDI_IDX, -1}, {RAX_IDX, RDX_IDX, RSI_IDX, RDI_IDX, -1}, {RAX_IDX, RCX_IDX, RDX_IDX, RSI_IDX, RDI_IDX, -1}, {RAX_IDX, R8_IDX, RCX_IDX, RDX_IDX, RSI_IDX, RDI_IDX, -1}, {RAX_IDX, R9_IDX, R8_IDX, RCX_IDX, RDX_IDX, RSI_IDX, RDI_IDX, -1}, {RAX_IDX, R10_IDX, R9_IDX, R8_IDX, RCX_IDX, RDX_IDX, RSI_IDX, RDI_IDX, -1}, {RAX_IDX, R11_IDX, R10_IDX, R9_IDX, R8_IDX, RCX_IDX, RDX_IDX, RSI_IDX, RDI_IDX, -1}, }; return conditional_save[num_args]; } else { static const int conditional_save[][10] = { {RAX_IDX, -1}, {RAX_IDX, RCX_IDX, -1}, {RAX_IDX, RDX_IDX, RCX_IDX, -1}, {RAX_IDX, R8_IDX, RDX_IDX, RCX_IDX, -1}, {RAX_IDX, R9_IDX, R8_IDX, RDX_IDX, RCX_IDX, -1}, {RAX_IDX, R10_IDX, R9_IDX, R8_IDX, RDX_IDX, RCX_IDX, -1}, {RAX_IDX, R11_IDX, R10_IDX, R9_IDX, R8_IDX, RDX_IDX, RCX_IDX, -1}, }; return conditional_save[num_args]; } } /* * Move a register to stack. */ static bool sendMovBetweenRegAndStack(FILE *out, Register reg, bool to_stack) { uint8_t opcode = (to_stack? 0x7f: 0x6f); uint8_t modrm = 0; switch (reg) { case REGISTER_XMM0: case REGISTER_XMM8: case REGISTER_XMM16: case REGISTER_XMM24: case REGISTER_YMM0: case REGISTER_YMM8: case REGISTER_YMM16: case REGISTER_YMM24: case REGISTER_ZMM0: case REGISTER_ZMM8: case REGISTER_ZMM16: case REGISTER_ZMM24: modrm = 0x04; break; case REGISTER_XMM1: case REGISTER_XMM9: case REGISTER_XMM17: case REGISTER_XMM25: case REGISTER_YMM1: case REGISTER_YMM9: case REGISTER_YMM17: case REGISTER_YMM25: case REGISTER_ZMM1: case REGISTER_ZMM9: case REGISTER_ZMM17: case REGISTER_ZMM25: modrm = 0x0c; break; case REGISTER_XMM2: case REGISTER_XMM10: case REGISTER_XMM18: case REGISTER_XMM26: case REGISTER_YMM2: case REGISTER_YMM10: case REGISTER_YMM18: case REGISTER_YMM26: case REGISTER_ZMM2: case REGISTER_ZMM10: case REGISTER_ZMM18: case REGISTER_ZMM26: modrm = 0x14; break; case REGISTER_XMM3: case REGISTER_XMM11: case REGISTER_XMM19: case REGISTER_XMM27: case REGISTER_YMM3: case REGISTER_YMM11: case REGISTER_YMM19: case REGISTER_YMM27: case REGISTER_ZMM3: case REGISTER_ZMM11: case REGISTER_ZMM19: case REGISTER_ZMM27: modrm = 0x1c; break; case REGISTER_XMM4: case REGISTER_XMM12: case REGISTER_XMM20: case REGISTER_XMM28: case REGISTER_YMM4: case REGISTER_YMM12: case REGISTER_YMM20: case REGISTER_YMM28: case REGISTER_ZMM4: case REGISTER_ZMM12: case REGISTER_ZMM20: case REGISTER_ZMM28: modrm = 0x24; break; case REGISTER_XMM5: case REGISTER_XMM13: case REGISTER_XMM21: case REGISTER_XMM29: case REGISTER_YMM5: case REGISTER_YMM13: case REGISTER_YMM21: case REGISTER_YMM29: case REGISTER_ZMM5: case REGISTER_ZMM13: case REGISTER_ZMM21: case REGISTER_ZMM29: modrm = 0x2c; break; case REGISTER_XMM6: case REGISTER_XMM14: case REGISTER_XMM22: case REGISTER_XMM30: case REGISTER_YMM6: case REGISTER_YMM14: case REGISTER_YMM22: case REGISTER_YMM30: case REGISTER_ZMM6: case REGISTER_ZMM14: case REGISTER_ZMM22: case REGISTER_ZMM30: modrm = 0x34; break; case REGISTER_XMM7: case REGISTER_XMM15: case REGISTER_XMM23: case REGISTER_XMM31: case REGISTER_YMM7: case REGISTER_YMM15: case REGISTER_YMM23: case REGISTER_YMM31: case REGISTER_ZMM7: case REGISTER_ZMM15: case REGISTER_ZMM23: case REGISTER_ZMM31: modrm = 0x3c; break; default: return false; } switch (reg) { case REGISTER_XMM0: case REGISTER_XMM1: case REGISTER_XMM2: case REGISTER_XMM3: case REGISTER_XMM4: case REGISTER_XMM5: case REGISTER_XMM6: case REGISTER_XMM7: // movdqu %xmm,(%rsp) fprintf(out, "%u,%u,%u,%u,%u,", 0xf3, 0x0f, opcode, modrm, 0x24); return true; case REGISTER_YMM0: case REGISTER_YMM1: case REGISTER_YMM2: case REGISTER_YMM3: case REGISTER_YMM4: case REGISTER_YMM5: case REGISTER_YMM6: case REGISTER_YMM7: // vmovdqu %ymm,(%rsp) fprintf(out, "%u,%u,%u,%u,%u,", 0xc5, 0xfe, opcode, modrm, 0x24); return true; case REGISTER_ZMM0: case REGISTER_ZMM1: case REGISTER_ZMM2: case REGISTER_ZMM3: case REGISTER_ZMM4: case REGISTER_ZMM5: case REGISTER_ZMM6: case REGISTER_ZMM7: // vmovdqu64 %zmm,(%rsp) fprintf(out, "%u,%u,%u,%u,%u,%u,%u,", 0x62, 0xf1, 0xfe, 0x48, opcode, modrm, 0x24); return true; case REGISTER_XMM8: case REGISTER_XMM9: case REGISTER_XMM10: case REGISTER_XMM11: case REGISTER_XMM12: case REGISTER_XMM13: case REGISTER_XMM14: case REGISTER_XMM15: // movdqu %xmm,(%rsp) fprintf(out, "%u,%u,%u,%u,%u,%u,", 0xf3, 0x44, 0x0f, opcode, modrm, 0x24); return true; case REGISTER_YMM8: case REGISTER_YMM9: case REGISTER_YMM10: case REGISTER_YMM11: case REGISTER_YMM12: case REGISTER_YMM13: case REGISTER_YMM14: case REGISTER_YMM15: // vmovdqu %ymm,(%rsp) fprintf(out, "%u,%u,%u,%u,%u,", 0xc5, 0x7e, opcode, modrm, 0x24); return true; case REGISTER_ZMM8: case REGISTER_ZMM9: case REGISTER_ZMM10: case REGISTER_ZMM11: case REGISTER_ZMM12: case REGISTER_ZMM13: case REGISTER_ZMM14: case REGISTER_ZMM15: // vmovdqu64 %zmm,(%rsp) fprintf(out, "%u,%u,%u,%u,%u,%u,%u,", 0x62, 0x71, 0xfe, 0x48, opcode, modrm, 0x24); return true; case REGISTER_XMM16: case REGISTER_XMM17: case REGISTER_XMM18: case REGISTER_XMM19: case REGISTER_XMM20: case REGISTER_XMM21: case REGISTER_XMM22: case REGISTER_XMM23: // vmovdqu64 %xmm,(%rsp) fprintf(out, "%u,%u,%u,%u,%u,%u,%u,", 0x62, 0xe1, 0xfe, 0x08, opcode, modrm, 0x24); return true; case REGISTER_YMM16: case REGISTER_YMM17: case REGISTER_YMM18: case REGISTER_YMM19: case REGISTER_YMM20: case REGISTER_YMM21: case REGISTER_YMM22: case REGISTER_YMM23: // vmovdqu64 %ymm,(%rsp) fprintf(out, "%u,%u,%u,%u,%u,%u,%u,", 0x62, 0xe1, 0xfe, 0x28, opcode, modrm, 0x24); return true; case REGISTER_ZMM16: case REGISTER_ZMM17: case REGISTER_ZMM18: case REGISTER_ZMM19: case REGISTER_ZMM20: case REGISTER_ZMM21: case REGISTER_ZMM22: case REGISTER_ZMM23: // vmovdqu64 %zmm,(%rsp) fprintf(out, "%u,%u,%u,%u,%u,%u,%u,", 0x62, 0xe1, 0xfe, 0x48, opcode, modrm, 0x24); return true; case REGISTER_XMM24: case REGISTER_XMM25: case REGISTER_XMM26: case REGISTER_XMM27: case REGISTER_XMM28: case REGISTER_XMM29: case REGISTER_XMM30: case REGISTER_XMM31: // vmovdqu64 %xmm,(%rsp) fprintf(out, "%u,%u,%u,%u,%u,%u,%u,", 0x62, 0x61, 0xfe, 0x08, opcode, modrm, 0x24); return true; case REGISTER_YMM24: case REGISTER_YMM25: case REGISTER_YMM26: case REGISTER_YMM27: case REGISTER_YMM28: case REGISTER_YMM29: case REGISTER_YMM30: case REGISTER_YMM31: // vmovdqu64 %xmm,(%rsp) fprintf(out, "%u,%u,%u,%u,%u,%u,%u,", 0x62, 0x61, 0xfe, 0x28, opcode, modrm, 0x24); return true; case REGISTER_ZMM24: case REGISTER_ZMM25: case REGISTER_ZMM26: case REGISTER_ZMM27: case REGISTER_ZMM28: case REGISTER_ZMM29: case REGISTER_ZMM30: case REGISTER_ZMM31: // vmovdqu64 %zmm,(%rsp) fprintf(out, "%u,%u,%u,%u,%u,%u,%u,", 0x62, 0x61, 0xfe, 0x48, opcode, modrm, 0x24); return true; default: return false; } } /* * Send (or emulate) a push instruction. */ std::pair<bool, bool> sendPush(FILE *out, int32_t offset, bool before, Register reg, Register rscratch) { // Special cases: int scratch = -1, old_scratch = -1; bool rax_stack = false; switch (reg) { case REGISTER_RIP: case REGISTER_RSP: case REGISTER_EFLAGS: scratch = getRegIdx(rscratch); assert(scratch != RSP_IDX && scratch != RFLAGS_IDX && scratch != RIP_IDX); if (scratch < 0) { // No available scratch register. Evict %rax to into stack // redzone at offset -16: sendMovFromR64ToStack(out, RAX_IDX, -16); scratch = RAX_IDX; rax_stack = true; } if (reg == REGISTER_EFLAGS && scratch != RAX_IDX) { // %rflags requires %rax as the scratch register: sendMovFromR64ToR64(out, RAX_IDX, scratch); old_scratch = scratch; scratch = RAX_IDX; } break; default: break; } switch (reg) { case REGISTER_RIP: if (before) sendLeaFromPCRelToR64(out, "{\"rel32\":\".Linstr\"}", scratch); else sendLeaFromPCRelToR64(out, "{\"rel32\":\".Lbreak\"}", scratch); sendMovFromR64ToStack(out, scratch, offset - RIP_SLOT); break; case REGISTER_RSP: // lea offset(%rsp),%rax // mov %rax,0x4000-8(%rax) sendLeaFromStackToR64(out, offset, scratch); sendMovFromR64ToStack(out, scratch, offset - RSP_SLOT); break; case REGISTER_EFLAGS: // seto %al // lahf assert(scratch == RAX_IDX); fprintf(out, "%u,%u,%u,", 0x0f, 0x90, 0xc0); fprintf(out, "%u,", 0x9f); sendPush(out, offset + sizeof(int64_t), before, REGISTER_RAX); break; default: break; } switch (reg) { case REGISTER_RIP: case REGISTER_RSP: case REGISTER_EFLAGS: if (old_scratch >= 0) sendMovFromR64ToR64(out, old_scratch, scratch); else if (rax_stack) sendMovFromStackToR64(out, -16+8, RAX_IDX); return {true, !rax_stack}; default: break; } // Normal cases: int regno = getRegIdx(reg); int32_t size = getRegSize(reg); if (regno >= 0) { // push %reg const uint8_t REX[] = {0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x00, 0x00, 0x41, 0x41, 0x00, 0x00, 0x41, 0x41, 0x41, 0x41, 0x00}; const uint8_t OPCODE[] = {0x57, 0x56, 0x52, 0x51, 0x50, 0x51, 0x00, 0x50, 0x52, 0x53, 0x53, 0x55, 0x54, 0x55, 0x56, 0x57, 0x54}; if (REX[regno] != 0x00) fprintf(out, "%u,", REX[regno]); fprintf(out, "%u,", OPCODE[regno]); return {true, false}; } else if (size > 0) { // lea -size(%rsp),%rsp // mov %reg,(%rsp) fprintf(out, "%u,%u,%u,%u,{\"int8\":%d},", 0x48, 0x8d, 0x64, 0x24, -size); sendMovBetweenRegAndStack(out, reg, /*to_stack=*/true); return {true, false}; } else return {false, false}; } /* * Send (or emulate) a pop instruction. */ bool sendPop(FILE *out, bool preserve_rax, Register reg, Register rscratch) { // Special cases: switch (reg) { case REGISTER_EFLAGS: { int scratch = -1; if (preserve_rax) { scratch = getRegIdx(rscratch); if (scratch < 0) sendMovFromR64ToStack(out, RAX_IDX, -(int32_t)sizeof(uint64_t)); else sendMovFromR64ToR64(out, RAX_IDX, scratch); } sendPop(out, false, REGISTER_RAX); // add $0x7f,%al // sahf fprintf(out, "%u,%u,", 0x04, 0x7f); fprintf(out, "%u,", 0x9e); if (preserve_rax) { if (scratch < 0) sendMovFromStackToR64(out, -2*(int32_t)sizeof(uint64_t), RAX_IDX); else { sendMovFromR64ToR64(out, scratch, RAX_IDX); return true; } } return false; } case REGISTER_RIP: // %rip is treated as read-only & stored in a special slot. // So the pop operation is treated as a NOP. return false; default: break; } int regno = getRegIdx(reg); int32_t size = getRegSize(reg); if (regno >= 0) { // pop %reg const uint8_t REX[] = {0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x00, 0x00, 0x41, 0x41, 0x00, 0x00, 0x41, 0x41, 0x41, 0x41, 0x00}; const uint8_t OPCODE[] = {0x5f, 0x5e, 0x5a, 0x59, 0x58, 0x59, 0x00, 0x58, 0x5a, 0x5b, 0x5b, 0x5d, 0x5c, 0x5d, 0x5e, 0x5f, 0x5c}; if (REX[regno] != 0x00) fprintf(out, "%u,", REX[regno]); fprintf(out, "%u,", OPCODE[regno]); } else if (size > 0) { // mov (%rsp),%reg // lea size(%rsp),%rsp sendMovBetweenRegAndStack(out, reg, /*to_stack=*/false); fprintf(out, "%u,%u,%u,%u,{\"int8\":%d},", 0x48, 0x8d, 0x64, 0x24, size); } else ; // NOP return false; } /* * Send a `mov %r64,%r64' instruction. */ bool sendMovFromR64ToR64(FILE *out, int srcno, int dstno) { if (srcno == dstno) return false; const uint8_t REX_MASK[] = {0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0}; const uint8_t REX[] = {0x48, 0x4c, 0x49, 0x4d}; const uint8_t REG[] = {0x07, 0x06, 0x02, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x03, 0x03, 0x05, 0x04, 0x05, 0x06, 0x07, 0x04}; uint8_t rex = REX[(REX_MASK[dstno] << 1) | REX_MASK[srcno]]; uint8_t modrm = (0x03 << 6) | (REG[srcno] << 3) | REG[dstno]; fprintf(out, "%u,%u,%u,", rex, 0x89, modrm); return true; } /* * Send a `movslq %r32,%r64' instruction. */ void sendMovFromR32ToR64(FILE *out, int srcno, int dstno) { const uint8_t REX_MASK[] = {0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0}; const uint8_t REX[] = {0x48, 0x4c, 0x49, 0x4d}; const uint8_t REG[] = {0x07, 0x06, 0x02, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x03, 0x03, 0x05, 0x04, 0x05, 0x06, 0x07, 0x04}; uint8_t rex = REX[(REX_MASK[srcno] << 1) | REX_MASK[dstno]]; uint8_t modrm = (0x03 << 6) | (REG[dstno] << 3) | REG[srcno]; fprintf(out, "%u,%u,%u,", rex, 0x63, modrm); } /* * Send a `movswl %r16,%r64' instruction. */ void sendMovFromR16ToR64(FILE *out, int srcno, int dstno) { const uint8_t REX_MASK[] = {0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0}; const uint8_t REX[] = {0x48, 0x4c, 0x49, 0x4d}; const uint8_t REG[] = {0x07, 0x06, 0x02, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x03, 0x03, 0x05, 0x04, 0x05, 0x06, 0x07, 0x04}; uint8_t rex = REX[(REX_MASK[srcno] << 1) | REX_MASK[dstno]]; uint8_t modrm = (0x03 << 6) | (REG[dstno] << 3) | REG[srcno]; fprintf(out, "%u,%u,%u,%u,", rex, 0x0f, 0xbf, modrm); } /* * Send a `movsbl %r8,%r32' instruction. */ void sendMovFromR8ToR64(FILE *out, int srcno, bool srchi, int dstno) { const uint8_t REX_MASK[] = {0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0}; const uint8_t REX[] = {0x48, 0x4c, 0x49, 0x4d}; const uint8_t REG[] = {0x07, 0x06, 0x02, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x03, 0x03, 0x05, 0x04, 0x05, 0x06, 0x07, 0x04}; uint8_t rex = REX[(REX_MASK[srcno] << 1) | REX_MASK[dstno]]; bool xchg = false; uint8_t srcreg = REG[srcno]; if (rex == 0x00) { switch (srcno) { case RAX_IDX: case RBX_IDX: case RCX_IDX: case RDX_IDX: if (srchi) srcreg += 4; // Convert to %rh encoding break; case RDI_IDX: case RSI_IDX: case RSP_IDX: case RBP_IDX: rex = 0x40; break; default: break; } } else if (srchi) { // xchgb %rh,%rl xchg = true; switch (srcno) { case RAX_IDX: fprintf(out, "%u,%u,", 0x86, 0xe0); break; case RBX_IDX: fprintf(out, "%u,%u,", 0x86, 0xfb); break; case RCX_IDX: fprintf(out, "%u,%u,", 0x86, 0xe9); break; case RDX_IDX: fprintf(out, "%u,%u,", 0x86, 0xf2); break; } } uint8_t modrm = (0x03 << 6) | (REG[dstno] << 3) | srcreg; fprintf(out, "%u,%u,%u,%u,", rex, 0x0f, 0xbe, modrm); if (xchg) { // xchgb %rh,%rl switch (srcno) { case RAX_IDX: fprintf(out, "%u,%u,", 0x86, 0xe0); break; case RBX_IDX: fprintf(out, "%u,%u,", 0x86, 0xfb); break; case RCX_IDX: fprintf(out, "%u,%u,", 0x86, 0xe9); break; case RDX_IDX: fprintf(out, "%u,%u,", 0x86, 0xf2); break; } } } /* * Send a `mov offset(%rsp),%r64' instruction. */ void sendMovFromStackToR64(FILE *out, int32_t offset, int regno) { const uint8_t REX[] = {0x48, 0x48, 0x48, 0x48, 0x4c, 0x4c, 0x00, 0x48, 0x4c, 0x4c, 0x48, 0x48, 0x4c, 0x4c, 0x4c, 0x4c, 0x48}; const uint8_t MODRM_0[] = {0x3c, 0x34, 0x14, 0x0c, 0x04, 0x0c, 0x00, 0x04, 0x14, 0x1c, 0x1c, 0x2c, 0x24, 0x2c, 0x34, 0x3c, 0x24}; const uint8_t MODRM_8[] = {0x7c, 0x74, 0x54, 0x4c, 0x44, 0x4c, 0x00, 0x44, 0x54, 0x5c, 0x5c, 0x6c, 0x64, 0x6c, 0x74, 0x7c, 0x64}; const uint8_t MODRM_32[] = {0xbc, 0xb4, 0x94, 0x8c, 0x84, 0x8c, 0x00, 0x84, 0x94, 0x9c, 0x9c, 0xac, 0xa4, 0xac, 0xb4, 0xbc, 0xa4}; if (offset == 0) fprintf(out, "%u,%u,%u,%u,", REX[regno], 0x8b, MODRM_0[regno], 0x24); else if (offset >= INT8_MIN && offset <= INT8_MAX) fprintf(out, "%u,%u,%u,%u,{\"int8\":%d},", REX[regno], 0x8b, MODRM_8[regno], 0x24, offset); else fprintf(out, "%u,%u,%u,%u,{\"int32\":%d},", REX[regno], 0x8b, MODRM_32[regno], 0x24, offset); } /* * Send a `movslq offset(%rsp),%r64' instruction. */ void sendMovFromStack32ToR64(FILE *out, int32_t offset, int regno) { const uint8_t REX[] = {0x48, 0x48, 0x48, 0x48, 0x4c, 0x4c, 0x00, 0x48, 0x4c, 0x4c, 0x48, 0x48, 0x4c, 0x4c, 0x4c, 0x4c, 0x48}; const uint8_t MODRM_0[] = {0x3c, 0x34, 0x14, 0x0c, 0x04, 0x0c, 0x00, 0x04, 0x14, 0x1c, 0x1c, 0x2c, 0x24, 0x2c, 0x34, 0x3c, 0x24}; const uint8_t MODRM_8[] = {0x7c, 0x74, 0x54, 0x4c, 0x44, 0x4c, 0x00, 0x44, 0x54, 0x5c, 0x5c, 0x6c, 0x64, 0x6c, 0x74, 0x7c, 0x64}; const uint8_t MODRM_32[] = {0xbc, 0xb4, 0x94, 0x8c, 0x84, 0x8c, 0x00, 0x84, 0x94, 0x9c, 0x9c, 0xac, 0xa4, 0xac, 0xb4, 0xbc, 0xa4}; if (offset == 0) fprintf(out, "%u,%u,%u,%u,", REX[regno], 0x63, MODRM_0[regno], 0x24); else if (offset >= INT8_MIN && offset <= INT8_MAX) fprintf(out, "%u,%u,%u,%u,{\"int8\":%d},", REX[regno], 0x63, MODRM_8[regno], 0x24, offset); else fprintf(out, "%u,%u,%u,%u,{\"int32\":%d},", REX[regno], 0x63, MODRM_32[regno], 0x24, offset); } /* * Send a `movswl offset(%rsp),%r64' instruction. */ void sendMovFromStack16ToR64(FILE *out, int32_t offset, int regno) { const uint8_t REX[] = {0x48, 0x48, 0x48, 0x48, 0x4c, 0x4c, 0x00, 0x48, 0x4c, 0x4c, 0x48, 0x48, 0x4c, 0x4c, 0x4c, 0x4c, 0x48}; const uint8_t MODRM_0[] = {0x3c, 0x34, 0x14, 0x0c, 0x04, 0x0c, 0x00, 0x04, 0x14, 0x1c, 0x1c, 0x2c, 0x24, 0x2c, 0x34, 0x3c, 0x24}; const uint8_t MODRM_8[] = {0x7c, 0x74, 0x54, 0x4c, 0x44, 0x4c, 0x00, 0x44, 0x54, 0x5c, 0x5c, 0x6c, 0x64, 0x6c, 0x74, 0x7c, 0x64}; const uint8_t MODRM_32[] = {0xbc, 0xb4, 0x94, 0x8c, 0x84, 0x8c, 0x00, 0x84, 0x94, 0x9c, 0x9c, 0xac, 0xa4, 0xac, 0xb4, 0xbc, 0xa4}; if (offset == 0) fprintf(out, "%u,%u,%u,%u,%u,", REX[regno], 0x0f, 0xbf, MODRM_0[regno], 0x24); else if (offset >= INT8_MIN && offset <= INT8_MAX) fprintf(out, "%u,%u,%u,%u,%u,{\"int8\":%d},", REX[regno], 0x0f, 0xbf, MODRM_8[regno], 0x24, offset); else fprintf(out, "%u,%u,%u,%u,%u,{\"int32\":%d},", REX[regno], 0x0f, 0xbf, MODRM_32[regno], 0x24, offset); } /* * Send a `movzbl offset(%rsp),%r64' instruction. */ void sendMovFromStack8ToR64(FILE *out, int32_t offset, int regno) { const uint8_t REX[] = {0x48, 0x48, 0x48, 0x48, 0x4c, 0x4c, 0x00, 0x48, 0x4c, 0x4c, 0x48, 0x48, 0x4c, 0x4c, 0x4c, 0x4c, 0x48}; const uint8_t MODRM_0[] = {0x3c, 0x34, 0x14, 0x0c, 0x04, 0x0c, 0x00, 0x04, 0x14, 0x1c, 0x1c, 0x2c, 0x24, 0x2c, 0x34, 0x3c, 0x24}; const uint8_t MODRM_8[] = {0x7c, 0x74, 0x54, 0x4c, 0x44, 0x4c, 0x00, 0x44, 0x54, 0x5c, 0x5c, 0x6c, 0x64, 0x6c, 0x74, 0x7c, 0x64}; const uint8_t MODRM_32[] = {0xbc, 0xb4, 0x94, 0x8c, 0x84, 0x8c, 0x00, 0x84, 0x94, 0x9c, 0x9c, 0xac, 0xa4, 0xac, 0xb4, 0xbc, 0xa4}; if (offset == 0) fprintf(out, "%u,%u,%u,%u,%u,", REX[regno], 0x0f, 0xbe, MODRM_0[regno], 0x24); else if (offset >= INT8_MIN && offset <= INT8_MAX) fprintf(out, "%u,%u,%u,%u,%u,{\"int8\":%d},", REX[regno], 0x0f, 0xbe, MODRM_8[regno], 0x24, offset); else fprintf(out, "%u,%u,%u,%u,%u,{\"int32\":%d},", REX[regno], 0x0f, 0xbe, MODRM_32[regno], 0x24, offset); } /* * Send a `mov %r64,offset(%rsp)' instruction. */ void sendMovFromR64ToStack(FILE *out, int regno, int32_t offset) { const uint8_t REX[] = {0x48, 0x48, 0x48, 0x48, 0x4c, 0x4c, 0x00, 0x48, 0x4c, 0x4c, 0x48, 0x48, 0x4c, 0x4c, 0x4c, 0x4c, 0x48}; const uint8_t MODRM_0[] = {0x3c, 0x34, 0x14, 0x0c, 0x04, 0x0c, 0x00, 0x04, 0x14, 0x1c, 0x1c, 0x2c, 0x24, 0x2c, 0x34, 0x3c, 0x24}; const uint8_t MODRM_8[] = {0x7c, 0x74, 0x54, 0x4c, 0x44, 0x4c, 0x00, 0x44, 0x54, 0x5c, 0x5c, 0x6c, 0x64, 0x6c, 0x74, 0x7c, 0x64}; const uint8_t MODRM_32[] = {0xbc, 0xb4, 0x94, 0x8c, 0x84, 0x8c, 0x00, 0x84, 0x94, 0x9c, 0x9c, 0xac, 0xa4, 0xac, 0xb4, 0xbc, 0xa4}; if (offset == 0) fprintf(out, "%u,%u,%u,%u,", REX[regno], 0x89, MODRM_0[regno], 0x24); else if (offset >= INT8_MIN && offset <= INT8_MAX) fprintf(out, "%u,%u,%u,%u,{\"int8\":%d},", REX[regno], 0x89, MODRM_8[regno], 0x24, offset); else fprintf(out, "%u,%u,%u,%u,{\"int32\":%d},", REX[regno], 0x89, MODRM_32[regno], 0x24, offset); } /* * Send a `movzwl %ax,%r32' instruction. */ void sendMovFromRAX16ToR64(FILE *out, int regno) { const uint8_t REX[] = {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x00}; const uint8_t MODRM[] = {0xf8, 0xf0, 0xd0, 0xc8, 0xc0, 0xc8, 0x00, 0xc0, 0xd0, 0xd8, 0xd8, 0xe8, 0xe0, 0xe8, 0xf0, 0xf8, 0xe0}; if (REX[regno] != 0x00) fprintf(out, "%u,", REX[regno]); fprintf(out, "%u,%u,%u,", 0x0f, 0xb7, MODRM[regno]); } /* * Send a `mov $value,%r32' instruction. */ void sendSExtFromI32ToR64(FILE *out, const char *value, int regno) { const uint8_t REX[] = {0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x00, 0x48, 0x49, 0x49, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x48}; const uint8_t MODRM[] = {0xc7, 0xc6, 0xc2, 0xc1, 0xc0, 0xc1, 0x00, 0xc0, 0xc2, 0xc3, 0xc3, 0xc5, 0xc4, 0xc5, 0xc6, 0xc7, 0xc4}; fprintf(out, "%u,%u,%u,%s,", REX[regno], 0xc7, MODRM[regno], value); } /* * Send a `mov $value,%r32' instruction. */ void sendSExtFromI32ToR64(FILE *out, int32_t value, int regno) { const uint8_t REX[] = {0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x00, 0x48, 0x49, 0x49, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x48}; const uint8_t MODRM[] = {0xc7, 0xc6, 0xc2, 0xc1, 0xc0, 0xc1, 0x00, 0xc0, 0xc2, 0xc3, 0xc3, 0xc5, 0xc4, 0xc5, 0xc6, 0xc7, 0xc4}; fprintf(out, "%u,%u,%u,{\"int32\":%d},", REX[regno], 0xc7, MODRM[regno], value); } /* * Send a `mov $value,%r64' instruction. */ void sendZExtFromI32ToR64(FILE *out, const char *value, int regno) { const uint8_t REX[] = {0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x00, 0x00, 0x41, 0x41, 0x00, 0x00, 0x41, 0x41, 0x41, 0x41, 0x00}; const uint8_t OPCODE[] = {0xbf, 0xbe, 0xba, 0xb9, 0xb8, 0xb9, 0x00, 0xb8, 0xba, 0xbb, 0xbb, 0xbd, 0xbc, 0xbd, 0xbe, 0xbf, 0xbc}; if (REX[regno] != 0x00) fprintf(out, "%u,", REX[regno]); fprintf(out, "%u,%s,", OPCODE[regno], value); } /* * Send a `mov $value,%r64' instruction. */ void sendZExtFromI32ToR64(FILE *out, int32_t value, int regno) { const uint8_t REX[] = {0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x00, 0x00, 0x41, 0x41, 0x00, 0x00, 0x41, 0x41, 0x41, 0x41, 0x00}; const uint8_t OPCODE[] = {0xbf, 0xbe, 0xba, 0xb9, 0xb8, 0xb9, 0x00, 0xb8, 0xba, 0xbb, 0xbb, 0xbd, 0xbc, 0xbd, 0xbe, 0xbf, 0xbc}; if (REX[regno] != 0x00) fprintf(out, "%u,", REX[regno]); fprintf(out, "%u,{\"int32\":%d},", OPCODE[regno], value); } /* * Send a `movabs $i64,%r64' instruction. */ void sendMovFromI64ToR64(FILE *out, intptr_t value, int regno) { const uint8_t REX[] = {0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x00, 0x48, 0x49, 0x49, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x48}; const uint8_t OPCODE[] = {0xbf, 0xbe, 0xba, 0xb9, 0xb8, 0xb9, 0x00, 0xb8, 0xba, 0xbb, 0xbb, 0xbd, 0xbc, 0xbd, 0xbe, 0xbf, 0xbc}; fprintf(out, "%u,%u,{\"int64\":", REX[regno], OPCODE[regno]); sendInteger(out, value); fputs("},", out); } /* * Send a `movabs $i64,%r64' instruction. */ void sendMovFromI64ToR64(FILE *out, const char *value, int regno) { const uint8_t REX[] = {0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x00, 0x48, 0x49, 0x49, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x48}; const uint8_t OPCODE[] = {0xbf, 0xbe, 0xba, 0xb9, 0xb8, 0xb9, 0x00, 0xb8, 0xba, 0xbb, 0xbb, 0xbd, 0xbc, 0xbd, 0xbe, 0xbf, 0xbc}; fprintf(out, "%u,%u,%s,", REX[regno], OPCODE[regno], value); } /* * Send a `lea offset(%rip),%r64' instruction. */ void sendLeaFromPCRelToR64(FILE *out, const char *offset, int regno) { const uint8_t REX[] = {0x48, 0x48, 0x48, 0x48, 0x4c, 0x4c, 0x00, 0x48, 0x4c, 0x4c, 0x48, 0x48, 0x4c, 0x4c, 0x4c, 0x4c, 0x48}; const uint8_t MODRM[] = {0x3d, 0x35, 0x15, 0x0d, 0x05, 0x0d, 0x00, 0x05, 0x15, 0x1d, 0x1d, 0x2d, 0x25, 0x2d, 0x35, 0x3d, 0x25}; fprintf(out, "%u,%u,%u,%s,", REX[regno], 0x8d, MODRM[regno], offset); } /* * Send a `lea offset(%rip),%r64' instruction. */ void sendLeaFromPCRelToR64(FILE *out, int32_t offset, int regno) { const uint8_t REX[] = {0x48, 0x48, 0x48, 0x48, 0x4c, 0x4c, 0x00, 0x48, 0x4c, 0x4c, 0x48, 0x48, 0x4c, 0x4c, 0x4c, 0x4c, 0x48}; const uint8_t MODRM[] = {0x3d, 0x35, 0x15, 0x0d, 0x05, 0x0d, 0x00, 0x05, 0x15, 0x1d, 0x1d, 0x2d, 0x25, 0x2d, 0x35, 0x3d, 0x25}; fprintf(out, "%u,%u,%u,{\"rel32\":%d},", REX[regno], 0x8d, MODRM[regno], offset); } /* * Send a `mov offset(%rip),%r64' instruction. */ void sendMovFromPCRelToR64(FILE *out, int32_t offset, int regno) { const uint8_t REX[] = {0x48, 0x48, 0x48, 0x48, 0x4c, 0x4c, 0x00, 0x48, 0x4c, 0x4c, 0x48, 0x48, 0x4c, 0x4c, 0x4c, 0x4c, 0x48}; const uint8_t MODRM[] = {0x3d, 0x35, 0x15, 0x0d, 0x05, 0x0d, 0x00, 0x05, 0x15, 0x1d, 0x1d, 0x2d, 0x25, 0x2d, 0x35, 0x3d, 0x25}; fprintf(out, "%u,%u,%u,{\"rel32\":%d},", REX[regno], 0x8b, MODRM[regno], offset); } /* * Send a `lea offset(%rsp),%r64' instruction. */ void sendLeaFromStackToR64(FILE *out, int32_t offset, int regno) { const uint8_t REX[] = {0x48, 0x48, 0x48, 0x48, 0x4c, 0x4c, 0x00, 0x48, 0x4c, 0x4c, 0x48, 0x48, 0x4c, 0x4c, 0x4c, 0x4c, 0x48}; const uint8_t MODRM_8[] = {0x7c, 0x74, 0x54, 0x4c, 0x44, 0x4c, 0x00, 0x44, 0x54, 0x5c, 0x5c, 0x6c, 0x64, 0x6c, 0x74, 0x7c, 0x64}; const uint8_t MODRM_32[] = {0xbc, 0xb4, 0x94, 0x8c, 0x84, 0x8c, 0x00, 0x84, 0x94, 0x9c, 0x9c, 0xac, 0xa4, 0xac, 0xb4, 0xbc, 0xa4}; if (offset == 0) sendMovFromR64ToR64(out, RSP_IDX, regno); else if (offset >= INT8_MIN && offset <= INT8_MAX) fprintf(out, "%u,%u,%u,%u,{\"int8\":%d},", REX[regno], 0x8d, MODRM_8[regno], 0x24, offset); else fprintf(out, "%u,%u,%u,%u,{\"int32\":%d},", REX[regno], 0x8d, MODRM_32[regno], 0x24, offset); }