// Copyright 2011-2020 Molecular Matters GmbH, all rights reserved. #if LC_VERSION == 1 // BEGIN EPIC MOD //#include PCH_INCLUDE // END EPIC MOD #include "LC_Assembler.h" // BEGIN EPIC MOD #include "LC_Platform.h" #include "LC_Foundation_Windows.h" #include "LC_Assert.h" #include // END EPIC MOD namespace Assembler { namespace Opcode { // NOP - No Operation // multi-byte sequences of NOP instructions, recommended by Intel (see Intel Instruction Set Reference) const uint8_t NOP1[1u] = { 0x90 }; // nop const uint8_t NOP2[2u] = { 0x66, 0x90 }; // xchg ax,ax const uint8_t NOP3[3u] = { 0x0F, 0x1F, 0x00 }; // nop DWORD PTR [rax] const uint8_t NOP4[4u] = { 0x0F, 0x1F, 0x40, 0x00 }; // nop DWORD PTR [rax+0x00] const uint8_t NOP5[5u] = { 0x0F, 0x1F, 0x44, 0x00, 0x00 }; // nop DWORD PTR [rax+rax*1+0x00] const uint8_t NOP6[6u] = { 0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00 }; // nop WORD PTR [rax+rax*1+0x00] const uint8_t NOP7[7u] = { 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00 }; // nop DWORD PTR [rax+0x0] const uint8_t NOP8[8u] = { 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 }; // nop DWORD PTR [rax+rax*1+0x0] // longer NOPs are built from other multi-byte NOPs const uint8_t NOP9[9u] = { NOP8[0], NOP8[1], NOP8[2], NOP8[3], NOP8[4], NOP8[5], NOP8[6], NOP8[7], NOP1[0] }; const uint8_t NOP10[10u] = { NOP8[0], NOP8[1], NOP8[2], NOP8[3], NOP8[4], NOP8[5], NOP8[6], NOP8[7], NOP2[0], NOP2[1] }; const uint8_t NOP11[11u] = { NOP8[0], NOP8[1], NOP8[2], NOP8[3], NOP8[4], NOP8[5], NOP8[6], NOP8[7], NOP3[0], NOP3[1], NOP3[2] }; const uint8_t NOP12[12u] = { NOP8[0], NOP8[1], NOP8[2], NOP8[3], NOP8[4], NOP8[5], NOP8[6], NOP8[7], NOP4[0], NOP4[1], NOP4[2], NOP4[3] }; const uint8_t NOP13[13u] = { NOP8[0], NOP8[1], NOP8[2], NOP8[3], NOP8[4], NOP8[5], NOP8[6], NOP8[7], NOP5[0], NOP5[1], NOP5[2], NOP5[3], NOP5[4] }; const uint8_t NOP14[14u] = { NOP8[0], NOP8[1], NOP8[2], NOP8[3], NOP8[4], NOP8[5], NOP8[6], NOP8[7], NOP6[0], NOP6[1], NOP6[2], NOP6[3], NOP6[4], NOP6[5] }; const uint8_t NOP15[15u] = { NOP8[0], NOP8[1], NOP8[2], NOP8[3], NOP8[4], NOP8[5], NOP8[6], NOP8[7], NOP7[0], NOP7[1], NOP7[2], NOP7[3], NOP7[4], NOP7[5], NOP7[6] }; // RET - Return const uint8_t RET[1u] = { 0xC3 }; // ret // JMP - Jump const uint8_t JMP_REL8[1u] = { 0xEB }; // JMP rel8; Jump short, RIP = RIP + 8-bit displacement sign extended to 64-bits const uint8_t JMP_REL32[1u] = { 0xE9 }; // JMP rel32; Jump near, relative, RIP = RIP + 32-bit displacement sign extended to 64-bits const uint8_t JMP_INDIRECT_RIP32[2u] = { 0xFF, 0x25 }; // JMP r/m64; Jump near, absolute indirect, RIP = 64-Bit offset from register or memory // CALL - Call Procedure const uint8_t CALL_INDIRECT_RIP32[2u] = { 0xFF, 0x15 }; // CALL r/m64; Call near, absolute indirect, address given in r/m64. // MOV - Move const uint8_t MOV_RAX_TCB[9u] = { 0x64, 0x48, 0x8B, 0x04, 0x25, 0x0, 0x0, 0x0, 0x0 }; // mov RAX, QWORD PTR FS:[0000000000000000h] // ADD - Addition const uint8_t ADD_RAX_INDIRECT_RIP32[3u] = { 0x48, 0x03, 0x05 }; // add RAX, QWORD PTR [RIP + OFFSET] } } namespace { // small lookup table from size to corresponding NOP opcode static const uint8_t* const SIZE_TO_NOP_OPCODE[16u] = { nullptr, Assembler::Opcode::NOP1, Assembler::Opcode::NOP2, Assembler::Opcode::NOP3, Assembler::Opcode::NOP4, Assembler::Opcode::NOP5, Assembler::Opcode::NOP6, Assembler::Opcode::NOP7, Assembler::Opcode::NOP8, Assembler::Opcode::NOP9, Assembler::Opcode::NOP10, Assembler::Opcode::NOP11, Assembler::Opcode::NOP12, Assembler::Opcode::NOP13, Assembler::Opcode::NOP14, Assembler::Opcode::NOP15 }; // generic helper function to generate different instructions using differently-sized offsets template static Assembler::SizedInstruction MakeSizedInstructionWithOffset(const Opcode& opcode, Offset offset) { Assembler::SizedInstruction instruction; memcpy(instruction.machineCode, opcode, sizeof(Opcode)); // the displacement/offset is relative to the next instruction const Offset offsetRelativeToNextInstruction = static_cast(offset - INSTRUCTION_SIZE); memcpy(instruction.machineCode + sizeof(Opcode), &offsetRelativeToNextInstruction, sizeof(Offset)); return instruction; } } Assembler::Instruction Assembler::MakeNOP(uint8_t size) { LC_ASSERT(size != 0u, "Invalid NOP length."); LC_ASSERT(size <= Instruction::MAXIMUM_LENGTH, "Exceeded maximum length of instruction."); Instruction instruction; instruction.size = size; memcpy(instruction.machineCode, SIZE_TO_NOP_OPCODE[size], size); return instruction; } Assembler::SizedInstruction Assembler::MakeRET(void) { Assembler::SizedInstruction instruction; memcpy(instruction.machineCode, Opcode::RET, sizeof(Opcode::RET)); return instruction; } Assembler::SizedInstruction Assembler::MakeJMP8Relative(int8_t displacement) { return MakeSizedInstructionWithOffset(Opcode::JMP_REL8, displacement); } Assembler::SizedInstruction Assembler::MakeJMP32Relative(int32_t displacement) { return MakeSizedInstructionWithOffset(Opcode::JMP_REL32, displacement); } Assembler::SizedInstruction Assembler::MakeJMP32IndirectRIPRelative(int32_t ripOffset) { return MakeSizedInstructionWithOffset(Opcode::JMP_INDIRECT_RIP32, ripOffset); } Assembler::SizedInstruction Assembler::MakeCALL32IndirectRIPRelative(int32_t ripOffset) { return MakeSizedInstructionWithOffset(Opcode::CALL_INDIRECT_RIP32, ripOffset); } Assembler::SizedInstruction Assembler::MakeMOVLoadTCB(void) { Assembler::SizedInstruction instruction; memcpy(instruction.machineCode, Opcode::MOV_RAX_TCB, sizeof(Opcode::MOV_RAX_TCB)); return instruction; } Assembler::SizedInstruction Assembler::MakeADD32IndirectRIPRelative(int32_t ripOffset) { return MakeSizedInstructionWithOffset(Opcode::ADD_RAX_INDIRECT_RIP32, ripOffset); } #endif