diff options
Diffstat (limited to 'asm/intel64/codes.cpp')
-rw-r--r-- | asm/intel64/codes.cpp | 43 |
1 files changed, 30 insertions, 13 deletions
diff --git a/asm/intel64/codes.cpp b/asm/intel64/codes.cpp index 58d921f..9f82d37 100644 --- a/asm/intel64/codes.cpp +++ b/asm/intel64/codes.cpp @@ -1,5 +1,8 @@ #include "codes.h" +#include "minicc.h" +#include "../operators.h" + #include <exception> #include <unordered_map> @@ -44,12 +47,13 @@ namespace { {"rdx", 2}, {"rdi", 7}, }; -} +} // namespace // Manual, page 530 // Reg + Reg/Memory -uint8_t ModRM(const std::string& reg, const std::string& rm) { - uint8_t result{0b11000000}; // TODO: other than 11: Indexed forms of r/m +std::vector<uint8_t> ModRM(const std::string& reg, const std::string& rm, int32_t disp) { + uint8_t result{}; // MOD is highest 2 bits, then 3 bits Reg, the 3 bits R/M + std::vector<uint8_t> displacement_bytes; size_t val_reg{}; // reg @@ -60,22 +64,35 @@ uint8_t ModRM(const std::string& reg, const std::string& rm) { throw std::runtime_error("ModRM: Bad digit in arg1: "s + reg); } } else { // reg - auto index1{ IndexOfRegister.find(reg) }; - if (index1 == IndexOfRegister.end()) - throw std::runtime_error("ModRM: Unknown register for arg1: "s + reg); - val_reg = index1->second; + val_reg = RegNo(reg); } result |= (val_reg << 3); // rm - auto index2{ IndexOfRegister.find(rm) }; - if (index2 == IndexOfRegister.end()) - throw std::runtime_error("Unknown register for arg2: "s + rm); - - result |= index2->second; + if (rm.size() > 2 && rm.front() == '[' && rm.back() == ']') { // indexed / MemPtr + uint8_t rm_bits {RegNo(rm.substr(1, rm.size() - 2))}; + if (rm_bits == 4) + throw std::runtime_error("ICE: SIB byte not yet supported"); + + if (disp == 0 && rm_bits != 5) { // no displacement + // ignore: keep MOD == 00, no displacement bytes + if (rm_bits == 5) + throw std::runtime_error("ICE: [rbp] with now displacement is not supported"); // TODO: Support this, and SIB byte + } else if (disp >= -128 && disp < 128) { + result |= 0b01000000; // 8 bit displacement + displacement_bytes.push_back(uint8_t(disp)); + } else { + result |= 0b10000000; // 32 bit displacement + displacement_bytes += to_little_endian(disp); + } + result |= rm_bits; + } else { // normal register access + result |= 0b11000000; + result |= RegNo(rm); + } - return result; + return std::vector<uint8_t>{result} + displacement_bytes; } uint8_t RegNo(const std::string& reg) |