#include "examples.common.hpp" #include #include #include #include #if _WIN32 # include #else #endif static void* allocatePage(std::size_t codeSize) { #ifdef _WIN32 return VirtualAlloc(0, codeSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); #else // TODO: mmap for Linux. return nullptr; #endif } static void freePage(void* p) { #ifdef _WIN32 VirtualFree(p, 0, MEM_RELEASE); #else // TODO: munmap for Linux. #endif } // Calculate the estimated code size of the Program. static std::size_t estimateCodeSize(const zasm::Program& program) { std::size_t size = 0; for (auto* node = program.getHead(); node != nullptr; node = node->getNext()) { if (auto* nodeData = node->getIf(); nodeData != nullptr) { size += nodeData->getTotalSize(); } else if (auto* nodeInstr = node->getIf(); nodeInstr != nullptr) { const auto& instrInfo = nodeInstr->getDetail(program.getMode()); if (instrInfo.hasValue()) { size += instrInfo->getLength(); } else { std::cout << "Error: Unable to get instruction info\n"; } } else if (auto* nodeEmbeddedLabel = node->getIf(); nodeEmbeddedLabel != nullptr) { const auto bitSize = nodeEmbeddedLabel->getSize(); if (bitSize == zasm::BitSize::_32) size += 4; if (bitSize == zasm::BitSize::_64) size += 8; } } return size; } // Create fastcall function to add two inputs together. struct AddFunctionGenerator { #if _WIN64 # define FASTCALL_CONV #elif _WIN32 # define FASTCALL_CONV __fastcall #else # define FASTCALL_CONV __attribute__((fastcall)) #endif using FunctionType = std::uintptr_t(FASTCALL_CONV*)(std::uintptr_t a, std::uintptr_t b); static void generate(zasm::Label labelFunc, zasm::Program& program) { using namespace zasm; x86::Assembler a(program); #if _WIN32 # ifdef _WIN64 const auto arg0 = x86::rcx; const auto arg1 = x86::rdx; # else const auto arg0 = x86::ecx; const auto arg1 = x86::edx; # endif #else const auto arg0 = x86::rdi; const auto arg1 = x86::rsi; #endif // The function. a.bind(labelFunc); a.mov(x86::rax, arg0); a.add(x86::rax, arg1); a.ret(); } }; int main() { using namespace zasm; Program program(MachineMode::AMD64); // Generate function into program. auto labelFunc = program.createLabel("add"); AddFunctionGenerator::generate(labelFunc, program); // Estimate the current size and allocate a page. const auto requiredSize = estimateCodeSize(program); void* pCodePage = allocatePage(requiredSize); if (pCodePage == nullptr) { std::cerr << "Failed to allocate page with " << requiredSize << " bytes.\n"; return EXIT_FAILURE; } // Serialize program. Serializer serializer; if (auto err = serializer.serialize(program, reinterpret_cast(pCodePage)); err != zasm::ErrorCode::None) { std::cout << "Serialization failure: " << err.getErrorName() << "\n"; return EXIT_FAILURE; } // Copy code to page. std::memcpy(pCodePage, serializer.getCode(), serializer.getCodeSize()); // Get the function address. const auto funcAddress = serializer.getLabelAddress(labelFunc.getId()); assert(funcAddress != -1); const auto adderFunc = reinterpret_cast(funcAddress); // Calling the function, doing some additions: { auto res = adderFunc(0x8000u, 0x8000u); assert(res == 0x8000u + 0x8000u); } { auto res = adderFunc(0x16000u, 0x16000u); assert(res == 0x16000u + 0x16000u); } // Release page freePage(pCodePage); }