/*
* ___ _ _
* ___ / _ \| |_ ___ ___ | |
* / _ \ (_) | __/ _ \ / _ \| |
* | __/\__, | || (_) | (_) | |
* \___| /_/ \__\___/ \___/|_|
*
* 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 .
*/
#include
#include
#include
#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 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);
}