From 8a2d1dc5c8b6639985d26d1c915048d87d52426b Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Sun, 18 Oct 2020 16:59:54 +0200 Subject: Added xor, mov, jmp --- asm/intel64/add.cpp | 25 +++++++----- asm/intel64/codes.cpp | 63 +++++++++++++++++++++++++++++- asm/intel64/codes.h | 6 ++- asm/intel64/int.cpp | 4 +- asm/intel64/jmp.cpp | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++ asm/intel64/jmp.h | 31 +++++++++++++++ asm/intel64/mov.cpp | 31 +++++++++++++++ asm/intel64/mov.h | 31 +++++++++++++++ asm/intel64/xor.cpp | 31 +++++++++++++++ asm/intel64/xor.h | 31 +++++++++++++++ 10 files changed, 343 insertions(+), 13 deletions(-) create mode 100644 asm/intel64/jmp.cpp create mode 100644 asm/intel64/jmp.h create mode 100644 asm/intel64/mov.cpp create mode 100644 asm/intel64/mov.h create mode 100644 asm/intel64/xor.cpp create mode 100644 asm/intel64/xor.h (limited to 'asm/intel64') diff --git a/asm/intel64/add.cpp b/asm/intel64/add.cpp index dc5c704..2de2219 100644 --- a/asm/intel64/add.cpp +++ b/asm/intel64/add.cpp @@ -9,10 +9,16 @@ using namespace std::string_literals; Op_add::Op_add(AsmArgs& args) { - if (args[0].type() == typeid(Register32) && std::any_cast(args[0]).name() == "eax" && args[1].type() == typeid(Immediate32)) { // add eax, imm32 - machine_code = std::vector{ 0x05 } + std::any_cast(args[1]).getCode(); - } else if (args[0].type() == typeid(Register64) && std::any_cast(args[0]).name() == "rax" && args[1].type() == typeid(Immediate32)) { // add rax, imm32 - machine_code = REX("W") + std::vector{ 0x05 } + std::any_cast(args[1]).getCode(); + if (args[0].type() == typeid(AsmArgs::Register32) && + std::any_cast(args[0]).name() == "eax" && + args[1].type() == typeid(AsmArgs::Immediate32)) + { // add eax, imm32 + machine_code = std::vector{ 0x05 } + std::any_cast(args[1]).getCode(); + } else if (args[0].type() == typeid(AsmArgs::Register64) && + std::any_cast(args[0]).name() == "rax" && + args[1].type() == typeid(AsmArgs::Immediate32)) + { // add rax, imm32 + machine_code = REX("W") + std::vector{ 0x05 } + std::any_cast(args[1]).getCode(); } else { throw std::runtime_error("Unimplemented: add "s + args[0].type().name() + " "s + args[1].type().name()); } @@ -20,12 +26,13 @@ Op_add::Op_add(AsmArgs& args) namespace { -bool registered0 { registerOp(mangleName("add"), [](AsmArgs& args) -> std::shared_ptr{ +bool registered { + registerOp(mangleName("add"), [](AsmArgs& args) -> std::shared_ptr{ return std::make_shared(args); - }) }; -// TODO -bool registered1 { registerOp(mangleName("add"), [](AsmArgs& args) -> std::shared_ptr{ + }) && + registerOp(mangleName("add"), [](AsmArgs& args) -> std::shared_ptr{ return std::make_shared(args); - }) }; + }) +}; } diff --git a/asm/intel64/codes.cpp b/asm/intel64/codes.cpp index a1d9e87..66a08dd 100644 --- a/asm/intel64/codes.cpp +++ b/asm/intel64/codes.cpp @@ -1,7 +1,12 @@ #include "codes.h" +#include +#include + +using namespace std::string_literals; + // REX prefix: 0b0100WRXB -std::vector REX(std::string s) { +std::vector REX(const std::string& s) { uint8_t result{0b01000000}; if (s == "W") result |= 0b00001000; @@ -15,3 +20,59 @@ std::vector REX(std::string s) { return { result }; } +namespace { + + std::unordered_map IndexOfRegister{ + {"al", 0}, {"ah", 4}, + {"bl", 3}, {"bh", 7}, + {"cl", 1}, {"ch", 5}, + {"dl", 2}, {"dh", 6}, + + {"ax", 0}, {"sp", 4}, + {"bx", 3}, {"bp", 7}, + {"cx", 1}, {"si", 5}, + {"dx", 2}, {"di", 6}, + + {"eax", 0}, {"esp", 4}, + {"ebx", 3}, {"ebp", 7}, + {"ecx", 1}, {"esi", 5}, + {"edx", 2}, {"edi", 6}, + }; + +} + +// Manual, page 530 +// Reg + Reg/Memory +uint8_t ModRM(const std::string& reg, const std::string& rm) { + // TODO: extend + uint8_t result{0b11000000}; + + auto index1{ IndexOfRegister.find(reg) }; + if (index1 == IndexOfRegister.end()) + throw std::runtime_error("Unknown register for arg1: "s + reg); + + result |= (index1->second << 3); + + auto index2{ IndexOfRegister.find(rm) }; + if (index2 == IndexOfRegister.end()) + throw std::runtime_error("Unknown register for arg2: "s + rm); + + result |= index2->second; + + return result; +} + +#if 0 + prefixes{ + "lock", 0xf0, + + // branch hint + 0x2e, "branch not taken" + 0x3e, "branch taken" + + 0x66, "operand size override" // switch between 16 and 32 bit operands + 0x67, "address size override" // switch between 16 and 32 bit addresses + }; + }; +#endif + diff --git a/asm/intel64/codes.h b/asm/intel64/codes.h index 32eff1c..0ff17f1 100644 --- a/asm/intel64/codes.h +++ b/asm/intel64/codes.h @@ -5,4 +5,8 @@ #include // REX prefix: 0b0100WRXB -std::vector REX(std::string s); +std::vector REX(const std::string& s); + +// Manual, page 530 +// Reg + Reg/Memory +uint8_t ModRM(const std::string& reg, const std::string& rm); diff --git a/asm/intel64/int.cpp b/asm/intel64/int.cpp index 7b682ab..a7df338 100644 --- a/asm/intel64/int.cpp +++ b/asm/intel64/int.cpp @@ -6,7 +6,7 @@ Op_int::Op_int(AsmArgs& args) { // At this point, the registration already ensured the number and types of args - Immediate8 i {std::any_cast(args[0])}; + AsmArgs::Immediate8 i {std::any_cast(args[0])}; if (i.value() == 0) { // INT 0 machine_code = { 0xCE }; @@ -21,7 +21,7 @@ Op_int::Op_int(AsmArgs& args) namespace { -bool registered { registerOp(mangleName("int"), [](AsmArgs& args) -> std::shared_ptr{ +bool registered { registerOp(mangleName("int"), [](AsmArgs& args) -> std::shared_ptr{ return std::make_shared(args); }) }; diff --git a/asm/intel64/jmp.cpp b/asm/intel64/jmp.cpp new file mode 100644 index 0000000..30ae546 --- /dev/null +++ b/asm/intel64/jmp.cpp @@ -0,0 +1,103 @@ +#include "jmp.h" + +#include "codes.h" + +#include +#include + +#include + +using namespace std::string_literals; + +namespace { + struct Jump { + std::string name; + OP_T jmp8; ///< if empty, not available + OP_T jmp32; ///< if empty, not available + }; + + std::vector jumpOps { + // Call Procedure + {"call", OP_T{}, OP_T{ 0xE8 } }, // no addr8 version + + // Unconditional Jump + {"jmp", OP_T{ 0xEB }, OP_T{ 0xE9 } }, + + // Conditional Jumps + {"ja", OP_T{ 0x77 }, OP_T{ 0x0F, 0x87 }}, + {"jae", OP_T{ 0x73 }, OP_T{ 0x0F, 0x83 }}, + {"jb", OP_T{ 0x72 }, OP_T{ 0x0F, 0x82 }}, + {"jbe", OP_T{ 0x76 }, OP_T{ 0x0F, 0x86 }}, + {"jc", OP_T{ 0x72 }, OP_T{ 0x0F, 0x82 }}, + {"jecxz", OP_T{ 0xE3 }, OP_T{} }, // no addr32 version + {"jrcxz", OP_T{ 0xE3 }, OP_T{} }, // no addr32 version + {"je", OP_T{ 0x74 }, OP_T{ 0x0F, 0x84 }}, + {"jg", OP_T{ 0x7F }, OP_T{ 0x0F, 0x8F }}, + {"jge", OP_T{ 0x7D }, OP_T{ 0x0F, 0x8D }}, + {"jl", OP_T{ 0x7C }, OP_T{ 0x0F, 0x8C }}, + {"jle", OP_T{ 0x7E }, OP_T{ 0x0F, 0x8E }}, + {"jna", OP_T{ 0x76 }, OP_T{ 0x0F, 0x86 }}, + {"jnae", OP_T{ 0x72 }, OP_T{ 0x0F, 0x82 }}, + {"jnb", OP_T{ 0x73 }, OP_T{ 0x0F, 0x83 }}, + {"jnbe", OP_T{ 0x77 }, OP_T{ 0x0F, 0x87 }}, + {"jnc", OP_T{ 0x73 }, OP_T{ 0x0F, 0x83 }}, + {"jne", OP_T{ 0x75 }, OP_T{ 0x0F, 0x85 }}, + {"jng", OP_T{ 0x7E }, OP_T{ 0x0F, 0x8E }}, + {"jnge", OP_T{ 0x7C }, OP_T{ 0x0F, 0x8C }}, + {"jnl", OP_T{ 0x7D }, OP_T{ 0x0F, 0x8D }}, + {"jnle", OP_T{ 0x7F }, OP_T{ 0x0F, 0x8F }}, + {"jno", OP_T{ 0x71 }, OP_T{ 0x0F, 0x81 }}, + {"jnp", OP_T{ 0x7B }, OP_T{ 0x0F, 0x8B }}, + {"jns", OP_T{ 0x79 }, OP_T{ 0x0F, 0x89 }}, + {"jnz", OP_T{ 0x75 }, OP_T{ 0x0F, 0x85 }}, + {"jo", OP_T{ 0x70 }, OP_T{ 0x0F, 0x80 }}, + {"jp", OP_T{ 0x7A }, OP_T{ 0x0F, 0x8A }}, + {"jpe", OP_T{ 0x7A }, OP_T{ 0x0F, 0x8A }}, + {"jpo", OP_T{ 0x7B }, OP_T{ 0x0F, 0x8B }}, + {"js", OP_T{ 0x78 }, OP_T{ 0x0F, 0x88 }}, + {"jz", OP_T{ 0x74 }, OP_T{ 0x0F, 0x84 }}, + }; + + bool registerOps() { + bool result{true}; + for (const auto& jumpOp: jumpOps) { + result &= registerOp(mangleName(jumpOp.name), [&](AsmArgs& args) -> std::shared_ptr{ + return std::make_shared(jumpOp.name, args, jumpOp.jmp8, jumpOp.jmp32); + }); + } + return result; + } + + bool registered { + registerOps() + }; +} + +Op_jmp::Op_jmp(const std::string& name, AsmArgs& args, const OP_T& jmp8, const OP_T& jmp32) +{ + label = std::any_cast(args[0]).name(); + + if (!jmp32.empty()) { // set machine_code + machine_code = jmp32 + OP_T{size_t(4), uint8_t(0)}; + addr_size = 4; + addr_offs = jmp32.size(); + if (!jmp8.empty()) { // also provide alternative + alternative_code = jmp8 + OP_T{size_t(1), uint8_t(0)}; + alternative_size = 1; + alternative_offs = jmp8.size(); + } + } + + if (machine_code.empty() && !jmp8.empty()) { + machine_code = jmp8 + OP_T{size_t(1), uint8_t(0)}; + addr_size = 1; + addr_offs = jmp8.size(); + } + + if (machine_code.empty()) { + throw std::runtime_error("Unimplemented: "s + name); + } + + // actual address not set, yet! +} + diff --git a/asm/intel64/jmp.h b/asm/intel64/jmp.h new file mode 100644 index 0000000..db8a5a8 --- /dev/null +++ b/asm/intel64/jmp.h @@ -0,0 +1,31 @@ +// jmp +// call +// ja +// ... + +#pragma once + +#include + +class Op_jmp: public Op, public AddressFeature +{ +public: + Op_jmp(const std::string& name, AsmArgs& args, const OP_T& jmp8, const OP_T& jmp32); + + std::vector getCode() override + { + return machine_code; + } + + size_t size() override + { + return machine_code.size(); + } + + bool optimize() override ///< returns true if changed + { + return false; + } + +}; + diff --git a/asm/intel64/mov.cpp b/asm/intel64/mov.cpp new file mode 100644 index 0000000..33589e9 --- /dev/null +++ b/asm/intel64/mov.cpp @@ -0,0 +1,31 @@ +#include "mov.h" + +#include "codes.h" + +#include +#include + +#include + +using namespace std::string_literals; + +Op_mov::Op_mov(AsmArgs& args) +{ + if (args[0].type() == typeid(AsmArgs::Register8) && args[1].type() == typeid(AsmArgs::Register8)) { // mov reg8, reg8 + // r/m8, r8: ModRM:r/m (w), ModRM:reg (r) + machine_code = std::vector{ 0x88 } + + ModRM(std::any_cast(args[1]).name(), std::any_cast(args[0]).name()); + } else { + throw std::runtime_error("Unimplemented: mov "s + args[0].type().name() + " "s + args[1].type().name()); + } +} + +namespace { + +bool registered { + registerOp(mangleName("mov"), [](AsmArgs& args) -> std::shared_ptr{ + return std::make_shared(args); + }) +}; + +} diff --git a/asm/intel64/mov.h b/asm/intel64/mov.h new file mode 100644 index 0000000..e1b2304 --- /dev/null +++ b/asm/intel64/mov.h @@ -0,0 +1,31 @@ +// Memory Move + +#pragma once + +#include + +class Op_mov: public Op +{ +public: + Op_mov(AsmArgs& args); + +public: + std::vector getCode() override + { + return machine_code; + } + + size_t size() override + { + return machine_code.size(); + } + + bool optimize() override ///< returns true if changed + { + return false; + } + +protected: + std::vector machine_code; +}; + diff --git a/asm/intel64/xor.cpp b/asm/intel64/xor.cpp new file mode 100644 index 0000000..c0dbb68 --- /dev/null +++ b/asm/intel64/xor.cpp @@ -0,0 +1,31 @@ +#include "xor.h" + +#include "codes.h" + +#include +#include + +#include + +using namespace std::string_literals; + +Op_xor::Op_xor(AsmArgs& args) +{ + if (args[0].type() == typeid(AsmArgs::Register8) && args[1].type() == typeid(AsmArgs::Register8)) { // xor reg8, reg8 + // r8, r/m8: ModRM:reg (w), ModRM:r/m (r) + machine_code = std::vector{ 0x32 } + + ModRM(std::any_cast(args[0]).name(), std::any_cast(args[1]).name()); + } else { + throw std::runtime_error("Unimplemented: xor "s + args[0].type().name() + " "s + args[1].type().name()); + } +} + +namespace { + +bool registered { + registerOp(mangleName("xor"), [](AsmArgs& args) -> std::shared_ptr{ + return std::make_shared(args); + }) +}; + +} diff --git a/asm/intel64/xor.h b/asm/intel64/xor.h new file mode 100644 index 0000000..f00a657 --- /dev/null +++ b/asm/intel64/xor.h @@ -0,0 +1,31 @@ +// XOR + +#pragma once + +#include + +class Op_xor: public Op +{ +public: + Op_xor(AsmArgs& args); + +public: + std::vector getCode() override + { + return machine_code; + } + + size_t size() override + { + return machine_code.size(); + } + + bool optimize() override ///< returns true if changed + { + return false; + } + +protected: + std::vector machine_code; +}; + -- cgit v1.2.3