Repository: techiew/DirectXHook Branch: master Commit: 2fcd7487298d Files: 27 Total size: 731.4 KB Directory structure: gitextract_hawrj9jj/ ├── .gitignore ├── DirectXHook.sln ├── DirectXHook.vcxproj ├── DirectXHook.vcxproj.filters ├── DirectXHook.vcxproj.user ├── README.md ├── assets/ │ └── hook_fonts/ │ └── OpenSans-22.spritefont ├── include/ │ ├── DirectXHook.h │ ├── ID3DRenderer.h │ ├── IRenderCallback.h │ ├── Logger.h │ ├── MemoryUtils.h │ ├── OverlayFramework.h │ ├── Renderer.h │ ├── UniversalProxyDLL.h │ └── nmd_assembly.h ├── overlays/ │ ├── Example/ │ │ ├── Example.cpp │ │ └── Example.h │ ├── PauseTheGame/ │ │ ├── PauseTheGame.cpp │ │ └── PauseTheGame.h │ └── RiseDpsMeter/ │ ├── RiseDpsMeter.cpp │ └── RiseDpsMeter.h ├── packages.config └── src/ ├── DirectXHook.cpp ├── DllMain.cpp ├── Renderer.cpp └── Shaders.hlsl ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .vs packages/ x64/ x86/ Debug/ Release/ ================================================ FILE: DirectXHook.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.31205.134 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DirectXHook", "DirectXHook.vcxproj", "{5EB93C8A-65BB-403D-A8B5-A39FCF98F17F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {5EB93C8A-65BB-403D-A8B5-A39FCF98F17F}.Debug|x64.ActiveCfg = Debug|x64 {5EB93C8A-65BB-403D-A8B5-A39FCF98F17F}.Debug|x64.Build.0 = Debug|x64 {5EB93C8A-65BB-403D-A8B5-A39FCF98F17F}.Debug|x86.ActiveCfg = Debug|Win32 {5EB93C8A-65BB-403D-A8B5-A39FCF98F17F}.Debug|x86.Build.0 = Debug|Win32 {5EB93C8A-65BB-403D-A8B5-A39FCF98F17F}.Release|x64.ActiveCfg = Release|x64 {5EB93C8A-65BB-403D-A8B5-A39FCF98F17F}.Release|x64.Build.0 = Release|x64 {5EB93C8A-65BB-403D-A8B5-A39FCF98F17F}.Release|x86.ActiveCfg = Release|Win32 {5EB93C8A-65BB-403D-A8B5-A39FCF98F17F}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B1B72F8D-E60B-4269-AC0B-EAC732492566} EndGlobalSection EndGlobal ================================================ FILE: DirectXHook.vcxproj ================================================ Debug Win32 Release Win32 Debug x64 Release x64 16.0 Win32Proj {5eb93c8a-65bb-403d-a8b5-a39fcf98f17f} DirectXHook 10.0 DynamicLibrary true MultiByte v143 DynamicLibrary false true MultiByte v143 DynamicLibrary true MultiByte v143 DynamicLibrary false true MultiByte v143 false dinput8 $(SolutionDir)overlays;$(SolutionDir)include;$(IncludePath) $(SolutionDir)overlays;$(SolutionDir)src false dinput8 $(SolutionDir)overlays;$(SolutionDir)include;$(IncludePath) $(SolutionDir)overlays;$(SolutionDir)src false $(SolutionDir)overlays;$(SolutionDir)include;$(IncludePath) $(SolutionDir)overlays;$(SolutionDir)src dinput8 false $(SolutionDir)overlays;$(SolutionDir)include;$(IncludePath) $(SolutionDir)overlays;$(SolutionDir)src .dll dinput8 true Level3 true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING true MultiThreadedDLL stdcpp17 Windows true d3d11.lib;d3d12.lib;d3dcompiler.lib;%(AdditionalDependencies) Level3 true true true _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;NDEBUG;_CONSOLE true MultiThreadedDLL stdcpp17 Windows true true false d3d11.lib;d3d12.lib;d3dcompiler.lib;%(AdditionalDependencies) Level3 true _DEBUG;_CONSOLE;%(PreprocessorDefinitions);_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING true MultiThreadedDebug stdcpp17 Windows true d3d11.lib;d3d12.lib;d3dcompiler.lib;%(AdditionalDependencies) COPY "C:\Programming\Github repositories\DirectXHook\x64\Release\dinput8.dll" "G:\SteamLibrary\steamapps\common\MonsterHunterRise\reframework\plugins\RiseDpsMeter.dll" Level3 true true true _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;NDEBUG;_CONSOLE true MultiThreadedDLL stdcpp17 Windows true true false d3d11.lib;d3d12.lib;d3dcompiler.lib;%(AdditionalDependencies) COPY "C:\Programming\Github repositories\DirectXHook\x64\Release\dinput8.dll" "F:\SteamLibrary\steamapps\common\ELDEN RING\Game\dinput8.dll" XCOPY /y "C:\Programming\Github repositories\DirectXHook\assets\hook_textures" "F:\SteamLibrary\steamapps\common\ELDEN RING\Game\hook_textures\" XCOPY /y "C:\Programming\Github repositories\DirectXHook\assets\hook_fonts" "F:\SteamLibrary\steamapps\common\ELDEN RING\Game\hook_fonts\" false false true true true true false false This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. ================================================ FILE: DirectXHook.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd {4e722490-89b1-476c-8f11-f855725e5074} {8a12ed8f-5e32-450f-8ec9-985d3e5cde32} {f65c6413-9861-46d0-ac93-cc3206db7958} {49480136-b55a-468a-b6ab-1720b97d7141} Source Files Source Files Source Files Overlays\Example Overlays\PauseTheGame Overlays\RiseDpsMeter Source Files Header Files Header Files Header Files Header Files Header Files Header Files Overlays\Example Overlays\RiseDpsMeter Overlays\PauseTheGame Header Files Header Files ================================================ FILE: DirectXHook.vcxproj.user ================================================  G:\SteamLibrary\steamapps\common\ELDEN RING\Game\eldenring.exe true WindowsLocalDebugger G:\SteamLibrary\steamapps\common\ELDEN RING\Game\eldenring.exe true WindowsLocalDebugger G:\SteamLibrary\steamapps\common\ELDEN RING\Game\eldenring.exe WindowsLocalDebugger true G:\SteamLibrary\steamapps\common\ELDEN RING\Game\eldenring.exe WindowsLocalDebugger true ================================================ FILE: README.md ================================================ ## DirectXHook + Overlay Framework A DirectX hook that works with DirectX11 and DirectX12 in 32-bit and 64-bit modes. Basically this library lets you render your own things inside the game window, as an integrated part of the game rather than as an external overlay. A straightforward but primitive overlay framework is included so you can quickly and easily start creating overlays. Tutorial below. ### This library is used in... #### A mod for Elden Ring, ["First Person Souls - Full Game Conversion found on NexusMods"](https://www.nexusmods.com/eldenring/mods/3266) [![First Person Souls](https://github.com/techiew/DirectXHook/blob/master/assets/repo_pictures/er_first_person_souls.png)](https://www.youtube.com/watch?v=nuau_lZ0Imc) #### A mod for Elden Ring, ["Pause the game" found on NexusMods](https://www.nexusmods.com/eldenring/mods/43) [![Pause the Game](https://github.com/techiew/DirectXHook/blob/master/assets/repo_pictures/er_pause_the_game.png)](https://www.youtube.com/watch?v=xvK1ti_hHh4) #### A mod for Monster Hunter Rise, ["Rise DPS Meter" found on NexusMods](https://www.nexusmods.com/monsterhunterrise/mods/289) -video to be added- #### Example triangle -video to be added- ## How to create an overlay First, check the [wiki page](https://github.com/techiew/DirectXHook/wiki/How-to-set-up-the-Visual-Studio-solution) on how to quickly set up the Visual Studio solution. When the project is built, "dinput8.dll" will be generated in the project folder. This must be copied next to a game executable which uses DirectX 11 or 12. The game will then load the .dll automatically on startup and will render what you told it to. Also note that the "hook_textures" folder containing "blank.jpg" must be present next to dxgi.dll in order for anything to render. ### Create files Create a .cpp and .h file in the Overlays folder (optionally put these inside a parent folder): ![create_files](https://github.com/techiew/DirectXHook/blob/master/assets/repo_pictures/create_files.png) Create a class that inherits from the IRenderCallback interface and includes "OverlayFramework.h": ![example_header](https://github.com/techiew/DirectXHook/blob/master/assets/repo_pictures/example_header.png) Define the Setup() and Render() functions in the .cpp file: ![example_source](https://github.com/techiew/DirectXHook/blob/master/assets/repo_pictures/example_source.png) **Note: Setup() is called once and Render() is called every frame. InitFramework() must be called on the very first line in Setup().** Make the hook render your stuff by adding these lines in DllMain.cpp: ![dllmain](https://github.com/techiew/DirectXHook/blob/master/assets/repo_pictures/dllmain.png) But we have yet to define anything to render... ### Boxes All rendering with the overlay framework is done using Boxes: ![box_struct](https://github.com/techiew/DirectXHook/blob/master/assets/repo_pictures/box_struct.png) Boxes are a simple struct with data that the framework manages. - **pressed** = if the mouse is currently being pressed on this box - **clicked** = if the mouse was previously pressed and then released on the box this frame - **hover** = if the mouse is hovering over the box The rest are self-explanatory. Do not modify **visible** or **z**. Create some boxes and render them: ![rgb_boxes_code](https://github.com/techiew/DirectXHook/blob/master/assets/repo_pictures/rgb_boxes_code.png) Result: ![rgb_boxes](https://github.com/techiew/DirectXHook/blob/master/assets/repo_pictures/rgb_boxes.png) Boxes can be rendered with either textures or colors: ![textures_code](https://github.com/techiew/DirectXHook/blob/master/assets/repo_pictures/textures_code.png) **Note: textures should be loaded in Setup().** Result: ![textures](https://github.com/techiew/DirectXHook/blob/master/assets/repo_pictures/textures.png) Text can be rendered inside Boxes: ![text_code](https://github.com/techiew/DirectXHook/blob/master/assets/repo_pictures/text_code.png) **Note: a font must be set before rendering text.** Result: ![text](https://github.com/techiew/DirectXHook/blob/master/assets/repo_pictures/text.png) ### Contributions Feel free to create issues or contribute code to the repo. ### License Feel free to use this code for anything and however you like, but if you create something with it then it would be cool if you could show me what you made :) ================================================ FILE: include/DirectXHook.h ================================================ #pragma once #include #include #include #include "Renderer.h" #include "ID3DRenderer.h" #include "IRenderCallback.h" #include "Logger.h" #include "MemoryUtils.h" /* * Here we have typedefs of the functions we want to hook. * They are defined so we can call the respective functions through pointers to their memory addresses. * * Setting the proper calling convention is important (__stdcall). * It makes it so the function arguments are read/written to/from memory in the correct way. * 64-bit functions actually use the __fastcall calling convention, but the compiler changes * __stdcall to __fastcall automatically for 64-bit compilation. */ typedef HRESULT(__stdcall* Present)(IDXGISwapChain* This, UINT SyncInterval, UINT Flags); typedef HRESULT(__stdcall* ResizeBuffers)(IDXGISwapChain* This, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags); typedef void(__stdcall* ExecuteCommandLists)(ID3D12CommandQueue* This, UINT NumCommandLists, const ID3D12CommandList** ppCommandLists); // Hooks DirectX 11 and DirectX 12 class DirectXHook { public: ID3DRenderer* renderer; uintptr_t executeCommandListsAddress = 0; uintptr_t presentReturnAddress = 0; uintptr_t resizeBuffersReturnAddress = 0; uintptr_t executeCommandListsReturnAddress = 0; DirectXHook(ID3DRenderer* renderer); void Hook(); void SetDrawExampleTriangle(bool doDraw); void AddRenderCallback(IRenderCallback* object); ID3D12CommandQueue* CreateDummyCommandQueue(); void HookCommandQueue(ID3D12CommandQueue* dummyCommandQueue, uintptr_t executeCommandListsDetourFunction, uintptr_t* executeCommandListsReturnAddress); void UnhookCommandQueue(); private: Logger logger{ "DirectXHook" }; IDXGISwapChain* CreateDummySwapChain(); void HookSwapChain(IDXGISwapChain* dummySwapChain, uintptr_t presentDetourFunction, uintptr_t resizeBuffersDetourFunction, uintptr_t* presentReturnAddress, uintptr_t* resizeBuffersReturnAddress); }; ================================================ FILE: include/ID3DRenderer.h ================================================ #pragma once #include #include "IRenderCallback.h" class ID3DRenderer { public: virtual void OnPresent(IDXGISwapChain* pThis, UINT syncInterval, UINT flags) = 0; virtual void OnResizeBuffers(IDXGISwapChain* pThis, UINT bufferCount, UINT width, UINT height, DXGI_FORMAT newFormat, UINT swapChainFlags) {}; virtual void AddRenderCallback(IRenderCallback* object) {}; virtual void SetCommandQueue(ID3D12CommandQueue* commandQueue) {}; virtual void SetGetCommandQueueCallback(void (*callback)()) {}; }; ================================================ FILE: include/IRenderCallback.h ================================================ #pragma once #include #include #include #include class IRenderCallback { public: virtual void Setup() { }; virtual void Render() = 0; void Init( Microsoft::WRL::ComPtr device, Microsoft::WRL::ComPtr context, std::shared_ptr spriteBatch, HWND window) { this->device = device; this->context = context; this->spriteBatch = spriteBatch; this->window = window; } protected: Microsoft::WRL::ComPtr device = nullptr; Microsoft::WRL::ComPtr context = nullptr; std::shared_ptr spriteBatch = nullptr; HWND window = NULL; }; ================================================ FILE: include/Logger.h ================================================ #pragma once #include #include class Logger { public: Logger(const char* prefix) { printPrefix = prefix; FILE* logFile = GetLogFile(); if (logFile == nullptr) { fopen_s(&logFile, "hook_log.txt", "w"); GetLogFile(logFile); } } void Log(std::string msg, ...) { va_list args; va_start(args, msg); vprintf(std::string(printPrefix + " > " + msg + "\n").c_str(), args); if (GetLogFile() != nullptr) { vfprintf(GetLogFile(), std::string(printPrefix + " > " + msg + "\n").c_str(), args); fflush(GetLogFile()); } va_end(args); } private: std::string printPrefix = ""; static FILE* GetLogFile(FILE* newLogFile = nullptr) { static FILE* logFile = nullptr; if (newLogFile != nullptr) { logFile = newLogFile; } return logFile; } }; ================================================ FILE: include/MemoryUtils.h ================================================ #pragma once #include #include #include #include #include #include #include #include #define NMD_ASSEMBLY_IMPLEMENTATION #define NMD_ASSEMBLY_PRIVATE #include "nmd_assembly.h" #include "Logger.h" // Contains various memory manipulation functions related to hooking or modding namespace MemoryUtils { static Logger logger{ "MemoryUtils" }; static constexpr int maskBytes = 0xffff; struct HookInformation { std::vector originalBytes = { 0 }; uintptr_t trampolineInstructionsAddress = 0; }; static std::unordered_map InfoBufferForHookedAddresses; // Disables or enables the memory protection in a given region. // Remembers and restores the original memory protection type of the given addresses. static void ToggleMemoryProtection(bool enableProtection, uintptr_t address, size_t size) { static std::map protectionHistory; if (enableProtection && protectionHistory.find(address) != protectionHistory.end()) { VirtualProtect((void*)address, size, protectionHistory[address], &protectionHistory[address]); protectionHistory.erase(address); } else if (!enableProtection && protectionHistory.find(address) == protectionHistory.end()) { DWORD oldProtection = 0; VirtualProtect((void*)address, size, PAGE_EXECUTE_READWRITE, &oldProtection); protectionHistory[address] = oldProtection; } } // Copies memory after changing the permissions at both the source and destination so we don't get an access violation. static void MemCopy(uintptr_t destination, uintptr_t source, size_t numBytes) { ToggleMemoryProtection(false, destination, numBytes); ToggleMemoryProtection(false, source, numBytes); memcpy((void*)destination, (void*)source, numBytes); ToggleMemoryProtection(true, source, numBytes); ToggleMemoryProtection(true, destination, numBytes); } // Simple wrapper around memset static void MemSet(uintptr_t address, unsigned char byte, size_t numBytes) { ToggleMemoryProtection(false, address, numBytes); memset((void*)address, byte, numBytes); ToggleMemoryProtection(true, address, numBytes); } // Gets the base address of the game's memory. static uintptr_t GetProcessBaseAddress(DWORD processId) { DWORD_PTR baseAddress = 0; HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId); if (processHandle) { DWORD bytesRequired = 0; if (EnumProcessModules(processHandle, NULL, 0, &bytesRequired)) { if (bytesRequired) { LPBYTE moduleArrayBytes = (LPBYTE)LocalAlloc(LPTR, bytesRequired); if (moduleArrayBytes) { HMODULE* moduleArray = (HMODULE*)moduleArrayBytes; if (EnumProcessModules(processHandle, moduleArray, bytesRequired, &bytesRequired)) { baseAddress = (DWORD_PTR)moduleArray[0]; } LocalFree(moduleArrayBytes); } } } CloseHandle(processHandle); } return baseAddress; } static std::string GetCurrentProcessName() { char lpFilename[MAX_PATH]; GetModuleFileNameA(NULL, lpFilename, sizeof(lpFilename)); std::string moduleName = strrchr(lpFilename, '\\'); moduleName = moduleName.substr(1, moduleName.length()); return moduleName; } static std::string GetCurrentModuleName() { HMODULE module = NULL; static char dummyStaticVariableToGetModuleName = 'x'; GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, &dummyStaticVariableToGetModuleName, &module); char lpFilename[MAX_PATH]; GetModuleFileNameA(module, lpFilename, sizeof(lpFilename)); char* lastSlash = strrchr(lpFilename, '\\'); std::string moduleName = ""; if (lastSlash != nullptr) { moduleName = lastSlash; moduleName = moduleName.substr(1, moduleName.length()); moduleName.erase(moduleName.find(".dll"), moduleName.length()); } return moduleName; } static void ShowErrorPopup(std::string error) { logger.Log("Raised error: %s", error.c_str()); MessageBox(NULL, error.c_str(), GetCurrentModuleName().c_str(), MB_OK | MB_ICONERROR | MB_SYSTEMMODAL); } static void PrintPattern(std::vector pattern) { std::string patternString = ""; for (auto bytes : pattern) { std::stringstream stream; std::string byte = ""; if (bytes == maskBytes) { byte = "?"; } else { stream << "0x" << std::hex << bytes; byte = stream.str(); } patternString.append(byte + " "); } logger.Log("Pattern: %s", patternString.c_str()); } // Scans the memory of the main process module for the given signature. static uintptr_t SigScan(std::vector pattern) { DWORD processId = GetCurrentProcessId(); uintptr_t regionStart = GetProcessBaseAddress(processId); logger.Log("Process name: %s", GetCurrentProcessName().c_str()); logger.Log("Process ID: %i", processId); logger.Log("Process base address: 0x%llX", regionStart); PrintPattern(pattern); size_t numRegionsChecked = 0; size_t maxNumberOfRegionsToCheck = 10000; uintptr_t currentAddress = 0; while (numRegionsChecked < maxNumberOfRegionsToCheck) { MEMORY_BASIC_INFORMATION memoryInfo = { 0 }; if (VirtualQuery((void*)regionStart, &memoryInfo, sizeof(MEMORY_BASIC_INFORMATION)) == 0) { DWORD error = GetLastError(); if (error == ERROR_INVALID_PARAMETER) { logger.Log("Reached end of scannable memory."); } else { logger.Log("VirtualQuery failed, error code: %i.", error); } break; } regionStart = (uintptr_t)memoryInfo.BaseAddress; size_t regionSize = memoryInfo.RegionSize; uintptr_t regionEnd = regionStart + regionSize; DWORD protection = memoryInfo.Protect; DWORD state = memoryInfo.State; bool isMemoryReadable = ( protection == PAGE_EXECUTE_READWRITE || protection == PAGE_READWRITE || protection == PAGE_READONLY || protection == PAGE_WRITECOPY || protection == PAGE_EXECUTE_WRITECOPY) && state == MEM_COMMIT; if (isMemoryReadable) { logger.Log("Checking region: %p", regionStart); currentAddress = regionStart; while (currentAddress < regionEnd - pattern.size()) { for (size_t i = 0; i < pattern.size(); i++) { if (pattern[i] == maskBytes) { currentAddress++; continue; } else if (*(unsigned char*)currentAddress != (unsigned char)pattern[i]) { currentAddress++; break; } else if (i == pattern.size() - 1) { uintptr_t signature = currentAddress - pattern.size() + 1; logger.Log("Found signature at %p", signature); return signature; } currentAddress++; } } } else { logger.Log("Skipped region: %p", regionStart); } numRegionsChecked++; regionStart += regionSize; } logger.Log("Stopped at: %p, num regions checked: %i", currentAddress, numRegionsChecked); ShowErrorPopup("Could not find signature!"); return 0; } static uintptr_t AllocateMemory(size_t numBytes) { uintptr_t memoryAddress = NULL; memoryAddress = (uintptr_t)VirtualAlloc(NULL, numBytes, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (memoryAddress == NULL) { logger.Log("Failed to allocate %i bytes of memory", numBytes); } else { logger.Log("Allocated %i bytes of memory at %p", numBytes, memoryAddress); MemSet(memoryAddress, 0x90, numBytes); } return memoryAddress; } static uintptr_t AllocateMemoryWithin32BitRange(size_t numBytes, uintptr_t origin) { uintptr_t memoryAddress = NULL; size_t unidirectionalRange = 0x7fffffff; uintptr_t lowerBound = origin - unidirectionalRange; uintptr_t higherBound = origin + unidirectionalRange; size_t numAttempts = 0; for (size_t i = lowerBound; i < higherBound;) { numAttempts++; memoryAddress = (uintptr_t)VirtualAlloc((void*)i, numBytes, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (memoryAddress != NULL) { bool memoryAddressIsAcceptable = memoryAddress >= lowerBound && memoryAddress <= higherBound; if (memoryAddressIsAcceptable) { break; } else { MEMORY_BASIC_INFORMATION info; VirtualQuery((void*)memoryAddress, &info, sizeof(MEMORY_BASIC_INFORMATION)); i += info.RegionSize; VirtualFree((void*)memoryAddress, 0, MEM_RELEASE); } } else { size_t arbitraryIncrement = 10000; i += arbitraryIncrement; } } if (memoryAddress == NULL) { logger.Log( "Failed to allocate %i bytes of memory. Origin: %p, lower: %p, higher: %p, attempts: %i", numBytes, origin, lowerBound, higherBound, numAttempts); } else { logger.Log("Allocated %i bytes of memory at %p", numBytes, memoryAddress); MemSet(memoryAddress, 0x90, numBytes); } return memoryAddress; } static bool IsRelativeNearJumpPresentAtAddress(uintptr_t address) { std::vector buffer(1, 0x90); std::vector assemblyRelativeNearJumpByte = { 0xe9 }; MemCopy((uintptr_t)&buffer[0], address, 1); if (buffer == assemblyRelativeNearJumpByte) { return true; }; return false; } static bool IsAbsoluteIndirectNearJumpPresentAtAddress(uintptr_t address) { std::vector buffer(3, 0x90); std::vector absoluteIndirectNearJumpBytes = { 0x48, 0xff, 0x25 }; MemCopy((uintptr_t)&buffer[0], address, 3); if (buffer == absoluteIndirectNearJumpBytes) { return true; } return false; } static bool IsAbsoluteDirectFarJumpPresentAtAddress(uintptr_t address) { std::vector absoluteDirectFarJump = { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }; std::vector buffer(absoluteDirectFarJump.size(), 0x90); MemCopy((uintptr_t)&buffer[0], address, buffer.size()); if (buffer == absoluteDirectFarJump) { return true; } return false; } static bool IsAddressHooked(uintptr_t address) { if ( IsRelativeNearJumpPresentAtAddress(address) || IsAbsoluteIndirectNearJumpPresentAtAddress(address) || IsAbsoluteDirectFarJumpPresentAtAddress(address)) { return true; } return false; } static size_t CalculateRequiredAsmClearance(uintptr_t address, size_t minimumClearance) { size_t maximumAmountOfBytesToCheck = 30; std::vector bytesBuffer(maximumAmountOfBytesToCheck, 0x90); MemCopy((uintptr_t)&bytesBuffer[0], address, maximumAmountOfBytesToCheck); if (IsAbsoluteDirectFarJumpPresentAtAddress(address)) { return 14; } size_t requiredClearance = 0; for (size_t byteCount = 0; byteCount < maximumAmountOfBytesToCheck;) { size_t instructionSize = nmd_x86_ldisasm( &bytesBuffer[byteCount], maximumAmountOfBytesToCheck - byteCount, NMD_X86_MODE_64); if (instructionSize <= 0) { logger.Log("Instruction invalid, could not check length!"); return minimumClearance; } if (byteCount >= minimumClearance) { requiredClearance = byteCount; break; } byteCount += instructionSize; } return requiredClearance; } static uintptr_t CalculateAbsoluteDestinationFromRelativeNearJumpAtAddress(uintptr_t relativeNearJumpMemoryLocation) { int32_t offset = 0; MemCopy((uintptr_t)&offset, relativeNearJumpMemoryLocation + 1, 4); uintptr_t absoluteAddress = relativeNearJumpMemoryLocation + 5 + offset; return absoluteAddress; } static uintptr_t CalculateAbsoluteDestinationFromAbsoluteIndirectNearJumpAtAddress(uintptr_t absoluteIndirectNearJumpMemoryLocation) { int32_t offset = 0; MemCopy((uintptr_t)&offset, absoluteIndirectNearJumpMemoryLocation + 3, 4); uintptr_t memoryContainingAbsoluteAddress = absoluteIndirectNearJumpMemoryLocation + 7 + offset; uintptr_t absoluteAddress = *(uintptr_t*)memoryContainingAbsoluteAddress; return absoluteAddress; } static uintptr_t CalculateAbsoluteDestinationFromAbsoluteDirectFarJumpAtAddress(uintptr_t absoluteDirectFarJumpMemoryLocation) { uintptr_t absoluteAddress = 0; MemCopy((uintptr_t)&absoluteAddress, absoluteDirectFarJumpMemoryLocation + 6, 8); return absoluteAddress; } static int32_t CalculateRelativeDisplacementForRelativeJump(uintptr_t relativeJumpAddress, uintptr_t destinationAddress) { return -int32_t(relativeJumpAddress + 5 - destinationAddress); } // Places a 14-byte absolutely addressed jump from A to B. // Add extra clearance when the jump doesn't fit cleanly. static void PlaceAbsoluteJump(uintptr_t address, uintptr_t destinationAddress, size_t clearance = 14) { MemSet(address, 0x90, clearance); unsigned char absoluteJumpBytes[6] = { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00}; MemCopy(address, (uintptr_t)&absoluteJumpBytes[0], 6); MemCopy(address + 6, (uintptr_t)&destinationAddress, 8); logger.Log("Created absolute jump from %p to %p with a clearance of %i", address, destinationAddress, clearance); } // Places a 5-byte relatively addressed jump from A to B. // Add extra clearance when the jump doesn't fit cleanly. static void PlaceRelativeJump(uintptr_t address, uintptr_t destinationAddress, size_t clearance = 5) { MemSet(address, 0x90, clearance); unsigned char relativeJumpBytes[5] = { 0xe9, 0x00, 0x00, 0x00, 0x00 }; MemCopy(address, (uintptr_t)&relativeJumpBytes[0], 5); int32_t relativeAddress = CalculateRelativeDisplacementForRelativeJump(address, destinationAddress); MemCopy((address + 1), (uintptr_t)&relativeAddress, 4); logger.Log("Created relative jump from %p to %p with a clearance of %i", address, destinationAddress, clearance); } static std::string ConvertVectorOfBytesToStringOfHex(std::vector bytes) { std::string hexString = ""; for (auto byte : bytes) { std::stringstream stream; std::string byteAsHex = ""; stream << std::hex << std::setfill('0') << std::setw(2) << (int)byte; byteAsHex = stream.str(); hexString.append("0x" + byteAsHex + " "); } return hexString; } static void PrintBytesAtAddress(uintptr_t address, size_t numBytes) { std::vector bytesBuffer(numBytes, 0x90); MemCopy((uintptr_t)&bytesBuffer[0], address, bytesBuffer.size()); std::string hexString = ConvertVectorOfBytesToStringOfHex(bytesBuffer); logger.Log("Existing bytes: %s", hexString.c_str()); } // Place a trampoline hook from A to B while taking third-party hooks into consideration. // Add extra clearance when the jump doesn't fit cleanly. static void PlaceHook(uintptr_t addressToHook, uintptr_t destinationAddress, uintptr_t* returnAddress) { logger.Log("Hooking..."); // Most overlays don't care if we overwrite the 0xE9 jump and place it somewhere else, but MSI Afterburner does. // So instead of overwriting jumps we follow them and place our jump at the final destination. int maxFollowAttempts = 50; int countFollowAttempts = 0; while (IsAddressHooked(addressToHook)) { if (IsRelativeNearJumpPresentAtAddress(addressToHook)) { addressToHook = CalculateAbsoluteDestinationFromRelativeNearJumpAtAddress(addressToHook); } else if (IsAbsoluteIndirectNearJumpPresentAtAddress(addressToHook)) { addressToHook = CalculateAbsoluteDestinationFromAbsoluteIndirectNearJumpAtAddress(addressToHook); } else if (IsAbsoluteDirectFarJumpPresentAtAddress(addressToHook)) { //addressToHook = CalculateAbsoluteDestinationFromAbsoluteDirectFarJumpAtAddress(addressToHook); } countFollowAttempts++; if (countFollowAttempts >= maxFollowAttempts) { break; } } PrintBytesAtAddress(addressToHook, 20); const size_t assemblyShortJumpSize = 5; const size_t assemblyFarJumpSize = 14; size_t trampolineSize = 0; uintptr_t trampolineAddress = 0; uintptr_t trampolineReturnAddress = 0; size_t thirdPartyHookProtectionBuffer = assemblyFarJumpSize; size_t clearance = CalculateRequiredAsmClearance(addressToHook, assemblyShortJumpSize); trampolineSize = assemblyFarJumpSize * 3 + clearance + thirdPartyHookProtectionBuffer; #ifdef _WIN64 trampolineAddress = AllocateMemoryWithin32BitRange(trampolineSize, addressToHook + assemblyShortJumpSize); #else trampolineAddress = AllocateMemory(trampolineSize); #endif trampolineReturnAddress = addressToHook + clearance; MemCopy(trampolineAddress + assemblyFarJumpSize + thirdPartyHookProtectionBuffer, addressToHook, clearance); HookInformation hookInfo; hookInfo.originalBytes = std::vector(clearance); hookInfo.trampolineInstructionsAddress = trampolineAddress + assemblyFarJumpSize + thirdPartyHookProtectionBuffer; InfoBufferForHookedAddresses[addressToHook] = hookInfo; MemCopy( (uintptr_t)&InfoBufferForHookedAddresses[addressToHook].originalBytes[0], trampolineAddress + assemblyFarJumpSize + thirdPartyHookProtectionBuffer, InfoBufferForHookedAddresses[addressToHook].originalBytes.size()); #ifdef _WIN64 PlaceAbsoluteJump(trampolineAddress + thirdPartyHookProtectionBuffer, destinationAddress); PlaceAbsoluteJump(trampolineAddress + trampolineSize - assemblyFarJumpSize, trampolineReturnAddress); #else PlaceRelativeJump(trampolineAddress + thirdPartyHookProtectionBuffer, destinationAddress); PlaceRelativeJump(trampolineAddress + trampolineSize - assemblyFarJumpSize, trampolineReturnAddress); #endif *returnAddress = trampolineAddress + assemblyFarJumpSize + thirdPartyHookProtectionBuffer; PlaceRelativeJump(addressToHook, trampolineAddress, clearance); } static void Unhook(uintptr_t hookedAddress) { auto search = InfoBufferForHookedAddresses.find(hookedAddress); if (search != InfoBufferForHookedAddresses.end()) { MemSet( InfoBufferForHookedAddresses[hookedAddress].trampolineInstructionsAddress, 0x90, InfoBufferForHookedAddresses[hookedAddress].originalBytes.size()); MemCopy( hookedAddress, (uintptr_t)&InfoBufferForHookedAddresses[hookedAddress].originalBytes[0], InfoBufferForHookedAddresses[hookedAddress].originalBytes.size()); logger.Log("Removed hook from %p", hookedAddress); } } static uintptr_t ReadPointerChain(std::vector pointerOffsets) { DWORD processId = GetCurrentProcessId(); uintptr_t baseAddress = GetProcessBaseAddress(processId); uintptr_t pointer = baseAddress; for (size_t i = 0; i < pointerOffsets.size(); i++) { pointer += pointerOffsets[i]; if (pointerOffsets[i] != pointerOffsets.back()) { MemCopy((uintptr_t)&pointer, pointer, sizeof(uintptr_t)); } if (pointer == 0) { return 0; } } return pointer; } } ================================================ FILE: include/OverlayFramework.h ================================================ #pragma once #include #include #include #include #include #include #include #include #include #include #include "Logger.h" #undef DrawText namespace OF { static struct Box { int x = 0; int y = 0; float z = 0.0f; int width = 0; int height = 0; bool pressed = false; bool clicked = false; bool hover = false; bool draggable = true; bool hasBeenRendered = false; Box* parentBox = nullptr; }; static Logger logger{ "OverlayFramework" }; static HWND ofWindow = 0; static int ofWindowWidth = 0; static int ofWindowHeight = 0; static std::vector ofBoxes = std::vector(); static constexpr unsigned char UNBOUND = 0x07; static Microsoft::WRL::ComPtr ofDevice = nullptr; static std::shared_ptr ofSpriteBatch = nullptr; static std::vector> ofTextures = std::vector>(); static std::vector> ofFonts = std::vector>(); static std::shared_ptr ofActiveFont = nullptr; // Gives the framework the required DirectX objects to draw static void InitFramework( Microsoft::WRL::ComPtr device, std::shared_ptr spriteBatch, HWND window) { logger.Log("Initialized"); ofDevice = device; ofSpriteBatch = spriteBatch; ofWindow = window; RECT hwndRect; GetClientRect(ofWindow, &hwndRect); ofWindowWidth = hwndRect.right - hwndRect.left; ofWindowHeight = hwndRect.bottom - hwndRect.top; } static int MapIntToRange( int number, int inputStart, int inputEnd, int outputStart, int outputEnd) { return outputStart + (outputEnd - outputStart) * (number - inputStart) / (inputEnd - inputStart); } static float MapFloatToRange( float number, float inputStart, float inputEnd, float outputStart, float outputEnd) { return outputStart + (outputEnd - outputStart) * (number - inputStart) / (inputEnd - inputStart); } static int LoadTexture(std::string filepath) { if (ofDevice.Get() == nullptr) { logger.Log("Could not load texture, ofDevice is nullptr! Run InitFramework before attempting to load textures!"); return -1; } if (ofTextures.size() == 0 && filepath != "blank") { if (LoadTexture("blank") != 0) { return -1; } } else if (filepath == "blank") { filepath = "hook_textures\\blank.jpg"; } logger.Log("Loading texture: %s", filepath.c_str()); std::wstring wideString(filepath.length(), ' '); std::copy(filepath.begin(), filepath.end(), wideString.begin()); std::fstream file = std::fstream(filepath); if (file.fail()) { logger.Log("Texture loading failed, file not found: %s", filepath.c_str()); file.close(); return -1; } file.close(); HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if (FAILED(hr)) { logger.Log("Error %#010x when initializing the COM library", hr); } else { logger.Log("Successfully initialized the COM library"); } Microsoft::WRL::ComPtr texture = nullptr; HRESULT texResult = DirectX::CreateWICTextureFromFile(ofDevice.Get(), wideString.c_str(), nullptr, texture.GetAddressOf()); _com_error texErr(texResult); logger.Log("Texture HRESULT: %s", texErr.ErrorMessage()); if (FAILED(texResult)) { logger.Log("Texture loading failed: %s", filepath.c_str()); return -1; } ofTextures.push_back(texture); return ofTextures.size() - 1; } static int LoadFont(std::string filepath) { if (ofDevice.Get() == nullptr) { logger.Log("Could not load font, ofDevice is nullptr! Run InitFramework before attempting to load fonts!"); return -1; } logger.Log("Loading font: %s", filepath.c_str()); std::fstream file = std::fstream(filepath); std::wstring wideString(filepath.length(), ' '); std::copy(filepath.begin(), filepath.end(), wideString.begin()); if (file.fail()) { logger.Log("Font loading failed: %s", filepath.c_str()); file.close(); return -1; } file.close(); logger.Log("Font was loaded successfully"); ofFonts.push_back(std::make_shared(ofDevice.Get(), wideString.c_str())); return ofFonts.size() - 1; } static void SetFont(int font) { if (font > ofFonts.size() - 1 || font < 0) { logger.Log("Attempted to set invalid font!"); return; } ofActiveFont = ofFonts[font]; } static void PlaceOnTop(Box* box) { static std::vector ofBoxOrder = std::vector(); size_t boxIndex = 0; for (size_t i = 0; i < ofBoxes.size(); i++) { if (ofBoxes[i] == box) { boxIndex = i; break; } } ofBoxOrder.push_back(boxIndex); for (size_t i = 0; i < ofBoxOrder.size() - 1; i++) { if (ofBoxes[ofBoxOrder[i]] == ofBoxes[ofBoxOrder.back()]) { ofBoxOrder.erase(ofBoxOrder.begin() + i); } } for (float i = 0; i < ofBoxOrder.size(); i++) { ofBoxes[ofBoxOrder[i]]->z = 1.0f / (1 + (i / 1000)); } } static POINT GetAbsolutePosition(Box* box) { if (box == nullptr) { return { 0, 0 }; } POINT absolutePosition = { box->x, box->y }; Box* parentBox = box->parentBox; while (parentBox != nullptr) { if (parentBox->parentBox == box) { break; } absolutePosition.x += parentBox->x; absolutePosition.y += parentBox->y; parentBox = parentBox->parentBox; } return absolutePosition; } static Box* CreateBox(Box* parentBox, int x, int y, int width, int height) { Box* box = new Box; box->x = x; box->y = y; box->width = width; box->height = height; box->parentBox = parentBox; if (parentBox != nullptr) { box->draggable = false; } ofBoxes.push_back(box); PlaceOnTop(box); return ofBoxes.back(); } static Box* CreateBox(int x, int y, int width, int height) { return CreateBox(nullptr, x, y, width, height); } static void _DrawBox(Box* box, DirectX::XMVECTOR color, int textureID) { static bool ofFailedToLoadBlank = false; if (box == nullptr) { logger.Log("Attempted to render a nullptr Box!"); return; } if (ofSpriteBatch == nullptr) { logger.Log("Attempted to render with ofSpriteBatch as nullptr! Run InitFramework before attempting to draw!"); return; } if (ofTextures.size() < 1) { if (ofFailedToLoadBlank == false) { if (LoadTexture("blank") != 0) { ofFailedToLoadBlank = true; return; } } else { return; } } if (textureID < 0 || textureID > ofTextures.size() - 1) { logger.Log("'%i' is an invalid texture ID!", textureID); return; } POINT position = GetAbsolutePosition(box); RECT rect; rect.top = position.y; rect.left = position.x; rect.bottom = position.y + box->height; rect.right = position.x + box->width; box->hasBeenRendered = true; ofSpriteBatch->Draw(ofTextures[textureID].Get(), rect, nullptr, color, 0.0f, DirectX::XMFLOAT2(0.0f, 0.0f), DirectX::SpriteEffects_None, box->z); } static void DrawBox(Box* box, int textureID) { _DrawBox(box, { 1.0f, 1.0f, 1.0f, 1.0f }, textureID); } static void DrawBox(Box* box, int r, int g, int b, int a = 255) { float _r = MapFloatToRange((float)r, 0.0f, 255.0f, 0.0f, 1.0f); float _g = MapFloatToRange((float)g, 0.0f, 255.0f, 0.0f, 1.0f); float _b = MapFloatToRange((float)b, 0.0f, 255.0f, 0.0f, 1.0f); float _a = MapFloatToRange((float)a, 0.0f, 255.0f, 0.0f, 1.0f); _DrawBox(box, { _r, _g, _b, _a }, 0); } static void DrawText( Box* box, std::string text, int offsetX = 0, int offsetY = 0, float scale = 1.0f, int r = 255, int g = 255, int b = 255, int a = 255, float rotation = 0.0f) { if (ofActiveFont == nullptr) { logger.Log("Attempted to render text with an invalid font, make sure to run SetFont first!"); return; } POINT position = GetAbsolutePosition(box); DirectX::XMFLOAT2 textPos = DirectX::XMFLOAT2 ( position.x + offsetX, position.y + offsetY ); float _r = MapFloatToRange((float)r, 0.0f, 255.0f, 0.0f, 1.0f); float _g = MapFloatToRange((float)g, 0.0f, 255.0f, 0.0f, 1.0f); float _b = MapFloatToRange((float)b, 0.0f, 255.0f, 0.0f, 1.0f); float _a = MapFloatToRange((float)a, 0.0f, 255.0f, 0.0f, 1.0f); ofActiveFont->DrawString( ofSpriteBatch.get(), text.c_str(), textPos, { _r, _g, _b, _a }, rotation, { 0.0f, 0.0f }, scale, DirectX::SpriteEffects_None, box->z); } static bool IsCursorInsideBox(POINT cursorPos, Box* box) { POINT position = GetAbsolutePosition(box); POINT boxSize = { box->width, box->height }; if (cursorPos.x < (position.x + boxSize.x) && cursorPos.x > position.x) { if (cursorPos.y < (position.y + boxSize.y) && cursorPos.y > position.y) { return true; } } return false; } static bool CheckHotkey(unsigned char key, unsigned char modifier = UNBOUND) { static std::vector notReleasedKeys; if (ofWindow != GetForegroundWindow()) { return false; } bool keyPressed = GetAsyncKeyState(key) & 0x8000; bool modifierPressed = GetAsyncKeyState(modifier) & 0x8000; if (key == UNBOUND) { return modifierPressed; } auto iterator = std::find(notReleasedKeys.begin(), notReleasedKeys.end(), key); bool keyNotReleased = iterator != notReleasedKeys.end(); if (keyPressed && keyNotReleased) { return false; } if(!keyPressed) { if (keyNotReleased) { notReleasedKeys.erase(iterator); } return false; } if (modifier != UNBOUND && !modifierPressed) { return false; } notReleasedKeys.push_back(key); return true; } static void CheckMouseEvents() { static int ofMouseX = 0, ofMouseY = 0; static int ofDeltaMouseX = 0, ofDeltaMouseY = 0; static bool ofMousePressed = false; static Box* ofClickedBox = nullptr; if (ofWindow == GetForegroundWindow()) { POINT cursorPos; GetCursorPos(&cursorPos); ScreenToClient(ofWindow, &cursorPos); ofDeltaMouseX = ofMouseX; ofDeltaMouseY = ofMouseY; ofMouseX = cursorPos.x; ofMouseY = cursorPos.y; ofDeltaMouseX = ofDeltaMouseX - ofMouseX; ofDeltaMouseY = ofDeltaMouseY - ofMouseY; if (ofClickedBox != nullptr) { if (ofClickedBox->clicked) { ofClickedBox->clicked = false; ofClickedBox = nullptr; } } Box* topMostBox = nullptr; for (size_t i = 0; i < ofBoxes.size(); i++) { Box* box = ofBoxes[i]; box->hover = false; if (!box->hasBeenRendered) { continue; } if (IsCursorInsideBox(cursorPos, box)) { if (topMostBox == nullptr || box->z < topMostBox->z) { topMostBox = box; } } } if (topMostBox != nullptr) { topMostBox->hover = true; } if (GetAsyncKeyState(VK_LBUTTON) & 0x8000) { ofMousePressed = true; if (topMostBox != nullptr) { ofClickedBox = topMostBox; ofClickedBox->pressed = true; } if (ofClickedBox != nullptr && ofClickedBox->draggable) { ofClickedBox->x -= ofDeltaMouseX; ofClickedBox->y -= ofDeltaMouseY; } } else { ofMousePressed = false; if (ofClickedBox != nullptr && IsCursorInsideBox(cursorPos, ofClickedBox)) { if (ofClickedBox->parentBox != nullptr) { PlaceOnTop(ofClickedBox->parentBox); for (size_t i = 0; i < ofBoxes.size(); i++) { if (ofClickedBox->parentBox == ofBoxes[i]->parentBox) { PlaceOnTop(ofBoxes[i]); } } } PlaceOnTop(ofClickedBox); for (size_t i = 0; i < ofBoxes.size(); i++) { if (ofBoxes[i]->parentBox == ofClickedBox) { PlaceOnTop(ofBoxes[i]); } } ofClickedBox->pressed = false; ofClickedBox->clicked = true; } } } for (auto box : ofBoxes) { box->hasBeenRendered = false; } } }; ================================================ FILE: include/Renderer.h ================================================ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ID3DRenderer.h" #include "IRenderCallback.h" #include "Logger.h" // D3D11 renderer with support for D3D12 using D3D11On12 class Renderer : public ID3DRenderer { public: void OnPresent(IDXGISwapChain* pThis, UINT syncInterval, UINT flags); void OnResizeBuffers(IDXGISwapChain* pThis, UINT bufferCount, UINT width, UINT height, DXGI_FORMAT newFormat, UINT swapChainFlags); void SetDrawExampleTriangle(bool doDraw); void AddRenderCallback(IRenderCallback* object); void SetCommandQueue(ID3D12CommandQueue* commandQueue); void SetGetCommandQueueCallback(void (*callback)()); private: Logger logger{"Renderer"}; HWND window = 0; IRenderCallback* callbackObject = nullptr; void (*callbackGetCommandQueue)(); bool mustInitializeD3DResources = true; bool firstTimeInitPerformed = false; bool isDeviceRetrieved = false; bool isRunningD3D12 = false; bool getCommandQueueCalled = false; bool drawExamples = false; bool examplesLoaded = false; bool callbackInitialized = false; int windowWidth = 0; int windowHeight = 0; UINT bufferIndex = 0; UINT bufferCount = 0; Microsoft::WRL::ComPtr d3d12Device = nullptr; Microsoft::WRL::ComPtr d3d11Context = nullptr; Microsoft::WRL::ComPtr d3d11Device = nullptr; Microsoft::WRL::ComPtr commandQueue = nullptr; Microsoft::WRL::ComPtr d3d11On12Device = nullptr; std::vector> d3d12RenderTargets; std::vector> d3d11WrappedBackBuffers; std::vector> d3d11RenderTargetViews; Microsoft::WRL::ComPtr swapChain = nullptr; Microsoft::WRL::ComPtr swapChain3 = nullptr; std::shared_ptr spriteBatch = nullptr; std::shared_ptr exampleFont = nullptr; DXGI_SWAP_CHAIN_DESC swapChainDesc; D3D11_VIEWPORT viewport; // Load the shaders from disk at compile time into a string. const char* shaderData = { #include "Shaders.hlsl" }; Microsoft::WRL::ComPtr vertexBuffer = nullptr; Microsoft::WRL::ComPtr indexBuffer = nullptr; Microsoft::WRL::ComPtr vertexShader = nullptr; Microsoft::WRL::ComPtr pixelShaderTextures = nullptr; Microsoft::WRL::ComPtr pixelShader = nullptr; Microsoft::WRL::ComPtr inputLayout = nullptr; Microsoft::WRL::ComPtr samplerState = nullptr; Microsoft::WRL::ComPtr constantBuffer = nullptr; Microsoft::WRL::ComPtr rasterizerState = nullptr; Microsoft::WRL::ComPtr depthStencilState = nullptr; Microsoft::WRL::ComPtr depthStencilBuffer = nullptr; Microsoft::WRL::ComPtr depthStencilView = nullptr; DirectX::XMVECTOR trianglePos = { 0.0f, 0.0f, -5.0f }; DirectX::XMFLOAT3 triangleScale = DirectX::XMFLOAT3(0.7f, 0.7f, 0.7f); DirectX::XMFLOAT3 triangleNdc = DirectX::XMFLOAT3(0.0f, 0.0f, 0.0f); unsigned int triangleNumIndices = 0; float triangleSpeed = 0.003f; float triangleVelX = triangleSpeed; float triangleVelY = -triangleSpeed; float triangleRotX = 0; float triangleRotY = 0; float triangleRotZ = 0; float triangleCounter = 0; struct Vertex { DirectX::XMFLOAT3 pos; DirectX::XMFLOAT4 color; DirectX::XMFLOAT2 texCoord; }; struct ConstantBufferData { DirectX::XMMATRIX wvp = DirectX::XMMatrixIdentity(); } constantBufferData; bool InitD3DResources(IDXGISwapChain* swapChain); bool RetrieveD3DDeviceFromSwapChain(); void GetSwapChainDescription(); void GetBufferCount(); void GetSwapchainWindowInfo(); void CreateViewport(); void InitD3D(); void InitD3D11(); void CreateD3D11Context(); void CreateSpriteBatch(); void CreateD3D11RenderTargetView(); void InitD3D12(); void CreateD3D11On12Device(); void CreateD3D12Buffers(); Microsoft::WRL::ComPtr CreateD3D12RtvHeap(); void CreateD3D12RenderTargetView(UINT bufferIndex, D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle); void CreateD3D11WrappedBackBuffer(UINT bufferIndex); void CreateD3D11RenderTargetViewWithWrappedBackBuffer(UINT bufferIndex); bool WaitForCommandQueueIfRunningD3D12(); void Render(); void PreRender(); void RenderCallbacks(); void PostRender(); void CreatePipeline(); Microsoft::WRL::ComPtr LoadShader(const char* shaderData, std::string targetShaderVersion, std::string shaderEntry); void CreateExampleTriangle(); void CreateExampleFont(); void DrawExampleTriangle(); void DrawExampleText(); void ReleaseViewsBuffersAndContext(); bool CheckSuccess(HRESULT hr); }; ================================================ FILE: include/UniversalProxyDLL.h ================================================ #pragma once #include #include #include #include #include #include #include #include // The DLL will crash with incremental linking enabled for some reason. // This linker comment will override any other project setting. #pragma comment(linker, "/INCREMENTAL:NO") extern std::vector forwardAddresses; extern std::vector forwardOrdinalAddresses; extern std::vector forwardSharedAddresses; #define SharedExportIndex_DllCanUnloadNow 0 #define SharedExportIndex_DllGetClassObject 1 #define SharedExportIndex_SetAppCompatStringPointer 2 namespace UPD { struct ExportData { std::string name = "N/A"; WORD ordinal = 0; uintptr_t relativeAddress = 0; uintptr_t asmCodeAddress = 0; void* forwardFunctionAddress = nullptr; }; struct Callback { uintptr_t callbackAddress = 0; uintptr_t returnAddress = 0; }; std::map sharedExports = { { "DllCanUnloadNow", SharedExportIndex_DllCanUnloadNow }, { "DllGetClassObject", SharedExportIndex_DllGetClassObject }, { "SetAppCompatStringPointer", SharedExportIndex_SetAppCompatStringPointer } }; // Global variables bool muteLogging = false; alignas(256) bool isProxyReady = false; std::ofstream logFile; std::vector managedExports; std::map callbacks; std::vector dllMemory; PIMAGE_SECTION_HEADER sectionHeadersBase = 0; WORD numSections = 0; // Function prototypes void* RegisterCallback(std::string exportName, void* callback); void CreateProxy(HMODULE dllToProxy, std::string specificPathToSearch); std::string GetModuleFileNameFromModuleHandle(HMODULE handle); std::string FindOriginalDLL(std::string dllFileName, std::string specificPathToSearch); std::string SearchForDLLInSpecificPath(std::string dllFileName, std::string specificPath); std::string SearchForDLLUsingStandardSearchOrder(std::string dllFileName); std::string SearchForDLLInCurrentFolder(std::string dllFileName); std::string SearchForDLLInSystemFolder(std::string dllFileName); bool DoesFileExist(std::string filePath); std::vector LoadFileToVectorOfBytes(std::string filePath); void ReadRequiredDataFromDLLExportTable(std::string dllFilePath); PIMAGE_DOS_HEADER GetDLLDosHeader(void* peHeaderBase); PIMAGE_NT_HEADERS GetDLLNtHeaders(PIMAGE_DOS_HEADER dosHeader); void SetSectionHeadersInfo(PIMAGE_FILE_HEADER fileHeader, PIMAGE_OPTIONAL_HEADER optionalHeader); PIMAGE_EXPORT_DIRECTORY GetExportDirectory(PIMAGE_OPTIONAL_HEADER optionalHeader); uintptr_t RvaToRawAddress(DWORD rva); void PrepareForwardFunctionsWithJumpsToAsm(); uintptr_t CreateMemoryWithAssemblyForwardingCode(); std::vector GetAsmForwardingCode32(); std::vector GetAsmForwardingCode64(); void StartProxyCreationThread(std::string originalDllPath); DWORD WINAPI ThreadCreateProxy(LPVOID lpParam); void InjectFunctionAddressesIntoAsmForwardingCode(HMODULE module); void InjectFunctionAddresses32(HMODULE module); void InjectFunctionAddresses64(HMODULE module); void MemCopy(uintptr_t destination, uintptr_t source, size_t numBytes); void MemSet(uintptr_t address, unsigned char byte, size_t numBytes); void ToggleMemoryProtection(bool enableProtection, uintptr_t address, size_t size); void Hook(uintptr_t address, uintptr_t destination, size_t extraClearance = 0); void Hook32(uintptr_t address, uintptr_t destination, size_t clearance); void Hook64(uintptr_t address, uintptr_t destination, size_t clearance); int32_t CalculateDisplacementForRelativeJump(uintptr_t relativeJumpAddress, uintptr_t destinationAddress); void LogAndThrow(std::string exceptionMessage); template void Log(Types... args); template std::string NumberToHexString(T number); void* RegisterCallback(std::string exportName, void* callback) { if (callback != nullptr) { callbacks[exportName].callbackAddress = (uintptr_t)callback; Log("Registered callback: ", exportName); return &callbacks[exportName].returnAddress; } return nullptr; } void CreateProxy(HMODULE dllToProxy, std::string specificPathToSearch = "") { std::string dllToProxyFileName = GetModuleFileNameFromModuleHandle(dllToProxy); std::string dllFilePath = FindOriginalDLL(dllToProxyFileName, specificPathToSearch); dllMemory = LoadFileToVectorOfBytes(dllFilePath); ReadRequiredDataFromDLLExportTable(dllFilePath); PrepareForwardFunctionsWithJumpsToAsm(); StartProxyCreationThread(dllFilePath); } std::string GetModuleFileNameFromModuleHandle(HMODULE handle) { std::string moduleFileName = ""; char lpFilename[MAX_PATH]; GetModuleFileNameA(handle, lpFilename, sizeof(lpFilename)); char* lastSlashPos = strrchr(lpFilename, '\\'); if (lastSlashPos != nullptr) { moduleFileName = lastSlashPos; moduleFileName = moduleFileName.substr(1, moduleFileName.length()); } Log("Module name: ", moduleFileName.c_str()); if (moduleFileName == "") { LogAndThrow("Could not get module name from module handle"); } return moduleFileName; } std::string FindOriginalDLL(std::string dllFileName, std::string specificPathToSearch = "") { std::string dllPath = ""; if (specificPathToSearch != "") { dllPath = SearchForDLLInSpecificPath(dllFileName, specificPathToSearch); } if (dllPath == "") { dllPath = SearchForDLLUsingStandardSearchOrder(dllFileName); } if (dllPath == "") { LogAndThrow("Could not find DLL to proxy"); } Log("DLL found: ", dllPath); return dllPath; } std::string SearchForDLLInSpecificPath(std::string dllFileName, std::string specificPath) { std::string dllPath = specificPath + "\\" + dllFileName; if (!DoesFileExist(dllPath)) { return ""; } return dllPath; } std::string SearchForDLLUsingStandardSearchOrder(std::string dllFileName) { std::string dllPath = SearchForDLLInCurrentFolder("_" + dllFileName); if (dllPath == "") { dllPath = SearchForDLLInSystemFolder(dllFileName); } return dllPath; } std::string SearchForDLLInCurrentFolder(std::string dllFileName) { std::string dllPath = ".\\" + dllFileName; if (!DoesFileExist(dllPath)) { return ""; } return dllPath; } std::string SearchForDLLInSystemFolder(std::string dllFileName) { char lpBuffer[MAX_PATH]; UINT pathLength = GetSystemDirectoryA(lpBuffer, sizeof(lpBuffer)); std::string systemFolderPath = lpBuffer; std::string dllPath = systemFolderPath + "\\" + dllFileName; if (!DoesFileExist(dllPath)) { return ""; } return dllPath; } bool DoesFileExist(std::string filePath) { std::ifstream file(filePath); if (file.is_open()) { return true; } return false; } std::vector LoadFileToVectorOfBytes(std::string filePath) { std::ifstream file; file.open(filePath, std::ios::in | std::ios::binary); if (!file.is_open()) { LogAndThrow("Failed to read DLL: " + filePath); } return std::vector(std::istreambuf_iterator(file), std::istreambuf_iterator()); } void ReadRequiredDataFromDLLExportTable(std::string dllFilePath) { void* peHeaderBase = &dllMemory[0]; PIMAGE_DOS_HEADER dosHeader = GetDLLDosHeader(peHeaderBase); PIMAGE_NT_HEADERS ntHeaders = GetDLLNtHeaders(dosHeader); PIMAGE_OPTIONAL_HEADER optionalHeader = &ntHeaders->OptionalHeader; PIMAGE_FILE_HEADER fileHeader = &ntHeaders->FileHeader; SetSectionHeadersInfo(fileHeader, optionalHeader); PIMAGE_EXPORT_DIRECTORY exportDirectory = GetExportDirectory(optionalHeader); DWORD numberOfExports = exportDirectory->NumberOfFunctions; DWORD numberOfNamedExports = exportDirectory->NumberOfNames; Log("Number of exports: ", numberOfExports); uintptr_t tableOfRvaPointersToExportNames = RvaToRawAddress(exportDirectory->AddressOfNames); uintptr_t tableOfNameOrdinals = RvaToRawAddress(exportDirectory->AddressOfNameOrdinals); uintptr_t tableOfRvaPointersToExportAddresses = RvaToRawAddress(exportDirectory->AddressOfFunctions); std::map indicesOfNamePointersInOrdinalOrder; std::vector buffer(numberOfNamedExports, 0); MemCopy((uintptr_t)&buffer[0], (uintptr_t)tableOfNameOrdinals, numberOfNamedExports * sizeof(WORD)); for (WORD i = 0; i < numberOfExports; i++) { auto it = std::find(buffer.begin(), buffer.end(), i); if (it != buffer.end()) { WORD bufferIndex = (WORD)(it - buffer.begin()); indicesOfNamePointersInOrdinalOrder[i] = bufferIndex; } } for (WORD i = 0; i < numberOfExports; i++) { ExportData exportData; if (indicesOfNamePointersInOrdinalOrder.find(i) != indicesOfNamePointersInOrdinalOrder.end()) { DWORD* exportNameAddress = ((DWORD*)tableOfRvaPointersToExportNames + indicesOfNamePointersInOrdinalOrder[i]); exportData.name = (char*)RvaToRawAddress(*exportNameAddress); } exportData.ordinal = (WORD)exportDirectory->Base + i; exportData.relativeAddress = *((DWORD*)tableOfRvaPointersToExportAddresses + i); Log("Export name: ", exportData.name); Log("Export ordinal: ", exportData.ordinal); Log("Export RVA: ", NumberToHexString(exportData.relativeAddress)); bool exportIsUnnamed = exportData.name == "N/A"; bool exportIsShared = sharedExports.find(exportData.name) != sharedExports.end(); if (exportIsUnnamed) { exportData.forwardFunctionAddress = forwardOrdinalAddresses[exportData.ordinal - 1]; } else if (exportIsShared) { exportData.forwardFunctionAddress = forwardSharedAddresses[sharedExports[exportData.name]]; } else { exportData.forwardFunctionAddress = forwardAddresses[i]; } managedExports.push_back(exportData); } } PIMAGE_DOS_HEADER GetDLLDosHeader(void* peHeaderBase) { PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)peHeaderBase; if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) { LogAndThrow("Incorrect DOS signature"); } return dosHeader; } PIMAGE_NT_HEADERS GetDLLNtHeaders(PIMAGE_DOS_HEADER dosHeader) { PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((unsigned char*)dosHeader + dosHeader->e_lfanew); if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) { LogAndThrow("Incorrect NT signature"); } return ntHeaders; } void SetSectionHeadersInfo(PIMAGE_FILE_HEADER fileHeader, PIMAGE_OPTIONAL_HEADER optionalHeader) { DWORD sizeOfOptionalHeader = fileHeader->SizeOfOptionalHeader; sectionHeadersBase = (PIMAGE_SECTION_HEADER)((unsigned char*)optionalHeader + sizeOfOptionalHeader); numSections = fileHeader->NumberOfSections; } PIMAGE_EXPORT_DIRECTORY GetExportDirectory(PIMAGE_OPTIONAL_HEADER optionalHeader) { PIMAGE_DATA_DIRECTORY exportDataDirectory = &(optionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]); PIMAGE_EXPORT_DIRECTORY exportDirectory = (PIMAGE_EXPORT_DIRECTORY)RvaToRawAddress(exportDataDirectory->VirtualAddress); return exportDirectory; } uintptr_t RvaToRawAddress(DWORD rva) { for (DWORD i = 0; i < numSections; i++) { PIMAGE_SECTION_HEADER section = sectionHeadersBase + i; DWORD sectionVirtualBegin = section->VirtualAddress; DWORD sectionVirtualEnd = section->VirtualAddress + section->Misc.VirtualSize; bool isWithinSection = rva >= sectionVirtualBegin && rva <= sectionVirtualEnd; if (isWithinSection) { uintptr_t moduleBaseAddress = (uintptr_t)&dllMemory[0]; uintptr_t rawAddress = (uintptr_t)((section->PointerToRawData + (rva - section->VirtualAddress)) + moduleBaseAddress); return rawAddress; } } LogAndThrow("Could not convert RVA to raw address"); return 0; } void PrepareForwardFunctionsWithJumpsToAsm() { for (auto& managedExport : managedExports) { managedExport.asmCodeAddress = CreateMemoryWithAssemblyForwardingCode(); Hook((uintptr_t)managedExport.forwardFunctionAddress, managedExport.asmCodeAddress); bool exportIsNamed = managedExport.name != "N/A"; if (exportIsNamed) { Hook((uintptr_t)forwardOrdinalAddresses[managedExport.ordinal - 1], managedExport.asmCodeAddress); } Log("Prepared forward function ", NumberToHexString((uintptr_t)managedExport.forwardFunctionAddress)); } } uintptr_t CreateMemoryWithAssemblyForwardingCode() { std::vector asmBytes; size_t asmOffsetOfBoolAddress = 0; #ifndef _WIN64 asmBytes = GetAsmForwardingCode32(); asmOffsetOfBoolAddress = 1; #else asmBytes = GetAsmForwardingCode64(); asmOffsetOfBoolAddress = 2; #endif void* pointerToBool = &isProxyReady; MemCopy((uintptr_t)&asmBytes[asmOffsetOfBoolAddress], (uintptr_t)&pointerToBool, sizeof(uintptr_t)); uintptr_t memoryAddress = (uintptr_t)VirtualAlloc(NULL, asmBytes.size(), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (memoryAddress == NULL) { LogAndThrow("Failed to allocate memory"); } MemCopy((uintptr_t)memoryAddress, (uintptr_t)&asmBytes[0], asmBytes.size()); Log("Created assembly forwarding code at ", NumberToHexString(memoryAddress)); return memoryAddress; } std::vector GetAsmForwardingCode32() { std::vector asmBytes = { 0xb8, 0x00, 0x00, 0x00, 0x00, // mov eax,isProxyReady 0x38, 0x00, // cmp [eax],al 0x74, 0x05, // je // : 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp funcAddr // : 0xf3, 0x90, // pause 0xf0, 0x00, 0x00, // lock add [eax],al 0x74, 0xf9, // je 0xe9, 0xef, 0xff, 0xff, 0xff // jmp }; return asmBytes; } std::vector GetAsmForwardingCode64() { std::vector asmBytes = { // Courtesy of my buddy Dasaav 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rax,isProxyReady 0x38, 0x00, // cmp [rax],al 0x74, 0x06, // je 0xff, 0x25, 0x0d, 0x00, 0x00, 0x00, // jmp qword ptr [funcAddr] // : 0xf3, 0x90, // pause 0xf0, 0x00, 0x00, // lock add [rax],al 0x74, 0xf9, // je 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // jmp funcAddr }; return asmBytes; } void StartProxyCreationThread(std::string originalDllPath) { // Thread will run only after DllMain is finished! // This is enforced by the DLL loader. This means any calls to LoadLibrary, etc. is safe. std::string* dllPath = new std::string(originalDllPath); CreateThread(0, 0, &ThreadCreateProxy, dllPath, 0, NULL); } DWORD WINAPI ThreadCreateProxy(LPVOID lpParam) { Log("Starting proxy creation thread..."); std::string dllPath = *(std::string*)lpParam; delete (std::string*)lpParam; HMODULE originalDll = LoadLibraryA(dllPath.c_str()); if (!originalDll) { LogAndThrow("LoadLibrary call for original DLL failed!"); } Log("Module base address: ", NumberToHexString(originalDll)); InjectFunctionAddressesIntoAsmForwardingCode(originalDll); // We have created/modified instructions, flush the CPU instruction cache just in case FlushInstructionCache(GetCurrentProcess(), NULL, NULL); isProxyReady = true; Log("Proxy creation finished"); return 0; } void InjectFunctionAddressesIntoAsmForwardingCode(HMODULE module) { #ifndef _WIN64 InjectFunctionAddresses32(module); #else InjectFunctionAddresses64(module); #endif } void InjectFunctionAddresses32(HMODULE module) { const size_t asmOffsetOfJmpAddr = 10; for (auto& managedExport : managedExports) { uintptr_t exportAbsoluteAddress = (uintptr_t)module + managedExport.relativeAddress; uintptr_t jumpTargetAddress = exportAbsoluteAddress; Log("Export absolute address: ", NumberToHexString(exportAbsoluteAddress)); bool isCallbackRegistered = callbacks.find(managedExport.name) != callbacks.end(); if (isCallbackRegistered) { auto& callback = callbacks[managedExport.name]; callback.returnAddress = exportAbsoluteAddress; jumpTargetAddress = callback.callbackAddress; Log("Added callback in ", managedExport.name, " to ", NumberToHexString(callback.callbackAddress)); } int32_t relativeDisplacement = CalculateDisplacementForRelativeJump(managedExport.asmCodeAddress + asmOffsetOfJmpAddr - 1, jumpTargetAddress); MemCopy(managedExport.asmCodeAddress + asmOffsetOfJmpAddr, (uintptr_t)&relativeDisplacement, sizeof(uintptr_t)); } } void InjectFunctionAddresses64(HMODULE module) { const size_t asmOffsetOfJmpAddr = 33; for (auto& managedExport : managedExports) { uintptr_t exportAbsoluteAddress = (uintptr_t)module + managedExport.relativeAddress; uintptr_t jumpTargetAddress = exportAbsoluteAddress; Log("Export absolute address: ", NumberToHexString(exportAbsoluteAddress)); bool isCallbackRegistered = callbacks.find(managedExport.name) != callbacks.end(); if (isCallbackRegistered) { auto& callback = callbacks[managedExport.name]; callback.returnAddress = exportAbsoluteAddress; jumpTargetAddress = callback.callbackAddress; Log("Added callback in ", managedExport.name, " to ", NumberToHexString(callback.callbackAddress)); } MemCopy(managedExport.asmCodeAddress + asmOffsetOfJmpAddr, (uintptr_t)&jumpTargetAddress, sizeof(uintptr_t)); } } void Hook(uintptr_t address, uintptr_t destination, size_t extraClearance) { size_t clearance = 0; #ifndef _WIN64 clearance = 5 + extraClearance; Hook32(address, destination, extraClearance); #else clearance = 14 + extraClearance; Hook64(address, destination, extraClearance); #endif Log("Created jump from ", NumberToHexString(address), " to ", NumberToHexString(destination), " with a clearance of ", clearance); } void Hook32(uintptr_t address, uintptr_t destination, size_t clearance) { MemSet(address, 0x90, clearance); unsigned char jumpByte = 0xe9; MemCopy(address, (uintptr_t)&jumpByte, 1); int32_t relativeDisplacement = CalculateDisplacementForRelativeJump(address, destination); MemCopy(address + 1, (uintptr_t)&relativeDisplacement, sizeof(uintptr_t)); } void Hook64(uintptr_t address, uintptr_t destination, size_t clearance) { MemSet(address, 0x90, clearance); std::vector jumpBytes = { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }; MemCopy(address, (uintptr_t)&jumpBytes[0], jumpBytes.size()); MemCopy((address + 6), (uintptr_t)&destination, sizeof(uintptr_t)); } int32_t CalculateDisplacementForRelativeJump(uintptr_t relativeJumpAddress, uintptr_t destinationAddress) { const size_t sizeOfE9Jmp = 5; return -int32_t(relativeJumpAddress + sizeOfE9Jmp - destinationAddress); } void MemCopy(uintptr_t destination, uintptr_t source, size_t numBytes) { ToggleMemoryProtection(false, destination, numBytes); ToggleMemoryProtection(false, source, numBytes); memcpy((void*)destination, (void*)source, numBytes); ToggleMemoryProtection(true, source, numBytes); ToggleMemoryProtection(true, destination, numBytes); } void MemSet(uintptr_t address, unsigned char byte, size_t numBytes) { ToggleMemoryProtection(false, address, numBytes); memset((void*)address, byte, numBytes); ToggleMemoryProtection(true, address, numBytes); } void ToggleMemoryProtection(bool enableProtection, uintptr_t address, size_t size) { static std::map protectionHistory; if (enableProtection && protectionHistory.find(address) != protectionHistory.end()) { VirtualProtect((void*)address, size, protectionHistory[address], &protectionHistory[address]); protectionHistory.erase(address); } else if (!enableProtection && protectionHistory.find(address) == protectionHistory.end()) { DWORD oldProtection = 0; VirtualProtect((void*)address, size, PAGE_EXECUTE_READWRITE, &oldProtection); protectionHistory[address] = oldProtection; } } void LogAndThrow(std::string exceptionMessage) { Log("UniversalProxyDLL > Exception thrown: ", exceptionMessage); throw std::runtime_error(exceptionMessage); } template void Log(Types... args) { if (muteLogging) { return; } if (!logFile.is_open()) { logFile.open("upd_log.txt"); } std::stringstream stream; stream << "UniversalProxyDLL > "; // Magic to fold variadic arguments prior to C++17 // https://stackoverflow.com/a/55717030 // If it doesn't work for you, switch to C++17 and replace the code block with: // (stream << ... << args) << std::endl; // std::cout << stream.str(); using do_ = int[]; do_{ 0, (stream << args, 0)... }; std::cout << stream.str() << std::endl; if (logFile.is_open()) { logFile << stream.str() << std::endl; logFile.flush(); } } template std::string NumberToHexString(T number) { std::stringstream stream; stream << std::setfill('0') << std::setw(sizeof(T) * 2) << std::hex << number; return stream.str(); } void MuteLogging(bool mute = true) { muteLogging = mute; } void OpenDebugTerminal() { if (AllocConsole()) { freopen_s((FILE**)stdout, "CONOUT$", "w", stdout); SetWindowText(GetConsoleWindow(), "UPD"); } } } // Macro hell begins! #define GenerateForwardFunction(N) extern "C" const char* Forward##N() { return("F"#N); } #define GenerateForwardOrdinalFunction(N) extern "C" const char* ForwardOrdinal##N() { return ("FO"#N); } #define GenerateForwardSharedFunction(N) extern "C" const char* ForwardShared##N() { return ("FS"#N); } GenerateForwardFunction(0) GenerateForwardFunction(1) GenerateForwardFunction(2) GenerateForwardFunction(3) GenerateForwardFunction(4) GenerateForwardFunction(5) GenerateForwardFunction(6) GenerateForwardFunction(7) GenerateForwardFunction(8) GenerateForwardFunction(9) GenerateForwardFunction(10) GenerateForwardFunction(11) GenerateForwardFunction(12) GenerateForwardFunction(13) GenerateForwardFunction(14) GenerateForwardFunction(15) GenerateForwardFunction(16) GenerateForwardFunction(17) GenerateForwardFunction(18) GenerateForwardFunction(19) GenerateForwardFunction(20) GenerateForwardFunction(21) GenerateForwardFunction(22) GenerateForwardFunction(23) GenerateForwardFunction(24) GenerateForwardFunction(25) GenerateForwardFunction(26) GenerateForwardFunction(27) GenerateForwardFunction(28) GenerateForwardFunction(29) GenerateForwardFunction(30) GenerateForwardFunction(31) GenerateForwardFunction(32) GenerateForwardFunction(33) GenerateForwardFunction(34) GenerateForwardFunction(35) GenerateForwardFunction(36) GenerateForwardFunction(37) GenerateForwardFunction(38) GenerateForwardFunction(39) GenerateForwardFunction(40) GenerateForwardFunction(41) GenerateForwardFunction(42) GenerateForwardFunction(43) GenerateForwardFunction(44) GenerateForwardFunction(45) GenerateForwardFunction(46) GenerateForwardFunction(47) GenerateForwardFunction(48) GenerateForwardFunction(49) GenerateForwardFunction(50) GenerateForwardFunction(51) GenerateForwardFunction(52) GenerateForwardFunction(53) GenerateForwardFunction(54) GenerateForwardFunction(55) GenerateForwardFunction(56) GenerateForwardFunction(57) GenerateForwardFunction(58) GenerateForwardFunction(59) GenerateForwardFunction(60) GenerateForwardFunction(61) GenerateForwardFunction(62) GenerateForwardFunction(63) GenerateForwardFunction(64) GenerateForwardFunction(65) GenerateForwardFunction(66) GenerateForwardFunction(67) GenerateForwardFunction(68) GenerateForwardFunction(69) GenerateForwardFunction(70) GenerateForwardFunction(71) GenerateForwardFunction(72) GenerateForwardFunction(73) GenerateForwardFunction(74) GenerateForwardFunction(75) GenerateForwardFunction(76) GenerateForwardFunction(77) GenerateForwardFunction(78) GenerateForwardFunction(79) GenerateForwardFunction(80) GenerateForwardFunction(81) GenerateForwardFunction(82) GenerateForwardFunction(83) GenerateForwardFunction(84) GenerateForwardFunction(85) GenerateForwardFunction(86) GenerateForwardFunction(87) GenerateForwardFunction(88) GenerateForwardFunction(89) GenerateForwardFunction(90) GenerateForwardFunction(91) GenerateForwardFunction(92) GenerateForwardFunction(93) GenerateForwardFunction(94) GenerateForwardFunction(95) GenerateForwardFunction(96) GenerateForwardFunction(97) GenerateForwardFunction(98) GenerateForwardFunction(99) GenerateForwardFunction(100) GenerateForwardFunction(101) GenerateForwardFunction(102) GenerateForwardFunction(103) GenerateForwardFunction(104) GenerateForwardFunction(105) GenerateForwardFunction(106) GenerateForwardFunction(107) GenerateForwardFunction(108) GenerateForwardFunction(109) GenerateForwardFunction(110) GenerateForwardFunction(111) GenerateForwardFunction(112) GenerateForwardFunction(113) GenerateForwardFunction(114) GenerateForwardFunction(115) GenerateForwardFunction(116) GenerateForwardFunction(117) GenerateForwardFunction(118) GenerateForwardFunction(119) GenerateForwardFunction(120) GenerateForwardFunction(121) GenerateForwardFunction(122) GenerateForwardFunction(123) GenerateForwardFunction(124) GenerateForwardFunction(125) GenerateForwardFunction(126) GenerateForwardFunction(127) GenerateForwardFunction(128) GenerateForwardFunction(129) GenerateForwardFunction(130) GenerateForwardFunction(131) GenerateForwardFunction(132) GenerateForwardFunction(133) GenerateForwardFunction(134) GenerateForwardFunction(135) GenerateForwardFunction(136) GenerateForwardFunction(137) GenerateForwardFunction(138) GenerateForwardFunction(139) GenerateForwardFunction(140) GenerateForwardFunction(141) GenerateForwardFunction(142) GenerateForwardFunction(143) GenerateForwardFunction(144) GenerateForwardFunction(145) GenerateForwardFunction(146) GenerateForwardFunction(147) GenerateForwardFunction(148) GenerateForwardFunction(149) GenerateForwardFunction(150) GenerateForwardFunction(151) GenerateForwardFunction(152) GenerateForwardFunction(153) GenerateForwardFunction(154) GenerateForwardFunction(155) GenerateForwardFunction(156) GenerateForwardFunction(157) GenerateForwardFunction(158) GenerateForwardFunction(159) GenerateForwardFunction(160) GenerateForwardFunction(161) GenerateForwardFunction(162) GenerateForwardFunction(163) GenerateForwardFunction(164) GenerateForwardFunction(165) GenerateForwardFunction(166) GenerateForwardFunction(167) GenerateForwardFunction(168) GenerateForwardFunction(169) GenerateForwardFunction(170) GenerateForwardFunction(171) GenerateForwardFunction(172) GenerateForwardFunction(173) GenerateForwardFunction(174) GenerateForwardFunction(175) GenerateForwardFunction(176) GenerateForwardFunction(177) GenerateForwardFunction(178) GenerateForwardFunction(179) GenerateForwardFunction(180) GenerateForwardFunction(181) GenerateForwardFunction(182) GenerateForwardFunction(183) GenerateForwardFunction(184) GenerateForwardFunction(185) GenerateForwardFunction(186) GenerateForwardFunction(187) GenerateForwardFunction(188) GenerateForwardFunction(189) GenerateForwardFunction(190) GenerateForwardFunction(191) GenerateForwardFunction(192) GenerateForwardFunction(193) GenerateForwardFunction(194) GenerateForwardFunction(195) GenerateForwardFunction(196) GenerateForwardFunction(197) GenerateForwardFunction(198) GenerateForwardFunction(199) GenerateForwardFunction(200) GenerateForwardFunction(201) GenerateForwardFunction(202) GenerateForwardFunction(203) GenerateForwardFunction(204) GenerateForwardFunction(205) GenerateForwardFunction(206) GenerateForwardFunction(207) GenerateForwardFunction(208) GenerateForwardFunction(209) GenerateForwardFunction(210) GenerateForwardFunction(211) GenerateForwardFunction(212) GenerateForwardFunction(213) GenerateForwardFunction(214) GenerateForwardFunction(215) GenerateForwardFunction(216) GenerateForwardFunction(217) GenerateForwardFunction(218) GenerateForwardFunction(219) GenerateForwardFunction(220) GenerateForwardFunction(221) GenerateForwardFunction(222) GenerateForwardFunction(223) GenerateForwardFunction(224) GenerateForwardFunction(225) GenerateForwardFunction(226) GenerateForwardFunction(227) GenerateForwardFunction(228) GenerateForwardFunction(229) GenerateForwardFunction(230) GenerateForwardFunction(231) GenerateForwardFunction(232) GenerateForwardFunction(233) GenerateForwardFunction(234) GenerateForwardFunction(235) GenerateForwardFunction(236) GenerateForwardFunction(237) GenerateForwardFunction(238) GenerateForwardFunction(239) GenerateForwardFunction(240) GenerateForwardFunction(241) GenerateForwardFunction(242) GenerateForwardFunction(243) GenerateForwardFunction(244) GenerateForwardFunction(245) GenerateForwardFunction(246) GenerateForwardFunction(247) GenerateForwardFunction(248) GenerateForwardFunction(249) GenerateForwardFunction(250) GenerateForwardFunction(251) GenerateForwardFunction(252) GenerateForwardFunction(253) GenerateForwardFunction(254) GenerateForwardFunction(255) GenerateForwardFunction(256) GenerateForwardFunction(257) GenerateForwardFunction(258) GenerateForwardFunction(259) GenerateForwardFunction(260) GenerateForwardFunction(261) GenerateForwardFunction(262) GenerateForwardFunction(263) GenerateForwardFunction(264) GenerateForwardFunction(265) GenerateForwardFunction(266) GenerateForwardFunction(267) GenerateForwardFunction(268) GenerateForwardFunction(269) GenerateForwardFunction(270) GenerateForwardFunction(271) GenerateForwardFunction(272) GenerateForwardFunction(273) GenerateForwardFunction(274) GenerateForwardFunction(275) GenerateForwardFunction(276) GenerateForwardFunction(277) GenerateForwardFunction(278) GenerateForwardFunction(279) GenerateForwardFunction(280) GenerateForwardFunction(281) GenerateForwardFunction(282) GenerateForwardFunction(283) GenerateForwardFunction(284) GenerateForwardFunction(285) GenerateForwardFunction(286) GenerateForwardFunction(287) GenerateForwardFunction(288) GenerateForwardFunction(289) GenerateForwardFunction(290) GenerateForwardFunction(291) GenerateForwardFunction(292) GenerateForwardFunction(293) GenerateForwardFunction(294) GenerateForwardFunction(295) GenerateForwardFunction(296) GenerateForwardFunction(297) GenerateForwardFunction(298) GenerateForwardFunction(299) GenerateForwardFunction(300) GenerateForwardFunction(301) GenerateForwardFunction(302) GenerateForwardFunction(303) GenerateForwardFunction(304) GenerateForwardFunction(305) GenerateForwardFunction(306) GenerateForwardFunction(307) GenerateForwardFunction(308) GenerateForwardFunction(309) GenerateForwardFunction(310) GenerateForwardFunction(311) GenerateForwardFunction(312) GenerateForwardFunction(313) GenerateForwardFunction(314) GenerateForwardFunction(315) GenerateForwardFunction(316) GenerateForwardFunction(317) GenerateForwardFunction(318) GenerateForwardFunction(319) GenerateForwardFunction(320) GenerateForwardFunction(321) GenerateForwardFunction(322) GenerateForwardFunction(323) GenerateForwardFunction(324) GenerateForwardFunction(325) GenerateForwardFunction(326) GenerateForwardFunction(327) GenerateForwardFunction(328) GenerateForwardFunction(329) GenerateForwardFunction(330) GenerateForwardFunction(331) GenerateForwardFunction(332) GenerateForwardFunction(333) GenerateForwardFunction(334) GenerateForwardFunction(335) GenerateForwardFunction(336) GenerateForwardFunction(337) GenerateForwardFunction(338) GenerateForwardFunction(339) GenerateForwardFunction(340) GenerateForwardFunction(341) GenerateForwardFunction(342) GenerateForwardFunction(343) GenerateForwardFunction(344) GenerateForwardFunction(345) GenerateForwardFunction(346) GenerateForwardFunction(347) GenerateForwardFunction(348) GenerateForwardFunction(349) GenerateForwardFunction(350) GenerateForwardFunction(351) GenerateForwardFunction(352) GenerateForwardFunction(353) GenerateForwardFunction(354) GenerateForwardFunction(355) GenerateForwardFunction(356) GenerateForwardFunction(357) GenerateForwardFunction(358) GenerateForwardFunction(359) GenerateForwardFunction(360) GenerateForwardFunction(361) GenerateForwardFunction(362) GenerateForwardFunction(363) GenerateForwardFunction(364) GenerateForwardFunction(365) GenerateForwardFunction(366) GenerateForwardFunction(367) GenerateForwardFunction(368) GenerateForwardFunction(369) GenerateForwardFunction(370) GenerateForwardFunction(371) GenerateForwardFunction(372) GenerateForwardFunction(373) GenerateForwardFunction(374) GenerateForwardFunction(375) GenerateForwardFunction(376) GenerateForwardFunction(377) GenerateForwardFunction(378) GenerateForwardFunction(379) GenerateForwardFunction(380) GenerateForwardFunction(381) GenerateForwardFunction(382) GenerateForwardFunction(383) GenerateForwardFunction(384) GenerateForwardFunction(385) GenerateForwardFunction(386) GenerateForwardFunction(387) GenerateForwardFunction(388) GenerateForwardFunction(389) GenerateForwardFunction(390) GenerateForwardFunction(391) GenerateForwardFunction(392) GenerateForwardFunction(393) GenerateForwardFunction(394) GenerateForwardFunction(395) GenerateForwardFunction(396) GenerateForwardFunction(397) GenerateForwardFunction(398) GenerateForwardFunction(399) GenerateForwardFunction(400) GenerateForwardFunction(401) GenerateForwardFunction(402) GenerateForwardFunction(403) GenerateForwardFunction(404) GenerateForwardFunction(405) GenerateForwardFunction(406) GenerateForwardFunction(407) GenerateForwardFunction(408) GenerateForwardFunction(409) GenerateForwardFunction(410) GenerateForwardFunction(411) GenerateForwardFunction(412) GenerateForwardFunction(413) GenerateForwardFunction(414) GenerateForwardFunction(415) GenerateForwardFunction(416) GenerateForwardFunction(417) GenerateForwardFunction(418) GenerateForwardFunction(419) GenerateForwardFunction(420) GenerateForwardFunction(421) GenerateForwardFunction(422) GenerateForwardFunction(423) GenerateForwardFunction(424) GenerateForwardFunction(425) GenerateForwardFunction(426) GenerateForwardFunction(427) GenerateForwardFunction(428) GenerateForwardFunction(429) GenerateForwardFunction(430) GenerateForwardFunction(431) GenerateForwardFunction(432) GenerateForwardFunction(433) GenerateForwardFunction(434) GenerateForwardFunction(435) GenerateForwardFunction(436) GenerateForwardFunction(437) GenerateForwardFunction(438) GenerateForwardFunction(439) GenerateForwardFunction(440) GenerateForwardFunction(441) GenerateForwardFunction(442) GenerateForwardFunction(443) GenerateForwardFunction(444) GenerateForwardFunction(445) GenerateForwardFunction(446) GenerateForwardFunction(447) GenerateForwardFunction(448) GenerateForwardFunction(449) GenerateForwardFunction(450) GenerateForwardFunction(451) GenerateForwardFunction(452) GenerateForwardFunction(453) GenerateForwardFunction(454) GenerateForwardFunction(455) GenerateForwardFunction(456) GenerateForwardFunction(457) GenerateForwardFunction(458) GenerateForwardFunction(459) GenerateForwardFunction(460) GenerateForwardFunction(461) GenerateForwardFunction(462) GenerateForwardFunction(463) GenerateForwardFunction(464) GenerateForwardFunction(465) GenerateForwardFunction(466) GenerateForwardFunction(467) GenerateForwardFunction(468) GenerateForwardFunction(469) GenerateForwardFunction(470) GenerateForwardFunction(471) GenerateForwardFunction(472) GenerateForwardFunction(473) GenerateForwardFunction(474) GenerateForwardFunction(475) GenerateForwardFunction(476) GenerateForwardFunction(477) GenerateForwardFunction(478) GenerateForwardFunction(479) GenerateForwardFunction(480) GenerateForwardFunction(481) GenerateForwardFunction(482) GenerateForwardFunction(483) GenerateForwardFunction(484) GenerateForwardFunction(485) GenerateForwardFunction(486) GenerateForwardFunction(487) GenerateForwardFunction(488) GenerateForwardFunction(489) GenerateForwardFunction(490) GenerateForwardFunction(491) GenerateForwardFunction(492) GenerateForwardFunction(493) GenerateForwardFunction(494) GenerateForwardFunction(495) GenerateForwardFunction(496) GenerateForwardFunction(497) GenerateForwardFunction(498) GenerateForwardFunction(499) GenerateForwardFunction(500) GenerateForwardFunction(501) GenerateForwardFunction(502) GenerateForwardFunction(503) GenerateForwardFunction(504) GenerateForwardFunction(505) GenerateForwardFunction(506) GenerateForwardFunction(507) GenerateForwardFunction(508) GenerateForwardFunction(509) GenerateForwardFunction(510) GenerateForwardFunction(511) GenerateForwardFunction(512) GenerateForwardFunction(513) GenerateForwardFunction(514) GenerateForwardFunction(515) GenerateForwardFunction(516) GenerateForwardFunction(517) GenerateForwardFunction(518) GenerateForwardFunction(519) GenerateForwardFunction(520) GenerateForwardFunction(521) GenerateForwardFunction(522) GenerateForwardFunction(523) GenerateForwardFunction(524) GenerateForwardFunction(525) GenerateForwardFunction(526) GenerateForwardFunction(527) GenerateForwardFunction(528) GenerateForwardFunction(529) GenerateForwardFunction(530) GenerateForwardFunction(531) GenerateForwardFunction(532) GenerateForwardFunction(533) GenerateForwardFunction(534) GenerateForwardFunction(535) GenerateForwardFunction(536) GenerateForwardFunction(537) GenerateForwardFunction(538) GenerateForwardFunction(539) GenerateForwardFunction(540) GenerateForwardFunction(541) GenerateForwardFunction(542) GenerateForwardFunction(543) GenerateForwardFunction(544) GenerateForwardFunction(545) GenerateForwardFunction(546) GenerateForwardFunction(547) GenerateForwardFunction(548) GenerateForwardFunction(549) GenerateForwardFunction(550) GenerateForwardFunction(551) GenerateForwardFunction(552) GenerateForwardFunction(553) GenerateForwardFunction(554) GenerateForwardFunction(555) GenerateForwardFunction(556) GenerateForwardFunction(557) GenerateForwardFunction(558) GenerateForwardFunction(559) GenerateForwardFunction(560) GenerateForwardFunction(561) GenerateForwardFunction(562) GenerateForwardFunction(563) GenerateForwardFunction(564) GenerateForwardFunction(565) GenerateForwardFunction(566) GenerateForwardFunction(567) GenerateForwardFunction(568) GenerateForwardFunction(569) GenerateForwardFunction(570) GenerateForwardFunction(571) GenerateForwardFunction(572) GenerateForwardFunction(573) GenerateForwardFunction(574) GenerateForwardFunction(575) GenerateForwardFunction(576) GenerateForwardFunction(577) GenerateForwardFunction(578) GenerateForwardFunction(579) GenerateForwardFunction(580) GenerateForwardFunction(581) GenerateForwardFunction(582) GenerateForwardFunction(583) GenerateForwardFunction(584) GenerateForwardFunction(585) GenerateForwardFunction(586) GenerateForwardFunction(587) GenerateForwardFunction(588) GenerateForwardFunction(589) GenerateForwardFunction(590) GenerateForwardFunction(591) GenerateForwardFunction(592) GenerateForwardFunction(593) GenerateForwardFunction(594) GenerateForwardFunction(595) GenerateForwardFunction(596) GenerateForwardFunction(597) GenerateForwardFunction(598) GenerateForwardFunction(599) GenerateForwardFunction(600) GenerateForwardFunction(601) GenerateForwardFunction(602) GenerateForwardFunction(603) GenerateForwardFunction(604) GenerateForwardFunction(605) GenerateForwardFunction(606) GenerateForwardFunction(607) GenerateForwardFunction(608) GenerateForwardFunction(609) GenerateForwardFunction(610) GenerateForwardFunction(611) GenerateForwardFunction(612) GenerateForwardFunction(613) GenerateForwardFunction(614) GenerateForwardFunction(615) GenerateForwardFunction(616) GenerateForwardFunction(617) GenerateForwardFunction(618) GenerateForwardFunction(619) GenerateForwardFunction(620) GenerateForwardFunction(621) GenerateForwardFunction(622) GenerateForwardFunction(623) GenerateForwardFunction(624) GenerateForwardFunction(625) GenerateForwardFunction(626) GenerateForwardFunction(627) GenerateForwardFunction(628) GenerateForwardFunction(629) GenerateForwardFunction(630) GenerateForwardFunction(631) GenerateForwardFunction(632) GenerateForwardFunction(633) GenerateForwardFunction(634) GenerateForwardFunction(635) GenerateForwardFunction(636) GenerateForwardFunction(637) GenerateForwardFunction(638) GenerateForwardFunction(639) GenerateForwardFunction(640) GenerateForwardFunction(641) GenerateForwardFunction(642) GenerateForwardFunction(643) GenerateForwardFunction(644) GenerateForwardFunction(645) GenerateForwardFunction(646) GenerateForwardFunction(647) GenerateForwardFunction(648) GenerateForwardFunction(649) GenerateForwardFunction(650) GenerateForwardFunction(651) GenerateForwardFunction(652) GenerateForwardFunction(653) GenerateForwardFunction(654) GenerateForwardFunction(655) GenerateForwardFunction(656) GenerateForwardFunction(657) GenerateForwardFunction(658) GenerateForwardFunction(659) GenerateForwardFunction(660) GenerateForwardFunction(661) GenerateForwardFunction(662) GenerateForwardFunction(663) GenerateForwardFunction(664) GenerateForwardFunction(665) GenerateForwardFunction(666) GenerateForwardFunction(667) GenerateForwardFunction(668) GenerateForwardFunction(669) GenerateForwardFunction(670) GenerateForwardFunction(671) GenerateForwardFunction(672) GenerateForwardFunction(673) GenerateForwardFunction(674) GenerateForwardFunction(675) GenerateForwardFunction(676) GenerateForwardFunction(677) GenerateForwardFunction(678) GenerateForwardFunction(679) GenerateForwardFunction(680) GenerateForwardFunction(681) GenerateForwardFunction(682) GenerateForwardFunction(683) GenerateForwardFunction(684) GenerateForwardFunction(685) GenerateForwardFunction(686) GenerateForwardFunction(687) GenerateForwardFunction(688) GenerateForwardFunction(689) GenerateForwardFunction(690) GenerateForwardFunction(691) GenerateForwardFunction(692) GenerateForwardFunction(693) GenerateForwardFunction(694) GenerateForwardFunction(695) GenerateForwardFunction(696) GenerateForwardFunction(697) GenerateForwardFunction(698) GenerateForwardFunction(699) GenerateForwardFunction(700) GenerateForwardFunction(701) GenerateForwardFunction(702) GenerateForwardFunction(703) GenerateForwardFunction(704) GenerateForwardFunction(705) GenerateForwardFunction(706) GenerateForwardFunction(707) GenerateForwardFunction(708) GenerateForwardFunction(709) GenerateForwardFunction(710) GenerateForwardFunction(711) GenerateForwardFunction(712) GenerateForwardFunction(713) GenerateForwardFunction(714) GenerateForwardFunction(715) GenerateForwardFunction(716) GenerateForwardFunction(717) GenerateForwardFunction(718) GenerateForwardFunction(719) GenerateForwardFunction(720) GenerateForwardFunction(721) GenerateForwardFunction(722) GenerateForwardFunction(723) GenerateForwardFunction(724) GenerateForwardFunction(725) GenerateForwardFunction(726) GenerateForwardFunction(727) GenerateForwardFunction(728) GenerateForwardFunction(729) GenerateForwardFunction(730) GenerateForwardFunction(731) GenerateForwardFunction(732) GenerateForwardFunction(733) GenerateForwardFunction(734) GenerateForwardFunction(735) GenerateForwardFunction(736) GenerateForwardFunction(737) GenerateForwardFunction(738) GenerateForwardFunction(739) GenerateForwardFunction(740) GenerateForwardFunction(741) GenerateForwardFunction(742) GenerateForwardFunction(743) GenerateForwardFunction(744) GenerateForwardFunction(745) GenerateForwardFunction(746) GenerateForwardFunction(747) GenerateForwardFunction(748) GenerateForwardFunction(749) GenerateForwardFunction(750) GenerateForwardFunction(751) GenerateForwardFunction(752) GenerateForwardFunction(753) GenerateForwardFunction(754) GenerateForwardFunction(755) GenerateForwardFunction(756) GenerateForwardFunction(757) GenerateForwardFunction(758) GenerateForwardFunction(759) GenerateForwardFunction(760) GenerateForwardFunction(761) GenerateForwardFunction(762) GenerateForwardFunction(763) GenerateForwardFunction(764) GenerateForwardFunction(765) GenerateForwardFunction(766) GenerateForwardFunction(767) GenerateForwardFunction(768) GenerateForwardFunction(769) GenerateForwardFunction(770) GenerateForwardFunction(771) GenerateForwardFunction(772) GenerateForwardFunction(773) GenerateForwardFunction(774) GenerateForwardFunction(775) GenerateForwardFunction(776) GenerateForwardFunction(777) GenerateForwardFunction(778) GenerateForwardFunction(779) GenerateForwardFunction(780) GenerateForwardFunction(781) GenerateForwardFunction(782) GenerateForwardFunction(783) GenerateForwardFunction(784) GenerateForwardFunction(785) GenerateForwardFunction(786) GenerateForwardFunction(787) GenerateForwardFunction(788) GenerateForwardFunction(789) GenerateForwardFunction(790) GenerateForwardFunction(791) GenerateForwardFunction(792) GenerateForwardFunction(793) GenerateForwardFunction(794) GenerateForwardFunction(795) GenerateForwardFunction(796) GenerateForwardFunction(797) GenerateForwardFunction(798) GenerateForwardFunction(799) GenerateForwardFunction(800) GenerateForwardFunction(801) GenerateForwardFunction(802) GenerateForwardFunction(803) GenerateForwardFunction(804) GenerateForwardFunction(805) GenerateForwardFunction(806) GenerateForwardFunction(807) GenerateForwardFunction(808) GenerateForwardFunction(809) GenerateForwardFunction(810) GenerateForwardFunction(811) GenerateForwardFunction(812) GenerateForwardFunction(813) GenerateForwardFunction(814) GenerateForwardFunction(815) GenerateForwardFunction(816) GenerateForwardFunction(817) GenerateForwardFunction(818) GenerateForwardFunction(819) GenerateForwardFunction(820) GenerateForwardFunction(821) GenerateForwardFunction(822) GenerateForwardFunction(823) GenerateForwardFunction(824) GenerateForwardFunction(825) GenerateForwardFunction(826) GenerateForwardFunction(827) GenerateForwardFunction(828) GenerateForwardFunction(829) GenerateForwardFunction(830) GenerateForwardFunction(831) GenerateForwardFunction(832) GenerateForwardFunction(833) GenerateForwardFunction(834) GenerateForwardFunction(835) GenerateForwardFunction(836) GenerateForwardFunction(837) GenerateForwardFunction(838) GenerateForwardFunction(839) GenerateForwardFunction(840) GenerateForwardFunction(841) GenerateForwardFunction(842) GenerateForwardFunction(843) GenerateForwardFunction(844) GenerateForwardFunction(845) GenerateForwardFunction(846) GenerateForwardFunction(847) GenerateForwardFunction(848) GenerateForwardFunction(849) GenerateForwardFunction(850) GenerateForwardFunction(851) GenerateForwardFunction(852) GenerateForwardFunction(853) GenerateForwardFunction(854) GenerateForwardFunction(855) GenerateForwardFunction(856) GenerateForwardFunction(857) GenerateForwardFunction(858) GenerateForwardFunction(859) GenerateForwardFunction(860) GenerateForwardFunction(861) GenerateForwardFunction(862) GenerateForwardFunction(863) GenerateForwardFunction(864) GenerateForwardFunction(865) GenerateForwardFunction(866) GenerateForwardFunction(867) GenerateForwardFunction(868) GenerateForwardFunction(869) GenerateForwardFunction(870) GenerateForwardFunction(871) GenerateForwardFunction(872) GenerateForwardFunction(873) GenerateForwardFunction(874) GenerateForwardFunction(875) GenerateForwardFunction(876) GenerateForwardFunction(877) GenerateForwardFunction(878) GenerateForwardFunction(879) GenerateForwardFunction(880) GenerateForwardFunction(881) GenerateForwardFunction(882) GenerateForwardFunction(883) GenerateForwardFunction(884) GenerateForwardFunction(885) GenerateForwardFunction(886) GenerateForwardFunction(887) GenerateForwardFunction(888) GenerateForwardFunction(889) GenerateForwardFunction(890) GenerateForwardFunction(891) GenerateForwardFunction(892) GenerateForwardFunction(893) GenerateForwardFunction(894) GenerateForwardFunction(895) GenerateForwardFunction(896) GenerateForwardFunction(897) GenerateForwardFunction(898) GenerateForwardFunction(899) GenerateForwardFunction(900) GenerateForwardFunction(901) GenerateForwardFunction(902) GenerateForwardFunction(903) GenerateForwardFunction(904) GenerateForwardFunction(905) GenerateForwardFunction(906) GenerateForwardFunction(907) GenerateForwardFunction(908) GenerateForwardFunction(909) GenerateForwardFunction(910) GenerateForwardFunction(911) GenerateForwardFunction(912) GenerateForwardFunction(913) GenerateForwardFunction(914) GenerateForwardFunction(915) GenerateForwardFunction(916) GenerateForwardFunction(917) GenerateForwardFunction(918) GenerateForwardFunction(919) GenerateForwardFunction(920) GenerateForwardFunction(921) GenerateForwardFunction(922) GenerateForwardFunction(923) GenerateForwardFunction(924) GenerateForwardFunction(925) GenerateForwardFunction(926) GenerateForwardFunction(927) GenerateForwardFunction(928) GenerateForwardFunction(929) GenerateForwardFunction(930) GenerateForwardFunction(931) GenerateForwardFunction(932) GenerateForwardFunction(933) GenerateForwardFunction(934) GenerateForwardFunction(935) GenerateForwardFunction(936) GenerateForwardFunction(937) GenerateForwardFunction(938) GenerateForwardFunction(939) GenerateForwardFunction(940) GenerateForwardFunction(941) GenerateForwardFunction(942) GenerateForwardFunction(943) GenerateForwardFunction(944) GenerateForwardFunction(945) GenerateForwardFunction(946) GenerateForwardFunction(947) GenerateForwardFunction(948) GenerateForwardFunction(949) GenerateForwardFunction(950) GenerateForwardFunction(951) GenerateForwardFunction(952) GenerateForwardFunction(953) GenerateForwardFunction(954) GenerateForwardFunction(955) GenerateForwardFunction(956) GenerateForwardFunction(957) GenerateForwardFunction(958) GenerateForwardFunction(959) GenerateForwardFunction(960) GenerateForwardFunction(961) GenerateForwardFunction(962) GenerateForwardFunction(963) GenerateForwardFunction(964) GenerateForwardFunction(965) GenerateForwardFunction(966) GenerateForwardFunction(967) GenerateForwardFunction(968) GenerateForwardFunction(969) GenerateForwardFunction(970) GenerateForwardFunction(971) GenerateForwardFunction(972) GenerateForwardFunction(973) GenerateForwardFunction(974) GenerateForwardFunction(975) GenerateForwardFunction(976) GenerateForwardFunction(977) GenerateForwardFunction(978) GenerateForwardFunction(979) GenerateForwardFunction(980) GenerateForwardFunction(981) GenerateForwardFunction(982) GenerateForwardFunction(983) GenerateForwardFunction(984) GenerateForwardFunction(985) GenerateForwardFunction(986) GenerateForwardFunction(987) GenerateForwardFunction(988) GenerateForwardFunction(989) GenerateForwardFunction(990) GenerateForwardFunction(991) GenerateForwardFunction(992) GenerateForwardFunction(993) GenerateForwardFunction(994) GenerateForwardFunction(995) GenerateForwardFunction(996) GenerateForwardFunction(997) GenerateForwardFunction(998) GenerateForwardFunction(999) GenerateForwardFunction(1000) GenerateForwardFunction(1001) GenerateForwardFunction(1002) GenerateForwardFunction(1003) GenerateForwardFunction(1004) GenerateForwardFunction(1005) GenerateForwardFunction(1006) GenerateForwardFunction(1007) GenerateForwardFunction(1008) GenerateForwardFunction(1009) GenerateForwardFunction(1010) GenerateForwardFunction(1011) GenerateForwardFunction(1012) GenerateForwardFunction(1013) GenerateForwardFunction(1014) GenerateForwardFunction(1015) GenerateForwardFunction(1016) GenerateForwardFunction(1017) GenerateForwardFunction(1018) std::vector forwardAddresses = { &Forward0, &Forward1, &Forward2, &Forward3, &Forward4, &Forward5, &Forward6, &Forward7, &Forward8, &Forward9, &Forward10, &Forward11, &Forward12, &Forward13, &Forward14, &Forward15, &Forward16, &Forward17, &Forward18, &Forward19, &Forward20, &Forward21, &Forward22, &Forward23, &Forward24, &Forward25, &Forward26, &Forward27, &Forward28, &Forward29, &Forward30, &Forward31, &Forward32, &Forward33, &Forward34, &Forward35, &Forward36, &Forward37, &Forward38, &Forward39, &Forward40, &Forward41, &Forward42, &Forward43, &Forward44, &Forward45, &Forward46, &Forward47, &Forward48, &Forward49, &Forward50, &Forward51, &Forward52, &Forward53, &Forward54, &Forward55, &Forward56, &Forward57, &Forward58, &Forward59, &Forward60, &Forward61, &Forward62, &Forward63, &Forward64, &Forward65, &Forward66, &Forward67, &Forward68, &Forward69, &Forward70, &Forward71, &Forward72, &Forward73, &Forward74, &Forward75, &Forward76, &Forward77, &Forward78, &Forward79, &Forward80, &Forward81, &Forward82, &Forward83, &Forward84, &Forward85, &Forward86, &Forward87, &Forward88, &Forward89, &Forward90, &Forward91, &Forward92, &Forward93, &Forward94, &Forward95, &Forward96, &Forward97, &Forward98, &Forward99, &Forward100, &Forward101, &Forward102, &Forward103, &Forward104, &Forward105, &Forward106, &Forward107, &Forward108, &Forward109, &Forward110, &Forward111, &Forward112, &Forward113, &Forward114, &Forward115, &Forward116, &Forward117, &Forward118, &Forward119, &Forward120, &Forward121, &Forward122, &Forward123, &Forward124, &Forward125, &Forward126, &Forward127, &Forward128, &Forward129, &Forward130, &Forward131, &Forward132, &Forward133, &Forward134, &Forward135, &Forward136, &Forward137, &Forward138, &Forward139, &Forward140, &Forward141, &Forward142, &Forward143, &Forward144, &Forward145, &Forward146, &Forward147, &Forward148, &Forward149, &Forward150, &Forward151, &Forward152, &Forward153, &Forward154, &Forward155, &Forward156, &Forward157, &Forward158, &Forward159, &Forward160, &Forward161, &Forward162, &Forward163, &Forward164, &Forward165, &Forward166, &Forward167, &Forward168, &Forward169, &Forward170, &Forward171, &Forward172, &Forward173, &Forward174, &Forward175, &Forward176, &Forward177, &Forward178, &Forward179, &Forward180, &Forward181, &Forward182, &Forward183, &Forward184, &Forward185, &Forward186, &Forward187, &Forward188, &Forward189, &Forward190, &Forward191, &Forward192, &Forward193, &Forward194, &Forward195, &Forward196, &Forward197, &Forward198, &Forward199, &Forward200, &Forward201, &Forward202, &Forward203, &Forward204, &Forward205, &Forward206, &Forward207, &Forward208, &Forward209, &Forward210, &Forward211, &Forward212, &Forward213, &Forward214, &Forward215, &Forward216, &Forward217, &Forward218, &Forward219, &Forward220, &Forward221, &Forward222, &Forward223, &Forward224, &Forward225, &Forward226, &Forward227, &Forward228, &Forward229, &Forward230, &Forward231, &Forward232, &Forward233, &Forward234, &Forward235, &Forward236, &Forward237, &Forward238, &Forward239, &Forward240, &Forward241, &Forward242, &Forward243, &Forward244, &Forward245, &Forward246, &Forward247, &Forward248, &Forward249, &Forward250, &Forward251, &Forward252, &Forward253, &Forward254, &Forward255, &Forward256, &Forward257, &Forward258, &Forward259, &Forward260, &Forward261, &Forward262, &Forward263, &Forward264, &Forward265, &Forward266, &Forward267, &Forward268, &Forward269, &Forward270, &Forward271, &Forward272, &Forward273, &Forward274, &Forward275, &Forward276, &Forward277, &Forward278, &Forward279, &Forward280, &Forward281, &Forward282, &Forward283, &Forward284, &Forward285, &Forward286, &Forward287, &Forward288, &Forward289, &Forward290, &Forward291, &Forward292, &Forward293, &Forward294, &Forward295, &Forward296, &Forward297, &Forward298, &Forward299, &Forward300, &Forward301, &Forward302, &Forward303, &Forward304, &Forward305, &Forward306, &Forward307, &Forward308, &Forward309, &Forward310, &Forward311, &Forward312, &Forward313, &Forward314, &Forward315, &Forward316, &Forward317, &Forward318, &Forward319, &Forward320, &Forward321, &Forward322, &Forward323, &Forward324, &Forward325, &Forward326, &Forward327, &Forward328, &Forward329, &Forward330, &Forward331, &Forward332, &Forward333, &Forward334, &Forward335, &Forward336, &Forward337, &Forward338, &Forward339, &Forward340, &Forward341, &Forward342, &Forward343, &Forward344, &Forward345, &Forward346, &Forward347, &Forward348, &Forward349, &Forward350, &Forward351, &Forward352, &Forward353, &Forward354, &Forward355, &Forward356, &Forward357, &Forward358, &Forward359, &Forward360, &Forward361, &Forward362, &Forward363, &Forward364, &Forward365, &Forward366, &Forward367, &Forward368, &Forward369, &Forward370, &Forward371, &Forward372, &Forward373, &Forward374, &Forward375, &Forward376, &Forward377, &Forward378, &Forward379, &Forward380, &Forward381, &Forward382, &Forward383, &Forward384, &Forward385, &Forward386, &Forward387, &Forward388, &Forward389, &Forward390, &Forward391, &Forward392, &Forward393, &Forward394, &Forward395, &Forward396, &Forward397, &Forward398, &Forward399, &Forward400, &Forward401, &Forward402, &Forward403, &Forward404, &Forward405, &Forward406, &Forward407, &Forward408, &Forward409, &Forward410, &Forward411, &Forward412, &Forward413, &Forward414, &Forward415, &Forward416, &Forward417, &Forward418, &Forward419, &Forward420, &Forward421, &Forward422, &Forward423, &Forward424, &Forward425, &Forward426, &Forward427, &Forward428, &Forward429, &Forward430, &Forward431, &Forward432, &Forward433, &Forward434, &Forward435, &Forward436, &Forward437, &Forward438, &Forward439, &Forward440, &Forward441, &Forward442, &Forward443, &Forward444, &Forward445, &Forward446, &Forward447, &Forward448, &Forward449, &Forward450, &Forward451, &Forward452, &Forward453, &Forward454, &Forward455, &Forward456, &Forward457, &Forward458, &Forward459, &Forward460, &Forward461, &Forward462, &Forward463, &Forward464, &Forward465, &Forward466, &Forward467, &Forward468, &Forward469, &Forward470, &Forward471, &Forward472, &Forward473, &Forward474, &Forward475, &Forward476, &Forward477, &Forward478, &Forward479, &Forward480, &Forward481, &Forward482, &Forward483, &Forward484, &Forward485, &Forward486, &Forward487, &Forward488, &Forward489, &Forward490, &Forward491, &Forward492, &Forward493, &Forward494, &Forward495, &Forward496, &Forward497, &Forward498, &Forward499, &Forward500, &Forward501, &Forward502, &Forward503, &Forward504, &Forward505, &Forward506, &Forward507, &Forward508, &Forward509, &Forward510, &Forward511, &Forward512, &Forward513, &Forward514, &Forward515, &Forward516, &Forward517, &Forward518, &Forward519, &Forward520, &Forward521, &Forward522, &Forward523, &Forward524, &Forward525, &Forward526, &Forward527, &Forward528, &Forward529, &Forward530, &Forward531, &Forward532, &Forward533, &Forward534, &Forward535, &Forward536, &Forward537, &Forward538, &Forward539, &Forward540, &Forward541, &Forward542, &Forward543, &Forward544, &Forward545, &Forward546, &Forward547, &Forward548, &Forward549, &Forward550, &Forward551, &Forward552, &Forward553, &Forward554, &Forward555, &Forward556, &Forward557, &Forward558, &Forward559, &Forward560, &Forward561, &Forward562, &Forward563, &Forward564, &Forward565, &Forward566, &Forward567, &Forward568, &Forward569, &Forward570, &Forward571, &Forward572, &Forward573, &Forward574, &Forward575, &Forward576, &Forward577, &Forward578, &Forward579, &Forward580, &Forward581, &Forward582, &Forward583, &Forward584, &Forward585, &Forward586, &Forward587, &Forward588, &Forward589, &Forward590, &Forward591, &Forward592, &Forward593, &Forward594, &Forward595, &Forward596, &Forward597, &Forward598, &Forward599, &Forward600, &Forward601, &Forward602, &Forward603, &Forward604, &Forward605, &Forward606, &Forward607, &Forward608, &Forward609, &Forward610, &Forward611, &Forward612, &Forward613, &Forward614, &Forward615, &Forward616, &Forward617, &Forward618, &Forward619, &Forward620, &Forward621, &Forward622, &Forward623, &Forward624, &Forward625, &Forward626, &Forward627, &Forward628, &Forward629, &Forward630, &Forward631, &Forward632, &Forward633, &Forward634, &Forward635, &Forward636, &Forward637, &Forward638, &Forward639, &Forward640, &Forward641, &Forward642, &Forward643, &Forward644, &Forward645, &Forward646, &Forward647, &Forward648, &Forward649, &Forward650, &Forward651, &Forward652, &Forward653, &Forward654, &Forward655, &Forward656, &Forward657, &Forward658, &Forward659, &Forward660, &Forward661, &Forward662, &Forward663, &Forward664, &Forward665, &Forward666, &Forward667, &Forward668, &Forward669, &Forward670, &Forward671, &Forward672, &Forward673, &Forward674, &Forward675, &Forward676, &Forward677, &Forward678, &Forward679, &Forward680, &Forward681, &Forward682, &Forward683, &Forward684, &Forward685, &Forward686, &Forward687, &Forward688, &Forward689, &Forward690, &Forward691, &Forward692, &Forward693, &Forward694, &Forward695, &Forward696, &Forward697, &Forward698, &Forward699, &Forward700, &Forward701, &Forward702, &Forward703, &Forward704, &Forward705, &Forward706, &Forward707, &Forward708, &Forward709, &Forward710, &Forward711, &Forward712, &Forward713, &Forward714, &Forward715, &Forward716, &Forward717, &Forward718, &Forward719, &Forward720, &Forward721, &Forward722, &Forward723, &Forward724, &Forward725, &Forward726, &Forward727, &Forward728, &Forward729, &Forward730, &Forward731, &Forward732, &Forward733, &Forward734, &Forward735, &Forward736, &Forward737, &Forward738, &Forward739, &Forward740, &Forward741, &Forward742, &Forward743, &Forward744, &Forward745, &Forward746, &Forward747, &Forward748, &Forward749, &Forward750, &Forward751, &Forward752, &Forward753, &Forward754, &Forward755, &Forward756, &Forward757, &Forward758, &Forward759, &Forward760, &Forward761, &Forward762, &Forward763, &Forward764, &Forward765, &Forward766, &Forward767, &Forward768, &Forward769, &Forward770, &Forward771, &Forward772, &Forward773, &Forward774, &Forward775, &Forward776, &Forward777, &Forward778, &Forward779, &Forward780, &Forward781, &Forward782, &Forward783, &Forward784, &Forward785, &Forward786, &Forward787, &Forward788, &Forward789, &Forward790, &Forward791, &Forward792, &Forward793, &Forward794, &Forward795, &Forward796, &Forward797, &Forward798, &Forward799, &Forward800, &Forward801, &Forward802, &Forward803, &Forward804, &Forward805, &Forward806, &Forward807, &Forward808, &Forward809, &Forward810, &Forward811, &Forward812, &Forward813, &Forward814, &Forward815, &Forward816, &Forward817, &Forward818, &Forward819, &Forward820, &Forward821, &Forward822, &Forward823, &Forward824, &Forward825, &Forward826, &Forward827, &Forward828, &Forward829, &Forward830, &Forward831, &Forward832, &Forward833, &Forward834, &Forward835, &Forward836, &Forward837, &Forward838, &Forward839, &Forward840, &Forward841, &Forward842, &Forward843, &Forward844, &Forward845, &Forward846, &Forward847, &Forward848, &Forward849, &Forward850, &Forward851, &Forward852, &Forward853, &Forward854, &Forward855, &Forward856, &Forward857, &Forward858, &Forward859, &Forward860, &Forward861, &Forward862, &Forward863, &Forward864, &Forward865, &Forward866, &Forward867, &Forward868, &Forward869, &Forward870, &Forward871, &Forward872, &Forward873, &Forward874, &Forward875, &Forward876, &Forward877, &Forward878, &Forward879, &Forward880, &Forward881, &Forward882, &Forward883, &Forward884, &Forward885, &Forward886, &Forward887, &Forward888, &Forward889, &Forward890, &Forward891, &Forward892, &Forward893, &Forward894, &Forward895, &Forward896, &Forward897, &Forward898, &Forward899, &Forward900, &Forward901, &Forward902, &Forward903, &Forward904, &Forward905, &Forward906, &Forward907, &Forward908, &Forward909, &Forward910, &Forward911, &Forward912, &Forward913, &Forward914, &Forward915, &Forward916, &Forward917, &Forward918, &Forward919, &Forward920, &Forward921, &Forward922, &Forward923, &Forward924, &Forward925, &Forward926, &Forward927, &Forward928, &Forward929, &Forward930, &Forward931, &Forward932, &Forward933, &Forward934, &Forward935, &Forward936, &Forward937, &Forward938, &Forward939, &Forward940, &Forward941, &Forward942, &Forward943, &Forward944, &Forward945, &Forward946, &Forward947, &Forward948, &Forward949, &Forward950, &Forward951, &Forward952, &Forward953, &Forward954, &Forward955, &Forward956, &Forward957, &Forward958, &Forward959, &Forward960, &Forward961, &Forward962, &Forward963, &Forward964, &Forward965, &Forward966, &Forward967, &Forward968, &Forward969, &Forward970, &Forward971, &Forward972, &Forward973, &Forward974, &Forward975, &Forward976, &Forward977, &Forward978, &Forward979, &Forward980, &Forward981, &Forward982, &Forward983, &Forward984, &Forward985, &Forward986, &Forward987, &Forward988, &Forward989, &Forward990, &Forward991, &Forward992, &Forward993, &Forward994, &Forward995, &Forward996, &Forward997, &Forward998, &Forward999, &Forward1000, &Forward1001, &Forward1002, &Forward1003, &Forward1004, &Forward1005, &Forward1006, &Forward1007, &Forward1008, &Forward1009, &Forward1010, &Forward1011, &Forward1012, &Forward1013, &Forward1014, &Forward1015, &Forward1016, &Forward1017, &Forward1018 }; GenerateForwardOrdinalFunction(1) GenerateForwardOrdinalFunction(2) GenerateForwardOrdinalFunction(3) GenerateForwardOrdinalFunction(4) GenerateForwardOrdinalFunction(5) GenerateForwardOrdinalFunction(6) GenerateForwardOrdinalFunction(7) GenerateForwardOrdinalFunction(8) GenerateForwardOrdinalFunction(9) GenerateForwardOrdinalFunction(10) GenerateForwardOrdinalFunction(11) GenerateForwardOrdinalFunction(12) GenerateForwardOrdinalFunction(13) GenerateForwardOrdinalFunction(14) GenerateForwardOrdinalFunction(15) GenerateForwardOrdinalFunction(16) GenerateForwardOrdinalFunction(17) GenerateForwardOrdinalFunction(18) GenerateForwardOrdinalFunction(19) GenerateForwardOrdinalFunction(20) GenerateForwardOrdinalFunction(21) GenerateForwardOrdinalFunction(22) GenerateForwardOrdinalFunction(23) GenerateForwardOrdinalFunction(24) GenerateForwardOrdinalFunction(25) GenerateForwardOrdinalFunction(26) GenerateForwardOrdinalFunction(27) GenerateForwardOrdinalFunction(28) GenerateForwardOrdinalFunction(29) GenerateForwardOrdinalFunction(30) GenerateForwardOrdinalFunction(31) GenerateForwardOrdinalFunction(32) GenerateForwardOrdinalFunction(33) GenerateForwardOrdinalFunction(34) GenerateForwardOrdinalFunction(35) GenerateForwardOrdinalFunction(36) GenerateForwardOrdinalFunction(37) GenerateForwardOrdinalFunction(38) GenerateForwardOrdinalFunction(39) GenerateForwardOrdinalFunction(40) GenerateForwardOrdinalFunction(41) GenerateForwardOrdinalFunction(42) GenerateForwardOrdinalFunction(43) GenerateForwardOrdinalFunction(44) GenerateForwardOrdinalFunction(45) GenerateForwardOrdinalFunction(46) GenerateForwardOrdinalFunction(47) GenerateForwardOrdinalFunction(48) GenerateForwardOrdinalFunction(49) GenerateForwardOrdinalFunction(50) GenerateForwardOrdinalFunction(51) GenerateForwardOrdinalFunction(52) GenerateForwardOrdinalFunction(53) GenerateForwardOrdinalFunction(54) GenerateForwardOrdinalFunction(55) GenerateForwardOrdinalFunction(56) GenerateForwardOrdinalFunction(57) GenerateForwardOrdinalFunction(58) GenerateForwardOrdinalFunction(59) GenerateForwardOrdinalFunction(60) GenerateForwardOrdinalFunction(61) GenerateForwardOrdinalFunction(62) GenerateForwardOrdinalFunction(63) GenerateForwardOrdinalFunction(64) GenerateForwardOrdinalFunction(65) GenerateForwardOrdinalFunction(66) GenerateForwardOrdinalFunction(67) GenerateForwardOrdinalFunction(68) GenerateForwardOrdinalFunction(69) GenerateForwardOrdinalFunction(70) GenerateForwardOrdinalFunction(71) GenerateForwardOrdinalFunction(72) GenerateForwardOrdinalFunction(73) GenerateForwardOrdinalFunction(74) GenerateForwardOrdinalFunction(75) GenerateForwardOrdinalFunction(76) GenerateForwardOrdinalFunction(77) GenerateForwardOrdinalFunction(78) GenerateForwardOrdinalFunction(79) GenerateForwardOrdinalFunction(80) GenerateForwardOrdinalFunction(81) GenerateForwardOrdinalFunction(82) GenerateForwardOrdinalFunction(83) GenerateForwardOrdinalFunction(84) GenerateForwardOrdinalFunction(85) GenerateForwardOrdinalFunction(86) GenerateForwardOrdinalFunction(87) GenerateForwardOrdinalFunction(88) GenerateForwardOrdinalFunction(89) GenerateForwardOrdinalFunction(90) GenerateForwardOrdinalFunction(91) GenerateForwardOrdinalFunction(92) GenerateForwardOrdinalFunction(93) GenerateForwardOrdinalFunction(94) GenerateForwardOrdinalFunction(95) GenerateForwardOrdinalFunction(96) GenerateForwardOrdinalFunction(97) GenerateForwardOrdinalFunction(98) GenerateForwardOrdinalFunction(99) GenerateForwardOrdinalFunction(100) GenerateForwardOrdinalFunction(101) GenerateForwardOrdinalFunction(102) GenerateForwardOrdinalFunction(103) GenerateForwardOrdinalFunction(104) GenerateForwardOrdinalFunction(105) GenerateForwardOrdinalFunction(106) GenerateForwardOrdinalFunction(107) GenerateForwardOrdinalFunction(108) GenerateForwardOrdinalFunction(109) GenerateForwardOrdinalFunction(110) GenerateForwardOrdinalFunction(111) GenerateForwardOrdinalFunction(112) GenerateForwardOrdinalFunction(113) GenerateForwardOrdinalFunction(114) GenerateForwardOrdinalFunction(115) GenerateForwardOrdinalFunction(116) GenerateForwardOrdinalFunction(117) GenerateForwardOrdinalFunction(118) GenerateForwardOrdinalFunction(119) GenerateForwardOrdinalFunction(120) GenerateForwardOrdinalFunction(121) GenerateForwardOrdinalFunction(122) GenerateForwardOrdinalFunction(123) GenerateForwardOrdinalFunction(124) GenerateForwardOrdinalFunction(125) GenerateForwardOrdinalFunction(126) GenerateForwardOrdinalFunction(127) GenerateForwardOrdinalFunction(128) GenerateForwardOrdinalFunction(129) GenerateForwardOrdinalFunction(130) GenerateForwardOrdinalFunction(131) GenerateForwardOrdinalFunction(132) GenerateForwardOrdinalFunction(133) GenerateForwardOrdinalFunction(134) GenerateForwardOrdinalFunction(135) GenerateForwardOrdinalFunction(136) GenerateForwardOrdinalFunction(137) GenerateForwardOrdinalFunction(138) GenerateForwardOrdinalFunction(139) GenerateForwardOrdinalFunction(140) GenerateForwardOrdinalFunction(141) GenerateForwardOrdinalFunction(142) GenerateForwardOrdinalFunction(143) GenerateForwardOrdinalFunction(144) GenerateForwardOrdinalFunction(145) GenerateForwardOrdinalFunction(146) GenerateForwardOrdinalFunction(147) GenerateForwardOrdinalFunction(148) GenerateForwardOrdinalFunction(149) GenerateForwardOrdinalFunction(150) GenerateForwardOrdinalFunction(151) GenerateForwardOrdinalFunction(152) GenerateForwardOrdinalFunction(153) GenerateForwardOrdinalFunction(154) GenerateForwardOrdinalFunction(155) GenerateForwardOrdinalFunction(156) GenerateForwardOrdinalFunction(157) GenerateForwardOrdinalFunction(158) GenerateForwardOrdinalFunction(159) GenerateForwardOrdinalFunction(160) GenerateForwardOrdinalFunction(161) GenerateForwardOrdinalFunction(162) GenerateForwardOrdinalFunction(163) GenerateForwardOrdinalFunction(164) GenerateForwardOrdinalFunction(165) GenerateForwardOrdinalFunction(166) GenerateForwardOrdinalFunction(167) GenerateForwardOrdinalFunction(168) GenerateForwardOrdinalFunction(169) GenerateForwardOrdinalFunction(170) GenerateForwardOrdinalFunction(171) GenerateForwardOrdinalFunction(172) GenerateForwardOrdinalFunction(173) GenerateForwardOrdinalFunction(174) GenerateForwardOrdinalFunction(175) GenerateForwardOrdinalFunction(176) GenerateForwardOrdinalFunction(177) GenerateForwardOrdinalFunction(178) GenerateForwardOrdinalFunction(179) GenerateForwardOrdinalFunction(180) GenerateForwardOrdinalFunction(181) GenerateForwardOrdinalFunction(182) GenerateForwardOrdinalFunction(183) GenerateForwardOrdinalFunction(184) GenerateForwardOrdinalFunction(185) GenerateForwardOrdinalFunction(186) GenerateForwardOrdinalFunction(187) GenerateForwardOrdinalFunction(188) GenerateForwardOrdinalFunction(189) GenerateForwardOrdinalFunction(190) GenerateForwardOrdinalFunction(191) GenerateForwardOrdinalFunction(192) GenerateForwardOrdinalFunction(193) GenerateForwardOrdinalFunction(194) GenerateForwardOrdinalFunction(195) GenerateForwardOrdinalFunction(196) GenerateForwardOrdinalFunction(197) GenerateForwardOrdinalFunction(198) GenerateForwardOrdinalFunction(199) GenerateForwardOrdinalFunction(200) GenerateForwardOrdinalFunction(201) GenerateForwardOrdinalFunction(202) GenerateForwardOrdinalFunction(203) GenerateForwardOrdinalFunction(204) GenerateForwardOrdinalFunction(205) GenerateForwardOrdinalFunction(206) GenerateForwardOrdinalFunction(207) GenerateForwardOrdinalFunction(208) GenerateForwardOrdinalFunction(209) GenerateForwardOrdinalFunction(210) GenerateForwardOrdinalFunction(211) GenerateForwardOrdinalFunction(212) GenerateForwardOrdinalFunction(213) GenerateForwardOrdinalFunction(214) GenerateForwardOrdinalFunction(215) GenerateForwardOrdinalFunction(216) GenerateForwardOrdinalFunction(217) GenerateForwardOrdinalFunction(218) GenerateForwardOrdinalFunction(219) GenerateForwardOrdinalFunction(220) GenerateForwardOrdinalFunction(221) GenerateForwardOrdinalFunction(222) GenerateForwardOrdinalFunction(223) GenerateForwardOrdinalFunction(224) GenerateForwardOrdinalFunction(225) GenerateForwardOrdinalFunction(226) GenerateForwardOrdinalFunction(227) GenerateForwardOrdinalFunction(228) GenerateForwardOrdinalFunction(229) GenerateForwardOrdinalFunction(230) GenerateForwardOrdinalFunction(231) GenerateForwardOrdinalFunction(232) GenerateForwardOrdinalFunction(233) GenerateForwardOrdinalFunction(234) GenerateForwardOrdinalFunction(235) GenerateForwardOrdinalFunction(236) GenerateForwardOrdinalFunction(237) GenerateForwardOrdinalFunction(238) GenerateForwardOrdinalFunction(239) GenerateForwardOrdinalFunction(240) GenerateForwardOrdinalFunction(241) GenerateForwardOrdinalFunction(242) GenerateForwardOrdinalFunction(243) GenerateForwardOrdinalFunction(244) GenerateForwardOrdinalFunction(245) GenerateForwardOrdinalFunction(246) GenerateForwardOrdinalFunction(247) GenerateForwardOrdinalFunction(248) GenerateForwardOrdinalFunction(249) GenerateForwardOrdinalFunction(250) GenerateForwardOrdinalFunction(251) GenerateForwardOrdinalFunction(252) GenerateForwardOrdinalFunction(253) GenerateForwardOrdinalFunction(254) GenerateForwardOrdinalFunction(255) GenerateForwardOrdinalFunction(256) GenerateForwardOrdinalFunction(257) GenerateForwardOrdinalFunction(258) GenerateForwardOrdinalFunction(259) GenerateForwardOrdinalFunction(260) GenerateForwardOrdinalFunction(261) GenerateForwardOrdinalFunction(262) GenerateForwardOrdinalFunction(263) GenerateForwardOrdinalFunction(264) GenerateForwardOrdinalFunction(265) GenerateForwardOrdinalFunction(266) GenerateForwardOrdinalFunction(267) GenerateForwardOrdinalFunction(268) GenerateForwardOrdinalFunction(269) GenerateForwardOrdinalFunction(270) GenerateForwardOrdinalFunction(271) GenerateForwardOrdinalFunction(272) GenerateForwardOrdinalFunction(273) GenerateForwardOrdinalFunction(274) GenerateForwardOrdinalFunction(275) GenerateForwardOrdinalFunction(276) GenerateForwardOrdinalFunction(277) GenerateForwardOrdinalFunction(278) GenerateForwardOrdinalFunction(279) GenerateForwardOrdinalFunction(280) GenerateForwardOrdinalFunction(281) GenerateForwardOrdinalFunction(282) GenerateForwardOrdinalFunction(283) GenerateForwardOrdinalFunction(284) GenerateForwardOrdinalFunction(285) GenerateForwardOrdinalFunction(286) GenerateForwardOrdinalFunction(287) GenerateForwardOrdinalFunction(288) GenerateForwardOrdinalFunction(289) GenerateForwardOrdinalFunction(290) GenerateForwardOrdinalFunction(291) GenerateForwardOrdinalFunction(292) GenerateForwardOrdinalFunction(293) GenerateForwardOrdinalFunction(294) GenerateForwardOrdinalFunction(295) GenerateForwardOrdinalFunction(296) GenerateForwardOrdinalFunction(297) GenerateForwardOrdinalFunction(298) GenerateForwardOrdinalFunction(299) GenerateForwardOrdinalFunction(300) GenerateForwardOrdinalFunction(301) GenerateForwardOrdinalFunction(302) GenerateForwardOrdinalFunction(303) GenerateForwardOrdinalFunction(304) GenerateForwardOrdinalFunction(305) GenerateForwardOrdinalFunction(306) GenerateForwardOrdinalFunction(307) GenerateForwardOrdinalFunction(308) GenerateForwardOrdinalFunction(309) GenerateForwardOrdinalFunction(310) GenerateForwardOrdinalFunction(311) GenerateForwardOrdinalFunction(312) GenerateForwardOrdinalFunction(313) GenerateForwardOrdinalFunction(314) GenerateForwardOrdinalFunction(315) GenerateForwardOrdinalFunction(316) GenerateForwardOrdinalFunction(317) GenerateForwardOrdinalFunction(318) GenerateForwardOrdinalFunction(319) GenerateForwardOrdinalFunction(320) GenerateForwardOrdinalFunction(321) GenerateForwardOrdinalFunction(322) GenerateForwardOrdinalFunction(323) GenerateForwardOrdinalFunction(324) GenerateForwardOrdinalFunction(325) GenerateForwardOrdinalFunction(326) GenerateForwardOrdinalFunction(327) GenerateForwardOrdinalFunction(328) GenerateForwardOrdinalFunction(329) GenerateForwardOrdinalFunction(330) GenerateForwardOrdinalFunction(331) GenerateForwardOrdinalFunction(332) GenerateForwardOrdinalFunction(333) GenerateForwardOrdinalFunction(334) GenerateForwardOrdinalFunction(335) GenerateForwardOrdinalFunction(336) GenerateForwardOrdinalFunction(337) GenerateForwardOrdinalFunction(338) GenerateForwardOrdinalFunction(339) GenerateForwardOrdinalFunction(340) GenerateForwardOrdinalFunction(341) GenerateForwardOrdinalFunction(342) GenerateForwardOrdinalFunction(343) GenerateForwardOrdinalFunction(344) GenerateForwardOrdinalFunction(345) GenerateForwardOrdinalFunction(346) GenerateForwardOrdinalFunction(347) GenerateForwardOrdinalFunction(348) GenerateForwardOrdinalFunction(349) GenerateForwardOrdinalFunction(350) GenerateForwardOrdinalFunction(351) GenerateForwardOrdinalFunction(352) GenerateForwardOrdinalFunction(353) GenerateForwardOrdinalFunction(354) GenerateForwardOrdinalFunction(355) GenerateForwardOrdinalFunction(356) GenerateForwardOrdinalFunction(357) GenerateForwardOrdinalFunction(358) GenerateForwardOrdinalFunction(359) GenerateForwardOrdinalFunction(360) GenerateForwardOrdinalFunction(361) GenerateForwardOrdinalFunction(362) GenerateForwardOrdinalFunction(363) GenerateForwardOrdinalFunction(364) GenerateForwardOrdinalFunction(365) GenerateForwardOrdinalFunction(366) GenerateForwardOrdinalFunction(367) GenerateForwardOrdinalFunction(368) GenerateForwardOrdinalFunction(369) GenerateForwardOrdinalFunction(370) GenerateForwardOrdinalFunction(371) GenerateForwardOrdinalFunction(372) GenerateForwardOrdinalFunction(373) GenerateForwardOrdinalFunction(374) GenerateForwardOrdinalFunction(375) GenerateForwardOrdinalFunction(376) GenerateForwardOrdinalFunction(377) GenerateForwardOrdinalFunction(378) GenerateForwardOrdinalFunction(379) GenerateForwardOrdinalFunction(380) GenerateForwardOrdinalFunction(381) GenerateForwardOrdinalFunction(382) GenerateForwardOrdinalFunction(383) GenerateForwardOrdinalFunction(384) GenerateForwardOrdinalFunction(385) GenerateForwardOrdinalFunction(386) GenerateForwardOrdinalFunction(387) GenerateForwardOrdinalFunction(388) GenerateForwardOrdinalFunction(389) GenerateForwardOrdinalFunction(390) GenerateForwardOrdinalFunction(391) GenerateForwardOrdinalFunction(392) GenerateForwardOrdinalFunction(393) GenerateForwardOrdinalFunction(394) GenerateForwardOrdinalFunction(395) GenerateForwardOrdinalFunction(396) GenerateForwardOrdinalFunction(397) GenerateForwardOrdinalFunction(398) GenerateForwardOrdinalFunction(399) GenerateForwardOrdinalFunction(400) GenerateForwardOrdinalFunction(401) GenerateForwardOrdinalFunction(402) GenerateForwardOrdinalFunction(403) GenerateForwardOrdinalFunction(404) GenerateForwardOrdinalFunction(405) GenerateForwardOrdinalFunction(406) GenerateForwardOrdinalFunction(407) GenerateForwardOrdinalFunction(408) GenerateForwardOrdinalFunction(409) GenerateForwardOrdinalFunction(410) GenerateForwardOrdinalFunction(411) GenerateForwardOrdinalFunction(412) GenerateForwardOrdinalFunction(413) GenerateForwardOrdinalFunction(414) GenerateForwardOrdinalFunction(415) GenerateForwardOrdinalFunction(416) GenerateForwardOrdinalFunction(417) GenerateForwardOrdinalFunction(418) GenerateForwardOrdinalFunction(419) GenerateForwardOrdinalFunction(420) GenerateForwardOrdinalFunction(421) GenerateForwardOrdinalFunction(422) GenerateForwardOrdinalFunction(423) GenerateForwardOrdinalFunction(424) GenerateForwardOrdinalFunction(425) GenerateForwardOrdinalFunction(426) GenerateForwardOrdinalFunction(427) GenerateForwardOrdinalFunction(428) GenerateForwardOrdinalFunction(429) GenerateForwardOrdinalFunction(430) GenerateForwardOrdinalFunction(431) GenerateForwardOrdinalFunction(432) GenerateForwardOrdinalFunction(433) GenerateForwardOrdinalFunction(434) GenerateForwardOrdinalFunction(435) GenerateForwardOrdinalFunction(436) GenerateForwardOrdinalFunction(437) GenerateForwardOrdinalFunction(438) GenerateForwardOrdinalFunction(439) GenerateForwardOrdinalFunction(440) GenerateForwardOrdinalFunction(441) GenerateForwardOrdinalFunction(442) GenerateForwardOrdinalFunction(443) GenerateForwardOrdinalFunction(444) GenerateForwardOrdinalFunction(445) GenerateForwardOrdinalFunction(446) GenerateForwardOrdinalFunction(447) GenerateForwardOrdinalFunction(448) GenerateForwardOrdinalFunction(449) GenerateForwardOrdinalFunction(450) GenerateForwardOrdinalFunction(451) GenerateForwardOrdinalFunction(452) GenerateForwardOrdinalFunction(453) GenerateForwardOrdinalFunction(454) GenerateForwardOrdinalFunction(455) GenerateForwardOrdinalFunction(456) GenerateForwardOrdinalFunction(457) GenerateForwardOrdinalFunction(458) GenerateForwardOrdinalFunction(459) GenerateForwardOrdinalFunction(460) GenerateForwardOrdinalFunction(461) GenerateForwardOrdinalFunction(462) GenerateForwardOrdinalFunction(463) GenerateForwardOrdinalFunction(464) GenerateForwardOrdinalFunction(465) GenerateForwardOrdinalFunction(466) GenerateForwardOrdinalFunction(467) GenerateForwardOrdinalFunction(468) GenerateForwardOrdinalFunction(469) GenerateForwardOrdinalFunction(470) GenerateForwardOrdinalFunction(471) GenerateForwardOrdinalFunction(472) GenerateForwardOrdinalFunction(473) GenerateForwardOrdinalFunction(474) GenerateForwardOrdinalFunction(475) GenerateForwardOrdinalFunction(476) GenerateForwardOrdinalFunction(477) GenerateForwardOrdinalFunction(478) GenerateForwardOrdinalFunction(479) GenerateForwardOrdinalFunction(480) GenerateForwardOrdinalFunction(481) GenerateForwardOrdinalFunction(482) GenerateForwardOrdinalFunction(483) GenerateForwardOrdinalFunction(484) GenerateForwardOrdinalFunction(485) GenerateForwardOrdinalFunction(486) GenerateForwardOrdinalFunction(487) GenerateForwardOrdinalFunction(488) GenerateForwardOrdinalFunction(489) GenerateForwardOrdinalFunction(490) GenerateForwardOrdinalFunction(491) GenerateForwardOrdinalFunction(492) GenerateForwardOrdinalFunction(493) GenerateForwardOrdinalFunction(494) GenerateForwardOrdinalFunction(495) GenerateForwardOrdinalFunction(496) GenerateForwardOrdinalFunction(497) GenerateForwardOrdinalFunction(498) GenerateForwardOrdinalFunction(499) GenerateForwardOrdinalFunction(500) GenerateForwardOrdinalFunction(501) GenerateForwardOrdinalFunction(502) GenerateForwardOrdinalFunction(503) GenerateForwardOrdinalFunction(504) GenerateForwardOrdinalFunction(505) GenerateForwardOrdinalFunction(506) GenerateForwardOrdinalFunction(507) GenerateForwardOrdinalFunction(508) GenerateForwardOrdinalFunction(509) GenerateForwardOrdinalFunction(510) GenerateForwardOrdinalFunction(511) GenerateForwardOrdinalFunction(512) GenerateForwardOrdinalFunction(513) GenerateForwardOrdinalFunction(514) GenerateForwardOrdinalFunction(515) GenerateForwardOrdinalFunction(516) GenerateForwardOrdinalFunction(517) GenerateForwardOrdinalFunction(518) GenerateForwardOrdinalFunction(519) GenerateForwardOrdinalFunction(520) GenerateForwardOrdinalFunction(521) GenerateForwardOrdinalFunction(522) GenerateForwardOrdinalFunction(523) GenerateForwardOrdinalFunction(524) GenerateForwardOrdinalFunction(525) GenerateForwardOrdinalFunction(526) GenerateForwardOrdinalFunction(527) GenerateForwardOrdinalFunction(528) GenerateForwardOrdinalFunction(529) GenerateForwardOrdinalFunction(530) GenerateForwardOrdinalFunction(531) GenerateForwardOrdinalFunction(532) GenerateForwardOrdinalFunction(533) GenerateForwardOrdinalFunction(534) GenerateForwardOrdinalFunction(535) GenerateForwardOrdinalFunction(536) GenerateForwardOrdinalFunction(537) GenerateForwardOrdinalFunction(538) GenerateForwardOrdinalFunction(539) GenerateForwardOrdinalFunction(540) GenerateForwardOrdinalFunction(541) GenerateForwardOrdinalFunction(542) GenerateForwardOrdinalFunction(543) GenerateForwardOrdinalFunction(544) GenerateForwardOrdinalFunction(545) GenerateForwardOrdinalFunction(546) GenerateForwardOrdinalFunction(547) GenerateForwardOrdinalFunction(548) GenerateForwardOrdinalFunction(549) GenerateForwardOrdinalFunction(550) GenerateForwardOrdinalFunction(551) GenerateForwardOrdinalFunction(552) GenerateForwardOrdinalFunction(553) GenerateForwardOrdinalFunction(554) GenerateForwardOrdinalFunction(555) GenerateForwardOrdinalFunction(556) GenerateForwardOrdinalFunction(557) GenerateForwardOrdinalFunction(558) GenerateForwardOrdinalFunction(559) GenerateForwardOrdinalFunction(560) GenerateForwardOrdinalFunction(561) GenerateForwardOrdinalFunction(562) GenerateForwardOrdinalFunction(563) GenerateForwardOrdinalFunction(564) GenerateForwardOrdinalFunction(565) GenerateForwardOrdinalFunction(566) GenerateForwardOrdinalFunction(567) GenerateForwardOrdinalFunction(568) GenerateForwardOrdinalFunction(569) GenerateForwardOrdinalFunction(570) GenerateForwardOrdinalFunction(571) GenerateForwardOrdinalFunction(572) GenerateForwardOrdinalFunction(573) GenerateForwardOrdinalFunction(574) GenerateForwardOrdinalFunction(575) GenerateForwardOrdinalFunction(576) GenerateForwardOrdinalFunction(577) GenerateForwardOrdinalFunction(578) GenerateForwardOrdinalFunction(579) GenerateForwardOrdinalFunction(580) GenerateForwardOrdinalFunction(581) GenerateForwardOrdinalFunction(582) GenerateForwardOrdinalFunction(583) GenerateForwardOrdinalFunction(584) GenerateForwardOrdinalFunction(585) GenerateForwardOrdinalFunction(586) GenerateForwardOrdinalFunction(587) GenerateForwardOrdinalFunction(588) GenerateForwardOrdinalFunction(589) GenerateForwardOrdinalFunction(590) GenerateForwardOrdinalFunction(591) GenerateForwardOrdinalFunction(592) GenerateForwardOrdinalFunction(593) GenerateForwardOrdinalFunction(594) GenerateForwardOrdinalFunction(595) GenerateForwardOrdinalFunction(596) GenerateForwardOrdinalFunction(597) GenerateForwardOrdinalFunction(598) GenerateForwardOrdinalFunction(599) GenerateForwardOrdinalFunction(600) GenerateForwardOrdinalFunction(601) GenerateForwardOrdinalFunction(602) GenerateForwardOrdinalFunction(603) GenerateForwardOrdinalFunction(604) GenerateForwardOrdinalFunction(605) GenerateForwardOrdinalFunction(606) GenerateForwardOrdinalFunction(607) GenerateForwardOrdinalFunction(608) GenerateForwardOrdinalFunction(609) GenerateForwardOrdinalFunction(610) GenerateForwardOrdinalFunction(611) GenerateForwardOrdinalFunction(612) GenerateForwardOrdinalFunction(613) GenerateForwardOrdinalFunction(614) GenerateForwardOrdinalFunction(615) GenerateForwardOrdinalFunction(616) GenerateForwardOrdinalFunction(617) GenerateForwardOrdinalFunction(618) GenerateForwardOrdinalFunction(619) GenerateForwardOrdinalFunction(620) GenerateForwardOrdinalFunction(621) GenerateForwardOrdinalFunction(622) GenerateForwardOrdinalFunction(623) GenerateForwardOrdinalFunction(624) GenerateForwardOrdinalFunction(625) GenerateForwardOrdinalFunction(626) GenerateForwardOrdinalFunction(627) GenerateForwardOrdinalFunction(628) GenerateForwardOrdinalFunction(629) GenerateForwardOrdinalFunction(630) GenerateForwardOrdinalFunction(631) GenerateForwardOrdinalFunction(632) GenerateForwardOrdinalFunction(633) GenerateForwardOrdinalFunction(634) GenerateForwardOrdinalFunction(635) GenerateForwardOrdinalFunction(636) GenerateForwardOrdinalFunction(637) GenerateForwardOrdinalFunction(638) GenerateForwardOrdinalFunction(639) GenerateForwardOrdinalFunction(640) GenerateForwardOrdinalFunction(641) GenerateForwardOrdinalFunction(642) GenerateForwardOrdinalFunction(643) GenerateForwardOrdinalFunction(644) GenerateForwardOrdinalFunction(645) GenerateForwardOrdinalFunction(646) GenerateForwardOrdinalFunction(647) GenerateForwardOrdinalFunction(648) GenerateForwardOrdinalFunction(649) GenerateForwardOrdinalFunction(650) GenerateForwardOrdinalFunction(651) GenerateForwardOrdinalFunction(652) GenerateForwardOrdinalFunction(653) GenerateForwardOrdinalFunction(654) GenerateForwardOrdinalFunction(655) GenerateForwardOrdinalFunction(656) GenerateForwardOrdinalFunction(657) GenerateForwardOrdinalFunction(658) GenerateForwardOrdinalFunction(659) GenerateForwardOrdinalFunction(660) GenerateForwardOrdinalFunction(661) GenerateForwardOrdinalFunction(662) GenerateForwardOrdinalFunction(663) GenerateForwardOrdinalFunction(664) GenerateForwardOrdinalFunction(665) GenerateForwardOrdinalFunction(666) GenerateForwardOrdinalFunction(667) GenerateForwardOrdinalFunction(668) GenerateForwardOrdinalFunction(669) GenerateForwardOrdinalFunction(670) GenerateForwardOrdinalFunction(671) GenerateForwardOrdinalFunction(672) GenerateForwardOrdinalFunction(673) GenerateForwardOrdinalFunction(674) GenerateForwardOrdinalFunction(675) GenerateForwardOrdinalFunction(676) GenerateForwardOrdinalFunction(677) GenerateForwardOrdinalFunction(678) GenerateForwardOrdinalFunction(679) GenerateForwardOrdinalFunction(680) GenerateForwardOrdinalFunction(681) GenerateForwardOrdinalFunction(682) GenerateForwardOrdinalFunction(683) GenerateForwardOrdinalFunction(684) GenerateForwardOrdinalFunction(685) GenerateForwardOrdinalFunction(686) GenerateForwardOrdinalFunction(687) GenerateForwardOrdinalFunction(688) GenerateForwardOrdinalFunction(689) GenerateForwardOrdinalFunction(690) GenerateForwardOrdinalFunction(691) GenerateForwardOrdinalFunction(692) GenerateForwardOrdinalFunction(693) GenerateForwardOrdinalFunction(694) GenerateForwardOrdinalFunction(695) GenerateForwardOrdinalFunction(696) GenerateForwardOrdinalFunction(697) GenerateForwardOrdinalFunction(698) GenerateForwardOrdinalFunction(699) GenerateForwardOrdinalFunction(700) GenerateForwardOrdinalFunction(701) GenerateForwardOrdinalFunction(702) GenerateForwardOrdinalFunction(703) GenerateForwardOrdinalFunction(704) GenerateForwardOrdinalFunction(705) GenerateForwardOrdinalFunction(706) GenerateForwardOrdinalFunction(707) GenerateForwardOrdinalFunction(708) GenerateForwardOrdinalFunction(709) GenerateForwardOrdinalFunction(710) GenerateForwardOrdinalFunction(711) GenerateForwardOrdinalFunction(712) GenerateForwardOrdinalFunction(713) GenerateForwardOrdinalFunction(714) GenerateForwardOrdinalFunction(715) GenerateForwardOrdinalFunction(716) GenerateForwardOrdinalFunction(717) GenerateForwardOrdinalFunction(718) GenerateForwardOrdinalFunction(719) GenerateForwardOrdinalFunction(720) GenerateForwardOrdinalFunction(721) GenerateForwardOrdinalFunction(722) GenerateForwardOrdinalFunction(723) GenerateForwardOrdinalFunction(724) GenerateForwardOrdinalFunction(725) GenerateForwardOrdinalFunction(726) GenerateForwardOrdinalFunction(727) GenerateForwardOrdinalFunction(728) GenerateForwardOrdinalFunction(729) GenerateForwardOrdinalFunction(730) GenerateForwardOrdinalFunction(731) GenerateForwardOrdinalFunction(732) GenerateForwardOrdinalFunction(733) GenerateForwardOrdinalFunction(734) GenerateForwardOrdinalFunction(735) GenerateForwardOrdinalFunction(736) GenerateForwardOrdinalFunction(737) GenerateForwardOrdinalFunction(738) GenerateForwardOrdinalFunction(739) GenerateForwardOrdinalFunction(740) GenerateForwardOrdinalFunction(741) GenerateForwardOrdinalFunction(742) GenerateForwardOrdinalFunction(743) GenerateForwardOrdinalFunction(744) GenerateForwardOrdinalFunction(745) GenerateForwardOrdinalFunction(746) GenerateForwardOrdinalFunction(747) GenerateForwardOrdinalFunction(748) GenerateForwardOrdinalFunction(749) GenerateForwardOrdinalFunction(750) GenerateForwardOrdinalFunction(751) GenerateForwardOrdinalFunction(752) GenerateForwardOrdinalFunction(753) GenerateForwardOrdinalFunction(754) GenerateForwardOrdinalFunction(755) GenerateForwardOrdinalFunction(756) GenerateForwardOrdinalFunction(757) GenerateForwardOrdinalFunction(758) GenerateForwardOrdinalFunction(759) GenerateForwardOrdinalFunction(760) GenerateForwardOrdinalFunction(761) GenerateForwardOrdinalFunction(762) GenerateForwardOrdinalFunction(763) GenerateForwardOrdinalFunction(764) GenerateForwardOrdinalFunction(765) GenerateForwardOrdinalFunction(766) GenerateForwardOrdinalFunction(767) GenerateForwardOrdinalFunction(768) GenerateForwardOrdinalFunction(769) GenerateForwardOrdinalFunction(770) GenerateForwardOrdinalFunction(771) GenerateForwardOrdinalFunction(772) GenerateForwardOrdinalFunction(773) GenerateForwardOrdinalFunction(774) GenerateForwardOrdinalFunction(775) GenerateForwardOrdinalFunction(776) GenerateForwardOrdinalFunction(777) GenerateForwardOrdinalFunction(778) GenerateForwardOrdinalFunction(779) GenerateForwardOrdinalFunction(780) GenerateForwardOrdinalFunction(781) GenerateForwardOrdinalFunction(782) GenerateForwardOrdinalFunction(783) GenerateForwardOrdinalFunction(784) GenerateForwardOrdinalFunction(785) GenerateForwardOrdinalFunction(786) GenerateForwardOrdinalFunction(787) GenerateForwardOrdinalFunction(788) GenerateForwardOrdinalFunction(789) GenerateForwardOrdinalFunction(790) GenerateForwardOrdinalFunction(791) GenerateForwardOrdinalFunction(792) GenerateForwardOrdinalFunction(793) GenerateForwardOrdinalFunction(794) GenerateForwardOrdinalFunction(795) GenerateForwardOrdinalFunction(796) GenerateForwardOrdinalFunction(797) GenerateForwardOrdinalFunction(798) GenerateForwardOrdinalFunction(799) GenerateForwardOrdinalFunction(800) GenerateForwardOrdinalFunction(801) GenerateForwardOrdinalFunction(802) GenerateForwardOrdinalFunction(803) GenerateForwardOrdinalFunction(804) GenerateForwardOrdinalFunction(805) GenerateForwardOrdinalFunction(806) GenerateForwardOrdinalFunction(807) GenerateForwardOrdinalFunction(808) GenerateForwardOrdinalFunction(809) GenerateForwardOrdinalFunction(810) GenerateForwardOrdinalFunction(811) GenerateForwardOrdinalFunction(812) GenerateForwardOrdinalFunction(813) GenerateForwardOrdinalFunction(814) GenerateForwardOrdinalFunction(815) GenerateForwardOrdinalFunction(816) GenerateForwardOrdinalFunction(817) GenerateForwardOrdinalFunction(818) GenerateForwardOrdinalFunction(819) GenerateForwardOrdinalFunction(820) GenerateForwardOrdinalFunction(821) GenerateForwardOrdinalFunction(822) GenerateForwardOrdinalFunction(823) GenerateForwardOrdinalFunction(824) GenerateForwardOrdinalFunction(825) GenerateForwardOrdinalFunction(826) GenerateForwardOrdinalFunction(827) GenerateForwardOrdinalFunction(828) GenerateForwardOrdinalFunction(829) GenerateForwardOrdinalFunction(830) GenerateForwardOrdinalFunction(831) GenerateForwardOrdinalFunction(832) GenerateForwardOrdinalFunction(833) GenerateForwardOrdinalFunction(834) GenerateForwardOrdinalFunction(835) GenerateForwardOrdinalFunction(836) GenerateForwardOrdinalFunction(837) GenerateForwardOrdinalFunction(838) GenerateForwardOrdinalFunction(839) GenerateForwardOrdinalFunction(840) GenerateForwardOrdinalFunction(841) GenerateForwardOrdinalFunction(842) GenerateForwardOrdinalFunction(843) GenerateForwardOrdinalFunction(844) GenerateForwardOrdinalFunction(845) GenerateForwardOrdinalFunction(846) GenerateForwardOrdinalFunction(847) GenerateForwardOrdinalFunction(848) GenerateForwardOrdinalFunction(849) GenerateForwardOrdinalFunction(850) GenerateForwardOrdinalFunction(851) GenerateForwardOrdinalFunction(852) GenerateForwardOrdinalFunction(853) GenerateForwardOrdinalFunction(854) GenerateForwardOrdinalFunction(855) GenerateForwardOrdinalFunction(856) GenerateForwardOrdinalFunction(857) GenerateForwardOrdinalFunction(858) GenerateForwardOrdinalFunction(859) GenerateForwardOrdinalFunction(860) GenerateForwardOrdinalFunction(861) GenerateForwardOrdinalFunction(862) GenerateForwardOrdinalFunction(863) GenerateForwardOrdinalFunction(864) GenerateForwardOrdinalFunction(865) GenerateForwardOrdinalFunction(866) GenerateForwardOrdinalFunction(867) GenerateForwardOrdinalFunction(868) GenerateForwardOrdinalFunction(869) GenerateForwardOrdinalFunction(870) GenerateForwardOrdinalFunction(871) GenerateForwardOrdinalFunction(872) GenerateForwardOrdinalFunction(873) GenerateForwardOrdinalFunction(874) GenerateForwardOrdinalFunction(875) GenerateForwardOrdinalFunction(876) GenerateForwardOrdinalFunction(877) GenerateForwardOrdinalFunction(878) GenerateForwardOrdinalFunction(879) GenerateForwardOrdinalFunction(880) GenerateForwardOrdinalFunction(881) GenerateForwardOrdinalFunction(882) GenerateForwardOrdinalFunction(883) GenerateForwardOrdinalFunction(884) GenerateForwardOrdinalFunction(885) GenerateForwardOrdinalFunction(886) GenerateForwardOrdinalFunction(887) GenerateForwardOrdinalFunction(888) GenerateForwardOrdinalFunction(889) GenerateForwardOrdinalFunction(890) GenerateForwardOrdinalFunction(891) GenerateForwardOrdinalFunction(892) GenerateForwardOrdinalFunction(893) GenerateForwardOrdinalFunction(894) GenerateForwardOrdinalFunction(895) GenerateForwardOrdinalFunction(896) GenerateForwardOrdinalFunction(897) GenerateForwardOrdinalFunction(898) GenerateForwardOrdinalFunction(899) GenerateForwardOrdinalFunction(900) GenerateForwardOrdinalFunction(901) GenerateForwardOrdinalFunction(902) GenerateForwardOrdinalFunction(903) GenerateForwardOrdinalFunction(904) GenerateForwardOrdinalFunction(905) GenerateForwardOrdinalFunction(906) GenerateForwardOrdinalFunction(907) GenerateForwardOrdinalFunction(908) GenerateForwardOrdinalFunction(909) GenerateForwardOrdinalFunction(910) GenerateForwardOrdinalFunction(911) GenerateForwardOrdinalFunction(912) GenerateForwardOrdinalFunction(913) GenerateForwardOrdinalFunction(914) GenerateForwardOrdinalFunction(915) GenerateForwardOrdinalFunction(916) GenerateForwardOrdinalFunction(917) GenerateForwardOrdinalFunction(918) GenerateForwardOrdinalFunction(919) GenerateForwardOrdinalFunction(920) GenerateForwardOrdinalFunction(921) GenerateForwardOrdinalFunction(922) GenerateForwardOrdinalFunction(923) GenerateForwardOrdinalFunction(924) GenerateForwardOrdinalFunction(925) GenerateForwardOrdinalFunction(926) GenerateForwardOrdinalFunction(927) GenerateForwardOrdinalFunction(928) GenerateForwardOrdinalFunction(929) GenerateForwardOrdinalFunction(930) GenerateForwardOrdinalFunction(931) GenerateForwardOrdinalFunction(932) GenerateForwardOrdinalFunction(933) GenerateForwardOrdinalFunction(934) GenerateForwardOrdinalFunction(935) GenerateForwardOrdinalFunction(936) GenerateForwardOrdinalFunction(937) GenerateForwardOrdinalFunction(938) GenerateForwardOrdinalFunction(939) GenerateForwardOrdinalFunction(940) GenerateForwardOrdinalFunction(941) GenerateForwardOrdinalFunction(942) GenerateForwardOrdinalFunction(943) GenerateForwardOrdinalFunction(944) GenerateForwardOrdinalFunction(945) GenerateForwardOrdinalFunction(946) GenerateForwardOrdinalFunction(947) GenerateForwardOrdinalFunction(948) GenerateForwardOrdinalFunction(949) GenerateForwardOrdinalFunction(950) GenerateForwardOrdinalFunction(951) GenerateForwardOrdinalFunction(952) GenerateForwardOrdinalFunction(953) GenerateForwardOrdinalFunction(954) GenerateForwardOrdinalFunction(955) GenerateForwardOrdinalFunction(956) GenerateForwardOrdinalFunction(957) GenerateForwardOrdinalFunction(958) GenerateForwardOrdinalFunction(959) GenerateForwardOrdinalFunction(960) GenerateForwardOrdinalFunction(961) GenerateForwardOrdinalFunction(962) GenerateForwardOrdinalFunction(963) GenerateForwardOrdinalFunction(964) GenerateForwardOrdinalFunction(965) GenerateForwardOrdinalFunction(966) GenerateForwardOrdinalFunction(967) GenerateForwardOrdinalFunction(968) GenerateForwardOrdinalFunction(969) GenerateForwardOrdinalFunction(970) GenerateForwardOrdinalFunction(971) GenerateForwardOrdinalFunction(972) GenerateForwardOrdinalFunction(973) GenerateForwardOrdinalFunction(974) GenerateForwardOrdinalFunction(975) GenerateForwardOrdinalFunction(976) GenerateForwardOrdinalFunction(977) GenerateForwardOrdinalFunction(978) GenerateForwardOrdinalFunction(979) GenerateForwardOrdinalFunction(980) GenerateForwardOrdinalFunction(981) GenerateForwardOrdinalFunction(982) GenerateForwardOrdinalFunction(983) GenerateForwardOrdinalFunction(984) GenerateForwardOrdinalFunction(985) GenerateForwardOrdinalFunction(986) GenerateForwardOrdinalFunction(987) GenerateForwardOrdinalFunction(988) GenerateForwardOrdinalFunction(989) GenerateForwardOrdinalFunction(990) GenerateForwardOrdinalFunction(991) GenerateForwardOrdinalFunction(992) GenerateForwardOrdinalFunction(993) GenerateForwardOrdinalFunction(994) GenerateForwardOrdinalFunction(995) GenerateForwardOrdinalFunction(996) GenerateForwardOrdinalFunction(997) GenerateForwardOrdinalFunction(998) GenerateForwardOrdinalFunction(999) GenerateForwardOrdinalFunction(1000) GenerateForwardOrdinalFunction(1001) GenerateForwardOrdinalFunction(1002) GenerateForwardOrdinalFunction(1003) GenerateForwardOrdinalFunction(1004) GenerateForwardOrdinalFunction(1005) GenerateForwardOrdinalFunction(1006) GenerateForwardOrdinalFunction(1007) GenerateForwardOrdinalFunction(1008) GenerateForwardOrdinalFunction(1009) GenerateForwardOrdinalFunction(1010) GenerateForwardOrdinalFunction(1011) GenerateForwardOrdinalFunction(1012) GenerateForwardOrdinalFunction(1013) GenerateForwardOrdinalFunction(1014) GenerateForwardOrdinalFunction(1015) GenerateForwardOrdinalFunction(1016) GenerateForwardOrdinalFunction(1017) GenerateForwardOrdinalFunction(1018) GenerateForwardOrdinalFunction(1019) std::vector forwardOrdinalAddresses = { &ForwardOrdinal1, &ForwardOrdinal2, &ForwardOrdinal3, &ForwardOrdinal4, &ForwardOrdinal5, &ForwardOrdinal6, &ForwardOrdinal7, &ForwardOrdinal8, &ForwardOrdinal9, &ForwardOrdinal10, &ForwardOrdinal11, &ForwardOrdinal12, &ForwardOrdinal13, &ForwardOrdinal14, &ForwardOrdinal15, &ForwardOrdinal16, &ForwardOrdinal17, &ForwardOrdinal18, &ForwardOrdinal19, &ForwardOrdinal20, &ForwardOrdinal21, &ForwardOrdinal22, &ForwardOrdinal23, &ForwardOrdinal24, &ForwardOrdinal25, &ForwardOrdinal26, &ForwardOrdinal27, &ForwardOrdinal28, &ForwardOrdinal29, &ForwardOrdinal30, &ForwardOrdinal31, &ForwardOrdinal32, &ForwardOrdinal33, &ForwardOrdinal34, &ForwardOrdinal35, &ForwardOrdinal36, &ForwardOrdinal37, &ForwardOrdinal38, &ForwardOrdinal39, &ForwardOrdinal40, &ForwardOrdinal41, &ForwardOrdinal42, &ForwardOrdinal43, &ForwardOrdinal44, &ForwardOrdinal45, &ForwardOrdinal46, &ForwardOrdinal47, &ForwardOrdinal48, &ForwardOrdinal49, &ForwardOrdinal50, &ForwardOrdinal51, &ForwardOrdinal52, &ForwardOrdinal53, &ForwardOrdinal54, &ForwardOrdinal55, &ForwardOrdinal56, &ForwardOrdinal57, &ForwardOrdinal58, &ForwardOrdinal59, &ForwardOrdinal60, &ForwardOrdinal61, &ForwardOrdinal62, &ForwardOrdinal63, &ForwardOrdinal64, &ForwardOrdinal65, &ForwardOrdinal66, &ForwardOrdinal67, &ForwardOrdinal68, &ForwardOrdinal69, &ForwardOrdinal70, &ForwardOrdinal71, &ForwardOrdinal72, &ForwardOrdinal73, &ForwardOrdinal74, &ForwardOrdinal75, &ForwardOrdinal76, &ForwardOrdinal77, &ForwardOrdinal78, &ForwardOrdinal79, &ForwardOrdinal80, &ForwardOrdinal81, &ForwardOrdinal82, &ForwardOrdinal83, &ForwardOrdinal84, &ForwardOrdinal85, &ForwardOrdinal86, &ForwardOrdinal87, &ForwardOrdinal88, &ForwardOrdinal89, &ForwardOrdinal90, &ForwardOrdinal91, &ForwardOrdinal92, &ForwardOrdinal93, &ForwardOrdinal94, &ForwardOrdinal95, &ForwardOrdinal96, &ForwardOrdinal97, &ForwardOrdinal98, &ForwardOrdinal99, &ForwardOrdinal100, &ForwardOrdinal101, &ForwardOrdinal102, &ForwardOrdinal103, &ForwardOrdinal104, &ForwardOrdinal105, &ForwardOrdinal106, &ForwardOrdinal107, &ForwardOrdinal108, &ForwardOrdinal109, &ForwardOrdinal110, &ForwardOrdinal111, &ForwardOrdinal112, &ForwardOrdinal113, &ForwardOrdinal114, &ForwardOrdinal115, &ForwardOrdinal116, &ForwardOrdinal117, &ForwardOrdinal118, &ForwardOrdinal119, &ForwardOrdinal120, &ForwardOrdinal121, &ForwardOrdinal122, &ForwardOrdinal123, &ForwardOrdinal124, &ForwardOrdinal125, &ForwardOrdinal126, &ForwardOrdinal127, &ForwardOrdinal128, &ForwardOrdinal129, &ForwardOrdinal130, &ForwardOrdinal131, &ForwardOrdinal132, &ForwardOrdinal133, &ForwardOrdinal134, &ForwardOrdinal135, &ForwardOrdinal136, &ForwardOrdinal137, &ForwardOrdinal138, &ForwardOrdinal139, &ForwardOrdinal140, &ForwardOrdinal141, &ForwardOrdinal142, &ForwardOrdinal143, &ForwardOrdinal144, &ForwardOrdinal145, &ForwardOrdinal146, &ForwardOrdinal147, &ForwardOrdinal148, &ForwardOrdinal149, &ForwardOrdinal150, &ForwardOrdinal151, &ForwardOrdinal152, &ForwardOrdinal153, &ForwardOrdinal154, &ForwardOrdinal155, &ForwardOrdinal156, &ForwardOrdinal157, &ForwardOrdinal158, &ForwardOrdinal159, &ForwardOrdinal160, &ForwardOrdinal161, &ForwardOrdinal162, &ForwardOrdinal163, &ForwardOrdinal164, &ForwardOrdinal165, &ForwardOrdinal166, &ForwardOrdinal167, &ForwardOrdinal168, &ForwardOrdinal169, &ForwardOrdinal170, &ForwardOrdinal171, &ForwardOrdinal172, &ForwardOrdinal173, &ForwardOrdinal174, &ForwardOrdinal175, &ForwardOrdinal176, &ForwardOrdinal177, &ForwardOrdinal178, &ForwardOrdinal179, &ForwardOrdinal180, &ForwardOrdinal181, &ForwardOrdinal182, &ForwardOrdinal183, &ForwardOrdinal184, &ForwardOrdinal185, &ForwardOrdinal186, &ForwardOrdinal187, &ForwardOrdinal188, &ForwardOrdinal189, &ForwardOrdinal190, &ForwardOrdinal191, &ForwardOrdinal192, &ForwardOrdinal193, &ForwardOrdinal194, &ForwardOrdinal195, &ForwardOrdinal196, &ForwardOrdinal197, &ForwardOrdinal198, &ForwardOrdinal199, &ForwardOrdinal200, &ForwardOrdinal201, &ForwardOrdinal202, &ForwardOrdinal203, &ForwardOrdinal204, &ForwardOrdinal205, &ForwardOrdinal206, &ForwardOrdinal207, &ForwardOrdinal208, &ForwardOrdinal209, &ForwardOrdinal210, &ForwardOrdinal211, &ForwardOrdinal212, &ForwardOrdinal213, &ForwardOrdinal214, &ForwardOrdinal215, &ForwardOrdinal216, &ForwardOrdinal217, &ForwardOrdinal218, &ForwardOrdinal219, &ForwardOrdinal220, &ForwardOrdinal221, &ForwardOrdinal222, &ForwardOrdinal223, &ForwardOrdinal224, &ForwardOrdinal225, &ForwardOrdinal226, &ForwardOrdinal227, &ForwardOrdinal228, &ForwardOrdinal229, &ForwardOrdinal230, &ForwardOrdinal231, &ForwardOrdinal232, &ForwardOrdinal233, &ForwardOrdinal234, &ForwardOrdinal235, &ForwardOrdinal236, &ForwardOrdinal237, &ForwardOrdinal238, &ForwardOrdinal239, &ForwardOrdinal240, &ForwardOrdinal241, &ForwardOrdinal242, &ForwardOrdinal243, &ForwardOrdinal244, &ForwardOrdinal245, &ForwardOrdinal246, &ForwardOrdinal247, &ForwardOrdinal248, &ForwardOrdinal249, &ForwardOrdinal250, &ForwardOrdinal251, &ForwardOrdinal252, &ForwardOrdinal253, &ForwardOrdinal254, &ForwardOrdinal255, &ForwardOrdinal256, &ForwardOrdinal257, &ForwardOrdinal258, &ForwardOrdinal259, &ForwardOrdinal260, &ForwardOrdinal261, &ForwardOrdinal262, &ForwardOrdinal263, &ForwardOrdinal264, &ForwardOrdinal265, &ForwardOrdinal266, &ForwardOrdinal267, &ForwardOrdinal268, &ForwardOrdinal269, &ForwardOrdinal270, &ForwardOrdinal271, &ForwardOrdinal272, &ForwardOrdinal273, &ForwardOrdinal274, &ForwardOrdinal275, &ForwardOrdinal276, &ForwardOrdinal277, &ForwardOrdinal278, &ForwardOrdinal279, &ForwardOrdinal280, &ForwardOrdinal281, &ForwardOrdinal282, &ForwardOrdinal283, &ForwardOrdinal284, &ForwardOrdinal285, &ForwardOrdinal286, &ForwardOrdinal287, &ForwardOrdinal288, &ForwardOrdinal289, &ForwardOrdinal290, &ForwardOrdinal291, &ForwardOrdinal292, &ForwardOrdinal293, &ForwardOrdinal294, &ForwardOrdinal295, &ForwardOrdinal296, &ForwardOrdinal297, &ForwardOrdinal298, &ForwardOrdinal299, &ForwardOrdinal300, &ForwardOrdinal301, &ForwardOrdinal302, &ForwardOrdinal303, &ForwardOrdinal304, &ForwardOrdinal305, &ForwardOrdinal306, &ForwardOrdinal307, &ForwardOrdinal308, &ForwardOrdinal309, &ForwardOrdinal310, &ForwardOrdinal311, &ForwardOrdinal312, &ForwardOrdinal313, &ForwardOrdinal314, &ForwardOrdinal315, &ForwardOrdinal316, &ForwardOrdinal317, &ForwardOrdinal318, &ForwardOrdinal319, &ForwardOrdinal320, &ForwardOrdinal321, &ForwardOrdinal322, &ForwardOrdinal323, &ForwardOrdinal324, &ForwardOrdinal325, &ForwardOrdinal326, &ForwardOrdinal327, &ForwardOrdinal328, &ForwardOrdinal329, &ForwardOrdinal330, &ForwardOrdinal331, &ForwardOrdinal332, &ForwardOrdinal333, &ForwardOrdinal334, &ForwardOrdinal335, &ForwardOrdinal336, &ForwardOrdinal337, &ForwardOrdinal338, &ForwardOrdinal339, &ForwardOrdinal340, &ForwardOrdinal341, &ForwardOrdinal342, &ForwardOrdinal343, &ForwardOrdinal344, &ForwardOrdinal345, &ForwardOrdinal346, &ForwardOrdinal347, &ForwardOrdinal348, &ForwardOrdinal349, &ForwardOrdinal350, &ForwardOrdinal351, &ForwardOrdinal352, &ForwardOrdinal353, &ForwardOrdinal354, &ForwardOrdinal355, &ForwardOrdinal356, &ForwardOrdinal357, &ForwardOrdinal358, &ForwardOrdinal359, &ForwardOrdinal360, &ForwardOrdinal361, &ForwardOrdinal362, &ForwardOrdinal363, &ForwardOrdinal364, &ForwardOrdinal365, &ForwardOrdinal366, &ForwardOrdinal367, &ForwardOrdinal368, &ForwardOrdinal369, &ForwardOrdinal370, &ForwardOrdinal371, &ForwardOrdinal372, &ForwardOrdinal373, &ForwardOrdinal374, &ForwardOrdinal375, &ForwardOrdinal376, &ForwardOrdinal377, &ForwardOrdinal378, &ForwardOrdinal379, &ForwardOrdinal380, &ForwardOrdinal381, &ForwardOrdinal382, &ForwardOrdinal383, &ForwardOrdinal384, &ForwardOrdinal385, &ForwardOrdinal386, &ForwardOrdinal387, &ForwardOrdinal388, &ForwardOrdinal389, &ForwardOrdinal390, &ForwardOrdinal391, &ForwardOrdinal392, &ForwardOrdinal393, &ForwardOrdinal394, &ForwardOrdinal395, &ForwardOrdinal396, &ForwardOrdinal397, &ForwardOrdinal398, &ForwardOrdinal399, &ForwardOrdinal400, &ForwardOrdinal401, &ForwardOrdinal402, &ForwardOrdinal403, &ForwardOrdinal404, &ForwardOrdinal405, &ForwardOrdinal406, &ForwardOrdinal407, &ForwardOrdinal408, &ForwardOrdinal409, &ForwardOrdinal410, &ForwardOrdinal411, &ForwardOrdinal412, &ForwardOrdinal413, &ForwardOrdinal414, &ForwardOrdinal415, &ForwardOrdinal416, &ForwardOrdinal417, &ForwardOrdinal418, &ForwardOrdinal419, &ForwardOrdinal420, &ForwardOrdinal421, &ForwardOrdinal422, &ForwardOrdinal423, &ForwardOrdinal424, &ForwardOrdinal425, &ForwardOrdinal426, &ForwardOrdinal427, &ForwardOrdinal428, &ForwardOrdinal429, &ForwardOrdinal430, &ForwardOrdinal431, &ForwardOrdinal432, &ForwardOrdinal433, &ForwardOrdinal434, &ForwardOrdinal435, &ForwardOrdinal436, &ForwardOrdinal437, &ForwardOrdinal438, &ForwardOrdinal439, &ForwardOrdinal440, &ForwardOrdinal441, &ForwardOrdinal442, &ForwardOrdinal443, &ForwardOrdinal444, &ForwardOrdinal445, &ForwardOrdinal446, &ForwardOrdinal447, &ForwardOrdinal448, &ForwardOrdinal449, &ForwardOrdinal450, &ForwardOrdinal451, &ForwardOrdinal452, &ForwardOrdinal453, &ForwardOrdinal454, &ForwardOrdinal455, &ForwardOrdinal456, &ForwardOrdinal457, &ForwardOrdinal458, &ForwardOrdinal459, &ForwardOrdinal460, &ForwardOrdinal461, &ForwardOrdinal462, &ForwardOrdinal463, &ForwardOrdinal464, &ForwardOrdinal465, &ForwardOrdinal466, &ForwardOrdinal467, &ForwardOrdinal468, &ForwardOrdinal469, &ForwardOrdinal470, &ForwardOrdinal471, &ForwardOrdinal472, &ForwardOrdinal473, &ForwardOrdinal474, &ForwardOrdinal475, &ForwardOrdinal476, &ForwardOrdinal477, &ForwardOrdinal478, &ForwardOrdinal479, &ForwardOrdinal480, &ForwardOrdinal481, &ForwardOrdinal482, &ForwardOrdinal483, &ForwardOrdinal484, &ForwardOrdinal485, &ForwardOrdinal486, &ForwardOrdinal487, &ForwardOrdinal488, &ForwardOrdinal489, &ForwardOrdinal490, &ForwardOrdinal491, &ForwardOrdinal492, &ForwardOrdinal493, &ForwardOrdinal494, &ForwardOrdinal495, &ForwardOrdinal496, &ForwardOrdinal497, &ForwardOrdinal498, &ForwardOrdinal499, &ForwardOrdinal500, &ForwardOrdinal501, &ForwardOrdinal502, &ForwardOrdinal503, &ForwardOrdinal504, &ForwardOrdinal505, &ForwardOrdinal506, &ForwardOrdinal507, &ForwardOrdinal508, &ForwardOrdinal509, &ForwardOrdinal510, &ForwardOrdinal511, &ForwardOrdinal512, &ForwardOrdinal513, &ForwardOrdinal514, &ForwardOrdinal515, &ForwardOrdinal516, &ForwardOrdinal517, &ForwardOrdinal518, &ForwardOrdinal519, &ForwardOrdinal520, &ForwardOrdinal521, &ForwardOrdinal522, &ForwardOrdinal523, &ForwardOrdinal524, &ForwardOrdinal525, &ForwardOrdinal526, &ForwardOrdinal527, &ForwardOrdinal528, &ForwardOrdinal529, &ForwardOrdinal530, &ForwardOrdinal531, &ForwardOrdinal532, &ForwardOrdinal533, &ForwardOrdinal534, &ForwardOrdinal535, &ForwardOrdinal536, &ForwardOrdinal537, &ForwardOrdinal538, &ForwardOrdinal539, &ForwardOrdinal540, &ForwardOrdinal541, &ForwardOrdinal542, &ForwardOrdinal543, &ForwardOrdinal544, &ForwardOrdinal545, &ForwardOrdinal546, &ForwardOrdinal547, &ForwardOrdinal548, &ForwardOrdinal549, &ForwardOrdinal550, &ForwardOrdinal551, &ForwardOrdinal552, &ForwardOrdinal553, &ForwardOrdinal554, &ForwardOrdinal555, &ForwardOrdinal556, &ForwardOrdinal557, &ForwardOrdinal558, &ForwardOrdinal559, &ForwardOrdinal560, &ForwardOrdinal561, &ForwardOrdinal562, &ForwardOrdinal563, &ForwardOrdinal564, &ForwardOrdinal565, &ForwardOrdinal566, &ForwardOrdinal567, &ForwardOrdinal568, &ForwardOrdinal569, &ForwardOrdinal570, &ForwardOrdinal571, &ForwardOrdinal572, &ForwardOrdinal573, &ForwardOrdinal574, &ForwardOrdinal575, &ForwardOrdinal576, &ForwardOrdinal577, &ForwardOrdinal578, &ForwardOrdinal579, &ForwardOrdinal580, &ForwardOrdinal581, &ForwardOrdinal582, &ForwardOrdinal583, &ForwardOrdinal584, &ForwardOrdinal585, &ForwardOrdinal586, &ForwardOrdinal587, &ForwardOrdinal588, &ForwardOrdinal589, &ForwardOrdinal590, &ForwardOrdinal591, &ForwardOrdinal592, &ForwardOrdinal593, &ForwardOrdinal594, &ForwardOrdinal595, &ForwardOrdinal596, &ForwardOrdinal597, &ForwardOrdinal598, &ForwardOrdinal599, &ForwardOrdinal600, &ForwardOrdinal601, &ForwardOrdinal602, &ForwardOrdinal603, &ForwardOrdinal604, &ForwardOrdinal605, &ForwardOrdinal606, &ForwardOrdinal607, &ForwardOrdinal608, &ForwardOrdinal609, &ForwardOrdinal610, &ForwardOrdinal611, &ForwardOrdinal612, &ForwardOrdinal613, &ForwardOrdinal614, &ForwardOrdinal615, &ForwardOrdinal616, &ForwardOrdinal617, &ForwardOrdinal618, &ForwardOrdinal619, &ForwardOrdinal620, &ForwardOrdinal621, &ForwardOrdinal622, &ForwardOrdinal623, &ForwardOrdinal624, &ForwardOrdinal625, &ForwardOrdinal626, &ForwardOrdinal627, &ForwardOrdinal628, &ForwardOrdinal629, &ForwardOrdinal630, &ForwardOrdinal631, &ForwardOrdinal632, &ForwardOrdinal633, &ForwardOrdinal634, &ForwardOrdinal635, &ForwardOrdinal636, &ForwardOrdinal637, &ForwardOrdinal638, &ForwardOrdinal639, &ForwardOrdinal640, &ForwardOrdinal641, &ForwardOrdinal642, &ForwardOrdinal643, &ForwardOrdinal644, &ForwardOrdinal645, &ForwardOrdinal646, &ForwardOrdinal647, &ForwardOrdinal648, &ForwardOrdinal649, &ForwardOrdinal650, &ForwardOrdinal651, &ForwardOrdinal652, &ForwardOrdinal653, &ForwardOrdinal654, &ForwardOrdinal655, &ForwardOrdinal656, &ForwardOrdinal657, &ForwardOrdinal658, &ForwardOrdinal659, &ForwardOrdinal660, &ForwardOrdinal661, &ForwardOrdinal662, &ForwardOrdinal663, &ForwardOrdinal664, &ForwardOrdinal665, &ForwardOrdinal666, &ForwardOrdinal667, &ForwardOrdinal668, &ForwardOrdinal669, &ForwardOrdinal670, &ForwardOrdinal671, &ForwardOrdinal672, &ForwardOrdinal673, &ForwardOrdinal674, &ForwardOrdinal675, &ForwardOrdinal676, &ForwardOrdinal677, &ForwardOrdinal678, &ForwardOrdinal679, &ForwardOrdinal680, &ForwardOrdinal681, &ForwardOrdinal682, &ForwardOrdinal683, &ForwardOrdinal684, &ForwardOrdinal685, &ForwardOrdinal686, &ForwardOrdinal687, &ForwardOrdinal688, &ForwardOrdinal689, &ForwardOrdinal690, &ForwardOrdinal691, &ForwardOrdinal692, &ForwardOrdinal693, &ForwardOrdinal694, &ForwardOrdinal695, &ForwardOrdinal696, &ForwardOrdinal697, &ForwardOrdinal698, &ForwardOrdinal699, &ForwardOrdinal700, &ForwardOrdinal701, &ForwardOrdinal702, &ForwardOrdinal703, &ForwardOrdinal704, &ForwardOrdinal705, &ForwardOrdinal706, &ForwardOrdinal707, &ForwardOrdinal708, &ForwardOrdinal709, &ForwardOrdinal710, &ForwardOrdinal711, &ForwardOrdinal712, &ForwardOrdinal713, &ForwardOrdinal714, &ForwardOrdinal715, &ForwardOrdinal716, &ForwardOrdinal717, &ForwardOrdinal718, &ForwardOrdinal719, &ForwardOrdinal720, &ForwardOrdinal721, &ForwardOrdinal722, &ForwardOrdinal723, &ForwardOrdinal724, &ForwardOrdinal725, &ForwardOrdinal726, &ForwardOrdinal727, &ForwardOrdinal728, &ForwardOrdinal729, &ForwardOrdinal730, &ForwardOrdinal731, &ForwardOrdinal732, &ForwardOrdinal733, &ForwardOrdinal734, &ForwardOrdinal735, &ForwardOrdinal736, &ForwardOrdinal737, &ForwardOrdinal738, &ForwardOrdinal739, &ForwardOrdinal740, &ForwardOrdinal741, &ForwardOrdinal742, &ForwardOrdinal743, &ForwardOrdinal744, &ForwardOrdinal745, &ForwardOrdinal746, &ForwardOrdinal747, &ForwardOrdinal748, &ForwardOrdinal749, &ForwardOrdinal750, &ForwardOrdinal751, &ForwardOrdinal752, &ForwardOrdinal753, &ForwardOrdinal754, &ForwardOrdinal755, &ForwardOrdinal756, &ForwardOrdinal757, &ForwardOrdinal758, &ForwardOrdinal759, &ForwardOrdinal760, &ForwardOrdinal761, &ForwardOrdinal762, &ForwardOrdinal763, &ForwardOrdinal764, &ForwardOrdinal765, &ForwardOrdinal766, &ForwardOrdinal767, &ForwardOrdinal768, &ForwardOrdinal769, &ForwardOrdinal770, &ForwardOrdinal771, &ForwardOrdinal772, &ForwardOrdinal773, &ForwardOrdinal774, &ForwardOrdinal775, &ForwardOrdinal776, &ForwardOrdinal777, &ForwardOrdinal778, &ForwardOrdinal779, &ForwardOrdinal780, &ForwardOrdinal781, &ForwardOrdinal782, &ForwardOrdinal783, &ForwardOrdinal784, &ForwardOrdinal785, &ForwardOrdinal786, &ForwardOrdinal787, &ForwardOrdinal788, &ForwardOrdinal789, &ForwardOrdinal790, &ForwardOrdinal791, &ForwardOrdinal792, &ForwardOrdinal793, &ForwardOrdinal794, &ForwardOrdinal795, &ForwardOrdinal796, &ForwardOrdinal797, &ForwardOrdinal798, &ForwardOrdinal799, &ForwardOrdinal800, &ForwardOrdinal801, &ForwardOrdinal802, &ForwardOrdinal803, &ForwardOrdinal804, &ForwardOrdinal805, &ForwardOrdinal806, &ForwardOrdinal807, &ForwardOrdinal808, &ForwardOrdinal809, &ForwardOrdinal810, &ForwardOrdinal811, &ForwardOrdinal812, &ForwardOrdinal813, &ForwardOrdinal814, &ForwardOrdinal815, &ForwardOrdinal816, &ForwardOrdinal817, &ForwardOrdinal818, &ForwardOrdinal819, &ForwardOrdinal820, &ForwardOrdinal821, &ForwardOrdinal822, &ForwardOrdinal823, &ForwardOrdinal824, &ForwardOrdinal825, &ForwardOrdinal826, &ForwardOrdinal827, &ForwardOrdinal828, &ForwardOrdinal829, &ForwardOrdinal830, &ForwardOrdinal831, &ForwardOrdinal832, &ForwardOrdinal833, &ForwardOrdinal834, &ForwardOrdinal835, &ForwardOrdinal836, &ForwardOrdinal837, &ForwardOrdinal838, &ForwardOrdinal839, &ForwardOrdinal840, &ForwardOrdinal841, &ForwardOrdinal842, &ForwardOrdinal843, &ForwardOrdinal844, &ForwardOrdinal845, &ForwardOrdinal846, &ForwardOrdinal847, &ForwardOrdinal848, &ForwardOrdinal849, &ForwardOrdinal850, &ForwardOrdinal851, &ForwardOrdinal852, &ForwardOrdinal853, &ForwardOrdinal854, &ForwardOrdinal855, &ForwardOrdinal856, &ForwardOrdinal857, &ForwardOrdinal858, &ForwardOrdinal859, &ForwardOrdinal860, &ForwardOrdinal861, &ForwardOrdinal862, &ForwardOrdinal863, &ForwardOrdinal864, &ForwardOrdinal865, &ForwardOrdinal866, &ForwardOrdinal867, &ForwardOrdinal868, &ForwardOrdinal869, &ForwardOrdinal870, &ForwardOrdinal871, &ForwardOrdinal872, &ForwardOrdinal873, &ForwardOrdinal874, &ForwardOrdinal875, &ForwardOrdinal876, &ForwardOrdinal877, &ForwardOrdinal878, &ForwardOrdinal879, &ForwardOrdinal880, &ForwardOrdinal881, &ForwardOrdinal882, &ForwardOrdinal883, &ForwardOrdinal884, &ForwardOrdinal885, &ForwardOrdinal886, &ForwardOrdinal887, &ForwardOrdinal888, &ForwardOrdinal889, &ForwardOrdinal890, &ForwardOrdinal891, &ForwardOrdinal892, &ForwardOrdinal893, &ForwardOrdinal894, &ForwardOrdinal895, &ForwardOrdinal896, &ForwardOrdinal897, &ForwardOrdinal898, &ForwardOrdinal899, &ForwardOrdinal900, &ForwardOrdinal901, &ForwardOrdinal902, &ForwardOrdinal903, &ForwardOrdinal904, &ForwardOrdinal905, &ForwardOrdinal906, &ForwardOrdinal907, &ForwardOrdinal908, &ForwardOrdinal909, &ForwardOrdinal910, &ForwardOrdinal911, &ForwardOrdinal912, &ForwardOrdinal913, &ForwardOrdinal914, &ForwardOrdinal915, &ForwardOrdinal916, &ForwardOrdinal917, &ForwardOrdinal918, &ForwardOrdinal919, &ForwardOrdinal920, &ForwardOrdinal921, &ForwardOrdinal922, &ForwardOrdinal923, &ForwardOrdinal924, &ForwardOrdinal925, &ForwardOrdinal926, &ForwardOrdinal927, &ForwardOrdinal928, &ForwardOrdinal929, &ForwardOrdinal930, &ForwardOrdinal931, &ForwardOrdinal932, &ForwardOrdinal933, &ForwardOrdinal934, &ForwardOrdinal935, &ForwardOrdinal936, &ForwardOrdinal937, &ForwardOrdinal938, &ForwardOrdinal939, &ForwardOrdinal940, &ForwardOrdinal941, &ForwardOrdinal942, &ForwardOrdinal943, &ForwardOrdinal944, &ForwardOrdinal945, &ForwardOrdinal946, &ForwardOrdinal947, &ForwardOrdinal948, &ForwardOrdinal949, &ForwardOrdinal950, &ForwardOrdinal951, &ForwardOrdinal952, &ForwardOrdinal953, &ForwardOrdinal954, &ForwardOrdinal955, &ForwardOrdinal956, &ForwardOrdinal957, &ForwardOrdinal958, &ForwardOrdinal959, &ForwardOrdinal960, &ForwardOrdinal961, &ForwardOrdinal962, &ForwardOrdinal963, &ForwardOrdinal964, &ForwardOrdinal965, &ForwardOrdinal966, &ForwardOrdinal967, &ForwardOrdinal968, &ForwardOrdinal969, &ForwardOrdinal970, &ForwardOrdinal971, &ForwardOrdinal972, &ForwardOrdinal973, &ForwardOrdinal974, &ForwardOrdinal975, &ForwardOrdinal976, &ForwardOrdinal977, &ForwardOrdinal978, &ForwardOrdinal979, &ForwardOrdinal980, &ForwardOrdinal981, &ForwardOrdinal982, &ForwardOrdinal983, &ForwardOrdinal984, &ForwardOrdinal985, &ForwardOrdinal986, &ForwardOrdinal987, &ForwardOrdinal988, &ForwardOrdinal989, &ForwardOrdinal990, &ForwardOrdinal991, &ForwardOrdinal992, &ForwardOrdinal993, &ForwardOrdinal994, &ForwardOrdinal995, &ForwardOrdinal996, &ForwardOrdinal997, &ForwardOrdinal998, &ForwardOrdinal999, &ForwardOrdinal1000, &ForwardOrdinal1001, &ForwardOrdinal1002, &ForwardOrdinal1003, &ForwardOrdinal1004, &ForwardOrdinal1005, &ForwardOrdinal1006, &ForwardOrdinal1007, &ForwardOrdinal1008, &ForwardOrdinal1009, &ForwardOrdinal1010, &ForwardOrdinal1011, &ForwardOrdinal1012, &ForwardOrdinal1013, &ForwardOrdinal1014, &ForwardOrdinal1015, &ForwardOrdinal1016, &ForwardOrdinal1017, &ForwardOrdinal1018, &ForwardOrdinal1019 }; GenerateForwardSharedFunction(0) GenerateForwardSharedFunction(1) GenerateForwardSharedFunction(2) GenerateForwardSharedFunction(3) GenerateForwardSharedFunction(4) GenerateForwardSharedFunction(5) GenerateForwardSharedFunction(6) GenerateForwardSharedFunction(7) GenerateForwardSharedFunction(8) GenerateForwardSharedFunction(9) GenerateForwardSharedFunction(10) GenerateForwardSharedFunction(11) GenerateForwardSharedFunction(12) GenerateForwardSharedFunction(13) GenerateForwardSharedFunction(14) GenerateForwardSharedFunction(15) GenerateForwardSharedFunction(16) GenerateForwardSharedFunction(17) GenerateForwardSharedFunction(18) GenerateForwardSharedFunction(19) GenerateForwardSharedFunction(20) GenerateForwardSharedFunction(21) GenerateForwardSharedFunction(22) GenerateForwardSharedFunction(23) GenerateForwardSharedFunction(24) GenerateForwardSharedFunction(25) GenerateForwardSharedFunction(26) GenerateForwardSharedFunction(27) GenerateForwardSharedFunction(28) GenerateForwardSharedFunction(29) GenerateForwardSharedFunction(30) GenerateForwardSharedFunction(31) GenerateForwardSharedFunction(32) GenerateForwardSharedFunction(33) GenerateForwardSharedFunction(34) GenerateForwardSharedFunction(35) GenerateForwardSharedFunction(36) GenerateForwardSharedFunction(37) GenerateForwardSharedFunction(38) GenerateForwardSharedFunction(39) GenerateForwardSharedFunction(40) GenerateForwardSharedFunction(41) GenerateForwardSharedFunction(42) GenerateForwardSharedFunction(43) GenerateForwardSharedFunction(44) GenerateForwardSharedFunction(45) GenerateForwardSharedFunction(46) GenerateForwardSharedFunction(47) GenerateForwardSharedFunction(48) GenerateForwardSharedFunction(49) std::vector forwardSharedAddresses = { &ForwardShared0, &ForwardShared1, &ForwardShared2, &ForwardShared3, &ForwardShared4, &ForwardShared5, &ForwardShared6, &ForwardShared7, &ForwardShared8, &ForwardShared9, &ForwardShared10, &ForwardShared11, &ForwardShared12, &ForwardShared13, &ForwardShared14, &ForwardShared15, &ForwardShared16, &ForwardShared17, &ForwardShared18, &ForwardShared19, &ForwardShared20, &ForwardShared21, &ForwardShared22, &ForwardShared23, &ForwardShared24, &ForwardShared25, &ForwardShared26, &ForwardShared27, &ForwardShared28, &ForwardShared29, &ForwardShared30, &ForwardShared31, &ForwardShared32, &ForwardShared33, &ForwardShared34, &ForwardShared35, &ForwardShared36, &ForwardShared37, &ForwardShared38, &ForwardShared39, &ForwardShared40, &ForwardShared41, &ForwardShared42, &ForwardShared43, &ForwardShared44, &ForwardShared45, &ForwardShared46, &ForwardShared47, &ForwardShared48, &ForwardShared49 }; #ifndef _WIN64 #define Export_(index, name) __pragma(comment(linker, "/export:"#name"=_Forward"#index)) #define ExportOrdinal_(ordinal) __pragma(comment(linker, "/export:"#ordinal"=_ForwardOrdinal"#ordinal",@"#ordinal",NONAME")) #define ExportShared_(index, name) __pragma(comment(linker, "/export:"#name"=_ForwardShared"##index)) #else #define Export_(index, name) __pragma(comment(linker, "/export:"#name"=Forward"#index)) #define ExportOrdinal_(ordinal) __pragma(comment(linker, "/export:"#ordinal"=ForwardOrdinal"#ordinal",@"#ordinal",NONAME")) #define ExportShared_(index, name) __pragma(comment(linker, "/export:"#name"=ForwardShared"##index)) #endif #define Export(index, name) Export_(index, name) #define ExportOrdinal(ordinal) ExportOrdinal_(ordinal) #define ExportShared(index, name) ExportShared_(index, name) // Handle export names shared by multiple DLLs // Note: it's fine if these are duplicated in the normal export list #define ExpandNumber_(num) #num #define ExpandNumber(num) ExpandNumber_(num) ExportShared(ExpandNumber(SharedExportIndex_DllCanUnloadNow), DllCanUnloadNow) ExportShared(ExpandNumber(SharedExportIndex_DllGetClassObject), DllGetClassObject) ExportShared(ExpandNumber(SharedExportIndex_SetAppCompatStringPointer), SetAppCompatStringPointer) // Export an amount of ordinals equal to highest amount of exports exported by one of the supported DLLs ExportOrdinal(1) ExportOrdinal(2) ExportOrdinal(3) ExportOrdinal(4) ExportOrdinal(5) ExportOrdinal(6) ExportOrdinal(7) ExportOrdinal(8) ExportOrdinal(9) ExportOrdinal(10) ExportOrdinal(11) ExportOrdinal(12) ExportOrdinal(13) ExportOrdinal(14) ExportOrdinal(15) ExportOrdinal(16) ExportOrdinal(17) ExportOrdinal(18) ExportOrdinal(19) ExportOrdinal(20) ExportOrdinal(21) ExportOrdinal(22) ExportOrdinal(23) ExportOrdinal(24) ExportOrdinal(25) ExportOrdinal(26) ExportOrdinal(27) ExportOrdinal(28) ExportOrdinal(29) ExportOrdinal(30) ExportOrdinal(31) ExportOrdinal(32) ExportOrdinal(33) ExportOrdinal(34) ExportOrdinal(35) ExportOrdinal(36) ExportOrdinal(37) ExportOrdinal(38) ExportOrdinal(39) ExportOrdinal(40) ExportOrdinal(41) ExportOrdinal(42) ExportOrdinal(43) ExportOrdinal(44) ExportOrdinal(45) ExportOrdinal(46) ExportOrdinal(47) ExportOrdinal(48) ExportOrdinal(49) ExportOrdinal(50) ExportOrdinal(51) ExportOrdinal(52) ExportOrdinal(53) ExportOrdinal(54) ExportOrdinal(55) ExportOrdinal(56) ExportOrdinal(57) ExportOrdinal(58) ExportOrdinal(59) ExportOrdinal(60) ExportOrdinal(61) ExportOrdinal(62) ExportOrdinal(63) ExportOrdinal(64) ExportOrdinal(65) ExportOrdinal(66) ExportOrdinal(67) ExportOrdinal(68) ExportOrdinal(69) ExportOrdinal(70) ExportOrdinal(71) ExportOrdinal(72) ExportOrdinal(73) ExportOrdinal(74) ExportOrdinal(75) ExportOrdinal(76) ExportOrdinal(77) ExportOrdinal(78) ExportOrdinal(79) ExportOrdinal(80) ExportOrdinal(81) ExportOrdinal(82) ExportOrdinal(83) ExportOrdinal(84) ExportOrdinal(85) ExportOrdinal(86) ExportOrdinal(87) ExportOrdinal(88) ExportOrdinal(89) ExportOrdinal(90) ExportOrdinal(91) ExportOrdinal(92) ExportOrdinal(93) ExportOrdinal(94) ExportOrdinal(95) ExportOrdinal(96) ExportOrdinal(97) ExportOrdinal(98) ExportOrdinal(99) ExportOrdinal(100) ExportOrdinal(101) ExportOrdinal(102) ExportOrdinal(103) ExportOrdinal(104) ExportOrdinal(105) ExportOrdinal(106) ExportOrdinal(107) ExportOrdinal(108) ExportOrdinal(109) ExportOrdinal(110) ExportOrdinal(111) ExportOrdinal(112) ExportOrdinal(113) ExportOrdinal(114) ExportOrdinal(115) ExportOrdinal(116) ExportOrdinal(117) ExportOrdinal(118) ExportOrdinal(119) ExportOrdinal(120) ExportOrdinal(121) ExportOrdinal(122) ExportOrdinal(123) ExportOrdinal(124) ExportOrdinal(125) ExportOrdinal(126) ExportOrdinal(127) ExportOrdinal(128) ExportOrdinal(129) ExportOrdinal(130) ExportOrdinal(131) ExportOrdinal(132) ExportOrdinal(133) ExportOrdinal(134) ExportOrdinal(135) ExportOrdinal(136) ExportOrdinal(137) ExportOrdinal(138) ExportOrdinal(139) ExportOrdinal(140) ExportOrdinal(141) ExportOrdinal(142) ExportOrdinal(143) ExportOrdinal(144) ExportOrdinal(145) ExportOrdinal(146) ExportOrdinal(147) ExportOrdinal(148) ExportOrdinal(149) ExportOrdinal(150) ExportOrdinal(151) ExportOrdinal(152) ExportOrdinal(153) ExportOrdinal(154) ExportOrdinal(155) ExportOrdinal(156) ExportOrdinal(157) ExportOrdinal(158) ExportOrdinal(159) ExportOrdinal(160) ExportOrdinal(161) ExportOrdinal(162) ExportOrdinal(163) ExportOrdinal(164) ExportOrdinal(165) ExportOrdinal(166) ExportOrdinal(167) ExportOrdinal(168) ExportOrdinal(169) ExportOrdinal(170) ExportOrdinal(171) ExportOrdinal(172) ExportOrdinal(173) ExportOrdinal(174) ExportOrdinal(175) ExportOrdinal(176) ExportOrdinal(177) ExportOrdinal(178) ExportOrdinal(179) ExportOrdinal(180) ExportOrdinal(181) ExportOrdinal(182) ExportOrdinal(183) ExportOrdinal(184) ExportOrdinal(185) ExportOrdinal(186) ExportOrdinal(187) ExportOrdinal(188) ExportOrdinal(189) ExportOrdinal(190) ExportOrdinal(191) ExportOrdinal(192) ExportOrdinal(193) ExportOrdinal(194) ExportOrdinal(195) ExportOrdinal(196) ExportOrdinal(197) ExportOrdinal(198) ExportOrdinal(199) ExportOrdinal(200) ExportOrdinal(201) ExportOrdinal(202) ExportOrdinal(203) ExportOrdinal(204) ExportOrdinal(205) ExportOrdinal(206) ExportOrdinal(207) ExportOrdinal(208) ExportOrdinal(209) ExportOrdinal(210) ExportOrdinal(211) ExportOrdinal(212) ExportOrdinal(213) ExportOrdinal(214) ExportOrdinal(215) ExportOrdinal(216) ExportOrdinal(217) ExportOrdinal(218) ExportOrdinal(219) ExportOrdinal(220) ExportOrdinal(221) ExportOrdinal(222) ExportOrdinal(223) ExportOrdinal(224) ExportOrdinal(225) ExportOrdinal(226) ExportOrdinal(227) ExportOrdinal(228) ExportOrdinal(229) ExportOrdinal(230) ExportOrdinal(231) ExportOrdinal(232) ExportOrdinal(233) ExportOrdinal(234) ExportOrdinal(235) ExportOrdinal(236) ExportOrdinal(237) ExportOrdinal(238) ExportOrdinal(239) ExportOrdinal(240) ExportOrdinal(241) ExportOrdinal(242) ExportOrdinal(243) ExportOrdinal(244) ExportOrdinal(245) ExportOrdinal(246) ExportOrdinal(247) ExportOrdinal(248) ExportOrdinal(249) ExportOrdinal(250) ExportOrdinal(251) ExportOrdinal(252) ExportOrdinal(253) ExportOrdinal(254) ExportOrdinal(255) ExportOrdinal(256) ExportOrdinal(257) ExportOrdinal(258) ExportOrdinal(259) ExportOrdinal(260) ExportOrdinal(261) ExportOrdinal(262) ExportOrdinal(263) ExportOrdinal(264) ExportOrdinal(265) ExportOrdinal(266) ExportOrdinal(267) ExportOrdinal(268) ExportOrdinal(269) ExportOrdinal(270) ExportOrdinal(271) ExportOrdinal(272) ExportOrdinal(273) ExportOrdinal(274) ExportOrdinal(275) ExportOrdinal(276) ExportOrdinal(277) ExportOrdinal(278) ExportOrdinal(279) ExportOrdinal(280) ExportOrdinal(281) ExportOrdinal(282) ExportOrdinal(283) ExportOrdinal(284) ExportOrdinal(285) ExportOrdinal(286) ExportOrdinal(287) ExportOrdinal(288) ExportOrdinal(289) ExportOrdinal(290) ExportOrdinal(291) ExportOrdinal(292) ExportOrdinal(293) ExportOrdinal(294) ExportOrdinal(295) ExportOrdinal(296) ExportOrdinal(297) ExportOrdinal(298) ExportOrdinal(299) ExportOrdinal(300) ExportOrdinal(301) ExportOrdinal(302) ExportOrdinal(303) ExportOrdinal(304) ExportOrdinal(305) ExportOrdinal(306) ExportOrdinal(307) ExportOrdinal(308) ExportOrdinal(309) ExportOrdinal(310) ExportOrdinal(311) ExportOrdinal(312) ExportOrdinal(313) ExportOrdinal(314) ExportOrdinal(315) ExportOrdinal(316) ExportOrdinal(317) ExportOrdinal(318) ExportOrdinal(319) ExportOrdinal(320) ExportOrdinal(321) ExportOrdinal(322) ExportOrdinal(323) ExportOrdinal(324) ExportOrdinal(325) ExportOrdinal(326) ExportOrdinal(327) ExportOrdinal(328) ExportOrdinal(329) ExportOrdinal(330) ExportOrdinal(331) ExportOrdinal(332) ExportOrdinal(333) ExportOrdinal(334) ExportOrdinal(335) ExportOrdinal(336) ExportOrdinal(337) ExportOrdinal(338) ExportOrdinal(339) ExportOrdinal(340) ExportOrdinal(341) ExportOrdinal(342) ExportOrdinal(343) ExportOrdinal(344) ExportOrdinal(345) ExportOrdinal(346) ExportOrdinal(347) ExportOrdinal(348) ExportOrdinal(349) ExportOrdinal(350) ExportOrdinal(351) ExportOrdinal(352) ExportOrdinal(353) ExportOrdinal(354) ExportOrdinal(355) ExportOrdinal(356) ExportOrdinal(357) ExportOrdinal(358) ExportOrdinal(359) ExportOrdinal(360) ExportOrdinal(361) ExportOrdinal(362) ExportOrdinal(363) ExportOrdinal(364) ExportOrdinal(365) ExportOrdinal(366) ExportOrdinal(367) ExportOrdinal(368) ExportOrdinal(369) ExportOrdinal(370) ExportOrdinal(371) ExportOrdinal(372) ExportOrdinal(373) ExportOrdinal(374) ExportOrdinal(375) ExportOrdinal(376) ExportOrdinal(377) ExportOrdinal(378) ExportOrdinal(379) ExportOrdinal(380) ExportOrdinal(381) ExportOrdinal(382) ExportOrdinal(383) ExportOrdinal(384) ExportOrdinal(385) ExportOrdinal(386) ExportOrdinal(387) ExportOrdinal(388) ExportOrdinal(389) ExportOrdinal(390) ExportOrdinal(391) ExportOrdinal(392) ExportOrdinal(393) ExportOrdinal(394) ExportOrdinal(395) ExportOrdinal(396) ExportOrdinal(397) ExportOrdinal(398) ExportOrdinal(399) ExportOrdinal(400) ExportOrdinal(401) ExportOrdinal(402) ExportOrdinal(403) ExportOrdinal(404) ExportOrdinal(405) ExportOrdinal(406) ExportOrdinal(407) ExportOrdinal(408) ExportOrdinal(409) ExportOrdinal(410) ExportOrdinal(411) ExportOrdinal(412) ExportOrdinal(413) ExportOrdinal(414) ExportOrdinal(415) ExportOrdinal(416) ExportOrdinal(417) ExportOrdinal(418) ExportOrdinal(419) ExportOrdinal(420) ExportOrdinal(421) ExportOrdinal(422) ExportOrdinal(423) ExportOrdinal(424) ExportOrdinal(425) ExportOrdinal(426) ExportOrdinal(427) ExportOrdinal(428) ExportOrdinal(429) ExportOrdinal(430) ExportOrdinal(431) ExportOrdinal(432) ExportOrdinal(433) ExportOrdinal(434) ExportOrdinal(435) ExportOrdinal(436) ExportOrdinal(437) ExportOrdinal(438) ExportOrdinal(439) ExportOrdinal(440) ExportOrdinal(441) ExportOrdinal(442) ExportOrdinal(443) ExportOrdinal(444) ExportOrdinal(445) ExportOrdinal(446) ExportOrdinal(447) ExportOrdinal(448) ExportOrdinal(449) ExportOrdinal(450) ExportOrdinal(451) ExportOrdinal(452) ExportOrdinal(453) ExportOrdinal(454) ExportOrdinal(455) ExportOrdinal(456) ExportOrdinal(457) ExportOrdinal(458) ExportOrdinal(459) ExportOrdinal(460) ExportOrdinal(461) ExportOrdinal(462) ExportOrdinal(463) ExportOrdinal(464) ExportOrdinal(465) ExportOrdinal(466) ExportOrdinal(467) ExportOrdinal(468) ExportOrdinal(469) ExportOrdinal(470) ExportOrdinal(471) ExportOrdinal(472) ExportOrdinal(473) ExportOrdinal(474) ExportOrdinal(475) ExportOrdinal(476) ExportOrdinal(477) ExportOrdinal(478) ExportOrdinal(479) ExportOrdinal(480) ExportOrdinal(481) ExportOrdinal(482) ExportOrdinal(483) ExportOrdinal(484) ExportOrdinal(485) ExportOrdinal(486) ExportOrdinal(487) ExportOrdinal(488) ExportOrdinal(489) ExportOrdinal(490) ExportOrdinal(491) ExportOrdinal(492) ExportOrdinal(493) ExportOrdinal(494) ExportOrdinal(495) ExportOrdinal(496) ExportOrdinal(497) ExportOrdinal(498) ExportOrdinal(499) ExportOrdinal(500) ExportOrdinal(501) ExportOrdinal(502) ExportOrdinal(503) ExportOrdinal(504) ExportOrdinal(505) ExportOrdinal(506) ExportOrdinal(507) ExportOrdinal(508) ExportOrdinal(509) ExportOrdinal(510) ExportOrdinal(511) ExportOrdinal(512) ExportOrdinal(513) ExportOrdinal(514) ExportOrdinal(515) ExportOrdinal(516) ExportOrdinal(517) ExportOrdinal(518) ExportOrdinal(519) ExportOrdinal(520) ExportOrdinal(521) ExportOrdinal(522) ExportOrdinal(523) ExportOrdinal(524) ExportOrdinal(525) ExportOrdinal(526) ExportOrdinal(527) ExportOrdinal(528) ExportOrdinal(529) ExportOrdinal(530) ExportOrdinal(531) ExportOrdinal(532) ExportOrdinal(533) ExportOrdinal(534) ExportOrdinal(535) ExportOrdinal(536) ExportOrdinal(537) ExportOrdinal(538) ExportOrdinal(539) ExportOrdinal(540) ExportOrdinal(541) ExportOrdinal(542) ExportOrdinal(543) ExportOrdinal(544) ExportOrdinal(545) ExportOrdinal(546) ExportOrdinal(547) ExportOrdinal(548) ExportOrdinal(549) ExportOrdinal(550) ExportOrdinal(551) ExportOrdinal(552) ExportOrdinal(553) ExportOrdinal(554) ExportOrdinal(555) ExportOrdinal(556) ExportOrdinal(557) ExportOrdinal(558) ExportOrdinal(559) ExportOrdinal(560) ExportOrdinal(561) ExportOrdinal(562) ExportOrdinal(563) ExportOrdinal(564) ExportOrdinal(565) ExportOrdinal(566) ExportOrdinal(567) ExportOrdinal(568) ExportOrdinal(569) ExportOrdinal(570) ExportOrdinal(571) ExportOrdinal(572) ExportOrdinal(573) ExportOrdinal(574) ExportOrdinal(575) ExportOrdinal(576) ExportOrdinal(577) ExportOrdinal(578) ExportOrdinal(579) ExportOrdinal(580) ExportOrdinal(581) ExportOrdinal(582) ExportOrdinal(583) ExportOrdinal(584) ExportOrdinal(585) ExportOrdinal(586) ExportOrdinal(587) ExportOrdinal(588) ExportOrdinal(589) ExportOrdinal(590) ExportOrdinal(591) ExportOrdinal(592) ExportOrdinal(593) ExportOrdinal(594) ExportOrdinal(595) ExportOrdinal(596) ExportOrdinal(597) ExportOrdinal(598) ExportOrdinal(599) ExportOrdinal(600) ExportOrdinal(601) ExportOrdinal(602) ExportOrdinal(603) ExportOrdinal(604) ExportOrdinal(605) ExportOrdinal(606) ExportOrdinal(607) ExportOrdinal(608) ExportOrdinal(609) ExportOrdinal(610) ExportOrdinal(611) ExportOrdinal(612) ExportOrdinal(613) ExportOrdinal(614) ExportOrdinal(615) ExportOrdinal(616) ExportOrdinal(617) ExportOrdinal(618) ExportOrdinal(619) ExportOrdinal(620) ExportOrdinal(621) ExportOrdinal(622) ExportOrdinal(623) ExportOrdinal(624) ExportOrdinal(625) ExportOrdinal(626) ExportOrdinal(627) ExportOrdinal(628) ExportOrdinal(629) ExportOrdinal(630) ExportOrdinal(631) ExportOrdinal(632) ExportOrdinal(633) ExportOrdinal(634) ExportOrdinal(635) ExportOrdinal(636) ExportOrdinal(637) ExportOrdinal(638) ExportOrdinal(639) ExportOrdinal(640) ExportOrdinal(641) ExportOrdinal(642) ExportOrdinal(643) ExportOrdinal(644) ExportOrdinal(645) ExportOrdinal(646) ExportOrdinal(647) ExportOrdinal(648) ExportOrdinal(649) ExportOrdinal(650) ExportOrdinal(651) ExportOrdinal(652) ExportOrdinal(653) ExportOrdinal(654) ExportOrdinal(655) ExportOrdinal(656) ExportOrdinal(657) ExportOrdinal(658) ExportOrdinal(659) ExportOrdinal(660) ExportOrdinal(661) ExportOrdinal(662) ExportOrdinal(663) ExportOrdinal(664) ExportOrdinal(665) ExportOrdinal(666) ExportOrdinal(667) ExportOrdinal(668) ExportOrdinal(669) ExportOrdinal(670) ExportOrdinal(671) ExportOrdinal(672) ExportOrdinal(673) ExportOrdinal(674) ExportOrdinal(675) ExportOrdinal(676) ExportOrdinal(677) ExportOrdinal(678) ExportOrdinal(679) ExportOrdinal(680) ExportOrdinal(681) ExportOrdinal(682) ExportOrdinal(683) ExportOrdinal(684) ExportOrdinal(685) ExportOrdinal(686) ExportOrdinal(687) ExportOrdinal(688) ExportOrdinal(689) ExportOrdinal(690) ExportOrdinal(691) ExportOrdinal(692) ExportOrdinal(693) ExportOrdinal(694) ExportOrdinal(695) ExportOrdinal(696) ExportOrdinal(697) ExportOrdinal(698) ExportOrdinal(699) ExportOrdinal(700) ExportOrdinal(701) ExportOrdinal(702) ExportOrdinal(703) ExportOrdinal(704) ExportOrdinal(705) ExportOrdinal(706) ExportOrdinal(707) ExportOrdinal(708) ExportOrdinal(709) ExportOrdinal(710) ExportOrdinal(711) ExportOrdinal(712) ExportOrdinal(713) ExportOrdinal(714) ExportOrdinal(715) ExportOrdinal(716) ExportOrdinal(717) ExportOrdinal(718) ExportOrdinal(719) ExportOrdinal(720) ExportOrdinal(721) ExportOrdinal(722) ExportOrdinal(723) ExportOrdinal(724) ExportOrdinal(725) ExportOrdinal(726) ExportOrdinal(727) ExportOrdinal(728) ExportOrdinal(729) ExportOrdinal(730) ExportOrdinal(731) ExportOrdinal(732) ExportOrdinal(733) ExportOrdinal(734) ExportOrdinal(735) ExportOrdinal(736) ExportOrdinal(737) ExportOrdinal(738) ExportOrdinal(739) ExportOrdinal(740) ExportOrdinal(741) ExportOrdinal(742) ExportOrdinal(743) ExportOrdinal(744) ExportOrdinal(745) ExportOrdinal(746) ExportOrdinal(747) ExportOrdinal(748) ExportOrdinal(749) ExportOrdinal(750) ExportOrdinal(751) ExportOrdinal(752) ExportOrdinal(753) ExportOrdinal(754) ExportOrdinal(755) ExportOrdinal(756) ExportOrdinal(757) ExportOrdinal(758) ExportOrdinal(759) ExportOrdinal(760) ExportOrdinal(761) ExportOrdinal(762) ExportOrdinal(763) ExportOrdinal(764) ExportOrdinal(765) ExportOrdinal(766) ExportOrdinal(767) ExportOrdinal(768) ExportOrdinal(769) ExportOrdinal(770) ExportOrdinal(771) ExportOrdinal(772) ExportOrdinal(773) ExportOrdinal(774) ExportOrdinal(775) ExportOrdinal(776) ExportOrdinal(777) ExportOrdinal(778) ExportOrdinal(779) ExportOrdinal(780) ExportOrdinal(781) ExportOrdinal(782) ExportOrdinal(783) ExportOrdinal(784) ExportOrdinal(785) ExportOrdinal(786) ExportOrdinal(787) ExportOrdinal(788) ExportOrdinal(789) ExportOrdinal(790) ExportOrdinal(791) ExportOrdinal(792) ExportOrdinal(793) ExportOrdinal(794) ExportOrdinal(795) ExportOrdinal(796) ExportOrdinal(797) ExportOrdinal(798) ExportOrdinal(799) ExportOrdinal(800) ExportOrdinal(801) ExportOrdinal(802) ExportOrdinal(803) ExportOrdinal(804) ExportOrdinal(805) ExportOrdinal(806) ExportOrdinal(807) ExportOrdinal(808) ExportOrdinal(809) ExportOrdinal(810) ExportOrdinal(811) ExportOrdinal(812) ExportOrdinal(813) ExportOrdinal(814) ExportOrdinal(815) ExportOrdinal(816) ExportOrdinal(817) ExportOrdinal(818) ExportOrdinal(819) ExportOrdinal(820) ExportOrdinal(821) ExportOrdinal(822) ExportOrdinal(823) ExportOrdinal(824) ExportOrdinal(825) ExportOrdinal(826) ExportOrdinal(827) ExportOrdinal(828) ExportOrdinal(829) ExportOrdinal(830) ExportOrdinal(831) ExportOrdinal(832) ExportOrdinal(833) ExportOrdinal(834) ExportOrdinal(835) ExportOrdinal(836) ExportOrdinal(837) ExportOrdinal(838) ExportOrdinal(839) ExportOrdinal(840) ExportOrdinal(841) ExportOrdinal(842) ExportOrdinal(843) ExportOrdinal(844) ExportOrdinal(845) ExportOrdinal(846) ExportOrdinal(847) ExportOrdinal(848) ExportOrdinal(849) ExportOrdinal(850) ExportOrdinal(851) ExportOrdinal(852) ExportOrdinal(853) ExportOrdinal(854) ExportOrdinal(855) ExportOrdinal(856) ExportOrdinal(857) ExportOrdinal(858) ExportOrdinal(859) ExportOrdinal(860) ExportOrdinal(861) ExportOrdinal(862) ExportOrdinal(863) ExportOrdinal(864) ExportOrdinal(865) ExportOrdinal(866) ExportOrdinal(867) ExportOrdinal(868) ExportOrdinal(869) ExportOrdinal(870) ExportOrdinal(871) ExportOrdinal(872) ExportOrdinal(873) ExportOrdinal(874) ExportOrdinal(875) ExportOrdinal(876) ExportOrdinal(877) ExportOrdinal(878) ExportOrdinal(879) ExportOrdinal(880) ExportOrdinal(881) ExportOrdinal(882) ExportOrdinal(883) ExportOrdinal(884) ExportOrdinal(885) ExportOrdinal(886) ExportOrdinal(887) ExportOrdinal(888) ExportOrdinal(889) ExportOrdinal(890) ExportOrdinal(891) ExportOrdinal(892) ExportOrdinal(893) ExportOrdinal(894) ExportOrdinal(895) ExportOrdinal(896) ExportOrdinal(897) ExportOrdinal(898) ExportOrdinal(899) ExportOrdinal(900) ExportOrdinal(901) ExportOrdinal(902) ExportOrdinal(903) ExportOrdinal(904) ExportOrdinal(905) ExportOrdinal(906) ExportOrdinal(907) ExportOrdinal(908) ExportOrdinal(909) ExportOrdinal(910) ExportOrdinal(911) ExportOrdinal(912) ExportOrdinal(913) ExportOrdinal(914) ExportOrdinal(915) ExportOrdinal(916) ExportOrdinal(917) ExportOrdinal(918) ExportOrdinal(919) ExportOrdinal(920) ExportOrdinal(921) ExportOrdinal(922) ExportOrdinal(923) ExportOrdinal(924) ExportOrdinal(925) ExportOrdinal(926) ExportOrdinal(927) ExportOrdinal(928) ExportOrdinal(929) ExportOrdinal(930) ExportOrdinal(931) ExportOrdinal(932) ExportOrdinal(933) ExportOrdinal(934) ExportOrdinal(935) ExportOrdinal(936) ExportOrdinal(937) ExportOrdinal(938) ExportOrdinal(939) ExportOrdinal(940) ExportOrdinal(941) ExportOrdinal(942) ExportOrdinal(943) ExportOrdinal(944) ExportOrdinal(945) ExportOrdinal(946) ExportOrdinal(947) ExportOrdinal(948) ExportOrdinal(949) ExportOrdinal(950) ExportOrdinal(951) ExportOrdinal(952) ExportOrdinal(953) ExportOrdinal(954) ExportOrdinal(955) ExportOrdinal(956) ExportOrdinal(957) ExportOrdinal(958) ExportOrdinal(959) ExportOrdinal(960) ExportOrdinal(961) ExportOrdinal(962) ExportOrdinal(963) ExportOrdinal(964) ExportOrdinal(965) ExportOrdinal(966) ExportOrdinal(967) ExportOrdinal(968) ExportOrdinal(969) ExportOrdinal(970) ExportOrdinal(971) ExportOrdinal(972) ExportOrdinal(973) ExportOrdinal(974) ExportOrdinal(975) ExportOrdinal(976) ExportOrdinal(977) ExportOrdinal(978) ExportOrdinal(979) ExportOrdinal(980) ExportOrdinal(981) ExportOrdinal(982) ExportOrdinal(983) ExportOrdinal(984) ExportOrdinal(985) ExportOrdinal(986) ExportOrdinal(987) ExportOrdinal(988) ExportOrdinal(989) ExportOrdinal(990) ExportOrdinal(991) ExportOrdinal(992) ExportOrdinal(993) ExportOrdinal(994) ExportOrdinal(995) ExportOrdinal(996) ExportOrdinal(997) ExportOrdinal(998) ExportOrdinal(999) ExportOrdinal(1000) ExportOrdinal(1001) ExportOrdinal(1002) ExportOrdinal(1003) ExportOrdinal(1004) ExportOrdinal(1005) ExportOrdinal(1006) ExportOrdinal(1007) ExportOrdinal(1008) ExportOrdinal(1009) ExportOrdinal(1010) ExportOrdinal(1011) ExportOrdinal(1012) ExportOrdinal(1013) ExportOrdinal(1014) ExportOrdinal(1015) ExportOrdinal(1016) ExportOrdinal(1017) ExportOrdinal(1018) ExportOrdinal(1019) // dxgi Export(0, ApplyCompatResolutionQuirking) Export(1, CompatString) Export(2, CompatValue) Export(3, DXGIDumpJournal) Export(4, PIXBeginCapture) Export(5, PIXEndCapture) Export(6, PIXGetCaptureState) Export(7, SetAppCompatStringPointer) Export(8, UpdateHMDEmulationStatus) Export(9, CreateDXGIFactory) Export(10, CreateDXGIFactory1) Export(11, CreateDXGIFactory2) Export(12, DXGID3D10CreateDevice) Export(13, DXGID3D10CreateLayeredDevice) Export(14, DXGID3D10GetLayeredDeviceSize) Export(15, DXGID3D10RegisterLayers) Export(16, DXGIDeclareAdapterRemovalSupport) Export(17, DXGIGetDebugInterface1) Export(18, DXGIReportAdapterConfiguration) // d3d10 Export(0, D3D10CompileEffectFromMemory) Export(1, D3D10CompileShader) Export(2, D3D10CreateBlob) Export(3, D3D10CreateDevice) Export(4, D3D10CreateDeviceAndSwapChain) Export(5, D3D10CreateEffectFromMemory) Export(6, D3D10CreateEffectPoolFromMemory) Export(7, D3D10CreateStateBlock) Export(8, D3D10DisassembleEffect) Export(9, D3D10DisassembleShader) Export(10, D3D10GetGeometryShaderProfile) Export(11, D3D10GetInputAndOutputSignatureBlob) Export(12, D3D10GetInputSignatureBlob) Export(13, D3D10GetOutputSignatureBlob) Export(14, D3D10GetPixelShaderProfile) Export(15, D3D10GetShaderDebugInfo) Export(16, D3D10GetVersion) Export(17, D3D10GetVertexShaderProfile) Export(18, D3D10PreprocessShader) Export(19, D3D10ReflectShader) Export(20, D3D10RegisterLayers) Export(21, D3D10StateBlockMaskDifference) Export(22, D3D10StateBlockMaskDisableAll) Export(23, D3D10StateBlockMaskDisableCapture) Export(24, D3D10StateBlockMaskEnableAll) Export(25, D3D10StateBlockMaskEnableCapture) Export(26, D3D10StateBlockMaskGetSetting) Export(27, D3D10StateBlockMaskIntersect) Export(28, D3D10StateBlockMaskUnion) // d3d11 Export(0, D3D11CreateDeviceForD3D12) Export(1, D3DKMTCloseAdapter) Export(2, D3DKMTDestroyAllocation) Export(3, D3DKMTDestroyContext) Export(4, D3DKMTDestroyDevice) Export(5, D3DKMTDestroySynchronizationObject) Export(6, D3DKMTPresent) Export(7, D3DKMTQueryAdapterInfo) Export(8, D3DKMTSetDisplayPrivateDriverFormat) Export(9, D3DKMTSignalSynchronizationObject) Export(10, D3DKMTUnlock) Export(11, D3DKMTWaitForSynchronizationObject) Export(12, EnableFeatureLevelUpgrade) Export(13, OpenAdapter10) Export(14, OpenAdapter10_2) Export(15, CreateDirect3D11DeviceFromDXGIDevice) Export(16, CreateDirect3D11SurfaceFromDXGISurface) Export(17, D3D11CoreCreateDevice) Export(18, D3D11CoreCreateLayeredDevice) Export(19, D3D11CoreGetLayeredDeviceSize) Export(20, D3D11CoreRegisterLayers) Export(21, D3D11CreateDevice) Export(22, D3D11CreateDeviceAndSwapChain) Export(23, D3D11On12CreateDevice) Export(24, D3DKMTCreateAllocation) Export(25, D3DKMTCreateContext) Export(26, D3DKMTCreateDevice) Export(27, D3DKMTCreateSynchronizationObject) Export(28, D3DKMTEscape) Export(29, D3DKMTGetContextSchedulingPriority) Export(30, D3DKMTGetDeviceState) Export(31, D3DKMTGetDisplayModeList) Export(32, D3DKMTGetMultisampleMethodList) Export(33, D3DKMTGetRuntimeData) Export(34, D3DKMTGetSharedPrimaryHandle) Export(35, D3DKMTLock) Export(36, D3DKMTOpenAdapterFromHdc) Export(37, D3DKMTOpenResource) Export(38, D3DKMTQueryAllocationResidency) Export(39, D3DKMTQueryResourceInfo) Export(40, D3DKMTRender) Export(41, D3DKMTSetAllocationPriority) Export(42, D3DKMTSetContextSchedulingPriority) Export(43, D3DKMTSetDisplayMode) Export(44, D3DKMTSetGammaRamp) Export(45, D3DKMTSetVidPnSourceOwner) Export(46, D3DKMTWaitForVerticalBlankEvent) Export(47, D3DPerformance_BeginEvent) Export(48, D3DPerformance_EndEvent) Export(49, D3DPerformance_GetStatus) Export(50, D3DPerformance_SetMarker) // d3d12 - crashes for some unknown reason! Export(0, GetBehaviorValue) Export(1, D3D12CreateDevice) Export(2, D3D12GetDebugInterface) Export(3, SetAppCompatStringPointer) Export(4, D3D12CoreCreateLayeredDevice) Export(5, D3D12CoreGetLayeredDeviceSize) Export(6, D3D12CoreRegisterLayers) Export(7, D3D12CreateRootSignatureDeserializer) Export(8, D3D12CreateVersionedRootSignatureDeserializer) Export(9, D3D12DeviceRemovedExtendedData) Export(10, D3D12EnableExperimentalFeatures) Export(11, D3D12GetInterface) Export(12, D3D12PIXEventsReplaceBlock) Export(13, D3D12PIXGetThreadInfo) Export(14, D3D12PIXNotifyWakeFromFenceSignal) Export(15, D3D12PIXReportCounter) Export(16, D3D12SerializeRootSignature) Export(17, D3D12SerializeVersionedRootSignature) // dinput8 Export(0, DirectInput8Create) Export(1, DllCanUnloadNow) Export(2, DllGetClassObject) Export(3, DllRegisterServer) Export(4, DllUnregisterServer) Export(5, GetdfDIJoystick) // xinput1_4 AND xinput1_3 Export(0, DllMain) Export(1, XInputGetState) Export(2, XInputSetState) Export(3, XInputGetCapabilities) Export(4, XInputEnable) Export(5, XInputGetBatteryInformation) Export(6, XInputGetKeystroke) Export(7, XInputGetAudioDeviceIds) // steam_api64 #ifdef _WIN64 Export(0, GetHSteamPipe) Export(1, GetHSteamUser) Export(2, SteamAPI_GetHSteamPipe) Export(3, SteamAPI_GetHSteamUser) Export(4, SteamAPI_GetSteamInstallPath) Export(5, SteamAPI_ISteamAppList_GetAppBuildId) Export(6, SteamAPI_ISteamAppList_GetAppInstallDir) Export(7, SteamAPI_ISteamAppList_GetAppName) Export(8, SteamAPI_ISteamAppList_GetInstalledApps) Export(9, SteamAPI_ISteamAppList_GetNumInstalledApps) Export(10, SteamAPI_ISteamApps_BGetDLCDataByIndex) Export(11, SteamAPI_ISteamApps_BIsAppInstalled) Export(12, SteamAPI_ISteamApps_BIsCybercafe) Export(13, SteamAPI_ISteamApps_BIsDlcInstalled) Export(14, SteamAPI_ISteamApps_BIsLowViolence) Export(15, SteamAPI_ISteamApps_BIsSubscribed) Export(16, SteamAPI_ISteamApps_BIsSubscribedApp) Export(17, SteamAPI_ISteamApps_BIsSubscribedFromFamilySharing) Export(18, SteamAPI_ISteamApps_BIsSubscribedFromFreeWeekend) Export(19, SteamAPI_ISteamApps_BIsTimedTrial) Export(20, SteamAPI_ISteamApps_BIsVACBanned) Export(21, SteamAPI_ISteamApps_GetAppBuildId) Export(22, SteamAPI_ISteamApps_GetAppInstallDir) Export(23, SteamAPI_ISteamApps_GetAppOwner) Export(24, SteamAPI_ISteamApps_GetAvailableGameLanguages) Export(25, SteamAPI_ISteamApps_GetCurrentBetaName) Export(26, SteamAPI_ISteamApps_GetCurrentGameLanguage) Export(27, SteamAPI_ISteamApps_GetDLCCount) Export(28, SteamAPI_ISteamApps_GetDlcDownloadProgress) Export(29, SteamAPI_ISteamApps_GetEarliestPurchaseUnixTime) Export(30, SteamAPI_ISteamApps_GetFileDetails) Export(31, SteamAPI_ISteamApps_GetInstalledDepots) Export(32, SteamAPI_ISteamApps_GetLaunchCommandLine) Export(33, SteamAPI_ISteamApps_GetLaunchQueryParam) Export(34, SteamAPI_ISteamApps_InstallDLC) Export(35, SteamAPI_ISteamApps_MarkContentCorrupt) Export(36, SteamAPI_ISteamApps_RequestAllProofOfPurchaseKeys) Export(37, SteamAPI_ISteamApps_RequestAppProofOfPurchaseKey) Export(38, SteamAPI_ISteamApps_UninstallDLC) Export(39, SteamAPI_ISteamClient_BReleaseSteamPipe) Export(40, SteamAPI_ISteamClient_BShutdownIfAllPipesClosed) Export(41, SteamAPI_ISteamClient_ConnectToGlobalUser) Export(42, SteamAPI_ISteamClient_CreateLocalUser) Export(43, SteamAPI_ISteamClient_CreateSteamPipe) Export(44, SteamAPI_ISteamClient_GetIPCCallCount) Export(45, SteamAPI_ISteamClient_GetISteamAppList) Export(46, SteamAPI_ISteamClient_GetISteamApps) Export(47, SteamAPI_ISteamClient_GetISteamController) Export(48, SteamAPI_ISteamClient_GetISteamFriends) Export(49, SteamAPI_ISteamClient_GetISteamGameSearch) Export(50, SteamAPI_ISteamClient_GetISteamGameServer) Export(51, SteamAPI_ISteamClient_GetISteamGameServerStats) Export(52, SteamAPI_ISteamClient_GetISteamGenericInterface) Export(53, SteamAPI_ISteamClient_GetISteamHTMLSurface) Export(54, SteamAPI_ISteamClient_GetISteamHTTP) Export(55, SteamAPI_ISteamClient_GetISteamInput) Export(56, SteamAPI_ISteamClient_GetISteamInventory) Export(57, SteamAPI_ISteamClient_GetISteamMatchmaking) Export(58, SteamAPI_ISteamClient_GetISteamMatchmakingServers) Export(59, SteamAPI_ISteamClient_GetISteamMusic) Export(60, SteamAPI_ISteamClient_GetISteamMusicRemote) Export(61, SteamAPI_ISteamClient_GetISteamNetworking) Export(62, SteamAPI_ISteamClient_GetISteamParentalSettings) Export(63, SteamAPI_ISteamClient_GetISteamParties) Export(64, SteamAPI_ISteamClient_GetISteamRemotePlay) Export(65, SteamAPI_ISteamClient_GetISteamRemoteStorage) Export(66, SteamAPI_ISteamClient_GetISteamScreenshots) Export(67, SteamAPI_ISteamClient_GetISteamUGC) Export(68, SteamAPI_ISteamClient_GetISteamUser) Export(69, SteamAPI_ISteamClient_GetISteamUserStats) Export(70, SteamAPI_ISteamClient_GetISteamUtils) Export(71, SteamAPI_ISteamClient_GetISteamVideo) Export(72, SteamAPI_ISteamClient_ReleaseUser) Export(73, SteamAPI_ISteamClient_SetLocalIPBinding) Export(74, SteamAPI_ISteamClient_SetWarningMessageHook) Export(75, SteamAPI_ISteamController_ActivateActionSet) Export(76, SteamAPI_ISteamController_ActivateActionSetLayer) Export(77, SteamAPI_ISteamController_DeactivateActionSetLayer) Export(78, SteamAPI_ISteamController_DeactivateAllActionSetLayers) Export(79, SteamAPI_ISteamController_GetActionOriginFromXboxOrigin) Export(80, SteamAPI_ISteamController_GetActionSetHandle) Export(81, SteamAPI_ISteamController_GetActiveActionSetLayers) Export(82, SteamAPI_ISteamController_GetAnalogActionData) Export(83, SteamAPI_ISteamController_GetAnalogActionHandle) Export(84, SteamAPI_ISteamController_GetAnalogActionOrigins) Export(85, SteamAPI_ISteamController_GetConnectedControllers) Export(86, SteamAPI_ISteamController_GetControllerBindingRevision) Export(87, SteamAPI_ISteamController_GetControllerForGamepadIndex) Export(88, SteamAPI_ISteamController_GetCurrentActionSet) Export(89, SteamAPI_ISteamController_GetDigitalActionData) Export(90, SteamAPI_ISteamController_GetDigitalActionHandle) Export(91, SteamAPI_ISteamController_GetDigitalActionOrigins) Export(92, SteamAPI_ISteamController_GetGamepadIndexForController) Export(93, SteamAPI_ISteamController_GetGlyphForActionOrigin) Export(94, SteamAPI_ISteamController_GetGlyphForXboxOrigin) Export(95, SteamAPI_ISteamController_GetInputTypeForHandle) Export(96, SteamAPI_ISteamController_GetMotionData) Export(97, SteamAPI_ISteamController_GetStringForActionOrigin) Export(98, SteamAPI_ISteamController_GetStringForXboxOrigin) Export(99, SteamAPI_ISteamController_Init) Export(100, SteamAPI_ISteamController_RunFrame) Export(101, SteamAPI_ISteamController_SetLEDColor) Export(102, SteamAPI_ISteamController_ShowBindingPanel) Export(103, SteamAPI_ISteamController_Shutdown) Export(104, SteamAPI_ISteamController_StopAnalogActionMomentum) Export(105, SteamAPI_ISteamController_TranslateActionOrigin) Export(106, SteamAPI_ISteamController_TriggerHapticPulse) Export(107, SteamAPI_ISteamController_TriggerRepeatedHapticPulse) Export(108, SteamAPI_ISteamController_TriggerVibration) Export(109, SteamAPI_ISteamFriends_ActivateGameOverlay) Export(110, SteamAPI_ISteamFriends_ActivateGameOverlayInviteDialog) Export(111, SteamAPI_ISteamFriends_ActivateGameOverlayInviteDialogConnectString) Export(112, SteamAPI_ISteamFriends_ActivateGameOverlayRemotePlayTogetherInviteDialog) Export(113, SteamAPI_ISteamFriends_ActivateGameOverlayToStore) Export(114, SteamAPI_ISteamFriends_ActivateGameOverlayToUser) Export(115, SteamAPI_ISteamFriends_ActivateGameOverlayToWebPage) Export(116, SteamAPI_ISteamFriends_ClearRichPresence) Export(117, SteamAPI_ISteamFriends_CloseClanChatWindowInSteam) Export(118, SteamAPI_ISteamFriends_DownloadClanActivityCounts) Export(119, SteamAPI_ISteamFriends_EnumerateFollowingList) Export(120, SteamAPI_ISteamFriends_GetChatMemberByIndex) Export(121, SteamAPI_ISteamFriends_GetClanActivityCounts) Export(122, SteamAPI_ISteamFriends_GetClanByIndex) Export(123, SteamAPI_ISteamFriends_GetClanChatMemberCount) Export(124, SteamAPI_ISteamFriends_GetClanChatMessage) Export(125, SteamAPI_ISteamFriends_GetClanCount) Export(126, SteamAPI_ISteamFriends_GetClanName) Export(127, SteamAPI_ISteamFriends_GetClanOfficerByIndex) Export(128, SteamAPI_ISteamFriends_GetClanOfficerCount) Export(129, SteamAPI_ISteamFriends_GetClanOwner) Export(130, SteamAPI_ISteamFriends_GetClanTag) Export(131, SteamAPI_ISteamFriends_GetCoplayFriend) Export(132, SteamAPI_ISteamFriends_GetCoplayFriendCount) Export(133, SteamAPI_ISteamFriends_GetFollowerCount) Export(134, SteamAPI_ISteamFriends_GetFriendByIndex) Export(135, SteamAPI_ISteamFriends_GetFriendCoplayGame) Export(136, SteamAPI_ISteamFriends_GetFriendCoplayTime) Export(137, SteamAPI_ISteamFriends_GetFriendCount) Export(138, SteamAPI_ISteamFriends_GetFriendCountFromSource) Export(139, SteamAPI_ISteamFriends_GetFriendFromSourceByIndex) Export(140, SteamAPI_ISteamFriends_GetFriendGamePlayed) Export(141, SteamAPI_ISteamFriends_GetFriendMessage) Export(142, SteamAPI_ISteamFriends_GetFriendPersonaName) Export(143, SteamAPI_ISteamFriends_GetFriendPersonaNameHistory) Export(144, SteamAPI_ISteamFriends_GetFriendPersonaState) Export(145, SteamAPI_ISteamFriends_GetFriendRelationship) Export(146, SteamAPI_ISteamFriends_GetFriendRichPresence) Export(147, SteamAPI_ISteamFriends_GetFriendRichPresenceKeyByIndex) Export(148, SteamAPI_ISteamFriends_GetFriendRichPresenceKeyCount) Export(149, SteamAPI_ISteamFriends_GetFriendSteamLevel) Export(150, SteamAPI_ISteamFriends_GetFriendsGroupCount) Export(151, SteamAPI_ISteamFriends_GetFriendsGroupIDByIndex) Export(152, SteamAPI_ISteamFriends_GetFriendsGroupMembersCount) Export(153, SteamAPI_ISteamFriends_GetFriendsGroupMembersList) Export(154, SteamAPI_ISteamFriends_GetFriendsGroupName) Export(155, SteamAPI_ISteamFriends_GetLargeFriendAvatar) Export(156, SteamAPI_ISteamFriends_GetMediumFriendAvatar) Export(157, SteamAPI_ISteamFriends_GetNumChatsWithUnreadPriorityMessages) Export(158, SteamAPI_ISteamFriends_GetPersonaName) Export(159, SteamAPI_ISteamFriends_GetPersonaState) Export(160, SteamAPI_ISteamFriends_GetPlayerNickname) Export(161, SteamAPI_ISteamFriends_GetSmallFriendAvatar) Export(162, SteamAPI_ISteamFriends_GetUserRestrictions) Export(163, SteamAPI_ISteamFriends_HasFriend) Export(164, SteamAPI_ISteamFriends_InviteUserToGame) Export(165, SteamAPI_ISteamFriends_IsClanChatAdmin) Export(166, SteamAPI_ISteamFriends_IsClanChatWindowOpenInSteam) Export(167, SteamAPI_ISteamFriends_IsClanOfficialGameGroup) Export(168, SteamAPI_ISteamFriends_IsClanPublic) Export(169, SteamAPI_ISteamFriends_IsFollowing) Export(170, SteamAPI_ISteamFriends_IsUserInSource) Export(171, SteamAPI_ISteamFriends_JoinClanChatRoom) Export(172, SteamAPI_ISteamFriends_LeaveClanChatRoom) Export(173, SteamAPI_ISteamFriends_OpenClanChatWindowInSteam) Export(174, SteamAPI_ISteamFriends_RegisterProtocolInOverlayBrowser) Export(175, SteamAPI_ISteamFriends_ReplyToFriendMessage) Export(176, SteamAPI_ISteamFriends_RequestClanOfficerList) Export(177, SteamAPI_ISteamFriends_RequestFriendRichPresence) Export(178, SteamAPI_ISteamFriends_RequestUserInformation) Export(179, SteamAPI_ISteamFriends_SendClanChatMessage) Export(180, SteamAPI_ISteamFriends_SetInGameVoiceSpeaking) Export(181, SteamAPI_ISteamFriends_SetListenForFriendsMessages) Export(182, SteamAPI_ISteamFriends_SetPersonaName) Export(183, SteamAPI_ISteamFriends_SetPlayedWith) Export(184, SteamAPI_ISteamFriends_SetRichPresence) Export(185, SteamAPI_ISteamGameSearch_AcceptGame) Export(186, SteamAPI_ISteamGameSearch_AddGameSearchParams) Export(187, SteamAPI_ISteamGameSearch_CancelRequestPlayersForGame) Export(188, SteamAPI_ISteamGameSearch_DeclineGame) Export(189, SteamAPI_ISteamGameSearch_EndGame) Export(190, SteamAPI_ISteamGameSearch_EndGameSearch) Export(191, SteamAPI_ISteamGameSearch_HostConfirmGameStart) Export(192, SteamAPI_ISteamGameSearch_RequestPlayersForGame) Export(193, SteamAPI_ISteamGameSearch_RetrieveConnectionDetails) Export(194, SteamAPI_ISteamGameSearch_SearchForGameSolo) Export(195, SteamAPI_ISteamGameSearch_SearchForGameWithLobby) Export(196, SteamAPI_ISteamGameSearch_SetConnectionDetails) Export(197, SteamAPI_ISteamGameSearch_SetGameHostParams) Export(198, SteamAPI_ISteamGameSearch_SubmitPlayerResult) Export(199, SteamAPI_ISteamGameServerStats_ClearUserAchievement) Export(200, SteamAPI_ISteamGameServerStats_GetUserAchievement) Export(201, SteamAPI_ISteamGameServerStats_GetUserStatFloat) Export(202, SteamAPI_ISteamGameServerStats_GetUserStatInt32) Export(203, SteamAPI_ISteamGameServerStats_RequestUserStats) Export(204, SteamAPI_ISteamGameServerStats_SetUserAchievement) Export(205, SteamAPI_ISteamGameServerStats_SetUserStatFloat) Export(206, SteamAPI_ISteamGameServerStats_SetUserStatInt32) Export(207, SteamAPI_ISteamGameServerStats_StoreUserStats) Export(208, SteamAPI_ISteamGameServerStats_UpdateUserAvgRateStat) Export(209, SteamAPI_ISteamGameServer_AssociateWithClan) Export(210, SteamAPI_ISteamGameServer_BLoggedOn) Export(211, SteamAPI_ISteamGameServer_BSecure) Export(212, SteamAPI_ISteamGameServer_BUpdateUserData) Export(213, SteamAPI_ISteamGameServer_BeginAuthSession) Export(214, SteamAPI_ISteamGameServer_CancelAuthTicket) Export(215, SteamAPI_ISteamGameServer_ClearAllKeyValues) Export(216, SteamAPI_ISteamGameServer_ComputeNewPlayerCompatibility) Export(217, SteamAPI_ISteamGameServer_CreateUnauthenticatedUserConnection) Export(218, SteamAPI_ISteamGameServer_EnableHeartbeats) Export(219, SteamAPI_ISteamGameServer_EndAuthSession) Export(220, SteamAPI_ISteamGameServer_ForceHeartbeat) Export(221, SteamAPI_ISteamGameServer_GetAuthSessionTicket) Export(222, SteamAPI_ISteamGameServer_GetGameplayStats) Export(223, SteamAPI_ISteamGameServer_GetNextOutgoingPacket) Export(224, SteamAPI_ISteamGameServer_GetPublicIP) Export(225, SteamAPI_ISteamGameServer_GetServerReputation) Export(226, SteamAPI_ISteamGameServer_GetSteamID) Export(227, SteamAPI_ISteamGameServer_HandleIncomingPacket) Export(228, SteamAPI_ISteamGameServer_LogOff) Export(229, SteamAPI_ISteamGameServer_LogOn) Export(230, SteamAPI_ISteamGameServer_LogOnAnonymous) Export(231, SteamAPI_ISteamGameServer_RequestUserGroupStatus) Export(232, SteamAPI_ISteamGameServer_SendUserConnectAndAuthenticate) Export(233, SteamAPI_ISteamGameServer_SendUserDisconnect) Export(234, SteamAPI_ISteamGameServer_SetBotPlayerCount) Export(235, SteamAPI_ISteamGameServer_SetDedicatedServer) Export(236, SteamAPI_ISteamGameServer_SetGameData) Export(237, SteamAPI_ISteamGameServer_SetGameDescription) Export(238, SteamAPI_ISteamGameServer_SetGameTags) Export(239, SteamAPI_ISteamGameServer_SetHeartbeatInterval) Export(240, SteamAPI_ISteamGameServer_SetKeyValue) Export(241, SteamAPI_ISteamGameServer_SetMapName) Export(242, SteamAPI_ISteamGameServer_SetMaxPlayerCount) Export(243, SteamAPI_ISteamGameServer_SetModDir) Export(244, SteamAPI_ISteamGameServer_SetPasswordProtected) Export(245, SteamAPI_ISteamGameServer_SetProduct) Export(246, SteamAPI_ISteamGameServer_SetRegion) Export(247, SteamAPI_ISteamGameServer_SetServerName) Export(248, SteamAPI_ISteamGameServer_SetSpectatorPort) Export(249, SteamAPI_ISteamGameServer_SetSpectatorServerName) Export(250, SteamAPI_ISteamGameServer_UserHasLicenseForApp) Export(251, SteamAPI_ISteamGameServer_WasRestartRequested) Export(252, SteamAPI_ISteamHTMLSurface_AddHeader) Export(253, SteamAPI_ISteamHTMLSurface_AllowStartRequest) Export(254, SteamAPI_ISteamHTMLSurface_CopyToClipboard) Export(255, SteamAPI_ISteamHTMLSurface_CreateBrowser) Export(256, SteamAPI_ISteamHTMLSurface_ExecuteJavascript) Export(257, SteamAPI_ISteamHTMLSurface_FileLoadDialogResponse) Export(258, SteamAPI_ISteamHTMLSurface_Find) Export(259, SteamAPI_ISteamHTMLSurface_GetLinkAtPosition) Export(260, SteamAPI_ISteamHTMLSurface_GoBack) Export(261, SteamAPI_ISteamHTMLSurface_GoForward) Export(262, SteamAPI_ISteamHTMLSurface_Init) Export(263, SteamAPI_ISteamHTMLSurface_JSDialogResponse) Export(264, SteamAPI_ISteamHTMLSurface_KeyChar) Export(265, SteamAPI_ISteamHTMLSurface_KeyDown) Export(266, SteamAPI_ISteamHTMLSurface_KeyUp) Export(267, SteamAPI_ISteamHTMLSurface_LoadURL) Export(268, SteamAPI_ISteamHTMLSurface_MouseDoubleClick) Export(269, SteamAPI_ISteamHTMLSurface_MouseDown) Export(270, SteamAPI_ISteamHTMLSurface_MouseMove) Export(271, SteamAPI_ISteamHTMLSurface_MouseUp) Export(272, SteamAPI_ISteamHTMLSurface_MouseWheel) Export(273, SteamAPI_ISteamHTMLSurface_OpenDeveloperTools) Export(274, SteamAPI_ISteamHTMLSurface_PasteFromClipboard) Export(275, SteamAPI_ISteamHTMLSurface_Reload) Export(276, SteamAPI_ISteamHTMLSurface_RemoveBrowser) Export(277, SteamAPI_ISteamHTMLSurface_SetBackgroundMode) Export(278, SteamAPI_ISteamHTMLSurface_SetCookie) Export(279, SteamAPI_ISteamHTMLSurface_SetDPIScalingFactor) Export(280, SteamAPI_ISteamHTMLSurface_SetHorizontalScroll) Export(281, SteamAPI_ISteamHTMLSurface_SetKeyFocus) Export(282, SteamAPI_ISteamHTMLSurface_SetPageScaleFactor) Export(283, SteamAPI_ISteamHTMLSurface_SetSize) Export(284, SteamAPI_ISteamHTMLSurface_SetVerticalScroll) Export(285, SteamAPI_ISteamHTMLSurface_Shutdown) Export(286, SteamAPI_ISteamHTMLSurface_StopFind) Export(287, SteamAPI_ISteamHTMLSurface_StopLoad) Export(288, SteamAPI_ISteamHTMLSurface_ViewSource) Export(289, SteamAPI_ISteamHTTP_CreateCookieContainer) Export(290, SteamAPI_ISteamHTTP_CreateHTTPRequest) Export(291, SteamAPI_ISteamHTTP_DeferHTTPRequest) Export(292, SteamAPI_ISteamHTTP_GetHTTPDownloadProgressPct) Export(293, SteamAPI_ISteamHTTP_GetHTTPRequestWasTimedOut) Export(294, SteamAPI_ISteamHTTP_GetHTTPResponseBodyData) Export(295, SteamAPI_ISteamHTTP_GetHTTPResponseBodySize) Export(296, SteamAPI_ISteamHTTP_GetHTTPResponseHeaderSize) Export(297, SteamAPI_ISteamHTTP_GetHTTPResponseHeaderValue) Export(298, SteamAPI_ISteamHTTP_GetHTTPStreamingResponseBodyData) Export(299, SteamAPI_ISteamHTTP_PrioritizeHTTPRequest) Export(300, SteamAPI_ISteamHTTP_ReleaseCookieContainer) Export(301, SteamAPI_ISteamHTTP_ReleaseHTTPRequest) Export(302, SteamAPI_ISteamHTTP_SendHTTPRequest) Export(303, SteamAPI_ISteamHTTP_SendHTTPRequestAndStreamResponse) Export(304, SteamAPI_ISteamHTTP_SetCookie) Export(305, SteamAPI_ISteamHTTP_SetHTTPRequestAbsoluteTimeoutMS) Export(306, SteamAPI_ISteamHTTP_SetHTTPRequestContextValue) Export(307, SteamAPI_ISteamHTTP_SetHTTPRequestCookieContainer) Export(308, SteamAPI_ISteamHTTP_SetHTTPRequestGetOrPostParameter) Export(309, SteamAPI_ISteamHTTP_SetHTTPRequestHeaderValue) Export(310, SteamAPI_ISteamHTTP_SetHTTPRequestNetworkActivityTimeout) Export(311, SteamAPI_ISteamHTTP_SetHTTPRequestRawPostBody) Export(312, SteamAPI_ISteamHTTP_SetHTTPRequestRequiresVerifiedCertificate) Export(313, SteamAPI_ISteamHTTP_SetHTTPRequestUserAgentInfo) Export(314, SteamAPI_ISteamInput_ActivateActionSet) Export(315, SteamAPI_ISteamInput_ActivateActionSetLayer) Export(316, SteamAPI_ISteamInput_DeactivateActionSetLayer) Export(317, SteamAPI_ISteamInput_DeactivateAllActionSetLayers) Export(318, SteamAPI_ISteamInput_GetActionOriginFromXboxOrigin) Export(319, SteamAPI_ISteamInput_GetActionSetHandle) Export(320, SteamAPI_ISteamInput_GetActiveActionSetLayers) Export(321, SteamAPI_ISteamInput_GetAnalogActionData) Export(322, SteamAPI_ISteamInput_GetAnalogActionHandle) Export(323, SteamAPI_ISteamInput_GetAnalogActionOrigins) Export(324, SteamAPI_ISteamInput_GetConnectedControllers) Export(325, SteamAPI_ISteamInput_GetControllerForGamepadIndex) Export(326, SteamAPI_ISteamInput_GetCurrentActionSet) Export(327, SteamAPI_ISteamInput_GetDeviceBindingRevision) Export(328, SteamAPI_ISteamInput_GetDigitalActionData) Export(329, SteamAPI_ISteamInput_GetDigitalActionHandle) Export(330, SteamAPI_ISteamInput_GetDigitalActionOrigins) Export(331, SteamAPI_ISteamInput_GetGamepadIndexForController) Export(332, SteamAPI_ISteamInput_GetGlyphForActionOrigin) Export(333, SteamAPI_ISteamInput_GetGlyphForXboxOrigin) Export(334, SteamAPI_ISteamInput_GetInputTypeForHandle) Export(335, SteamAPI_ISteamInput_GetMotionData) Export(336, SteamAPI_ISteamInput_GetRemotePlaySessionID) Export(337, SteamAPI_ISteamInput_GetStringForActionOrigin) Export(338, SteamAPI_ISteamInput_GetStringForXboxOrigin) Export(339, SteamAPI_ISteamInput_Init) Export(340, SteamAPI_ISteamInput_RunFrame) Export(341, SteamAPI_ISteamInput_SetLEDColor) Export(342, SteamAPI_ISteamInput_ShowBindingPanel) Export(343, SteamAPI_ISteamInput_Shutdown) Export(344, SteamAPI_ISteamInput_StopAnalogActionMomentum) Export(345, SteamAPI_ISteamInput_TranslateActionOrigin) Export(346, SteamAPI_ISteamInput_TriggerHapticPulse) Export(347, SteamAPI_ISteamInput_TriggerRepeatedHapticPulse) Export(348, SteamAPI_ISteamInput_TriggerVibration) Export(349, SteamAPI_ISteamInventory_AddPromoItem) Export(350, SteamAPI_ISteamInventory_AddPromoItems) Export(351, SteamAPI_ISteamInventory_CheckResultSteamID) Export(352, SteamAPI_ISteamInventory_ConsumeItem) Export(353, SteamAPI_ISteamInventory_DeserializeResult) Export(354, SteamAPI_ISteamInventory_DestroyResult) Export(355, SteamAPI_ISteamInventory_ExchangeItems) Export(356, SteamAPI_ISteamInventory_GenerateItems) Export(357, SteamAPI_ISteamInventory_GetAllItems) Export(358, SteamAPI_ISteamInventory_GetEligiblePromoItemDefinitionIDs) Export(359, SteamAPI_ISteamInventory_GetItemDefinitionIDs) Export(360, SteamAPI_ISteamInventory_GetItemDefinitionProperty) Export(361, SteamAPI_ISteamInventory_GetItemPrice) Export(362, SteamAPI_ISteamInventory_GetItemsByID) Export(363, SteamAPI_ISteamInventory_GetItemsWithPrices) Export(364, SteamAPI_ISteamInventory_GetNumItemsWithPrices) Export(365, SteamAPI_ISteamInventory_GetResultItemProperty) Export(366, SteamAPI_ISteamInventory_GetResultItems) Export(367, SteamAPI_ISteamInventory_GetResultStatus) Export(368, SteamAPI_ISteamInventory_GetResultTimestamp) Export(369, SteamAPI_ISteamInventory_GrantPromoItems) Export(370, SteamAPI_ISteamInventory_InspectItem) Export(371, SteamAPI_ISteamInventory_LoadItemDefinitions) Export(372, SteamAPI_ISteamInventory_RemoveProperty) Export(373, SteamAPI_ISteamInventory_RequestEligiblePromoItemDefinitionsIDs) Export(374, SteamAPI_ISteamInventory_RequestPrices) Export(375, SteamAPI_ISteamInventory_SendItemDropHeartbeat) Export(376, SteamAPI_ISteamInventory_SerializeResult) Export(377, SteamAPI_ISteamInventory_SetPropertyBool) Export(378, SteamAPI_ISteamInventory_SetPropertyFloat) Export(379, SteamAPI_ISteamInventory_SetPropertyInt64) Export(380, SteamAPI_ISteamInventory_SetPropertyString) Export(381, SteamAPI_ISteamInventory_StartPurchase) Export(382, SteamAPI_ISteamInventory_StartUpdateProperties) Export(383, SteamAPI_ISteamInventory_SubmitUpdateProperties) Export(384, SteamAPI_ISteamInventory_TradeItems) Export(385, SteamAPI_ISteamInventory_TransferItemQuantity) Export(386, SteamAPI_ISteamInventory_TriggerItemDrop) Export(387, SteamAPI_ISteamMatchmakingPingResponse_ServerFailedToRespond) Export(388, SteamAPI_ISteamMatchmakingPingResponse_ServerResponded) Export(389, SteamAPI_ISteamMatchmakingPlayersResponse_AddPlayerToList) Export(390, SteamAPI_ISteamMatchmakingPlayersResponse_PlayersFailedToRespond) Export(391, SteamAPI_ISteamMatchmakingPlayersResponse_PlayersRefreshComplete) Export(392, SteamAPI_ISteamMatchmakingRulesResponse_RulesFailedToRespond) Export(393, SteamAPI_ISteamMatchmakingRulesResponse_RulesRefreshComplete) Export(394, SteamAPI_ISteamMatchmakingRulesResponse_RulesResponded) Export(395, SteamAPI_ISteamMatchmakingServerListResponse_RefreshComplete) Export(396, SteamAPI_ISteamMatchmakingServerListResponse_ServerFailedToRespond) Export(397, SteamAPI_ISteamMatchmakingServerListResponse_ServerResponded) Export(398, SteamAPI_ISteamMatchmakingServers_CancelQuery) Export(399, SteamAPI_ISteamMatchmakingServers_CancelServerQuery) Export(400, SteamAPI_ISteamMatchmakingServers_GetServerCount) Export(401, SteamAPI_ISteamMatchmakingServers_GetServerDetails) Export(402, SteamAPI_ISteamMatchmakingServers_IsRefreshing) Export(403, SteamAPI_ISteamMatchmakingServers_PingServer) Export(404, SteamAPI_ISteamMatchmakingServers_PlayerDetails) Export(405, SteamAPI_ISteamMatchmakingServers_RefreshQuery) Export(406, SteamAPI_ISteamMatchmakingServers_RefreshServer) Export(407, SteamAPI_ISteamMatchmakingServers_ReleaseRequest) Export(408, SteamAPI_ISteamMatchmakingServers_RequestFavoritesServerList) Export(409, SteamAPI_ISteamMatchmakingServers_RequestFriendsServerList) Export(410, SteamAPI_ISteamMatchmakingServers_RequestHistoryServerList) Export(411, SteamAPI_ISteamMatchmakingServers_RequestInternetServerList) Export(412, SteamAPI_ISteamMatchmakingServers_RequestLANServerList) Export(413, SteamAPI_ISteamMatchmakingServers_RequestSpectatorServerList) Export(414, SteamAPI_ISteamMatchmakingServers_ServerRules) Export(415, SteamAPI_ISteamMatchmaking_AddFavoriteGame) Export(416, SteamAPI_ISteamMatchmaking_AddRequestLobbyListCompatibleMembersFilter) Export(417, SteamAPI_ISteamMatchmaking_AddRequestLobbyListDistanceFilter) Export(418, SteamAPI_ISteamMatchmaking_AddRequestLobbyListFilterSlotsAvailable) Export(419, SteamAPI_ISteamMatchmaking_AddRequestLobbyListNearValueFilter) Export(420, SteamAPI_ISteamMatchmaking_AddRequestLobbyListNumericalFilter) Export(421, SteamAPI_ISteamMatchmaking_AddRequestLobbyListResultCountFilter) Export(422, SteamAPI_ISteamMatchmaking_AddRequestLobbyListStringFilter) Export(423, SteamAPI_ISteamMatchmaking_CreateLobby) Export(424, SteamAPI_ISteamMatchmaking_DeleteLobbyData) Export(425, SteamAPI_ISteamMatchmaking_GetFavoriteGame) Export(426, SteamAPI_ISteamMatchmaking_GetFavoriteGameCount) Export(427, SteamAPI_ISteamMatchmaking_GetLobbyByIndex) Export(428, SteamAPI_ISteamMatchmaking_GetLobbyChatEntry) Export(429, SteamAPI_ISteamMatchmaking_GetLobbyData) Export(430, SteamAPI_ISteamMatchmaking_GetLobbyDataByIndex) Export(431, SteamAPI_ISteamMatchmaking_GetLobbyDataCount) Export(432, SteamAPI_ISteamMatchmaking_GetLobbyGameServer) Export(433, SteamAPI_ISteamMatchmaking_GetLobbyMemberByIndex) Export(434, SteamAPI_ISteamMatchmaking_GetLobbyMemberData) Export(435, SteamAPI_ISteamMatchmaking_GetLobbyMemberLimit) Export(436, SteamAPI_ISteamMatchmaking_GetLobbyOwner) Export(437, SteamAPI_ISteamMatchmaking_GetNumLobbyMembers) Export(438, SteamAPI_ISteamMatchmaking_InviteUserToLobby) Export(439, SteamAPI_ISteamMatchmaking_JoinLobby) Export(440, SteamAPI_ISteamMatchmaking_LeaveLobby) Export(441, SteamAPI_ISteamMatchmaking_RemoveFavoriteGame) Export(442, SteamAPI_ISteamMatchmaking_RequestLobbyData) Export(443, SteamAPI_ISteamMatchmaking_RequestLobbyList) Export(444, SteamAPI_ISteamMatchmaking_SendLobbyChatMsg) Export(445, SteamAPI_ISteamMatchmaking_SetLinkedLobby) Export(446, SteamAPI_ISteamMatchmaking_SetLobbyData) Export(447, SteamAPI_ISteamMatchmaking_SetLobbyGameServer) Export(448, SteamAPI_ISteamMatchmaking_SetLobbyJoinable) Export(449, SteamAPI_ISteamMatchmaking_SetLobbyMemberData) Export(450, SteamAPI_ISteamMatchmaking_SetLobbyMemberLimit) Export(451, SteamAPI_ISteamMatchmaking_SetLobbyOwner) Export(452, SteamAPI_ISteamMatchmaking_SetLobbyType) Export(453, SteamAPI_ISteamMusicRemote_BActivationSuccess) Export(454, SteamAPI_ISteamMusicRemote_BIsCurrentMusicRemote) Export(455, SteamAPI_ISteamMusicRemote_CurrentEntryDidChange) Export(456, SteamAPI_ISteamMusicRemote_CurrentEntryIsAvailable) Export(457, SteamAPI_ISteamMusicRemote_CurrentEntryWillChange) Export(458, SteamAPI_ISteamMusicRemote_DeregisterSteamMusicRemote) Export(459, SteamAPI_ISteamMusicRemote_EnableLooped) Export(460, SteamAPI_ISteamMusicRemote_EnablePlayNext) Export(461, SteamAPI_ISteamMusicRemote_EnablePlayPrevious) Export(462, SteamAPI_ISteamMusicRemote_EnablePlaylists) Export(463, SteamAPI_ISteamMusicRemote_EnableQueue) Export(464, SteamAPI_ISteamMusicRemote_EnableShuffled) Export(465, SteamAPI_ISteamMusicRemote_PlaylistDidChange) Export(466, SteamAPI_ISteamMusicRemote_PlaylistWillChange) Export(467, SteamAPI_ISteamMusicRemote_QueueDidChange) Export(468, SteamAPI_ISteamMusicRemote_QueueWillChange) Export(469, SteamAPI_ISteamMusicRemote_RegisterSteamMusicRemote) Export(470, SteamAPI_ISteamMusicRemote_ResetPlaylistEntries) Export(471, SteamAPI_ISteamMusicRemote_ResetQueueEntries) Export(472, SteamAPI_ISteamMusicRemote_SetCurrentPlaylistEntry) Export(473, SteamAPI_ISteamMusicRemote_SetCurrentQueueEntry) Export(474, SteamAPI_ISteamMusicRemote_SetDisplayName) Export(475, SteamAPI_ISteamMusicRemote_SetPNGIcon_64x64) Export(476, SteamAPI_ISteamMusicRemote_SetPlaylistEntry) Export(477, SteamAPI_ISteamMusicRemote_SetQueueEntry) Export(478, SteamAPI_ISteamMusicRemote_UpdateCurrentEntryCoverArt) Export(479, SteamAPI_ISteamMusicRemote_UpdateCurrentEntryElapsedSeconds) Export(480, SteamAPI_ISteamMusicRemote_UpdateCurrentEntryText) Export(481, SteamAPI_ISteamMusicRemote_UpdateLooped) Export(482, SteamAPI_ISteamMusicRemote_UpdatePlaybackStatus) Export(483, SteamAPI_ISteamMusicRemote_UpdateShuffled) Export(484, SteamAPI_ISteamMusicRemote_UpdateVolume) Export(485, SteamAPI_ISteamMusic_BIsEnabled) Export(486, SteamAPI_ISteamMusic_BIsPlaying) Export(487, SteamAPI_ISteamMusic_GetPlaybackStatus) Export(488, SteamAPI_ISteamMusic_GetVolume) Export(489, SteamAPI_ISteamMusic_Pause) Export(490, SteamAPI_ISteamMusic_Play) Export(491, SteamAPI_ISteamMusic_PlayNext) Export(492, SteamAPI_ISteamMusic_PlayPrevious) Export(493, SteamAPI_ISteamMusic_SetVolume) Export(494, SteamAPI_ISteamNetworkingMessages_AcceptSessionWithUser) Export(495, SteamAPI_ISteamNetworkingMessages_CloseChannelWithUser) Export(496, SteamAPI_ISteamNetworkingMessages_CloseSessionWithUser) Export(497, SteamAPI_ISteamNetworkingMessages_GetSessionConnectionInfo) Export(498, SteamAPI_ISteamNetworkingMessages_ReceiveMessagesOnChannel) Export(499, SteamAPI_ISteamNetworkingMessages_SendMessageToUser) Export(500, SteamAPI_ISteamNetworkingSockets_AcceptConnection) Export(501, SteamAPI_ISteamNetworkingSockets_CloseConnection) Export(502, SteamAPI_ISteamNetworkingSockets_CloseListenSocket) Export(503, SteamAPI_ISteamNetworkingSockets_ConnectByIPAddress) Export(504, SteamAPI_ISteamNetworkingSockets_ConnectP2P) Export(505, SteamAPI_ISteamNetworkingSockets_ConnectP2PCustomSignaling) Export(506, SteamAPI_ISteamNetworkingSockets_ConnectToHostedDedicatedServer) Export(507, SteamAPI_ISteamNetworkingSockets_CreateHostedDedicatedServerListenSocket) Export(508, SteamAPI_ISteamNetworkingSockets_CreateListenSocketIP) Export(509, SteamAPI_ISteamNetworkingSockets_CreateListenSocketP2P) Export(510, SteamAPI_ISteamNetworkingSockets_CreatePollGroup) Export(511, SteamAPI_ISteamNetworkingSockets_CreateSocketPair) Export(512, SteamAPI_ISteamNetworkingSockets_DestroyPollGroup) Export(513, SteamAPI_ISteamNetworkingSockets_FindRelayAuthTicketForServer) Export(514, SteamAPI_ISteamNetworkingSockets_FlushMessagesOnConnection) Export(515, SteamAPI_ISteamNetworkingSockets_GetAuthenticationStatus) Export(516, SteamAPI_ISteamNetworkingSockets_GetCertificateRequest) Export(517, SteamAPI_ISteamNetworkingSockets_GetConnectionInfo) Export(518, SteamAPI_ISteamNetworkingSockets_GetConnectionName) Export(519, SteamAPI_ISteamNetworkingSockets_GetConnectionUserData) Export(520, SteamAPI_ISteamNetworkingSockets_GetDetailedConnectionStatus) Export(521, SteamAPI_ISteamNetworkingSockets_GetGameCoordinatorServerLogin) Export(522, SteamAPI_ISteamNetworkingSockets_GetHostedDedicatedServerAddress) Export(523, SteamAPI_ISteamNetworkingSockets_GetHostedDedicatedServerPOPID) Export(524, SteamAPI_ISteamNetworkingSockets_GetHostedDedicatedServerPort) Export(525, SteamAPI_ISteamNetworkingSockets_GetIdentity) Export(526, SteamAPI_ISteamNetworkingSockets_GetListenSocketAddress) Export(527, SteamAPI_ISteamNetworkingSockets_GetQuickConnectionStatus) Export(528, SteamAPI_ISteamNetworkingSockets_InitAuthentication) Export(529, SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnConnection) Export(530, SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnPollGroup) Export(531, SteamAPI_ISteamNetworkingSockets_ReceivedP2PCustomSignal) Export(532, SteamAPI_ISteamNetworkingSockets_ReceivedRelayAuthTicket) Export(533, SteamAPI_ISteamNetworkingSockets_RunCallbacks) Export(534, SteamAPI_ISteamNetworkingSockets_SendMessageToConnection) Export(535, SteamAPI_ISteamNetworkingSockets_SendMessages) Export(536, SteamAPI_ISteamNetworkingSockets_SetCertificate) Export(537, SteamAPI_ISteamNetworkingSockets_SetConnectionName) Export(538, SteamAPI_ISteamNetworkingSockets_SetConnectionPollGroup) Export(539, SteamAPI_ISteamNetworkingSockets_SetConnectionUserData) Export(540, SteamAPI_ISteamNetworkingUtils_AllocateMessage) Export(541, SteamAPI_ISteamNetworkingUtils_CheckPingDataUpToDate) Export(542, SteamAPI_ISteamNetworkingUtils_ConvertPingLocationToString) Export(543, SteamAPI_ISteamNetworkingUtils_EstimatePingTimeBetweenTwoLocations) Export(544, SteamAPI_ISteamNetworkingUtils_EstimatePingTimeFromLocalHost) Export(545, SteamAPI_ISteamNetworkingUtils_GetConfigValue) Export(546, SteamAPI_ISteamNetworkingUtils_GetConfigValueInfo) Export(547, SteamAPI_ISteamNetworkingUtils_GetDirectPingToPOP) Export(548, SteamAPI_ISteamNetworkingUtils_GetFirstConfigValue) Export(549, SteamAPI_ISteamNetworkingUtils_GetLocalPingLocation) Export(550, SteamAPI_ISteamNetworkingUtils_GetLocalTimestamp) Export(551, SteamAPI_ISteamNetworkingUtils_GetPOPCount) Export(552, SteamAPI_ISteamNetworkingUtils_GetPOPList) Export(553, SteamAPI_ISteamNetworkingUtils_GetPingToDataCenter) Export(554, SteamAPI_ISteamNetworkingUtils_GetRelayNetworkStatus) Export(555, SteamAPI_ISteamNetworkingUtils_InitRelayNetworkAccess) Export(556, SteamAPI_ISteamNetworkingUtils_ParsePingLocationString) Export(557, SteamAPI_ISteamNetworkingUtils_SetConfigValue) Export(558, SteamAPI_ISteamNetworkingUtils_SetConfigValueStruct) Export(559, SteamAPI_ISteamNetworkingUtils_SetConnectionConfigValueFloat) Export(560, SteamAPI_ISteamNetworkingUtils_SetConnectionConfigValueInt32) Export(561, SteamAPI_ISteamNetworkingUtils_SetConnectionConfigValueString) Export(562, SteamAPI_ISteamNetworkingUtils_SetDebugOutputFunction) Export(563, SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_MessagesSessionFailed) Export(564, SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_MessagesSessionRequest) Export(565, SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_SteamNetAuthenticationStatusChanged) Export(566, SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_SteamNetConnectionStatusChanged) Export(567, SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_SteamRelayNetworkStatusChanged) Export(568, SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValueFloat) Export(569, SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValueInt32) Export(570, SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValuePtr) Export(571, SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValueString) Export(572, SteamAPI_ISteamNetworkingUtils_SteamNetworkingIPAddr_ParseString) Export(573, SteamAPI_ISteamNetworkingUtils_SteamNetworkingIPAddr_ToString) Export(574, SteamAPI_ISteamNetworkingUtils_SteamNetworkingIdentity_ParseString) Export(575, SteamAPI_ISteamNetworkingUtils_SteamNetworkingIdentity_ToString) Export(576, SteamAPI_ISteamNetworking_AcceptP2PSessionWithUser) Export(577, SteamAPI_ISteamNetworking_AllowP2PPacketRelay) Export(578, SteamAPI_ISteamNetworking_CloseP2PChannelWithUser) Export(579, SteamAPI_ISteamNetworking_CloseP2PSessionWithUser) Export(580, SteamAPI_ISteamNetworking_CreateConnectionSocket) Export(581, SteamAPI_ISteamNetworking_CreateListenSocket) Export(582, SteamAPI_ISteamNetworking_CreateP2PConnectionSocket) Export(583, SteamAPI_ISteamNetworking_DestroyListenSocket) Export(584, SteamAPI_ISteamNetworking_DestroySocket) Export(585, SteamAPI_ISteamNetworking_GetListenSocketInfo) Export(586, SteamAPI_ISteamNetworking_GetMaxPacketSize) Export(587, SteamAPI_ISteamNetworking_GetP2PSessionState) Export(588, SteamAPI_ISteamNetworking_GetSocketConnectionType) Export(589, SteamAPI_ISteamNetworking_GetSocketInfo) Export(590, SteamAPI_ISteamNetworking_IsDataAvailable) Export(591, SteamAPI_ISteamNetworking_IsDataAvailableOnSocket) Export(592, SteamAPI_ISteamNetworking_IsP2PPacketAvailable) Export(593, SteamAPI_ISteamNetworking_ReadP2PPacket) Export(594, SteamAPI_ISteamNetworking_RetrieveData) Export(595, SteamAPI_ISteamNetworking_RetrieveDataFromSocket) Export(596, SteamAPI_ISteamNetworking_SendDataOnSocket) Export(597, SteamAPI_ISteamNetworking_SendP2PPacket) Export(598, SteamAPI_ISteamParentalSettings_BIsAppBlocked) Export(599, SteamAPI_ISteamParentalSettings_BIsAppInBlockList) Export(600, SteamAPI_ISteamParentalSettings_BIsFeatureBlocked) Export(601, SteamAPI_ISteamParentalSettings_BIsFeatureInBlockList) Export(602, SteamAPI_ISteamParentalSettings_BIsParentalLockEnabled) Export(603, SteamAPI_ISteamParentalSettings_BIsParentalLockLocked) Export(604, SteamAPI_ISteamParties_CancelReservation) Export(605, SteamAPI_ISteamParties_ChangeNumOpenSlots) Export(606, SteamAPI_ISteamParties_CreateBeacon) Export(607, SteamAPI_ISteamParties_DestroyBeacon) Export(608, SteamAPI_ISteamParties_GetAvailableBeaconLocations) Export(609, SteamAPI_ISteamParties_GetBeaconByIndex) Export(610, SteamAPI_ISteamParties_GetBeaconDetails) Export(611, SteamAPI_ISteamParties_GetBeaconLocationData) Export(612, SteamAPI_ISteamParties_GetNumActiveBeacons) Export(613, SteamAPI_ISteamParties_GetNumAvailableBeaconLocations) Export(614, SteamAPI_ISteamParties_JoinParty) Export(615, SteamAPI_ISteamParties_OnReservationCompleted) Export(616, SteamAPI_ISteamRemotePlay_BGetSessionClientResolution) Export(617, SteamAPI_ISteamRemotePlay_BSendRemotePlayTogetherInvite) Export(618, SteamAPI_ISteamRemotePlay_GetSessionClientFormFactor) Export(619, SteamAPI_ISteamRemotePlay_GetSessionClientName) Export(620, SteamAPI_ISteamRemotePlay_GetSessionCount) Export(621, SteamAPI_ISteamRemotePlay_GetSessionID) Export(622, SteamAPI_ISteamRemotePlay_GetSessionSteamID) Export(623, SteamAPI_ISteamRemoteStorage_CommitPublishedFileUpdate) Export(624, SteamAPI_ISteamRemoteStorage_CreatePublishedFileUpdateRequest) Export(625, SteamAPI_ISteamRemoteStorage_DeletePublishedFile) Export(626, SteamAPI_ISteamRemoteStorage_EnumeratePublishedFilesByUserAction) Export(627, SteamAPI_ISteamRemoteStorage_EnumeratePublishedWorkshopFiles) Export(628, SteamAPI_ISteamRemoteStorage_EnumerateUserPublishedFiles) Export(629, SteamAPI_ISteamRemoteStorage_EnumerateUserSharedWorkshopFiles) Export(630, SteamAPI_ISteamRemoteStorage_EnumerateUserSubscribedFiles) Export(631, SteamAPI_ISteamRemoteStorage_FileDelete) Export(632, SteamAPI_ISteamRemoteStorage_FileExists) Export(633, SteamAPI_ISteamRemoteStorage_FileForget) Export(634, SteamAPI_ISteamRemoteStorage_FilePersisted) Export(635, SteamAPI_ISteamRemoteStorage_FileRead) Export(636, SteamAPI_ISteamRemoteStorage_FileReadAsync) Export(637, SteamAPI_ISteamRemoteStorage_FileReadAsyncComplete) Export(638, SteamAPI_ISteamRemoteStorage_FileShare) Export(639, SteamAPI_ISteamRemoteStorage_FileWrite) Export(640, SteamAPI_ISteamRemoteStorage_FileWriteAsync) Export(641, SteamAPI_ISteamRemoteStorage_FileWriteStreamCancel) Export(642, SteamAPI_ISteamRemoteStorage_FileWriteStreamClose) Export(643, SteamAPI_ISteamRemoteStorage_FileWriteStreamOpen) Export(644, SteamAPI_ISteamRemoteStorage_FileWriteStreamWriteChunk) Export(645, SteamAPI_ISteamRemoteStorage_GetCachedUGCCount) Export(646, SteamAPI_ISteamRemoteStorage_GetCachedUGCHandle) Export(647, SteamAPI_ISteamRemoteStorage_GetFileCount) Export(648, SteamAPI_ISteamRemoteStorage_GetFileNameAndSize) Export(649, SteamAPI_ISteamRemoteStorage_GetFileSize) Export(650, SteamAPI_ISteamRemoteStorage_GetFileTimestamp) Export(651, SteamAPI_ISteamRemoteStorage_GetPublishedFileDetails) Export(652, SteamAPI_ISteamRemoteStorage_GetPublishedItemVoteDetails) Export(653, SteamAPI_ISteamRemoteStorage_GetQuota) Export(654, SteamAPI_ISteamRemoteStorage_GetSyncPlatforms) Export(655, SteamAPI_ISteamRemoteStorage_GetUGCDetails) Export(656, SteamAPI_ISteamRemoteStorage_GetUGCDownloadProgress) Export(657, SteamAPI_ISteamRemoteStorage_GetUserPublishedItemVoteDetails) Export(658, SteamAPI_ISteamRemoteStorage_IsCloudEnabledForAccount) Export(659, SteamAPI_ISteamRemoteStorage_IsCloudEnabledForApp) Export(660, SteamAPI_ISteamRemoteStorage_PublishVideo) Export(661, SteamAPI_ISteamRemoteStorage_PublishWorkshopFile) Export(662, SteamAPI_ISteamRemoteStorage_SetCloudEnabledForApp) Export(663, SteamAPI_ISteamRemoteStorage_SetSyncPlatforms) Export(664, SteamAPI_ISteamRemoteStorage_SetUserPublishedFileAction) Export(665, SteamAPI_ISteamRemoteStorage_SubscribePublishedFile) Export(666, SteamAPI_ISteamRemoteStorage_UGCDownload) Export(667, SteamAPI_ISteamRemoteStorage_UGCDownloadToLocation) Export(668, SteamAPI_ISteamRemoteStorage_UGCRead) Export(669, SteamAPI_ISteamRemoteStorage_UnsubscribePublishedFile) Export(670, SteamAPI_ISteamRemoteStorage_UpdatePublishedFileDescription) Export(671, SteamAPI_ISteamRemoteStorage_UpdatePublishedFileFile) Export(672, SteamAPI_ISteamRemoteStorage_UpdatePublishedFilePreviewFile) Export(673, SteamAPI_ISteamRemoteStorage_UpdatePublishedFileSetChangeDescription) Export(674, SteamAPI_ISteamRemoteStorage_UpdatePublishedFileTags) Export(675, SteamAPI_ISteamRemoteStorage_UpdatePublishedFileTitle) Export(676, SteamAPI_ISteamRemoteStorage_UpdatePublishedFileVisibility) Export(677, SteamAPI_ISteamRemoteStorage_UpdateUserPublishedItemVote) Export(678, SteamAPI_ISteamScreenshots_AddScreenshotToLibrary) Export(679, SteamAPI_ISteamScreenshots_AddVRScreenshotToLibrary) Export(680, SteamAPI_ISteamScreenshots_HookScreenshots) Export(681, SteamAPI_ISteamScreenshots_IsScreenshotsHooked) Export(682, SteamAPI_ISteamScreenshots_SetLocation) Export(683, SteamAPI_ISteamScreenshots_TagPublishedFile) Export(684, SteamAPI_ISteamScreenshots_TagUser) Export(685, SteamAPI_ISteamScreenshots_TriggerScreenshot) Export(686, SteamAPI_ISteamScreenshots_WriteScreenshot) Export(687, SteamAPI_ISteamUGC_AddAppDependency) Export(688, SteamAPI_ISteamUGC_AddDependency) Export(689, SteamAPI_ISteamUGC_AddExcludedTag) Export(690, SteamAPI_ISteamUGC_AddItemKeyValueTag) Export(691, SteamAPI_ISteamUGC_AddItemPreviewFile) Export(692, SteamAPI_ISteamUGC_AddItemPreviewVideo) Export(693, SteamAPI_ISteamUGC_AddItemToFavorites) Export(694, SteamAPI_ISteamUGC_AddRequiredKeyValueTag) Export(695, SteamAPI_ISteamUGC_AddRequiredTag) Export(696, SteamAPI_ISteamUGC_AddRequiredTagGroup) Export(697, SteamAPI_ISteamUGC_BInitWorkshopForGameServer) Export(698, SteamAPI_ISteamUGC_CreateItem) Export(699, SteamAPI_ISteamUGC_CreateQueryAllUGCRequestCursor) Export(700, SteamAPI_ISteamUGC_CreateQueryAllUGCRequestPage) Export(701, SteamAPI_ISteamUGC_CreateQueryUGCDetailsRequest) Export(702, SteamAPI_ISteamUGC_CreateQueryUserUGCRequest) Export(703, SteamAPI_ISteamUGC_DeleteItem) Export(704, SteamAPI_ISteamUGC_DownloadItem) Export(705, SteamAPI_ISteamUGC_GetAppDependencies) Export(706, SteamAPI_ISteamUGC_GetItemDownloadInfo) Export(707, SteamAPI_ISteamUGC_GetItemInstallInfo) Export(708, SteamAPI_ISteamUGC_GetItemState) Export(709, SteamAPI_ISteamUGC_GetItemUpdateProgress) Export(710, SteamAPI_ISteamUGC_GetNumSubscribedItems) Export(711, SteamAPI_ISteamUGC_GetQueryFirstUGCKeyValueTag) Export(712, SteamAPI_ISteamUGC_GetQueryUGCAdditionalPreview) Export(713, SteamAPI_ISteamUGC_GetQueryUGCChildren) Export(714, SteamAPI_ISteamUGC_GetQueryUGCKeyValueTag) Export(715, SteamAPI_ISteamUGC_GetQueryUGCMetadata) Export(716, SteamAPI_ISteamUGC_GetQueryUGCNumAdditionalPreviews) Export(717, SteamAPI_ISteamUGC_GetQueryUGCNumKeyValueTags) Export(718, SteamAPI_ISteamUGC_GetQueryUGCNumTags) Export(719, SteamAPI_ISteamUGC_GetQueryUGCPreviewURL) Export(720, SteamAPI_ISteamUGC_GetQueryUGCResult) Export(721, SteamAPI_ISteamUGC_GetQueryUGCStatistic) Export(722, SteamAPI_ISteamUGC_GetQueryUGCTag) Export(723, SteamAPI_ISteamUGC_GetQueryUGCTagDisplayName) Export(724, SteamAPI_ISteamUGC_GetSubscribedItems) Export(725, SteamAPI_ISteamUGC_GetUserItemVote) Export(726, SteamAPI_ISteamUGC_ReleaseQueryUGCRequest) Export(727, SteamAPI_ISteamUGC_RemoveAllItemKeyValueTags) Export(728, SteamAPI_ISteamUGC_RemoveAppDependency) Export(729, SteamAPI_ISteamUGC_RemoveDependency) Export(730, SteamAPI_ISteamUGC_RemoveItemFromFavorites) Export(731, SteamAPI_ISteamUGC_RemoveItemKeyValueTags) Export(732, SteamAPI_ISteamUGC_RemoveItemPreview) Export(733, SteamAPI_ISteamUGC_RequestUGCDetails) Export(734, SteamAPI_ISteamUGC_SendQueryUGCRequest) Export(735, SteamAPI_ISteamUGC_SetAllowCachedResponse) Export(736, SteamAPI_ISteamUGC_SetAllowLegacyUpload) Export(737, SteamAPI_ISteamUGC_SetCloudFileNameFilter) Export(738, SteamAPI_ISteamUGC_SetItemContent) Export(739, SteamAPI_ISteamUGC_SetItemDescription) Export(740, SteamAPI_ISteamUGC_SetItemMetadata) Export(741, SteamAPI_ISteamUGC_SetItemPreview) Export(742, SteamAPI_ISteamUGC_SetItemTags) Export(743, SteamAPI_ISteamUGC_SetItemTitle) Export(744, SteamAPI_ISteamUGC_SetItemUpdateLanguage) Export(745, SteamAPI_ISteamUGC_SetItemVisibility) Export(746, SteamAPI_ISteamUGC_SetLanguage) Export(747, SteamAPI_ISteamUGC_SetMatchAnyTag) Export(748, SteamAPI_ISteamUGC_SetRankedByTrendDays) Export(749, SteamAPI_ISteamUGC_SetReturnAdditionalPreviews) Export(750, SteamAPI_ISteamUGC_SetReturnChildren) Export(751, SteamAPI_ISteamUGC_SetReturnKeyValueTags) Export(752, SteamAPI_ISteamUGC_SetReturnLongDescription) Export(753, SteamAPI_ISteamUGC_SetReturnMetadata) Export(754, SteamAPI_ISteamUGC_SetReturnOnlyIDs) Export(755, SteamAPI_ISteamUGC_SetReturnPlaytimeStats) Export(756, SteamAPI_ISteamUGC_SetReturnTotalOnly) Export(757, SteamAPI_ISteamUGC_SetSearchText) Export(758, SteamAPI_ISteamUGC_SetUserItemVote) Export(759, SteamAPI_ISteamUGC_StartItemUpdate) Export(760, SteamAPI_ISteamUGC_StartPlaytimeTracking) Export(761, SteamAPI_ISteamUGC_StopPlaytimeTracking) Export(762, SteamAPI_ISteamUGC_StopPlaytimeTrackingForAllItems) Export(763, SteamAPI_ISteamUGC_SubmitItemUpdate) Export(764, SteamAPI_ISteamUGC_SubscribeItem) Export(765, SteamAPI_ISteamUGC_SuspendDownloads) Export(766, SteamAPI_ISteamUGC_UnsubscribeItem) Export(767, SteamAPI_ISteamUGC_UpdateItemPreviewFile) Export(768, SteamAPI_ISteamUGC_UpdateItemPreviewVideo) Export(769, SteamAPI_ISteamUserStats_AttachLeaderboardUGC) Export(770, SteamAPI_ISteamUserStats_ClearAchievement) Export(771, SteamAPI_ISteamUserStats_DownloadLeaderboardEntries) Export(772, SteamAPI_ISteamUserStats_DownloadLeaderboardEntriesForUsers) Export(773, SteamAPI_ISteamUserStats_FindLeaderboard) Export(774, SteamAPI_ISteamUserStats_FindOrCreateLeaderboard) Export(775, SteamAPI_ISteamUserStats_GetAchievement) Export(776, SteamAPI_ISteamUserStats_GetAchievementAchievedPercent) Export(777, SteamAPI_ISteamUserStats_GetAchievementAndUnlockTime) Export(778, SteamAPI_ISteamUserStats_GetAchievementDisplayAttribute) Export(779, SteamAPI_ISteamUserStats_GetAchievementIcon) Export(780, SteamAPI_ISteamUserStats_GetAchievementName) Export(781, SteamAPI_ISteamUserStats_GetAchievementProgressLimitsFloat) Export(782, SteamAPI_ISteamUserStats_GetAchievementProgressLimitsInt32) Export(783, SteamAPI_ISteamUserStats_GetDownloadedLeaderboardEntry) Export(784, SteamAPI_ISteamUserStats_GetGlobalStatDouble) Export(785, SteamAPI_ISteamUserStats_GetGlobalStatHistoryDouble) Export(786, SteamAPI_ISteamUserStats_GetGlobalStatHistoryInt64) Export(787, SteamAPI_ISteamUserStats_GetGlobalStatInt64) Export(788, SteamAPI_ISteamUserStats_GetLeaderboardDisplayType) Export(789, SteamAPI_ISteamUserStats_GetLeaderboardEntryCount) Export(790, SteamAPI_ISteamUserStats_GetLeaderboardName) Export(791, SteamAPI_ISteamUserStats_GetLeaderboardSortMethod) Export(792, SteamAPI_ISteamUserStats_GetMostAchievedAchievementInfo) Export(793, SteamAPI_ISteamUserStats_GetNextMostAchievedAchievementInfo) Export(794, SteamAPI_ISteamUserStats_GetNumAchievements) Export(795, SteamAPI_ISteamUserStats_GetNumberOfCurrentPlayers) Export(796, SteamAPI_ISteamUserStats_GetStatFloat) Export(797, SteamAPI_ISteamUserStats_GetStatInt32) Export(798, SteamAPI_ISteamUserStats_GetUserAchievement) Export(799, SteamAPI_ISteamUserStats_GetUserAchievementAndUnlockTime) Export(800, SteamAPI_ISteamUserStats_GetUserStatFloat) Export(801, SteamAPI_ISteamUserStats_GetUserStatInt32) Export(802, SteamAPI_ISteamUserStats_IndicateAchievementProgress) Export(803, SteamAPI_ISteamUserStats_RequestCurrentStats) Export(804, SteamAPI_ISteamUserStats_RequestGlobalAchievementPercentages) Export(805, SteamAPI_ISteamUserStats_RequestGlobalStats) Export(806, SteamAPI_ISteamUserStats_RequestUserStats) Export(807, SteamAPI_ISteamUserStats_ResetAllStats) Export(808, SteamAPI_ISteamUserStats_SetAchievement) Export(809, SteamAPI_ISteamUserStats_SetStatFloat) Export(810, SteamAPI_ISteamUserStats_SetStatInt32) Export(811, SteamAPI_ISteamUserStats_StoreStats) Export(812, SteamAPI_ISteamUserStats_UpdateAvgRateStat) Export(813, SteamAPI_ISteamUserStats_UploadLeaderboardScore) Export(814, SteamAPI_ISteamUser_AdvertiseGame) Export(815, SteamAPI_ISteamUser_BIsBehindNAT) Export(816, SteamAPI_ISteamUser_BIsPhoneIdentifying) Export(817, SteamAPI_ISteamUser_BIsPhoneRequiringVerification) Export(818, SteamAPI_ISteamUser_BIsPhoneVerified) Export(819, SteamAPI_ISteamUser_BIsTwoFactorEnabled) Export(820, SteamAPI_ISteamUser_BLoggedOn) Export(821, SteamAPI_ISteamUser_BSetDurationControlOnlineState) Export(822, SteamAPI_ISteamUser_BeginAuthSession) Export(823, SteamAPI_ISteamUser_CancelAuthTicket) Export(824, SteamAPI_ISteamUser_DecompressVoice) Export(825, SteamAPI_ISteamUser_EndAuthSession) Export(826, SteamAPI_ISteamUser_GetAuthSessionTicket) Export(827, SteamAPI_ISteamUser_GetAvailableVoice) Export(828, SteamAPI_ISteamUser_GetDurationControl) Export(829, SteamAPI_ISteamUser_GetEncryptedAppTicket) Export(830, SteamAPI_ISteamUser_GetGameBadgeLevel) Export(831, SteamAPI_ISteamUser_GetHSteamUser) Export(832, SteamAPI_ISteamUser_GetMarketEligibility) Export(833, SteamAPI_ISteamUser_GetPlayerSteamLevel) Export(834, SteamAPI_ISteamUser_GetSteamID) Export(835, SteamAPI_ISteamUser_GetUserDataFolder) Export(836, SteamAPI_ISteamUser_GetVoice) Export(837, SteamAPI_ISteamUser_GetVoiceOptimalSampleRate) Export(838, SteamAPI_ISteamUser_InitiateGameConnection) Export(839, SteamAPI_ISteamUser_RequestEncryptedAppTicket) Export(840, SteamAPI_ISteamUser_RequestStoreAuthURL) Export(841, SteamAPI_ISteamUser_StartVoiceRecording) Export(842, SteamAPI_ISteamUser_StopVoiceRecording) Export(843, SteamAPI_ISteamUser_TerminateGameConnection) Export(844, SteamAPI_ISteamUser_TrackAppUsageEvent) Export(845, SteamAPI_ISteamUser_UserHasLicenseForApp) Export(846, SteamAPI_ISteamUtils_BOverlayNeedsPresent) Export(847, SteamAPI_ISteamUtils_CheckFileSignature) Export(848, SteamAPI_ISteamUtils_FilterText) Export(849, SteamAPI_ISteamUtils_GetAPICallFailureReason) Export(850, SteamAPI_ISteamUtils_GetAPICallResult) Export(851, SteamAPI_ISteamUtils_GetAppID) Export(852, SteamAPI_ISteamUtils_GetConnectedUniverse) Export(853, SteamAPI_ISteamUtils_GetCurrentBatteryPower) Export(854, SteamAPI_ISteamUtils_GetEnteredGamepadTextInput) Export(855, SteamAPI_ISteamUtils_GetEnteredGamepadTextLength) Export(856, SteamAPI_ISteamUtils_GetIPCCallCount) Export(857, SteamAPI_ISteamUtils_GetIPCountry) Export(858, SteamAPI_ISteamUtils_GetIPv6ConnectivityState) Export(859, SteamAPI_ISteamUtils_GetImageRGBA) Export(860, SteamAPI_ISteamUtils_GetImageSize) Export(861, SteamAPI_ISteamUtils_GetSecondsSinceAppActive) Export(862, SteamAPI_ISteamUtils_GetSecondsSinceComputerActive) Export(863, SteamAPI_ISteamUtils_GetServerRealTime) Export(864, SteamAPI_ISteamUtils_GetSteamUILanguage) Export(865, SteamAPI_ISteamUtils_InitFilterText) Export(866, SteamAPI_ISteamUtils_IsAPICallCompleted) Export(867, SteamAPI_ISteamUtils_IsOverlayEnabled) Export(868, SteamAPI_ISteamUtils_IsSteamChinaLauncher) Export(869, SteamAPI_ISteamUtils_IsSteamInBigPictureMode) Export(870, SteamAPI_ISteamUtils_IsSteamRunningInVR) Export(871, SteamAPI_ISteamUtils_IsVRHeadsetStreamingEnabled) Export(872, SteamAPI_ISteamUtils_SetOverlayNotificationInset) Export(873, SteamAPI_ISteamUtils_SetOverlayNotificationPosition) Export(874, SteamAPI_ISteamUtils_SetVRHeadsetStreamingEnabled) Export(875, SteamAPI_ISteamUtils_SetWarningMessageHook) Export(876, SteamAPI_ISteamUtils_ShowGamepadTextInput) Export(877, SteamAPI_ISteamUtils_StartVRDashboard) Export(878, SteamAPI_ISteamVideo_GetOPFSettings) Export(879, SteamAPI_ISteamVideo_GetOPFStringForApp) Export(880, SteamAPI_ISteamVideo_GetVideoURL) Export(881, SteamAPI_ISteamVideo_IsBroadcasting) Export(882, SteamAPI_Init) Export(883, SteamAPI_InitAnonymousUser) Export(884, SteamAPI_InitSafe) Export(885, SteamAPI_IsSteamRunning) Export(886, SteamAPI_ManualDispatch_FreeLastCallback) Export(887, SteamAPI_ManualDispatch_GetAPICallResult) Export(888, SteamAPI_ManualDispatch_GetNextCallback) Export(889, SteamAPI_ManualDispatch_Init) Export(890, SteamAPI_ManualDispatch_RunFrame) Export(891, SteamAPI_MatchMakingKeyValuePair_t_Construct) Export(892, SteamAPI_RegisterCallResult) Export(893, SteamAPI_RegisterCallback) Export(894, SteamAPI_ReleaseCurrentThreadMemory) Export(895, SteamAPI_RestartAppIfNecessary) Export(896, SteamAPI_RunCallbacks) Export(897, SteamAPI_SetBreakpadAppID) Export(898, SteamAPI_SetMiniDumpComment) Export(899, SteamAPI_SetTryCatchCallbacks) Export(900, SteamAPI_Shutdown) Export(901, SteamAPI_SteamAppList_v001) Export(902, SteamAPI_SteamApps_v008) Export(903, SteamAPI_SteamController_v008) Export(904, SteamAPI_SteamDatagramHostedAddress_Clear) Export(905, SteamAPI_SteamDatagramHostedAddress_GetPopID) Export(906, SteamAPI_SteamDatagramHostedAddress_SetDevAddress) Export(907, SteamAPI_SteamFriends_v017) Export(908, SteamAPI_SteamGameSearch_v001) Export(909, SteamAPI_SteamGameServerApps_v008) Export(910, SteamAPI_SteamGameServerHTTP_v003) Export(911, SteamAPI_SteamGameServerInventory_v003) Export(912, SteamAPI_SteamGameServerNetworkingMessages_SteamAPI_v002) Export(913, SteamAPI_SteamGameServerNetworkingSockets_SteamAPI_v009) Export(914, SteamAPI_SteamGameServerNetworking_v006) Export(915, SteamAPI_SteamGameServerStats_v001) Export(916, SteamAPI_SteamGameServerUGC_v015) Export(917, SteamAPI_SteamGameServerUtils_v010) Export(918, SteamAPI_SteamGameServer_v013) Export(919, SteamAPI_SteamHTMLSurface_v005) Export(920, SteamAPI_SteamHTTP_v003) Export(921, SteamAPI_SteamIPAddress_t_IsSet) Export(922, SteamAPI_SteamInput_v002) Export(923, SteamAPI_SteamInventory_v003) Export(924, SteamAPI_SteamMatchmakingServers_v002) Export(925, SteamAPI_SteamMatchmaking_v009) Export(926, SteamAPI_SteamMusicRemote_v001) Export(927, SteamAPI_SteamMusic_v001) Export(928, SteamAPI_SteamNetworkingConfigValue_t_SetFloat) Export(929, SteamAPI_SteamNetworkingConfigValue_t_SetInt32) Export(930, SteamAPI_SteamNetworkingConfigValue_t_SetInt64) Export(931, SteamAPI_SteamNetworkingConfigValue_t_SetPtr) Export(932, SteamAPI_SteamNetworkingConfigValue_t_SetString) Export(933, SteamAPI_SteamNetworkingIPAddrRender_c_str) Export(934, SteamAPI_SteamNetworkingIPAddr_Clear) Export(935, SteamAPI_SteamNetworkingIPAddr_GetIPv4) Export(936, SteamAPI_SteamNetworkingIPAddr_IsEqualTo) Export(937, SteamAPI_SteamNetworkingIPAddr_IsIPv4) Export(938, SteamAPI_SteamNetworkingIPAddr_IsIPv6AllZeros) Export(939, SteamAPI_SteamNetworkingIPAddr_IsLocalHost) Export(940, SteamAPI_SteamNetworkingIPAddr_ParseString) Export(941, SteamAPI_SteamNetworkingIPAddr_SetIPv4) Export(942, SteamAPI_SteamNetworkingIPAddr_SetIPv6) Export(943, SteamAPI_SteamNetworkingIPAddr_SetIPv6LocalHost) Export(944, SteamAPI_SteamNetworkingIPAddr_ToString) Export(945, SteamAPI_SteamNetworkingIdentityRender_c_str) Export(946, SteamAPI_SteamNetworkingIdentity_Clear) Export(947, SteamAPI_SteamNetworkingIdentity_GetGenericBytes) Export(948, SteamAPI_SteamNetworkingIdentity_GetGenericString) Export(949, SteamAPI_SteamNetworkingIdentity_GetIPAddr) Export(950, SteamAPI_SteamNetworkingIdentity_GetPSNID) Export(951, SteamAPI_SteamNetworkingIdentity_GetStadiaID) Export(952, SteamAPI_SteamNetworkingIdentity_GetSteamID) Export(953, SteamAPI_SteamNetworkingIdentity_GetSteamID64) Export(954, SteamAPI_SteamNetworkingIdentity_GetXboxPairwiseID) Export(955, SteamAPI_SteamNetworkingIdentity_IsEqualTo) Export(956, SteamAPI_SteamNetworkingIdentity_IsInvalid) Export(957, SteamAPI_SteamNetworkingIdentity_IsLocalHost) Export(958, SteamAPI_SteamNetworkingIdentity_ParseString) Export(959, SteamAPI_SteamNetworkingIdentity_SetGenericBytes) Export(960, SteamAPI_SteamNetworkingIdentity_SetGenericString) Export(961, SteamAPI_SteamNetworkingIdentity_SetIPAddr) Export(962, SteamAPI_SteamNetworkingIdentity_SetLocalHost) Export(963, SteamAPI_SteamNetworkingIdentity_SetPSNID) Export(964, SteamAPI_SteamNetworkingIdentity_SetStadiaID) Export(965, SteamAPI_SteamNetworkingIdentity_SetSteamID) Export(966, SteamAPI_SteamNetworkingIdentity_SetSteamID64) Export(967, SteamAPI_SteamNetworkingIdentity_SetXboxPairwiseID) Export(968, SteamAPI_SteamNetworkingIdentity_ToString) Export(969, SteamAPI_SteamNetworkingMessage_t_Release) Export(970, SteamAPI_SteamNetworkingMessages_SteamAPI_v002) Export(971, SteamAPI_SteamNetworkingPOPIDRender_c_str) Export(972, SteamAPI_SteamNetworkingSockets_SteamAPI_v009) Export(973, SteamAPI_SteamNetworkingUtils_SteamAPI_v003) Export(974, SteamAPI_SteamNetworking_v006) Export(975, SteamAPI_SteamParentalSettings_v001) Export(976, SteamAPI_SteamParties_v002) Export(977, SteamAPI_SteamRemotePlay_v001) Export(978, SteamAPI_SteamRemoteStorage_v014) Export(979, SteamAPI_SteamScreenshots_v003) Export(980, SteamAPI_SteamUGC_v015) Export(981, SteamAPI_SteamUserStats_v012) Export(982, SteamAPI_SteamUser_v021) Export(983, SteamAPI_SteamUtils_v010) Export(984, SteamAPI_SteamVideo_v002) Export(985, SteamAPI_UnregisterCallResult) Export(986, SteamAPI_UnregisterCallback) Export(987, SteamAPI_UseBreakpadCrashHandler) Export(988, SteamAPI_WriteMiniDump) Export(989, SteamAPI_gameserveritem_t_Construct) Export(990, SteamAPI_gameserveritem_t_GetName) Export(991, SteamAPI_gameserveritem_t_SetName) Export(992, SteamAPI_servernetadr_t_Assign) Export(993, SteamAPI_servernetadr_t_Construct) Export(994, SteamAPI_servernetadr_t_GetConnectionAddressString) Export(995, SteamAPI_servernetadr_t_GetConnectionPort) Export(996, SteamAPI_servernetadr_t_GetIP) Export(997, SteamAPI_servernetadr_t_GetQueryAddressString) Export(998, SteamAPI_servernetadr_t_GetQueryPort) Export(999, SteamAPI_servernetadr_t_Init) Export(1000, SteamAPI_servernetadr_t_IsLessThan) Export(1001, SteamAPI_servernetadr_t_SetConnectionPort) Export(1002, SteamAPI_servernetadr_t_SetIP) Export(1003, SteamAPI_servernetadr_t_SetQueryPort) Export(1004, SteamClient) Export(1005, SteamGameServer_BSecure) Export(1006, SteamGameServer_GetHSteamPipe) Export(1007, SteamGameServer_GetHSteamUser) Export(1008, SteamGameServer_GetIPCCallCount) Export(1009, SteamGameServer_GetSteamID) Export(1010, SteamGameServer_InitSafe) Export(1011, SteamGameServer_RunCallbacks) Export(1012, SteamGameServer_Shutdown) Export(1013, SteamInternal_ContextInit) Export(1014, SteamInternal_CreateInterface) Export(1015, SteamInternal_FindOrCreateGameServerInterface) Export(1016, SteamInternal_FindOrCreateUserInterface) Export(1017, SteamInternal_GameServer_Init) Export(1018, g_pSteamClientGameServer) #else // steam_api Export(0, GetHSteamPipe) Export(1, GetHSteamUser) Export(2, SteamAPI_GetHSteamPipe) Export(3, SteamAPI_GetHSteamUser) Export(4, SteamAPI_GetSteamInstallPath) Export(5, SteamAPI_Init) Export(6, SteamAPI_InitSafe) Export(7, SteamAPI_IsSteamRunning) Export(8, SteamAPI_RegisterCallResult) Export(9, SteamAPI_RegisterCallback) Export(10, SteamAPI_RestartAppIfNecessary) Export(11, SteamAPI_RunCallbacks) Export(12, SteamAPI_SetBreakpadAppID) Export(13, SteamAPI_SetMiniDumpComment) Export(14, SteamAPI_SetTryCatchCallbacks) Export(15, SteamAPI_Shutdown) Export(16, SteamAPI_UnregisterCallResult) Export(17, SteamAPI_UnregisterCallback) Export(18, SteamAPI_UseBreakpadCrashHandler) Export(19, SteamAPI_WriteMiniDump) Export(20, SteamApps) Export(21, SteamClient) Export(22, SteamContentServer) Export(23, SteamContentServerUtils) Export(24, SteamContentServer_Init) Export(25, SteamContentServer_RunCallbacks) Export(26, SteamContentServer_Shutdown) Export(27, SteamFriends) Export(28, SteamGameServer) Export(29, SteamGameServerApps) Export(30, SteamGameServerHTTP) Export(31, SteamGameServerNetworking) Export(32, SteamGameServerStats) Export(33, SteamGameServerUtils) Export(34, SteamGameServer_BSecure) Export(35, SteamGameServer_GetHSteamPipe) Export(36, SteamGameServer_GetHSteamUser) Export(37, SteamGameServer_GetIPCCallCount) Export(38, SteamGameServer_GetSteamID) Export(39, SteamGameServer_Init) Export(40, SteamGameServer_InitSafe) Export(41, SteamGameServer_RunCallbacks) Export(42, SteamGameServer_Shutdown) Export(43, SteamHTTP) Export(44, SteamMatchmaking) Export(45, SteamMatchmakingServers) Export(46, SteamNetworking) Export(47, SteamRemoteStorage) Export(48, SteamScreenshots) Export(49, SteamUser) Export(50, SteamUserStats) Export(51, SteamUtils) Export(52, Steam_GetHSteamUserCurrent) Export(53, Steam_RegisterInterfaceFuncs) Export(54, Steam_RunCallbacks) Export(55, g_pSteamClientGameServer) #endif // opengl32 Export(0, GlmfBeginGlsBlock) Export(1, GlmfCloseMetaFile) Export(2, GlmfEndGlsBlock) Export(3, GlmfEndPlayback) Export(4, GlmfInitPlayback) Export(5, GlmfPlayGlsRecord) Export(6, glAccum) Export(7, glAlphaFunc) Export(8, glAreTexturesResident) Export(9, glArrayElement) Export(10, glBegin) Export(11, glBindTexture) Export(12, glBitmap) Export(13, glBlendFunc) Export(14, glCallList) Export(15, glCallLists) Export(16, glClear) Export(17, glClearAccum) Export(18, glClearColor) Export(19, glClearDepth) Export(20, glClearIndex) Export(21, glClearStencil) Export(22, glClipPlane) Export(23, glColor3b) Export(24, glColor3bv) Export(25, glColor3d) Export(26, glColor3dv) Export(27, glColor3f) Export(28, glColor3fv) Export(29, glColor3i) Export(30, glColor3iv) Export(31, glColor3s) Export(32, glColor3sv) Export(33, glColor3ub) Export(34, glColor3ubv) Export(35, glColor3ui) Export(36, glColor3uiv) Export(37, glColor3us) Export(38, glColor3usv) Export(39, glColor4b) Export(40, glColor4bv) Export(41, glColor4d) Export(42, glColor4dv) Export(43, glColor4f) Export(44, glColor4fv) Export(45, glColor4i) Export(46, glColor4iv) Export(47, glColor4s) Export(48, glColor4sv) Export(49, glColor4ub) Export(50, glColor4ubv) Export(51, glColor4ui) Export(52, glColor4uiv) Export(53, glColor4us) Export(54, glColor4usv) Export(55, glColorMask) Export(56, glColorMaterial) Export(57, glColorPointer) Export(58, glCopyPixels) Export(59, glCopyTexImage1D) Export(60, glCopyTexImage2D) Export(61, glCopyTexSubImage1D) Export(62, glCopyTexSubImage2D) Export(63, glCullFace) Export(64, glDebugEntry) Export(65, glDeleteLists) Export(66, glDeleteTextures) Export(67, glDepthFunc) Export(68, glDepthMask) Export(69, glDepthRange) Export(70, glDisable) Export(71, glDisableClientState) Export(72, glDrawArrays) Export(73, glDrawBuffer) Export(74, glDrawElements) Export(75, glDrawPixels) Export(76, glEdgeFlag) Export(77, glEdgeFlagPointer) Export(78, glEdgeFlagv) Export(79, glEnable) Export(80, glEnableClientState) Export(81, glEnd) Export(82, glEndList) Export(83, glEvalCoord1d) Export(84, glEvalCoord1dv) Export(85, glEvalCoord1f) Export(86, glEvalCoord1fv) Export(87, glEvalCoord2d) Export(88, glEvalCoord2dv) Export(89, glEvalCoord2f) Export(90, glEvalCoord2fv) Export(91, glEvalMesh1) Export(92, glEvalMesh2) Export(93, glEvalPoint1) Export(94, glEvalPoint2) Export(95, glFeedbackBuffer) Export(96, glFinish) Export(97, glFlush) Export(98, glFogf) Export(99, glFogfv) Export(100, glFogi) Export(101, glFogiv) Export(102, glFrontFace) Export(103, glFrustum) Export(104, glGenLists) Export(105, glGenTextures) Export(106, glGetBooleanv) Export(107, glGetClipPlane) Export(108, glGetDoublev) Export(109, glGetError) Export(110, glGetFloatv) Export(111, glGetIntegerv) Export(112, glGetLightfv) Export(113, glGetLightiv) Export(114, glGetMapdv) Export(115, glGetMapfv) Export(116, glGetMapiv) Export(117, glGetMaterialfv) Export(118, glGetMaterialiv) Export(119, glGetPixelMapfv) Export(120, glGetPixelMapuiv) Export(121, glGetPixelMapusv) Export(122, glGetPointerv) Export(123, glGetPolygonStipple) Export(124, glGetString) Export(125, glGetTexEnvfv) Export(126, glGetTexEnviv) Export(127, glGetTexGendv) Export(128, glGetTexGenfv) Export(129, glGetTexGeniv) Export(130, glGetTexImage) Export(131, glGetTexLevelParameterfv) Export(132, glGetTexLevelParameteriv) Export(133, glGetTexParameterfv) Export(134, glGetTexParameteriv) Export(135, glHint) Export(136, glIndexMask) Export(137, glIndexPointer) Export(138, glIndexd) Export(139, glIndexdv) Export(140, glIndexf) Export(141, glIndexfv) Export(142, glIndexi) Export(143, glIndexiv) Export(144, glIndexs) Export(145, glIndexsv) Export(146, glIndexub) Export(147, glIndexubv) Export(148, glInitNames) Export(149, glInterleavedArrays) Export(150, glIsEnabled) Export(151, glIsList) Export(152, glIsTexture) Export(153, glLightModelf) Export(154, glLightModelfv) Export(155, glLightModeli) Export(156, glLightModeliv) Export(157, glLightf) Export(158, glLightfv) Export(159, glLighti) Export(160, glLightiv) Export(161, glLineStipple) Export(162, glLineWidth) Export(163, glListBase) Export(164, glLoadIdentity) Export(165, glLoadMatrixd) Export(166, glLoadMatrixf) Export(167, glLoadName) Export(168, glLogicOp) Export(169, glMap1d) Export(170, glMap1f) Export(171, glMap2d) Export(172, glMap2f) Export(173, glMapGrid1d) Export(174, glMapGrid1f) Export(175, glMapGrid2d) Export(176, glMapGrid2f) Export(177, glMaterialf) Export(178, glMaterialfv) Export(179, glMateriali) Export(180, glMaterialiv) Export(181, glMatrixMode) Export(182, glMultMatrixd) Export(183, glMultMatrixf) Export(184, glNewList) Export(185, glNormal3b) Export(186, glNormal3bv) Export(187, glNormal3d) Export(188, glNormal3dv) Export(189, glNormal3f) Export(190, glNormal3fv) Export(191, glNormal3i) Export(192, glNormal3iv) Export(193, glNormal3s) Export(194, glNormal3sv) Export(195, glNormalPointer) Export(196, glOrtho) Export(197, glPassThrough) Export(198, glPixelMapfv) Export(199, glPixelMapuiv) Export(200, glPixelMapusv) Export(201, glPixelStoref) Export(202, glPixelStorei) Export(203, glPixelTransferf) Export(204, glPixelTransferi) Export(205, glPixelZoom) Export(206, glPointSize) Export(207, glPolygonMode) Export(208, glPolygonOffset) Export(209, glPolygonStipple) Export(210, glPopAttrib) Export(211, glPopClientAttrib) Export(212, glPopMatrix) Export(213, glPopName) Export(214, glPrioritizeTextures) Export(215, glPushAttrib) Export(216, glPushClientAttrib) Export(217, glPushMatrix) Export(218, glPushName) Export(219, glRasterPos2d) Export(220, glRasterPos2dv) Export(221, glRasterPos2f) Export(222, glRasterPos2fv) Export(223, glRasterPos2i) Export(224, glRasterPos2iv) Export(225, glRasterPos2s) Export(226, glRasterPos2sv) Export(227, glRasterPos3d) Export(228, glRasterPos3dv) Export(229, glRasterPos3f) Export(230, glRasterPos3fv) Export(231, glRasterPos3i) Export(232, glRasterPos3iv) Export(233, glRasterPos3s) Export(234, glRasterPos3sv) Export(235, glRasterPos4d) Export(236, glRasterPos4dv) Export(237, glRasterPos4f) Export(238, glRasterPos4fv) Export(239, glRasterPos4i) Export(240, glRasterPos4iv) Export(241, glRasterPos4s) Export(242, glRasterPos4sv) Export(243, glReadBuffer) Export(244, glReadPixels) Export(245, glRectd) Export(246, glRectdv) Export(247, glRectf) Export(248, glRectfv) Export(249, glRecti) Export(250, glRectiv) Export(251, glRects) Export(252, glRectsv) Export(253, glRenderMode) Export(254, glRotated) Export(255, glRotatef) Export(256, glScaled) Export(257, glScalef) Export(258, glScissor) Export(259, glSelectBuffer) Export(260, glShadeModel) Export(261, glStencilFunc) Export(262, glStencilMask) Export(263, glStencilOp) Export(264, glTexCoord1d) Export(265, glTexCoord1dv) Export(266, glTexCoord1f) Export(267, glTexCoord1fv) Export(268, glTexCoord1i) Export(269, glTexCoord1iv) Export(270, glTexCoord1s) Export(271, glTexCoord1sv) Export(272, glTexCoord2d) Export(273, glTexCoord2dv) Export(274, glTexCoord2f) Export(275, glTexCoord2fv) Export(276, glTexCoord2i) Export(277, glTexCoord2iv) Export(278, glTexCoord2s) Export(279, glTexCoord2sv) Export(280, glTexCoord3d) Export(281, glTexCoord3dv) Export(282, glTexCoord3f) Export(283, glTexCoord3fv) Export(284, glTexCoord3i) Export(285, glTexCoord3iv) Export(286, glTexCoord3s) Export(287, glTexCoord3sv) Export(288, glTexCoord4d) Export(289, glTexCoord4dv) Export(290, glTexCoord4f) Export(291, glTexCoord4fv) Export(292, glTexCoord4i) Export(293, glTexCoord4iv) Export(294, glTexCoord4s) Export(295, glTexCoord4sv) Export(296, glTexCoordPointer) Export(297, glTexEnvf) Export(298, glTexEnvfv) Export(299, glTexEnvi) Export(300, glTexEnviv) Export(301, glTexGend) Export(302, glTexGendv) Export(303, glTexGenf) Export(304, glTexGenfv) Export(305, glTexGeni) Export(306, glTexGeniv) Export(307, glTexImage1D) Export(308, glTexImage2D) Export(309, glTexParameterf) Export(310, glTexParameterfv) Export(311, glTexParameteri) Export(312, glTexParameteriv) Export(313, glTexSubImage1D) Export(314, glTexSubImage2D) Export(315, glTranslated) Export(316, glTranslatef) Export(317, glVertex2d) Export(318, glVertex2dv) Export(319, glVertex2f) Export(320, glVertex2fv) Export(321, glVertex2i) Export(322, glVertex2iv) Export(323, glVertex2s) Export(324, glVertex2sv) Export(325, glVertex3d) Export(326, glVertex3dv) Export(327, glVertex3f) Export(328, glVertex3fv) Export(329, glVertex3i) Export(330, glVertex3iv) Export(331, glVertex3s) Export(332, glVertex3sv) Export(333, glVertex4d) Export(334, glVertex4dv) Export(335, glVertex4f) Export(336, glVertex4fv) Export(337, glVertex4i) Export(338, glVertex4iv) Export(339, glVertex4s) Export(340, glVertex4sv) Export(341, glVertexPointer) Export(342, glViewport) Export(343, wglChoosePixelFormat) Export(344, wglCopyContext) Export(345, wglCreateContext) Export(346, wglCreateLayerContext) Export(347, wglDeleteContext) Export(348, wglDescribeLayerPlane) Export(349, wglDescribePixelFormat) Export(350, wglGetCurrentContext) Export(351, wglGetCurrentDC) Export(352, wglGetDefaultProcAddress) Export(353, wglGetLayerPaletteEntries) Export(354, wglGetPixelFormat) Export(355, wglGetProcAddress) Export(356, wglMakeCurrent) Export(357, wglRealizeLayerPalette) Export(358, wglSetLayerPaletteEntries) Export(359, wglSetPixelFormat) Export(360, wglShareLists) Export(361, wglSwapBuffers) Export(362, wglSwapLayerBuffers) Export(363, wglSwapMultipleBuffers) Export(364, wglUseFontBitmapsA) Export(365, wglUseFontBitmapsW) Export(366, wglUseFontOutlinesA) Export(367, wglUseFontOutlinesW) // winhttp Export(0, WinHttpPacJsWorkerMain) Export(1, WinHttpSetSecureLegacyServersAppCompat) Export(2, DllCanUnloadNow) Export(3, DllGetClassObject) Export(4, Private1) Export(5, SvchostPushServiceGlobals) Export(6, WinHttpAddRequestHeaders) Export(7, WinHttpAddRequestHeadersEx) Export(8, WinHttpAutoProxySvcMain) Export(9, WinHttpCheckPlatform) Export(10, WinHttpCloseHandle) Export(11, WinHttpConnect) Export(12, WinHttpConnectionDeletePolicyEntries) Export(13, WinHttpConnectionDeleteProxyInfo) Export(14, WinHttpConnectionFreeNameList) Export(15, WinHttpConnectionFreeProxyInfo) Export(16, WinHttpConnectionFreeProxyList) Export(17, WinHttpConnectionGetNameList) Export(18, WinHttpConnectionGetProxyInfo) Export(19, WinHttpConnectionGetProxyList) Export(20, WinHttpConnectionSetPolicyEntries) Export(21, WinHttpConnectionSetProxyInfo) Export(22, WinHttpConnectionUpdateIfIndexTable) Export(23, WinHttpCrackUrl) Export(24, WinHttpCreateProxyResolver) Export(25, WinHttpCreateUrl) Export(26, WinHttpDetectAutoProxyConfigUrl) Export(27, WinHttpFreeProxyResult) Export(28, WinHttpFreeProxyResultEx) Export(29, WinHttpFreeProxySettings) Export(30, WinHttpGetDefaultProxyConfiguration) Export(31, WinHttpGetIEProxyConfigForCurrentUser) Export(32, WinHttpGetProxyForUrl) Export(33, WinHttpGetProxyForUrlEx) Export(34, WinHttpGetProxyForUrlEx2) Export(35, WinHttpGetProxyForUrlHvsi) Export(36, WinHttpGetProxyResult) Export(37, WinHttpGetProxyResultEx) Export(38, WinHttpGetProxySettingsVersion) Export(39, WinHttpGetTunnelSocket) Export(40, WinHttpOpen) Export(41, WinHttpOpenRequest) Export(42, WinHttpProbeConnectivity) Export(43, WinHttpQueryAuthSchemes) Export(44, WinHttpQueryDataAvailable) Export(45, WinHttpQueryHeaders) Export(46, WinHttpQueryOption) Export(47, WinHttpReadData) Export(48, WinHttpReadProxySettings) Export(49, WinHttpReadProxySettingsHvsi) Export(50, WinHttpReceiveResponse) Export(51, WinHttpResetAutoProxy) Export(52, WinHttpSaveProxyCredentials) Export(53, WinHttpSendRequest) Export(54, WinHttpSetCredentials) Export(55, WinHttpSetDefaultProxyConfiguration) Export(56, WinHttpSetOption) Export(57, WinHttpSetProxySettingsPerUser) Export(58, WinHttpSetStatusCallback) Export(59, WinHttpSetTimeouts) Export(60, WinHttpTimeFromSystemTime) Export(61, WinHttpTimeToSystemTime) Export(62, WinHttpWebSocketClose) Export(63, WinHttpWebSocketCompleteUpgrade) Export(64, WinHttpWebSocketQueryCloseStatus) Export(65, WinHttpWebSocketReceive) Export(66, WinHttpWebSocketSend) Export(67, WinHttpWebSocketShutdown) Export(68, WinHttpWriteData) Export(69, WinHttpWriteProxySettings) // bink2w64 Export(0, BinkAllocateFrameBuffers) Export(1, BinkClose) Export(2, BinkCloseTrack) Export(3, BinkControlBackgroundIO) Export(4, BinkCopyToBuffer) Export(5, BinkCopyToBufferRect) Export(6, BinkDoFrame) Export(7, BinkDoFrameAsync) Export(8, BinkDoFrameAsyncMulti) Export(9, BinkDoFrameAsyncWait) Export(10, BinkDoFramePlane) Export(11, BinkFindXAudio2WinDevice) Export(12, BinkFreeGlobals) Export(13, BinkGetError) Export(14, BinkGetFrameBuffersInfo) Export(15, BinkGetGPUDataBuffersInfo) Export(16, BinkGetKeyFrame) Export(17, BinkGetPlatformInfo) Export(18, BinkGetRealtime) Export(19, BinkGetRects) Export(20, BinkGetSummary) Export(21, BinkGetTrackData) Export(22, BinkGetTrackID) Export(23, BinkGetTrackMaxSize) Export(24, BinkGetTrackType) Export(25, BinkGoto) Export(26, BinkLogoAddress) Export(27, BinkNextFrame) Export(28, BinkOpen) Export(29, BinkOpenDirectSound) Export(30, BinkOpenTrack) Export(31, BinkOpenWaveOut) Export(32, BinkOpenWithOptions) Export(33, BinkOpenXAudio2) Export(34, BinkOpenXAudio27) Export(35, BinkOpenXAudio28) Export(36, BinkOpenXAudio29) Export(37, BinkPause) Export(38, BinkRegisterFrameBuffers) Export(39, BinkRegisterGPUDataBuffers) Export(40, BinkRequestStopAsyncThread) Export(41, BinkRequestStopAsyncThreadsMulti) Export(42, BinkService) Export(43, BinkSetError) Export(44, BinkSetFileOffset) Export(45, BinkSetFrameRate) Export(46, BinkSetIO) Export(47, BinkSetIOSize) Export(48, BinkSetMemory) Export(49, BinkSetOSFileCallbacks) Export(50, BinkSetPan) Export(51, BinkSetSimulate) Export(52, BinkSetSoundOnOff) Export(53, BinkSetSoundSystem) Export(54, BinkSetSoundSystem2) Export(55, BinkSetSoundTrack) Export(56, BinkSetSpeakerVolumes) Export(57, BinkSetVideoOnOff) Export(58, BinkSetVolume) Export(59, BinkSetWillLoop) Export(60, BinkShouldSkip) Export(61, BinkStartAsyncThread) Export(62, BinkUtilCPUs) Export(63, BinkUtilFree) Export(64, BinkUtilMalloc) Export(65, BinkUtilMutexCreate) Export(66, BinkUtilMutexDestroy) Export(67, BinkUtilMutexLock) Export(68, BinkUtilMutexLockTimeOut) Export(69, BinkUtilMutexUnlock) Export(70, BinkUtilSoundGlobalLock) Export(71, BinkUtilSoundGlobalUnlock) Export(72, BinkWait) Export(73, BinkWaitStopAsyncThread) Export(74, BinkWaitStopAsyncThreadsMulti) Export(75, RADTimerRead) ================================================ FILE: include/nmd_assembly.h ================================================ /* This is a platform independent C89 x86 assembler and disassembler library. Features: - Support for x86(16/32/64). Intel and AT&T syntax. - No libc, dynamic memory allocation, static/global variables/state/context or runtime initialization. - Thread-safe by design. - No header files need to be included. Setup: Define the 'NMD_ASSEMBLY_IMPLEMENTATION' macro in one source file before the include statement to instantiate the implementation. #define NMD_ASSEMBLY_IMPLEMENTATION #include "nmd_assembly.h" Interfaces(i.e the functions you call from your application): - The assembler is implemented by the following function: Assembles an instruction from a string. Returns the number of bytes written to the buffer on success, zero otherwise. Instructions can be separated using the '\n'(new line) character. Parameters: - string [in] A pointer to a string that represents one or more instructions in assembly language. - buffer [out] A pointer to a buffer that receives the encoded instructions. - buffer_size [in] The size of the buffer in bytes. - runtime_address [in] The instruction's runtime address. You may use 'NMD_X86_INVALID_RUNTIME_ADDRESS'. - mode [in] The architecture mode. 'NMD_X86_MODE_32', 'NMD_X86_MODE_64' or 'NMD_X86_MODE_16'. - count [in/out/opt] A pointer to a variable that on input is the maximum number of instructions that can be parsed(or zero for unlimited instructions), and on output is the number of instructions parsed. This parameter may be zero. size_t nmd_x86_assemble(const char* string, void* buffer, size_t buffer_size, uint64_t runtime_address, NMD_X86_MODE mode, size_t* const count); - The disassembler is composed of a decoder and a formatter implemented by these two functions respectively: - Decodes an instruction. Returns true if the instruction is valid, false otherwise. Parameters: - buffer [in] A pointer to a buffer containing an encoded instruction. - buffer_size [in] The size of the buffer in bytes. - instruction [out] A pointer to a variable of type 'nmd_x86_instruction' that receives information about the instruction. - mode [in] The architecture mode. 'NMD_X86_MODE_32', 'NMD_X86_MODE_64' or 'NMD_X86_MODE_16'. - flags [in] A mask of 'NMD_X86_DECODER_FLAGS_XXX' that specifies which features the decoder is allowed to use. If uncertain, use 'NMD_X86_DECODER_FLAGS_MINIMAL'. bool nmd_x86_decode(const void* buffer, size_t buffer_size, nmd_x86_instruction* instruction, NMD_X86_MODE mode, uint32_t flags); - Formats an instruction. This function may access invalid memory(thus causing a crash) if you modify 'instruction' manually. Parameters: - instruction [in] A pointer to a variable of type 'nmd_x86_instruction' describing the instruction to be formatted. - buffer [out] A pointer to buffer that receives the string. The buffer's recommended size is 128 bytes. - runtime_address [in] The instruction's runtime address. You may use 'NMD_X86_INVALID_RUNTIME_ADDRESS'. - flags [in] A mask of 'NMD_X86_FORMAT_FLAGS_XXX' that specifies how the function should format the instruction. If uncertain, use 'NMD_X86_FORMAT_FLAGS_DEFAULT'. void nmd_x86_format(const nmd_x86_instruction* instruction, char buffer[], uint64_t runtime_address, uint32_t flags); - The length disassembler is implemented by the following function: Returns the length of the instruction if it is valid, zero otherwise. Parameters: - buffer [in] A pointer to a buffer containing an encoded instruction. - buffer_size [in] The size of the buffer in bytes. - mode [in] The architecture mode. 'NMD_X86_MODE_32', 'NMD_X86_MODE_64' or 'NMD_X86_MODE_16'. size_t nmd_x86_ldisasm(const void* buffer, size_t buffer_size, NMD_X86_MODE mode); Enabling and disabling features of the decoder at compile-time: To dynamically choose which features are used by the decoder, use the 'flags' parameter of nmd_x86_decode(). The less features specified in the mask, the faster the decoder runs. By default all features are available, some can be completely disabled at compile time(thus reducing code size and increasing code speed) by defining the following macros: - 'NMD_ASSEMBLY_DISABLE_DECODER_VALIDITY_CHECK': the decoder does not check if the instruction is invalid. - 'NMD_ASSEMBLY_DISABLE_DECODER_INSTRUCTION_ID': the decoder does not fill the 'id' variable. - 'NMD_ASSEMBLY_DISABLE_DECODER_CPU_FLAGS': the decoder does not fill the variables related to cpu fags. - 'NMD_ASSEMBLY_DISABLE_DECODER_OPERANDS': the decoder does not fill the 'num_operands' and 'operands' variable. - 'NMD_ASSEMBLY_DISABLE_DECODER_GROUP': the decoder does not fill the 'group' variable. - 'NMD_ASSEMBLY_DISABLE_DECODER_VEX': the decoder does not support VEX instructions. - 'NMD_ASSEMBLY_DISABLE_DECODER_EVEX': the decoder does not support EVEX instructions. - 'NMD_ASSEMBLY_DISABLE_DECODER_3DNOW': the decoder does not support 3DNow! instructions. Enabling and disabling features of the formatter at compile-time: To dynamically choose which features are used by the formatter, use the 'flags' parameter of nmd_x86_format(). The less features specified in the mask, the faster the function runs. By default all features are available, some can be completely disabled at compile time(thus reducing code size and increasing code speed) by defining the following macros: - 'NMD_ASSEMBLY_DISABLE_FORMATTER_POINTER_SIZE': the formatter does not support pointer size. - 'NMD_ASSEMBLY_DISABLE_FORMATTER_BYTES: the formatter does not support instruction bytes. You may define the 'NMD_X86_FORMATTER_NUM_PADDING_BYTES' macro to be the number of bytes used as space padding. - 'NMD_ASSEMBLY_DISABLE_FORMATTER_ATT_SYNTAX: the formatter does not support AT&T syntax. - 'NMD_ASSEMBLY_DISABLE_FORMATTER_UPPERCASE: the formatter does not support uppercase. - 'NMD_ASSEMBLY_DISABLE_FORMATTER_COMMA_SPACES: the formatter does not support comma spaces. - 'NMD_ASSEMBLY_DISABLE_FORMATTER_OPERATOR_SPACES: the formatter does not support operator spaces. - 'NMD_ASSEMBLY_DISABLE_FORMATTER_VEX': the formatter does not support VEX instructions. - 'NMD_ASSEMBLY_DISABLE_FORMATTER_EVEX': the formatter does not support EVEX instructions. - 'NMD_ASSEMBLY_DISABLE_FORMATTER_3DNOW': the formatter does not support 3DNow! instructions. Enabling and disabling features of the length disassembler at compile-time: Use the following macros to disable features at compile-time: - 'NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK': the length disassembler does not check if the instruction is invalid. - 'NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VEX': the length disassembler does not support VEX instructions. - 'NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_3DNOW': the length disassembler does not support 3DNow! instructions. Fixed width integer types: By default the library includes and to include int types. If these header-files are not available in your environment you may define the 'NMD_DEFINE_INT_TYPES' macro so the library will define them. By defining the 'NMD_IGNORE_INT_TYPES' macro, the library will neither include nor define int types. You may define the 'NMD_ASSEMBLY_PRIVATE' macro to mark all functions as static so that they're not visible to other translation units. Common helper functions: Some 'nmd' libraries utilize the same functions such as '_nmd_assembly_get_num_digits' and '_nmd_assembly_get_num_digits_hex'. All libraries include the same implementation which internally are defined as '_nmd_[LIBRARY_NAME]_[FUNCTION_NAME]' to avoid name conflits between them. When the function is called a macro is used in the form '_NMD_FUNCTION_NAME', this allows another function to override the default implementation, so in the case that two 'nmd' libraries need the same function, only one implementation will be used by both libraries. You may also provide your implemetation: Example: size_t my_get_num_digits(int x); #define _NMD_GET_NUM_DIGITS my_get_num_digits Shared helper functions used by this library: - _NMD_GET_NUM_DIGITS() - _NMD_GET_NUM_DIGITS_HEX() Conventions: - Every identifier uses snake case. - Enums and macros are uppercase, every other identifier is lowercase. - Non-internal identifiers start with the 'NMD_' prefix. - Internal identifiers start with the '_NMD_' prefix. TODO: Short-Term - Implement instruction set extensions to the decoder : VEX, EVEX, MVEX, 3DNOW, XOP. - Implement x86 assembler Long-Term - Add support for other architectures(ARM, MIPS and PowerPC ?). References: - Intel 64 and IA-32 Architectures. Software Developer's Manual Volume 2 (2A, 2B, 2C & 2D): Instruction Set Reference, A-Z. - Chapter 2 Instruction Format. - Chapter 3-5 Instruction set reference. - Appendix A Opcode Map. - Appendix B.16 Instruction and Formats and Encoding. - 3DNow! Technology Manual. - AMD Extensions to the 3DNow! and MMX Instruction Sets Manual. - Intel Architecture Instruction Set Extensions and Future Features Programming Reference. - Capstone Engine. - Zydis Disassembler. - VIA PadLock Programming Guide. - Control registers - Wikipedia. Contributors(This may not be a complete list): - Nomade: Founder and maintainer. - Darkratos: Bug reporting and feature suggesting. */ #ifndef NMD_ASSEMBLY_H #define NMD_ASSEMBLY_H #ifndef _NMD_DEFINE_INT_TYPES #ifdef NMD_DEFINE_INT_TYPES #define _NMD_DEFINE_INT_TYPES #ifndef __cplusplus #define bool _Bool #define false 0 #define true 1 #endif /* __cplusplus */ typedef signed char int8_t; typedef unsigned char uint8_t; typedef signed short int16_t; typedef unsigned short uint16_t; typedef signed int int32_t; typedef unsigned int uint32_t; typedef signed long long int64_t; typedef unsigned long long uint64_t; #if defined(_WIN64) && defined(_MSC_VER) typedef unsigned __int64 size_t; typedef __int64 ptrdiff_t; #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER) typedef unsigned __int32 size_t typedef __int32 ptrdiff_t; #elif defined(__GNUC__) || defined(__clang__) #if defined(__x86_64__) || defined(__ppc64__) typedef unsigned long size_t typedef long ptrdiff_t #else typedef unsigned int size_t typedef int ptrdiff_t #endif #else typedef unsigned long size_t typedef long ptrdiff_t #endif #else /* NMD_DEFINE_INT_TYPES */ #ifndef NMD_IGNORE_INT_TYPES #include #include #include #endif /* NMD_IGNORE_INT_TYPES */ #endif /* NMD_DEFINE_INT_TYPES */ #endif /* _NMD_DEFINE_INT_TYPES */ #ifndef _NMD_GET_NUM_DIGITS #define _NMD_GET_NUM_DIGITS _nmd_assembly_get_num_digits #endif /* _NMD_GET_NUM_DIGITS */ #ifndef _NMD_GET_NUM_DIGITS_HEX #define _NMD_GET_NUM_DIGITS_HEX _nmd_assembly_get_num_digits_hex #endif /* _NMD_GET_NUM_DIGITS_HEX */ #ifndef NMD_X86_FORMATTER_NUM_PADDING_BYTES #define NMD_X86_FORMATTER_NUM_PADDING_BYTES 10 #endif /* NMD_X86_FORMATTER_NUM_PADDING_BYTES */ #define NMD_X86_INVALID_RUNTIME_ADDRESS ((uint64_t)(-1)) #define NMD_X86_MAXIMUM_INSTRUCTION_LENGTH 15 #define NMD_X86_MAXIMUM_NUM_OPERANDS 10 /* Define the api macro to potentially change functions's attributes. */ #ifndef NMD_ASSEMBLY_API #ifdef NMD_ASSEMBLY_PRIVATE #define NMD_ASSEMBLY_API static #else #define NMD_ASSEMBLY_API #endif /* NMD_ASSEMBLY_PRIVATE */ #endif /* NMD_ASSEMBLY_API */ /* These flags specify how the formatter should work. */ enum NMD_X86_FORMATTER_FLAGS { NMD_X86_FORMAT_FLAGS_HEX = (1 << 0), /* If set, numbers are displayed in hex base, otherwise they are displayed in decimal base. */ NMD_X86_FORMAT_FLAGS_POINTER_SIZE = (1 << 1), /* Pointer sizes(e.g. 'dword ptr', 'byte ptr') are displayed. */ NMD_X86_FORMAT_FLAGS_ONLY_SEGMENT_OVERRIDE = (1 << 2), /* If set, only segment overrides using prefixes(e.g. '2EH', '64H') are displayed, otherwise a segment is always present before a memory operand. */ NMD_X86_FORMAT_FLAGS_COMMA_SPACES = (1 << 3), /* A space is placed after a comma. */ NMD_X86_FORMAT_FLAGS_OPERATOR_SPACES = (1 << 4), /* A space is placed before and after the '+' and '-' characters. */ NMD_X86_FORMAT_FLAGS_UPPERCASE = (1 << 5), /* The string is uppercase. */ NMD_X86_FORMAT_FLAGS_0X_PREFIX = (1 << 6), /* Hexadecimal numbers have the '0x'('0X' if uppercase) prefix. */ NMD_X86_FORMAT_FLAGS_H_SUFFIX = (1 << 7), /* Hexadecimal numbers have the 'h'('H' if uppercase') suffix. */ NMD_X86_FORMAT_FLAGS_ENFORCE_HEX_ID = (1 << 8), /* If the HEX flag is set and either the prefix or suffix flag is also set, numbers less than 10 are displayed with preffix or suffix. */ NMD_X86_FORMAT_FLAGS_HEX_LOWERCASE = (1 << 9), /* If the HEX flag is set and the UPPERCASE flag is not set, hexadecimal numbers are displayed in lowercase. */ NMD_X86_FORMAT_FLAGS_SIGNED_NUMBER_MEMORY_VIEW = (1 << 10), /* If set, signed numbers are displayed as they are represented in memory(e.g. -1 = 0xFFFFFFFF). */ NMD_X86_FORMAT_FLAGS_SIGNED_NUMBER_HINT_HEX = (1 << 11), /* If set and NMD_X86_FORMAT_FLAGS_SIGNED_NUMBER_MEMORY_VIEW is also set, the number's hexadecimal representation is displayed in parenthesis. */ NMD_X86_FORMAT_FLAGS_SIGNED_NUMBER_HINT_DEC = (1 << 12), /* Same as NMD_X86_FORMAT_FLAGS_SIGNED_NUMBER_HINT_HEX, but the number is displayed in decimal base. */ NMD_X86_FORMAT_FLAGS_SCALE_ONE = (1 << 13), /* If set, scale one is displayed. E.g. add byte ptr [eax+eax*1], al. */ NMD_X86_FORMAT_FLAGS_BYTES = (1 << 14), /* The instruction's bytes are displayed before the instructions. */ NMD_X86_FORMAT_FLAGS_ATT_SYNTAX = (1 << 15), /* AT&T syntax is used instead of Intel's. */ /* The formatter's default formatting style. */ NMD_X86_FORMAT_FLAGS_DEFAULT = (NMD_X86_FORMAT_FLAGS_HEX | NMD_X86_FORMAT_FLAGS_H_SUFFIX | NMD_X86_FORMAT_FLAGS_ONLY_SEGMENT_OVERRIDE | NMD_X86_FORMAT_FLAGS_SIGNED_NUMBER_MEMORY_VIEW | NMD_X86_FORMAT_FLAGS_SIGNED_NUMBER_HINT_DEC), }; enum NMD_X86_DECODER_FLAGS { NMD_X86_DECODER_FLAGS_VALIDITY_CHECK = (1 << 0), /* The decoder checks if the instruction is valid. */ NMD_X86_DECODER_FLAGS_INSTRUCTION_ID = (1 << 1), /* The decoder fills the 'id' variable. */ NMD_X86_DECODER_FLAGS_CPU_FLAGS = (1 << 2), /* The decoder fills the variables related to cpu flags. */ NMD_X86_DECODER_FLAGS_OPERANDS = (1 << 3), /* The decoder fills the 'num_operands' and 'operands' variable. */ NMD_X86_DECODER_FLAGS_GROUP = (1 << 4), /* The decoder fills 'group' variable. */ NMD_X86_DECODER_FLAGS_VEX = (1 << 5), /* The decoder parses VEX instructions. */ NMD_X86_DECODER_FLAGS_EVEX = (1 << 6), /* The decoder parses EVEX instructions. */ NMD_X86_DECODER_FLAGS_3DNOW = (1 << 7), /* The decoder parses 3DNow! instructions. */ /* These are not actual features, but rather masks of features. */ NMD_X86_DECODER_FLAGS_NONE = 0, NMD_X86_DECODER_FLAGS_MINIMAL = (NMD_X86_DECODER_FLAGS_VALIDITY_CHECK | NMD_X86_DECODER_FLAGS_VEX | NMD_X86_DECODER_FLAGS_EVEX), /* Mask that specifies minimal features to provide acurate results in any environment. */ NMD_X86_DECODER_FLAGS_ALL = (1 << 8) - 1, /* Mask that specifies all features. */ }; enum NMD_X86_PREFIXES { NMD_X86_PREFIXES_NONE = 0, NMD_X86_PREFIXES_ES_SEGMENT_OVERRIDE = (1 << 0), NMD_X86_PREFIXES_CS_SEGMENT_OVERRIDE = (1 << 1), NMD_X86_PREFIXES_SS_SEGMENT_OVERRIDE = (1 << 2), NMD_X86_PREFIXES_DS_SEGMENT_OVERRIDE = (1 << 3), NMD_X86_PREFIXES_FS_SEGMENT_OVERRIDE = (1 << 4), NMD_X86_PREFIXES_GS_SEGMENT_OVERRIDE = (1 << 5), NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE = (1 << 6), NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE = (1 << 7), NMD_X86_PREFIXES_LOCK = (1 << 8), NMD_X86_PREFIXES_REPEAT_NOT_ZERO = (1 << 9), NMD_X86_PREFIXES_REPEAT = (1 << 10), NMD_X86_PREFIXES_REX_W = (1 << 11), NMD_X86_PREFIXES_REX_R = (1 << 12), NMD_X86_PREFIXES_REX_X = (1 << 13), NMD_X86_PREFIXES_REX_B = (1 << 14) }; enum NMD_X86_IMM { NMD_X86_IMM_NONE = 0, NMD_X86_IMM8 = 1, NMD_X86_IMM16 = 2, NMD_X86_IMM32 = 4, NMD_X86_IMM48 = 6, NMD_X86_IMM64 = 8, NMD_X86_IMM_ANY = (NMD_X86_IMM8 | NMD_X86_IMM16 | NMD_X86_IMM32 | NMD_X86_IMM64) }; enum NMD_X86_DISP { NMD_X86_DISP_NONE = 0, NMD_X86_DISP8 = 1, NMD_X86_DISP16 = 2, NMD_X86_DISP32 = 4, NMD_X86_DISP64 = 8, NMD_X86_DISP_ANY = (NMD_X86_DISP8 | NMD_X86_DISP16 | NMD_X86_DISP32) }; typedef union nmd_x86_modrm { struct { uint8_t rm : 3; uint8_t reg : 3; uint8_t mod : 2; } fields; uint8_t modrm; } nmd_x86_modrm; typedef union nmd_x86_sib { struct { uint8_t base : 3; uint8_t index : 3; uint8_t scale : 2; } fields; uint8_t sib; } nmd_x86_sib; typedef enum NMD_X86_MODE { NMD_X86_MODE_NONE = 0, /* Invalid mode. */ NMD_X86_MODE_16 = 2, NMD_X86_MODE_32 = 4, NMD_X86_MODE_64 = 8, } NMD_X86_MODE; enum NMD_X86_OPCODE_MAP { NMD_X86_OPCODE_MAP_NONE = 0, NMD_X86_OPCODE_MAP_DEFAULT, NMD_X86_OPCODE_MAP_0F, NMD_X86_OPCODE_MAP_0F38, NMD_X86_OPCODE_MAP_0F3A, NMD_X86_OPCODE_MAP_0F0F }; enum NMD_X86_ENCODING { NMD_X86_ENCODING_NONE = 0, NMD_X86_ENCODING_LEGACY, /* Legacy encoding. */ NMD_X86_ENCODING_VEX, /* Intel's VEX(vector extensions) coding scheme. */ NMD_X86_ENCODING_EVEX, /* Intel's EVEX(Enhanced vector extension) coding scheme. */ NMD_X86_ENCODING_3DNOW, /* AMD's 3DNow! extension. */ NMD_X86_ENCODING_XOP, /* AMD's XOP(eXtended Operations) instruction set. */ /* NMD_X86_ENCODING_MVEX, MVEX used by Intel's "Xeon Phi" ISA. */ }; typedef struct nmd_x86_vex { bool R : 1; bool X : 1; bool B : 1; bool L : 1; bool W : 1; uint8_t pp : 2; uint8_t m_mmmm : 5; uint8_t vvvv : 4; uint8_t vex[3]; /* The full vex prefix. vex[0] is either C4h(3-byte VEX) or C5h(2-byte VEX).*/ } nmd_x86_vex; enum NMD_GROUP { NMD_GROUP_NONE = 0, /* The instruction is not part of any group. */ NMD_GROUP_JUMP = (1 << 0), /* All jump instructions. */ NMD_GROUP_CALL = (1 << 1), /* Call instruction. */ NMD_GROUP_RET = (1 << 2), /* Return instruction. */ NMD_GROUP_INT = (1 << 3), /* Interrupt instruction. */ NMD_GROUP_PRIVILEGE = (1 << 4), /* Privileged instruction. */ NMD_GROUP_CONDITIONAL_BRANCH = (1 << 5), /* Conditional branch instruction. */ NMD_GROUP_UNCONDITIONAL_BRANCH = (1 << 6), /* Unconditional branch instruction. */ NMD_GROUP_RELATIVE_ADDRESSING = (1 << 7), /* Relative addressing instruction. */ /* These are not actual groups, but rather masks of groups. */ NMD_GROUP_BRANCH = (NMD_GROUP_CONDITIONAL_BRANCH | NMD_GROUP_UNCONDITIONAL_BRANCH), /* Mask used to check if the instruction is a branch instruction. */ NMD_GROUP_ANY = (1 << 8) - 1, /* Mask used to check if the instruction is part of any group. */ }; /* The enums for a some classes of registers always start at a multiple of eight */ typedef enum NMD_X86_REG { NMD_X86_REG_NONE = 0, NMD_X86_REG_IP = 8, NMD_X86_REG_EIP = 9, NMD_X86_REG_RIP = 10, NMD_X86_REG_AL = 16, NMD_X86_REG_CL = 17, NMD_X86_REG_DL = 18, NMD_X86_REG_BL = 19, NMD_X86_REG_AH = 20, NMD_X86_REG_CH = 21, NMD_X86_REG_DH = 22, NMD_X86_REG_BH = 23, NMD_X86_REG_AX = 24, NMD_X86_REG_CX = 25, NMD_X86_REG_DX = 26, NMD_X86_REG_BX = 27, NMD_X86_REG_SP = 28, NMD_X86_REG_BP = 29, NMD_X86_REG_SI = 30, NMD_X86_REG_DI = 31, NMD_X86_REG_EAX = 32, NMD_X86_REG_ECX = 33, NMD_X86_REG_EDX = 34, NMD_X86_REG_EBX = 35, NMD_X86_REG_ESP = 36, NMD_X86_REG_EBP = 37, NMD_X86_REG_ESI = 38, NMD_X86_REG_EDI = 39, NMD_X86_REG_RAX = 40, NMD_X86_REG_RCX = 41, NMD_X86_REG_RDX = 42, NMD_X86_REG_RBX = 43, NMD_X86_REG_RSP = 44, NMD_X86_REG_RBP = 45, NMD_X86_REG_RSI = 46, NMD_X86_REG_RDI = 47, NMD_X86_REG_R8 = 48, NMD_X86_REG_R9 = 49, NMD_X86_REG_R10 = 50, NMD_X86_REG_R11 = 51, NMD_X86_REG_R12 = 52, NMD_X86_REG_R13 = 53, NMD_X86_REG_R14 = 54, NMD_X86_REG_R15 = 55, NMD_X86_REG_R8B = 56, NMD_X86_REG_R9B = 57, NMD_X86_REG_R10B = 58, NMD_X86_REG_R11B = 59, NMD_X86_REG_R12B = 60, NMD_X86_REG_R13B = 61, NMD_X86_REG_R14B = 62, NMD_X86_REG_R15B = 63, NMD_X86_REG_R8W = 64, NMD_X86_REG_R9W = 65, NMD_X86_REG_R10W = 66, NMD_X86_REG_R11W = 67, NMD_X86_REG_R12W = 68, NMD_X86_REG_R13W = 69, NMD_X86_REG_R14W = 70, NMD_X86_REG_R15W = 71, NMD_X86_REG_R8D = 72, NMD_X86_REG_R9D = 73, NMD_X86_REG_R10D = 74, NMD_X86_REG_R11D = 75, NMD_X86_REG_R12D = 76, NMD_X86_REG_R13D = 77, NMD_X86_REG_R14D = 78, NMD_X86_REG_R15D = 79, NMD_X86_REG_ES = 80, NMD_X86_REG_CS = 81, NMD_X86_REG_SS = 82, NMD_X86_REG_DS = 83, NMD_X86_REG_FS = 84, NMD_X86_REG_GS = 85, NMD_X86_REG_CR0 = 88, NMD_X86_REG_CR1 = 89, NMD_X86_REG_CR2 = 90, NMD_X86_REG_CR3 = 91, NMD_X86_REG_CR4 = 92, NMD_X86_REG_CR5 = 93, NMD_X86_REG_CR6 = 94, NMD_X86_REG_CR7 = 95, NMD_X86_REG_CR8 = 96, NMD_X86_REG_CR9 = 97, NMD_X86_REG_CR10 = 98, NMD_X86_REG_CR11 = 99, NMD_X86_REG_CR12 = 100, NMD_X86_REG_CR13 = 101, NMD_X86_REG_CR14 = 102, NMD_X86_REG_CR15 = 103, NMD_X86_REG_DR0 = 104, NMD_X86_REG_DR1 = 105, NMD_X86_REG_DR2 = 106, NMD_X86_REG_DR3 = 107, NMD_X86_REG_DR4 = 108, NMD_X86_REG_DR5 = 109, NMD_X86_REG_DR6 = 110, NMD_X86_REG_DR7 = 111, NMD_X86_REG_DR8 = 112, NMD_X86_REG_DR9 = 113, NMD_X86_REG_DR10 = 114, NMD_X86_REG_DR11 = 115, NMD_X86_REG_DR12 = 116, NMD_X86_REG_DR13 = 117, NMD_X86_REG_DR14 = 118, NMD_X86_REG_DR15 = 119, NMD_X86_REG_MM0 = 120, NMD_X86_REG_MM1 = 121, NMD_X86_REG_MM2 = 122, NMD_X86_REG_MM3 = 123, NMD_X86_REG_MM4 = 124, NMD_X86_REG_MM5 = 125, NMD_X86_REG_MM6 = 126, NMD_X86_REG_MM7 = 127, NMD_X86_REG_XMM0 = 128, NMD_X86_REG_XMM1 = 129, NMD_X86_REG_XMM2 = 130, NMD_X86_REG_XMM3 = 131, NMD_X86_REG_XMM4 = 132, NMD_X86_REG_XMM5 = 133, NMD_X86_REG_XMM6 = 134, NMD_X86_REG_XMM7 = 135, NMD_X86_REG_XMM8 = 136, NMD_X86_REG_XMM9 = 137, NMD_X86_REG_XMM10 = 138, NMD_X86_REG_XMM11 = 139, NMD_X86_REG_XMM12 = 140, NMD_X86_REG_XMM13 = 141, NMD_X86_REG_XMM14 = 142, NMD_X86_REG_XMM15 = 143, NMD_X86_REG_XMM16 = 144, NMD_X86_REG_XMM17 = 145, NMD_X86_REG_XMM18 = 146, NMD_X86_REG_XMM19 = 147, NMD_X86_REG_XMM20 = 148, NMD_X86_REG_XMM21 = 149, NMD_X86_REG_XMM22 = 150, NMD_X86_REG_XMM23 = 151, NMD_X86_REG_XMM24 = 152, NMD_X86_REG_XMM25 = 153, NMD_X86_REG_XMM26 = 154, NMD_X86_REG_XMM27 = 155, NMD_X86_REG_XMM28 = 156, NMD_X86_REG_XMM29 = 157, NMD_X86_REG_XMM30 = 158, NMD_X86_REG_XMM31 = 159, NMD_X86_REG_YMM0 = 160, NMD_X86_REG_YMM1 = 161, NMD_X86_REG_YMM2 = 162, NMD_X86_REG_YMM3 = 163, NMD_X86_REG_YMM4 = 164, NMD_X86_REG_YMM5 = 165, NMD_X86_REG_YMM6 = 166, NMD_X86_REG_YMM7 = 167, NMD_X86_REG_YMM8 = 168, NMD_X86_REG_YMM9 = 169, NMD_X86_REG_YMM10 = 170, NMD_X86_REG_YMM11 = 171, NMD_X86_REG_YMM12 = 172, NMD_X86_REG_YMM13 = 173, NMD_X86_REG_YMM14 = 174, NMD_X86_REG_YMM15 = 175, NMD_X86_REG_YMM16 = 176, NMD_X86_REG_YMM17 = 177, NMD_X86_REG_YMM18 = 178, NMD_X86_REG_YMM19 = 179, NMD_X86_REG_YMM20 = 180, NMD_X86_REG_YMM21 = 181, NMD_X86_REG_YMM22 = 182, NMD_X86_REG_YMM23 = 183, NMD_X86_REG_YMM24 = 184, NMD_X86_REG_YMM25 = 185, NMD_X86_REG_YMM26 = 186, NMD_X86_REG_YMM27 = 187, NMD_X86_REG_YMM28 = 188, NMD_X86_REG_YMM29 = 189, NMD_X86_REG_YMM30 = 190, NMD_X86_REG_YMM31 = 191, NMD_X86_REG_ZMM0 = 192, NMD_X86_REG_ZMM1 = 193, NMD_X86_REG_ZMM2 = 194, NMD_X86_REG_ZMM3 = 195, NMD_X86_REG_ZMM4 = 196, NMD_X86_REG_ZMM5 = 197, NMD_X86_REG_ZMM6 = 198, NMD_X86_REG_ZMM7 = 199, NMD_X86_REG_ZMM8 = 200, NMD_X86_REG_ZMM9 = 201, NMD_X86_REG_ZMM10 = 202, NMD_X86_REG_ZMM11 = 203, NMD_X86_REG_ZMM12 = 204, NMD_X86_REG_ZMM13 = 205, NMD_X86_REG_ZMM14 = 206, NMD_X86_REG_ZMM15 = 207, NMD_X86_REG_ZMM16 = 208, NMD_X86_REG_ZMM17 = 209, NMD_X86_REG_ZMM18 = 210, NMD_X86_REG_ZMM19 = 211, NMD_X86_REG_ZMM20 = 212, NMD_X86_REG_ZMM21 = 213, NMD_X86_REG_ZMM22 = 214, NMD_X86_REG_ZMM23 = 215, NMD_X86_REG_ZMM24 = 216, NMD_X86_REG_ZMM25 = 217, NMD_X86_REG_ZMM26 = 218, NMD_X86_REG_ZMM27 = 219, NMD_X86_REG_ZMM28 = 220, NMD_X86_REG_ZMM29 = 221, NMD_X86_REG_ZMM30 = 222, NMD_X86_REG_ZMM31 = 223, NMD_X86_REG_K0 = 224, NMD_X86_REG_K1 = 225, NMD_X86_REG_K2 = 226, NMD_X86_REG_K3 = 227, NMD_X86_REG_K4 = 228, NMD_X86_REG_K5 = 229, NMD_X86_REG_K6 = 230, NMD_X86_REG_K7 = 231, NMD_X86_REG_ST0 = 232, NMD_X86_REG_ST1 = 233, NMD_X86_REG_ST2 = 234, NMD_X86_REG_ST3 = 235, NMD_X86_REG_ST4 = 236, NMD_X86_REG_ST5 = 237, NMD_X86_REG_ST6 = 238, NMD_X86_REG_ST7 = 239, } NMD_X86_REG; /* Credits to the capstone engine: Some members of the enum are organized in such a way because the instruction's id parsing component of the decoder can take advantage of it. If an instruction as marked as 'padding', it means that it's being used to fill holes between instructions organized in a special way for optimization reasons. */ enum NMD_X86_INSTRUCTION { NMD_X86_INSTRUCTION_INVALID = 0, /* Optimized for opcode extension group 1. */ NMD_X86_INSTRUCTION_ADD, NMD_X86_INSTRUCTION_OR, NMD_X86_INSTRUCTION_ADC, NMD_X86_INSTRUCTION_SBB, NMD_X86_INSTRUCTION_AND, NMD_X86_INSTRUCTION_SUB, NMD_X86_INSTRUCTION_XOR, NMD_X86_INSTRUCTION_CMP, /* Optimized for opcode extension group 2. */ NMD_X86_INSTRUCTION_ROL, NMD_X86_INSTRUCTION_ROR, NMD_X86_INSTRUCTION_RCL, NMD_X86_INSTRUCTION_RCR, NMD_X86_INSTRUCTION_SHL, NMD_X86_INSTRUCTION_SHR, NMD_X86_INSTRUCTION_AAA, /* padding */ NMD_X86_INSTRUCTION_SAR, /* Optimized for opcode extension group 3. */ NMD_X86_INSTRUCTION_TEST, NMD_X86_INSTRUCTION_BLSFILL, /* pading */ NMD_X86_INSTRUCTION_NOT, NMD_X86_INSTRUCTION_NEG, NMD_X86_INSTRUCTION_MUL, NMD_X86_INSTRUCTION_IMUL, NMD_X86_INSTRUCTION_DIV, NMD_X86_INSTRUCTION_IDIV, /* Optimized for opcode extension group 5. */ NMD_X86_INSTRUCTION_INC, NMD_X86_INSTRUCTION_DEC, NMD_X86_INSTRUCTION_CALL, NMD_X86_INSTRUCTION_LCALL, NMD_X86_INSTRUCTION_JMP, NMD_X86_INSTRUCTION_LJMP, NMD_X86_INSTRUCTION_PUSH, /* Optimized for the 7th row of the 1 byte opcode map and the 8th row of the 2 byte opcode map. */ NMD_X86_INSTRUCTION_JO, NMD_X86_INSTRUCTION_JNO, NMD_X86_INSTRUCTION_JB, NMD_X86_INSTRUCTION_JNB, NMD_X86_INSTRUCTION_JZ, NMD_X86_INSTRUCTION_JNZ, NMD_X86_INSTRUCTION_JBE, NMD_X86_INSTRUCTION_JA, NMD_X86_INSTRUCTION_JS, NMD_X86_INSTRUCTION_JNS, NMD_X86_INSTRUCTION_JP, NMD_X86_INSTRUCTION_JNP, NMD_X86_INSTRUCTION_JL, NMD_X86_INSTRUCTION_JGE, NMD_X86_INSTRUCTION_JLE, NMD_X86_INSTRUCTION_JG, /* Optimized for escape opcodes with D8 as first byte. */ NMD_X86_INSTRUCTION_FADD, NMD_X86_INSTRUCTION_FMUL, NMD_X86_INSTRUCTION_FCOM, NMD_X86_INSTRUCTION_FCOMP, NMD_X86_INSTRUCTION_FSUB, NMD_X86_INSTRUCTION_FSUBR, NMD_X86_INSTRUCTION_FDIV, NMD_X86_INSTRUCTION_FDIVR, /* Optimized for escape opcodes with D9 as first byte. */ NMD_X86_INSTRUCTION_FLD, NMD_X86_INSTRUCTION_ADOX, /* padding */ NMD_X86_INSTRUCTION_FST, NMD_X86_INSTRUCTION_FSTP, NMD_X86_INSTRUCTION_FLDENV, NMD_X86_INSTRUCTION_FLDCW, NMD_X86_INSTRUCTION_FNSTENV, NMD_X86_INSTRUCTION_FNSTCW, NMD_X86_INSTRUCTION_FCHS, NMD_X86_INSTRUCTION_FABS, NMD_X86_INSTRUCTION_AAS, /* padding */ NMD_X86_INSTRUCTION_ADCX, /* padding */ NMD_X86_INSTRUCTION_FTST, NMD_X86_INSTRUCTION_FXAM, NMD_X86_INSTRUCTION_RET, /* padding */ NMD_X86_INSTRUCTION_ENTER, /* padding */ NMD_X86_INSTRUCTION_FLD1, NMD_X86_INSTRUCTION_FLDL2T, NMD_X86_INSTRUCTION_FLDL2E, NMD_X86_INSTRUCTION_FLDPI, NMD_X86_INSTRUCTION_FLDLG2, NMD_X86_INSTRUCTION_FLDLN2, NMD_X86_INSTRUCTION_FLDZ, NMD_X86_INSTRUCTION_FNOP, /* padding */ NMD_X86_INSTRUCTION_F2XM1, NMD_X86_INSTRUCTION_FYL2X, NMD_X86_INSTRUCTION_FPTAN, NMD_X86_INSTRUCTION_FPATAN, NMD_X86_INSTRUCTION_FXTRACT, NMD_X86_INSTRUCTION_FPREM1, NMD_X86_INSTRUCTION_FDECSTP, NMD_X86_INSTRUCTION_FINCSTP, NMD_X86_INSTRUCTION_FPREM, NMD_X86_INSTRUCTION_FYL2XP1, NMD_X86_INSTRUCTION_FSQRT, NMD_X86_INSTRUCTION_FSINCOS, NMD_X86_INSTRUCTION_FRNDINT, NMD_X86_INSTRUCTION_FSCALE, NMD_X86_INSTRUCTION_FSIN, NMD_X86_INSTRUCTION_FCOS, /* Optimized for escape opcodes with DA as first byte. */ NMD_X86_INSTRUCTION_FIADD, NMD_X86_INSTRUCTION_FIMUL, NMD_X86_INSTRUCTION_FICOM, NMD_X86_INSTRUCTION_FICOMP, NMD_X86_INSTRUCTION_FISUB, NMD_X86_INSTRUCTION_FISUBR, NMD_X86_INSTRUCTION_FIDIV, NMD_X86_INSTRUCTION_FIDIVR, NMD_X86_INSTRUCTION_FCMOVB, NMD_X86_INSTRUCTION_FCMOVE, NMD_X86_INSTRUCTION_FCMOVBE, NMD_X86_INSTRUCTION_FCMOVU, /* Optimized for escape opcodes with DB/DF as first byte. */ NMD_X86_INSTRUCTION_FILD, NMD_X86_INSTRUCTION_FISTTP, NMD_X86_INSTRUCTION_FIST, NMD_X86_INSTRUCTION_FISTP, NMD_X86_INSTRUCTION_FBLD, NMD_X86_INSTRUCTION_AESKEYGENASSIST, /* padding */ NMD_X86_INSTRUCTION_FBSTP, NMD_X86_INSTRUCTION_ANDN, /* padding */ NMD_X86_INSTRUCTION_FCMOVNB, NMD_X86_INSTRUCTION_FCMOVNE, NMD_X86_INSTRUCTION_FCMOVNBE, NMD_X86_INSTRUCTION_FCMOVNU, NMD_X86_INSTRUCTION_FNCLEX, NMD_X86_INSTRUCTION_FUCOMI, NMD_X86_INSTRUCTION_FCOMI, /* Optimized for escape opcodes with DE as first byte. */ NMD_X86_INSTRUCTION_FADDP, NMD_X86_INSTRUCTION_FMULP, NMD_X86_INSTRUCTION_MOVAPD, /* padding */ NMD_X86_INSTRUCTION_BNDCN, /* padding */ NMD_X86_INSTRUCTION_FSUBRP, NMD_X86_INSTRUCTION_FSUBP, NMD_X86_INSTRUCTION_FDIVRP, NMD_X86_INSTRUCTION_FDIVP, /* Optimized for the 15th row of the 1 byte opcode map. */ NMD_X86_INSTRUCTION_INT1, NMD_X86_INSTRUCTION_BSR, /* padding */ NMD_X86_INSTRUCTION_ADDSUBPD, /* padding */ NMD_X86_INSTRUCTION_HLT, NMD_X86_INSTRUCTION_CMC, NMD_X86_INSTRUCTION_ADDSUBPS, /* padding */ NMD_X86_INSTRUCTION_BLENDVPD, /* padding*/ NMD_X86_INSTRUCTION_CLC, NMD_X86_INSTRUCTION_STC, NMD_X86_INSTRUCTION_CLI, NMD_X86_INSTRUCTION_STI, NMD_X86_INSTRUCTION_CLD, NMD_X86_INSTRUCTION_STD, /* Optimized for the 13th row of the 1 byte opcode map. */ NMD_X86_INSTRUCTION_AAM, NMD_X86_INSTRUCTION_AAD, NMD_X86_INSTRUCTION_SALC, NMD_X86_INSTRUCTION_XLAT, /* Optimized for the 14th row of the 1 byte opcode map. */ NMD_X86_INSTRUCTION_LOOPNE, NMD_X86_INSTRUCTION_LOOPE, NMD_X86_INSTRUCTION_LOOP, NMD_X86_INSTRUCTION_JRCXZ, /* Optimized for opcode extension group 6. */ NMD_X86_INSTRUCTION_SLDT, NMD_X86_INSTRUCTION_STR, NMD_X86_INSTRUCTION_LLDT, NMD_X86_INSTRUCTION_LTR, NMD_X86_INSTRUCTION_VERR, NMD_X86_INSTRUCTION_VERW, /* Optimized for opcode extension group 7. */ NMD_X86_INSTRUCTION_SGDT, NMD_X86_INSTRUCTION_SIDT, NMD_X86_INSTRUCTION_LGDT, NMD_X86_INSTRUCTION_LIDT, NMD_X86_INSTRUCTION_SMSW, NMD_X86_INSTRUCTION_CLWB, /* padding */ NMD_X86_INSTRUCTION_LMSW, NMD_X86_INSTRUCTION_INVLPG, NMD_X86_INSTRUCTION_VMCALL, NMD_X86_INSTRUCTION_VMLAUNCH, NMD_X86_INSTRUCTION_VMRESUME, NMD_X86_INSTRUCTION_VMXOFF, NMD_X86_INSTRUCTION_MONITOR, NMD_X86_INSTRUCTION_MWAIT, NMD_X86_INSTRUCTION_CLAC, NMD_X86_INSTRUCTION_STAC, NMD_X86_INSTRUCTION_CBW, /* padding */ NMD_X86_INSTRUCTION_CMPSB, /* padding */ NMD_X86_INSTRUCTION_CMPSQ, /* padding */ NMD_X86_INSTRUCTION_ENCLS, NMD_X86_INSTRUCTION_XGETBV, NMD_X86_INSTRUCTION_XSETBV, NMD_X86_INSTRUCTION_ARPL, /* padding */ NMD_X86_INSTRUCTION_BEXTR, /* padding */ NMD_X86_INSTRUCTION_VMFUNC, NMD_X86_INSTRUCTION_XEND, NMD_X86_INSTRUCTION_XTEST, NMD_X86_INSTRUCTION_ENCLU, NMD_X86_INSTRUCTION_VMRUN, NMD_X86_INSTRUCTION_VMMCALL, NMD_X86_INSTRUCTION_VMLOAD, NMD_X86_INSTRUCTION_VMSAVE, NMD_X86_INSTRUCTION_STGI, NMD_X86_INSTRUCTION_CLGI, NMD_X86_INSTRUCTION_SKINIT, NMD_X86_INSTRUCTION_INVLPGA, /* Optimized for the row 0x0 of the 2 byte opcode map. */ NMD_X86_INSTRUCTION_LAR, NMD_X86_INSTRUCTION_LSL, NMD_X86_INSTRUCTION_BLCFILL, /* padding */ NMD_X86_INSTRUCTION_SYSCALL, NMD_X86_INSTRUCTION_CLTS, NMD_X86_INSTRUCTION_SYSRET, NMD_X86_INSTRUCTION_INVD, NMD_X86_INSTRUCTION_WBINVD, NMD_X86_INSTRUCTION_BLCI, /* padding */ NMD_X86_INSTRUCTION_UD2, NMD_X86_INSTRUCTION_PREFETCHW, NMD_X86_INSTRUCTION_FEMMS, /* Optimized for the row 0x3 of the 2 byte opcode map. */ NMD_X86_INSTRUCTION_WRMSR, NMD_X86_INSTRUCTION_RDTSC, NMD_X86_INSTRUCTION_RDMSR, NMD_X86_INSTRUCTION_RDPMC, NMD_X86_INSTRUCTION_SYSENTER, NMD_X86_INSTRUCTION_SYSEXIT, NMD_X86_INSTRUCTION_BLCIC, /* padding */ NMD_X86_INSTRUCTION_GETSEC, /* Optimized for the row 0x4 of the 2 byte opcode map. */ NMD_X86_INSTRUCTION_CMOVO, NMD_X86_INSTRUCTION_CMOVNO, NMD_X86_INSTRUCTION_CMOVB, NMD_X86_INSTRUCTION_CMOVAE, NMD_X86_INSTRUCTION_CMOVE, NMD_X86_INSTRUCTION_CMOVNE, NMD_X86_INSTRUCTION_CMOVBE, NMD_X86_INSTRUCTION_CMOVA, NMD_X86_INSTRUCTION_CMOVS, NMD_X86_INSTRUCTION_CMOVNS, NMD_X86_INSTRUCTION_CMOVP, NMD_X86_INSTRUCTION_CMOVNP, NMD_X86_INSTRUCTION_CMOVL, NMD_X86_INSTRUCTION_CMOVGE, NMD_X86_INSTRUCTION_CMOVLE, NMD_X86_INSTRUCTION_CMOVG, /* Optimized for the row 0x9 of the 2 byte opcode map. */ NMD_X86_INSTRUCTION_SETO, NMD_X86_INSTRUCTION_SETNO, NMD_X86_INSTRUCTION_SETB, NMD_X86_INSTRUCTION_SETAE, NMD_X86_INSTRUCTION_SETE, NMD_X86_INSTRUCTION_SETNE, NMD_X86_INSTRUCTION_SETBE, NMD_X86_INSTRUCTION_SETA, NMD_X86_INSTRUCTION_SETS, NMD_X86_INSTRUCTION_SETNS, NMD_X86_INSTRUCTION_SETP, NMD_X86_INSTRUCTION_SETNP, NMD_X86_INSTRUCTION_SETL, NMD_X86_INSTRUCTION_SETGE, NMD_X86_INSTRUCTION_SETLE, NMD_X86_INSTRUCTION_SETG, /* Optimized for the row 0xb of the 2 byte opcode map. */ NMD_X86_INSTRUCTION_LSS, NMD_X86_INSTRUCTION_BTR, NMD_X86_INSTRUCTION_LFS, NMD_X86_INSTRUCTION_LGS, NMD_X86_INSTRUCTION_BT, NMD_X86_INSTRUCTION_BTC, NMD_X86_INSTRUCTION_BTS, /* Optimized for the row 0x0 of the 3 byte opcode map(38h). */ NMD_X86_INSTRUCTION_PSHUFB, NMD_X86_INSTRUCTION_PHADDW, NMD_X86_INSTRUCTION_PHADDD, NMD_X86_INSTRUCTION_PHADDSW, NMD_X86_INSTRUCTION_PMADDUBSW, NMD_X86_INSTRUCTION_PHSUBW, NMD_X86_INSTRUCTION_PHSUBD, NMD_X86_INSTRUCTION_PHSUBSW, NMD_X86_INSTRUCTION_PSIGNB, NMD_X86_INSTRUCTION_PSIGNW, NMD_X86_INSTRUCTION_PSIGND, NMD_X86_INSTRUCTION_PMULHRSW, /* Optimized for the row 0x1 of the 3 byte opcode map(38h). */ NMD_X86_INSTRUCTION_PABSB, NMD_X86_INSTRUCTION_PABSW, NMD_X86_INSTRUCTION_PABSD, /* Optimized for the row 0x2 of the 3 byte opcode map(38). */ NMD_X86_INSTRUCTION_PMOVSXBW, NMD_X86_INSTRUCTION_PMOVSXBD, NMD_X86_INSTRUCTION_PMOVSXBQ, NMD_X86_INSTRUCTION_PMOVSXWD, NMD_X86_INSTRUCTION_PMOVSXWQ, NMD_X86_INSTRUCTION_PMOVZXDQ, NMD_X86_INSTRUCTION_CPUID, /* padding */ NMD_X86_INSTRUCTION_BLCMSK, /* padding */ NMD_X86_INSTRUCTION_PMULDQ, NMD_X86_INSTRUCTION_PCMPEQQ, NMD_X86_INSTRUCTION_MOVNTDQA, NMD_X86_INSTRUCTION_PACKUSDW, /* Optimized for the row 0x3 of the 3 byte opcode map(38h). */ NMD_X86_INSTRUCTION_PMOVZXBW, NMD_X86_INSTRUCTION_PMOVZXBD, NMD_X86_INSTRUCTION_PMOVZXBQ, NMD_X86_INSTRUCTION_PMOVZXWD, NMD_X86_INSTRUCTION_PMOVZXWQ, NMD_X86_INSTRUCTION_PMOVSXDQ, NMD_X86_INSTRUCTION_BLCS, /* padding */ NMD_X86_INSTRUCTION_PCMPGTQ, NMD_X86_INSTRUCTION_PMINSB, NMD_X86_INSTRUCTION_PMINSD, NMD_X86_INSTRUCTION_PMINUW, NMD_X86_INSTRUCTION_PMINUD, NMD_X86_INSTRUCTION_PMAXSB, NMD_X86_INSTRUCTION_PMAXSD, NMD_X86_INSTRUCTION_PMAXUW, NMD_X86_INSTRUCTION_PMAXUD, /* Optimized for the row 0x8 of the 3 byte opcode map(38h). */ NMD_X86_INSTRUCTION_INVEPT, NMD_X86_INSTRUCTION_INVVPID, NMD_X86_INSTRUCTION_INVPCID, /* Optimized for the row 0xc of the 3 byte opcode map(38h). */ NMD_X86_INSTRUCTION_SHA1NEXTE, NMD_X86_INSTRUCTION_SHA1MSG1, NMD_X86_INSTRUCTION_SHA1MSG2, NMD_X86_INSTRUCTION_SHA256RNDS2, NMD_X86_INSTRUCTION_SHA256MSG1, NMD_X86_INSTRUCTION_SHA256MSG2, /* Optimized for the row 0xd of the 3 byte opcode map(38h). */ NMD_X86_INSTRUCTION_AESIMC, NMD_X86_INSTRUCTION_AESENC, NMD_X86_INSTRUCTION_AESENCLAST, NMD_X86_INSTRUCTION_AESDEC, NMD_X86_INSTRUCTION_AESDECLAST, /* Optimized for the row 0x0 of the 3 byte opcode map(3Ah). */ NMD_X86_INSTRUCTION_ROUNDPS, NMD_X86_INSTRUCTION_ROUNDPD, NMD_X86_INSTRUCTION_ROUNDSS, NMD_X86_INSTRUCTION_ROUNDSD, NMD_X86_INSTRUCTION_BLENDPS, NMD_X86_INSTRUCTION_BLENDPD, NMD_X86_INSTRUCTION_PBLENDW, NMD_X86_INSTRUCTION_PALIGNR, /* Optimized for the row 0x4 of the 3 byte opcode map(3A). */ NMD_X86_INSTRUCTION_DPPS, NMD_X86_INSTRUCTION_DPPD, NMD_X86_INSTRUCTION_MPSADBW, NMD_X86_INSTRUCTION_VPCMPGTQ, /* padding */ NMD_X86_INSTRUCTION_PCLMULQDQ, /* Optimized for the row 0x6 of the 3 byte opcode map(3A). */ NMD_X86_INSTRUCTION_PCMPESTRM, NMD_X86_INSTRUCTION_PCMPESTRI, NMD_X86_INSTRUCTION_PCMPISTRM, NMD_X86_INSTRUCTION_PCMPISTRI, /* Optimized for the rows 0xd, 0xe and 0xf of the 2 byte opcode map. */ NMD_X86_INSTRUCTION_PSRLW, NMD_X86_INSTRUCTION_PSRLD, NMD_X86_INSTRUCTION_PSRLQ, NMD_X86_INSTRUCTION_PADDQ, NMD_X86_INSTRUCTION_PMULLW, NMD_X86_INSTRUCTION_BOUND, /* padding */ NMD_X86_INSTRUCTION_PMOVMSKB, NMD_X86_INSTRUCTION_PSUBUSB, NMD_X86_INSTRUCTION_PSUBUSW, NMD_X86_INSTRUCTION_PMINUB, NMD_X86_INSTRUCTION_PAND, NMD_X86_INSTRUCTION_PADDUSB, NMD_X86_INSTRUCTION_PADDUSW, NMD_X86_INSTRUCTION_PMAXUB, NMD_X86_INSTRUCTION_PANDN, NMD_X86_INSTRUCTION_PAVGB, NMD_X86_INSTRUCTION_PSRAW, NMD_X86_INSTRUCTION_PSRAD, NMD_X86_INSTRUCTION_PAVGW, NMD_X86_INSTRUCTION_PMULHUW, NMD_X86_INSTRUCTION_PMULHW, NMD_X86_INSTRUCTION_CQO, /* padding */ NMD_X86_INSTRUCTION_CRC32, /* padding */ NMD_X86_INSTRUCTION_PSUBSB, NMD_X86_INSTRUCTION_PSUBSW, NMD_X86_INSTRUCTION_PMINSW, NMD_X86_INSTRUCTION_POR, NMD_X86_INSTRUCTION_PADDSB, NMD_X86_INSTRUCTION_PADDSW, NMD_X86_INSTRUCTION_PMAXSW, NMD_X86_INSTRUCTION_PXOR, NMD_X86_INSTRUCTION_LDDQU, NMD_X86_INSTRUCTION_PSLLW, NMD_X86_INSTRUCTION_PSLLD, NMD_X86_INSTRUCTION_PSLLQ, NMD_X86_INSTRUCTION_PMULUDQ, NMD_X86_INSTRUCTION_PMADDWD, NMD_X86_INSTRUCTION_PSADBW, NMD_X86_INSTRUCTION_BSWAP, /* padding */ NMD_X86_INSTRUCTION_PSUBB, NMD_X86_INSTRUCTION_PSUBW, NMD_X86_INSTRUCTION_PSUBD, NMD_X86_INSTRUCTION_PSUBQ, NMD_X86_INSTRUCTION_PADDB, NMD_X86_INSTRUCTION_PADDW, NMD_X86_INSTRUCTION_PADDD, /* Optimized for the row 0xc of the 2 byte opcode map. */ NMD_X86_INSTRUCTION_MOVNTI, NMD_X86_INSTRUCTION_PINSRW, NMD_X86_INSTRUCTION_PEXTRW, /* Optimized for opcode extension group 15. */ NMD_X86_INSTRUCTION_FXSAVE, NMD_X86_INSTRUCTION_FXRSTOR, NMD_X86_INSTRUCTION_LDMXCSR, NMD_X86_INSTRUCTION_STMXCSR, NMD_X86_INSTRUCTION_XSAVE, NMD_X86_INSTRUCTION_XRSTOR, NMD_X86_INSTRUCTION_XSAVEOPT, NMD_X86_INSTRUCTION_CLFLUSH, NMD_X86_INSTRUCTION_RDFSBASE, NMD_X86_INSTRUCTION_RDGSBASE, NMD_X86_INSTRUCTION_WRFSBASE, NMD_X86_INSTRUCTION_WRGSBASE, NMD_X86_INSTRUCTION_CMPXCHG, /* padding */ NMD_X86_INSTRUCTION_LFENCE, NMD_X86_INSTRUCTION_MFENCE, NMD_X86_INSTRUCTION_SFENCE, NMD_X86_INSTRUCTION_PCMPEQB, NMD_X86_INSTRUCTION_PCMPEQW, NMD_X86_INSTRUCTION_PCMPEQD, /* Optimized for the row 0x5 of the 2 byte opcode map. */ NMD_X86_INSTRUCTION_MOVMSKPS, NMD_X86_INSTRUCTION_SQRTPS, NMD_X86_INSTRUCTION_RSQRTPS, NMD_X86_INSTRUCTION_RCPPS, NMD_X86_INSTRUCTION_ANDPS, NMD_X86_INSTRUCTION_ANDNPS, NMD_X86_INSTRUCTION_ORPS, NMD_X86_INSTRUCTION_XORPS, NMD_X86_INSTRUCTION_ADDPS, NMD_X86_INSTRUCTION_MULPS, NMD_X86_INSTRUCTION_CVTPS2PD, NMD_X86_INSTRUCTION_CVTDQ2PS, NMD_X86_INSTRUCTION_SUBPS, NMD_X86_INSTRUCTION_MINPS, NMD_X86_INSTRUCTION_DIVPS, NMD_X86_INSTRUCTION_MAXPS, NMD_X86_INSTRUCTION_MOVMSKPD, NMD_X86_INSTRUCTION_SQRTPD, NMD_X86_INSTRUCTION_BNDLDX, /* padding */ NMD_X86_INSTRUCTION_BNDSTX, /* padding */ NMD_X86_INSTRUCTION_ANDPD, NMD_X86_INSTRUCTION_ANDNPD, NMD_X86_INSTRUCTION_ORPD, NMD_X86_INSTRUCTION_XORPD, NMD_X86_INSTRUCTION_ADDPD, NMD_X86_INSTRUCTION_MULPD, NMD_X86_INSTRUCTION_CVTPD2PS, NMD_X86_INSTRUCTION_CVTPS2DQ, NMD_X86_INSTRUCTION_SUBPD, NMD_X86_INSTRUCTION_MINPD, NMD_X86_INSTRUCTION_DIVPD, NMD_X86_INSTRUCTION_MAXPD, NMD_X86_INSTRUCTION_BNDMOV, /* padding */ NMD_X86_INSTRUCTION_SQRTSS, NMD_X86_INSTRUCTION_RSQRTSS, NMD_X86_INSTRUCTION_RCPSS, NMD_X86_INSTRUCTION_CMPXCHG16B, /* padding */ NMD_X86_INSTRUCTION_DAA, /* padding */ NMD_X86_INSTRUCTION_CWD, /* padding */ NMD_X86_INSTRUCTION_INSD, /* padding */ NMD_X86_INSTRUCTION_ADDSS, NMD_X86_INSTRUCTION_MULSS, NMD_X86_INSTRUCTION_CVTSS2SD, NMD_X86_INSTRUCTION_CVTTPS2DQ, NMD_X86_INSTRUCTION_SUBSS, NMD_X86_INSTRUCTION_MINSS, NMD_X86_INSTRUCTION_DIVSS, NMD_X86_INSTRUCTION_MAXSS, NMD_X86_INSTRUCTION_BNDCL, /* padding */ NMD_X86_INSTRUCTION_SQRTSD, NMD_X86_INSTRUCTION_BNDCU, /* padding */ NMD_X86_INSTRUCTION_BNDMK, /* padding */ NMD_X86_INSTRUCTION_CMPXCHG8B, /* padding */ NMD_X86_INSTRUCTION_DAS, /* padding */ NMD_X86_INSTRUCTION_CWDE, /* padding */ NMD_X86_INSTRUCTION_INSW, /* padding */ NMD_X86_INSTRUCTION_ADDSD, NMD_X86_INSTRUCTION_MULSD, NMD_X86_INSTRUCTION_CVTSD2SS, NMD_X86_INSTRUCTION_FCOMIP, /* padding */ NMD_X86_INSTRUCTION_SUBSD, NMD_X86_INSTRUCTION_MINSD, NMD_X86_INSTRUCTION_DIVSD, NMD_X86_INSTRUCTION_MAXSD, /* Optimized for the row 0x6 of the 2 byte opcode map. */ NMD_X86_INSTRUCTION_PUNPCKLBW, NMD_X86_INSTRUCTION_PUNPCKLWD, NMD_X86_INSTRUCTION_PUNPCKLDQ, NMD_X86_INSTRUCTION_PACKSSWB, NMD_X86_INSTRUCTION_PCMPGTB, NMD_X86_INSTRUCTION_PCMPGTW, NMD_X86_INSTRUCTION_PCMPGTD, NMD_X86_INSTRUCTION_PACKUSWB, NMD_X86_INSTRUCTION_PUNPCKHBW, NMD_X86_INSTRUCTION_PUNPCKHWD, NMD_X86_INSTRUCTION_PUNPCKHDQ, NMD_X86_INSTRUCTION_PACKSSDW, NMD_X86_INSTRUCTION_PUNPCKLQDQ, NMD_X86_INSTRUCTION_PUNPCKHQDQ, /* Optimized for AVX instructions. */ NMD_X86_INSTRUCTION_VPSHUFB, /* 00 */ NMD_X86_INSTRUCTION_VPHADDW, /* 01 */ NMD_X86_INSTRUCTION_VPHADDD, /* 02 */ NMD_X86_INSTRUCTION_VPHADDSW, /* 03 */ NMD_X86_INSTRUCTION_VPMADDUBSW, /* 04 */ NMD_X86_INSTRUCTION_VPHSUBW, /* 05 */ NMD_X86_INSTRUCTION_VPHSUBD, /* 06 */ NMD_X86_INSTRUCTION_VPHSUBSW, /* 07 */ NMD_X86_INSTRUCTION_VPSIGNB, /* 08 */ NMD_X86_INSTRUCTION_VPSIGNW, /* 09 */ NMD_X86_INSTRUCTION_VPSIGND, /* 0A dup */ NMD_X86_INSTRUCTION_VPMULHRSW, /* 0B dup */ NMD_X86_INSTRUCTION_VPHADDWQ, NMD_X86_INSTRUCTION_VPHADDDQ, NMD_X86_INSTRUCTION_BLSI, NMD_X86_INSTRUCTION_BLSIC, NMD_X86_INSTRUCTION_BLSMSK, NMD_X86_INSTRUCTION_BLSR, NMD_X86_INSTRUCTION_BSF, NMD_X86_INSTRUCTION_BZHI, NMD_X86_INSTRUCTION_CDQ, NMD_X86_INSTRUCTION_CDQE, NMD_X86_INSTRUCTION_CLFLUSHOPT, NMD_X86_INSTRUCTION_CMPSW, NMD_X86_INSTRUCTION_COMISD, NMD_X86_INSTRUCTION_COMISS, NMD_X86_INSTRUCTION_CVTDQ2PD, NMD_X86_INSTRUCTION_CVTPD2DQ, NMD_X86_INSTRUCTION_CVTSD2SI, NMD_X86_INSTRUCTION_CVTSI2SD, NMD_X86_INSTRUCTION_CVTSI2SS, NMD_X86_INSTRUCTION_CVTSS2SI, NMD_X86_INSTRUCTION_CVTTPD2DQ, NMD_X86_INSTRUCTION_CVTTSD2SI, NMD_X86_INSTRUCTION_CVTTSS2SI, NMD_X86_INSTRUCTION_DATA16, NMD_X86_INSTRUCTION_EXTRACTPS, NMD_X86_INSTRUCTION_EXTRQ, NMD_X86_INSTRUCTION_FCOMPP, NMD_X86_INSTRUCTION_FFREE, NMD_X86_INSTRUCTION_FNINIT, NMD_X86_INSTRUCTION_FNSTSW, NMD_X86_INSTRUCTION_FFREEP, NMD_X86_INSTRUCTION_FRSTOR, NMD_X86_INSTRUCTION_FNSAVE, NMD_X86_INSTRUCTION_FSETPM, NMD_X86_INSTRUCTION_FXRSTOR64, NMD_X86_INSTRUCTION_FXSAVE64, NMD_X86_INSTRUCTION_MOVAPS, NMD_X86_INSTRUCTION_VMOVAPD, NMD_X86_INSTRUCTION_VMOVAPS, NMD_X86_INSTRUCTION_HADDPD, NMD_X86_INSTRUCTION_HADDPS, NMD_X86_INSTRUCTION_HSUBPD, NMD_X86_INSTRUCTION_HSUBPS, NMD_X86_INSTRUCTION_IN, NMD_X86_INSTRUCTION_INSB, NMD_X86_INSTRUCTION_INSERTPS, NMD_X86_INSTRUCTION_INSERTQ, NMD_X86_INSTRUCTION_INT, NMD_X86_INSTRUCTION_INT3, NMD_X86_INSTRUCTION_INTO, NMD_X86_INSTRUCTION_IRET, NMD_X86_INSTRUCTION_IRETD, NMD_X86_INSTRUCTION_IRETQ, NMD_X86_INSTRUCTION_UCOMISD, NMD_X86_INSTRUCTION_UCOMISS, NMD_X86_INSTRUCTION_VCOMISD, NMD_X86_INSTRUCTION_VCOMISS, NMD_X86_INSTRUCTION_VCVTSD2SS, NMD_X86_INSTRUCTION_VCVTSI2SD, NMD_X86_INSTRUCTION_VCVTSI2SS, NMD_X86_INSTRUCTION_VCVTSS2SD, NMD_X86_INSTRUCTION_VCVTTSD2SI, NMD_X86_INSTRUCTION_VCVTTSD2USI, NMD_X86_INSTRUCTION_VCVTTSS2SI, NMD_X86_INSTRUCTION_VCVTTSS2USI, NMD_X86_INSTRUCTION_VCVTUSI2SD, NMD_X86_INSTRUCTION_VCVTUSI2SS, NMD_X86_INSTRUCTION_VUCOMISD, NMD_X86_INSTRUCTION_VUCOMISS, NMD_X86_INSTRUCTION_JCXZ, NMD_X86_INSTRUCTION_JECXZ, NMD_X86_INSTRUCTION_KANDB, NMD_X86_INSTRUCTION_KANDD, NMD_X86_INSTRUCTION_KANDNB, NMD_X86_INSTRUCTION_KANDND, NMD_X86_INSTRUCTION_KANDNQ, NMD_X86_INSTRUCTION_KANDNW, NMD_X86_INSTRUCTION_KANDQ, NMD_X86_INSTRUCTION_KANDW, NMD_X86_INSTRUCTION_KMOVB, NMD_X86_INSTRUCTION_KMOVD, NMD_X86_INSTRUCTION_KMOVQ, NMD_X86_INSTRUCTION_KMOVW, NMD_X86_INSTRUCTION_KNOTB, NMD_X86_INSTRUCTION_KNOTD, NMD_X86_INSTRUCTION_KNOTQ, NMD_X86_INSTRUCTION_KNOTW, NMD_X86_INSTRUCTION_KORB, NMD_X86_INSTRUCTION_KORD, NMD_X86_INSTRUCTION_KORQ, NMD_X86_INSTRUCTION_KORTESTB, NMD_X86_INSTRUCTION_KORTESTD, NMD_X86_INSTRUCTION_KORTESTQ, NMD_X86_INSTRUCTION_KORTESTW, NMD_X86_INSTRUCTION_KORW, NMD_X86_INSTRUCTION_KSHIFTLB, NMD_X86_INSTRUCTION_KSHIFTLD, NMD_X86_INSTRUCTION_KSHIFTLQ, NMD_X86_INSTRUCTION_KSHIFTLW, NMD_X86_INSTRUCTION_KSHIFTRB, NMD_X86_INSTRUCTION_KSHIFTRD, NMD_X86_INSTRUCTION_KSHIFTRQ, NMD_X86_INSTRUCTION_KSHIFTRW, NMD_X86_INSTRUCTION_KUNPCKBW, NMD_X86_INSTRUCTION_KXNORB, NMD_X86_INSTRUCTION_KXNORD, NMD_X86_INSTRUCTION_KXNORQ, NMD_X86_INSTRUCTION_KXNORW, NMD_X86_INSTRUCTION_KXORB, NMD_X86_INSTRUCTION_KXORD, NMD_X86_INSTRUCTION_KXORQ, NMD_X86_INSTRUCTION_KXORW, NMD_X86_INSTRUCTION_LAHF, NMD_X86_INSTRUCTION_LDS, NMD_X86_INSTRUCTION_LEA, NMD_X86_INSTRUCTION_LEAVE, NMD_X86_INSTRUCTION_LES, NMD_X86_INSTRUCTION_LODSB, NMD_X86_INSTRUCTION_LODSD, NMD_X86_INSTRUCTION_LODSQ, NMD_X86_INSTRUCTION_LODSW, NMD_X86_INSTRUCTION_RETF, NMD_X86_INSTRUCTION_XADD, NMD_X86_INSTRUCTION_LZCNT, NMD_X86_INSTRUCTION_MASKMOVDQU, NMD_X86_INSTRUCTION_CVTPD2PI, NMD_X86_INSTRUCTION_CVTPI2PD, NMD_X86_INSTRUCTION_CVTPI2PS, NMD_X86_INSTRUCTION_CVTPS2PI, NMD_X86_INSTRUCTION_CVTTPD2PI, NMD_X86_INSTRUCTION_CVTTPS2PI, NMD_X86_INSTRUCTION_EMMS, NMD_X86_INSTRUCTION_MASKMOVQ, NMD_X86_INSTRUCTION_MOVD, NMD_X86_INSTRUCTION_MOVDQ2Q, NMD_X86_INSTRUCTION_MOVNTQ, NMD_X86_INSTRUCTION_MOVQ2DQ, NMD_X86_INSTRUCTION_MOVQ, NMD_X86_INSTRUCTION_PSHUFW, NMD_X86_INSTRUCTION_MONTMUL, NMD_X86_INSTRUCTION_MOV, NMD_X86_INSTRUCTION_MOVABS, NMD_X86_INSTRUCTION_MOVBE, NMD_X86_INSTRUCTION_MOVDDUP, NMD_X86_INSTRUCTION_MOVDQA, NMD_X86_INSTRUCTION_MOVDQU, NMD_X86_INSTRUCTION_MOVHLPS, NMD_X86_INSTRUCTION_MOVHPD, NMD_X86_INSTRUCTION_MOVHPS, NMD_X86_INSTRUCTION_MOVLHPS, NMD_X86_INSTRUCTION_MOVLPD, NMD_X86_INSTRUCTION_MOVLPS, NMD_X86_INSTRUCTION_MOVNTDQ, NMD_X86_INSTRUCTION_MOVNTPD, NMD_X86_INSTRUCTION_MOVNTPS, NMD_X86_INSTRUCTION_MOVNTSD, NMD_X86_INSTRUCTION_MOVNTSS, NMD_X86_INSTRUCTION_MOVSB, NMD_X86_INSTRUCTION_MOVSD, NMD_X86_INSTRUCTION_MOVSHDUP, NMD_X86_INSTRUCTION_MOVSLDUP, NMD_X86_INSTRUCTION_MOVSQ, NMD_X86_INSTRUCTION_MOVSS, NMD_X86_INSTRUCTION_MOVSW, NMD_X86_INSTRUCTION_MOVSX, NMD_X86_INSTRUCTION_MOVSXD, NMD_X86_INSTRUCTION_MOVUPD, NMD_X86_INSTRUCTION_MOVUPS, NMD_X86_INSTRUCTION_MOVZX, NMD_X86_INSTRUCTION_MULX, NMD_X86_INSTRUCTION_NOP, NMD_X86_INSTRUCTION_OUT, NMD_X86_INSTRUCTION_OUTSB, NMD_X86_INSTRUCTION_OUTSD, NMD_X86_INSTRUCTION_OUTSW, NMD_X86_INSTRUCTION_PAUSE, NMD_X86_INSTRUCTION_PAVGUSB, NMD_X86_INSTRUCTION_PBLENDVB, NMD_X86_INSTRUCTION_PCOMMIT, NMD_X86_INSTRUCTION_PDEP, NMD_X86_INSTRUCTION_PEXT, NMD_X86_INSTRUCTION_PEXTRB, NMD_X86_INSTRUCTION_PEXTRD, NMD_X86_INSTRUCTION_PEXTRQ, NMD_X86_INSTRUCTION_PF2ID, NMD_X86_INSTRUCTION_PF2IW, NMD_X86_INSTRUCTION_PFACC, NMD_X86_INSTRUCTION_PFADD, NMD_X86_INSTRUCTION_BLENDVPS, /* padding*/ NMD_X86_INSTRUCTION_PFCMPEQ, NMD_X86_INSTRUCTION_PFCMPGE, NMD_X86_INSTRUCTION_PFCMPGT, NMD_X86_INSTRUCTION_PFMAX, NMD_X86_INSTRUCTION_PFMIN, NMD_X86_INSTRUCTION_PFMUL, NMD_X86_INSTRUCTION_PFNACC, NMD_X86_INSTRUCTION_PFPNACC, NMD_X86_INSTRUCTION_PFRCPIT1, NMD_X86_INSTRUCTION_PFRCPIT2, NMD_X86_INSTRUCTION_PFRCP, NMD_X86_INSTRUCTION_PFRSQIT1, NMD_X86_INSTRUCTION_PFRSQRT, NMD_X86_INSTRUCTION_PFSUBR, NMD_X86_INSTRUCTION_PFSUB, NMD_X86_INSTRUCTION_PHMINPOSUW, NMD_X86_INSTRUCTION_PI2FD, NMD_X86_INSTRUCTION_PI2FW, NMD_X86_INSTRUCTION_PINSRB, NMD_X86_INSTRUCTION_PINSRD, NMD_X86_INSTRUCTION_PINSRQ, NMD_X86_INSTRUCTION_PMULHRW, NMD_X86_INSTRUCTION_PMULLD, NMD_X86_INSTRUCTION_POP, NMD_X86_INSTRUCTION_POPA, NMD_X86_INSTRUCTION_POPAD, NMD_X86_INSTRUCTION_POPCNT, NMD_X86_INSTRUCTION_POPF, NMD_X86_INSTRUCTION_POPFD, NMD_X86_INSTRUCTION_POPFQ, NMD_X86_INSTRUCTION_PREFETCH, NMD_X86_INSTRUCTION_PREFETCHNTA, NMD_X86_INSTRUCTION_PREFETCHT0, NMD_X86_INSTRUCTION_PREFETCHT1, NMD_X86_INSTRUCTION_PREFETCHT2, NMD_X86_INSTRUCTION_PSHUFD, NMD_X86_INSTRUCTION_PSHUFHW, NMD_X86_INSTRUCTION_PSHUFLW, NMD_X86_INSTRUCTION_PSLLDQ, NMD_X86_INSTRUCTION_PSRLDQ, NMD_X86_INSTRUCTION_PSWAPD, NMD_X86_INSTRUCTION_PTEST, NMD_X86_INSTRUCTION_PUSHA, NMD_X86_INSTRUCTION_PUSHAD, NMD_X86_INSTRUCTION_PUSHF, NMD_X86_INSTRUCTION_PUSHFD, NMD_X86_INSTRUCTION_PUSHFQ, NMD_X86_INSTRUCTION_RDRAND, NMD_X86_INSTRUCTION_RDPID, NMD_X86_INSTRUCTION_RDSEED, NMD_X86_INSTRUCTION_RDTSCP, NMD_X86_INSTRUCTION_RORX, NMD_X86_INSTRUCTION_RSM, NMD_X86_INSTRUCTION_SAHF, NMD_X86_INSTRUCTION_SAL, NMD_X86_INSTRUCTION_SARX, NMD_X86_INSTRUCTION_SCASB, NMD_X86_INSTRUCTION_SCASD, NMD_X86_INSTRUCTION_SCASQ, NMD_X86_INSTRUCTION_SCASW, NMD_X86_INSTRUCTION_SHA1RNDS4, NMD_X86_INSTRUCTION_SHLD, NMD_X86_INSTRUCTION_SHLX, NMD_X86_INSTRUCTION_SHRD, NMD_X86_INSTRUCTION_SHRX, NMD_X86_INSTRUCTION_SHUFPD, NMD_X86_INSTRUCTION_SHUFPS, NMD_X86_INSTRUCTION_STOSB, NMD_X86_INSTRUCTION_STOSD, NMD_X86_INSTRUCTION_STOSQ, NMD_X86_INSTRUCTION_STOSW, NMD_X86_INSTRUCTION_FSTPNCE, NMD_X86_INSTRUCTION_FXCH, NMD_X86_INSTRUCTION_SWAPGS, NMD_X86_INSTRUCTION_T1MSKC, NMD_X86_INSTRUCTION_TZCNT, NMD_X86_INSTRUCTION_TZMSK, NMD_X86_INSTRUCTION_FUCOMIP, NMD_X86_INSTRUCTION_FUCOMPP, NMD_X86_INSTRUCTION_FUCOMP, NMD_X86_INSTRUCTION_FUCOM, NMD_X86_INSTRUCTION_UD1, NMD_X86_INSTRUCTION_UNPCKHPD, NMD_X86_INSTRUCTION_UNPCKHPS, NMD_X86_INSTRUCTION_UNPCKLPD, NMD_X86_INSTRUCTION_UNPCKLPS, NMD_X86_INSTRUCTION_VADDPD, NMD_X86_INSTRUCTION_VADDPS, NMD_X86_INSTRUCTION_VADDSD, NMD_X86_INSTRUCTION_VADDSS, NMD_X86_INSTRUCTION_VADDSUBPD, NMD_X86_INSTRUCTION_VADDSUBPS, NMD_X86_INSTRUCTION_VAESDECLAST, NMD_X86_INSTRUCTION_VAESDEC, NMD_X86_INSTRUCTION_VAESENCLAST, NMD_X86_INSTRUCTION_VAESENC, NMD_X86_INSTRUCTION_VAESIMC, NMD_X86_INSTRUCTION_VAESKEYGENASSIST, NMD_X86_INSTRUCTION_VALIGND, NMD_X86_INSTRUCTION_VALIGNQ, NMD_X86_INSTRUCTION_VANDNPD, NMD_X86_INSTRUCTION_VANDNPS, NMD_X86_INSTRUCTION_VANDPD, NMD_X86_INSTRUCTION_VANDPS, NMD_X86_INSTRUCTION_VBLENDMPD, NMD_X86_INSTRUCTION_VBLENDMPS, NMD_X86_INSTRUCTION_VBLENDPD, NMD_X86_INSTRUCTION_VBLENDPS, NMD_X86_INSTRUCTION_VBLENDVPD, NMD_X86_INSTRUCTION_VBLENDVPS, NMD_X86_INSTRUCTION_VBROADCASTF128, NMD_X86_INSTRUCTION_VBROADCASTI32X4, NMD_X86_INSTRUCTION_VBROADCASTI64X4, NMD_X86_INSTRUCTION_VBROADCASTSD, NMD_X86_INSTRUCTION_VBROADCASTSS, NMD_X86_INSTRUCTION_VCOMPRESSPD, NMD_X86_INSTRUCTION_VCOMPRESSPS, NMD_X86_INSTRUCTION_VCVTDQ2PD, NMD_X86_INSTRUCTION_VCVTDQ2PS, NMD_X86_INSTRUCTION_VCVTPD2DQX, NMD_X86_INSTRUCTION_VCVTPD2DQ, NMD_X86_INSTRUCTION_VCVTPD2PSX, NMD_X86_INSTRUCTION_VCVTPD2PS, NMD_X86_INSTRUCTION_VCVTPD2UDQ, NMD_X86_INSTRUCTION_VCVTPH2PS, NMD_X86_INSTRUCTION_VCVTPS2DQ, NMD_X86_INSTRUCTION_VCVTPS2PD, NMD_X86_INSTRUCTION_VCVTPS2PH, NMD_X86_INSTRUCTION_VCVTPS2UDQ, NMD_X86_INSTRUCTION_VCVTSD2SI, NMD_X86_INSTRUCTION_VCVTSD2USI, NMD_X86_INSTRUCTION_VCVTSS2SI, NMD_X86_INSTRUCTION_VCVTSS2USI, NMD_X86_INSTRUCTION_VCVTTPD2DQX, NMD_X86_INSTRUCTION_VCVTTPD2DQ, NMD_X86_INSTRUCTION_VCVTTPD2UDQ, NMD_X86_INSTRUCTION_VCVTTPS2DQ, NMD_X86_INSTRUCTION_VCVTTPS2UDQ, NMD_X86_INSTRUCTION_VCVTUDQ2PD, NMD_X86_INSTRUCTION_VCVTUDQ2PS, NMD_X86_INSTRUCTION_VDIVPD, NMD_X86_INSTRUCTION_VDIVPS, NMD_X86_INSTRUCTION_VDIVSD, NMD_X86_INSTRUCTION_VDIVSS, NMD_X86_INSTRUCTION_VDPPD, NMD_X86_INSTRUCTION_VDPPS, NMD_X86_INSTRUCTION_VEXP2PD, NMD_X86_INSTRUCTION_VEXP2PS, NMD_X86_INSTRUCTION_VEXPANDPD, NMD_X86_INSTRUCTION_VEXPANDPS, NMD_X86_INSTRUCTION_VEXTRACTF128, NMD_X86_INSTRUCTION_VEXTRACTF32X4, NMD_X86_INSTRUCTION_VEXTRACTF64X4, NMD_X86_INSTRUCTION_VEXTRACTI128, NMD_X86_INSTRUCTION_VEXTRACTI32X4, NMD_X86_INSTRUCTION_VEXTRACTI64X4, NMD_X86_INSTRUCTION_VEXTRACTPS, NMD_X86_INSTRUCTION_VFMADD132PD, NMD_X86_INSTRUCTION_VFMADD132PS, NMD_X86_INSTRUCTION_VFMADDPD, NMD_X86_INSTRUCTION_VFMADD213PD, NMD_X86_INSTRUCTION_VFMADD231PD, NMD_X86_INSTRUCTION_VFMADDPS, NMD_X86_INSTRUCTION_VFMADD213PS, NMD_X86_INSTRUCTION_VFMADD231PS, NMD_X86_INSTRUCTION_VFMADDSD, NMD_X86_INSTRUCTION_VFMADD213SD, NMD_X86_INSTRUCTION_VFMADD132SD, NMD_X86_INSTRUCTION_VFMADD231SD, NMD_X86_INSTRUCTION_VFMADDSS, NMD_X86_INSTRUCTION_VFMADD213SS, NMD_X86_INSTRUCTION_VFMADD132SS, NMD_X86_INSTRUCTION_VFMADD231SS, NMD_X86_INSTRUCTION_VFMADDSUB132PD, NMD_X86_INSTRUCTION_VFMADDSUB132PS, NMD_X86_INSTRUCTION_VFMADDSUBPD, NMD_X86_INSTRUCTION_VFMADDSUB213PD, NMD_X86_INSTRUCTION_VFMADDSUB231PD, NMD_X86_INSTRUCTION_VFMADDSUBPS, NMD_X86_INSTRUCTION_VFMADDSUB213PS, NMD_X86_INSTRUCTION_VFMADDSUB231PS, NMD_X86_INSTRUCTION_VFMSUB132PD, NMD_X86_INSTRUCTION_VFMSUB132PS, NMD_X86_INSTRUCTION_VFMSUBADD132PD, NMD_X86_INSTRUCTION_VFMSUBADD132PS, NMD_X86_INSTRUCTION_VFMSUBADDPD, NMD_X86_INSTRUCTION_VFMSUBADD213PD, NMD_X86_INSTRUCTION_VFMSUBADD231PD, NMD_X86_INSTRUCTION_VFMSUBADDPS, NMD_X86_INSTRUCTION_VFMSUBADD213PS, NMD_X86_INSTRUCTION_VFMSUBADD231PS, NMD_X86_INSTRUCTION_VFMSUBPD, NMD_X86_INSTRUCTION_VFMSUB213PD, NMD_X86_INSTRUCTION_VFMSUB231PD, NMD_X86_INSTRUCTION_VFMSUBPS, NMD_X86_INSTRUCTION_VFMSUB213PS, NMD_X86_INSTRUCTION_VFMSUB231PS, NMD_X86_INSTRUCTION_VFMSUBSD, NMD_X86_INSTRUCTION_VFMSUB213SD, NMD_X86_INSTRUCTION_VFMSUB132SD, NMD_X86_INSTRUCTION_VFMSUB231SD, NMD_X86_INSTRUCTION_VFMSUBSS, NMD_X86_INSTRUCTION_VFMSUB213SS, NMD_X86_INSTRUCTION_VFMSUB132SS, NMD_X86_INSTRUCTION_VFMSUB231SS, NMD_X86_INSTRUCTION_VFNMADD132PD, NMD_X86_INSTRUCTION_VFNMADD132PS, NMD_X86_INSTRUCTION_VFNMADDPD, NMD_X86_INSTRUCTION_VFNMADD213PD, NMD_X86_INSTRUCTION_VFNMADD231PD, NMD_X86_INSTRUCTION_VFNMADDPS, NMD_X86_INSTRUCTION_VFNMADD213PS, NMD_X86_INSTRUCTION_VFNMADD231PS, NMD_X86_INSTRUCTION_VFNMADDSD, NMD_X86_INSTRUCTION_VFNMADD213SD, NMD_X86_INSTRUCTION_VFNMADD132SD, NMD_X86_INSTRUCTION_VFNMADD231SD, NMD_X86_INSTRUCTION_VFNMADDSS, NMD_X86_INSTRUCTION_VFNMADD213SS, NMD_X86_INSTRUCTION_VFNMADD132SS, NMD_X86_INSTRUCTION_VFNMADD231SS, NMD_X86_INSTRUCTION_VFNMSUB132PD, NMD_X86_INSTRUCTION_VFNMSUB132PS, NMD_X86_INSTRUCTION_VFNMSUBPD, NMD_X86_INSTRUCTION_VFNMSUB213PD, NMD_X86_INSTRUCTION_VFNMSUB231PD, NMD_X86_INSTRUCTION_VFNMSUBPS, NMD_X86_INSTRUCTION_VFNMSUB213PS, NMD_X86_INSTRUCTION_VFNMSUB231PS, NMD_X86_INSTRUCTION_VFNMSUBSD, NMD_X86_INSTRUCTION_VFNMSUB213SD, NMD_X86_INSTRUCTION_VFNMSUB132SD, NMD_X86_INSTRUCTION_VFNMSUB231SD, NMD_X86_INSTRUCTION_VFNMSUBSS, NMD_X86_INSTRUCTION_VFNMSUB213SS, NMD_X86_INSTRUCTION_VFNMSUB132SS, NMD_X86_INSTRUCTION_VFNMSUB231SS, NMD_X86_INSTRUCTION_VFRCZPD, NMD_X86_INSTRUCTION_VFRCZPS, NMD_X86_INSTRUCTION_VFRCZSD, NMD_X86_INSTRUCTION_VFRCZSS, NMD_X86_INSTRUCTION_VORPD, NMD_X86_INSTRUCTION_VORPS, NMD_X86_INSTRUCTION_VXORPD, NMD_X86_INSTRUCTION_VXORPS, NMD_X86_INSTRUCTION_VGATHERDPD, NMD_X86_INSTRUCTION_VGATHERDPS, NMD_X86_INSTRUCTION_VGATHERPF0DPD, NMD_X86_INSTRUCTION_VGATHERPF0DPS, NMD_X86_INSTRUCTION_VGATHERPF0QPD, NMD_X86_INSTRUCTION_VGATHERPF0QPS, NMD_X86_INSTRUCTION_VGATHERPF1DPD, NMD_X86_INSTRUCTION_VGATHERPF1DPS, NMD_X86_INSTRUCTION_VGATHERPF1QPD, NMD_X86_INSTRUCTION_VGATHERPF1QPS, NMD_X86_INSTRUCTION_VGATHERQPD, NMD_X86_INSTRUCTION_VGATHERQPS, NMD_X86_INSTRUCTION_VHADDPD, NMD_X86_INSTRUCTION_VHADDPS, NMD_X86_INSTRUCTION_VHSUBPD, NMD_X86_INSTRUCTION_VHSUBPS, NMD_X86_INSTRUCTION_VINSERTF128, NMD_X86_INSTRUCTION_VINSERTF32X4, NMD_X86_INSTRUCTION_VINSERTF32X8, NMD_X86_INSTRUCTION_VINSERTF64X2, NMD_X86_INSTRUCTION_VINSERTF64X4, NMD_X86_INSTRUCTION_VINSERTI128, NMD_X86_INSTRUCTION_VINSERTI32X4, NMD_X86_INSTRUCTION_VINSERTI32X8, NMD_X86_INSTRUCTION_VINSERTI64X2, NMD_X86_INSTRUCTION_VINSERTI64X4, NMD_X86_INSTRUCTION_VINSERTPS, NMD_X86_INSTRUCTION_VLDDQU, NMD_X86_INSTRUCTION_VLDMXCSR, NMD_X86_INSTRUCTION_VMASKMOVDQU, NMD_X86_INSTRUCTION_VMASKMOVPD, NMD_X86_INSTRUCTION_VMASKMOVPS, NMD_X86_INSTRUCTION_VMAXPD, NMD_X86_INSTRUCTION_VMAXPS, NMD_X86_INSTRUCTION_VMAXSD, NMD_X86_INSTRUCTION_VMAXSS, NMD_X86_INSTRUCTION_VMCLEAR, NMD_X86_INSTRUCTION_VMINPD, NMD_X86_INSTRUCTION_VMINPS, NMD_X86_INSTRUCTION_VMINSD, NMD_X86_INSTRUCTION_VMINSS, NMD_X86_INSTRUCTION_VMOVQ, NMD_X86_INSTRUCTION_VMOVDDUP, NMD_X86_INSTRUCTION_VMOVD, NMD_X86_INSTRUCTION_VMOVDQA32, NMD_X86_INSTRUCTION_VMOVDQA64, NMD_X86_INSTRUCTION_VMOVDQA, NMD_X86_INSTRUCTION_VMOVDQU16, NMD_X86_INSTRUCTION_VMOVDQU32, NMD_X86_INSTRUCTION_VMOVDQU64, NMD_X86_INSTRUCTION_VMOVDQU8, NMD_X86_INSTRUCTION_VMOVDQU, NMD_X86_INSTRUCTION_VMOVHLPS, NMD_X86_INSTRUCTION_VMOVHPD, NMD_X86_INSTRUCTION_VMOVHPS, NMD_X86_INSTRUCTION_VMOVLHPS, NMD_X86_INSTRUCTION_VMOVLPD, NMD_X86_INSTRUCTION_VMOVLPS, NMD_X86_INSTRUCTION_VMOVMSKPD, NMD_X86_INSTRUCTION_VMOVMSKPS, NMD_X86_INSTRUCTION_VMOVNTDQA, NMD_X86_INSTRUCTION_VMOVNTDQ, NMD_X86_INSTRUCTION_VMOVNTPD, NMD_X86_INSTRUCTION_VMOVNTPS, NMD_X86_INSTRUCTION_VMOVSD, NMD_X86_INSTRUCTION_VMOVSHDUP, NMD_X86_INSTRUCTION_VMOVSLDUP, NMD_X86_INSTRUCTION_VMOVSS, NMD_X86_INSTRUCTION_VMOVUPD, NMD_X86_INSTRUCTION_VMOVUPS, NMD_X86_INSTRUCTION_VMPSADBW, NMD_X86_INSTRUCTION_VMPTRLD, NMD_X86_INSTRUCTION_VMPTRST, NMD_X86_INSTRUCTION_VMREAD, NMD_X86_INSTRUCTION_VMULPD, NMD_X86_INSTRUCTION_VMULPS, NMD_X86_INSTRUCTION_VMULSD, NMD_X86_INSTRUCTION_VMULSS, NMD_X86_INSTRUCTION_VMWRITE, NMD_X86_INSTRUCTION_VMXON, NMD_X86_INSTRUCTION_VPABSB, NMD_X86_INSTRUCTION_VPABSD, NMD_X86_INSTRUCTION_VPABSQ, NMD_X86_INSTRUCTION_VPABSW, NMD_X86_INSTRUCTION_VPACKSSDW, NMD_X86_INSTRUCTION_VPACKSSWB, NMD_X86_INSTRUCTION_VPACKUSDW, NMD_X86_INSTRUCTION_VPACKUSWB, NMD_X86_INSTRUCTION_VPADDB, NMD_X86_INSTRUCTION_VPADDD, NMD_X86_INSTRUCTION_VPADDQ, NMD_X86_INSTRUCTION_VPADDSB, NMD_X86_INSTRUCTION_VPADDSW, NMD_X86_INSTRUCTION_VPADDUSB, NMD_X86_INSTRUCTION_VPADDUSW, NMD_X86_INSTRUCTION_VPADDW, NMD_X86_INSTRUCTION_VPALIGNR, NMD_X86_INSTRUCTION_VPANDD, NMD_X86_INSTRUCTION_VPANDND, NMD_X86_INSTRUCTION_VPANDNQ, NMD_X86_INSTRUCTION_VPANDN, NMD_X86_INSTRUCTION_VPANDQ, NMD_X86_INSTRUCTION_VPAND, NMD_X86_INSTRUCTION_VPAVGB, NMD_X86_INSTRUCTION_VPAVGW, NMD_X86_INSTRUCTION_VPBLENDD, NMD_X86_INSTRUCTION_VPBLENDMB, NMD_X86_INSTRUCTION_VPBLENDMD, NMD_X86_INSTRUCTION_VPBLENDMQ, NMD_X86_INSTRUCTION_VPBLENDMW, NMD_X86_INSTRUCTION_VPBLENDVB, NMD_X86_INSTRUCTION_VPBLENDW, NMD_X86_INSTRUCTION_VPBROADCASTB, NMD_X86_INSTRUCTION_VPBROADCASTD, NMD_X86_INSTRUCTION_VPBROADCASTMB2Q, NMD_X86_INSTRUCTION_VPBROADCASTMW2D, NMD_X86_INSTRUCTION_VPBROADCASTQ, NMD_X86_INSTRUCTION_VPBROADCASTW, NMD_X86_INSTRUCTION_VPCLMULQDQ, NMD_X86_INSTRUCTION_VPCMOV, NMD_X86_INSTRUCTION_VPCMPB, NMD_X86_INSTRUCTION_VPCMPD, NMD_X86_INSTRUCTION_VPCMPEQB, NMD_X86_INSTRUCTION_VPCMPEQD, NMD_X86_INSTRUCTION_VPCMPEQQ, NMD_X86_INSTRUCTION_VPCMPEQW, NMD_X86_INSTRUCTION_VPCMPESTRI, NMD_X86_INSTRUCTION_VPCMPESTRM, NMD_X86_INSTRUCTION_VPCMPGTB, NMD_X86_INSTRUCTION_VPCMPGTD, NMD_X86_INSTRUCTION_VPCMPGTW, NMD_X86_INSTRUCTION_VPCMPISTRI, NMD_X86_INSTRUCTION_VPCMPISTRM, NMD_X86_INSTRUCTION_VPCMPQ, NMD_X86_INSTRUCTION_VPCMPUB, NMD_X86_INSTRUCTION_VPCMPUD, NMD_X86_INSTRUCTION_VPCMPUQ, NMD_X86_INSTRUCTION_VPCMPUW, NMD_X86_INSTRUCTION_VPCMPW, NMD_X86_INSTRUCTION_VPCOMB, NMD_X86_INSTRUCTION_VPCOMD, NMD_X86_INSTRUCTION_VPCOMPRESSD, NMD_X86_INSTRUCTION_VPCOMPRESSQ, NMD_X86_INSTRUCTION_VPCOMQ, NMD_X86_INSTRUCTION_VPCOMUB, NMD_X86_INSTRUCTION_VPCOMUD, NMD_X86_INSTRUCTION_VPCOMUQ, NMD_X86_INSTRUCTION_VPCOMUW, NMD_X86_INSTRUCTION_VPCOMW, NMD_X86_INSTRUCTION_VPCONFLICTD, NMD_X86_INSTRUCTION_VPCONFLICTQ, NMD_X86_INSTRUCTION_VPERM2F128, NMD_X86_INSTRUCTION_VPERM2I128, NMD_X86_INSTRUCTION_VPERMD, NMD_X86_INSTRUCTION_VPERMI2D, NMD_X86_INSTRUCTION_VPERMI2PD, NMD_X86_INSTRUCTION_VPERMI2PS, NMD_X86_INSTRUCTION_VPERMI2Q, NMD_X86_INSTRUCTION_VPERMIL2PD, NMD_X86_INSTRUCTION_VPERMIL2PS, NMD_X86_INSTRUCTION_VPERMILPD, NMD_X86_INSTRUCTION_VPERMILPS, NMD_X86_INSTRUCTION_VPERMPD, NMD_X86_INSTRUCTION_VPERMPS, NMD_X86_INSTRUCTION_VPERMQ, NMD_X86_INSTRUCTION_VPERMT2D, NMD_X86_INSTRUCTION_VPERMT2PD, NMD_X86_INSTRUCTION_VPERMT2PS, NMD_X86_INSTRUCTION_VPERMT2Q, NMD_X86_INSTRUCTION_VPEXPANDD, NMD_X86_INSTRUCTION_VPEXPANDQ, NMD_X86_INSTRUCTION_VPEXTRB, NMD_X86_INSTRUCTION_VPEXTRD, NMD_X86_INSTRUCTION_VPEXTRQ, NMD_X86_INSTRUCTION_VPEXTRW, NMD_X86_INSTRUCTION_VPGATHERDD, NMD_X86_INSTRUCTION_VPGATHERDQ, NMD_X86_INSTRUCTION_VPGATHERQD, NMD_X86_INSTRUCTION_VPGATHERQQ, NMD_X86_INSTRUCTION_VPHADDBD, NMD_X86_INSTRUCTION_VPHADDBQ, NMD_X86_INSTRUCTION_VPHADDBW, NMD_X86_INSTRUCTION_VPHADDUBD, NMD_X86_INSTRUCTION_VPHADDUBQ, NMD_X86_INSTRUCTION_VPHADDUBW, NMD_X86_INSTRUCTION_VPHADDUDQ, NMD_X86_INSTRUCTION_VPHADDUWD, NMD_X86_INSTRUCTION_VPHADDUWQ, NMD_X86_INSTRUCTION_VPHADDWD, NMD_X86_INSTRUCTION_VPHMINPOSUW, NMD_X86_INSTRUCTION_VPHSUBBW, NMD_X86_INSTRUCTION_VPHSUBDQ, NMD_X86_INSTRUCTION_VPHSUBWD, NMD_X86_INSTRUCTION_VPINSRB, NMD_X86_INSTRUCTION_VPINSRD, NMD_X86_INSTRUCTION_VPINSRQ, NMD_X86_INSTRUCTION_VPINSRW, NMD_X86_INSTRUCTION_VPLZCNTD, NMD_X86_INSTRUCTION_VPLZCNTQ, NMD_X86_INSTRUCTION_VPMACSDD, NMD_X86_INSTRUCTION_VPMACSDQH, NMD_X86_INSTRUCTION_VPMACSDQL, NMD_X86_INSTRUCTION_VPMACSSDD, NMD_X86_INSTRUCTION_VPMACSSDQH, NMD_X86_INSTRUCTION_VPMACSSDQL, NMD_X86_INSTRUCTION_VPMACSSWD, NMD_X86_INSTRUCTION_VPMACSSWW, NMD_X86_INSTRUCTION_VPMACSWD, NMD_X86_INSTRUCTION_VPMACSWW, NMD_X86_INSTRUCTION_VPMADCSSWD, NMD_X86_INSTRUCTION_VPMADCSWD, NMD_X86_INSTRUCTION_VPMADDWD, NMD_X86_INSTRUCTION_VPMASKMOVD, NMD_X86_INSTRUCTION_VPMASKMOVQ, NMD_X86_INSTRUCTION_VPMAXSB, NMD_X86_INSTRUCTION_VPMAXSD, NMD_X86_INSTRUCTION_VPMAXSQ, NMD_X86_INSTRUCTION_VPMAXSW, NMD_X86_INSTRUCTION_VPMAXUB, NMD_X86_INSTRUCTION_VPMAXUD, NMD_X86_INSTRUCTION_VPMAXUQ, NMD_X86_INSTRUCTION_VPMAXUW, NMD_X86_INSTRUCTION_VPMINSB, NMD_X86_INSTRUCTION_VPMINSD, NMD_X86_INSTRUCTION_VPMINSQ, NMD_X86_INSTRUCTION_VPMINSW, NMD_X86_INSTRUCTION_VPMINUB, NMD_X86_INSTRUCTION_VPMINUD, NMD_X86_INSTRUCTION_VPMINUQ, NMD_X86_INSTRUCTION_VPMINUW, NMD_X86_INSTRUCTION_VPMOVDB, NMD_X86_INSTRUCTION_VPMOVDW, NMD_X86_INSTRUCTION_VPMOVM2B, NMD_X86_INSTRUCTION_VPMOVM2D, NMD_X86_INSTRUCTION_VPMOVM2Q, NMD_X86_INSTRUCTION_VPMOVM2W, NMD_X86_INSTRUCTION_VPMOVMSKB, NMD_X86_INSTRUCTION_VPMOVQB, NMD_X86_INSTRUCTION_VPMOVQD, NMD_X86_INSTRUCTION_VPMOVQW, NMD_X86_INSTRUCTION_VPMOVSDB, NMD_X86_INSTRUCTION_VPMOVSDW, NMD_X86_INSTRUCTION_VPMOVSQB, NMD_X86_INSTRUCTION_VPMOVSQD, NMD_X86_INSTRUCTION_VPMOVSQW, NMD_X86_INSTRUCTION_VPMOVSXBD, NMD_X86_INSTRUCTION_VPMOVSXBQ, NMD_X86_INSTRUCTION_VPMOVSXBW, NMD_X86_INSTRUCTION_VPMOVSXDQ, NMD_X86_INSTRUCTION_VPMOVSXWD, NMD_X86_INSTRUCTION_VPMOVSXWQ, NMD_X86_INSTRUCTION_VPMOVUSDB, NMD_X86_INSTRUCTION_VPMOVUSDW, NMD_X86_INSTRUCTION_VPMOVUSQB, NMD_X86_INSTRUCTION_VPMOVUSQD, NMD_X86_INSTRUCTION_VPMOVUSQW, NMD_X86_INSTRUCTION_VPMOVZXBD, NMD_X86_INSTRUCTION_VPMOVZXBQ, NMD_X86_INSTRUCTION_VPMOVZXBW, NMD_X86_INSTRUCTION_VPMOVZXDQ, NMD_X86_INSTRUCTION_VPMOVZXWD, NMD_X86_INSTRUCTION_VPMOVZXWQ, NMD_X86_INSTRUCTION_VPMULDQ, NMD_X86_INSTRUCTION_VPMULHUW, NMD_X86_INSTRUCTION_VPMULHW, NMD_X86_INSTRUCTION_VPMULLD, NMD_X86_INSTRUCTION_VPMULLQ, NMD_X86_INSTRUCTION_VPMULLW, NMD_X86_INSTRUCTION_VPMULUDQ, NMD_X86_INSTRUCTION_VPORD, NMD_X86_INSTRUCTION_VPORQ, NMD_X86_INSTRUCTION_VPOR, NMD_X86_INSTRUCTION_VPPERM, NMD_X86_INSTRUCTION_VPROTB, NMD_X86_INSTRUCTION_VPROTD, NMD_X86_INSTRUCTION_VPROTQ, NMD_X86_INSTRUCTION_VPROTW, NMD_X86_INSTRUCTION_VPSADBW, NMD_X86_INSTRUCTION_VPSCATTERDD, NMD_X86_INSTRUCTION_VPSCATTERDQ, NMD_X86_INSTRUCTION_VPSCATTERQD, NMD_X86_INSTRUCTION_VPSCATTERQQ, NMD_X86_INSTRUCTION_VPSHAB, NMD_X86_INSTRUCTION_VPSHAD, NMD_X86_INSTRUCTION_VPSHAQ, NMD_X86_INSTRUCTION_VPSHAW, NMD_X86_INSTRUCTION_VPSHLB, NMD_X86_INSTRUCTION_VPSHLD, NMD_X86_INSTRUCTION_VPSHLQ, NMD_X86_INSTRUCTION_VPSHLW, NMD_X86_INSTRUCTION_VPSHUFD, NMD_X86_INSTRUCTION_VPSHUFHW, NMD_X86_INSTRUCTION_VPSHUFLW, NMD_X86_INSTRUCTION_VPSLLDQ, NMD_X86_INSTRUCTION_VPSLLD, NMD_X86_INSTRUCTION_VPSLLQ, NMD_X86_INSTRUCTION_VPSLLVD, NMD_X86_INSTRUCTION_VPSLLVQ, NMD_X86_INSTRUCTION_VPSLLW, NMD_X86_INSTRUCTION_VPSRAD, NMD_X86_INSTRUCTION_VPSRAQ, NMD_X86_INSTRUCTION_VPSRAVD, NMD_X86_INSTRUCTION_VPSRAVQ, NMD_X86_INSTRUCTION_VPSRAW, NMD_X86_INSTRUCTION_VPSRLDQ, NMD_X86_INSTRUCTION_VPSRLD, NMD_X86_INSTRUCTION_VPSRLQ, NMD_X86_INSTRUCTION_VPSRLVD, NMD_X86_INSTRUCTION_VPSRLVQ, NMD_X86_INSTRUCTION_VPSRLW, NMD_X86_INSTRUCTION_VPSUBB, NMD_X86_INSTRUCTION_VPSUBD, NMD_X86_INSTRUCTION_VPSUBQ, NMD_X86_INSTRUCTION_VPSUBSB, NMD_X86_INSTRUCTION_VPSUBSW, NMD_X86_INSTRUCTION_VPSUBUSB, NMD_X86_INSTRUCTION_VPSUBUSW, NMD_X86_INSTRUCTION_VPSUBW, NMD_X86_INSTRUCTION_VPTESTMD, NMD_X86_INSTRUCTION_VPTESTMQ, NMD_X86_INSTRUCTION_VPTESTNMD, NMD_X86_INSTRUCTION_VPTESTNMQ, NMD_X86_INSTRUCTION_VPTEST, NMD_X86_INSTRUCTION_VPUNPCKHBW, NMD_X86_INSTRUCTION_VPUNPCKHDQ, NMD_X86_INSTRUCTION_VPUNPCKHQDQ, NMD_X86_INSTRUCTION_VPUNPCKHWD, NMD_X86_INSTRUCTION_VPUNPCKLBW, NMD_X86_INSTRUCTION_VPUNPCKLDQ, NMD_X86_INSTRUCTION_VPUNPCKLQDQ, NMD_X86_INSTRUCTION_VPUNPCKLWD, NMD_X86_INSTRUCTION_VPXORD, NMD_X86_INSTRUCTION_VPXORQ, NMD_X86_INSTRUCTION_VPXOR, NMD_X86_INSTRUCTION_VRCP14PD, NMD_X86_INSTRUCTION_VRCP14PS, NMD_X86_INSTRUCTION_VRCP14SD, NMD_X86_INSTRUCTION_VRCP14SS, NMD_X86_INSTRUCTION_VRCP28PD, NMD_X86_INSTRUCTION_VRCP28PS, NMD_X86_INSTRUCTION_VRCP28SD, NMD_X86_INSTRUCTION_VRCP28SS, NMD_X86_INSTRUCTION_VRCPPS, NMD_X86_INSTRUCTION_VRCPSS, NMD_X86_INSTRUCTION_VRNDSCALEPD, NMD_X86_INSTRUCTION_VRNDSCALEPS, NMD_X86_INSTRUCTION_VRNDSCALESD, NMD_X86_INSTRUCTION_VRNDSCALESS, NMD_X86_INSTRUCTION_VROUNDPD, NMD_X86_INSTRUCTION_VROUNDPS, NMD_X86_INSTRUCTION_VROUNDSD, NMD_X86_INSTRUCTION_VROUNDSS, NMD_X86_INSTRUCTION_VRSQRT14PD, NMD_X86_INSTRUCTION_VRSQRT14PS, NMD_X86_INSTRUCTION_VRSQRT14SD, NMD_X86_INSTRUCTION_VRSQRT14SS, NMD_X86_INSTRUCTION_VRSQRT28PD, NMD_X86_INSTRUCTION_VRSQRT28PS, NMD_X86_INSTRUCTION_VRSQRT28SD, NMD_X86_INSTRUCTION_VRSQRT28SS, NMD_X86_INSTRUCTION_VRSQRTPS, NMD_X86_INSTRUCTION_VRSQRTSS, NMD_X86_INSTRUCTION_VSCATTERDPD, NMD_X86_INSTRUCTION_VSCATTERDPS, NMD_X86_INSTRUCTION_VSCATTERPF0DPD, NMD_X86_INSTRUCTION_VSCATTERPF0DPS, NMD_X86_INSTRUCTION_VSCATTERPF0QPD, NMD_X86_INSTRUCTION_VSCATTERPF0QPS, NMD_X86_INSTRUCTION_VSCATTERPF1DPD, NMD_X86_INSTRUCTION_VSCATTERPF1DPS, NMD_X86_INSTRUCTION_VSCATTERPF1QPD, NMD_X86_INSTRUCTION_VSCATTERPF1QPS, NMD_X86_INSTRUCTION_VSCATTERQPD, NMD_X86_INSTRUCTION_VSCATTERQPS, NMD_X86_INSTRUCTION_VSHUFPD, NMD_X86_INSTRUCTION_VSHUFPS, NMD_X86_INSTRUCTION_VSQRTPD, NMD_X86_INSTRUCTION_VSQRTPS, NMD_X86_INSTRUCTION_VSQRTSD, NMD_X86_INSTRUCTION_VSQRTSS, NMD_X86_INSTRUCTION_VSTMXCSR, NMD_X86_INSTRUCTION_VSUBPD, NMD_X86_INSTRUCTION_VSUBPS, NMD_X86_INSTRUCTION_VSUBSD, NMD_X86_INSTRUCTION_VSUBSS, NMD_X86_INSTRUCTION_VTESTPD, NMD_X86_INSTRUCTION_VTESTPS, NMD_X86_INSTRUCTION_VUNPCKHPD, NMD_X86_INSTRUCTION_VUNPCKHPS, NMD_X86_INSTRUCTION_VUNPCKLPD, NMD_X86_INSTRUCTION_VUNPCKLPS, NMD_X86_INSTRUCTION_VZEROALL, NMD_X86_INSTRUCTION_VZEROUPPER, NMD_X86_INSTRUCTION_FWAIT, NMD_X86_INSTRUCTION_XABORT, NMD_X86_INSTRUCTION_XACQUIRE, NMD_X86_INSTRUCTION_XBEGIN, NMD_X86_INSTRUCTION_XCHG, NMD_X86_INSTRUCTION_XCRYPTCBC, NMD_X86_INSTRUCTION_XCRYPTCFB, NMD_X86_INSTRUCTION_XCRYPTCTR, NMD_X86_INSTRUCTION_XCRYPTECB, NMD_X86_INSTRUCTION_XCRYPTOFB, NMD_X86_INSTRUCTION_XRELEASE, NMD_X86_INSTRUCTION_XRSTOR64, NMD_X86_INSTRUCTION_XRSTORS, NMD_X86_INSTRUCTION_XRSTORS64, NMD_X86_INSTRUCTION_XSAVE64, NMD_X86_INSTRUCTION_XSAVEC, NMD_X86_INSTRUCTION_XSAVEC64, NMD_X86_INSTRUCTION_XSAVEOPT64, NMD_X86_INSTRUCTION_XSAVES, NMD_X86_INSTRUCTION_XSAVES64, NMD_X86_INSTRUCTION_XSHA1, NMD_X86_INSTRUCTION_XSHA256, NMD_X86_INSTRUCTION_XSTORE, NMD_X86_INSTRUCTION_FDISI8087_NOP, NMD_X86_INSTRUCTION_FENI8087_NOP, /* pseudo instructions */ NMD_X86_INSTRUCTION_CMPSS, NMD_X86_INSTRUCTION_CMPEQSS, NMD_X86_INSTRUCTION_CMPLTSS, NMD_X86_INSTRUCTION_CMPLESS, NMD_X86_INSTRUCTION_CMPUNORDSS, NMD_X86_INSTRUCTION_CMPNEQSS, NMD_X86_INSTRUCTION_CMPNLTSS, NMD_X86_INSTRUCTION_CMPNLESS, NMD_X86_INSTRUCTION_CMPORDSS, NMD_X86_INSTRUCTION_CMPSD, NMD_X86_INSTRUCTION_CMPEQSD, NMD_X86_INSTRUCTION_CMPLTSD, NMD_X86_INSTRUCTION_CMPLESD, NMD_X86_INSTRUCTION_CMPUNORDSD, NMD_X86_INSTRUCTION_CMPNEQSD, NMD_X86_INSTRUCTION_CMPNLTSD, NMD_X86_INSTRUCTION_CMPNLESD, NMD_X86_INSTRUCTION_CMPORDSD, NMD_X86_INSTRUCTION_CMPPS, NMD_X86_INSTRUCTION_CMPEQPS, NMD_X86_INSTRUCTION_CMPLTPS, NMD_X86_INSTRUCTION_CMPLEPS, NMD_X86_INSTRUCTION_CMPUNORDPS, NMD_X86_INSTRUCTION_CMPNEQPS, NMD_X86_INSTRUCTION_CMPNLTPS, NMD_X86_INSTRUCTION_CMPNLEPS, NMD_X86_INSTRUCTION_CMPORDPS, NMD_X86_INSTRUCTION_CMPPD, NMD_X86_INSTRUCTION_CMPEQPD, NMD_X86_INSTRUCTION_CMPLTPD, NMD_X86_INSTRUCTION_CMPLEPD, NMD_X86_INSTRUCTION_CMPUNORDPD, NMD_X86_INSTRUCTION_CMPNEQPD, NMD_X86_INSTRUCTION_CMPNLTPD, NMD_X86_INSTRUCTION_CMPNLEPD, NMD_X86_INSTRUCTION_CMPORDPD, NMD_X86_INSTRUCTION_VCMPSS, NMD_X86_INSTRUCTION_VCMPEQSS, NMD_X86_INSTRUCTION_VCMPLTSS, NMD_X86_INSTRUCTION_VCMPLESS, NMD_X86_INSTRUCTION_VCMPUNORDSS, NMD_X86_INSTRUCTION_VCMPNEQSS, NMD_X86_INSTRUCTION_VCMPNLTSS, NMD_X86_INSTRUCTION_VCMPNLESS, NMD_X86_INSTRUCTION_VCMPORDSS, NMD_X86_INSTRUCTION_VCMPEQ_UQSS, NMD_X86_INSTRUCTION_VCMPNGESS, NMD_X86_INSTRUCTION_VCMPNGTSS, NMD_X86_INSTRUCTION_VCMPFALSESS, NMD_X86_INSTRUCTION_VCMPNEQ_OQSS, NMD_X86_INSTRUCTION_VCMPGESS, NMD_X86_INSTRUCTION_VCMPGTSS, NMD_X86_INSTRUCTION_VCMPTRUESS, NMD_X86_INSTRUCTION_VCMPEQ_OSSS, NMD_X86_INSTRUCTION_VCMPLT_OQSS, NMD_X86_INSTRUCTION_VCMPLE_OQSS, NMD_X86_INSTRUCTION_VCMPUNORD_SSS, NMD_X86_INSTRUCTION_VCMPNEQ_USSS, NMD_X86_INSTRUCTION_VCMPNLT_UQSS, NMD_X86_INSTRUCTION_VCMPNLE_UQSS, NMD_X86_INSTRUCTION_VCMPORD_SSS, NMD_X86_INSTRUCTION_VCMPEQ_USSS, NMD_X86_INSTRUCTION_VCMPNGE_UQSS, NMD_X86_INSTRUCTION_VCMPNGT_UQSS, NMD_X86_INSTRUCTION_VCMPFALSE_OSSS, NMD_X86_INSTRUCTION_VCMPNEQ_OSSS, NMD_X86_INSTRUCTION_VCMPGE_OQSS, NMD_X86_INSTRUCTION_VCMPGT_OQSS, NMD_X86_INSTRUCTION_VCMPTRUE_USSS, NMD_X86_INSTRUCTION_VCMPSD, NMD_X86_INSTRUCTION_VCMPEQSD, NMD_X86_INSTRUCTION_VCMPLTSD, NMD_X86_INSTRUCTION_VCMPLESD, NMD_X86_INSTRUCTION_VCMPUNORDSD, NMD_X86_INSTRUCTION_VCMPNEQSD, NMD_X86_INSTRUCTION_VCMPNLTSD, NMD_X86_INSTRUCTION_VCMPNLESD, NMD_X86_INSTRUCTION_VCMPORDSD, NMD_X86_INSTRUCTION_VCMPEQ_UQSD, NMD_X86_INSTRUCTION_VCMPNGESD, NMD_X86_INSTRUCTION_VCMPNGTSD, NMD_X86_INSTRUCTION_VCMPFALSESD, NMD_X86_INSTRUCTION_VCMPNEQ_OQSD, NMD_X86_INSTRUCTION_VCMPGESD, NMD_X86_INSTRUCTION_VCMPGTSD, NMD_X86_INSTRUCTION_VCMPTRUESD, NMD_X86_INSTRUCTION_VCMPEQ_OSSD, NMD_X86_INSTRUCTION_VCMPLT_OQSD, NMD_X86_INSTRUCTION_VCMPLE_OQSD, NMD_X86_INSTRUCTION_VCMPUNORD_SSD, NMD_X86_INSTRUCTION_VCMPNEQ_USSD, NMD_X86_INSTRUCTION_VCMPNLT_UQSD, NMD_X86_INSTRUCTION_VCMPNLE_UQSD, NMD_X86_INSTRUCTION_VCMPORD_SSD, NMD_X86_INSTRUCTION_VCMPEQ_USSD, NMD_X86_INSTRUCTION_VCMPNGE_UQSD, NMD_X86_INSTRUCTION_VCMPNGT_UQSD, NMD_X86_INSTRUCTION_VCMPFALSE_OSSD, NMD_X86_INSTRUCTION_VCMPNEQ_OSSD, NMD_X86_INSTRUCTION_VCMPGE_OQSD, NMD_X86_INSTRUCTION_VCMPGT_OQSD, NMD_X86_INSTRUCTION_VCMPTRUE_USSD, NMD_X86_INSTRUCTION_VCMPPS, NMD_X86_INSTRUCTION_VCMPEQPS, NMD_X86_INSTRUCTION_VCMPLTPS, NMD_X86_INSTRUCTION_VCMPLEPS, NMD_X86_INSTRUCTION_VCMPUNORDPS, NMD_X86_INSTRUCTION_VCMPNEQPS, NMD_X86_INSTRUCTION_VCMPNLTPS, NMD_X86_INSTRUCTION_VCMPNLEPS, NMD_X86_INSTRUCTION_VCMPORDPS, NMD_X86_INSTRUCTION_VCMPEQ_UQPS, NMD_X86_INSTRUCTION_VCMPNGEPS, NMD_X86_INSTRUCTION_VCMPNGTPS, NMD_X86_INSTRUCTION_VCMPFALSEPS, NMD_X86_INSTRUCTION_VCMPNEQ_OQPS, NMD_X86_INSTRUCTION_VCMPGEPS, NMD_X86_INSTRUCTION_VCMPGTPS, NMD_X86_INSTRUCTION_VCMPTRUEPS, NMD_X86_INSTRUCTION_VCMPEQ_OSPS, NMD_X86_INSTRUCTION_VCMPLT_OQPS, NMD_X86_INSTRUCTION_VCMPLE_OQPS, NMD_X86_INSTRUCTION_VCMPUNORD_SPS, NMD_X86_INSTRUCTION_VCMPNEQ_USPS, NMD_X86_INSTRUCTION_VCMPNLT_UQPS, NMD_X86_INSTRUCTION_VCMPNLE_UQPS, NMD_X86_INSTRUCTION_VCMPORD_SPS, NMD_X86_INSTRUCTION_VCMPEQ_USPS, NMD_X86_INSTRUCTION_VCMPNGE_UQPS, NMD_X86_INSTRUCTION_VCMPNGT_UQPS, NMD_X86_INSTRUCTION_VCMPFALSE_OSPS, NMD_X86_INSTRUCTION_VCMPNEQ_OSPS, NMD_X86_INSTRUCTION_VCMPGE_OQPS, NMD_X86_INSTRUCTION_VCMPGT_OQPS, NMD_X86_INSTRUCTION_VCMPTRUE_USPS, NMD_X86_INSTRUCTION_VCMPPD, NMD_X86_INSTRUCTION_VCMPEQPD, NMD_X86_INSTRUCTION_VCMPLTPD, NMD_X86_INSTRUCTION_VCMPLEPD, NMD_X86_INSTRUCTION_VCMPUNORDPD, NMD_X86_INSTRUCTION_VCMPNEQPD, NMD_X86_INSTRUCTION_VCMPNLTPD, NMD_X86_INSTRUCTION_VCMPNLEPD, NMD_X86_INSTRUCTION_VCMPORDPD, NMD_X86_INSTRUCTION_VCMPEQ_UQPD, NMD_X86_INSTRUCTION_VCMPNGEPD, NMD_X86_INSTRUCTION_VCMPNGTPD, NMD_X86_INSTRUCTION_VCMPFALSEPD, NMD_X86_INSTRUCTION_VCMPNEQ_OQPD, NMD_X86_INSTRUCTION_VCMPGEPD, NMD_X86_INSTRUCTION_VCMPGTPD, NMD_X86_INSTRUCTION_VCMPTRUEPD, NMD_X86_INSTRUCTION_VCMPEQ_OSPD, NMD_X86_INSTRUCTION_VCMPLT_OQPD, NMD_X86_INSTRUCTION_VCMPLE_OQPD, NMD_X86_INSTRUCTION_VCMPUNORD_SPD, NMD_X86_INSTRUCTION_VCMPNEQ_USPD, NMD_X86_INSTRUCTION_VCMPNLT_UQPD, NMD_X86_INSTRUCTION_VCMPNLE_UQPD, NMD_X86_INSTRUCTION_VCMPORD_SPD, NMD_X86_INSTRUCTION_VCMPEQ_USPD, NMD_X86_INSTRUCTION_VCMPNGE_UQPD, NMD_X86_INSTRUCTION_VCMPNGT_UQPD, NMD_X86_INSTRUCTION_VCMPFALSE_OSPD, NMD_X86_INSTRUCTION_VCMPNEQ_OSPD, NMD_X86_INSTRUCTION_VCMPGE_OQPD, NMD_X86_INSTRUCTION_VCMPGT_OQPD, NMD_X86_INSTRUCTION_VCMPTRUE_USPD, NMD_X86_INSTRUCTION_UD0, NMD_X86_INSTRUCTION_ENDBR32, NMD_X86_INSTRUCTION_ENDBR64, }; enum NMD_X86_OPERAND_TYPE { NMD_X86_OPERAND_TYPE_NONE = 0, NMD_X86_OPERAND_TYPE_REGISTER, NMD_X86_OPERAND_TYPE_MEMORY, NMD_X86_OPERAND_TYPE_IMMEDIATE, }; typedef struct nmd_x86_memory_operand { uint8_t segment; /* The segment register. A member of 'NMD_X86_REG'. */ uint8_t base; /* The base register. A member of 'NMD_X86_REG'. */ uint8_t index; /* The index register. A member of 'NMD_X86_REG'. */ uint8_t scale; /* Scale(1, 2, 4 or 8). */ int64_t disp; /* Displacement. */ } nmd_x86_memory_operand; enum NMD_X86_OPERAND_ACTION { NMD_X86_OPERAND_ACTION_NONE = 0, /* The operand is neither read from nor written to. */ NMD_X86_OPERAND_ACTION_READ = (1 << 0), /* The operand is read. */ NMD_X86_OPERAND_ACTION_WRITE = (1 << 1), /* The operand is modified. */ NMD_X86_OPERAND_ACTION_CONDREAD = (1 << 2), /* The operand may be read depending on some condition(conditional read). */ NMD_X86_OPERAND_ACTION_CONDWRITE = (1 << 3), /* The operand may be modified depending on some condition(conditional write). */ /* These are not actual actions, but rather masks of actions. */ NMD_X86_OPERAND_ACTION_READWRITE = (NMD_X86_OPERAND_ACTION_READ | NMD_X86_OPERAND_ACTION_WRITE), NMD_X86_OPERAND_ACTION_ANY_READ = (NMD_X86_OPERAND_ACTION_READ | NMD_X86_OPERAND_ACTION_CONDREAD), NMD_X86_OPERAND_ACTION_ANY_WRITE = (NMD_X86_OPERAND_ACTION_WRITE | NMD_X86_OPERAND_ACTION_CONDWRITE) }; typedef struct nmd_x86_operand { uint8_t type; /* The operand's type. A member of 'NMD_X86_OPERAND_TYPE'. */ /* uint8_t size; The operand's size. (I don't really know what this `size` variable represents or how it would be useful) */ bool is_implicit; /* If true, the operand does not appear on the intruction's formatted form. */ uint8_t action; /* The action on the operand. A member of 'NMD_X86_OPERAND_ACTION'. */ union { /* The operand's "raw" data. */ uint8_t reg; /* Register operand. A variable of type 'NMD_X86_REG' */ int64_t imm; /* Immediate operand. */ nmd_x86_memory_operand mem; /* Memory operand. */ } fields; } nmd_x86_operand; typedef union nmd_x86_cpu_flags { struct { uint8_t CF : 1; /* Bit 0. Carry Flag (CF) */ uint8_t b1 : 1; /* Bit 1. Reserved */ uint8_t PF : 1; /* Bit 2. Parity Flag (PF) */ uint8_t B3 : 1; /* Bit 3. Reserved */ uint8_t AF : 1; /* Bit 4. Auxiliary Carry Flag (AF) */ uint8_t B5 : 1; /* Bit 5. Reserved */ uint8_t ZF : 1; /* Bit 6. Zero flag(ZF) */ uint8_t SF : 1; /* Bit 7. Sign flag(SF) */ uint8_t TF : 1; /* Bit 8. Trap flag(TF) */ uint8_t IF : 1; /* Bit 9. Interrupt Enable Flag (IF) */ uint8_t DF : 1; /* Bit 10. Direction Flag (DF) */ uint8_t OF : 1; /* Bit 11. Overflow Flag (OF) */ uint8_t IOPL : 2; /* Bit 12,13. I/O Privilege Level (IOPL) */ uint8_t NT : 1; /* Bit 14. Nested Task (NT) */ uint8_t B15 : 1; /* Bit 15. Reserved */ uint8_t RF : 1; /* Bit 16. Resume Flag (RF) */ uint8_t VM : 1; /* Bit 17. Virtual-8086 Mode (VM) */ uint8_t AC : 1; /* Bit 18. Alignment Check / Access Control (AC) */ uint8_t VIF : 1; /* Bit 19. Virtual Interrupt Flag (VIF) */ uint8_t VIP : 1; /* Bit 20. Virtual Interrupt Pending (VIP) */ uint8_t ID : 1; /* Bit 21. ID Flag(ID) */ uint8_t B22 : 1; /* Bit 22. Reserved */ uint8_t B23 : 1; /* Bit 23. Reserved */ uint8_t B24 : 1; /* Bit 24. Reserved */ uint8_t B25 : 1; /* Bit 25. Reserved */ uint8_t B26 : 1; /* Bit 26. Reserved */ uint8_t B27 : 1; /* Bit 27. Reserved */ uint8_t B28 : 1; /* Bit 28. Reserved */ uint8_t B29 : 1; /* Bit 29. Reserved */ uint8_t B30 : 1; /* Bit 30. Reserved */ uint8_t B31 : 1; /* Bit 31. Reserved */ } fields; struct { uint8_t IE : 1; /* Bit 0. Invalid Operation (IE) */ uint8_t DE : 1; /* Bit 1. Denormalized Operand (DE) */ uint8_t ZE : 1; /* Bit 2. Zero Divide (ZE) */ uint8_t OE : 1; /* Bit 3. Overflow (OE) */ uint8_t UE : 1; /* Bit 4. Underflow (UE) */ uint8_t PE : 1; /* Bit 5. Precision (PE) */ uint8_t SF : 1; /* Bit 6. Stack Fault (SF) */ uint8_t ES : 1; /* Bit 7. Exception Summary Status (ES) */ uint8_t C0 : 1; /* Bit 8. Condition code 0 (C0) */ uint8_t C1 : 1; /* Bit 9. Condition code 1 (C1) */ uint8_t C2 : 1; /* Bit 10. Condition code 2 (C2) */ uint8_t TOP : 3; /* Bit 11-13. Top of Stack Pointer (TOP) */ uint8_t C3 : 1; /* Bit 14. Condition code 3 (C3) */ uint8_t B : 1; /* Bit 15. FPU Busy (B) */ } fpu_fields; uint8_t l8; uint32_t eflags; uint16_t fpu_flags; } nmd_x86_cpu_flags; enum NMD_X86_EFLAGS { NMD_X86_EFLAGS_ID = (1 << 21), NMD_X86_EFLAGS_VIP = (1 << 20), NMD_X86_EFLAGS_VIF = (1 << 19), NMD_X86_EFLAGS_AC = (1 << 18), NMD_X86_EFLAGS_VM = (1 << 17), NMD_X86_EFLAGS_RF = (1 << 16), NMD_X86_EFLAGS_NT = (1 << 14), NMD_X86_EFLAGS_IOPL = (1 << 12) /*| (1 << 13)*/, NMD_X86_EFLAGS_OF = (1 << 11), NMD_X86_EFLAGS_DF = (1 << 10), NMD_X86_EFLAGS_IF = (1 << 9), NMD_X86_EFLAGS_TF = (1 << 8), NMD_X86_EFLAGS_SF = (1 << 7), NMD_X86_EFLAGS_ZF = (1 << 6), NMD_X86_EFLAGS_AF = (1 << 4), NMD_X86_EFLAGS_PF = (1 << 2), NMD_X86_EFLAGS_CF = (1 << 0) }; enum NMD_X86_FPU_FLAGS { NMD_X86_FPU_FLAGS_C0 = (1 << 8), NMD_X86_FPU_FLAGS_C1 = (1 << 9), NMD_X86_FPU_FLAGS_C2 = (1 << 10), NMD_X86_FPU_FLAGS_C3 = (1 << 14) }; typedef struct nmd_x86_instruction { bool valid : 1; /* If true, the instruction is valid. */ bool has_modrm : 1; /* If true, the instruction has a ModR/M byte. */ bool has_sib : 1; /* If true, the instruction has an SIB byte. */ bool has_rex : 1; /* If true, the instruction has a REX prefix */ bool rex_w_prefix : 1; /* If true, a REX.W prefix is closer to the opcode than a operand size override prefix. */ bool repeat_prefix : 1; /* If true, a 'repeat'(F3h) prefix is closer to the opcode than a 'repeat not zero'(F2h) prefix. */ uint8_t mode; /* The decoding mode. A member of 'NMD_X86_MODE'. */ uint8_t length; /* The instruction's length in bytes. */ uint8_t opcode; /* Opcode byte. */ uint8_t opcode_size; /* The opcode's size in bytes. */ uint16_t id; /* The instruction's identifier. A member of 'NMD_X86_INSTRUCTION'. */ uint16_t prefixes; /* A mask of prefixes. See 'NMD_X86_PREFIXES'. */ uint8_t num_prefixes; /* Number of prefixes. */ uint8_t num_operands; /* The number of operands. */ uint8_t group; /* The instruction's group(e.g. jmp, prvileged...). A member of 'NMD_GROUP'. */ uint8_t buffer[NMD_X86_MAXIMUM_INSTRUCTION_LENGTH]; /* A buffer containing the full instruction. */ nmd_x86_operand operands[NMD_X86_MAXIMUM_NUM_OPERANDS]; /* Operands. */ nmd_x86_modrm modrm; /* The Mod/RM byte. Check 'flags.fields.has_modrm'. */ nmd_x86_sib sib; /* The SIB byte. Check 'flags.fields.has_sib'. */ uint8_t imm_mask; /* A mask of one or more members of 'NMD_X86_IMM'. */ uint8_t disp_mask; /* A mask of one or more members of 'NMD_X86_DISP'. */ uint64_t immediate; /* Immediate. Check 'imm_mask'. */ uint32_t displacement; /* Displacement. Check 'disp_mask'. */ uint8_t opcode_map; /* The instruction's opcode map. A member of 'NMD_X86_OPCODE_MAP'. */ uint8_t encoding; /* The instruction's encoding. A member of 'NMD_X86_INSTRUCTION_ENCODING'. */ nmd_x86_vex vex; /* VEX prefix. */ nmd_x86_cpu_flags modified_flags; /* Cpu flags modified by the instruction. */ nmd_x86_cpu_flags tested_flags; /* Cpu flags tested by the instruction. */ nmd_x86_cpu_flags set_flags; /* Cpu flags set by the instruction. */ nmd_x86_cpu_flags cleared_flags; /* Cpu flags cleared by the instruction. */ nmd_x86_cpu_flags undefined_flags; /* Cpu flags whose state is undefined. */ uint8_t rex; /* REX prefix. */ uint8_t segment_override; /* The segment override prefix closest to the opcode. A member of 'NMD_X86_PREFIXES'. */ uint16_t simd_prefix; /* One of these prefixes that is the closest to the opcode: NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE, NMD_X86_PREFIXES_LOCK, NMD_X86_PREFIXES_REPEAT_NOT_ZERO, NMD_X86_PREFIXES_REPEAT, or NMD_X86_PREFIXES_NONE. The prefixes are specified as members of the 'NMD_X86_PREFIXES' enum. */ } nmd_x86_instruction; typedef union nmd_x86_register { int8_t h8; int8_t l8; int16_t l16; int32_t l32; int64_t l64; } nmd_x86_register; typedef union nmd_x86_register_512 { uint64_t xmm0[2]; uint64_t ymm0[4]; uint64_t zmm0[8]; } nmd_x86_register_512; /* Assembles one or more instructions from a string. Returns the number of bytes written to the buffer on success, zero otherwise. Instructions can be separated using the '\n'(new line) character. Parameters: - string [in] A pointer to a string that represents one or more instructions in assembly language. - buffer [out] A pointer to a buffer that receives the encoded instructions. - buffer_size [in] The size of the buffer in bytes. - runtime_address [in] The instruction's runtime address. You may use 'NMD_X86_INVALID_RUNTIME_ADDRESS'. - mode [in] The architecture mode. 'NMD_X86_MODE_32', 'NMD_X86_MODE_64' or 'NMD_X86_MODE_16'. - count [in/out/opt] A pointer to a variable that on input is the maximum number of instructions that can be parsed, and on output the number of instructions parsed. This parameter may be null. */ NMD_ASSEMBLY_API size_t nmd_x86_assemble(const char* string, void* buffer, size_t buffer_size, uint64_t runtime_address, NMD_X86_MODE mode, size_t* count); /* Decodes an instruction. Returns true if the instruction is valid, false otherwise. Parameters: - buffer [in] A pointer to a buffer containing a encoded instruction. - buffer_size [in] The buffer's size in bytes. - instruction [out] A pointer to a variable of type 'nmd_x86_instruction' that receives information about the instruction. - mode [in] The architecture mode. 'NMD_X86_MODE_32', 'NMD_X86_MODE_64' or 'NMD_X86_MODE_16'. - flags [in] A mask of 'NMD_X86_DECODER_FLAGS_XXX' that specifies which features the decoder is allowed to use. If uncertain, use 'NMD_X86_DECODER_FLAGS_MINIMAL'. */ NMD_ASSEMBLY_API bool nmd_x86_decode(const void* buffer, size_t buffer_size, nmd_x86_instruction* instruction, NMD_X86_MODE mode, uint32_t flags); /* Formats an instruction. This function may cause a crash if you modify 'instruction' manually. Parameters: - instruction [in] A pointer to a variable of type 'nmd_x86_instruction' describing the instruction to be formatted. - buffer [out] A pointer to buffer that receives the string. The buffer's recommended size is 128 bytes. - runtime_address [in] The instruction's runtime address. You may use 'NMD_X86_INVALID_RUNTIME_ADDRESS'. - flags [in] A mask of 'NMD_X86_FORMAT_FLAGS_XXX' that specifies how the function should format the instruction. If uncertain, use 'NMD_X86_FORMAT_FLAGS_DEFAULT'. */ NMD_ASSEMBLY_API void nmd_x86_format(const nmd_x86_instruction* instruction, char* buffer, uint64_t runtime_address, uint32_t flags); /* Returns the instruction's length if it's valid, zero otherwise. Parameters: - buffer [in] A pointer to a buffer containing a encoded instruction. - buffer_size [in] The buffer's size in bytes. - mode [in] The architecture mode. 'NMD_X86_MODE_32', 'NMD_X86_MODE_64' or 'NMD_X86_MODE_16'. */ NMD_ASSEMBLY_API size_t nmd_x86_ldisasm(const void* buffer, size_t buffer_size, NMD_X86_MODE mode); #endif /* NMD_ASSEMBLY_H */ #ifdef NMD_ASSEMBLY_IMPLEMENTATION /* Four high-order bits of an opcode to index a row of the opcode table */ #define _NMD_R(b) ((b) >> 4) /* Four low-order bits to index a column of the table */ #define _NMD_C(b) ((b) & 0xF) #define _NMD_NUM_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0])) #ifndef _NMD_IS_UPPERCASE #define _NMD_IS_UPPERCASE(c) ((c) >= 'A' && (c) <= 'Z') #define _NMD_IS_LOWERCASE(c) ((c) >= 'a' && (c) <= 'z') #define _NMD_TOLOWER(c) (_NMD_IS_UPPERCASE(c) ? (c) + 0x20 : (c)) #define _NMD_IS_DECIMAL_NUMBER(c) ((c) >= '0' && (c) <= '9') #define _NMD_MIN(a, b) ((a)<(b)?(a):(b)) #define _NMD_MAX(a, b) ((a)>(b)?(a):(b)) #endif /* _NMD_IS_UPPERCASE */ #define _NMD_SET_REG_OPERAND(operand, _is_implicit, _action, _reg) {operand.type = NMD_X86_OPERAND_TYPE_REGISTER; operand.is_implicit = _is_implicit; operand.action = _action; operand.fields.reg = _reg;} #define _NMD_SET_IMM_OPERAND(operand, _is_implicit, _action, _imm) {operand.type = NMD_X86_OPERAND_TYPE_IMMEDIATE; operand.is_implicit = _is_implicit; operand.action = _action; operand.fields.imm = _imm;} #define _NMD_SET_MEM_OPERAND(operand, _is_implicit, _action, _segment, _base, _index, _scale, _disp) {operand.type = NMD_X86_OPERAND_TYPE_MEMORY; operand.is_implicit = _is_implicit; operand.action = _action; operand.fields.mem.segment = _segment; operand.fields.mem.base = _base; operand.fields.mem.index = _index; operand.fields.mem.scale = _scale; operand.fields.mem.disp = _disp;} #define _NMD_GET_GPR(reg) (reg + (instruction->mode>>2)*8) /* reg(16),reg(32),reg(64). e.g. ax,eax,rax */ #define _NMD_GET_IP() (NMD_X86_REG_IP + (instruction->mode>>2)) /* ip,eip,rip */ #define _NMD_GET_BY_MODE_OPSZPRFX(mode, opszprfx, _16, _32) ((mode) == NMD_X86_MODE_16 ? ((opszprfx) ? (_32) : (_16)) : ((opszprfx) ? (_16) : (_32))) /* Get something based on mode and operand size prefix. Used for instructions where the the 64-bit mode variant does not exist or is the same as the one for 32-bit mode */ #define _NMD_GET_BY_MODE_OPSZPRFX_W64(mode, opszprfx, rex_w_prefix, _16, _32, _64) ((mode) == NMD_X86_MODE_16 ? ((opszprfx) ? (_32) : (_16)) : ((opszprfx) ? (_16) : ((rex_w_prefix) ? (_64) : (_32)))) /* Get something based on mode and operand size prefix. The 64-bit version is accessed with the REX.W prefix */ #define _NMD_GET_BY_MODE_OPSZPRFX_D64(mode, opszprfx, _16, _32, _64) ((mode) == NMD_X86_MODE_16 ? ((opszprfx) ? (_32) : (_16)) : ((opszprfx) ? (_16) : ((mode) == NMD_X86_MODE_64 ? (_64) : (_32)))) /* Get something based on mode and operand size prefix. The 64-bit version is accessed by default when mode is NMD_X86_MODE_64 and there's no operand size override prefix. */ #define _NMD_GET_BY_MODE_OPSZPRFX_F64(mode, opszprfx, _16, _32, _64) ((mode) == NMD_X86_MODE_64 ? (_64) : ((mode) == NMD_X86_MODE_16 ? ((opszprfx) ? (_32) : (_16)) : ((opszprfx) ? (_16) : (_32)))) /* Get something based on mode and operand size prefix. The 64-bit version is accessed when mode is NMD_X86_MODE_64 independent of an operand size override prefix. */ /* Make sure we can read a byte, read a byte, increment the buffer and decrement the buffer's size */ #define _NMD_READ_BYTE(buffer_, buffer_size_, var_) { if ((buffer_size_) < sizeof(uint8_t)) { return false; } var_ = *((uint8_t*)(buffer_)); buffer_ = ((uint8_t*)(buffer_)) + sizeof(uint8_t); (buffer_size_) -= sizeof(uint8_t); } NMD_ASSEMBLY_API const char* const _nmd_reg8[] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" }; NMD_ASSEMBLY_API const char* const _nmd_reg8_x64[] = { "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil" }; NMD_ASSEMBLY_API const char* const _nmd_reg16[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" }; NMD_ASSEMBLY_API const char* const _nmd_reg32[] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" }; NMD_ASSEMBLY_API const char* const _nmd_reg64[] = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi" }; NMD_ASSEMBLY_API const char* const _nmd_regrxb[] = { "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" }; NMD_ASSEMBLY_API const char* const _nmd_regrxw[] = { "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" }; NMD_ASSEMBLY_API const char* const _nmd_regrxd[] = { "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" }; NMD_ASSEMBLY_API const char* const _nmd_regrx[] = { "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" }; NMD_ASSEMBLY_API const char* const _nmd_segment_reg[] = { "es", "cs", "ss", "ds", "fs", "gs" }; NMD_ASSEMBLY_API const char* const _nmd_condition_suffixes[] = { "o", "no", "b", "nb", "z", "nz", "be", "a", "s", "ns", "p", "np", "l", "ge", "le", "g" }; NMD_ASSEMBLY_API const char* const _nmd_op1_opcode_map_mnemonics[] = { "add", "adc", "and", "xor", "or", "sbb", "sub", "cmp" }; NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp1[] = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" }; NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp2[] = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" }; NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp3[] = { "test", "test", "not", "neg", "mul", "imul", "div", "idiv" }; NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp5[] = { "inc", "dec", "call", "call far", "jmp", "jmp far", "push" }; NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp6[] = { "sldt", "str", "lldt", "ltr", "verr", "verw" }; NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp7[] = { "sgdt", "sidt", "lgdt", "lidt", "smsw", 0, "lmsw", "invlpg" }; NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp7_reg0[] = { "enclv", "vmcall", "vmlaunch", "vmresume", "vmxoff", "pconfig" }; NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp7_reg1[] = { "monitor", "mwait", "clac", "stac", 0, 0, 0, "encls" }; NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp7_reg2[] = { "xgetbv", "xsetbv", 0, 0, "vmfunc", "xend", "xtest", "enclu" }; NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp7_reg3[] = { "vmrun ", "vmmcall", "vmload ", "vmsave", "stgi", "clgi", "skinit eax", "invlpga " }; NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp7_reg7[] = { "swapgs", "rdtscp", "monitorx", "mwaitx", "clzero ", "rdpru" }; NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesD8[] = { "add", "mul", "com", "comp", "sub", "subr", "div", "divr" }; NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesD9[] = { "ld", 0, "st", "stp", "ldenv", "ldcw", "nstenv", "nstcw" }; NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesDA_DE[] = { "iadd", "imul", "icom", "icomp", "isub", "isubr", "idiv", "idivr" }; NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesDB[] = { "ild", "isttp", "ist", "istp", 0, "ld", 0, "stp" }; NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesDC[] = { "add", "mul", "com", "comp", "sub", "subr", "div", "divr" }; NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesDD[] = { "ld", "isttp", "st", "stp", "rstor", 0, "nsave", "nstsw" }; NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesDF[] = { "ild", "isttp", "ist", "istp", "bld", "ild", "bstp", "istp" }; NMD_ASSEMBLY_API const char* const* _nmd_escape_opcodes[] = { _nmd_escape_opcodesD8, _nmd_escape_opcodesD9, _nmd_escape_opcodesDA_DE, _nmd_escape_opcodesDB, _nmd_escape_opcodesDC, _nmd_escape_opcodesDD, _nmd_escape_opcodesDA_DE, _nmd_escape_opcodesDF }; NMD_ASSEMBLY_API const uint8_t _nmd_op1_modrm[] = { 0xFF, 0x63, 0x69, 0x6B, 0xC0, 0xC1, 0xC6, 0xC7, 0xD0, 0xD1, 0xD2, 0xD3, 0xF6, 0xF7, 0xFE }; NMD_ASSEMBLY_API const uint8_t _nmd_op1_imm8[] = { 0x6A, 0x6B, 0x80, 0x82, 0x83, 0xA8, 0xC0, 0xC1, 0xC6, 0xCD, 0xD4, 0xD5, 0xEB }; NMD_ASSEMBLY_API const uint8_t _nmd_op1_imm32[] = { 0xE8, 0xE9, 0x68, 0x81, 0x69, 0xA9, 0xC7 }; NMD_ASSEMBLY_API const uint8_t _nmd_invalid_op2[] = { 0x04, 0x0a, 0x0c, 0x7a, 0x7b, 0x36, 0x39 }; NMD_ASSEMBLY_API const uint8_t _nmd_two_opcodes[] = { 0xb0, 0xb1, 0xb3, 0xbb, 0xc0, 0xc1 }; NMD_ASSEMBLY_API const uint8_t _nmd_valid_3DNow_opcodes[] = { 0x0c, 0x0d, 0x1c, 0x1d, 0x8a, 0x8e, 0x90, 0x94, 0x96, 0x97, 0x9a, 0x9e, 0xa0, 0xa4, 0xa6, 0xa7, 0xaa, 0xae, 0xb0, 0xb4, 0xb6, 0xb7, 0xbb, 0xbf }; NMD_ASSEMBLY_API bool _nmd_find_byte(const uint8_t* arr, const size_t N, const uint8_t x) { size_t i = 0; for (; i < N; i++) { if (arr[i] == x) return true; }; return false; } /* Returns a pointer to the first occurrence of 'c' in 's', or a null pointer if 'c' is not present. */ NMD_ASSEMBLY_API const char* _nmd_strchr(const char* s, char c) { for (; *s; s++) { if (*s == c) return s; } return 0; } /* Returns a pointer to the last occurrence of 'c' in 's', or a null pointer if 'c' is not present. */ NMD_ASSEMBLY_API const char* _nmd_reverse_strchr(const char* s, char c) { const char* end = s; while (*end) end++; for (; end > s; end--) { if (*end == c) return end; } return 0; } /* Returns a pointer to the first occurrence of 's2' in 's', or a null pointer if 's2' is not present. */ NMD_ASSEMBLY_API const char* _nmd_strstr(const char* s, const char* s2) { size_t i = 0; for (; *s; s++) { if (s2[i] == '\0') return s - i; if (*s != s2[i]) i = 0; if (*s == s2[i]) i++; } return 0; } /* Returns a pointer to the first occurrence of 's2' in 's', or a null pointer if 's2' is not present. If 's3_opt' is not null it receives the address of the next byte in 's'. */ NMD_ASSEMBLY_API const char* _nmd_strstr_ex(const char* s, const char* s2, const char** s3_opt) { size_t i = 0; for (; *s; s++) { if (s2[i] == '\0') { if (s3_opt) *s3_opt = s; return s - i; } if (*s != s2[i]) i = 0; if (*s == s2[i]) i++; } if (s2[i] == '\0') { if (s3_opt) *s3_opt = s; return s - i; } return 0; } /* Inserts 'c' at 's'. */ NMD_ASSEMBLY_API void _nmd_insert_char(const char* s, char c) { char* end = (char*)s; while (*end) end++; *(end + 1) = '\0'; for (; end > s; end--) *end = *(end - 1); *end = c; } /* Returns true if there is only a number between 's1' and 's2', false otherwise. */ NMD_ASSEMBLY_API bool _nmd_is_number(const char* s1, const char* s2) { const char* s = s1; for (; s < s2; s++) { if (!(*s >= '0' && *s <= '9') && !(*s >= 'a' && *s <= 'f') && !(*s >= 'A' && *s <= 'F')) { if ((s == s1 + 1 && *s1 == '0' && (*s == 'x' || *s == 'X')) || (s == s2 - 1 && (*s == 'h' || *s == 'H'))) continue; return false; } } return true; } /* Returns a pointer to the first occurrence of a number between 's1' and 's2', zero otherwise. */ NMD_ASSEMBLY_API const char* _nmd_find_number(const char* s1, const char* s2) { const char* s = s1; for (; s < s2; s++) { if ((*s >= '0' && *s <= '9') || (*s >= 'a' && *s <= 'f') || (*s >= 'A' && *s <= 'F')) return s; } return 0; } /* Returns true if s1 matches s2 exactly. */ NMD_ASSEMBLY_API bool _nmd_strcmp(const char* s1, const char* s2) { for (; *s1 && *s2; s1++, s2++) { if (*s1 != *s2) return false; } return !*s1 && !*s2; } NMD_ASSEMBLY_API size_t _nmd_get_bit_index(uint32_t mask) { size_t i = 0; while (!(mask & (1 << i))) i++; return i; } NMD_ASSEMBLY_API size_t _nmd_assembly_get_num_digits_hex(uint64_t n) { if (n == 0) return 1; size_t num_digits = 0; for (; n > 0; n /= 16) num_digits++; return num_digits; } NMD_ASSEMBLY_API size_t _nmd_assembly_get_num_digits(uint64_t n) { if (n == 0) return 1; size_t num_digits = 0; for (; n > 0; n /= 10) num_digits++; return num_digits; } typedef struct _nmd_assemble_info { char* s; /* string */ uint8_t* b; /* buffer */ NMD_X86_MODE mode; uint64_t runtime_address; } _nmd_assemble_info; enum _NMD_NUMBER_BASE { _NMD_NUMBER_BASE_NONE = 0, _NMD_NUMBER_BASE_DECIMAL = 10, _NMD_NUMBER_BASE_HEXADECIMAL = 16, _NMD_NUMBER_BASE_BINARY = 2 }; NMD_ASSEMBLY_API size_t _nmd_assemble_reg(_nmd_assemble_info* ai, uint8_t base_byte) { uint8_t i = 0; if (ai->mode == NMD_X86_MODE_64) { for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_reg64); i++) { if (_nmd_strcmp(ai->s, _nmd_reg64[i])) { ai->b[0] = base_byte + i; return 1; } } for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_regrx); i++) { if (_nmd_strcmp(ai->s, _nmd_regrx[i])) { ai->b[0] = 0x41; ai->b[1] = base_byte + i; return 2; } } } else if (ai->mode == NMD_X86_MODE_32) { for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_reg32); i++) { if (_nmd_strcmp(ai->s, _nmd_reg32[i])) { ai->b[0] = base_byte + i; return 1; } } } for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_reg16); i++) { if (_nmd_strcmp(ai->s, _nmd_reg16[i])) { ai->b[0] = 0x66; ai->b[1] = base_byte + i; return 2; } } return 0; } NMD_ASSEMBLY_API uint8_t _nmd_encode_segment_reg(NMD_X86_REG segment_reg) { switch (segment_reg) { case NMD_X86_REG_ES: return 0x26; case NMD_X86_REG_CS: return 0x2e; case NMD_X86_REG_SS: return 0x36; case NMD_X86_REG_DS: return 0x3e; case NMD_X86_REG_FS: return 0x64; case NMD_X86_REG_GS: return 0x65; default: return 0; } } NMD_ASSEMBLY_API size_t _nmd_parse_number(const char* string, int64_t* p_num) { if (*string == '\0') return 0; /* Assume decimal base. */ uint8_t base = _NMD_NUMBER_BASE_DECIMAL; size_t i; const char* s = string; bool is_negative = false; bool force_positive = false; bool h_suffix = false; bool assume_hex = false; if (s[0] == '-') { is_negative = true; s++; } else if (s[0] == '+') { force_positive = true; s++; } if (s[0] == '0') { if (s[1] == 'x') { s += 2; base = _NMD_NUMBER_BASE_HEXADECIMAL; } else if (s[1] == 'b') { s += 2; base = _NMD_NUMBER_BASE_BINARY; } } for (i = 0; s[i]; i++) { const char c = s[i]; if (base == _NMD_NUMBER_BASE_DECIMAL) { if ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { base = _NMD_NUMBER_BASE_HEXADECIMAL; assume_hex = true; continue; } else if (!(c >= '0' && c <= '9')) break; } else if (base == _NMD_NUMBER_BASE_HEXADECIMAL) { if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) break; } else if (c != '0' && c != '1') /* _NMD_NUMBER_BASE_BINARY */ break; } if (s[i] == 'h') { base = _NMD_NUMBER_BASE_HEXADECIMAL; h_suffix = true; } const size_t num_digits = i; if (num_digits == 0) return 0; int64_t num = 0; for (i = 0; i < num_digits; i++) { const char c = s[i]; int n = c % 16; if (c >= 'A') n += 9; num += n; if (i < num_digits - 1) { /* Return false if number is greater than 2^64-1 */ if ( num_digits > 16 && i >= 15) { if ((base == _NMD_NUMBER_BASE_DECIMAL && (uint64_t)num >= (uint64_t)1844674407370955162) || /* ceiling((2^64-1) / 10) */ (base == _NMD_NUMBER_BASE_HEXADECIMAL && (uint64_t)num >= (uint64_t)1152921504606846976) || /* *ceiling((2^64-1) / 16) */ (base == _NMD_NUMBER_BASE_BINARY && (uint64_t)num >= (uint64_t)9223372036854775808U)) /* ceiling((2^64-1) / 2) */ { return 0; } } num *= base; } } if (is_negative) num *= -1; *p_num = num; size_t offset = 0; if (is_negative || force_positive) offset += 1; if (h_suffix) offset += 1; else if ((base == _NMD_NUMBER_BASE_HEXADECIMAL && !assume_hex) || base == _NMD_NUMBER_BASE_BINARY) /* 0x / 0b*/ offset += 2; return offset + num_digits; } NMD_ASSEMBLY_API size_t _nmd_append_prefix_by_reg_size(uint8_t* b, const char* s, size_t* num_prefixes, size_t* index) { size_t i; for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_reg32); i++) { if (_nmd_strcmp(s, _nmd_reg32[i])) { *num_prefixes = 0; *index = i; return 4; } } for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_reg8); i++) { if (_nmd_strcmp(s, _nmd_reg8[i])) { *num_prefixes = 0; *index = i; return 1; } } for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_reg16); i++) { if (_nmd_strcmp(s, _nmd_reg16[i])) { b[0] = 0x66; *num_prefixes = 1; *index = i; return 2; } } for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_reg64); i++) { if (_nmd_strcmp(s, _nmd_reg64[i])) { b[0] = 0x48; *num_prefixes = 1; *index = i; return 8; } } for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_regrx); i++) { if (_nmd_strcmp(s, _nmd_regrx[i])) { b[0] = 0x49; *num_prefixes = 1; *index = i; return 8; } } for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_regrxd); i++) { if (_nmd_strcmp(s, _nmd_regrxd[i])) { b[0] = 0x41; *num_prefixes = 1; *index = i; return 4; } } for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_regrxw); i++) { if (_nmd_strcmp(s, _nmd_regrxw[i])) { b[0] = 0x66; b[1] = 0x41; *num_prefixes = 2; *index = i; return 2; } } for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_regrxb); i++) { if (_nmd_strcmp(s, _nmd_regrxb[i])) { b[0] = 0x41; *num_prefixes = 1; *index = i; return 1; } } return 0; } NMD_ASSEMBLY_API NMD_X86_REG _nmd_parse_reg8(const char** string) { const char* s = *string; size_t i; for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_reg8); i++) { if (_nmd_strstr_ex(s, _nmd_reg8[i], string) == s) return (NMD_X86_REG)(NMD_X86_REG_AL + i); } return NMD_X86_REG_NONE; } NMD_ASSEMBLY_API NMD_X86_REG _nmd_parse_reg16(const char** string) { const char* s = *string; size_t i; for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_reg16); i++) { if (_nmd_strstr_ex(s, _nmd_reg16[i], string) == s) return (NMD_X86_REG)(NMD_X86_REG_AX + i); } return NMD_X86_REG_NONE; } NMD_ASSEMBLY_API NMD_X86_REG _nmd_parse_reg32(const char** string) { const char* s = *string; size_t i; for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_reg32); i++) { if (_nmd_strstr_ex(s, _nmd_reg32[i], string) == s) return (NMD_X86_REG)(NMD_X86_REG_EAX + i); } return NMD_X86_REG_NONE; } NMD_ASSEMBLY_API NMD_X86_REG _nmd_parse_reg64(const char** string) { const char* s = *string; size_t i; for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_reg64); i++) { if (_nmd_strstr_ex(s, _nmd_reg64[i], string) == s) return (NMD_X86_REG)(NMD_X86_REG_RAX + i); } return NMD_X86_REG_NONE; } NMD_ASSEMBLY_API NMD_X86_REG _nmd_parse_regrxb(const char** string) { const char* s = *string; size_t i; for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_regrxb); i++) { if (_nmd_strstr_ex(s, _nmd_regrxb[i], string) == s) return (NMD_X86_REG)(NMD_X86_REG_R8B + i); } return NMD_X86_REG_NONE; } NMD_ASSEMBLY_API NMD_X86_REG _nmd_parse_regrxw(const char** string) { const char* s = *string; size_t i; for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_regrxw); i++) { if (_nmd_strstr_ex(s, _nmd_regrxw[i], string) == s) return (NMD_X86_REG)(NMD_X86_REG_R8W + i); } return NMD_X86_REG_NONE; } NMD_ASSEMBLY_API NMD_X86_REG _nmd_parse_regrxd(const char** string) { const char* s = *string; size_t i; for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_regrxd); i++) { if (_nmd_strstr_ex(s, _nmd_regrxd[i], string) == s) return (NMD_X86_REG)(NMD_X86_REG_R8D + i); } return NMD_X86_REG_NONE; } NMD_ASSEMBLY_API NMD_X86_REG _nmd_parse_regrx(const char** string) { const char* s = *string; size_t i; for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_regrx); i++) { if (_nmd_strstr_ex(s, _nmd_regrx[i], string) == s) return (NMD_X86_REG)(NMD_X86_REG_R8 + i); } return NMD_X86_REG_NONE; } /* Parses a register */ NMD_ASSEMBLY_API NMD_X86_REG _nmd_parse_reg(const char** string) { NMD_X86_REG reg; if(!(reg = _nmd_parse_reg8(string)) && !(reg = _nmd_parse_reg16(string)) && !(reg = _nmd_parse_reg32(string)) && !(reg = _nmd_parse_reg64(string)) && !(reg = _nmd_parse_regrxb(string)) && !(reg = _nmd_parse_regrxw(string)) && !(reg = _nmd_parse_regrxd(string)) && !(reg = _nmd_parse_regrx(string))) { } return reg; } /* Parses a memory operand in the format: '[exp]' string: a pointer to the string that represents the memory operand. The string is modified to point to the character after the memory operand. operand[out]: Describes the memory operand. size[out]: The size of the pointer. byte ptr:1, dword ptr:4, etc.. or zero if unknown. Return value: True if success, false otherwise. */ NMD_ASSEMBLY_API bool _nmd_parse_memory_operand(const char** string, nmd_x86_memory_operand* operand, size_t* size) { /* Check for pointer size */ const char* s = *string; size_t num_bytes; if (_nmd_strstr(s, "byte") == s) num_bytes = 1; else if (_nmd_strstr(s, "word") == s) num_bytes = 2; else if (_nmd_strstr(s, "dword") == s) num_bytes = 4; else if (_nmd_strstr(s, "qword") == s) num_bytes = 8; else num_bytes = 0; *size = num_bytes; /* Check for the "ptr" keyword. It should only be present if a pointer size was specified */ if (num_bytes > 0) { s += num_bytes >= 4 ? 5 : 4; /* " ptr" */ if (s[0] == ' ' && s[1] == 'p' && s[2] == 't' && s[3] == 'r') s += 4; if (s[0] == ' ') s++; else if (s[0] != '[') return false; } /* Check for a segment register */ size_t i = 0; operand->segment = NMD_X86_REG_NONE; for (; i < _NMD_NUM_ELEMENTS(_nmd_segment_reg); i++) { if (_nmd_strstr(s, _nmd_segment_reg[i]) == s) { if (s[2] != ':') return false; s += 3; operand->segment = (uint8_t)(NMD_X86_REG_ES + i); break; } } /* Check for the actual memory operand expression. If this check fails, this is not a memory operand */ if (s[0] == '[') s++; else return false; /* Parse the memory operand expression. Even though formally there's no support for subtraction, if the expression has such operation between two numeric operands, it'll be resolved to a single number(the same applies for the other operations). */ operand->base = 0; operand->index = 0; operand->scale = 0; operand->disp = 0; bool add = false; bool sub = false; bool multiply = false; bool is_register = false; while (true) { /* Check for the base/index register. The previous math operation must not be subtration nor multiplication because these are not valid for registers(only addition is). */ bool parsed_element = false; if (!sub && !multiply) { for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_reg32); i++) { const char* tmp; if (_nmd_strstr_ex(s, _nmd_reg32[i], &tmp) == s) { s = tmp; if (add) { operand->index = (uint8_t)(NMD_X86_REG_EAX + i); operand->scale = 1; add = false; } else operand->base = (uint8_t)(NMD_X86_REG_EAX + i); parsed_element = true; is_register = true; break; } } } int64_t num; size_t num_digits; if (!parsed_element && (num_digits = _nmd_parse_number(s, &num))) { s += num_digits; if (add) { operand->disp += num; add = false; } else if (sub) { operand->disp -= num; sub = false; } else if (multiply) { if (!is_register || (num != 1 && num != 2 && num != 4 && num != 8)) return false; operand->scale = (uint8_t)num; } else operand->disp = num; parsed_element = true; } if (!parsed_element) return false; if (s[0] == '+') add = true; else if (s[0] == '-') sub = true; else if (s[0] == '*') { /* There cannot be more than one '*' operator. */ if (multiply) return false; multiply = true; } else if (s[0] == ']') break; else return false; s++; } *string = s + 1; return true; } NMD_ASSEMBLY_API size_t _nmd_assemble_mem_reg(uint8_t* buffer, nmd_x86_memory_operand* mem, uint8_t opcode, uint8_t modrm_reg) { size_t offset = 0; /* Assemble segment register if required */ if (mem->segment && mem->segment != ((mem->base == NMD_X86_REG_ESP || mem->index == NMD_X86_REG_ESP) ? NMD_X86_REG_SS : NMD_X86_REG_DS)) buffer[offset++] = _nmd_encode_segment_reg((NMD_X86_REG)mem->segment); buffer[offset++] = opcode; nmd_x86_modrm modrm; modrm.fields.reg = modrm_reg; modrm.fields.mod = 0; if (mem->index != NMD_X86_REG_NONE && mem->base != NMD_X86_REG_NONE) { modrm.fields.rm = 0b100; nmd_x86_sib sib; sib.fields.scale = (uint8_t)_nmd_get_bit_index(mem->scale); sib.fields.base = mem->base - NMD_X86_REG_EAX; sib.fields.index = mem->index - NMD_X86_REG_EAX; const size_t next_offset = offset; if (mem->disp != 0) { if (mem->disp >= -128 && mem->disp <= 127) { modrm.fields.mod = 1; *(int8_t*)(buffer + offset + 2) = (int8_t)mem->disp; offset++; } else { modrm.fields.mod = 2; *(int32_t*)(buffer + offset + 2) = (int32_t)mem->disp; offset += 4; } } buffer[next_offset] = modrm.modrm; buffer[next_offset + 1] = sib.sib; offset += 2; return offset; } else if (mem->base != NMD_X86_REG_NONE) { modrm.fields.rm = mem->base - NMD_X86_REG_EAX; const size_t next_offset = offset; if (mem->disp != 0) { if (mem->disp >= -128 && mem->disp <= 127) { modrm.fields.mod = 1; *(int8_t*)(buffer + offset + 1) = (int8_t)mem->disp; offset++; } else { modrm.fields.mod = 2; *(int32_t*)(buffer + offset + 1) = (int32_t)mem->disp; offset += 4; } } buffer[next_offset] = modrm.modrm; offset++; } else { modrm.fields.rm = 0b101; buffer[offset++] = modrm.modrm; *(int32_t*)(buffer + offset) = (int32_t)mem->disp; offset += 4; } return offset; } NMD_ASSEMBLY_API size_t _nmd_assemble_single(_nmd_assemble_info* ai) { const char* s; int64_t num; size_t num_digits; NMD_X86_REG reg, reg2; size_t i = 0; /* Parse prefixes */ bool lock_prefix = false, repeat_prefix = false, repeat_zero_prefix = false, repeat_not_zero_prefix = false; if (_nmd_strstr(ai->s, "lock ") == ai->s) lock_prefix = true, ai->s += 5; else if (_nmd_strstr(ai->s, "rep ") == ai->s) repeat_prefix = true, ai->s += 4; else if (_nmd_strstr(ai->s, "repe ") == ai->s || _nmd_strstr(ai->s, "repz ") == ai->s) repeat_zero_prefix = true, ai->s += 5; else if (_nmd_strstr(ai->s, "repne ") == ai->s || _nmd_strstr(ai->s, "repnz ") == ai->s) repeat_not_zero_prefix = true, ai->s += 6; if (_nmd_strstr(ai->s, "xacquire ") == ai->s) { } else if (_nmd_strstr(ai->s, "xrelease ") == ai->s) { } /* Parse opcodes */ if (ai->mode == NMD_X86_MODE_64) /* Only x86-64. */ { if (_nmd_strstr(ai->s, "mov ")) { const char* s = ai->s + 4; if ((reg = _nmd_parse_regrxb((const char**)&s))) { ai->b[0] = 0x41; ai->b[1] = 0xb0 + (reg - NMD_X86_REG_R8B); if (*s++ != ',') return 0; if ((num_digits = _nmd_parse_number(s, &num))) { ai->b[2] = (uint8_t)num; return 3; } } } else if (_nmd_strstr(ai->s, "push ") == ai->s || _nmd_strstr(ai->s, "pop ") == ai->s) { const bool is_push = ai->s[1] == 'u'; s = ai->s + (is_push ? 5 : 4); if (((reg = _nmd_parse_reg64(&s))) && !*s) { ai->b[0] = (is_push ? 0x50 : 0x58) + reg % 8; return 1; } else if ((reg = _nmd_parse_regrxw(&s)) && !*s) { ai->b[0] = 0x66; ai->b[1] = 0x41; ai->b[2] = (is_push ? 0x50 : 0x58) + reg % 8; return 3; } else if (((reg = _nmd_parse_regrx(&s))) && !*s) { ai->b[0] = 0x41; ai->b[1] = (is_push ? 0x50 : 0x58) + reg % 8; return 2; } } else if (_nmd_strstr(ai->s, "mov ") == ai->s) { ai->s += 4; if ((reg = _nmd_parse_reg8((const char**)&ai->s))) { ai->b[0] = 0xb0 + reg % 8; if (*ai->s++ != ',') return 0; if ((num_digits = _nmd_parse_number(ai->s, &num))) { ai->b[1] = (uint8_t)num; return 2; } } } else if (_nmd_strcmp(ai->s, "xchg r8,rax") || _nmd_strcmp(ai->s, "xchg rax,r8")) { ai->b[0] = 0x49; ai->b[1] = 0x90; return 2; } else if (_nmd_strcmp(ai->s, "xchg r8d,eax") || _nmd_strcmp(ai->s, "xchg eax,r8d")) { ai->b[0] = 0x41; ai->b[1] = 0x90; return 2; } else if (_nmd_strcmp(ai->s, "pushfq")) { ai->b[0] = 0x9c; return 1; } else if (_nmd_strcmp(ai->s, "popfq")) { ai->b[0] = 0x9d; return 1; } else if (_nmd_strcmp(ai->s, "iretq")) { ai->b[0] = 0x48; ai->b[1] = 0xcf; return 2; } else if (_nmd_strcmp(ai->s, "cdqe")) { ai->b[0] = 0x48; ai->b[1] = 0x98; return 2; } else if (_nmd_strcmp(ai->s, "cqo")) { ai->b[0] = 0x48; ai->b[1] = 0x99; return 2; } } else /* x86-16 / x86-32 */ { if (_nmd_strstr(ai->s, "inc ") || _nmd_strstr(ai->s, "dec ")) { const bool is_inc = ai->s[0] == 'i'; s = ai->s + 4; int offset = 0; if (((reg = _nmd_parse_reg32(&s))) && !*s) { if (ai->mode == NMD_X86_MODE_16) ai->b[offset++] = 0x66; } else if (((reg = _nmd_parse_reg16(&s))) && !*s) { if (ai->mode == NMD_X86_MODE_32) ai->b[offset++] = 0x66; } else return 0; ai->b[offset++] = (is_inc ? 0x40 : 0x48) + reg % 8; return offset; } else if (_nmd_strstr(ai->s, "push ") == ai->s || _nmd_strstr(ai->s, "pop ") == ai->s) { const bool is_push = ai->s[1] == 'u'; s = ai->s + (is_push ? 5 : 4); if (((reg = _nmd_parse_reg32(&s))) && !*s) { if (ai->mode == NMD_X86_MODE_16) { ai->b[0] = 0x66; ai->b[1] = (is_push ? 0x50 : 0x58) + reg % 8; return 2; } else { ai->b[0] = (is_push ? 0x50 : 0x58) + reg % 8; return 1; } } } else if (_nmd_strcmp(ai->s, "pushad")) { if (ai->mode == NMD_X86_MODE_16) { ai->b[0] = 0x66; ai->b[1] = 0x60; return 2; } else { ai->b[0] = 0x60; return 1; } } else if (_nmd_strcmp(ai->s, "pusha")) { if (ai->mode == NMD_X86_MODE_16) { ai->b[0] = 0x60; return 1; } else { ai->b[0] = 0x66; ai->b[1] = 0x60; return 2; } } else if (_nmd_strcmp(ai->s, "popad")) { if (ai->mode == NMD_X86_MODE_16) { ai->b[0] = 0x66; ai->b[1] = 0x61; return 2; } else { ai->b[0] = 0x61; return 1; } } else if (_nmd_strcmp(ai->s, "popa")) { if (ai->mode == NMD_X86_MODE_16) { ai->b[0] = 0x61; return 1; } else { ai->b[0] = 0x66; ai->b[1] = 0x61; return 2; } } else if (_nmd_strcmp(ai->s, "pushfd")) { if (ai->mode == NMD_X86_MODE_16) { ai->b[0] = 0x66; ai->b[1] = 0x9c; return 2; } else { ai->b[0] = 0x9c; return 1; } } else if (_nmd_strcmp(ai->s, "popfd")) { if (ai->mode == NMD_X86_MODE_16) { ai->b[0] = 0x66; ai->b[1] = 0x9d; return 2; } else { ai->b[0] = 0x9d; return 1; } } } typedef struct _nmd_string_byte_pair { const char* s; uint8_t b; } _nmd_string_byte_pair; const _nmd_string_byte_pair single_byte_op1[] = { { "int3", 0xcc }, { "nop", 0x90 }, { "ret", 0xc3 }, { "retf", 0xcb }, { "ret far", 0xcb }, { "leave", 0xc9 }, { "int1", 0xf1 }, { "push es", 0x06 }, { "push ss", 0x16 }, { "push ds", 0x1e }, { "push cs", 0x0e }, { "pop es", 0x07 }, { "pop ss", 0x17 }, { "pop ds", 0x1f }, { "daa", 0x27 }, { "aaa", 0x37 }, { "das", 0x2f }, { "aas", 0x3f }, { "xlat", 0xd7 }, { "fwait", 0x9b }, { "hlt", 0xf4 }, { "cmc", 0xf5 }, { "clc", 0xf8 }, { "sahf", 0x9e }, { "lahf", 0x9f }, { "into", 0xce }, { "salc", 0xd6 }, { "slc", 0xf8 }, { "stc", 0xf9 }, { "cli", 0xfa }, { "sti", 0xfb }, { "cld", 0xfc }, { "std", 0xfd }, }; for (i = 0; i < _NMD_NUM_ELEMENTS(single_byte_op1); i++) { if (_nmd_strcmp(ai->s, single_byte_op1[i].s)) { ai->b[0] = single_byte_op1[i].b; return 1; } } const _nmd_string_byte_pair single_byte_op2[] = { { "syscall", 0x05 }, { "clts", 0x06 }, { "sysret", 0x07 }, { "invd", 0x08 }, { "wbinvd", 0x09 }, { "ud2", 0x0b }, { "femms", 0x0e }, { "wrmsr", 0x30 }, { "rdtsc", 0x31 }, { "rdmsr", 0x32 }, { "rdpmc", 0x33 }, { "sysenter", 0x34 }, { "sysexit", 0x35 }, { "getsec", 0x37 }, { "emms", 0x77 }, { "push fs", 0xa0 }, { "pop fs", 0xa1 }, { "cpuid", 0xa2 }, { "push gs", 0xa8 }, { "pop gs", 0xa9 }, { "rsm", 0xaa } }; for (i = 0; i < _NMD_NUM_ELEMENTS(single_byte_op2); i++) { if (_nmd_strcmp(ai->s, single_byte_op2[i].s)) { ai->b[0] = 0x0f; ai->b[1] = single_byte_op2[i].b; return 2; } } /* Parse 'add', 'adc', 'and', 'xor', 'or', 'sbb', 'sub' and 'cmp' . Opcodes in first "4 rows"/[80, 83] */ for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_op1_opcode_map_mnemonics); i++) { if (_nmd_strstr(ai->s, _nmd_op1_opcode_map_mnemonics[i]) == ai->s) { const uint8_t base_opcode = (i % 4) * 0x10 + (i >= 4 ? 8 : 0); ai->s += 4; nmd_x86_memory_operand memory_operand; size_t pointer_size; if (_nmd_parse_memory_operand((const char**)&ai->s, &memory_operand, &pointer_size)) /* Colum 00,01,08,09 */ { if (*ai->s++ != ',' || !(reg = _nmd_parse_reg((const char**)&ai->s))) return 0; return _nmd_assemble_mem_reg(ai->b, &memory_operand, base_opcode, reg % 8); /* size_t offset = 0; if (memory_operand.segment && memory_operand.segment != ((memory_operand.base == NMD_X86_REG_ESP || memory_operand.index == NMD_X86_REG_ESP) ? NMD_X86_REG_SS : NMD_X86_REG_DS)) ai->b[offset++] = _nmd_encode_segment_reg((NMD_X86_REG)memory_operand.segment); if (pointer_size == 1) { ai->b[offset++] = base_opcode + 0; if (*ai->s++ != ',') return 0; NMD_X86_REG reg = _nmd_parse_reg(&ai->s); nmd_x86_modrm modrm; modrm.fields.mod = 0; modrm.fields.reg = (reg - 1) % 8; modrm.fields.rm = (memory_operand.base - 1) % 8; ai->b[offset++] = modrm.modrm; return offset; } */ } else if (_nmd_strstr_ex(ai->s, "al,", &s) == ai->s && (num_digits = _nmd_parse_number(s, &num)) && *(s + num_digits) == '\0') /* column 04,0C */ { if (num < -0x80 || num > 0xff) return 0; ai->b[0] = base_opcode + 4; ai->b[1] = (int8_t)num; return 2; } else if ((_nmd_strstr_ex(ai->s, "eax,", &s) == ai->s || _nmd_strstr_ex(ai->s, "ax,", &s) == ai->s || _nmd_strstr_ex(ai->s, "rax,", &s) == ai->s) && _nmd_parse_number(s, &num)) /* column 05,0D */ { const bool is_eax = ai->s[0] == 'e'; const bool is_ax = ai->s[1] == 'x'; if (is_eax) { if (num < -(int64_t)0x80000000 || num > 0xffffffff) return 0; ai->b[0] = base_opcode + 5; *(int32_t*)(ai->b + 1) = (int32_t)num; return 5; } else if (!is_eax) { if (ai->mode != NMD_X86_MODE_64 && !is_ax) return 0; ai->b[0] = is_ax ? 0x66 : 0x48; ai->b[1] = base_opcode + 5; if (is_ax) { if (num < -0x8000 || num > 0xffff) return 0; *(int16_t*)(ai->b + 2) = (int16_t)num; return 4; } else { if (num < -(int64_t)0x80000000 || num > 0xffffffff) return 0; *(int32_t*)(ai->b + 2) = (int32_t)num; return 6; } } } else if ((reg = _nmd_parse_reg((const char**)&ai->s)) && *ai->s++ == ',') /* column 00-04,08-0B */ { if(_nmd_parse_memory_operand((const char**)&ai->s, &memory_operand, &pointer_size)) /* column 02,03,0A,0B */ { return 0; } else /* 00,01,08,09 */ { if(!(reg2 = _nmd_parse_reg((const char**)&ai->s))) return 0; ai->b[0] = base_opcode; /* mod = 0b11, reg = reg2, rm = reg */ ai->b[1] = 0b11000000 | ((reg2 % 8) << 3) | (reg % 8); return 2; } } return 0; } } if (_nmd_strstr(ai->s, "jmp ") == ai->s) { if (!(num_digits = _nmd_parse_number(ai->s + 4, &num)) && ai->s[4 + num_digits] == '\0') return 0; size_t offset = 0; if (ai->mode == NMD_X86_MODE_16) ai->b[offset++] = 0x66; ai->b[offset++] = 0xe9; const int64_t size = (int64_t)offset + 4; *(uint32_t*)(ai->b + offset) = (uint32_t)((ai->runtime_address == NMD_X86_INVALID_RUNTIME_ADDRESS) ? (num - size) : (ai->runtime_address + size + num)); return size; } else if (ai->s[0] == 'j') { char* s = ai->s; while (true) { if (*s == ' ') { *s = '\0'; break; } else if (*s == '\0') return 0; s++; } for (i = 0; i < _NMD_NUM_ELEMENTS(_nmd_condition_suffixes); i++) { if (_nmd_strcmp(ai->s + 1, _nmd_condition_suffixes[i])) { if (!(num_digits = _nmd_parse_number(s + 1, &num))) return 0; const int64_t delta = (ai->runtime_address == NMD_X86_INVALID_RUNTIME_ADDRESS ? num : num - ai->runtime_address); if (delta >= -(1 << 7) + 2 && delta <= (1 << 7) - 1 + 2) { ai->b[0] = 0x70 + (uint8_t)i; *(int8_t*)(ai->b + 1) = (int8_t)(delta - 2); return 2; } else if (delta >= -((int64_t)1 << 31) + 6 && delta <= ((int64_t)1 << 31) - 1 + 6) { size_t offset = 0; if (ai->mode == NMD_X86_MODE_16) ai->b[offset++] = 0x66; ai->b[offset++] = 0x0f; ai->b[offset++] = 0x80 + (uint8_t)i; *(int32_t*)(ai->b + offset) = (int32_t)(delta - (offset+4)); return offset + 4; } } } } else if (_nmd_strstr(ai->s, "inc ") == ai->s || _nmd_strstr(ai->s, "dec ") == ai->s) { const char* tmp = ai->s + 4; nmd_x86_memory_operand memory_operand; size_t size; if (_nmd_parse_memory_operand(&tmp, &memory_operand, &size)) { size_t offset = 0; if (memory_operand.segment && memory_operand.segment != ((memory_operand.base == NMD_X86_REG_ESP || memory_operand.index == NMD_X86_REG_ESP) ? NMD_X86_REG_SS : NMD_X86_REG_DS)) ai->b[offset++] = _nmd_encode_segment_reg((NMD_X86_REG)memory_operand.segment); ai->b[offset++] = size == 1 ? 0xfe : 0xff; nmd_x86_modrm modrm; modrm.fields.reg = ai->s[0] == 'i' ? 0 : 8; modrm.fields.mod = 0; if (memory_operand.index != NMD_X86_REG_NONE && memory_operand.base != NMD_X86_REG_NONE) { modrm.fields.rm = 0b100; nmd_x86_sib sib; sib.fields.scale = (uint8_t)_nmd_get_bit_index(memory_operand.scale); sib.fields.base = memory_operand.base - NMD_X86_REG_EAX; sib.fields.index = memory_operand.index - NMD_X86_REG_EAX; const size_t next_offset = offset; if (memory_operand.disp != 0) { if (memory_operand.disp >= -128 && memory_operand.disp <= 127) { modrm.fields.mod = 1; *(int8_t*)(ai->b + offset + 2) = (int8_t)memory_operand.disp; offset++; } else { modrm.fields.mod = 2; *(int32_t*)(ai->b + offset + 2) = (int32_t)memory_operand.disp; offset += 4; } } ai->b[next_offset] = modrm.modrm; ai->b[next_offset + 1] = sib.sib; offset += 2; return offset; } else if (memory_operand.base != NMD_X86_REG_NONE) { modrm.fields.rm = memory_operand.base - NMD_X86_REG_EAX; const size_t next_offset = offset; if (memory_operand.disp != 0) { if (memory_operand.disp >= -128 && memory_operand.disp <= 127) { modrm.fields.mod = 1; *(int8_t*)(ai->b + offset + 1) = (int8_t)memory_operand.disp; offset++; } else { modrm.fields.mod = 2; *(int32_t*)(ai->b + offset + 1) = (int32_t)memory_operand.disp; offset += 4; } } ai->b[next_offset] = modrm.modrm; offset++; } else { modrm.fields.rm = 0b101; ai->b[offset++] = modrm.modrm; *(int32_t*)(ai->b + offset) = (int32_t)memory_operand.disp; offset += 4; } return offset; } size_t num_prefixes, index; size = _nmd_append_prefix_by_reg_size(ai->b, ai->s + 4, &num_prefixes, &index); if (size > 0) { if (ai->mode == NMD_X86_MODE_64) { ai->b[num_prefixes + 0] = size == 1 ? 0xfe : 0xff; ai->b[num_prefixes + 1] = 0xc0 + (ai->s[0] == 'i' ? 0 : 8) + (uint8_t)index; return num_prefixes + 2; } else { if (size == 1) { ai->b[0] = 0xfe; ai->b[1] = 0xc0 + (ai->s[0] == 'i' ? 0 : 8) + (uint8_t)index; return 2; } else { ai->b[num_prefixes + 0] = (ai->s[0] == 'i' ? 0x40 : 0x48) + (uint8_t)index; return num_prefixes + 1; } } } } else if (_nmd_strstr(ai->s, "call ") == ai->s) { if ((num_digits = _nmd_parse_number(ai->s + 5, &num))) { ai->b[0] = 0xe8; if(ai->runtime_address == NMD_X86_INVALID_RUNTIME_ADDRESS) *(int32_t*)(ai->b + 1) = (int32_t)(num - 5); else *(int32_t*)(ai->b + 1) = (int32_t)(num - (ai->runtime_address + 5)); return 5; } } else if (_nmd_strstr(ai->s, "push ") == ai->s || _nmd_strstr(ai->s, "pop ") == ai->s) { const bool is_push = ai->s[1] == 'u'; ai->s += is_push ? 5 : 4; NMD_X86_REG reg; if ((reg = _nmd_parse_reg16((const char**)&ai->s))) { if (ai->mode == NMD_X86_MODE_16) { ai->b[0] = (is_push ? 0x50 : 0x58) + reg % 8; return 1; } else { ai->b[0] = 0x66; ai->b[1] = (is_push ? 0x50 : 0x58) + reg % 8; return 2; } } else if (is_push && (num_digits = _nmd_parse_number(ai->s, &num)) && ai->s[num_digits] == '\0') { if (num >= -(1 << 7) && num <= (1 << 7) - 1) { ai->b[0] = 0x6a; *(int8_t*)(ai->b + 1) = (int8_t)num; return 2; } else { size_t offset = 0; if (ai->mode == NMD_X86_MODE_16) ai->b[offset++] = 0x66; ai->b[offset++] = 0x68; *(int32_t*)(ai->b + offset) = (int32_t)num; return offset + 4; } } } else if (_nmd_strstr(ai->s, "mov ") == ai->s) { ai->s += 4; const NMD_X86_REG reg = _nmd_parse_reg8((const char**)&ai->s); if (reg) { ai->b[0] = 0xb0 + (reg - NMD_X86_REG_AL); if (*ai->s++ != ',') return 0; if ((num_digits = _nmd_parse_number(ai->s, &num))) { ai->b[1] = (uint8_t)num; return 2; } } } else if (_nmd_strstr(ai->s, "ret ") == ai->s || _nmd_strstr(ai->s, "retf ") == ai->s) { const bool is_far = ai->s[3] == 'f'; ai->s += is_far ? 5 : 4; if ((num_digits = _nmd_parse_number(ai->s, &num)) && ai->s[num_digits] == '\0') { ai->b[0] = is_far ? 0xca : 0xc2; *(uint16_t*)(ai->b + 1) = (uint16_t)num; return 3; } } else if (_nmd_strstr(ai->s, "emit ") == ai->s) { size_t offset = 5; while ((num_digits = _nmd_parse_number(ai->s + offset, &num))) { if (num < 0 || num > 0xff) return 0; ai->b[i++] = (uint8_t)num; offset += num_digits; if (ai->s[offset] == ' ') offset++; } return i; } else if (_nmd_strcmp(ai->s, "pushf")) { if (ai->mode == NMD_X86_MODE_16) { ai->b[0] = 0x9c; return 1; } else { ai->b[0] = 0x66; ai->b[1] = 0x9c; return 2; } } else if (_nmd_strcmp(ai->s, "popf")) { if (ai->mode == NMD_X86_MODE_16) { ai->b[0] = 0x9d; return 1; } else { ai->b[0] = 0x66; ai->b[1] = 0x9d; return 2; } } else if (_nmd_strcmp(ai->s, "pause")) { ai->b[0] = 0xf3; ai->b[1] = 0x90; return 2; } else if (_nmd_strcmp(ai->s, "iret")) { if (ai->mode == NMD_X86_MODE_16) { ai->b[0] = 0xcf; return 1; } else { ai->b[0] = 0x66; ai->b[1] = 0xcf; return 2; } } else if (_nmd_strcmp(ai->s, "iretd")) { if (ai->mode == NMD_X86_MODE_16) { ai->b[0] = 0x66; ai->b[1] = 0xcf; return 2; } else { ai->b[0] = 0xcf; return 1; } } else if (_nmd_strcmp(ai->s, "pushf")) { ai->b[0] = 0x66; ai->b[1] = 0x9c; return 2; } else if (_nmd_strcmp(ai->s, "popf")) { ai->b[0] = 0x66; ai->b[1] = 0x9d; return 2; } else if (_nmd_strcmp(ai->s, "cwde")) { int offset = 0; if (ai->mode == NMD_X86_MODE_16) ai->b[offset++] = 0x66; ai->b[offset++] = 0x98; return offset; } else if (_nmd_strstr(ai->s, "int ") == ai->s) { ai->s += 4; if ((num_digits = _nmd_parse_number(ai->s, &num)) && ai->s[num_digits] == '\0') { ai->b[0] = 0xcd; ai->b[1] = (uint8_t)num; return 2; } } else if (_nmd_strcmp(ai->s, "cbw")) { int offset = 0; if (ai->mode != NMD_X86_MODE_16) ai->b[offset++] = 0x66; ai->b[offset++] = 0x98; return offset; } else if (_nmd_strcmp(ai->s, "cdq")) { int offset = 0; if (ai->mode == NMD_X86_MODE_16) ai->b[offset++] = 0x66; ai->b[offset++] = 0x99; return offset; } else if (_nmd_strcmp(ai->s, "cwd")) { int offset = 0; if (ai->mode != NMD_X86_MODE_16) ai->b[offset++] = 0x66; ai->b[offset++] = 0x99; return offset; } return 0; } /* Assembles one or more instructions from a string. Returns the number of bytes written to the buffer on success, zero otherwise. Instructions can be separated using the '\n'(new line) character. Parameters: - string [in] A pointer to a string that represents one or more instructions in assembly language. - buffer [out] A pointer to a buffer that receives the encoded instructions. - buffer_size [in] The size of the buffer in bytes. - runtime_address [in] The instruction's runtime address. You may use 'NMD_X86_INVALID_RUNTIME_ADDRESS'. - mode [in] The architecture mode. 'NMD_X86_MODE_32', 'NMD_X86_MODE_64' or 'NMD_X86_MODE_16'. - count [in/out/opt] A pointer to a variable that on input is the maximum number of instructions that can be parsed, and on output the number of instructions parsed. This parameter may be null. */ NMD_ASSEMBLY_API size_t nmd_x86_assemble(const char* string, void* buffer, size_t buffer_size, uint64_t runtime_address, NMD_X86_MODE mode, size_t* count) { if (!*string) return 0; const uint8_t* const buffer_end = (uint8_t*)buffer + buffer_size; const size_t num_max_instructions = count ? *count : (size_t)(-1); size_t num_instructions = 0; char parsed_string[256]; uint8_t temp_buffer[15]; /* The assembling takes place on this buffer instead of the user's buffer because the assembler doesn't check the buffer size. If it assembled directly to the user's buffer it could access bad memory */ uint8_t* b = (uint8_t*)buffer; size_t remaining_size; size_t length = 0; _nmd_assemble_info ai; ai.s = parsed_string; ai.mode = mode; ai.runtime_address = runtime_address; ai.b = temp_buffer; /* Parse the first character of the string because the loop just ahead accesses `string-1` which could be bad memory if we didn't do this */ if (*string == ' ') string++; else { parsed_string[0] = *string++; length++; } while (*string && num_instructions < num_max_instructions) { remaining_size = buffer_end - b; /* Copy 'string' to 'parsed_string' converting it to lowercase and removing unwanted spaces. If the instruction separator character '\n' is found, stop. */ char c = *string; /* Current character */ char prev_c = *(string - 1); /* Previous character */ while (c && c != '\n') { /* Ignore(skip) the current character if it's a space and the previous character is one of the following: ' ', '+', '*', '[' */ if (c == ' ' && (prev_c == ' ' || prev_c == '+' || prev_c == '*' || prev_c == '[')) { c = *++string; continue; } /* Append character */ parsed_string[length++] = _NMD_TOLOWER(c); /* The maximum length is 255 */ if (length >= 256) return 0; /* Set previous character */ prev_c = c; /* Get the next character */ c = *++string; } /* This check is only ever true if *string == '\n', that is the instruction separator character */ if (*string /* == '\n' */) string++; /* Go forward by one character so 'string' points to the next instruction */ /* If the last character is a space, remove it. */ if (length > 0 && parsed_string[length - 1] == ' ') length--; /* After all of the string manipulation, place the null character */ parsed_string[length] = '\0'; /* Try to assemble the instruction */ const size_t num_bytes = _nmd_assemble_single(&ai); if (num_bytes == 0 || num_bytes > remaining_size) return 0; /* Copy bytes from 'temp_buffer' to 'buffer' */ size_t i = 0; for (; i < num_bytes; i++) b[i] = temp_buffer[i]; b += num_bytes; num_instructions++; /* Reset length in case there's another instruction */ length = 0; } if (count) *count = num_instructions; /* Return the number of bytes written to the buffer */ return (size_t)((ptrdiff_t)b - (ptrdiff_t)buffer); } NMD_ASSEMBLY_API void _nmd_decode_operand_segment_reg(const nmd_x86_instruction* instruction, nmd_x86_operand* operand) { if (instruction->segment_override) operand->fields.reg = (uint8_t)(NMD_X86_REG_ES + _nmd_get_bit_index(instruction->segment_override)); else operand->fields.reg = (uint8_t)(!(instruction->prefixes & NMD_X86_PREFIXES_REX_B) && (instruction->modrm.fields.rm == 0b100 || instruction->modrm.fields.rm == 0b101) ? NMD_X86_REG_SS : NMD_X86_REG_DS); } /* Decodes a memory operand. modrm is assumed to be in the range [00,BF] */ NMD_ASSEMBLY_API void _nmd_decode_modrm_upper32(const nmd_x86_instruction* instruction, nmd_x86_operand* operand) { /* Set operand type */ operand->type = NMD_X86_OPERAND_TYPE_MEMORY; if (instruction->has_sib) /* R/M is 0b100 */ { if (instruction->sib.fields.base == 0b101) /* Check if there is displacement */ { if (instruction->modrm.fields.mod != 0b00) operand->fields.mem.base = (uint8_t)(instruction->mode == NMD_X86_MODE_64 && !(instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE) ? (instruction->prefixes & NMD_X86_PREFIXES_REX_B ? NMD_X86_REG_R13 : NMD_X86_REG_RBP) : NMD_X86_REG_EBP); } else operand->fields.mem.base = (uint8_t)((instruction->mode == NMD_X86_MODE_64 && !(instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE) ? (instruction->prefixes & NMD_X86_PREFIXES_REX_B ? NMD_X86_REG_R8 : NMD_X86_REG_RAX) : NMD_X86_REG_EAX) + instruction->sib.fields.base); if (instruction->sib.fields.index != 0b100) operand->fields.mem.index = (uint8_t)((instruction->mode == NMD_X86_MODE_64 && !(instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE) ? (instruction->prefixes & NMD_X86_PREFIXES_REX_X ? NMD_X86_REG_R8 : NMD_X86_REG_RAX) : NMD_X86_REG_EAX) + instruction->sib.fields.index); if (instruction->prefixes & NMD_X86_PREFIXES_REX_X && instruction->sib.fields.index == 0b100) { operand->fields.mem.index = (uint8_t)NMD_X86_REG_R12; } operand->fields.mem.scale = instruction->sib.fields.scale; } else if (!(instruction->modrm.fields.mod == 0b00 && instruction->modrm.fields.rm == 0b101)) { if (instruction->mode == NMD_X86_MODE_16 && !(instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE)) { operand->fields.mem.base = NMD_X86_REG_BX; operand->fields.mem.index = NMD_X86_REG_SI; } else { if ((instruction->prefixes & (NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE | NMD_X86_PREFIXES_REX_B)) == (NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE | NMD_X86_PREFIXES_REX_B) && instruction->mode == NMD_X86_MODE_64) operand->fields.mem.base = (uint8_t)(NMD_X86_REG_R8D + instruction->modrm.fields.rm); else operand->fields.mem.base = (uint8_t)((instruction->mode == NMD_X86_MODE_64 && !(instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE) ? (instruction->prefixes & NMD_X86_PREFIXES_REX_B ? NMD_X86_REG_R8 : NMD_X86_REG_RAX) : NMD_X86_REG_EAX) + instruction->modrm.fields.rm); } } _nmd_decode_operand_segment_reg(instruction, operand); operand->fields.mem.disp = instruction->displacement; } NMD_ASSEMBLY_API void _nmd_decode_memory_operand(const nmd_x86_instruction* instruction, nmd_x86_operand* operand, uint8_t mod11base_reg) { if (instruction->modrm.fields.mod == 0b11) { operand->type = NMD_X86_OPERAND_TYPE_REGISTER; operand->fields.reg = mod11base_reg + instruction->modrm.fields.rm; } else _nmd_decode_modrm_upper32(instruction, operand); } NMD_ASSEMBLY_API void _nmd_decode_operand_Eb(const nmd_x86_instruction* instruction, nmd_x86_operand* operand) { _nmd_decode_memory_operand(instruction, operand, NMD_X86_REG_AL); } NMD_ASSEMBLY_API void _nmd_decode_operand_Ew(const nmd_x86_instruction* instruction, nmd_x86_operand* operand) { _nmd_decode_memory_operand(instruction, operand, NMD_X86_REG_AX); } NMD_ASSEMBLY_API void _nmd_decode_operand_Ev(const nmd_x86_instruction* instruction, nmd_x86_operand* operand) { _nmd_decode_memory_operand(instruction, operand, (uint8_t)(instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_REG_AX : NMD_X86_REG_EAX)); } NMD_ASSEMBLY_API void _nmd_decode_operand_Ey(const nmd_x86_instruction* instruction, nmd_x86_operand* operand) { _nmd_decode_memory_operand(instruction, operand, (uint8_t)(instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_REG_AX : NMD_X86_REG_EAX)); } NMD_ASSEMBLY_API void _nmd_decode_operand_Qq(const nmd_x86_instruction* instruction, nmd_x86_operand* operand) { _nmd_decode_memory_operand(instruction, operand, NMD_X86_REG_MM0); } NMD_ASSEMBLY_API void _nmd_decode_operand_Wdq(const nmd_x86_instruction* instruction, nmd_x86_operand* operand) { _nmd_decode_memory_operand(instruction, operand, NMD_X86_REG_XMM0); } NMD_ASSEMBLY_API void _nmd_decode_operand_Gb(const nmd_x86_instruction* instruction, nmd_x86_operand* operand) { operand->type = NMD_X86_OPERAND_TYPE_REGISTER; operand->fields.reg = NMD_X86_REG_AL + instruction->modrm.fields.reg; } NMD_ASSEMBLY_API void _nmd_decode_operand_Gd(const nmd_x86_instruction* instruction, nmd_x86_operand* operand) { operand->type = NMD_X86_OPERAND_TYPE_REGISTER; operand->fields.reg = NMD_X86_REG_EAX + instruction->modrm.fields.reg; } NMD_ASSEMBLY_API void _nmd_decode_operand_Gw(const nmd_x86_instruction* instruction, nmd_x86_operand* operand) { operand->type = NMD_X86_OPERAND_TYPE_REGISTER; operand->fields.reg = NMD_X86_REG_AX + instruction->modrm.fields.reg; } NMD_ASSEMBLY_API void _nmd_decode_operand_Gv(const nmd_x86_instruction* instruction, nmd_x86_operand* operand) { operand->type = NMD_X86_OPERAND_TYPE_REGISTER; if (instruction->prefixes & NMD_X86_PREFIXES_REX_B) operand->fields.reg = (uint8_t)((!(instruction->prefixes & NMD_X86_PREFIXES_REX_W) ? NMD_X86_REG_R8D : NMD_X86_REG_R8) + instruction->modrm.fields.reg); else operand->fields.reg = (uint8_t)((instruction->rex_w_prefix ? NMD_X86_REG_RAX : (instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && instruction->mode != NMD_X86_MODE_16 ? NMD_X86_REG_AX : NMD_X86_REG_EAX)) + instruction->modrm.fields.reg); } NMD_ASSEMBLY_API void _nmd_decode_operand_Rv(const nmd_x86_instruction* instruction, nmd_x86_operand* operand) { operand->type = NMD_X86_OPERAND_TYPE_REGISTER; if (instruction->prefixes & NMD_X86_PREFIXES_REX_R) operand->fields.reg = (uint8_t)((!(instruction->prefixes & NMD_X86_PREFIXES_REX_W) ? NMD_X86_REG_R8D : NMD_X86_REG_R8) + instruction->modrm.fields.rm); else operand->fields.reg = (uint8_t)((instruction->rex_w_prefix ? NMD_X86_REG_RAX : ((instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && instruction->mode != NMD_X86_MODE_16) || (instruction->mode == NMD_X86_MODE_16 && !(instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE)) ? NMD_X86_REG_AX : NMD_X86_REG_EAX)) + instruction->modrm.fields.rm); } NMD_ASSEMBLY_API void _nmd_decode_operand_Gy(const nmd_x86_instruction* instruction, nmd_x86_operand* operand) { operand->type = NMD_X86_OPERAND_TYPE_REGISTER; operand->fields.reg = (uint8_t)((instruction->mode == NMD_X86_MODE_64 ? NMD_X86_REG_RAX : NMD_X86_REG_EAX) + instruction->modrm.fields.reg); } NMD_ASSEMBLY_API void _nmd_decode_operand_Pq(const nmd_x86_instruction* instruction, nmd_x86_operand* operand) { operand->type = NMD_X86_OPERAND_TYPE_REGISTER; operand->fields.reg = NMD_X86_REG_MM0 + instruction->modrm.fields.reg; } NMD_ASSEMBLY_API void _nmd_decode_operand_Nq(const nmd_x86_instruction* instruction, nmd_x86_operand* operand) { operand->type = NMD_X86_OPERAND_TYPE_REGISTER; operand->fields.reg = NMD_X86_REG_MM0 + instruction->modrm.fields.rm; } NMD_ASSEMBLY_API void _nmd_decode_operand_Vdq(const nmd_x86_instruction* instruction, nmd_x86_operand* operand) { operand->type = NMD_X86_OPERAND_TYPE_REGISTER; operand->fields.reg = NMD_X86_REG_XMM0 + instruction->modrm.fields.reg; } NMD_ASSEMBLY_API void _nmd_decode_operand_Udq(const nmd_x86_instruction* instruction, nmd_x86_operand* operand) { operand->type = NMD_X86_OPERAND_TYPE_REGISTER; operand->fields.reg = NMD_X86_REG_XMM0 + instruction->modrm.fields.rm; } NMD_ASSEMBLY_API void _nmd_decode_conditional_flag(nmd_x86_instruction* instruction, const uint8_t condition) { switch (condition) { case 0x0: instruction->tested_flags.fields.OF = 1; break; /* Jump if overflow (OF=1) */ case 0x1: instruction->tested_flags.fields.OF = 1; break; /* Jump if not overflow (OF=0) */ case 0x2: instruction->tested_flags.fields.CF = 1; break; /* Jump if not above or equal (CF=1) */ case 0x3: instruction->tested_flags.fields.CF = 1; break; /* Jump if not below (CF=0) */ case 0x4: instruction->tested_flags.fields.ZF = 1; break; /* Jump if equal (ZF=1) */ case 0x5: instruction->tested_flags.fields.ZF = 1; break; /* Jump if not equal (ZF=0) */ case 0x6: instruction->tested_flags.fields.CF = instruction->tested_flags.fields.ZF = 1; break; /* Jump if not above (CF=1 or ZF=1) */ case 0x7: instruction->tested_flags.fields.CF = instruction->tested_flags.fields.ZF = 1; break; /* Jump if not below or equal (CF=0 and ZF=0) */ case 0x8: instruction->tested_flags.fields.SF = 1; break; /* Jump if sign (SF=1) */ case 0x9: instruction->tested_flags.fields.SF = 1; break; /* Jump if not sign (SF=0) */ case 0xa: instruction->tested_flags.fields.PF = 1; break; /* Jump if parity/parity even (PF=1) */ case 0xb: instruction->tested_flags.fields.PF = 1; break; /* Jump if parity odd (PF=0) */ case 0xc: instruction->tested_flags.fields.SF = instruction->tested_flags.fields.OF = 1; break; /* Jump if not greater or equal (SF != OF) */ case 0xd: instruction->tested_flags.fields.SF = instruction->tested_flags.fields.OF = 1; break; /* Jump if not less (SF=OF) */ case 0xe: instruction->tested_flags.fields.ZF = instruction->tested_flags.fields.SF = instruction->tested_flags.fields.OF = 1; break; /* Jump if not greater (ZF=1 or SF != OF) */ case 0xf: instruction->tested_flags.fields.ZF = instruction->tested_flags.fields.SF = instruction->tested_flags.fields.OF = 1; break; /* Jump if not less or equal (ZF=0 and SF=OF) */ } } NMD_ASSEMBLY_API bool _nmd_decode_modrm(const uint8_t** p_buffer, size_t* p_buffer_size, nmd_x86_instruction* const instruction) { instruction->has_modrm = true; _NMD_READ_BYTE(*p_buffer, *p_buffer_size, instruction->modrm.modrm); const bool address_prefix = (bool)(instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE); /* Check for 16-Bit Addressing Form */ if (instruction->mode == NMD_X86_MODE_16) { if (instruction->modrm.fields.mod != 0b11) { if (instruction->modrm.fields.mod == 0b00) { if (instruction->modrm.fields.rm == 0b110) instruction->disp_mask = NMD_X86_DISP16; } else instruction->disp_mask = (uint8_t)(instruction->modrm.fields.mod == 0b01 ? NMD_X86_DISP8 : NMD_X86_DISP16); } } else { /* Check for 16-Bit Addressing Form */ if (address_prefix && instruction->mode == NMD_X86_MODE_32) { /* Check for displacement */ if ((instruction->modrm.fields.mod == 0b00 && instruction->modrm.fields.rm == 0b110) || instruction->modrm.fields.mod == 0b10) instruction->disp_mask = NMD_X86_DISP16; else if (instruction->modrm.fields.mod == 0b01) instruction->disp_mask = NMD_X86_DISP8; } else /*if (!address_prefix || (address_prefix && **b >= 0x40) || (address_prefix && instruction->mode == NMD_X86_MODE_64)) */ { /* Check for SIB byte */ if (instruction->modrm.modrm < 0xC0 && instruction->modrm.fields.rm == 0b100 && (!address_prefix || (address_prefix && instruction->mode == NMD_X86_MODE_64))) { instruction->has_sib = true; _NMD_READ_BYTE(*p_buffer, *p_buffer_size, instruction->sib.sib); } /* Check for displacement */ if (instruction->modrm.fields.mod == 0b01) /* disp8 (ModR/M) */ instruction->disp_mask = NMD_X86_DISP8; else if ((instruction->modrm.fields.mod == 0b00 && instruction->modrm.fields.rm == 0b101) || instruction->modrm.fields.mod == 0b10) /* disp16,32 (ModR/M) */ instruction->disp_mask = (uint8_t)(address_prefix && !(instruction->mode == NMD_X86_MODE_64 && instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE) ? NMD_X86_DISP16 : NMD_X86_DISP32); else if (instruction->has_sib && instruction->sib.fields.base == 0b101) /* disp8,32 (SIB) */ instruction->disp_mask = (uint8_t)(instruction->modrm.fields.mod == 0b01 ? NMD_X86_DISP8 : NMD_X86_DISP32); } } /* Make sure we can read 'instruction->disp_mask' bytes from the buffer */ if (*p_buffer_size < instruction->disp_mask) return false; /* Copy 'instruction->disp_mask' bytes from the buffer */ size_t i = 0; for (; i < (size_t)instruction->disp_mask; i++) ((uint8_t*)(&instruction->displacement))[i] = (*p_buffer)[i]; /* Increment the buffer and decrement the buffer's size */ *p_buffer += instruction->disp_mask; *p_buffer_size -= instruction->disp_mask; return true; } /* Decodes an instruction. Returns true if the instruction is valid, false otherwise. Parameters: - buffer [in] A pointer to a buffer containing an encoded instruction. - buffer_size [in] The size of the buffer in bytes. - instruction [out] A pointer to a variable of type 'nmd_x86_instruction' that receives information about the instruction. - mode [in] The architecture mode. 'NMD_X86_MODE_32', 'NMD_X86_MODE_64' or 'NMD_X86_MODE_16'. - flags [in] A mask of 'NMD_X86_DECODER_FLAGS_XXX' that specifies which features the decoder is allowed to use. If uncertain, use 'NMD_X86_DECODER_FLAGS_MINIMAL'. */ NMD_ASSEMBLY_API bool nmd_x86_decode(const void* const buffer, size_t buffer_size, nmd_x86_instruction* instruction, NMD_X86_MODE mode, uint32_t flags) { /* Security considerations for memory safety: The contents of 'buffer' should be considered untrusted and decoded carefully. 'buffer' should always point to the start of the buffer. We use the 'b' buffer iterator to read data from the buffer, however before accessing it make sure to check 'buffer_size' to see if we can safely access it. Then, after reading data from the buffer we increment 'b' and decrement 'buffer_size'. Helper macros: _NMD_READ_BYTE() */ /* Clear 'instruction' */ size_t i = 0; for (; i < sizeof(nmd_x86_instruction); i++) ((uint8_t*)(instruction))[i] = 0x00; /* Set mode */ instruction->mode = (uint8_t)mode; /* Set buffer iterator */ const uint8_t* b = (const uint8_t*)buffer; /* Clamp 'buffer_size' to 15. We will only read up to 15 bytes(NMD_X86_MAXIMUM_INSTRUCTION_LENGTH) */ if (buffer_size > 15) buffer_size = 15; /* Decode legacy and REX prefixes */ for (; buffer_size > 0; b++, buffer_size--) { switch (*b) { case 0xF0: instruction->prefixes = (instruction->prefixes | (instruction->simd_prefix = NMD_X86_PREFIXES_LOCK)); continue; case 0xF2: instruction->prefixes = (instruction->prefixes | (instruction->simd_prefix = NMD_X86_PREFIXES_REPEAT_NOT_ZERO)), instruction->repeat_prefix = false; continue; case 0xF3: instruction->prefixes = (instruction->prefixes | (instruction->simd_prefix = NMD_X86_PREFIXES_REPEAT)), instruction->repeat_prefix = true; continue; case 0x2E: instruction->prefixes = (instruction->prefixes | (instruction->segment_override = NMD_X86_PREFIXES_CS_SEGMENT_OVERRIDE)); continue; case 0x36: instruction->prefixes = (instruction->prefixes | (instruction->segment_override = NMD_X86_PREFIXES_SS_SEGMENT_OVERRIDE)); continue; case 0x3E: instruction->prefixes = (instruction->prefixes | (instruction->segment_override = NMD_X86_PREFIXES_DS_SEGMENT_OVERRIDE)); continue; case 0x26: instruction->prefixes = (instruction->prefixes | (instruction->segment_override = NMD_X86_PREFIXES_ES_SEGMENT_OVERRIDE)); continue; case 0x64: instruction->prefixes = (instruction->prefixes | (instruction->segment_override = NMD_X86_PREFIXES_FS_SEGMENT_OVERRIDE)); continue; case 0x65: instruction->prefixes = (instruction->prefixes | (instruction->segment_override = NMD_X86_PREFIXES_GS_SEGMENT_OVERRIDE)); continue; case 0x66: instruction->prefixes = (instruction->prefixes | (instruction->simd_prefix = NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE)), instruction->rex_w_prefix = false; continue; case 0x67: instruction->prefixes = (instruction->prefixes | NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE); continue; default: if (mode == NMD_X86_MODE_64 && _NMD_R(*b) == 4) /* REX prefixes [0x40,0x4f] */ { instruction->has_rex = true; instruction->rex = *b; instruction->prefixes = (instruction->prefixes & ~(NMD_X86_PREFIXES_REX_B | NMD_X86_PREFIXES_REX_X | NMD_X86_PREFIXES_REX_R | NMD_X86_PREFIXES_REX_W)); if (*b & 0b0001) /* Bit position 0 */ instruction->prefixes = instruction->prefixes | NMD_X86_PREFIXES_REX_B; if (*b & 0b0010) /* Bit position 1 */ instruction->prefixes = instruction->prefixes | NMD_X86_PREFIXES_REX_X; if (*b & 0b0100) /* Bit position 2 */ instruction->prefixes = instruction->prefixes | NMD_X86_PREFIXES_REX_R; if (*b & 0b1000) /* Bit position 3 */ { instruction->prefixes = instruction->prefixes | NMD_X86_PREFIXES_REX_W; instruction->rex_w_prefix = true; } continue; } } break; } /* Calculate the number of prefixes based on how much the iterator moved */ instruction->num_prefixes = (uint8_t)((ptrdiff_t)(b)-(ptrdiff_t)(buffer)); /* Assume the instruction uses legacy encoding. It is most likely the case */ instruction->encoding = NMD_X86_ENCODING_LEGACY; /* Opcode byte. This variable is used because 'op' is simpler than 'instruction->opcode' */ uint8_t op; _NMD_READ_BYTE(b, buffer_size, op); if (op == 0x0F) /* 2 or 3 byte opcode */ { _NMD_READ_BYTE(b, buffer_size, op); if (op == 0x38 || op == 0x3A) /* 3 byte opcode */ { instruction->opcode_size = 3; instruction->opcode_map = (uint8_t)(op == 0x38 ? NMD_X86_OPCODE_MAP_0F38 : NMD_X86_OPCODE_MAP_0F3A); _NMD_READ_BYTE(b, buffer_size, op); instruction->opcode = op; if (!_nmd_decode_modrm(&b, &buffer_size, instruction)) return false; const nmd_x86_modrm modrm = instruction->modrm; if (instruction->opcode_map == NMD_X86_OPCODE_MAP_0F38) { #ifndef NMD_ASSEMBLY_DISABLE_DECODER_VALIDITY_CHECK if (flags & NMD_X86_DECODER_FLAGS_VALIDITY_CHECK) { /* Check if the instruction is invalid. */ if (op == 0x36) { return false; } else if (op <= 0xb || (op >= 0x1c && op <= 0x1e)) { if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT || instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) return false; } else if (op >= 0xc8 && op <= 0xcd) { if (instruction->simd_prefix) return false; } else if (op == 0x10 || op == 0x14 || op == 0x15 || op == 0x17 || (op >= 0x20 && op <= 0x25) || op == 0x28 || op == 0x29 || op == 0x2b || _NMD_R(op) == 3 || op == 0x40 || op == 0x41 || op == 0xcf || (op >= 0xdb && op <= 0xdf)) { if (instruction->simd_prefix != NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) return false; } else if (op == 0x2a || (op >= 0x80 && op <= 0x82)) { if (modrm.fields.mod == 0b11 || instruction->simd_prefix != NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) return false; } else if (op == 0xf0 || op == 0xf1) { if (modrm.fields.mod == 0b11 && (instruction->simd_prefix == NMD_X86_PREFIXES_NONE || instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE)) return false; else if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT) return false; } else if (op == 0xf5 || op == 0xf8) { if (instruction->simd_prefix != NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE || modrm.fields.mod == 0b11) return false; } else if (op == 0xf6) { if (instruction->simd_prefix == NMD_X86_PREFIXES_NONE && modrm.fields.mod == 0b11) return false; else if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) return false; } else if (op == 0xf9) { if (instruction->simd_prefix != NMD_X86_PREFIXES_NONE || modrm.fields.mod == 0b11) return false; } else return false; } #endif /* NMD_ASSEMBLY_DISABLE_DECODER_VALIDITY_CHECK */ #ifndef NMD_ASSEMBLY_DISABLE_DECODER_INSTRUCTION_ID if (flags & NMD_X86_DECODER_FLAGS_INSTRUCTION_ID) { if (_NMD_R(op) == 0x00) instruction->id = NMD_X86_INSTRUCTION_PSHUFB + op; else if (op >= 0x1c && op <= 0x1e) instruction->id = NMD_X86_INSTRUCTION_PABSB + (op - 0x1c); else if (_NMD_R(op) == 2) instruction->id = NMD_X86_INSTRUCTION_PMOVSXBW + _NMD_C(op); else if (_NMD_R(op) == 3) instruction->id = NMD_X86_INSTRUCTION_PMOVZXBW + _NMD_C(op); else if (_NMD_R(op) == 8) instruction->id = NMD_X86_INSTRUCTION_INVEPT + _NMD_C(op); else if (_NMD_R(op) == 0xc) instruction->id = NMD_X86_INSTRUCTION_SHA1NEXTE + (_NMD_C(op) - 8); else if (_NMD_R(op) == 0xd) instruction->id = NMD_X86_INSTRUCTION_AESIMC + (_NMD_C(op) - 0xb); else { switch (op) { case 0x10: instruction->id = NMD_X86_INSTRUCTION_PBLENDVB; break; case 0x14: instruction->id = NMD_X86_INSTRUCTION_BLENDVPS; break; case 0x15: instruction->id = NMD_X86_INSTRUCTION_BLENDVPD; break; case 0x17: instruction->id = NMD_X86_INSTRUCTION_PTEST; break; case 0x40: instruction->id = NMD_X86_INSTRUCTION_PMULLD; break; case 0x41: instruction->id = NMD_X86_INSTRUCTION_PHMINPOSUW; break; case 0xf0: case 0xf1: instruction->id = (uint16_t)((instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE || instruction->simd_prefix == 0x00) ? NMD_X86_INSTRUCTION_MOVBE : NMD_X86_INSTRUCTION_CRC32); break; case 0xf6: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_ADCX : NMD_X86_INSTRUCTION_ADOX); break; } } } #endif /* NMD_ASSEMBLY_DISABLE_DECODER_INSTRUCTION_ID */ #ifndef NMD_ASSEMBLY_DISABLE_DECODER_CPU_FLAGS if (flags & NMD_X86_DECODER_FLAGS_CPU_FLAGS) { if (op == 0x80 || op == 0x81) /* invept,invvpid */ { instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_ZF; instruction->cleared_flags.eflags = NMD_X86_EFLAGS_PF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_OF; } else if (op == 0xf6) { if (instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) /* adcx */ instruction->modified_flags.eflags = instruction->tested_flags.eflags = NMD_X86_EFLAGS_CF; if (instruction->prefixes & NMD_X86_PREFIXES_REPEAT) /* adox */ instruction->modified_flags.eflags = instruction->tested_flags.eflags = NMD_X86_EFLAGS_OF; } } #endif /* NMD_ASSEMBLY_DISABLE_DECODER_CPU_FLAGS */ #ifndef NMD_ASSEMBLY_DISABLE_DECODER_OPERANDS if (flags & NMD_X86_DECODER_FLAGS_OPERANDS) { instruction->num_operands = 2; instruction->operands[0].action = NMD_X86_OPERAND_ACTION_READWRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; if (_NMD_R(op) == 0 || (op >= 0x1c && op <= 0x1e)) { _nmd_decode_operand_Pq(instruction, &instruction->operands[0]); _nmd_decode_operand_Qq(instruction, &instruction->operands[1]); } else if (_NMD_R(op) == 8) { _nmd_decode_operand_Gy(instruction, &instruction->operands[0]); _nmd_decode_modrm_upper32(instruction, &instruction->operands[1]); } else if (_NMD_R(op) >= 1 && _NMD_R(op) <= 0xe) { _nmd_decode_operand_Vdq(instruction, &instruction->operands[0]); _nmd_decode_operand_Wdq(instruction, &instruction->operands[1]); } else if (op == 0xf6) { _nmd_decode_operand_Gy(instruction, &instruction->operands[!instruction->simd_prefix ? 1 : 0]); _nmd_decode_operand_Ey(instruction, &instruction->operands[!instruction->simd_prefix ? 0 : 1]); } else if (op == 0xf0 || op == 0xf1) { if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO || (instruction->prefixes & (NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE | NMD_X86_PREFIXES_REPEAT_NOT_ZERO)) == (NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE | NMD_X86_PREFIXES_REPEAT_NOT_ZERO)) { _nmd_decode_operand_Gd(instruction, &instruction->operands[0]); if (op == 0xf0) _nmd_decode_operand_Eb(instruction, &instruction->operands[1]); else if (instruction->prefixes == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) _nmd_decode_operand_Ey(instruction, &instruction->operands[1]); else _nmd_decode_operand_Ew(instruction, &instruction->operands[1]); } else { if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) _nmd_decode_operand_Gw(instruction, &instruction->operands[op == 0xf0 ? 0 : 1]); else _nmd_decode_operand_Gy(instruction, &instruction->operands[op == 0xf0 ? 0 : 1]); _nmd_decode_memory_operand(instruction, &instruction->operands[op == 0xf0 ? 1 : 0], (uint8_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_REG_AX : (instruction->rex_w_prefix ? NMD_X86_REG_RAX : NMD_X86_REG_EAX))); } } } #endif /* NMD_ASSEMBLY_DISABLE_DECODER_OPERANDS */ } else /* 0x3a */ { instruction->imm_mask = NMD_X86_IMM8; _NMD_READ_BYTE(b, buffer_size, instruction->immediate); #ifndef NMD_ASSEMBLY_DISABLE_DECODER_VALIDITY_CHECK if (flags & NMD_X86_DECODER_FLAGS_VALIDITY_CHECK) { /* Check if the instruction is invalid. */ if ((op >= 0x8 && op <= 0xe) || (op >= 0x14 && op <= 0x17) || (op >= 0x20 && op <= 0x22) || (op >= 0x40 && op <= 0x42) || op == 0x44 || (op >= 0x60 && op <= 0x63) || op == 0xdf || op == 0xce || op == 0xcf) { if (instruction->simd_prefix != NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) return false; } else if (op == 0x0f || op == 0xcc) { if (instruction->simd_prefix) return false; } else return false; } #endif /* NMD_ASSEMBLY_DISABLE_DECODER_VALIDITY_CHECK */ #ifndef NMD_ASSEMBLY_DISABLE_DECODER_INSTRUCTION_ID if (flags & NMD_X86_DECODER_FLAGS_INSTRUCTION_ID) { if (_NMD_R(op) == 0) instruction->id = NMD_X86_INSTRUCTION_ROUNDPS + (op - 8); else if (_NMD_R(op) == 4) instruction->id = NMD_X86_INSTRUCTION_DPPS + _NMD_C(op); else if (_NMD_R(op) == 6) instruction->id = NMD_X86_INSTRUCTION_PCMPESTRM + _NMD_C(op); else { switch (op) { case 0x14: instruction->id = NMD_X86_INSTRUCTION_PEXTRB; break; case 0x15: instruction->id = NMD_X86_INSTRUCTION_PEXTRW; break; case 0x16: instruction->id = (uint16_t)(instruction->prefixes & NMD_X86_PREFIXES_REX_W ? NMD_X86_INSTRUCTION_PEXTRQ : NMD_X86_INSTRUCTION_PEXTRD); break; case 0x17: instruction->id = NMD_X86_INSTRUCTION_EXTRACTPS; break; case 0x20: instruction->id = NMD_X86_INSTRUCTION_PINSRB; break; case 0x21: instruction->id = NMD_X86_INSTRUCTION_INSERTPS; break; case 0x22: instruction->id = (uint16_t)(instruction->prefixes & NMD_X86_PREFIXES_REX_W ? NMD_X86_INSTRUCTION_PINSRQ : NMD_X86_INSTRUCTION_PINSRD); break; case 0xcc: instruction->id = NMD_X86_INSTRUCTION_SHA1RNDS4; break; case 0xdf: instruction->id = NMD_X86_INSTRUCTION_AESKEYGENASSIST; break; } } } #endif /* NMD_ASSEMBLY_DISABLE_DECODER_INSTRUCTION_ID */ #ifndef NMD_ASSEMBLY_DISABLE_DECODER_OPERANDS if (flags & NMD_X86_DECODER_FLAGS_OPERANDS) { instruction->num_operands = 3; instruction->operands[0].action = NMD_X86_OPERAND_ACTION_READWRITE; instruction->operands[1].action = instruction->operands[2].action = NMD_X86_OPERAND_ACTION_READ; instruction->operands[2].type = NMD_X86_OPERAND_TYPE_IMMEDIATE; if (op == 0x0f && !instruction->simd_prefix) { _nmd_decode_operand_Pq(instruction, &instruction->operands[0]); _nmd_decode_operand_Qq(instruction, &instruction->operands[1]); } else if (_NMD_R(op) == 1) { _nmd_decode_memory_operand(instruction, &instruction->operands[0], NMD_X86_REG_EAX); _nmd_decode_operand_Vdq(instruction, &instruction->operands[1]); } else if (_NMD_R(op) == 2) { _nmd_decode_operand_Vdq(instruction, &instruction->operands[0]); _nmd_decode_memory_operand(instruction, &instruction->operands[1], (uint8_t)(_NMD_C(op) == 1 ? NMD_X86_REG_XMM0 : NMD_X86_REG_EAX)); } else if (op == 0xcc || op == 0xdf || _NMD_R(op) == 4 || _NMD_R(op) == 6 || _NMD_R(op) == 0) { _nmd_decode_operand_Vdq(instruction, &instruction->operands[0]); _nmd_decode_operand_Wdq(instruction, &instruction->operands[1]); } } #endif /* NMD_ASSEMBLY_DISABLE_DECODER_OPERANDS */ } } else if (op == 0x0f) /* 3DNow! opcode map*/ { #ifndef NMD_ASSEMBLY_DISABLE_DECODER_3DNOW if (flags & NMD_X86_DECODER_FLAGS_3DNOW) { if (!_nmd_decode_modrm(&b, &buffer_size, instruction)) return false; instruction->encoding = NMD_X86_ENCODING_3DNOW; instruction->opcode = 0x0f; instruction->imm_mask = NMD_X86_IMM8; /* The real opcode is encoded as the immediate byte. */ _NMD_READ_BYTE(b, buffer_size, instruction->immediate); #ifndef NMD_ASSEMBLY_DISABLE_DECODER_VALIDITY_CHECK if (!_nmd_find_byte(_nmd_valid_3DNow_opcodes, sizeof(_nmd_valid_3DNow_opcodes), (uint8_t)instruction->immediate)) return false; #endif /* NMD_ASSEMBLY_DISABLE_DECODER_VALIDITY_CHECK */ } else return false; #else /* NMD_ASSEMBLY_DISABLE_DECODER_3DNOW */ return false; #endif /* NMD_ASSEMBLY_DISABLE_DECODER_3DNOW */ } else /* 2 byte opcode. */ { instruction->opcode_size = 2; instruction->opcode = op; instruction->opcode_map = NMD_X86_OPCODE_MAP_0F; /* Check for ModR/M, SIB and displacement */ if (op >= 0x20 && op <= 0x23 && buffer_size == 2) { instruction->has_modrm = true; _NMD_READ_BYTE(b, buffer_size, instruction->modrm.modrm); } else if (op < 4 || (_NMD_R(op) != 3 && _NMD_R(op) > 0 && _NMD_R(op) < 7) || (op >= 0xD0 && op != 0xFF) || (_NMD_R(op) == 7 && _NMD_C(op) != 7) || _NMD_R(op) == 9 || _NMD_R(op) == 0xB || (_NMD_R(op) == 0xC && _NMD_C(op) < 8) || (_NMD_R(op) == 0xA && (op % 8) >= 3) || op == 0x0ff || op == 0x00 || op == 0x0d) { if (!_nmd_decode_modrm(&b, &buffer_size, instruction)) return false; } const nmd_x86_modrm modrm = instruction->modrm; #ifndef NMD_ASSEMBLY_DISABLE_DECODER_VALIDITY_CHECK if (flags & NMD_X86_DECODER_FLAGS_VALIDITY_CHECK) { /* Check if the instruction is invalid. */ if (_nmd_find_byte(_nmd_invalid_op2, sizeof(_nmd_invalid_op2), op)) return false; else if (op == 0xc7) { if ((!instruction->simd_prefix && (modrm.fields.mod == 0b11 ? modrm.fields.reg <= 0b101 : modrm.fields.reg == 0b000 || modrm.fields.reg == 0b010)) || (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO && (modrm.fields.mod == 0b11 || modrm.fields.reg != 0b001)) || ((instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE || instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT) && (modrm.fields.mod == 0b11 ? modrm.fields.reg <= (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? 0b110 : 0b101) : (modrm.fields.reg != 0b001 && modrm.fields.reg != 0b110)))) return false; } else if (op == 0x00) { if (modrm.fields.reg >= 0b110) return false; } else if (op == 0x01) { if ((modrm.fields.mod == 0b11 ? ((instruction->simd_prefix & (NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE | NMD_X86_PREFIXES_REPEAT_NOT_ZERO | NMD_X86_PREFIXES_REPEAT) && ((modrm.modrm >= 0xc0 && modrm.modrm <= 0xc5) || (modrm.modrm >= 0xc8 && modrm.modrm <= 0xcb) || (modrm.modrm >= 0xcf && modrm.modrm <= 0xd1) || (modrm.modrm >= 0xd4 && modrm.modrm <= 0xd7) || modrm.modrm == 0xee || modrm.modrm == 0xef || modrm.modrm == 0xfa || modrm.modrm == 0xfb)) || (modrm.fields.reg == 0b000 && modrm.fields.rm >= 0b110) || (modrm.fields.reg == 0b001 && modrm.fields.rm >= 0b100 && modrm.fields.rm <= 0b110) || (modrm.fields.reg == 0b010 && (modrm.fields.rm == 0b010 || modrm.fields.rm == 0b011)) || (modrm.fields.reg == 0b101 && modrm.fields.rm < 0b110 && (!(instruction->simd_prefix & NMD_X86_PREFIXES_REPEAT) || (instruction->simd_prefix & NMD_X86_PREFIXES_REPEAT && (modrm.fields.rm != 0b000 && modrm.fields.rm != 0b010)))) || (modrm.fields.reg == 0b111 && (modrm.fields.rm > 0b101 || (mode != NMD_X86_MODE_64 && modrm.fields.rm == 0b000)))) : (!(instruction->simd_prefix & NMD_X86_PREFIXES_REPEAT) && modrm.fields.reg == 0b101))) return false; } else if (op == 0x1A || op == 0x1B) { if (modrm.fields.mod == 0b11) return false; } else if (op == 0x20 || op == 0x22) { if (modrm.fields.reg == 0b001 || modrm.fields.reg >= 0b101) return false; } else if (op >= 0x24 && op <= 0x27) return false; else if (op >= 0x3b && op <= 0x3f) return false; else if (_NMD_R(op) == 5) { if ((op == 0x50 && modrm.fields.mod != 0b11) || (instruction->simd_prefix & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && (op == 0x52 || op == 0x53)) || (instruction->simd_prefix & NMD_X86_PREFIXES_REPEAT && (op == 0x50 || (op >= 0x54 && op <= 0x57))) || (instruction->simd_prefix & NMD_X86_PREFIXES_REPEAT_NOT_ZERO && (op == 0x50 || (op >= 0x52 && op <= 0x57) || op == 0x5b))) return false; } else if (_NMD_R(op) == 6) { if ((!(instruction->simd_prefix & (NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE | NMD_X86_PREFIXES_REPEAT | NMD_X86_PREFIXES_REPEAT_NOT_ZERO)) && (op == 0x6c || op == 0x6d)) || (instruction->simd_prefix & NMD_X86_PREFIXES_REPEAT && op != 0x6f) || instruction->simd_prefix & NMD_X86_PREFIXES_REPEAT_NOT_ZERO) return false; } else if (op == 0x78 || op == 0x79) { if ((((instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && op == 0x78) && !(modrm.fields.mod == 0b11 && modrm.fields.reg == 0b000)) || ((instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE || instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) && modrm.fields.mod != 0b11)) || (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT)) return false; } else if (op == 0x7c || op == 0x7d) { if (instruction->simd_prefix & NMD_X86_PREFIXES_REPEAT || !(instruction->simd_prefix & (NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE | NMD_X86_PREFIXES_REPEAT | NMD_X86_PREFIXES_REPEAT_NOT_ZERO))) return false; } else if (op == 0x7e || op == 0x7f) { if (instruction->simd_prefix & NMD_X86_PREFIXES_REPEAT_NOT_ZERO) return false; } else if (op >= 0x71 && op <= 0x73) { if (instruction->simd_prefix & (NMD_X86_PREFIXES_REPEAT | NMD_X86_PREFIXES_REPEAT_NOT_ZERO) || modrm.modrm <= 0xcf || (modrm.modrm >= 0xe8 && modrm.modrm <= 0xef)) return false; } else if (op == 0x73) { if (modrm.modrm >= 0xe0 && modrm.modrm <= 0xe8) return false; } else if (op == 0xa6) { if (modrm.modrm != 0xc0 && modrm.modrm != 0xc8 && modrm.modrm != 0xd0) return false; } else if (op == 0xa7) { if (!(modrm.fields.mod == 0b11 && modrm.fields.reg <= 0b101 && modrm.fields.rm == 0b000)) return false; } else if (op == 0xae) { if (((!instruction->simd_prefix && modrm.fields.mod == 0b11 && modrm.fields.reg <= 0b100) || (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO && !(modrm.fields.mod == 0b11 && modrm.fields.reg == 0b110)) || (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && (modrm.fields.reg < 0b110 || (modrm.fields.mod == 0b11 && modrm.fields.reg == 0b111))) || (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT && (modrm.fields.reg != 0b100 && modrm.fields.reg != 0b110) && !(modrm.fields.mod == 0b11 && modrm.fields.reg == 0b101)))) return false; } else if (op == 0xb8) { if (!(instruction->simd_prefix & NMD_X86_PREFIXES_REPEAT)) return false; } else if (op == 0xba) { if (modrm.fields.reg <= 0b011) return false; } else if (op == 0xd0) { if (!instruction->simd_prefix || instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT) return false; } else if (op == 0xe0) { if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT || instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) return false; } else if (op == 0xf0) { if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO ? modrm.fields.mod == 0b11 : true) return false; } else if (instruction->simd_prefix & (NMD_X86_PREFIXES_REPEAT | NMD_X86_PREFIXES_REPEAT_NOT_ZERO)) { if ((op >= 0x13 && op <= 0x17 && !(op == 0x16 && instruction->simd_prefix & NMD_X86_PREFIXES_REPEAT)) || op == 0x28 || op == 0x29 || op == 0x2e || op == 0x2f || (op <= 0x76 && op >= 0x74)) return false; } else if (op == 0x71 || op == 0x72 || (op == 0x73 && !(instruction->simd_prefix & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE))) { if ((modrm.modrm >= 0xd8 && modrm.modrm <= 0xdf) || modrm.modrm >= 0xf8) return false; } else if (op >= 0xc3 && op <= 0xc6) { if ((op == 0xc5 && modrm.fields.mod != 0b11) || (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT || instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) || (op == 0xc3 && instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE)) return false; } else if (_NMD_R(op) >= 0xd && _NMD_C(op) != 0 && op != 0xff && ((_NMD_C(op) == 6 && _NMD_R(op) != 0xf) ? (!instruction->simd_prefix || (_NMD_R(op) == 0xD && (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT || instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) ? modrm.fields.mod != 0b11 : false)) : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT || instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO || ((_NMD_C(op) == 7 && _NMD_R(op) != 0xe) ? modrm.fields.mod != 0b11 : false)))) return false; else if (modrm.fields.mod == 0b11) { if (op == 0xb2 || op == 0xb4 || op == 0xb5 || op == 0xc3 || op == 0xe7 || op == 0x2b || (instruction->simd_prefix & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && (op == 0x12 || op == 0x16)) || (!(instruction->simd_prefix & (NMD_X86_PREFIXES_REPEAT | NMD_X86_PREFIXES_REPEAT_NOT_ZERO)) && (op == 0x13 || op == 0x17))) return false; } } #endif /* NMD_ASSEMBLY_DISABLE_DECODER_VALIDITY_CHECK */ if (_NMD_R(op) == 8) /* imm32 */ instruction->imm_mask = _NMD_GET_BY_MODE_OPSZPRFX_F64(mode, instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE, NMD_X86_IMM16, NMD_X86_IMM32, NMD_X86_IMM32); else if ((_NMD_R(op) == 7 && _NMD_C(op) < 4) || op == 0xA4 || op == 0xC2 || (op > 0xC3 && op <= 0xC6) || op == 0xBA || op == 0xAC) /* imm8 */ instruction->imm_mask = NMD_X86_IMM8; else if (op == 0x78 && (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO || instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE)) /* imm8 + imm8 = "imm16" */ instruction->imm_mask = NMD_X86_IMM16; /* Make sure we can read 'instruction->imm_mask' bytes from the buffer */ if (buffer_size < instruction->imm_mask) return false; /* Copy 'instruction->imm_mask' bytes from the buffer */ for (i = 0; i < instruction->imm_mask; i++) ((uint8_t*)(&instruction->immediate))[i] = b[i]; /* Increment the buffer and decrement the buffer's size */ b += instruction->imm_mask; buffer_size -= instruction->imm_mask; if (_NMD_R(op) == 8 && instruction->immediate & ((uint64_t)(1) << (instruction->imm_mask * 8 - 1))) instruction->immediate |= 0xffffffffffffffff << (instruction->imm_mask * 8); #ifndef NMD_ASSEMBLY_DISABLE_DECODER_INSTRUCTION_ID if (flags & NMD_X86_DECODER_FLAGS_INSTRUCTION_ID) { if (_NMD_R(op) == 8) instruction->id = NMD_X86_INSTRUCTION_JO + _NMD_C(op); else if (op >= 0xa2 && op <= 0xa5) instruction->id = NMD_X86_INSTRUCTION_CPUID + (op - 0xa2); else if (op == 0x05) instruction->id = NMD_X86_INSTRUCTION_SYSCALL; else if (_NMD_R(op) == 4) instruction->id = NMD_X86_INSTRUCTION_CMOVO + _NMD_C(op); else if (op == 0x00) instruction->id = NMD_X86_INSTRUCTION_SLDT + modrm.fields.reg; else if (op == 0x01) { if (modrm.fields.mod == 0b11) { switch (modrm.fields.reg) { case 0b000: instruction->id = NMD_X86_INSTRUCTION_VMCALL + modrm.fields.rm; break; case 0b001: instruction->id = NMD_X86_INSTRUCTION_MONITOR + modrm.fields.rm; break; case 0b010: instruction->id = NMD_X86_INSTRUCTION_XGETBV + modrm.fields.rm; break; case 0b011: instruction->id = NMD_X86_INSTRUCTION_VMRUN + modrm.fields.rm; break; case 0b100: instruction->id = NMD_X86_INSTRUCTION_SMSW; break; case 0b110: instruction->id = NMD_X86_INSTRUCTION_LMSW; break; case 0b111: instruction->id = (uint16_t)(modrm.fields.rm == 0b000 ? NMD_X86_INSTRUCTION_SWAPGS : NMD_X86_INSTRUCTION_RDTSCP); break; } } else instruction->id = NMD_X86_INSTRUCTION_SGDT + modrm.fields.reg; } else if (op <= 0x0b) instruction->id = NMD_X86_INSTRUCTION_LAR + (op - 2); else if (op == 0x19 || (op >= 0x1c && op <= 0x1f)) { if (op == 0x1e && modrm.modrm == 0xfa) instruction->id = NMD_X86_INSTRUCTION_ENDBR64; else if (op == 0x1e && modrm.modrm == 0xfb) instruction->id = NMD_X86_INSTRUCTION_ENDBR32; else instruction->id = NMD_X86_INSTRUCTION_NOP; } else if (op >= 0x10 && op <= 0x17) { switch (instruction->simd_prefix) { case NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE: instruction->id = NMD_X86_INSTRUCTION_VMOVUPS + _NMD_C(op); break; case NMD_X86_PREFIXES_REPEAT: instruction->id = NMD_X86_INSTRUCTION_VMOVUPS + _NMD_C(op); break; case NMD_X86_PREFIXES_REPEAT_NOT_ZERO: instruction->id = NMD_X86_INSTRUCTION_VMOVUPS + _NMD_C(op); break; default: instruction->id = NMD_X86_INSTRUCTION_VMOVUPS + _NMD_C(op); break; } } else if (op >= 0x20 && op <= 0x23) instruction->id = NMD_X86_INSTRUCTION_MOV; else if (_NMD_R(op) == 3) instruction->id = NMD_X86_INSTRUCTION_WRMSR + _NMD_C(op); else if (_NMD_R(op) == 5) { switch (instruction->simd_prefix) { case NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE: instruction->id = NMD_X86_INSTRUCTION_MOVMSKPD + _NMD_C(op); break; case NMD_X86_PREFIXES_REPEAT: instruction->id = NMD_X86_INSTRUCTION_BNDMOV + _NMD_C(op); break; case NMD_X86_PREFIXES_REPEAT_NOT_ZERO: instruction->id = NMD_X86_INSTRUCTION_BNDCL + _NMD_C(op); break; default: instruction->id = NMD_X86_INSTRUCTION_MOVMSKPS + _NMD_C(op); break; } } else if (op >= 0x60 && op <= 0x6d) instruction->id = NMD_X86_INSTRUCTION_PUNPCKLBW + _NMD_C(op); else if (op >= 0x74 && op <= 0x76) instruction->id = NMD_X86_INSTRUCTION_PCMPEQB + (op - 0x74); else if (op >= 0xb2 && op <= 0xb5) instruction->id = NMD_X86_INSTRUCTION_LSS + (op - 0xb2); else if (op >= 0xc3 && op <= 0xc5) instruction->id = NMD_X86_INSTRUCTION_MOVNTI + (op - 0xc3); else if (op == 0xc7) { if (modrm.fields.reg == 0b001) instruction->id = (uint16_t)(instruction->rex_w_prefix ? NMD_X86_INSTRUCTION_CMPXCHG16B : NMD_X86_INSTRUCTION_CMPXCHG8B); else if (modrm.fields.reg == 0b111) instruction->id = (uint16_t)(modrm.fields.mod == 0b11 ? (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? NMD_X86_INSTRUCTION_RDPID : NMD_X86_INSTRUCTION_RDSEED) : NMD_X86_INSTRUCTION_VMPTRST); else instruction->id = (uint16_t)(modrm.fields.mod == 0b11 ? NMD_X86_INSTRUCTION_RDRAND : (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_VMCLEAR : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? NMD_X86_INSTRUCTION_VMXON : NMD_X86_INSTRUCTION_VMPTRLD))); } else if (op >= 0xc8 && op <= 0xcf) instruction->id = NMD_X86_INSTRUCTION_BSWAP; else if (op == 0xa3) instruction->id = (uint16_t)((modrm.fields.mod == 0b11 ? NMD_X86_INSTRUCTION_RDFSBASE : NMD_X86_INSTRUCTION_FXSAVE) + modrm.fields.reg); else if (op >= 0xd1 && op <= 0xfe) { if (op == 0xd6) instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_MOVQ : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? NMD_X86_INSTRUCTION_MOVQ2DQ : NMD_X86_INSTRUCTION_MOVDQ2Q)); else if (op == 0xe6) instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_CVTTPD2DQ : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? NMD_X86_INSTRUCTION_CVTDQ2PD : NMD_X86_INSTRUCTION_CVTPD2DQ)); else if (op == 0xe7) instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_MOVNTDQ : NMD_X86_INSTRUCTION_MOVNTQ); else if (op == 0xf7) instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_MASKMOVDQU : NMD_X86_INSTRUCTION_MASKMOVQ); else instruction->id = NMD_X86_INSTRUCTION_PSRLW + (op - 0xd1); } else { switch (op) { case 0xa0: case 0xa8: instruction->id = NMD_X86_INSTRUCTION_PUSH; break; case 0xa1: case 0xa9: instruction->id = NMD_X86_INSTRUCTION_POP; break; case 0xaf: instruction->id = NMD_X86_INSTRUCTION_IMUL; break; case 0xb0: case 0xb1: instruction->id = NMD_X86_INSTRUCTION_CMPXCHG; break; case 0x10: case 0x11: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_MOVUPD : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? NMD_X86_INSTRUCTION_MOVSS : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO ? NMD_X86_INSTRUCTION_MOVSD : NMD_X86_INSTRUCTION_MOVUPD))); break; case 0x12: case 0x13: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_MOVLPD : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? NMD_X86_INSTRUCTION_MOVSLDUP : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO ? NMD_X86_INSTRUCTION_MOVDDUP : NMD_X86_INSTRUCTION_MOVLPS))); break; case 0x14: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_UNPCKLPD : NMD_X86_INSTRUCTION_UNPCKLPS); break; case 0x15: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_UNPCKHPD : NMD_X86_INSTRUCTION_UNPCKHPS); break; case 0x16: case 0x17: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_MOVHPD : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? NMD_X86_INSTRUCTION_MOVSHDUP : NMD_X86_INSTRUCTION_MOVHPS)); break; case 0x18: instruction->id = (uint16_t)(modrm.fields.reg >= 0b100 ? NMD_X86_INSTRUCTION_NOP : (modrm.fields.reg == 0b000 ? NMD_X86_INSTRUCTION_PREFETCHNTA : (modrm.fields.reg == 0b001 ? NMD_X86_INSTRUCTION_PREFETCHT0 : (modrm.fields.reg == 0b010 ? NMD_X86_INSTRUCTION_PREFETCHT1 : NMD_X86_INSTRUCTION_PREFETCHT2)))); break; case 0x1a: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_BNDMOV : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? NMD_X86_INSTRUCTION_BNDCL : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO ? NMD_X86_INSTRUCTION_BNDCU : NMD_X86_INSTRUCTION_BNDLDX))); break; case 0x1b: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_BNDMOV : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? NMD_X86_INSTRUCTION_BNDMK : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO ? NMD_X86_INSTRUCTION_BNDCN : NMD_X86_INSTRUCTION_BNDSTX))); break; case 0x28: case 0x29: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_MOVAPD : NMD_X86_INSTRUCTION_MOVAPS); break; case 0x2a: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_CVTPI2PD : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? NMD_X86_INSTRUCTION_CVTSI2SS : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO ? NMD_X86_INSTRUCTION_CVTSI2SD : NMD_X86_INSTRUCTION_CVTPI2PS))); break; case 0x2b: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_MOVNTPD : NMD_X86_INSTRUCTION_MOVNTPS); break; case 0x2c: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_CVTTPD2PI : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? NMD_X86_INSTRUCTION_CVTTSS2SI : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO ? NMD_X86_INSTRUCTION_CVTTSS2SI : NMD_X86_INSTRUCTION_CVTTPS2PI))); break; case 0x2d: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_CVTPD2PI : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? NMD_X86_INSTRUCTION_CVTSS2SI : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO ? NMD_X86_INSTRUCTION_CVTSS2SI : NMD_X86_INSTRUCTION_CVTPS2PI))); break; case 0x2e: case 0x2f: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_UCOMISD : NMD_X86_INSTRUCTION_UCOMISS); break; case 0x6e: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && !instruction->rex_w_prefix && (instruction->prefixes & NMD_X86_PREFIXES_REX_W) ? NMD_X86_INSTRUCTION_MOVQ : NMD_X86_INSTRUCTION_MOVD); break; case 0x6f: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_MOVDQA : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? NMD_X86_INSTRUCTION_MOVDQU : NMD_X86_INSTRUCTION_MOVQ)); break; case 0x70: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_PSHUFD : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? NMD_X86_INSTRUCTION_PSHUFHW : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO ? NMD_X86_INSTRUCTION_PSHUFLW : NMD_X86_INSTRUCTION_PSHUFW))); break; case 0x71: instruction->id = (uint16_t)(modrm.fields.reg == 0b101 ? NMD_X86_INSTRUCTION_PSRLQ : (modrm.fields.reg == 0b100 ? NMD_X86_INSTRUCTION_PSRAW : NMD_X86_INSTRUCTION_PSLLW)); break; case 0x72: instruction->id = (uint16_t)(modrm.fields.reg == 0b101 ? NMD_X86_INSTRUCTION_PSRLD : (modrm.fields.reg == 0b100 ? NMD_X86_INSTRUCTION_PSRAD : NMD_X86_INSTRUCTION_PSLLD)); break; case 0x73: instruction->id = (uint16_t)(modrm.fields.reg == 0b010 ? NMD_X86_INSTRUCTION_PSRLQ : (modrm.fields.reg == 0b011 ? NMD_X86_INSTRUCTION_PSRLDQ : (modrm.fields.reg == 0b110 ? NMD_X86_INSTRUCTION_PSLLQ : NMD_X86_INSTRUCTION_PSLLDQ))); break; case 0x78: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_EXTRQ : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO ? NMD_X86_INSTRUCTION_INSERTQ : NMD_X86_INSTRUCTION_VMREAD)); break; case 0x79: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_EXTRQ : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO ? NMD_X86_INSTRUCTION_INSERTQ : NMD_X86_INSTRUCTION_VMWRITE)); break; case 0x7c: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_HADDPD : NMD_X86_INSTRUCTION_HADDPS); break; case 0x7d: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_HSUBPD : NMD_X86_INSTRUCTION_HSUBPS); break; case 0x7e: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT || (instruction->rex_w_prefix && instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) ? NMD_X86_INSTRUCTION_MOVQ : NMD_X86_INSTRUCTION_MOVD); break; case 0x7f: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_MOVDQA : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? NMD_X86_INSTRUCTION_MOVDQU : NMD_X86_INSTRUCTION_MOVQ)); break; case 0x77: instruction->id = NMD_X86_INSTRUCTION_EMMS; break; case 0x0e: instruction->id = NMD_X86_INSTRUCTION_FEMMS; break; case 0xa3: instruction->id = NMD_X86_INSTRUCTION_BT; break; case 0xa4: case 0xa5: instruction->id = NMD_X86_INSTRUCTION_SHLD; break; case 0xaa: instruction->id = NMD_X86_INSTRUCTION_RSM; break; case 0xab: instruction->id = NMD_X86_INSTRUCTION_BTS; break; case 0xac: case 0xad: instruction->id = NMD_X86_INSTRUCTION_SHRD; break; case 0xb6: case 0xb7: instruction->id = NMD_X86_INSTRUCTION_MOVZX; break; case 0xb8: instruction->id = NMD_X86_INSTRUCTION_POPCNT; break; case 0xb9: instruction->id = NMD_X86_INSTRUCTION_UD1; break; case 0xba: instruction->id = (uint16_t)(modrm.fields.reg == 0b100 ? NMD_X86_INSTRUCTION_BT : (modrm.fields.reg == 0b101 ? NMD_X86_INSTRUCTION_BTS : (modrm.fields.reg == 0b110 ? NMD_X86_INSTRUCTION_BTR : NMD_X86_INSTRUCTION_BTC))); break; case 0xbb: instruction->id = NMD_X86_INSTRUCTION_BTC; break; case 0xbc: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? NMD_X86_INSTRUCTION_BSF : NMD_X86_INSTRUCTION_TZCNT); break; case 0xbd: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? NMD_X86_INSTRUCTION_BSR : NMD_X86_INSTRUCTION_LZCNT); break; case 0xbe: case 0xbf: instruction->id = NMD_X86_INSTRUCTION_MOVSX; break; case 0xc0: case 0xc1: instruction->id = NMD_X86_INSTRUCTION_XADD; break; case 0xc2: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_CMPPD : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? NMD_X86_INSTRUCTION_CMPSS : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO ? NMD_X86_INSTRUCTION_CMPSD : NMD_X86_INSTRUCTION_CMPPS))); break; case 0xd0: instruction->id = (uint16_t)(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_INSTRUCTION_ADDSUBPD : NMD_X86_INSTRUCTION_ADDSUBPS); break; case 0xff: instruction->id = NMD_X86_INSTRUCTION_UD0; break; } } } #endif /* NMD_ASSEMBLY_DISABLE_DECODER_INSTRUCTION_ID */ #ifndef NMD_ASSEMBLY_DISABLE_DECODER_CPU_FLAGS if (flags & NMD_X86_DECODER_FLAGS_CPU_FLAGS) { if (_NMD_R(op) == 4 || _NMD_R(op) == 8 || _NMD_R(op) == 9) /* Conditional Move (CMOVcc),Conditional jump(Jcc),Byte set on condition(SETcc) */ _nmd_decode_conditional_flag(instruction, _NMD_C(op)); else if (op == 0x05 || op == 0x07) /* syscall,sysret */ { instruction->cleared_flags.eflags = op == 0x05 ? NMD_X86_EFLAGS_VM | NMD_X86_EFLAGS_RF : NMD_X86_EFLAGS_RF; instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_PF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_TF | NMD_X86_EFLAGS_IF | NMD_X86_EFLAGS_DF | NMD_X86_EFLAGS_OF | NMD_X86_EFLAGS_IOPL | NMD_X86_EFLAGS_NT | NMD_X86_EFLAGS_AC | NMD_X86_EFLAGS_VIF | NMD_X86_EFLAGS_VIP | NMD_X86_EFLAGS_ID; } else if (op == 0x34) /* sysenter */ instruction->cleared_flags.eflags = NMD_X86_EFLAGS_IF | NMD_X86_EFLAGS_RF | NMD_X86_EFLAGS_VM; else if (op == 0xaa) /* rsm */ instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_PF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_TF | NMD_X86_EFLAGS_IF | NMD_X86_EFLAGS_DF | NMD_X86_EFLAGS_OF | NMD_X86_EFLAGS_IOPL | NMD_X86_EFLAGS_NT | NMD_X86_EFLAGS_RF | NMD_X86_EFLAGS_VM | NMD_X86_EFLAGS_AC | NMD_X86_EFLAGS_VIF | NMD_X86_EFLAGS_VIP | NMD_X86_EFLAGS_ID; else if (op == 0xaf) /* mul */ { instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_OF; instruction->undefined_flags.eflags = NMD_X86_EFLAGS_PF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_SF; } else if (op == 0xb0 || op == 0xb1) /* cmpxchg */ instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_PF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_OF; else if (op == 0xc0 || op == 0xc1) /* xadd */ instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_PF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_OF; else if (op == 0x00 && (modrm.fields.reg == 0b100 || modrm.fields.reg == 0b101)) /* verr,verw*/ instruction->modified_flags.eflags = NMD_X86_EFLAGS_OF; else if (op == 0x01 && modrm.fields.mod == 0b11) { if (modrm.fields.reg == 0b000) { if (modrm.fields.rm == 0b001 || modrm.fields.rm == 0b010 || modrm.fields.rm == 0b011) /* vmcall,vmlaunch,vmresume */ { instruction->tested_flags.eflags = NMD_X86_EFLAGS_IOPL | NMD_X86_EFLAGS_VM; instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_PF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_TF | NMD_X86_EFLAGS_IF | NMD_X86_EFLAGS_DF | NMD_X86_EFLAGS_OF | NMD_X86_EFLAGS_IOPL | NMD_X86_EFLAGS_NT | NMD_X86_EFLAGS_RF | NMD_X86_EFLAGS_VM | NMD_X86_EFLAGS_AC | NMD_X86_EFLAGS_VIF | NMD_X86_EFLAGS_VIP | NMD_X86_EFLAGS_ID; } } } else if (op == 0x34) instruction->cleared_flags.eflags = NMD_X86_EFLAGS_VM | NMD_X86_EFLAGS_IF; else if (op == 0x78 || op == 0x79) /* vmread,vmwrite */ { instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_ZF; instruction->cleared_flags.eflags = NMD_X86_EFLAGS_PF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_OF; } else if (op == 0x02 || op == 0x03) /* lar,lsl */ instruction->modified_flags.eflags = NMD_X86_EFLAGS_ZF; else if (op == 0xa3 || op == 0xab || op == 0xb3 || op == 0xba || op == 0xbb) /* bt,bts,btc */ { instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF; instruction->undefined_flags.eflags = NMD_X86_EFLAGS_OF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_PF; } else if (op == 0xa4 || op == 0xa5 || op == 0xac || op == 0xad || op == 0xbc) /* shld,shrd */ { instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_PF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_SF; instruction->undefined_flags.eflags = NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_OF; } else if (op == 0xaa) /* rsm */ instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_PF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_TF | NMD_X86_EFLAGS_IF | NMD_X86_EFLAGS_DF | NMD_X86_EFLAGS_OF | NMD_X86_EFLAGS_IOPL | NMD_X86_EFLAGS_NT | NMD_X86_EFLAGS_RF | NMD_X86_EFLAGS_VM | NMD_X86_EFLAGS_AC | NMD_X86_EFLAGS_VIF | NMD_X86_EFLAGS_VIP | NMD_X86_EFLAGS_ID; else if ((op == 0xbc || op == 0xbd) && instruction->prefixes & NMD_X86_PREFIXES_REPEAT) /* tzcnt */ { instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_ZF; instruction->undefined_flags.eflags = NMD_X86_EFLAGS_PF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_OF; } else if (op == 0xbc || op == 0xbd) /* bsf */ { instruction->modified_flags.eflags = NMD_X86_EFLAGS_ZF; instruction->undefined_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_PF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_OF; } } #endif /* NMD_ASSEMBLY_DISABLE_DECODER_CPU_FLAGS */ #ifndef NMD_ASSEMBLY_DISABLE_DECODER_GROUP /* Parse the instruction's group. */ if (flags & NMD_X86_DECODER_FLAGS_GROUP) { if (_NMD_R(op) == 8) instruction->group = NMD_GROUP_JUMP | NMD_GROUP_CONDITIONAL_BRANCH | NMD_GROUP_RELATIVE_ADDRESSING; else if ((op == 0x01 && modrm.fields.rm == 0b111 && (modrm.fields.mod == 0b00 || modrm.modrm == 0xf8)) || op == 0x06 || op == 0x08 || op == 0x09 || op == 0x30 || op == 0x32 || op == 0x33 || op == 0x35 || op == 0x37) instruction->group = NMD_GROUP_PRIVILEGE; } #endif /* NMD_ASSEMBLY_DISABLE_DECODER_GROUP */ #ifndef NMD_ASSEMBLY_DISABLE_DECODER_OPERANDS if (flags & NMD_X86_DECODER_FLAGS_OPERANDS) { if (op == 0x2 || op == 0x3 || (op >= 0x10 && op <= 0x17) || _NMD_R(op) == 2 || (_NMD_R(op) >= 4 && _NMD_R(op) <= 7 && op != 0x77) || op == 0xa3 || op == 0xab || op == 0xaf || (_NMD_R(op) >= 0xc && op != 0xc7 && op != 0xff)) instruction->num_operands = 2; else if (_NMD_R(op) == 9 || op == 0xc7) instruction->num_operands = 1; else if (op == 0xa4 || op == 0xa5 || op == 0xc2 || (op >= 0xc4 && op <= 0xc6)) instruction->num_operands = 3; if (op == 0x05 || op == 0x07) /* syscall,sysret */ { instruction->num_operands = 5; _NMD_SET_REG_OPERAND(instruction->operands[0], true, NMD_X86_OPERAND_ACTION_WRITE, _NMD_GET_IP()); _NMD_SET_REG_OPERAND(instruction->operands[1], true, op == 0x05 ? NMD_X86_OPERAND_ACTION_WRITE : NMD_X86_OPERAND_ACTION_READ, NMD_X86_REG_RCX); _NMD_SET_REG_OPERAND(instruction->operands[2], true, op == 0x05 ? NMD_X86_OPERAND_ACTION_WRITE : NMD_X86_OPERAND_ACTION_READ, NMD_X86_REG_R11); _NMD_SET_REG_OPERAND(instruction->operands[3], true, NMD_X86_OPERAND_ACTION_WRITE, NMD_X86_REG_CS); _NMD_SET_REG_OPERAND(instruction->operands[4], true, NMD_X86_OPERAND_ACTION_WRITE, NMD_X86_REG_SS); } else if (op == 0x34 || op == 0x35) /* sysenter,sysexit */ { instruction->num_operands = op == 0x34 ? 2 : 4; _NMD_SET_REG_OPERAND(instruction->operands[0], true, NMD_X86_OPERAND_ACTION_WRITE, _NMD_GET_IP()); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_WRITE, _NMD_GET_GPR(NMD_X86_REG_SP)); if (op == 0x35) { _NMD_SET_REG_OPERAND(instruction->operands[2], true, NMD_X86_OPERAND_ACTION_READ, _NMD_GET_GPR(NMD_X86_REG_CX)); _NMD_SET_REG_OPERAND(instruction->operands[3], true, NMD_X86_OPERAND_ACTION_READ, _NMD_GET_GPR(NMD_X86_REG_DX)); } } else if (_NMD_R(op) == 8) /* jCC rel32 */ { instruction->num_operands = 2; _NMD_SET_IMM_OPERAND(instruction->operands[0], false, NMD_X86_OPERAND_ACTION_READ, instruction->immediate); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_IP()); } else if (op == 0x31) /* rdtsc */ { instruction->num_operands = 2; _NMD_SET_REG_OPERAND(instruction->operands[0], true, NMD_X86_OPERAND_ACTION_WRITE, NMD_X86_REG_EAX); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_WRITE, NMD_X86_REG_EDX); } else if (op == 0xa2) /* cpuid */ { instruction->num_operands = 4; _NMD_SET_REG_OPERAND(instruction->operands[0], true, NMD_X86_OPERAND_ACTION_READWRITE, NMD_X86_REG_EAX); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_WRITE, NMD_X86_REG_EBX); _NMD_SET_REG_OPERAND(instruction->operands[2], true, NMD_X86_OPERAND_ACTION_WRITE | NMD_X86_OPERAND_ACTION_CONDREAD, NMD_X86_REG_ECX); _NMD_SET_REG_OPERAND(instruction->operands[3], true, NMD_X86_OPERAND_ACTION_WRITE, NMD_X86_REG_EDX); } else if (op == 0xa0 || op == 0xa8) /* push fs,push gs */ { instruction->num_operands = 3; _NMD_SET_REG_OPERAND(instruction->operands[0], false, NMD_X86_OPERAND_ACTION_READ, op == 0xa0 ? NMD_X86_REG_FS : NMD_X86_REG_GS); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_GPR(NMD_X86_REG_SP)); _NMD_SET_MEM_OPERAND(instruction->operands[2], true, NMD_X86_OPERAND_ACTION_WRITE, NMD_X86_REG_SS, _NMD_GET_GPR(NMD_X86_REG_SP), NMD_X86_REG_NONE, 0, 0); } else if (op == 0x30 || op == 0x32 || op == 0x33) /* wrmsr,rdmsr,rdpmc */ { instruction->num_operands = 3; _NMD_SET_REG_OPERAND(instruction->operands[0], true, op == 0x30 ? NMD_X86_OPERAND_ACTION_READ : NMD_X86_OPERAND_ACTION_WRITE, NMD_X86_REG_EAX); _NMD_SET_REG_OPERAND(instruction->operands[1], true, op == 0x30 ? NMD_X86_OPERAND_ACTION_READ : NMD_X86_OPERAND_ACTION_WRITE, NMD_X86_REG_EDX); _NMD_SET_REG_OPERAND(instruction->operands[2], true, NMD_X86_OPERAND_ACTION_READ, NMD_X86_REG_ECX); } else if (op == 0xa1 || op == 0xa9) /* pop fs,pop gs */ { instruction->num_operands = 3; _NMD_SET_REG_OPERAND(instruction->operands[0], false, NMD_X86_OPERAND_ACTION_WRITE, op == 0xa1 ? NMD_X86_REG_FS : NMD_X86_REG_GS); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_GPR(NMD_X86_REG_SP)); _NMD_SET_MEM_OPERAND(instruction->operands[2], true, NMD_X86_OPERAND_ACTION_READ, NMD_X86_REG_SS, _NMD_GET_GPR(NMD_X86_REG_SP), NMD_X86_REG_NONE, 0, 0); } else if (op == 0x37) /* getsec */ { instruction->num_operands = 2; _NMD_SET_REG_OPERAND(instruction->operands[0], true, NMD_X86_OPERAND_ACTION_READ | NMD_X86_OPERAND_ACTION_CONDWRITE, NMD_X86_REG_EAX); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READ, NMD_X86_REG_EBX); } else if (op == 0xaa) /* rsm */ { instruction->num_operands = 1; _NMD_SET_REG_OPERAND(instruction->operands[0], true, NMD_X86_OPERAND_ACTION_WRITE, _NMD_GET_IP()); } else if (op == 0x00) { if (instruction->modrm.fields.reg >= 0b010) _nmd_decode_operand_Ew(instruction, &instruction->operands[0]); else _nmd_decode_operand_Ev(instruction, &instruction->operands[0]); instruction->operands[0].action = (uint8_t)(instruction->modrm.fields.reg >= 0b010 ? NMD_X86_OPERAND_ACTION_READ : NMD_X86_OPERAND_ACTION_WRITE); } else if (op == 0x01) { if (instruction->modrm.fields.mod != 0b11) { _nmd_decode_modrm_upper32(instruction, &instruction->operands[0]); instruction->operands[0].action = (uint8_t)(instruction->modrm.fields.reg >= 0b010 ? NMD_X86_OPERAND_ACTION_READ : NMD_X86_OPERAND_ACTION_WRITE); } else if (instruction->modrm.fields.reg == 0b100) _nmd_decode_operand_Rv(instruction, &instruction->operands[0]); else if (instruction->modrm.fields.reg == 0b110) { _nmd_decode_operand_Ew(instruction, &instruction->operands[0]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_READ; } if (instruction->modrm.fields.reg == 0b100) instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; } else if (op == 0x02 || op == 0x03) { _nmd_decode_operand_Gv(instruction, &instruction->operands[0]); _nmd_decode_operand_Ew(instruction, &instruction->operands[1]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (op == 0x0d) { _nmd_decode_operand_Ev(instruction, &instruction->operands[0]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_READ; } else if (_NMD_R(op) == 0x8) { instruction->operands[0].type = NMD_X86_OPERAND_TYPE_IMMEDIATE; } else if (_NMD_R(op) == 9) { _nmd_decode_operand_Eb(instruction, &instruction->operands[0]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; } else if (op == 0x17) { _nmd_decode_modrm_upper32(instruction, &instruction->operands[0]); _nmd_decode_operand_Vdq(instruction, &instruction->operands[1]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (op >= 0x20 && op <= 0x23) { instruction->operands[0].type = instruction->operands[1].type = NMD_X86_OPERAND_TYPE_REGISTER; instruction->operands[op < 0x22 ? 0 : 1].fields.reg = NMD_X86_REG_EAX + instruction->modrm.fields.rm; instruction->operands[op < 0x22 ? 1 : 0].fields.reg = (uint8_t)((op % 2 == 0 ? NMD_X86_REG_CR0 : NMD_X86_REG_DR0) + instruction->modrm.fields.reg); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (op == 0x29 || op == 0x2b || (op == 0x7f && instruction->simd_prefix)) { _nmd_decode_operand_Wdq(instruction, &instruction->operands[0]); _nmd_decode_operand_Vdq(instruction, &instruction->operands[1]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (op == 0x2a || op == 0x2c || op == 0x2d) { if (op == 0x2a) _nmd_decode_operand_Vdq(instruction, &instruction->operands[0]); else if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT || instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) _nmd_decode_operand_Gy(instruction, &instruction->operands[0]); else if (op == 0x2d && instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) _nmd_decode_operand_Qq(instruction, &instruction->operands[0]); else _nmd_decode_operand_Pq(instruction, &instruction->operands[0]); if (op == 0x2a) { if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT || instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) _nmd_decode_operand_Ey(instruction, &instruction->operands[1]); else _nmd_decode_operand_Qq(instruction, &instruction->operands[1]); } else _nmd_decode_operand_Wdq(instruction, &instruction->operands[1]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (op == 0x50) { _nmd_decode_operand_Gy(instruction, &instruction->operands[0]); _nmd_decode_operand_Udq(instruction, &instruction->operands[1]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (_NMD_R(op) == 5 || (op >= 0x10 && op <= 0x16) || op == 0x28 || op == 0x2e || op == 0x2f || (op == 0x7e && instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT)) { _nmd_decode_operand_Vdq(instruction, &instruction->operands[op == 0x11 || op == 0x13 ? 1 : 0]); _nmd_decode_operand_Wdq(instruction, &instruction->operands[op == 0x11 || op == 0x13 ? 0 : 1]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (op == 0x7e) { _nmd_decode_operand_Ey(instruction, &instruction->operands[0]); instruction->operands[1].type = NMD_X86_OPERAND_TYPE_REGISTER; instruction->operands[1].fields.reg = (uint8_t)((instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_REG_XMM0 : NMD_X86_REG_MM0) + instruction->modrm.fields.reg); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (_NMD_R(op) == 6 || op == 0x70 || (op >= 0x74 && op <= 0x76) || (op >= 0x7c && op <= 0x7f)) { if (!instruction->simd_prefix) { _nmd_decode_operand_Pq(instruction, &instruction->operands[op == 0x7f ? 1 : 0]); if (op == 0x6e) _nmd_decode_operand_Ey(instruction, &instruction->operands[1]); else _nmd_decode_operand_Qq(instruction, &instruction->operands[op == 0x7f ? 0 : 1]); } else { _nmd_decode_operand_Vdq(instruction, &instruction->operands[0]); if (op == 0x6e) _nmd_decode_operand_Ey(instruction, &instruction->operands[1]); else _nmd_decode_operand_Wdq(instruction, &instruction->operands[1]); } if (op == 0x70) instruction->operands[2].type = NMD_X86_OPERAND_TYPE_IMMEDIATE; instruction->operands[0].action = (uint8_t)(((op >= 0x60 && op <= 0x6d) || (op >= 0x74 && op <= 0x76)) ? NMD_X86_OPERAND_ACTION_READWRITE : NMD_X86_OPERAND_ACTION_WRITE); instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (op >= 0x71 && op <= 0x73) { if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) _nmd_decode_operand_Udq(instruction, &instruction->operands[0]); else _nmd_decode_operand_Qq(instruction, &instruction->operands[0]); instruction->operands[1].type = NMD_X86_OPERAND_TYPE_IMMEDIATE; instruction->operands[0].action = NMD_X86_OPERAND_ACTION_READWRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (op == 0x78 || op == 0x79) { if (instruction->simd_prefix) { if (op == 0x78) { i = 0; if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) _nmd_decode_operand_Vdq(instruction, &instruction->operands[i++]); _nmd_decode_operand_Udq(instruction, &instruction->operands[i + 0]); instruction->operands[i + 1].type = instruction->operands[i + 2].type = NMD_X86_OPERAND_TYPE_IMMEDIATE; /* FIXME: We should not access the buffer from here instruction->operands[i + 1].fields.imm = b[1]; instruction->operands[i + 2].fields.imm = b[2]; */ } else { _nmd_decode_operand_Vdq(instruction, &instruction->operands[0]); _nmd_decode_operand_Wdq(instruction, &instruction->operands[1]); } } else { _nmd_decode_operand_Ey(instruction, &instruction->operands[op == 0x78 ? 0 : 1]); _nmd_decode_operand_Gy(instruction, &instruction->operands[op == 0x78 ? 1 : 0]); } instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (_NMD_R(op) == 0xa && (op % 8) < 2) { instruction->operands[0].type = NMD_X86_OPERAND_TYPE_REGISTER; instruction->operands[0].fields.reg = (uint8_t)(op > 0xa8 ? NMD_X86_REG_GS : NMD_X86_REG_FS); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_READ; } else if ((_NMD_R(op) == 0xa && ((op % 8) >= 3 && (op % 8) <= 5)) || op == 0xb3 || op == 0xbb) { _nmd_decode_operand_Ev(instruction, &instruction->operands[0]); _nmd_decode_operand_Gv(instruction, &instruction->operands[1]); if (_NMD_R(op) == 0xa) { if ((op % 8) == 4) instruction->operands[2].type = NMD_X86_OPERAND_TYPE_IMMEDIATE; else if ((op % 8) == 5) { instruction->operands[2].type = NMD_X86_OPERAND_TYPE_REGISTER; instruction->operands[2].fields.reg = NMD_X86_REG_CL; } } instruction->operands[0].action = NMD_X86_OPERAND_ACTION_READWRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (op == 0xaf || op == 0xb8) { _nmd_decode_operand_Gv(instruction, &instruction->operands[0]); _nmd_decode_operand_Ev(instruction, &instruction->operands[1]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_READWRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (op == 0xba) { _nmd_decode_operand_Ev(instruction, &instruction->operands[0]); instruction->operands[0].action = (uint8_t)(instruction->modrm.fields.reg <= 0b101 ? NMD_X86_OPERAND_ACTION_READ : NMD_X86_OPERAND_ACTION_READWRITE); instruction->operands[1].type = NMD_X86_OPERAND_TYPE_IMMEDIATE; instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (_NMD_R(op) == 0xb && (op % 8) >= 6) { _nmd_decode_operand_Gv(instruction, &instruction->operands[0]); if ((op % 8) == 6) _nmd_decode_operand_Eb(instruction, &instruction->operands[1]); else _nmd_decode_operand_Ew(instruction, &instruction->operands[1]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (_NMD_R(op) == 0x4 || (_NMD_R(op) == 0xb && ((op % 8) == 0x4 || (op % 8) == 0x5))) { _nmd_decode_operand_Gv(instruction, &instruction->operands[0]); _nmd_decode_operand_Ev(instruction, &instruction->operands[1]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if ((_NMD_R(op) == 0xb || _NMD_R(op) == 0xc) && _NMD_C(op) < 2) { if (_NMD_C(op) == 0) { _nmd_decode_operand_Eb(instruction, &instruction->operands[0]); _nmd_decode_operand_Gb(instruction, &instruction->operands[1]); } else { _nmd_decode_operand_Ev(instruction, &instruction->operands[0]); _nmd_decode_operand_Gv(instruction, &instruction->operands[1]); } if (_NMD_R(op) == 0xb) { instruction->operands[0].action = NMD_X86_OPERAND_ACTION_READ | NMD_X86_OPERAND_ACTION_CONDWRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else instruction->operands[0].action = instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READWRITE; } else if (op == 0xb2) { _nmd_decode_operand_Gv(instruction, &instruction->operands[0]); _nmd_decode_modrm_upper32(instruction, &instruction->operands[1]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (op == 0xc3) { _nmd_decode_modrm_upper32(instruction, &instruction->operands[0]); _nmd_decode_operand_Gy(instruction, &instruction->operands[1]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (op == 0xc2 || op == 0xc6) { _nmd_decode_operand_Vdq(instruction, &instruction->operands[0]); _nmd_decode_operand_Wdq(instruction, &instruction->operands[1]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_READWRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; instruction->operands[2].type = NMD_X86_OPERAND_TYPE_IMMEDIATE; } else if (op == 0xc4) { if (instruction->prefixes == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) _nmd_decode_operand_Vdq(instruction, &instruction->operands[0]); else _nmd_decode_operand_Pq(instruction, &instruction->operands[0]); _nmd_decode_operand_Ey(instruction, &instruction->operands[1]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; instruction->operands[2].type = NMD_X86_OPERAND_TYPE_IMMEDIATE; } else if (op == 0xc5) { _nmd_decode_operand_Gd(instruction, &instruction->operands[0]); if (instruction->prefixes == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) _nmd_decode_operand_Udq(instruction, &instruction->operands[1]); else _nmd_decode_operand_Nq(instruction, &instruction->operands[1]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; instruction->operands[2].type = NMD_X86_OPERAND_TYPE_IMMEDIATE; } else if (op == 0xc7) { if (instruction->modrm.fields.mod == 0b11) _nmd_decode_operand_Ev(instruction, &instruction->operands[0]); else _nmd_decode_modrm_upper32(instruction, &instruction->operands[0]); instruction->operands[0].action = (uint8_t)(instruction->modrm.fields.reg == 0b001 ? (NMD_X86_OPERAND_ACTION_READ | NMD_X86_OPERAND_ACTION_CONDWRITE) : (instruction->modrm.fields.mod == 0b11 || !instruction->simd_prefix ? NMD_X86_OPERAND_ACTION_WRITE : NMD_X86_OPERAND_ACTION_READ)); } else if (op >= 0xc8 && op <= 0xcf) { instruction->operands[0].type = NMD_X86_OPERAND_TYPE_REGISTER; instruction->operands[0].fields.reg = (uint8_t)((instruction->prefixes & (NMD_X86_PREFIXES_REX_W | NMD_X86_PREFIXES_REX_B)) == (NMD_X86_PREFIXES_REX_W | NMD_X86_PREFIXES_REX_B) ? NMD_X86_REG_R8 : (instruction->prefixes & NMD_X86_PREFIXES_REX_W ? NMD_X86_REG_RAX : (instruction->prefixes & NMD_X86_PREFIXES_REX_B ? NMD_X86_REG_R8D : NMD_X86_REG_EAX)) + (op % 8)); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_READWRITE; } else if (_NMD_R(op) >= 0xd) { if (op == 0xff) { _nmd_decode_operand_Gd(instruction, &instruction->operands[0]); _nmd_decode_memory_operand(instruction, &instruction->operands[1], NMD_X86_REG_EAX); } else if (op == 0xd6 && instruction->simd_prefix != NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) { if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT) { _nmd_decode_operand_Vdq(instruction, &instruction->operands[0]); _nmd_decode_operand_Qq(instruction, &instruction->operands[1]); } else { _nmd_decode_operand_Pq(instruction, &instruction->operands[0]); _nmd_decode_operand_Wdq(instruction, &instruction->operands[1]); } } else { const size_t first_operand_index = op == 0xe7 || op == 0xd6 ? 1 : 0; const size_t second_operand_index = op == 0xe7 || op == 0xd6 ? 0 : 1; if (!instruction->simd_prefix) { if (op == 0xd7) _nmd_decode_operand_Gd(instruction, &instruction->operands[0]); else _nmd_decode_operand_Pq(instruction, &instruction->operands[first_operand_index]); _nmd_decode_operand_Qq(instruction, &instruction->operands[second_operand_index]); } else { if (op == 0xd7) _nmd_decode_operand_Gd(instruction, &instruction->operands[0]); else _nmd_decode_operand_Vdq(instruction, &instruction->operands[first_operand_index]); _nmd_decode_operand_Wdq(instruction, &instruction->operands[second_operand_index]); } } instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } } #endif /* NMD_ASSEMBLY_DISABLE_DECODER_OPERANDS */ } } else /* 1 byte opcode */ { instruction->opcode_size = 1; instruction->opcode = op; instruction->opcode_map = NMD_X86_OPCODE_MAP_DEFAULT; /* Check for ModR/M, SIB and displacement. */ if (_NMD_R(op) == 8 || _nmd_find_byte(_nmd_op1_modrm, sizeof(_nmd_op1_modrm), op) || (_NMD_R(op) < 4 && (_NMD_C(op) < 4 || (_NMD_C(op) >= 8 && _NMD_C(op) < 0xC))) || (_NMD_R(op) == 0xD && _NMD_C(op) >= 8) /* FIXME: We should not access the buffer directly from here || (remaining_size > 1 && ((nmd_x86_modrm*)(b + 1))->fields.mod != 0b11 && (op == 0xc4 || op == 0xc5 || op == 0x62)) */) { if (!_nmd_decode_modrm(&b, &buffer_size, instruction)) return false; } #ifndef NMD_ASSEMBLY_DISABLE_DECODER_EVEX /* Check if instruction is EVEX. */ if (flags & NMD_X86_DECODER_FLAGS_EVEX && op == 0x62 && !instruction->has_modrm) { instruction->encoding = NMD_X86_ENCODING_EVEX; return false; } #endif /* NMD_ASSEMBLY_DISABLE_DECODER_EVEX */ #if !defined(NMD_ASSEMBLY_DISABLE_DECODER_EVEX) && !defined(NMD_ASSEMBLY_DISABLE_DECODER_VEX) else #endif #ifndef NMD_ASSEMBLY_DISABLE_DECODER_VEX /* Check if instruction is VEX. */ if (flags & NMD_X86_DECODER_FLAGS_VEX && (op == 0xc4 || op == 0xc5) && !instruction->has_modrm) { instruction->encoding = NMD_X86_ENCODING_VEX; instruction->vex.vex[0] = op; uint8_t byte1; _NMD_READ_BYTE(b, buffer_size, byte1); instruction->vex.R = byte1 & 0b10000000; if (instruction->vex.vex[0] == 0xc4) { instruction->vex.X = (byte1 & 0b01000000) == 0b01000000; instruction->vex.B = (byte1 & 0b00100000) == 0b00100000; instruction->vex.m_mmmm = (uint8_t)(byte1 & 0b00011111); uint8_t byte2; _NMD_READ_BYTE(b, buffer_size, byte2); instruction->vex.W = (byte2 & 0b10000000) == 0b10000000; instruction->vex.vvvv = (uint8_t)((byte2 & 0b01111000) >> 3); instruction->vex.L = (byte2 & 0b00000100) == 0b00000100; instruction->vex.pp = (uint8_t)(byte2 & 0b00000011); _NMD_READ_BYTE(b, buffer_size, op); instruction->opcode = op; if (op == 0x0c || op == 0x0d || op == 0x40 || op == 0x41 || op == 0x17 || op == 0x21 || op == 0x42) { instruction->imm_mask = NMD_X86_IMM8; _NMD_READ_BYTE(b, buffer_size, instruction->immediate); } #ifndef NMD_ASSEMBLY_DISABLE_DECODER_VALIDITY_CHECK /* Check if the instruction is invalid. */ if (op == 0x0c && instruction->vex.m_mmmm != 3) return false; #endif /* NMD_ASSEMBLY_DISABLE_DECODER_VALIDITY_CHECK */ #ifndef NMD_ASSEMBLY_DISABLE_DECODER_INSTRUCTION_ID /*if(op == 0x0c) instruction->id = NMD_X86_INSTR */ #endif /* NMD_ASSEMBLY_DISABLE_DECODER_INSTRUCTION_ID */ } else /* 0xc5 */ { instruction->vex.vvvv = (uint8_t)(byte1 & 0b01111000); instruction->vex.L = byte1 & 0b00000100; instruction->vex.pp = (uint8_t)(byte1 & 0b00000011); _NMD_READ_BYTE(b, buffer_size, op); instruction->opcode = op; } if (!_nmd_decode_modrm(&b, &buffer_size, instruction)) return false; } #endif /* NMD_ASSEMBLY_DISABLE_DECODER_VEX */ #if !(defined(NMD_ASSEMBLY_DISABLE_DECODER_EVEX) && defined(NMD_ASSEMBLY_DISABLE_DECODER_VEX)) else #endif { const nmd_x86_modrm modrm = instruction->modrm; #ifndef NMD_ASSEMBLY_DISABLE_DECODER_VALIDITY_CHECK /* Check if the instruction is invalid. */ if (flags & NMD_X86_DECODER_FLAGS_VALIDITY_CHECK) { if (op == 0xC6 || op == 0xC7) { if ((modrm.fields.reg != 0b000 && modrm.fields.reg != 0b111) || (modrm.fields.reg == 0b111 && (modrm.fields.mod != 0b11 || modrm.fields.rm != 0b000))) return false; } else if (op == 0x8f) { if (modrm.fields.reg != 0b000) return false; } else if (op == 0xfe) { if (modrm.fields.reg >= 0b010) return false; } else if (op == 0xff) { if (modrm.fields.reg == 0b111 || (modrm.fields.mod == 0b11 && (modrm.fields.reg == 0b011 || modrm.fields.reg == 0b101))) return false; } else if (op == 0x8c) { if (modrm.fields.reg >= 0b110) return false; } else if (op == 0x8e) { if (modrm.fields.reg == 0b001 || modrm.fields.reg >= 0b110) return false; } else if (op == 0x62) { if (mode == NMD_X86_MODE_64) return false; } else if (op == 0x8d) { if (modrm.fields.mod == 0b11) return false; } else if (op == 0xc4 || op == 0xc5) { if (mode == NMD_X86_MODE_64 && instruction->has_modrm && modrm.fields.mod != 0b11) return false; } else if (op >= 0xd8 && op <= 0xdf) { switch (op) { case 0xd9: if ((modrm.fields.reg == 0b001 && modrm.fields.mod != 0b11) || (modrm.modrm > 0xd0 && modrm.modrm < 0xd8) || modrm.modrm == 0xe2 || modrm.modrm == 0xe3 || modrm.modrm == 0xe6 || modrm.modrm == 0xe7 || modrm.modrm == 0xef) return false; break; case 0xda: if (modrm.modrm >= 0xe0 && modrm.modrm != 0xe9) return false; break; case 0xdb: if (((modrm.fields.reg == 0b100 || modrm.fields.reg == 0b110) && modrm.fields.mod != 0b11) || (modrm.modrm >= 0xe5 && modrm.modrm <= 0xe7) || modrm.modrm >= 0xf8) return false; break; case 0xdd: if ((modrm.fields.reg == 0b101 && modrm.fields.mod != 0b11) || _NMD_R(modrm.modrm) == 0xf) return false; break; case 0xde: if (modrm.modrm == 0xd8 || (modrm.modrm >= 0xda && modrm.modrm <= 0xdf)) return false; break; case 0xdf: if ((modrm.modrm >= 0xe1 && modrm.modrm <= 0xe7) || modrm.modrm >= 0xf8) return false; break; } } else if (mode == NMD_X86_MODE_64) { if (op == 0x6 || op == 0x7 || op == 0xe || op == 0x16 || op == 0x17 || op == 0x1e || op == 0x1f || op == 0x27 || op == 0x2f || op == 0x37 || op == 0x3f || (op >= 0x60 && op <= 0x62) || op == 0x82 || op == 0xce || (op >= 0xd4 && op <= 0xd6)) return false; } } #endif /* NMD_ASSEMBLY_DISABLE_DECODER_VALIDITY_CHECK */ /* Check for immediate */ if (_nmd_find_byte(_nmd_op1_imm32, sizeof(_nmd_op1_imm32), op) || (_NMD_R(op) < 4 && (_NMD_C(op) == 5 || _NMD_C(op) == 0xD)) || (_NMD_R(op) == 0xB && _NMD_C(op) >= 8) || (op == 0xF7 && modrm.fields.reg == 0b000)) /* imm32,16 */ { if (_NMD_R(op) == 0xB && _NMD_C(op) >= 8) instruction->imm_mask = (uint8_t)(instruction->prefixes & NMD_X86_PREFIXES_REX_W ? NMD_X86_IMM64 : (instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE || (mode == NMD_X86_MODE_16 && !(instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE)) ? NMD_X86_IMM16 : NMD_X86_IMM32)); else { if ((mode == NMD_X86_MODE_16 && instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) || (mode != NMD_X86_MODE_16 && !(instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE))) instruction->imm_mask = NMD_X86_IMM32; else instruction->imm_mask = NMD_X86_IMM16; } } else if (_NMD_R(op) == 7 || (_NMD_R(op) == 0xE && _NMD_C(op) < 8) || (_NMD_R(op) == 0xB && _NMD_C(op) < 8) || (_NMD_R(op) < 4 && (_NMD_C(op) == 4 || _NMD_C(op) == 0xC)) || (op == 0xF6 && modrm.fields.reg <= 0b001) || _nmd_find_byte(_nmd_op1_imm8, sizeof(_nmd_op1_imm8), op)) /* imm8 */ instruction->imm_mask = NMD_X86_IMM8; else if (_NMD_R(op) == 0xA && _NMD_C(op) < 4) instruction->imm_mask = (uint8_t)(mode == NMD_X86_MODE_64 ? (instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE ? NMD_X86_IMM32 : NMD_X86_IMM64) : (instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE ? NMD_X86_IMM16 : NMD_X86_IMM32)); else if (op == 0xEA || op == 0x9A) /* imm32,48 */ { if (mode == NMD_X86_MODE_64) return false; instruction->imm_mask = (uint8_t)(instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_IMM32 : NMD_X86_IMM48); } else if (op == 0xC2 || op == 0xCA) /* imm16 */ instruction->imm_mask = NMD_X86_IMM16; else if (op == 0xC8) /* imm16 + imm8 */ instruction->imm_mask = NMD_X86_IMM16 | NMD_X86_IMM8; /* Make sure we can read 'instruction->imm_mask' bytes from the buffer */ if (buffer_size < instruction->imm_mask) return false; /* Copy 'instruction->imm_mask' bytes from the buffer */ for (i = 0; i < instruction->imm_mask; i++) ((uint8_t*)(&instruction->immediate))[i] = b[i]; /* Increment the buffer and decrement the buffer's size */ b += instruction->imm_mask; buffer_size -= instruction->imm_mask; /* Sign extend immediate for specific instructions */ if (op == 0xe9 || op == 0xeb || op == 0xe8 || _NMD_R(op) == 7) { if (instruction->immediate & ((uint64_t)(1) << (instruction->imm_mask * 8 - 1))) instruction->immediate |= 0xffffffffffffffff << (instruction->imm_mask * 8); } else if (op == 0x68 && mode == NMD_X86_MODE_64 && instruction->immediate & ((uint64_t)1<<31)) instruction->immediate |= 0xffffffff00000000; /* These are optional features */ #ifndef NMD_ASSEMBLY_DISABLE_DECODER_INSTRUCTION_ID if (flags & NMD_X86_DECODER_FLAGS_INSTRUCTION_ID) { const bool opszprfx = instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE; if ((op >= 0x88 && op <= 0x8c) || (op >= 0xa0 && op <= 0xa3) || _NMD_R(op) == 0xb || op == 0x8e) instruction->id = NMD_X86_INSTRUCTION_MOV; else if (_NMD_R(op) == 5) instruction->id = (uint16_t)((_NMD_C(op) < 8) ? NMD_X86_INSTRUCTION_PUSH : NMD_X86_INSTRUCTION_POP); else if (_NMD_R(op) < 4 && (op % 8 < 6)) instruction->id = (NMD_X86_INSTRUCTION_ADD + (_NMD_R(op) << 1) + (_NMD_C(op) >= 8 ? 1 : 0)); else if (op >= 0x80 && op <= 0x84) instruction->id = NMD_X86_INSTRUCTION_ADD + modrm.fields.reg; else if (op == 0xe8) instruction->id = NMD_X86_INSTRUCTION_CALL; else if (op == 0xcc) instruction->id = NMD_X86_INSTRUCTION_INT3; else if (op == 0x8d) instruction->id = NMD_X86_INSTRUCTION_LEA; else if (_NMD_R(op) == 4) instruction->id = (uint16_t)((_NMD_C(op) < 8) ? NMD_X86_INSTRUCTION_INC : NMD_X86_INSTRUCTION_DEC); else if (_NMD_R(op) == 7) instruction->id = NMD_X86_INSTRUCTION_JO + _NMD_C(op); else if (op == 0xff) instruction->id = NMD_X86_INSTRUCTION_INC + modrm.fields.reg; else if (op == 0xeb || op == 0xe9) instruction->id = NMD_X86_INSTRUCTION_JMP; else if (op == 0x90) { if (instruction->prefixes & NMD_X86_PREFIXES_REPEAT) instruction->id = NMD_X86_INSTRUCTION_PAUSE; else if (instruction->prefixes & NMD_X86_PREFIXES_REX_B) instruction->id = NMD_X86_INSTRUCTION_XCHG; else instruction->id = NMD_X86_INSTRUCTION_NOP; } else if (op == 0xc3 || op == 0xc2) instruction->id = NMD_X86_INSTRUCTION_RET; else if ((op >= 0x91 && op <= 0x97) || op == 0x86 || op == 0x87) instruction->id = NMD_X86_INSTRUCTION_XCHG; else if (op == 0xc0 || op == 0xc1 || (op >= 0xd0 && op <= 0xd3)) instruction->id = NMD_X86_INSTRUCTION_ROL + modrm.fields.reg; else if (_NMD_R(op) == 0x0f && (op % 8 < 6)) instruction->id = NMD_X86_INSTRUCTION_INT1 + (op - 0xf1); else if (op >= 0xd4 && op <= 0xd7) instruction->id = NMD_X86_INSTRUCTION_AAM + (op - 0xd4); else if (op >= 0xe0 && op <= 0xe3) instruction->id = NMD_X86_INSTRUCTION_LOOPNE + (op - 0xe0); else /* case 0x: instruction->id = NMD_X86_INSTRUCTION_; break; */ { switch (op) { case 0x8f: instruction->id = NMD_X86_INSTRUCTION_POP; break; case 0xfe: instruction->id = (uint16_t)(modrm.fields.reg == 0b000 ? NMD_X86_INSTRUCTION_INC : NMD_X86_INSTRUCTION_DEC); break; case 0x84: case 0x85: case 0xa8: case 0xa9: instruction->id = NMD_X86_INSTRUCTION_TEST; break; case 0xf6: case 0xf7: instruction->id = NMD_X86_INSTRUCTION_TEST + modrm.fields.reg; break; case 0x69: case 0x6b: instruction->id = NMD_X86_INSTRUCTION_IMUL; break; case 0x9a: instruction->id = NMD_X86_INSTRUCTION_CALL; break; case 0x62: instruction->id = NMD_X86_INSTRUCTION_BOUND; break; case 0x63: instruction->id = (uint16_t)(mode == NMD_X86_MODE_64 ? NMD_X86_INSTRUCTION_MOVSXD : NMD_X86_INSTRUCTION_ARPL); break; case 0x68: case 0x6a: case 0x06: case 0x16: case 0x1e: case 0x0e: instruction->id = NMD_X86_INSTRUCTION_PUSH; break; case 0x6c: instruction->id = NMD_X86_INSTRUCTION_INSB; break; case 0x6d: instruction->id = (uint16_t)(opszprfx ? NMD_X86_INSTRUCTION_INSW : NMD_X86_INSTRUCTION_INSD); break; case 0x6e: instruction->id = NMD_X86_INSTRUCTION_OUTSB; break; case 0x6f: instruction->id = (uint16_t)(opszprfx ? NMD_X86_INSTRUCTION_OUTSW : NMD_X86_INSTRUCTION_OUTSD); break; case 0xc4: instruction->id = NMD_X86_INSTRUCTION_LES; break; case 0xc5: instruction->id = NMD_X86_INSTRUCTION_LDS; break; case 0xc6: case 0xc7: instruction->id = (uint16_t)(modrm.fields.reg == 0b000 ? NMD_X86_INSTRUCTION_MOV : (instruction->opcode == 0xc6 ? NMD_X86_INSTRUCTION_XABORT : NMD_X86_INSTRUCTION_XBEGIN)); break; case 0xc8: instruction->id = NMD_X86_INSTRUCTION_ENTER; break; case 0xc9: instruction->id = NMD_X86_INSTRUCTION_LEAVE; break; case 0xca: case 0xcb: instruction->id = NMD_X86_INSTRUCTION_RETF; break; case 0xcd: instruction->id = NMD_X86_INSTRUCTION_INT; break; case 0xce: instruction->id = NMD_X86_INSTRUCTION_INTO; break; case 0xcf: if (instruction->rex_w_prefix) instruction->id = NMD_X86_INSTRUCTION_IRETQ; else if (mode == NMD_X86_MODE_16) instruction->id = (uint16_t)(opszprfx ? NMD_X86_INSTRUCTION_IRETD : NMD_X86_INSTRUCTION_IRET); else instruction->id = (uint16_t)(opszprfx ? NMD_X86_INSTRUCTION_IRET : NMD_X86_INSTRUCTION_IRETD); break; case 0xe4: case 0xe5: case 0xec: case 0xed: instruction->id = NMD_X86_INSTRUCTION_IN; break; case 0xe6: case 0xe7: case 0xee: case 0xef: instruction->id = NMD_X86_INSTRUCTION_OUT; break; case 0xea: instruction->id = NMD_X86_INSTRUCTION_LJMP; break; case 0x9c: if (opszprfx) instruction->id = (uint16_t)(mode == NMD_X86_MODE_16 ? NMD_X86_INSTRUCTION_PUSHFD : NMD_X86_INSTRUCTION_PUSHF); else instruction->id = (uint16_t)(mode == NMD_X86_MODE_16 ? NMD_X86_INSTRUCTION_PUSHF : (mode == NMD_X86_MODE_32 ? NMD_X86_INSTRUCTION_PUSHFD : NMD_X86_INSTRUCTION_PUSHFQ)); break; case 0x9d: if (opszprfx) instruction->id = (uint16_t)(mode == NMD_X86_MODE_16 ? NMD_X86_INSTRUCTION_POPFD : NMD_X86_INSTRUCTION_POPF); else instruction->id = (uint16_t)(mode == NMD_X86_MODE_16 ? NMD_X86_INSTRUCTION_POPF : (mode == NMD_X86_MODE_32 ? NMD_X86_INSTRUCTION_POPFD : NMD_X86_INSTRUCTION_POPFQ)); break; case 0x60: instruction->id = _NMD_GET_BY_MODE_OPSZPRFX(mode, opszprfx, NMD_X86_INSTRUCTION_PUSHA, NMD_X86_INSTRUCTION_PUSHAD); break; case 0x61: instruction->id = _NMD_GET_BY_MODE_OPSZPRFX(mode, opszprfx, NMD_X86_INSTRUCTION_POPA, NMD_X86_INSTRUCTION_POPAD); break; case 0x07: case 0x17: case 0x1f: instruction->id = NMD_X86_INSTRUCTION_POP; break; case 0x27: instruction->id = NMD_X86_INSTRUCTION_DAA; break; case 0x37: instruction->id = NMD_X86_INSTRUCTION_AAA; break; case 0x2f: instruction->id = NMD_X86_INSTRUCTION_DAS; break; case 0x3f: instruction->id = NMD_X86_INSTRUCTION_AAS; break; case 0x9b: instruction->id = NMD_X86_INSTRUCTION_FWAIT; break; case 0x9e: instruction->id = NMD_X86_INSTRUCTION_SAHF; break; case 0x9f: instruction->id = NMD_X86_INSTRUCTION_LAHF; break; case 0xA4: instruction->id = NMD_X86_INSTRUCTION_MOVSB; break; case 0xA5: instruction->id = _NMD_GET_BY_MODE_OPSZPRFX_W64(mode, opszprfx, instruction->rex_w_prefix, NMD_X86_INSTRUCTION_MOVSW, NMD_X86_INSTRUCTION_MOVSD, NMD_X86_INSTRUCTION_MOVSQ); break; /*(uint16_t)(instruction->rex_w_prefix ? NMD_X86_INSTRUCTION_MOVSQ : (opszprfx ? NMD_X86_INSTRUCTION_MOVSW : NMD_X86_INSTRUCTION_MOVSD)); break;*/ case 0xA6: instruction->id = NMD_X86_INSTRUCTION_CMPSB; break; case 0xA7: instruction->id = _NMD_GET_BY_MODE_OPSZPRFX_W64(mode, opszprfx, instruction->rex_w_prefix, NMD_X86_INSTRUCTION_CMPSW, NMD_X86_INSTRUCTION_CMPSD, NMD_X86_INSTRUCTION_CMPSQ); break; case 0xAA: instruction->id = NMD_X86_INSTRUCTION_STOSB; break; case 0xAB: instruction->id = _NMD_GET_BY_MODE_OPSZPRFX_W64(mode, opszprfx, instruction->rex_w_prefix, NMD_X86_INSTRUCTION_STOSW, NMD_X86_INSTRUCTION_STOSD, NMD_X86_INSTRUCTION_STOSQ); break; case 0xAC: instruction->id = NMD_X86_INSTRUCTION_LODSB; break; case 0xAD: instruction->id = _NMD_GET_BY_MODE_OPSZPRFX_W64(mode, opszprfx, instruction->rex_w_prefix, NMD_X86_INSTRUCTION_LODSW, NMD_X86_INSTRUCTION_LODSD, NMD_X86_INSTRUCTION_LODSQ); break; case 0xAE: instruction->id = NMD_X86_INSTRUCTION_SCASB; break; case 0xAF: instruction->id = _NMD_GET_BY_MODE_OPSZPRFX_W64(mode, opszprfx, instruction->rex_w_prefix, NMD_X86_INSTRUCTION_SCASW, NMD_X86_INSTRUCTION_SCASD, NMD_X86_INSTRUCTION_SCASQ); break; case 0x98: if(instruction->prefixes & NMD_X86_PREFIXES_REX_W) instruction->id = (uint16_t)NMD_X86_INSTRUCTION_CDQE; else if(instruction->mode == NMD_X86_MODE_16) instruction->id = (uint16_t)(opszprfx ? NMD_X86_INSTRUCTION_CWDE : NMD_X86_INSTRUCTION_CBW); else instruction->id = (uint16_t)(opszprfx ? NMD_X86_INSTRUCTION_CBW : NMD_X86_INSTRUCTION_CWDE); break; case 0x99: if (instruction->prefixes & NMD_X86_PREFIXES_REX_W) instruction->id = (uint16_t)NMD_X86_INSTRUCTION_CQO; else if (instruction->mode == NMD_X86_MODE_16) instruction->id = (uint16_t)(opszprfx ? NMD_X86_INSTRUCTION_CDQ : NMD_X86_INSTRUCTION_CWD); else instruction->id = (uint16_t)(opszprfx ? NMD_X86_INSTRUCTION_CWD : NMD_X86_INSTRUCTION_CDQ); break; /* Floating-point opcodes. */ #define _NMD_F_OP_GET_OFFSET() ((_NMD_R(modrm.modrm) - 0xc) << 1) + (_NMD_C(op) >= 8 ? 1 : 0) case 0xd8: instruction->id = (NMD_X86_INSTRUCTION_FADD + (modrm.fields.mod == 0b11 ? _NMD_F_OP_GET_OFFSET() : modrm.fields.reg)); break; case 0xd9: if (modrm.fields.mod == 0b11) { if (modrm.modrm <= 0xcf) instruction->id = (uint16_t)(modrm.modrm <= 0xc7 ? NMD_X86_INSTRUCTION_FLD : NMD_X86_INSTRUCTION_FXCH); else if (modrm.modrm >= 0xd8 && modrm.modrm <= 0xdf) instruction->id = NMD_X86_INSTRUCTION_FSTPNCE; else if (modrm.modrm == 0xd0) instruction->id = NMD_X86_INSTRUCTION_FNOP; else instruction->id = NMD_X86_INSTRUCTION_FCHS + (modrm.modrm - 0xe0); } else instruction->id = NMD_X86_INSTRUCTION_FLD + modrm.fields.reg; break; case 0xda: if (modrm.fields.mod == 0b11) instruction->id = ((modrm.modrm == 0xe9) ? NMD_X86_INSTRUCTION_FUCOMPP : NMD_X86_INSTRUCTION_FCMOVB + _NMD_F_OP_GET_OFFSET()); else instruction->id = NMD_X86_INSTRUCTION_FIADD + modrm.fields.reg; break; case 0xdb: if (modrm.fields.mod == 0b11) instruction->id = (modrm.modrm == 0xe2 ? NMD_X86_INSTRUCTION_FNCLEX : (modrm.modrm == 0xe2 ? NMD_X86_INSTRUCTION_FNINIT : NMD_X86_INSTRUCTION_FCMOVNB + _NMD_F_OP_GET_OFFSET())); else instruction->id = (modrm.fields.reg == 0b101 ? NMD_X86_INSTRUCTION_FLD : (modrm.fields.reg == 0b111 ? NMD_X86_INSTRUCTION_FSTP : NMD_X86_INSTRUCTION_FILD + modrm.fields.reg)); break; case 0xdc: if (modrm.fields.mod == 0b11) instruction->id = (NMD_X86_INSTRUCTION_FADD + ((_NMD_R(modrm.modrm) - 0xc) << 1) + ((_NMD_C(modrm.modrm) >= 8 && _NMD_R(modrm.modrm) <= 0xd) ? 1 : 0)); else instruction->id = NMD_X86_INSTRUCTION_FADD + modrm.fields.reg; break; case 0xdd: if (modrm.fields.mod == 0b11) { switch ((modrm.modrm - 0xc0) >> 3) { case 0b000: instruction->id = NMD_X86_INSTRUCTION_FFREE; break; case 0b001: instruction->id = NMD_X86_INSTRUCTION_FXCH; break; case 0b010: instruction->id = NMD_X86_INSTRUCTION_FST; break; case 0b011: instruction->id = NMD_X86_INSTRUCTION_FSTP; break; case 0b100: instruction->id = NMD_X86_INSTRUCTION_FUCOM; break; case 0b101: instruction->id = NMD_X86_INSTRUCTION_FUCOMP; break; } } else { switch (modrm.fields.reg) { case 0b000: instruction->id = NMD_X86_INSTRUCTION_FLD; break; case 0b001: instruction->id = NMD_X86_INSTRUCTION_FISTTP; break; case 0b010: instruction->id = NMD_X86_INSTRUCTION_FST; break; case 0b011: instruction->id = NMD_X86_INSTRUCTION_FSTP; break; case 0b100: instruction->id = NMD_X86_INSTRUCTION_FRSTOR; break; case 0b110: instruction->id = NMD_X86_INSTRUCTION_FNSAVE; break; case 0b111: instruction->id = NMD_X86_INSTRUCTION_FNSTSW; break; } } break; case 0xde: if (modrm.fields.mod == 0b11) instruction->id = (modrm.modrm == 0xd9 ? NMD_X86_INSTRUCTION_FCOMPP : ((modrm.modrm >= 0xd0 && modrm.modrm <= 0xd7) ? NMD_X86_INSTRUCTION_FCOMP : NMD_X86_INSTRUCTION_FADDP + _NMD_F_OP_GET_OFFSET())); else instruction->id = NMD_X86_INSTRUCTION_FIADD + modrm.fields.reg; break; case 0xdf: if (modrm.fields.mod == 0b11) { if (modrm.fields.reg == 0b000) instruction->id = NMD_X86_INSTRUCTION_FFREEP; else if (modrm.fields.reg == 0b001) instruction->id = NMD_X86_INSTRUCTION_FXCH; else if (modrm.fields.reg <= 3) instruction->id = NMD_X86_INSTRUCTION_FSTP; else if (modrm.modrm == 0xe0) instruction->id = NMD_X86_INSTRUCTION_FNSTSW; else if (modrm.fields.reg == 0b110) instruction->id = NMD_X86_INSTRUCTION_FCOMIP; else instruction->id = NMD_X86_INSTRUCTION_FUCOMIP; } else instruction->id = (modrm.fields.reg == 0b101 ? NMD_X86_INSTRUCTION_FILD : (modrm.fields.reg == 0b111 ? NMD_X86_INSTRUCTION_FISTP : (NMD_X86_INSTRUCTION_FILD + modrm.fields.reg))); break; } } } #endif /* NMD_ASSEMBLY_DISABLE_DECODER_INSTRUCTION_ID */ #ifndef NMD_ASSEMBLY_DISABLE_DECODER_CPU_FLAGS if (flags & NMD_X86_DECODER_FLAGS_CPU_FLAGS) { if (op == 0xcc || op == 0xcd) /* int3,int n */ { instruction->cleared_flags.eflags = NMD_X86_EFLAGS_TF | NMD_X86_EFLAGS_RF; instruction->tested_flags.eflags = NMD_X86_EFLAGS_IOPL | NMD_X86_EFLAGS_VM; instruction->modified_flags.eflags = NMD_X86_EFLAGS_IF | NMD_X86_EFLAGS_NT | NMD_X86_EFLAGS_VM | NMD_X86_EFLAGS_AC | NMD_X86_EFLAGS_VIF; } else if (op == 0xce) /* into */ { instruction->cleared_flags.eflags = NMD_X86_EFLAGS_RF; instruction->tested_flags.eflags = NMD_X86_EFLAGS_OF | NMD_X86_EFLAGS_IOPL | NMD_X86_EFLAGS_VM; instruction->modified_flags.eflags = NMD_X86_EFLAGS_TF | NMD_X86_EFLAGS_IF | NMD_X86_EFLAGS_NT | NMD_X86_EFLAGS_VM | NMD_X86_EFLAGS_AC; } else if (_NMD_R(op) == 7) /* conditional jump */ _nmd_decode_conditional_flag(instruction, _NMD_C(op)); else if (_NMD_R(op) == 4 || ((op == 0xfe || op == 0xff) && modrm.fields.reg <= 0b001)) /* inc,dec */ instruction->modified_flags.eflags = NMD_X86_EFLAGS_OF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_PF; else if (op <= 0x05 || (op >= 0x10 && op <= 0x15) || ((_NMD_R(op) == 1 || _NMD_R(op) == 2 || _NMD_R(op) == 3) && (_NMD_C(op) >= 0x8 && _NMD_C(op) <= 0x0d)) || ((op >= 0x80 && op <= 0x83) && (modrm.fields.reg == 0b000 || modrm.fields.reg == 0b010 || modrm.fields.reg == 0b011 || modrm.fields.reg == 0b010 || modrm.fields.reg == 0b101 || modrm.fields.reg == 0b111)) || (op == 0xa6 || op == 0xa7) || (op == 0xae || op == 0xaf)) /* add,adc,sbb,sub,cmp, cmps,cmpsb,cmpsw,cmpsd,cmpsq, scas,scasb,scasw,scasd */ instruction->modified_flags.eflags = NMD_X86_EFLAGS_OF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_PF; else if (op == 0x9c) /* pushf,pushfd,pushfq */ instruction->tested_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_PF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_TF | NMD_X86_EFLAGS_IF | NMD_X86_EFLAGS_DF | NMD_X86_EFLAGS_OF | NMD_X86_EFLAGS_IOPL | NMD_X86_EFLAGS_NT | NMD_X86_EFLAGS_RF | NMD_X86_EFLAGS_VM | NMD_X86_EFLAGS_AC | NMD_X86_EFLAGS_VIF | NMD_X86_EFLAGS_VIP | NMD_X86_EFLAGS_ID; else if (op == 0x9d) /* popf,popfd,popfq */ { instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_PF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_TF | NMD_X86_EFLAGS_IF | NMD_X86_EFLAGS_DF | NMD_X86_EFLAGS_OF | NMD_X86_EFLAGS_IOPL | NMD_X86_EFLAGS_NT | NMD_X86_EFLAGS_AC | NMD_X86_EFLAGS_VIF | NMD_X86_EFLAGS_ID; instruction->tested_flags.eflags = NMD_X86_EFLAGS_IOPL | NMD_X86_EFLAGS_VM | NMD_X86_EFLAGS_VIP; instruction->cleared_flags.eflags = NMD_X86_EFLAGS_RF; } else if (op == 0xcf) /* iret,iretd,iretf */ { instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_PF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_TF | NMD_X86_EFLAGS_IF | NMD_X86_EFLAGS_DF | NMD_X86_EFLAGS_OF | NMD_X86_EFLAGS_IOPL | NMD_X86_EFLAGS_NT | NMD_X86_EFLAGS_RF | NMD_X86_EFLAGS_VM | NMD_X86_EFLAGS_AC | NMD_X86_EFLAGS_VIF | NMD_X86_EFLAGS_VIP | NMD_X86_EFLAGS_ID; instruction->tested_flags.eflags = NMD_X86_EFLAGS_IOPL | NMD_X86_EFLAGS_NT | NMD_X86_EFLAGS_VM; } else if ((op >= 0x08 && op <= 0x0d) || ((_NMD_R(op) == 2 || _NMD_R(op) == 3) && _NMD_C(op) <= 5) || ((op >= 0x80 && op <= 0x83) && (modrm.fields.reg == 0b001 || modrm.fields.reg == 0b100 || modrm.fields.reg == 0b110)) || (op == 0x84 || op == 0x85 || op == 0xa8 || op == 0xa9) || ((op == 0xf6 || op == 0xf7) && modrm.fields.reg == 0b000)) /* or,and,xor, test */ { instruction->cleared_flags.eflags = NMD_X86_EFLAGS_OF | NMD_X86_EFLAGS_CF; instruction->undefined_flags.eflags = NMD_X86_EFLAGS_AF; instruction->modified_flags.eflags = NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_PF; } else if (op == 0x69 || op == 0x6b || ((op == 0xf6 || op == 0xf7) && (modrm.fields.reg == 0b100 || modrm.fields.reg == 0b101))) /* mul,imul */ { instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_OF; instruction->undefined_flags.eflags = NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_PF; } else if (op == 0xf6 || op == 0xf7) /* Group 3 */ { if (modrm.fields.reg == 0b011) /* neg */ instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_PF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_OF; else if (modrm.fields.reg >= 0b110) /* div,idiv */ instruction->undefined_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_OF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_PF; } else if (op == 0xc0 || op == 0xc1 || (op >= 0xd0 && op <= 0xd3)) { if (modrm.fields.reg <= 0b011) /* rol,ror,rcl,rcr */ { instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF; instruction->undefined_flags.eflags = NMD_X86_EFLAGS_OF; } else /* shl,shr,sar */ { instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_PF | NMD_X86_EFLAGS_OF; instruction->undefined_flags.eflags = NMD_X86_EFLAGS_AF; } } else if (op == 0x27 || op == 0x2f) /* daa,das */ { instruction->tested_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_AF; instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_PF; instruction->undefined_flags.eflags = NMD_X86_EFLAGS_OF; } else if (op == 0x37 || op == 0x3f) /* aaa,aas */ { instruction->tested_flags.eflags = NMD_X86_EFLAGS_AF; instruction->modified_flags.eflags = NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_CF; instruction->undefined_flags.eflags = NMD_X86_EFLAGS_OF | NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_PF; } else if (op == 0x63 && mode != NMD_X86_MODE_64) /* arpl */ instruction->modified_flags.eflags = NMD_X86_EFLAGS_ZF; else if (op == 0x9b) /* fwait,wait */ instruction->undefined_flags.fpu_flags = NMD_X86_FPU_FLAGS_C0 | NMD_X86_FPU_FLAGS_C1 | NMD_X86_FPU_FLAGS_C2 | NMD_X86_FPU_FLAGS_C3; else if (op == 0x9e) /* sahf */ instruction->modified_flags.eflags = NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_PF | NMD_X86_EFLAGS_CF; else if (op == 0x9f) /* lahf */ instruction->tested_flags.eflags = NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_PF | NMD_X86_EFLAGS_CF; else if (op == 0xd4 || op == 0xd5) /* aam,aad */ { instruction->modified_flags.eflags = NMD_X86_EFLAGS_SF | NMD_X86_EFLAGS_ZF | NMD_X86_EFLAGS_PF; instruction->undefined_flags.eflags = NMD_X86_EFLAGS_OF | NMD_X86_EFLAGS_AF | NMD_X86_EFLAGS_CF; } else if (op == 0xd6) /* salc */ instruction->tested_flags.eflags = NMD_X86_EFLAGS_CF; else if (op >= 0xd8 && op <= 0xdf) /* escape opcodes */ { if (op == 0xd8 || op == 0xdc) { if (modrm.fields.reg == 0b000 || modrm.fields.reg == 0b001 || modrm.fields.reg == 0b100 || modrm.fields.reg == 0b101 || modrm.fields.reg == 0b110 || modrm.fields.reg == 0b111) /* fadd,fmul,fsub,fsubr,fdiv,fdivr */ { instruction->modified_flags.fpu_flags = NMD_X86_FPU_FLAGS_C1; instruction->undefined_flags.fpu_flags = NMD_X86_FPU_FLAGS_C0 | NMD_X86_FPU_FLAGS_C2 | NMD_X86_FPU_FLAGS_C3; } else if (modrm.fields.reg == 0b010 || modrm.fields.reg == 0b011) /* fcom,fcomp */ { instruction->modified_flags.fpu_flags = NMD_X86_FPU_FLAGS_C0 | NMD_X86_FPU_FLAGS_C2 | NMD_X86_FPU_FLAGS_C3; instruction->cleared_flags.fpu_flags = NMD_X86_FPU_FLAGS_C1; } } else if (op == 0xd9) { if (modrm.fields.mod != 0b11) { if (modrm.fields.reg == 0b000 || modrm.fields.reg == 0b010 || modrm.fields.reg == 0b011) /* fld,fst,fstp */ { instruction->modified_flags.fpu_flags = NMD_X86_FPU_FLAGS_C1; instruction->undefined_flags.fpu_flags = NMD_X86_FPU_FLAGS_C0 | NMD_X86_FPU_FLAGS_C2 | NMD_X86_FPU_FLAGS_C3; } else if (modrm.fields.reg == 0b100) /* fldenv */ instruction->modified_flags.fpu_flags = NMD_X86_FPU_FLAGS_C0 | NMD_X86_FPU_FLAGS_C1 | NMD_X86_FPU_FLAGS_C2 | NMD_X86_FPU_FLAGS_C3; else if (modrm.fields.reg == 0b101 || modrm.fields.reg == 0b110 || modrm.fields.reg == 0b111) /* fldcw,fstenv,fstcw */ instruction->undefined_flags.fpu_flags = NMD_X86_FPU_FLAGS_C0 | NMD_X86_FPU_FLAGS_C1 | NMD_X86_FPU_FLAGS_C2 | NMD_X86_FPU_FLAGS_C3; } else { if (modrm.modrm < 0xc8) /* fld */ { instruction->modified_flags.fpu_flags = NMD_X86_FPU_FLAGS_C1; instruction->undefined_flags.fpu_flags = NMD_X86_FPU_FLAGS_C0 | NMD_X86_FPU_FLAGS_C2 | NMD_X86_FPU_FLAGS_C3; } else /*if (modrm.modrm <= 0xcf)*/ /* fxch */ { instruction->cleared_flags.fpu_flags = NMD_X86_FPU_FLAGS_C1; instruction->undefined_flags.fpu_flags = NMD_X86_FPU_FLAGS_C0 | NMD_X86_FPU_FLAGS_C2 | NMD_X86_FPU_FLAGS_C3; } } } else if (op == 0xda || op == 0xde) { if (modrm.fields.mod != 0b11) { if (modrm.fields.reg == 0b000 || modrm.fields.reg == 0b001 || modrm.fields.reg == 0b100 || modrm.fields.reg == 0b101 || modrm.fields.reg == 0b110 || modrm.fields.reg == 0b111) /* fiadd,fimul,fisub,fisubr,fidiv,fidivr */ { instruction->modified_flags.fpu_flags = NMD_X86_FPU_FLAGS_C1; instruction->undefined_flags.fpu_flags = NMD_X86_FPU_FLAGS_C0 | NMD_X86_FPU_FLAGS_C2 | NMD_X86_FPU_FLAGS_C3; } else /*if (modrm.fields.reg == 0b010 || modrm.fields.reg == 0b011)*/ /* ficom,ficomp */ { instruction->cleared_flags.fpu_flags = NMD_X86_FPU_FLAGS_C1; instruction->modified_flags.fpu_flags = NMD_X86_FPU_FLAGS_C0 | NMD_X86_FPU_FLAGS_C2 | NMD_X86_FPU_FLAGS_C3; } } else { if ((op == 0xda && modrm.modrm == 0xe9) || (op == 0xde && modrm.modrm == 0xd9)) instruction->modified_flags.fpu_flags = NMD_X86_FPU_FLAGS_C0 | NMD_X86_FPU_FLAGS_C1 | NMD_X86_FPU_FLAGS_C2 | NMD_X86_FPU_FLAGS_C3; else { instruction->modified_flags.fpu_flags = NMD_X86_FPU_FLAGS_C1; instruction->undefined_flags.fpu_flags = NMD_X86_FPU_FLAGS_C0 | NMD_X86_FPU_FLAGS_C2 | NMD_X86_FPU_FLAGS_C3; } } } else if (op == 0xdb || op == 0xdd || op == 0xdf) { if (modrm.fields.mod != 0b11) { if (modrm.fields.reg == 0b000 || modrm.fields.reg == 0b010 || modrm.fields.reg == 0b011 || modrm.fields.reg == 0b101 || modrm.fields.reg == 0b111) /* fild,fist,fistp,fld,fstp */ { instruction->modified_flags.fpu_flags = NMD_X86_FPU_FLAGS_C1; instruction->undefined_flags.fpu_flags = NMD_X86_FPU_FLAGS_C0 | NMD_X86_FPU_FLAGS_C2 | NMD_X86_FPU_FLAGS_C3; } else if (modrm.fields.reg == 0b001) /* fisttp */ { instruction->cleared_flags.fpu_flags = NMD_X86_FPU_FLAGS_C1; instruction->undefined_flags.fpu_flags = NMD_X86_FPU_FLAGS_C0 | NMD_X86_FPU_FLAGS_C2 | NMD_X86_FPU_FLAGS_C3; } } else { if (modrm.fields.reg <= 0b011) /* fcmovnb,fcmovne,fcmovnbe,fcmovnu */ { instruction->modified_flags.fpu_flags = NMD_X86_FPU_FLAGS_C1; instruction->undefined_flags.fpu_flags = NMD_X86_FPU_FLAGS_C0 | NMD_X86_FPU_FLAGS_C2 | NMD_X86_FPU_FLAGS_C3; } else if (modrm.modrm == 0xe0 || modrm.modrm == 0xe2) /* fstsw,fclex */ instruction->undefined_flags.fpu_flags = NMD_X86_FPU_FLAGS_C0 | NMD_X86_FPU_FLAGS_C1 | NMD_X86_FPU_FLAGS_C2 | NMD_X86_FPU_FLAGS_C3; else if (modrm.modrm == 0xe3) /* finit */ instruction->cleared_flags.fpu_flags = NMD_X86_FPU_FLAGS_C0 | NMD_X86_FPU_FLAGS_C1 | NMD_X86_FPU_FLAGS_C2 | NMD_X86_FPU_FLAGS_C3; else /* fucomi,fcomi */ { instruction->cleared_flags.fpu_flags = NMD_X86_FPU_FLAGS_C1; instruction->undefined_flags.fpu_flags = NMD_X86_FPU_FLAGS_C0 | NMD_X86_FPU_FLAGS_C2 | NMD_X86_FPU_FLAGS_C3; } } } } else if (op == 0xf5) /* cmc */ { instruction->modified_flags.eflags = NMD_X86_EFLAGS_CF; instruction->tested_flags.eflags = NMD_X86_EFLAGS_CF; } else if (op == 0xf8) /* clc */ instruction->cleared_flags.eflags = NMD_X86_EFLAGS_CF; else if (op == 0xf9) /* stc */ instruction->set_flags.eflags = NMD_X86_EFLAGS_CF; else if (op == 0xfa || op == 0xfb) /* cli,sti */ { instruction->modified_flags.eflags = NMD_X86_EFLAGS_IF | NMD_X86_EFLAGS_VIF; instruction->tested_flags.eflags = NMD_X86_EFLAGS_IOPL; } else if (op == 0xfc) /* cld */ instruction->cleared_flags.eflags = NMD_X86_EFLAGS_DF; else if (op == 0xfd) /* std */ instruction->set_flags.eflags = NMD_X86_EFLAGS_DF; } #endif /* NMD_ASSEMBLY_DISABLE_DECODER_CPU_FLAGS */ #ifndef NMD_ASSEMBLY_DISABLE_DECODER_GROUP /* Parse the instruction's group. */ if (flags & NMD_X86_DECODER_FLAGS_GROUP) { if (_NMD_R(op) == 7 || op == 0xe3) instruction->group = NMD_GROUP_JUMP | NMD_GROUP_CONDITIONAL_BRANCH | NMD_GROUP_RELATIVE_ADDRESSING; else if (op == 0xe9 || op == 0xea || op == 0xeb || (op == 0xff && (modrm.fields.reg == 0b100 || modrm.fields.reg == 0b101))) instruction->group = NMD_GROUP_JUMP | NMD_GROUP_UNCONDITIONAL_BRANCH | (op == 0xe9 || op == 0xeb ? NMD_GROUP_RELATIVE_ADDRESSING : 0); else if (op == 0x9a || op == 0xe8 || (op == 0xff && (modrm.fields.reg == 0b010 || modrm.fields.reg == 0b011))) instruction->group = NMD_GROUP_CALL | NMD_GROUP_UNCONDITIONAL_BRANCH | (op == 0xe8 ? NMD_GROUP_RELATIVE_ADDRESSING : 0); else if (op == 0xc2 || op == 0xc3 || op == 0xca || op == 0xcb) instruction->group = NMD_GROUP_RET; else if ((op >= 0xcc && op <= 0xce) || op == 0xf1) instruction->group = NMD_GROUP_INT; else if (op == 0xf4) instruction->group = NMD_GROUP_PRIVILEGE; else if (op == 0xc7 && modrm.modrm == 0xf8) instruction->group = NMD_GROUP_UNCONDITIONAL_BRANCH | NMD_GROUP_RELATIVE_ADDRESSING; else if (op >= 0xe0 && op <= 0xe2) instruction->group = NMD_GROUP_CONDITIONAL_BRANCH | NMD_GROUP_RELATIVE_ADDRESSING; else if (op == 0x8d && mode == NMD_X86_MODE_64) instruction->group = NMD_GROUP_RELATIVE_ADDRESSING; else if(op == 0xcf) instruction->group = NMD_GROUP_RET | NMD_GROUP_INT; } #endif /* NMD_ASSEMBLY_DISABLE_DECODER_GROUP */ #ifndef NMD_ASSEMBLY_DISABLE_DECODER_OPERANDS if (flags & NMD_X86_DECODER_FLAGS_OPERANDS) { if (op >= 0xd8 && op <= 0xdf) { if (modrm.fields.mod == 0b11) { if ((op == 0xd9 && (_NMD_R(modrm.modrm) == 0xc || (op >= 0xc8 && op <= 0xcf))) || (op == 0xda && _NMD_R(modrm.modrm) <= 0xd) || (op == 0xdb && (_NMD_R(modrm.modrm) <= 0xd || modrm.modrm >= 0xe8)) || (op == 0xde && modrm.modrm != 0xd9) || (op == 0xdf && modrm.modrm != 0xe0)) instruction->num_operands = 2; } else instruction->num_operands = 1; } else if ((_NMD_R(op) < 4 && op % 8 <= 5) || (_NMD_R(op) >= 8 && _NMD_R(op) <= 0xa && op != 0x8f && op != 0x90 && !(op >= 0x98 && op <= 0x9f)) || op == 0x62 || op == 0x63 || (op >= 0x6c && op <= 0x6f) || op == 0xc0 || op == 0xc1 || (op >= 0xc4 && op <= 0xc8) || (op >= 0xd0 && op <= 0xd3) || (_NMD_R(op) == 0xe && op % 8 >= 4)) instruction->num_operands = 2; else if (_NMD_R(op) == 4 || op == 0x8f || op == 0x9a || op == 0xd4 || op == 0xd5 || (_NMD_R(op) == 0xe && op % 8 <= 3 && op != 0xe9)) instruction->num_operands = 1; else if (op == 0x69 || op == 0x6b) instruction->num_operands = 3; const bool opszprfx = instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE; if (_NMD_R(op) == 0xb) /* mov reg,imm */ { instruction->num_operands = 2; _NMD_SET_REG_OPERAND(instruction->operands[0], false, NMD_X86_OPERAND_ACTION_WRITE, (op < 0xb8 ? (instruction->prefixes & NMD_X86_PREFIXES_REX_B ? NMD_X86_REG_R8B : NMD_X86_REG_AL) : (instruction->prefixes & NMD_X86_PREFIXES_REX_W ? (instruction->prefixes & NMD_X86_PREFIXES_REX_B ? NMD_X86_REG_R8 : NMD_X86_REG_RAX) : (instruction->prefixes & NMD_X86_PREFIXES_REX_B ? NMD_X86_REG_R8D : NMD_X86_REG_EAX))) + op % 8); _NMD_SET_IMM_OPERAND(instruction->operands[1], false, NMD_X86_OPERAND_ACTION_READ, instruction->immediate); } else if (_NMD_R(op) == 5) /* push reg,pop reg */ { instruction->num_operands = 3; _NMD_SET_REG_OPERAND(instruction->operands[0], false, _NMD_C(op) < 8 ? NMD_X86_OPERAND_ACTION_READ : NMD_X86_OPERAND_ACTION_WRITE, (instruction->prefixes & NMD_X86_PREFIXES_REX_B ? (opszprfx ? NMD_X86_REG_R8W : NMD_X86_REG_R8) : (opszprfx ? (instruction->mode == NMD_X86_MODE_16 ? NMD_X86_REG_EAX : NMD_X86_REG_AX) : (NMD_X86_REG_AX + (instruction->mode >> 2) * 8))) + (op % 8)); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_GPR(NMD_X86_REG_SP)); _NMD_SET_MEM_OPERAND(instruction->operands[2], true, _NMD_C(op) < 8 ? NMD_X86_OPERAND_ACTION_WRITE : NMD_X86_OPERAND_ACTION_READ, NMD_X86_REG_SS, _NMD_GET_GPR(NMD_X86_REG_SP), NMD_X86_REG_NONE, 0, 0); } else if (_NMD_R(op) == 7) /* jCC */ { instruction->num_operands = 2; _NMD_SET_IMM_OPERAND(instruction->operands[0], false, NMD_X86_OPERAND_ACTION_READ, instruction->immediate); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_IP()); } else if (op == 0xe9) /* jmp rel16,rel32 */ { instruction->num_operands = 2; _NMD_SET_IMM_OPERAND(instruction->operands[0], false, NMD_X86_OPERAND_ACTION_READ, instruction->immediate); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_IP()); } else if (op == 0x6a || op == 0x68) /* push imm8,push imm32/imm16 */ { instruction->num_operands = 3; _NMD_SET_IMM_OPERAND(instruction->operands[0], false, NMD_X86_OPERAND_ACTION_READ, instruction->immediate); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_GPR(NMD_X86_REG_SP)); _NMD_SET_MEM_OPERAND(instruction->operands[2], true, NMD_X86_OPERAND_ACTION_WRITE, NMD_X86_REG_SS, _NMD_GET_GPR(NMD_X86_REG_SP), NMD_X86_REG_NONE, 0, 0); } else if (_NMD_R(op) == 4) /* inc,dec*/ { instruction->num_operands = 1; _NMD_SET_REG_OPERAND(instruction->operands[0], false, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_BY_MODE_OPSZPRFX(mode, opszprfx, NMD_X86_REG_AX, NMD_X86_REG_EAX) + (op % 8)); } else if (op == 0xcc || op == 0xf1 || op == 0xce) /* int3,int1,into */ { instruction->num_operands = 1; _NMD_SET_REG_OPERAND(instruction->operands[0], true, NMD_X86_OPERAND_ACTION_WRITE, _NMD_GET_IP()); } else if (op == 0xcd) /* int n */ { instruction->num_operands = 2; _NMD_SET_IMM_OPERAND(instruction->operands[0], false, NMD_X86_OPERAND_ACTION_READ, instruction->immediate); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_WRITE, _NMD_GET_IP()); } else if (op == 0xe8) /* call rel32 */ { instruction->num_operands = 4; _NMD_SET_IMM_OPERAND(instruction->operands[0], false, NMD_X86_OPERAND_ACTION_READ, instruction->immediate); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_IP()); _NMD_SET_REG_OPERAND(instruction->operands[2], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_GPR(NMD_X86_REG_SP)); _NMD_SET_MEM_OPERAND(instruction->operands[3], true, NMD_X86_OPERAND_ACTION_WRITE, NMD_X86_REG_SS, _NMD_GET_GPR(NMD_X86_REG_SP), NMD_X86_REG_NONE, 0, 0); } else if (_NMD_R(op) < 4 && _NMD_C(op) < 6) /* add,adc,and,xor,or,sbb,sub,cmp Eb,Gb / Ev,Gv / Gb,Eb / Gv,Ev / AL,lb / rAX,lz */ { /* if (op % 8 == 0) { if (modrm.mod == 0b11) { } else { _nmd_decode_modrm_upper32(instruction, &instruction->operands[0]); } } */ if (op % 8 == 0 || op % 8 == 2) { _nmd_decode_operand_Eb(instruction, &instruction->operands[op % 8 == 0 ? 0 : 1]); _nmd_decode_operand_Gb(instruction, &instruction->operands[op % 8 == 0 ? 1 : 0]); } else if (op % 8 == 1 || op % 8 == 3) { _nmd_decode_operand_Ev(instruction, &instruction->operands[op % 8 == 1 ? 0 : 1]); _nmd_decode_operand_Gv(instruction, &instruction->operands[op % 8 == 1 ? 1 : 0]); } else if (op % 8 == 4 || op % 8 == 5) { instruction->operands[0].type = NMD_X86_OPERAND_TYPE_REGISTER; if (op % 8 == 4) instruction->operands[0].fields.reg = NMD_X86_REG_AL; else instruction->operands[0].fields.reg = (uint8_t)(instruction->rex_w_prefix ? NMD_X86_REG_RAX : (instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_REG_AX : NMD_X86_REG_EAX)); instruction->operands[1].type = NMD_X86_OPERAND_TYPE_IMMEDIATE; } instruction->operands[0].action = instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; if (!(_NMD_R(op) == 3 && _NMD_C(op) >= 8)) instruction->operands[0].action = NMD_X86_OPERAND_ACTION_READWRITE; } else if (op == 0xc3 || op == 0xcb || op == 0xcf) /* ret,retf,iret,iretd,iretf */ { instruction->num_operands = 3; _NMD_SET_REG_OPERAND(instruction->operands[0], true, NMD_X86_OPERAND_ACTION_WRITE, _NMD_GET_IP()); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_GPR(NMD_X86_REG_SP)); _NMD_SET_MEM_OPERAND(instruction->operands[2], true, NMD_X86_OPERAND_ACTION_READ, NMD_X86_REG_SS, _NMD_GET_GPR(NMD_X86_REG_SP), NMD_X86_REG_NONE, 0, 0); } else if (op == 0xc2 || op == 0xca) /* ret imm16,retf imm16 */ { instruction->num_operands = 4; _NMD_SET_IMM_OPERAND(instruction->operands[0], false, NMD_X86_OPERAND_ACTION_READ, instruction->immediate); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_WRITE, _NMD_GET_IP()); _NMD_SET_REG_OPERAND(instruction->operands[2], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_GPR(NMD_X86_REG_SP)); _NMD_SET_MEM_OPERAND(instruction->operands[3], true, NMD_X86_OPERAND_ACTION_READ, NMD_X86_REG_SS, _NMD_GET_GPR(NMD_X86_REG_SP), NMD_X86_REG_NONE, 0, 0); } else if (op == 0xff && modrm.fields.reg == 6) /* push mem */ { instruction->num_operands = 3; _NMD_SET_MEM_OPERAND(instruction->operands[0], false, NMD_X86_OPERAND_ACTION_READ, NMD_X86_REG_DS, (instruction->prefixes& NMD_X86_PREFIXES_REX_B ? (opszprfx ? NMD_X86_REG_R8W : NMD_X86_REG_R8) : (opszprfx ? (instruction->mode == NMD_X86_MODE_16 ? NMD_X86_REG_EAX : NMD_X86_REG_AX) : (NMD_X86_REG_AX + (instruction->mode >> 2) * 8))) + modrm.fields.rm, NMD_X86_REG_NONE, 0, 0); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_GPR(NMD_X86_REG_SP)); _NMD_SET_MEM_OPERAND(instruction->operands[2], true, NMD_X86_OPERAND_ACTION_WRITE, NMD_X86_REG_SS, _NMD_GET_GPR(NMD_X86_REG_SP), NMD_X86_REG_NONE, 0, 0); } else if (op == 0x9c) /* pushf,pushfd,pushfq */ { instruction->num_operands = 2; _NMD_SET_REG_OPERAND(instruction->operands[0], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_GPR(NMD_X86_REG_SP)); _NMD_SET_MEM_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_WRITE, NMD_X86_REG_SS, _NMD_GET_GPR(NMD_X86_REG_SP), NMD_X86_REG_NONE, 0, 0); } else if (op == 0x9d) /* popf,popfd,popfq */ { instruction->num_operands = 2; _NMD_SET_REG_OPERAND(instruction->operands[0], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_GPR(NMD_X86_REG_SP)); _NMD_SET_MEM_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READ, NMD_X86_REG_SS, _NMD_GET_GPR(NMD_X86_REG_SP), NMD_X86_REG_NONE, 0, 0); } else if (op == 0xc9) /* leave */ { instruction->num_operands = 3; _NMD_SET_REG_OPERAND(instruction->operands[0], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_GPR(NMD_X86_REG_SP)); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_GPR(NMD_X86_REG_BP)); _NMD_SET_MEM_OPERAND(instruction->operands[2], true, NMD_X86_OPERAND_ACTION_READ, NMD_X86_REG_SS, _NMD_GET_GPR(NMD_X86_REG_SP), NMD_X86_REG_NONE, 0, 0); } else if (op == 0x06 || op == 0x16 || op == 0x0e || op == 0x1e) /* push es,push ss,push ds,push cs */ { instruction->num_operands = 3; _NMD_SET_REG_OPERAND(instruction->operands[0], false, NMD_X86_OPERAND_ACTION_READ, op == 0x06 ? NMD_X86_REG_ES : (op == 0x16 ? NMD_X86_REG_SS : (op == 0x1e ? NMD_X86_REG_DS : NMD_X86_REG_CS))); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_GPR(NMD_X86_REG_SP)); _NMD_SET_MEM_OPERAND(instruction->operands[2], true, NMD_X86_OPERAND_ACTION_WRITE, NMD_X86_REG_SS, _NMD_GET_GPR(NMD_X86_REG_SP), NMD_X86_REG_NONE, 0, 0); } else if (op == 0x07 || op == 0x17 || op == 0x1f) /* pop es,pop ss,pop ds */ { instruction->num_operands = 3; _NMD_SET_REG_OPERAND(instruction->operands[0], false, NMD_X86_OPERAND_ACTION_WRITE, op == 0x07 ? NMD_X86_REG_ES : (op == 0x17 ? NMD_X86_REG_SS : NMD_X86_REG_DS)); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_GPR(NMD_X86_REG_SP)); _NMD_SET_MEM_OPERAND(instruction->operands[2], true, NMD_X86_OPERAND_ACTION_READ, NMD_X86_REG_SS, _NMD_GET_GPR(NMD_X86_REG_SP), NMD_X86_REG_NONE, 0, 0); } else if (op == 0x60) /* pusha,pushad */ { instruction->num_operands = 10; const uint32_t base_reg = _NMD_GET_BY_MODE_OPSZPRFX(mode, opszprfx, NMD_X86_REG_AX, NMD_X86_REG_EAX); _NMD_SET_REG_OPERAND(instruction->operands[0], true, NMD_X86_OPERAND_ACTION_READ, base_reg + 0); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READ, base_reg + 1); _NMD_SET_REG_OPERAND(instruction->operands[2], true, NMD_X86_OPERAND_ACTION_READ, base_reg + 2); _NMD_SET_REG_OPERAND(instruction->operands[3], true, NMD_X86_OPERAND_ACTION_READ, base_reg + 3); _NMD_SET_REG_OPERAND(instruction->operands[4], true, NMD_X86_OPERAND_ACTION_READ, base_reg + 4); _NMD_SET_REG_OPERAND(instruction->operands[5], true, NMD_X86_OPERAND_ACTION_READ, base_reg + 5); _NMD_SET_REG_OPERAND(instruction->operands[6], true, NMD_X86_OPERAND_ACTION_READ, base_reg + 6); _NMD_SET_REG_OPERAND(instruction->operands[7], true, NMD_X86_OPERAND_ACTION_READ, base_reg + 7); _NMD_SET_REG_OPERAND(instruction->operands[8], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_BY_MODE_OPSZPRFX(mode, opszprfx, NMD_X86_REG_SP, NMD_X86_REG_ESP)); _NMD_SET_MEM_OPERAND(instruction->operands[9], true, NMD_X86_OPERAND_ACTION_WRITE, NMD_X86_REG_SS, _NMD_GET_BY_MODE_OPSZPRFX(mode, opszprfx, NMD_X86_REG_SP, NMD_X86_REG_ESP), NMD_X86_REG_NONE, 0, 0); } else if (op == 0x61) /* popa,popad */ { instruction->num_operands = 10; const uint32_t base_reg = _NMD_GET_BY_MODE_OPSZPRFX(mode, opszprfx, NMD_X86_REG_AX, NMD_X86_REG_EAX); _NMD_SET_REG_OPERAND(instruction->operands[0], true, NMD_X86_OPERAND_ACTION_WRITE, base_reg + 0); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_WRITE, base_reg + 1); _NMD_SET_REG_OPERAND(instruction->operands[2], true, NMD_X86_OPERAND_ACTION_WRITE, base_reg + 2); _NMD_SET_REG_OPERAND(instruction->operands[3], true, NMD_X86_OPERAND_ACTION_WRITE, base_reg + 3); _NMD_SET_REG_OPERAND(instruction->operands[4], true, NMD_X86_OPERAND_ACTION_WRITE, base_reg + 4); _NMD_SET_REG_OPERAND(instruction->operands[5], true, NMD_X86_OPERAND_ACTION_WRITE, base_reg + 5); _NMD_SET_REG_OPERAND(instruction->operands[6], true, NMD_X86_OPERAND_ACTION_WRITE, base_reg + 6); _NMD_SET_REG_OPERAND(instruction->operands[7], true, NMD_X86_OPERAND_ACTION_WRITE, base_reg + 7); _NMD_SET_REG_OPERAND(instruction->operands[8], true, NMD_X86_OPERAND_ACTION_READWRITE, _NMD_GET_BY_MODE_OPSZPRFX(mode, opszprfx, NMD_X86_REG_SP, NMD_X86_REG_ESP)); _NMD_SET_MEM_OPERAND(instruction->operands[9], true, NMD_X86_OPERAND_ACTION_READ, NMD_X86_REG_SS, _NMD_GET_BY_MODE_OPSZPRFX(mode, opszprfx, NMD_X86_REG_SP, NMD_X86_REG_ESP), NMD_X86_REG_NONE, 0, 0); } else if (op == 0x27 || op == 0x2f) /* daa,das */ { instruction->num_operands = 1; _NMD_SET_REG_OPERAND(instruction->operands[0], true, NMD_X86_OPERAND_ACTION_READWRITE, NMD_X86_REG_AL); } else if (op == 0x37 || op == 0x3f) /* aaa,aas */ { instruction->num_operands = 2; _NMD_SET_REG_OPERAND(instruction->operands[0], true, NMD_X86_OPERAND_ACTION_READWRITE, NMD_X86_REG_AL); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READWRITE, NMD_X86_REG_AH); } else if (op == 0xd7) /* xlat */ { instruction->num_operands = 2; _NMD_SET_REG_OPERAND(instruction->operands[0], true, NMD_X86_OPERAND_ACTION_WRITE, NMD_X86_REG_AL); _NMD_SET_MEM_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READ, NMD_X86_REG_DS, _NMD_GET_GPR(NMD_X86_REG_BX), NMD_X86_REG_AL, 1, 0); } else if (op == 0x9e || op == 0x9f) /* sahf,lahf */ { instruction->num_operands = 1; _NMD_SET_REG_OPERAND(instruction->operands[0], true, op == 0x9e ? NMD_X86_OPERAND_ACTION_READ : NMD_X86_OPERAND_ACTION_WRITE, NMD_X86_REG_AH); } else if (op == 0x98) /* cbw,cwde,cdqe */ { instruction->num_operands = 2; const NMD_X86_REG reg = instruction->mode == NMD_X86_MODE_64 && instruction->rex_w_prefix ? NMD_X86_REG_RAX : (((instruction->mode == NMD_X86_MODE_16 && instruction->simd_prefix & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) || (instruction->mode != NMD_X86_MODE_16 && !(instruction->simd_prefix & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE))) ? NMD_X86_REG_EAX : NMD_X86_REG_AX); _NMD_SET_REG_OPERAND(instruction->operands[0], true, NMD_X86_OPERAND_ACTION_WRITE, reg); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READ, reg-8); } else if (op == 0x99) /* cwd,cdq,cqo */ { instruction->num_operands = 2; const NMD_X86_REG reg = instruction->mode == NMD_X86_MODE_64 && instruction->rex_w_prefix ? NMD_X86_REG_RAX : (((instruction->mode == NMD_X86_MODE_16 && instruction->simd_prefix & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) || (instruction->mode != NMD_X86_MODE_16 && !(instruction->simd_prefix & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE))) ? NMD_X86_REG_EAX : NMD_X86_REG_AX); _NMD_SET_REG_OPERAND(instruction->operands[0], true, NMD_X86_OPERAND_ACTION_WRITE, reg + 2); _NMD_SET_REG_OPERAND(instruction->operands[1], true, NMD_X86_OPERAND_ACTION_READ, reg); } else if (op == 0xd6) /* salc */ { instruction->num_operands = 1; _NMD_SET_REG_OPERAND(instruction->operands[0], true, NMD_X86_OPERAND_ACTION_WRITE, NMD_X86_REG_AL); } else if (op == 0xc7 && modrm.fields.reg == 0b000) /* mov Ev,lz */ { instruction->num_operands = 2; if (modrm.fields.mod == 0b11) { const NMD_X86_REG reg = (NMD_X86_REG)(_NMD_GET_BY_MODE_OPSZPRFX_W64(mode, opszprfx, instruction->rex_w_prefix, NMD_X86_REG_AX, NMD_X86_REG_EAX, NMD_X86_REG_RAX) + modrm.fields.rm); _NMD_SET_REG_OPERAND(instruction->operands[0], false, NMD_X86_OPERAND_ACTION_WRITE, reg); } else { _nmd_decode_modrm_upper32(instruction, &instruction->operands[0]); instruction->operands[0].is_implicit = false; instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; } _NMD_SET_IMM_OPERAND(instruction->operands[1], false, NMD_X86_OPERAND_ACTION_READ, instruction->immediate); } else if (op >= 0x84 && op <= 0x8b) { if (op % 2 == 0) { _nmd_decode_operand_Eb(instruction, &instruction->operands[op == 0x8a ? 1 : 0]); _nmd_decode_operand_Gb(instruction, &instruction->operands[op == 0x8a ? 0 : 1]); } else { _nmd_decode_operand_Ev(instruction, &instruction->operands[op == 0x8b ? 1 : 0]); _nmd_decode_operand_Gv(instruction, &instruction->operands[op == 0x8b ? 0 : 1]); } if (op >= 0x88) { instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (op >= 0x86) instruction->operands[0].action = instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READWRITE; } else if (op >= 0x80 && op <= 0x83) { if (op % 2 == 0) _nmd_decode_operand_Eb(instruction, &instruction->operands[0]); else _nmd_decode_operand_Ev(instruction, &instruction->operands[0]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_READWRITE; instruction->operands[1].type = NMD_X86_OPERAND_TYPE_IMMEDIATE; } else if (_NMD_R(op) == 7 || op == 0x9a || op == 0xcd || op == 0xd4 || op == 0xd5) instruction->operands[0].type = NMD_X86_OPERAND_TYPE_IMMEDIATE; else if (op == 0x90 && instruction->prefixes & NMD_X86_PREFIXES_REX_B) { instruction->operands[0].type = instruction->operands[1].type = NMD_X86_OPERAND_TYPE_REGISTER; instruction->operands[0].fields.reg = (uint8_t)(instruction->prefixes & NMD_X86_PREFIXES_REX_W ? NMD_X86_REG_R8 : NMD_X86_REG_R8D); instruction->operands[1].fields.reg = (uint8_t)(instruction->prefixes & NMD_X86_PREFIXES_REX_W ? NMD_X86_REG_RAX : NMD_X86_REG_EAX); } else if (_NMD_R(op) == 5) { instruction->operands[0].type = NMD_X86_OPERAND_TYPE_REGISTER; instruction->operands[0].fields.reg = (uint8_t)((instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_REG_AX : (mode == NMD_X86_MODE_64 ? NMD_X86_REG_RAX : NMD_X86_REG_EAX)) + (op % 8)); instruction->operands[0].action = (uint8_t)(_NMD_C(op) < 8 ? NMD_X86_OPERAND_ACTION_READ : NMD_X86_OPERAND_ACTION_WRITE); } else if (op == 0x62) { _nmd_decode_operand_Gv(instruction, &instruction->operands[0]); _nmd_decode_modrm_upper32(instruction, &instruction->operands[1]); instruction->operands[0].action = instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (op == 0x63) { if (mode == NMD_X86_MODE_64) { _nmd_decode_operand_Gv(instruction, &instruction->operands[0]); _nmd_decode_operand_Ev(instruction, &instruction->operands[1]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else { if (instruction->modrm.fields.mod == 0b11) { instruction->operands[0].type = NMD_X86_OPERAND_TYPE_REGISTER; instruction->operands[0].fields.reg = NMD_X86_REG_AX + instruction->modrm.fields.rm; } else _nmd_decode_modrm_upper32(instruction, &instruction->operands[0]); instruction->operands[1].type = NMD_X86_OPERAND_TYPE_REGISTER; instruction->operands[1].fields.reg = NMD_X86_REG_AX + instruction->modrm.fields.reg; instruction->operands[0].action = NMD_X86_OPERAND_ACTION_READWRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } } else if (op == 0x69 || op == 0x6b) { _nmd_decode_operand_Gv(instruction, &instruction->operands[0]); _nmd_decode_operand_Ev(instruction, &instruction->operands[1]); instruction->operands[2].type = NMD_X86_OPERAND_TYPE_IMMEDIATE; instruction->operands[2].fields.imm = (int64_t)(instruction->immediate); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = instruction->operands[2].action = NMD_X86_OPERAND_ACTION_READ; } else if (op == 0x8c) { _nmd_decode_operand_Ev(instruction, &instruction->operands[0]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; instruction->operands[1].type = NMD_X86_OPERAND_TYPE_REGISTER; instruction->operands[1].fields.reg = NMD_X86_REG_ES + instruction->modrm.fields.reg; } else if (op == 0x8d) { _nmd_decode_operand_Gv(instruction, &instruction->operands[0]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; _nmd_decode_modrm_upper32(instruction, &instruction->operands[1]); } else if (op == 0x8e) { instruction->operands[0].type = NMD_X86_OPERAND_TYPE_REGISTER; instruction->operands[0].fields.reg = NMD_X86_REG_ES + instruction->modrm.fields.reg; instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; _nmd_decode_operand_Ew(instruction, &instruction->operands[1]); } else if (op == 0x8f) { _nmd_decode_operand_Ev(instruction, &instruction->operands[0]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; } else if (op >= 0x91 && op <= 0x97) { _nmd_decode_operand_Gv(instruction, &instruction->operands[0]); instruction->operands[0].fields.reg = instruction->operands[0].fields.reg + _NMD_C(op); instruction->operands[1].type = NMD_X86_OPERAND_TYPE_REGISTER; instruction->operands[1].fields.reg = (uint8_t)(instruction->rex_w_prefix ? NMD_X86_REG_RAX : (instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && mode != NMD_X86_MODE_16 ? NMD_X86_REG_AX : NMD_X86_REG_EAX)); instruction->operands[0].action = instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READWRITE; } else if (op >= 0xa0 && op <= 0xa3) { instruction->operands[op < 0xa2 ? 0 : 1].type = NMD_X86_OPERAND_TYPE_REGISTER; instruction->operands[op < 0xa2 ? 0 : 1].fields.reg = (uint8_t)(op % 2 == 0 ? NMD_X86_REG_AL : (instruction->rex_w_prefix ? NMD_X86_REG_RAX : ((instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && mode != NMD_X86_MODE_16) || (mode == NMD_X86_MODE_16 && !(instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE)) ? NMD_X86_REG_AX : NMD_X86_REG_EAX))); instruction->operands[op < 0xa2 ? 1 : 0].type = NMD_X86_OPERAND_TYPE_MEMORY; /* FIXME: We should not access the buffer from here instruction->operands[op < 0xa2 ? 1 : 0].fields.mem.disp = (mode == NMD_X86_MODE_64) ? *(uint64_t*)(b + 1) : *(uint32_t*)(b + 1); */ _nmd_decode_operand_segment_reg(instruction, &instruction->operands[op < 0xa2 ? 1 : 0]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (op == 0xa8 || op == 0xa9) { instruction->operands[0].type = NMD_X86_OPERAND_TYPE_REGISTER; instruction->operands[0].fields.reg = (uint8_t)(op == 0xa8 ? NMD_X86_REG_AL : (instruction->rex_w_prefix ? NMD_X86_REG_RAX : ((instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && mode != NMD_X86_MODE_16) || (mode == NMD_X86_MODE_16 && !(instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE)) ? NMD_X86_REG_AX : NMD_X86_REG_EAX))); instruction->operands[1].type = NMD_X86_OPERAND_TYPE_IMMEDIATE; } else if (op == 0xc0 || op == 0xc1 || op == 0xc6) { if (!(op >= 0xc6 && instruction->modrm.fields.reg)) { if (op % 2 == 0) _nmd_decode_operand_Eb(instruction, &instruction->operands[0]); else _nmd_decode_operand_Ev(instruction, &instruction->operands[0]); } instruction->operands[op >= 0xc6 && instruction->modrm.fields.reg ? 0 : 1].type = NMD_X86_OPERAND_TYPE_IMMEDIATE; instruction->operands[0].action = (uint8_t)(op <= 0xc1 ? NMD_X86_OPERAND_ACTION_READWRITE : NMD_X86_OPERAND_ACTION_WRITE); } else if (op == 0xc4 || op == 0xc5) { instruction->operands[0].type = NMD_X86_OPERAND_TYPE_REGISTER; instruction->operands[0].fields.reg = (uint8_t)((instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_REG_AX : NMD_X86_REG_EAX) + instruction->modrm.fields.reg); _nmd_decode_modrm_upper32(instruction, &instruction->operands[1]); instruction->operands[0].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[1].action = NMD_X86_OPERAND_ACTION_READ; } else if (op == 0xc8) { instruction->operands[0].type = instruction->operands[1].type = NMD_X86_OPERAND_TYPE_IMMEDIATE; /* FIXME: We should not access the buffer from here instruction->operands[0].fields.imm = *(uint16_t*)(b + 1); instruction->operands[1].fields.imm = b[3]; */ } else if (op >= 0xd0 && op <= 0xd3) { if (op % 2 == 0) _nmd_decode_operand_Eb(instruction, &instruction->operands[0]); else _nmd_decode_operand_Ev(instruction, &instruction->operands[0]); if (op < 0xd2) { instruction->operands[1].type = NMD_X86_OPERAND_TYPE_IMMEDIATE; instruction->operands[1].fields.imm = 1; } else { instruction->operands[1].type = NMD_X86_OPERAND_TYPE_REGISTER; instruction->operands[1].fields.reg = NMD_X86_REG_CL; } instruction->operands[0].action = NMD_X86_OPERAND_ACTION_READWRITE; } else if (op >= 0xd8 && op <= 0xdf) { if (instruction->modrm.fields.mod != 0b11 || op == 0xd8 || (op == 0xd9 && _NMD_C(instruction->modrm.modrm) == 0xc) || (op == 0xda && _NMD_C(instruction->modrm.modrm) <= 0xd) || (op == 0xdb && (_NMD_C(instruction->modrm.modrm) <= 0xd || instruction->modrm.modrm >= 0xe8)) || op == 0xdc || op == 0xdd || (op == 0xde && instruction->modrm.modrm != 0xd9) || (op == 0xdf && instruction->modrm.modrm != 0xe0)) { instruction->operands[0].type = instruction->operands[1].type = NMD_X86_OPERAND_TYPE_REGISTER; instruction->operands[0].is_implicit = true; instruction->operands[0].fields.reg = NMD_X86_REG_ST0; instruction->operands[1].fields.reg = NMD_X86_REG_ST0 + instruction->modrm.fields.reg; } } else if (_NMD_R(op) == 0xe) { if (op % 8 < 4) { instruction->operands[0].type = NMD_X86_OPERAND_TYPE_IMMEDIATE; instruction->operands[0].fields.imm = (int64_t)(instruction->immediate); } else { if (op < 0xe8) { instruction->operands[0].type = (uint8_t)(_NMD_C(op) < 6 ? NMD_X86_OPERAND_TYPE_REGISTER : NMD_X86_OPERAND_TYPE_IMMEDIATE); instruction->operands[1].type = (uint8_t)(_NMD_C(op) < 6 ? NMD_X86_OPERAND_TYPE_IMMEDIATE : NMD_X86_OPERAND_TYPE_REGISTER); instruction->operands[0].fields.imm = instruction->operands[1].fields.imm = (int64_t)(instruction->immediate); } else { instruction->operands[0].type = instruction->operands[1].type = NMD_X86_OPERAND_TYPE_REGISTER; instruction->operands[0].fields.reg = instruction->operands[1].fields.reg = NMD_X86_REG_DX; } if (op % 2 == 0) instruction->operands[op % 8 == 4 ? 0 : 1].fields.reg = NMD_X86_REG_AL; else instruction->operands[op % 8 == 5 ? 0 : 1].fields.reg = (uint8_t)((instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? NMD_X86_REG_AX : NMD_X86_REG_EAX) + instruction->modrm.fields.reg); instruction->operands[op % 8 <= 5 ? 0 : 1].action = NMD_X86_OPERAND_ACTION_WRITE; instruction->operands[op % 8 <= 5 ? 1 : 0].action = NMD_X86_OPERAND_ACTION_READ; } } else if (op == 0xf6 || op == 0xfe) { _nmd_decode_operand_Eb(instruction, &instruction->operands[0]); instruction->operands[0].action = (uint8_t)(op == 0xfe && instruction->modrm.fields.reg >= 0b010 ? NMD_X86_OPERAND_ACTION_READ : NMD_X86_OPERAND_ACTION_READWRITE); } else if (op == 0xf7 || op == 0xff) { _nmd_decode_operand_Ev(instruction, &instruction->operands[0]); instruction->operands[0].action = (uint8_t)(op == 0xff && instruction->modrm.fields.reg >= 0b010 ? NMD_X86_OPERAND_ACTION_READ : NMD_X86_OPERAND_ACTION_READWRITE); } } #endif /* NMD_ASSEMBLY_DISABLE_DECODER_OPERANDS */ } } if (instruction->prefixes & NMD_X86_PREFIXES_LOCK) { if (!(instruction->has_modrm && instruction->modrm.fields.mod != 0b11 && ((instruction->opcode_size == 1 && (op == 0x86 || op == 0x87 || (_NMD_R(op) < 4 && (op % 8) < 2 && op < 0x38) || ((op >= 0x80 && op <= 0x83) && instruction->modrm.fields.reg != 0b111) || (op >= 0xfe && instruction->modrm.fields.reg < 2) || ((op == 0xf6 || op == 0xf7) && (instruction->modrm.fields.reg == 0b010 || instruction->modrm.fields.reg == 0b011)))) || (instruction->opcode_size == 2 && (_nmd_find_byte(_nmd_two_opcodes, sizeof(_nmd_two_opcodes), op) || op == 0xab || (op == 0xba && instruction->modrm.fields.reg != 0b100) || (op == 0xc7 && instruction->modrm.fields.reg == 0b001)))))) return false; } instruction->length = (uint8_t)((ptrdiff_t)(b) - (ptrdiff_t)(buffer)); for (i = 0; i < instruction->length; i++) instruction->buffer[i] = ((const uint8_t* const)(buffer))[i]; instruction->valid = true; return true; } NMD_ASSEMBLY_API bool _nmd_ldisasm_decode_modrm(const uint8_t** p_buffer, size_t* p_buffer_size, bool address_prefix, NMD_X86_MODE mode, nmd_x86_modrm* p_modrm) { _NMD_READ_BYTE(*p_buffer, *p_buffer_size, (*p_modrm).modrm); bool has_sib = false; size_t disp_size = 0; if (mode == NMD_X86_MODE_16) { if (p_modrm->fields.mod != 0b11) { if (p_modrm->fields.mod == 0b00) { if (p_modrm->fields.rm == 0b110) disp_size = 2; } else disp_size = p_modrm->fields.mod == 0b01 ? 1 : 2; } } else { if (address_prefix && mode == NMD_X86_MODE_32) { if ((p_modrm->fields.mod == 0b00 && p_modrm->fields.rm == 0b110) || p_modrm->fields.mod == 0b10) disp_size = 2; else if (p_modrm->fields.mod == 0b01) disp_size = 1; } else { /* Check for SIB byte */ uint8_t sib = 0; if (p_modrm->modrm < 0xC0 && p_modrm->fields.rm == 0b100 && (!address_prefix || (address_prefix && mode == NMD_X86_MODE_64))) { has_sib = true; _NMD_READ_BYTE(*p_buffer, *p_buffer_size, sib); } if (p_modrm->fields.mod == 0b01) /* disp8 (ModR/M) */ disp_size = 1; else if ((p_modrm->fields.mod == 0b00 && p_modrm->fields.rm == 0b101) || p_modrm->fields.mod == 0b10) /* disp16,32 (ModR/M) */ disp_size = (address_prefix && !(mode == NMD_X86_MODE_64 && address_prefix) ? 2 : 4); else if (has_sib && (sib & 0b111) == 0b101) /* disp8,32 (SIB) */ disp_size = (p_modrm->fields.mod == 0b01 ? 1 : 4); } } /* Make sure we can read 'instruction->disp_mask' bytes from the buffer */ if (*p_buffer_size < disp_size) return false; /* Increment the buffer and decrement the buffer's size */ *p_buffer += disp_size; *p_buffer_size -= disp_size; return true; } /* Returns the length of the instruction if it is valid, zero otherwise. Parameters: - buffer [in] A pointer to a buffer containing an encoded instruction. - buffer_size [in] The size of the buffer in bytes. - mode [in] The architecture mode. 'NMD_X86_MODE_32', 'NMD_X86_MODE_64' or 'NMD_X86_MODE_16'. */ NMD_ASSEMBLY_API size_t nmd_x86_ldisasm(const void* const buffer, size_t buffer_size, const NMD_X86_MODE mode) { bool operand_prefix = false; bool address_prefix = false; bool repeat_prefix = false; bool repeat_not_zero_prefix = false; bool rexW = false; bool lock_prefix = false; uint16_t simd_prefix = NMD_X86_PREFIXES_NONE; uint8_t opcode_size = 0; bool has_modrm = false; nmd_x86_modrm modrm; modrm.modrm = 0; /* Security considerations for memory safety: The contents of 'buffer' should be considered untrusted and decoded carefully. 'buffer' should always point to the start of the buffer. We use the 'b' buffer iterator to read data from the buffer, however before accessing it make sure to check 'buffer_size' to see if we can safely access it. Then, after reading data from the buffer we increment 'b' and decrement 'buffer_size'. Helper macros: _NMD_READ_BYTE() */ /* Set buffer iterator */ const uint8_t* b = (const uint8_t*)buffer; /* Clamp 'buffer_size' to 15. We will only read up to 15 bytes(NMD_X86_MAXIMUM_INSTRUCTION_LENGTH) */ if (buffer_size > 15) buffer_size = 15; /* Decode legacy and REX prefixes */ for (; buffer_size > 0; b++, buffer_size--) { switch (*b) { case 0xF0: lock_prefix = true; continue; case 0xF2: repeat_not_zero_prefix = true, simd_prefix = NMD_X86_PREFIXES_REPEAT_NOT_ZERO; continue; case 0xF3: repeat_prefix = true, simd_prefix = NMD_X86_PREFIXES_REPEAT; continue; case 0x2E: continue; case 0x36: continue; case 0x3E: continue; case 0x26: continue; case 0x64: continue; case 0x65: continue; case 0x66: operand_prefix = true, simd_prefix = NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE; continue; case 0x67: address_prefix = true; continue; default: if (mode == NMD_X86_MODE_64 && _NMD_R(*b) == 4) /* REX prefixes [0x40,0x4f] */ { if(_NMD_C(*b) & 0b1000) rexW = true; continue; } } break; } /* Calculate the number of prefixes based on how much the iterator moved */ const size_t num_prefixes = (uint8_t)((ptrdiff_t)(b)-(ptrdiff_t)(buffer)); /* Opcode byte. This variable is used because 'op' is simpler than 'instruction->opcode' */ uint8_t op; _NMD_READ_BYTE(b, buffer_size, op); if (op == 0x0F) /* 2 or 3 byte opcode */ { _NMD_READ_BYTE(b, buffer_size, op); if (op == 0x38 || op == 0x3A) /* 3 byte opcode */ { const bool is_opcode_map38 = op == 0x38; opcode_size = 3; _NMD_READ_BYTE(b, buffer_size, op); if (!_nmd_ldisasm_decode_modrm(&b, &buffer_size, address_prefix, mode, &modrm)) return 0; has_modrm = true; if (is_opcode_map38) { #ifndef NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK if (op == 0x36) { return 0; } else if (op <= 0xb || (op >= 0x1c && op <= 0x1e)) { if (simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) return 0; } else if (op >= 0xc8 && op <= 0xcd) { if (simd_prefix) return 0; } else if (op == 0x10 || op == 0x14 || op == 0x15 || op == 0x17 || (op >= 0x20 && op <= 0x25) || op == 0x28 || op == 0x29 || op == 0x2b || _NMD_R(op) == 3 || op == 0x40 || op == 0x41 || op == 0xcf || (op >= 0xdb && op <= 0xdf)) { if (simd_prefix != NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) return 0; } else if (op == 0x2a || (op >= 0x80 && op <= 0x82)) { if (modrm.fields.mod == 0b11 || simd_prefix != NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) return 0; } else if (op == 0xf0 || op == 0xf1) { if (modrm.fields.mod == 0b11 && (simd_prefix == NMD_X86_PREFIXES_NONE || simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE)) return 0; else if (simd_prefix == NMD_X86_PREFIXES_REPEAT) return 0; } else if (op == 0xf5 || op == 0xf8) { if (simd_prefix != NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE || modrm.fields.mod == 0b11) return 0; } else if (op == 0xf6) { if (simd_prefix == NMD_X86_PREFIXES_NONE && modrm.fields.mod == 0b11) return 0; else if (simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) return 0; } else if (op == 0xf9) { if (simd_prefix != NMD_X86_PREFIXES_NONE || modrm.fields.mod == 0b11) return 0; } else return 0; #endif /* NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK */ } else /* 0x3a */ { /* "Read" the immediate byte */ uint8_t imm; _NMD_READ_BYTE(b, buffer_size, imm); #ifndef NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK if ((op >= 0x8 && op <= 0xe) || (op >= 0x14 && op <= 0x17) || (op >= 0x20 && op <= 0x22) || (op >= 0x40 && op <= 0x42) || op == 0x44 || (op >= 0x60 && op <= 0x63) || op == 0xdf || op == 0xce || op == 0xcf) { if (simd_prefix != NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) return 0; } else if (op == 0x0f || op == 0xcc) { if (simd_prefix) return 0; } else return 0; #endif /* NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK */ } } else if (op == 0x0f) /* 3DNow! opcode map*/ { #ifndef NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_3DNOW if (!_nmd_ldisasm_decode_modrm(&b, &buffer_size, address_prefix, mode, &modrm)) return false; uint8_t imm; _NMD_READ_BYTE(b, buffer_size, imm); #ifndef NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK if (!_nmd_find_byte(_nmd_valid_3DNow_opcodes, sizeof(_nmd_valid_3DNow_opcodes), imm)) return false; #endif /*NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK */ #else /* NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_3DNOW */ return false; #endif /* NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_3DNOW */ } else /* 2 byte opcode. */ { opcode_size = 2; /* Check for ModR/M, SIB and displacement */ if (op >= 0x20 && op <= 0x23) { has_modrm = true; _NMD_READ_BYTE(b, buffer_size, modrm.modrm); } else if (op < 4 || (_NMD_R(op) != 3 && _NMD_R(op) > 0 && _NMD_R(op) < 7) || (op >= 0xD0 && op != 0xFF) || (_NMD_R(op) == 7 && _NMD_C(op) != 7) || _NMD_R(op) == 9 || _NMD_R(op) == 0xB || (_NMD_R(op) == 0xC && _NMD_C(op) < 8) || (_NMD_R(op) == 0xA && (op % 8) >= 3) || op == 0x0ff || op == 0x00 || op == 0x0d) { if (!_nmd_ldisasm_decode_modrm(&b, &buffer_size, address_prefix, mode, &modrm)) return 0; has_modrm = true; } #ifndef NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK if (_nmd_find_byte(_nmd_invalid_op2, sizeof(_nmd_invalid_op2), op)) return 0; else if (op == 0xc7) { if ((!simd_prefix && (modrm.fields.mod == 0b11 ? modrm.fields.reg <= 0b101 : modrm.fields.reg == 0b000 || modrm.fields.reg == 0b010)) || (simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO && (modrm.fields.mod == 0b11 || modrm.fields.reg != 0b001)) || ((simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE || simd_prefix == NMD_X86_PREFIXES_REPEAT) && (modrm.fields.mod == 0b11 ? modrm.fields.reg <= (simd_prefix == NMD_X86_PREFIXES_REPEAT ? 0b110 : 0b101) : (modrm.fields.reg != 0b001 && modrm.fields.reg != 0b110)))) return 0; } else if (op == 0x00) { if (modrm.fields.reg >= 0b110) return 0; } else if (op == 0x01) { if ((modrm.fields.mod == 0b11 ? (( (simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO || simd_prefix == NMD_X86_PREFIXES_REPEAT) && ((modrm.modrm >= 0xc0 && modrm.modrm <= 0xc5) || (modrm.modrm >= 0xc8 && modrm.modrm <= 0xcb) || (modrm.modrm >= 0xcf && modrm.modrm <= 0xd1) || (modrm.modrm >= 0xd4 && modrm.modrm <= 0xd7) || modrm.modrm == 0xee || modrm.modrm == 0xef || modrm.modrm == 0xfa || modrm.modrm == 0xfb)) || (modrm.fields.reg == 0b000 && modrm.fields.rm >= 0b110) || (modrm.fields.reg == 0b001 && modrm.fields.rm >= 0b100 && modrm.fields.rm <= 0b110) || (modrm.fields.reg == 0b010 && (modrm.fields.rm == 0b010 || modrm.fields.rm == 0b011)) || (modrm.fields.reg == 0b101 && modrm.fields.rm < 0b110 && (!repeat_prefix || (simd_prefix == NMD_X86_PREFIXES_REPEAT && (modrm.fields.rm != 0b000 && modrm.fields.rm != 0b010)))) || (modrm.fields.reg == 0b111 && (modrm.fields.rm > 0b101 || (mode != NMD_X86_MODE_64 && modrm.fields.rm == 0b000)))) : (!repeat_prefix && modrm.fields.reg == 0b101))) return 0; } else if (op == 0x1A || op == 0x1B) { if (modrm.fields.mod == 0b11) return 0; } else if (op == 0x20 || op == 0x22) { if (modrm.fields.reg == 0b001 || modrm.fields.reg >= 0b101) return 0; } else if (op >= 0x24 && op <= 0x27) return 0; else if (op >= 0x3b && op <= 0x3f) return 0; else if (_NMD_R(op) == 5) { if ((op == 0x50 && modrm.fields.mod != 0b11) || (simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && (op == 0x52 || op == 0x53)) || (simd_prefix == NMD_X86_PREFIXES_REPEAT && (op == 0x50 || (op >= 0x54 && op <= 0x57))) || (repeat_not_zero_prefix && (op == 0x50 || (op >= 0x52 && op <= 0x57) || op == 0x5b))) return 0; } else if (_NMD_R(op) == 6) { if ((!(simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE || simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) && (op == 0x6c || op == 0x6d)) || (simd_prefix == NMD_X86_PREFIXES_REPEAT && op != 0x6f) || repeat_not_zero_prefix) return 0; } else if (op == 0x78 || op == 0x79) { if ((((simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && op == 0x78) && !(modrm.fields.mod == 0b11 && modrm.fields.reg == 0b000)) || ((simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) && modrm.fields.mod != 0b11)) || (simd_prefix == NMD_X86_PREFIXES_REPEAT)) return 0; } else if (op == 0x7c || op == 0x7d) { if (simd_prefix == NMD_X86_PREFIXES_REPEAT || !(simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE || simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO)) return 0; } else if (op == 0x7e || op == 0x7f) { if (repeat_not_zero_prefix) return 0; } else if (op >= 0x71 && op <= 0x73) { if ((simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) || modrm.modrm <= 0xcf || (modrm.modrm >= 0xe8 && modrm.modrm <= 0xef)) return 0; } else if (op == 0x73) { if (modrm.modrm >= 0xe0 && modrm.modrm <= 0xe8) return 0; } else if (op == 0xa6) { if (modrm.modrm != 0xc0 && modrm.modrm != 0xc8 && modrm.modrm != 0xd0) return 0; } else if (op == 0xa7) { if (!(modrm.fields.mod == 0b11 && modrm.fields.reg <= 0b101 && modrm.fields.rm == 0b000)) return 0; } else if (op == 0xae) { if (((!simd_prefix && modrm.fields.mod == 0b11 && modrm.fields.reg <= 0b100) || (simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO && !(modrm.fields.mod == 0b11 && modrm.fields.reg == 0b110)) || (simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && (modrm.fields.reg < 0b110 || (modrm.fields.mod == 0b11 && modrm.fields.reg == 0b111))) || (simd_prefix == NMD_X86_PREFIXES_REPEAT && (modrm.fields.reg != 0b100 && modrm.fields.reg != 0b110) && !(modrm.fields.mod == 0b11 && modrm.fields.reg == 0b101)))) return 0; } else if (op == 0xb8) { if (!repeat_prefix) return 0; } else if (op == 0xba) { if (modrm.fields.reg <= 0b011) return 0; } else if (op == 0xd0) { if (!simd_prefix || simd_prefix == NMD_X86_PREFIXES_REPEAT) return 0; } else if (op == 0xe0) { if (simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) return 0; } else if (op == 0xf0) { if (simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO ? modrm.fields.mod == 0b11 : true) return 0; } else if (simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) { if ((op >= 0x13 && op <= 0x17 && !(op == 0x16 && simd_prefix == NMD_X86_PREFIXES_REPEAT)) || op == 0x28 || op == 0x29 || op == 0x2e || op == 0x2f || (op <= 0x76 && op >= 0x74)) return 0; } else if (op == 0x71 || op == 0x72 || (op == 0x73 && !(simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE))) { if ((modrm.modrm >= 0xd8 && modrm.modrm <= 0xdf) || modrm.modrm >= 0xf8) return 0; } else if (op >= 0xc3 && op <= 0xc6) { if ((op == 0xc5 && modrm.fields.mod != 0b11) || (simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) || (op == 0xc3 && simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE)) return 0; } else if (_NMD_R(op) >= 0xd && _NMD_C(op) != 0 && op != 0xff && ((_NMD_C(op) == 6 && _NMD_R(op) != 0xf) ? (!simd_prefix || (_NMD_R(op) == 0xD && (simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) ? modrm.fields.mod != 0b11 : false)) : (simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO || ((_NMD_C(op) == 7 && _NMD_R(op) != 0xe) ? modrm.fields.mod != 0b11 : false)))) return 0; else if (has_modrm && modrm.fields.mod == 0b11) { if (op == 0xb2 || op == 0xb4 || op == 0xb5 || op == 0xc3 || op == 0xe7 || op == 0x2b || (simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && (op == 0x12 || op == 0x16)) || (!(simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) && (op == 0x13 || op == 0x17))) return 0; } #endif /* NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK */ uint8_t imm_mask = 0; if (_NMD_R(op) == 8) /* imm32 */ imm_mask = _NMD_GET_BY_MODE_OPSZPRFX_F64(mode, operand_prefix, 2, 4, 4); else if ((_NMD_R(op) == 7 && _NMD_C(op) < 4) || op == 0xA4 || op == 0xC2 || (op > 0xC3 && op <= 0xC6) || op == 0xBA || op == 0xAC) /* imm8 */ imm_mask = 1; else if (op == 0x78 && (repeat_not_zero_prefix || operand_prefix)) /* imm8 + imm8 = "imm16" */ imm_mask = 2; /* Make sure we can "read" 'imm_mask' bytes from the buffer */ if (buffer_size < imm_mask) return false; /* Increment the buffer and decrement the buffer's size */ b += imm_mask; buffer_size -= imm_mask; } } else /* 1 byte opcode */ { opcode_size = 1; /* Check for ModR/M, SIB and displacement */ if (_NMD_R(op) == 8 || _nmd_find_byte(_nmd_op1_modrm, sizeof(_nmd_op1_modrm), op) || (_NMD_R(op) < 4 && (_NMD_C(op) < 4 || (_NMD_C(op) >= 8 && _NMD_C(op) < 0xC))) || (_NMD_R(op) == 0xD && _NMD_C(op) >= 8)/* || ((op == 0xc4 || op == 0xc5) && remaining_size > 1 && ((nmd_x86_modrm*)(b + 1))->fields.mod != 0b11)*/) { if (!_nmd_ldisasm_decode_modrm(&b, &buffer_size, address_prefix, mode, &modrm)) return 0; has_modrm = true; } #ifndef NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK if (op == 0xC6 || op == 0xC7) { if ((modrm.fields.reg != 0b000 && modrm.fields.reg != 0b111) || (modrm.fields.reg == 0b111 && (modrm.fields.mod != 0b11 || modrm.fields.rm != 0b000))) return 0; } else if (op == 0x8f) { if (modrm.fields.reg != 0b000) return 0; } else if (op == 0xfe) { if (modrm.fields.reg >= 0b010) return 0; } else if (op == 0xff) { if (modrm.fields.reg == 0b111 || (modrm.fields.mod == 0b11 && (modrm.fields.reg == 0b011 || modrm.fields.reg == 0b101))) return 0; } else if (op == 0x8c) { if (modrm.fields.reg >= 0b110) return 0; } else if (op == 0x8e) { if (modrm.fields.reg == 0b001 || modrm.fields.reg >= 0b110) return 0; } else if (op == 0x62) { if (mode == NMD_X86_MODE_64) return 0; } else if (op == 0x8d) { if (modrm.fields.mod == 0b11) return 0; } else if (op == 0xc4 || op == 0xc5) { if (mode == NMD_X86_MODE_64 && has_modrm && modrm.fields.mod != 0b11) return 0; } else if (op >= 0xd8 && op <= 0xdf) { switch (op) { case 0xd9: if ((modrm.fields.reg == 0b001 && modrm.fields.mod != 0b11) || (modrm.modrm > 0xd0 && modrm.modrm < 0xd8) || modrm.modrm == 0xe2 || modrm.modrm == 0xe3 || modrm.modrm == 0xe6 || modrm.modrm == 0xe7 || modrm.modrm == 0xef) return 0; break; case 0xda: if (modrm.modrm >= 0xe0 && modrm.modrm != 0xe9) return 0; break; case 0xdb: if (((modrm.fields.reg == 0b100 || modrm.fields.reg == 0b110) && modrm.fields.mod != 0b11) || (modrm.modrm >= 0xe5 && modrm.modrm <= 0xe7) || modrm.modrm >= 0xf8) return 0; break; case 0xdd: if ((modrm.fields.reg == 0b101 && modrm.fields.mod != 0b11) || _NMD_R(modrm.modrm) == 0xf) return 0; break; case 0xde: if (modrm.modrm == 0xd8 || (modrm.modrm >= 0xda && modrm.modrm <= 0xdf)) return 0; break; case 0xdf: if ((modrm.modrm >= 0xe1 && modrm.modrm <= 0xe7) || modrm.modrm >= 0xf8) return 0; break; } } else if (mode == NMD_X86_MODE_64) { if (op == 0x6 || op == 0x7 || op == 0xe || op == 0x16 || op == 0x17 || op == 0x1e || op == 0x1f || op == 0x27 || op == 0x2f || op == 0x37 || op == 0x3f || (op >= 0x60 && op <= 0x62) || op == 0x82 || op == 0xce || (op >= 0xd4 && op <= 0xd6)) return 0; } #endif /* NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK */ #ifndef NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VEX /* Check if instruction is VEX */ if ((op == 0xc4 || op == 0xc5) && !has_modrm) { const uint8_t byte0 = op; uint8_t byte1; _NMD_READ_BYTE(b, buffer_size, byte1); if (byte0 == 0xc4) { uint8_t byte2; _NMD_READ_BYTE(b, buffer_size, byte2); _NMD_READ_BYTE(b, buffer_size, op); if (op == 0x0c || op == 0x0d || op == 0x40 || op == 0x41 || op == 0x17 || op == 0x21 || op == 0x42) { uint8_t imm; _NMD_READ_BYTE(b, buffer_size, imm); } } else /* 0xc5 */ { _NMD_READ_BYTE(b, buffer_size, op); } if (!_nmd_ldisasm_decode_modrm(&b, &buffer_size, address_prefix, mode, &modrm)) return false; has_modrm = true; } else #endif /* NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VEX */ { /* Check for immediate */ uint8_t imm_mask = 0; if (_nmd_find_byte(_nmd_op1_imm32, sizeof(_nmd_op1_imm32), op) || (_NMD_R(op) < 4 && (_NMD_C(op) == 5 || _NMD_C(op) == 0xD)) || (_NMD_R(op) == 0xB && _NMD_C(op) >= 8) || (op == 0xF7 && modrm.fields.reg == 0b000)) /* imm32,16 */ { if (_NMD_R(op) == 0xB && _NMD_C(op) >= 8) imm_mask = rexW ? 8 : (operand_prefix || (mode == NMD_X86_MODE_16 && !operand_prefix) ? 2 : 4); else { if ((mode == NMD_X86_MODE_16 && operand_prefix) || (mode != NMD_X86_MODE_16 && !operand_prefix)) imm_mask = NMD_X86_IMM32; else imm_mask = NMD_X86_IMM16; } } else if (_NMD_R(op) == 7 || (_NMD_R(op) == 0xE && _NMD_C(op) < 8) || (_NMD_R(op) == 0xB && _NMD_C(op) < 8) || (_NMD_R(op) < 4 && (_NMD_C(op) == 4 || _NMD_C(op) == 0xC)) || (op == 0xF6 && modrm.fields.reg <= 0b001) || _nmd_find_byte(_nmd_op1_imm8, sizeof(_nmd_op1_imm8), op)) /* imm8 */ imm_mask = 1; else if (_NMD_R(op) == 0xA && _NMD_C(op) < 4) imm_mask = (mode == NMD_X86_MODE_64) ? (address_prefix ? 4 : 8) : (address_prefix ? 2 : 4); else if (op == 0xEA || op == 0x9A) /* imm32,48 */ { if (mode == NMD_X86_MODE_64) return 0; imm_mask = (operand_prefix ? 4 : 6); } else if (op == 0xC2 || op == 0xCA) /* imm16 */ imm_mask = 2; else if (op == 0xC8) /* imm16 + imm8 */ imm_mask = 3; /* Make sure we can "read" 'imm_mask' bytes from the buffer */ if (buffer_size < imm_mask) return false; /* Increment the buffer and decrement the buffer's size */ b += imm_mask; buffer_size -= imm_mask; } } if (lock_prefix) { if (!(has_modrm && modrm.fields.mod != 0b11 && ((opcode_size == 1 && (op == 0x86 || op == 0x87 || (_NMD_R(op) < 4 && (op % 8) < 2 && op < 0x38) || ((op >= 0x80 && op <= 0x83) && modrm.fields.reg != 0b111) || (op >= 0xfe && modrm.fields.reg < 2) || ((op == 0xf6 || op == 0xf7) && (modrm.fields.reg == 0b010 || modrm.fields.reg == 0b011)))) || (opcode_size == 2 && (_nmd_find_byte(_nmd_two_opcodes, sizeof(_nmd_two_opcodes), op) || op == 0xab || (op == 0xba && modrm.fields.reg != 0b100) || (op == 0xc7 && modrm.fields.reg == 0b001)))))) return 0; } return (size_t)((ptrdiff_t)(b) - (ptrdiff_t)(buffer)); } typedef struct { char* buffer; const nmd_x86_instruction* instruction; uint64_t runtime_address; uint32_t flags; } _nmd_string_info; NMD_ASSEMBLY_API void _nmd_append_string(_nmd_string_info* const si, const char* source) { while (*source) *si->buffer++ = *source++; } NMD_ASSEMBLY_API void _nmd_append_number(_nmd_string_info* const si, uint64_t n) { size_t buffer_offset; if (si->flags & NMD_X86_FORMAT_FLAGS_HEX) { size_t num_digits = _NMD_GET_NUM_DIGITS_HEX(n); buffer_offset = num_digits; const bool condition = n > 9 || si->flags & NMD_X86_FORMAT_FLAGS_ENFORCE_HEX_ID; if (si->flags & NMD_X86_FORMAT_FLAGS_0X_PREFIX && condition) *si->buffer++ = '0', *si->buffer++ = 'x'; const uint8_t base_char = (uint8_t)(si->flags & NMD_X86_FORMAT_FLAGS_HEX_LOWERCASE ? 0x57 : 0x37); do { size_t num = n % 16; *(si->buffer + --num_digits) = (char)((num > 9 ? base_char : '0') + num); } while ((n /= 16) > 0); if (si->flags & NMD_X86_FORMAT_FLAGS_H_SUFFIX && condition) *(si->buffer + buffer_offset++) = 'h'; } else { size_t num_digits = _NMD_GET_NUM_DIGITS(n); buffer_offset = num_digits + 1; do { *(si->buffer + --num_digits) = (char)('0' + n % 10); } while ((n /= 10) > 0); } si->buffer += buffer_offset; } NMD_ASSEMBLY_API void _nmd_append_signed_number(_nmd_string_info* const si, int64_t n, bool show_positive_sign) { if (n >= 0) { if (show_positive_sign) *si->buffer++ = '+'; _nmd_append_number(si, (uint64_t)n); } else { *si->buffer++ = '-'; _nmd_append_number(si, (uint64_t)(~n + 1)); } } NMD_ASSEMBLY_API void _nmd_append_signed_number_memory_view(_nmd_string_info* const si) { _nmd_append_number(si, (si->instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? 0xFF00 : (si->instruction->mode == NMD_X86_MODE_64 ? 0xFFFFFFFFFFFFFF00 : 0xFFFFFF00)) | si->instruction->immediate); if (si->flags & NMD_X86_FORMAT_FLAGS_SIGNED_NUMBER_HINT_HEX) { *si->buffer++ = '('; _nmd_append_signed_number(si, (int8_t)(si->instruction->immediate), false); *si->buffer++ = ')'; } else if (si->flags & NMD_X86_FORMAT_FLAGS_SIGNED_NUMBER_HINT_DEC) { *si->buffer++ = '('; const uint32_t previous_mask = si->flags; si->flags &= ~NMD_X86_FORMAT_FLAGS_HEX; _nmd_append_signed_number(si, (int8_t)(si->instruction->immediate), false); si->flags = previous_mask; *si->buffer++ = ')'; } } NMD_ASSEMBLY_API void _nmd_append_relative_address8(_nmd_string_info* const si) { if (si->runtime_address == NMD_X86_INVALID_RUNTIME_ADDRESS) { /* *si->buffer++ = '$'; */ _nmd_append_signed_number(si, (int64_t)((int8_t)(si->instruction->immediate) + (int8_t)(si->instruction->length)), true); } else { uint64_t n; if (si->instruction->mode == NMD_X86_MODE_64) n = (uint64_t)((int64_t)(si->runtime_address + (uint64_t)si->instruction->length) + (int8_t)(si->instruction->immediate)); else if (si->instruction->mode == NMD_X86_MODE_16) n = (uint16_t)((int16_t)(si->runtime_address + (uint64_t)si->instruction->length) + (int8_t)(si->instruction->immediate)); else n = (uint32_t)((int32_t)(si->runtime_address + (uint64_t)si->instruction->length) + (int8_t)(si->instruction->immediate)); _nmd_append_number(si, n); } } NMD_ASSEMBLY_API void _nmd_append_relative_address16_32(_nmd_string_info* const si) { if (si->runtime_address == NMD_X86_INVALID_RUNTIME_ADDRESS) { _nmd_append_signed_number(si, (int64_t)(si->instruction->immediate + si->instruction->length), true); } else { _nmd_append_number(si,(uint64_t)((int64_t)(si->runtime_address + (uint64_t)si->instruction->length) + (int64_t)((int32_t)(si->instruction->immediate)))); } /* _nmd_append_number(si, ((si->instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && si->instruction->mode == NMD_X86_MODE_32) || (si->instruction->mode == NMD_X86_MODE_16 && !(si->instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE)) ? 0xFFFF : 0xFFFFFFFFFFFFFFFF) & (si->instruction->mode == NMD_X86_MODE_64 ? (uint64_t)((int64_t)(si->runtime_address + (uint64_t)si->instruction->length) + (int64_t)((int32_t)(si->instruction->immediate))) : (uint64_t)((int64_t)(si->runtime_address + (uint64_t)si->instruction->length) + (int64_t)((int32_t)(si->instruction->immediate))) )); */ } NMD_ASSEMBLY_API void _nmd_append_modrm_memory_prefix(_nmd_string_info* const si, const char* addr_specifier_reg) { #ifndef NMD_ASSEMBLY_DISABLE_FORMATTER_POINTER_SIZE if (si->flags & NMD_X86_FORMAT_FLAGS_POINTER_SIZE) { _nmd_append_string(si, addr_specifier_reg); _nmd_append_string(si, " ptr "); } #endif /* NMD_ASSEMBLY_DISABLE_FORMATTER_POINTER_SIZE */ if (!(si->flags & NMD_X86_FORMAT_FLAGS_ONLY_SEGMENT_OVERRIDE && !si->instruction->segment_override)) { size_t i = 0; if (si->instruction->segment_override) i = _nmd_get_bit_index(si->instruction->segment_override); _nmd_append_string(si, si->instruction->segment_override ? _nmd_segment_reg[i] : (!(si->instruction->prefixes & NMD_X86_PREFIXES_REX_B) && (si->instruction->modrm.fields.rm == 0b100 || si->instruction->modrm.fields.rm == 0b101) ? "ss" : "ds")); *si->buffer++ = ':'; } } NMD_ASSEMBLY_API void _nmd_append_modrm16_upper(_nmd_string_info* const si) { *si->buffer++ = '['; if (!(si->instruction->modrm.fields.mod == 0b00 && si->instruction->modrm.fields.rm == 0b110)) { const char* addresses[] = { "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx" }; _nmd_append_string(si, addresses[si->instruction->modrm.fields.rm]); } if (si->instruction->disp_mask != NMD_X86_DISP_NONE && (si->instruction->displacement != 0 || *(si->buffer - 1) == '[')) { if (si->instruction->modrm.fields.mod == 0b00 && si->instruction->modrm.fields.rm == 0b110) _nmd_append_number(si, si->instruction->displacement); else { const bool is_negative = si->instruction->displacement & (1U << (si->instruction->disp_mask * 8 - 1)); if (*(si->buffer - 1) != '[') *si->buffer++ = is_negative ? '-' : '+'; if (is_negative) { const uint16_t mask = (uint16_t)(si->instruction->disp_mask == 2 ? 0xFFFF : 0xFF); _nmd_append_number(si, (uint64_t)(~si->instruction->displacement & mask) + 1); } else _nmd_append_number(si, si->instruction->displacement); } } *si->buffer++ = ']'; } NMD_ASSEMBLY_API void _nmd_append_modrm32_upper(_nmd_string_info* const si) { *si->buffer++ = '['; if (si->instruction->has_sib) { if (si->instruction->sib.fields.base == 0b101) { if (si->instruction->modrm.fields.mod != 0b00) _nmd_append_string(si, si->instruction->mode == NMD_X86_MODE_64 && !(si->instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE) ? (si->instruction->prefixes & NMD_X86_PREFIXES_REX_B ? "r13" : "rbp") : "ebp"); } else _nmd_append_string(si, (si->instruction->mode == NMD_X86_MODE_64 && !(si->instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE) ? (si->instruction->prefixes & NMD_X86_PREFIXES_REX_B ? _nmd_regrx : _nmd_reg64) : _nmd_reg32)[si->instruction->sib.fields.base]); if (si->instruction->sib.fields.index != 0b100) { if (!(si->instruction->sib.fields.base == 0b101 && si->instruction->modrm.fields.mod == 0b00)) *si->buffer++ = '+'; _nmd_append_string(si, (si->instruction->mode == NMD_X86_MODE_64 && !(si->instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE) ? (si->instruction->prefixes & NMD_X86_PREFIXES_REX_X ? _nmd_regrx : _nmd_reg64) : _nmd_reg32)[si->instruction->sib.fields.index]); if (!(si->instruction->sib.fields.scale == 0b00 && !(si->flags & NMD_X86_FORMAT_FLAGS_SCALE_ONE))) *si->buffer++ = '*', *si->buffer++ = (char)('0' + (1 << si->instruction->sib.fields.scale)); } if (si->instruction->prefixes & NMD_X86_PREFIXES_REX_X && si->instruction->sib.fields.index == 0b100) { if (*(si->buffer - 1) != '[') *si->buffer++ = '+'; _nmd_append_string(si, "r12"); if (!(si->instruction->sib.fields.scale == 0b00 && !(si->flags & NMD_X86_FORMAT_FLAGS_SCALE_ONE))) *si->buffer++ = '*', *si->buffer++ = (char)('0' + (1 << si->instruction->sib.fields.scale)); } } else if (!(si->instruction->modrm.fields.mod == 0b00 && si->instruction->modrm.fields.rm == 0b101)) { if ((si->instruction->prefixes & (NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE | NMD_X86_PREFIXES_REX_B)) == (NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE | NMD_X86_PREFIXES_REX_B) && si->instruction->mode == NMD_X86_MODE_64) _nmd_append_string(si, _nmd_regrx[si->instruction->modrm.fields.rm]), *si->buffer++ = 'd'; else _nmd_append_string(si, (si->instruction->mode == NMD_X86_MODE_64 && !(si->instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE) ? (si->instruction->prefixes & NMD_X86_PREFIXES_REX_B ? _nmd_regrx : _nmd_reg64) : _nmd_reg32)[si->instruction->modrm.fields.rm]); } /* Handle displacement. */ if (si->instruction->disp_mask != NMD_X86_DISP_NONE && (si->instruction->displacement != 0 || *(si->buffer - 1) == '[')) { /* Relative address. */ if (si->instruction->modrm.fields.rm == 0b101 && si->instruction->mode == NMD_X86_MODE_64 && si->instruction->modrm.fields.mod == 0b00 && si->runtime_address != NMD_X86_INVALID_RUNTIME_ADDRESS) { if (si->instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE) _nmd_append_number(si, (uint64_t)((int64_t)(si->runtime_address + (uint64_t)si->instruction->length) + (int64_t)si->instruction->displacement)); else _nmd_append_number(si, (uint64_t)((int64_t)(si->runtime_address + si->instruction->length) + (int64_t)((int32_t)si->instruction->displacement))); } else if (si->instruction->modrm.fields.mod == 0b00 && ((si->instruction->sib.fields.base == 0b101 && si->instruction->sib.fields.index == 0b100) || si->instruction->modrm.fields.rm == 0b101) && *(si->buffer - 1) == '[') _nmd_append_number(si, si->instruction->mode == NMD_X86_MODE_64 ? 0xFFFFFFFF00000000 | si->instruction->displacement : si->instruction->displacement); else { if (si->instruction->modrm.fields.rm == 0b101 && si->instruction->mode == NMD_X86_MODE_64 && si->instruction->modrm.fields.mod == 0b00) _nmd_append_string(si, si->instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE ? "eip" : "rip"); const bool is_negative = si->instruction->displacement & (1 << (si->instruction->disp_mask * 8 - 1)); if (*(si->buffer - 1) != '[') *si->buffer++ = is_negative ? '-' : '+'; if (is_negative) { const uint32_t mask = (uint32_t)(si->instruction->disp_mask == 4 ? -1 : (1 << (si->instruction->disp_mask * 8)) - 1); _nmd_append_number(si, (uint64_t)(~si->instruction->displacement & mask) + 1); } else _nmd_append_number(si, si->instruction->displacement); } } *si->buffer++ = ']'; } NMD_ASSEMBLY_API void _nmd_append_modrm_upper(_nmd_string_info* const si, const char* addr_specifier_reg) { _nmd_append_modrm_memory_prefix(si, addr_specifier_reg); if ((si->instruction->mode == NMD_X86_MODE_16 && !(si->instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE)) || (si->instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE && si->instruction->mode == NMD_X86_MODE_32)) _nmd_append_modrm16_upper(si); else _nmd_append_modrm32_upper(si); } NMD_ASSEMBLY_API void _nmd_append_modrm_upper_without_address_specifier(_nmd_string_info* const si) { if ((si->instruction->mode == NMD_X86_MODE_16 && !(si->instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE)) || (si->instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE && si->instruction->mode == NMD_X86_MODE_32)) _nmd_append_modrm16_upper(si); else _nmd_append_modrm32_upper(si); } NMD_ASSEMBLY_API void _nmd_append_Nq(_nmd_string_info* const si) { *si->buffer++ = 'm', *si->buffer++ = 'm'; *si->buffer++ = (char)('0' + si->instruction->modrm.fields.rm); } NMD_ASSEMBLY_API void _nmd_append_Pq(_nmd_string_info* const si) { *si->buffer++ = 'm', *si->buffer++ = 'm'; *si->buffer++ = (char)('0' + si->instruction->modrm.fields.reg); } NMD_ASSEMBLY_API void _nmd_append_avx_register_reg(_nmd_string_info* const si) { *si->buffer++ = si->instruction->vex.L ? 'y' : 'x'; _nmd_append_Pq(si); } NMD_ASSEMBLY_API void _nmd_append_avx_vvvv_register(_nmd_string_info* const si) { *si->buffer++ = si->instruction->vex.L ? 'y' : 'x'; *si->buffer++ = 'm', *si->buffer++ = 'm'; if ((15 - si->instruction->vex.vvvv) > 9) *si->buffer++ = '1', *si->buffer++ = (char)(0x26 + (15 - si->instruction->vex.vvvv)); else *si->buffer++ = (char)('0' + (15 - si->instruction->vex.vvvv)); } NMD_ASSEMBLY_API void _nmd_append_Vdq(_nmd_string_info* const si) { *si->buffer++ = 'x'; _nmd_append_Pq(si); } NMD_ASSEMBLY_API void _nmd_append_Vqq(_nmd_string_info* const si) { *si->buffer++ = 'y'; _nmd_append_Pq(si); } NMD_ASSEMBLY_API void _nmd_append_Vx(_nmd_string_info* const si) { if (si->instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) _nmd_append_Vdq(si); else _nmd_append_Vqq(si); } NMD_ASSEMBLY_API void _nmd_append_Udq(_nmd_string_info* const si) { *si->buffer++ = 'x'; _nmd_append_Nq(si); } NMD_ASSEMBLY_API void _nmd_append_Uqq(_nmd_string_info* const si) { *si->buffer++ = 'y'; _nmd_append_Nq(si); } NMD_ASSEMBLY_API void _nmd_append_Ux(_nmd_string_info* const si) { if (si->instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) _nmd_append_Udq(si); else _nmd_append_Uqq(si); } NMD_ASSEMBLY_API void _nmd_append_Qq(_nmd_string_info* const si) { if (si->instruction->modrm.fields.mod == 0b11) _nmd_append_Nq(si); else _nmd_append_modrm_upper(si, "qword"); } NMD_ASSEMBLY_API void _nmd_append_Ev(_nmd_string_info* const si) { if (si->instruction->modrm.fields.mod == 0b11) { if (si->instruction->prefixes & NMD_X86_PREFIXES_REX_B) { _nmd_append_string(si, _nmd_regrx[si->instruction->modrm.fields.rm]); if (!(si->instruction->prefixes & NMD_X86_PREFIXES_REX_W)) *si->buffer++ = 'd'; } else _nmd_append_string(si, ((si->instruction->rex_w_prefix ? _nmd_reg64 : (si->instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && si->instruction->mode != NMD_X86_MODE_16) || (si->instruction->mode == NMD_X86_MODE_16 && !(si->instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE)) ? _nmd_reg16 : _nmd_reg32))[si->instruction->modrm.fields.rm]); } else _nmd_append_modrm_upper(si, (si->instruction->rex_w_prefix) ? "qword" : ((si->instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && si->instruction->mode != NMD_X86_MODE_16) || (si->instruction->mode == NMD_X86_MODE_16 && !(si->instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE)) ? "word" : "dword")); } NMD_ASSEMBLY_API void _nmd_append_Ey(_nmd_string_info* const si) { if (si->instruction->modrm.fields.mod == 0b11) _nmd_append_string(si, (si->instruction->rex_w_prefix ? _nmd_reg64 : _nmd_reg32)[si->instruction->modrm.fields.rm]); else _nmd_append_modrm_upper(si, si->instruction->rex_w_prefix ? "qword" : "dword"); } NMD_ASSEMBLY_API void _nmd_append_Eb(_nmd_string_info* const si) { if (si->instruction->modrm.fields.mod == 0b11) { if (si->instruction->prefixes & NMD_X86_PREFIXES_REX_B) _nmd_append_string(si, _nmd_regrx[si->instruction->modrm.fields.rm]), *si->buffer++ = 'b'; else _nmd_append_string(si, (si->instruction->has_rex ? _nmd_reg8_x64 : _nmd_reg8)[si->instruction->modrm.fields.rm]); } else _nmd_append_modrm_upper(si, "byte"); } NMD_ASSEMBLY_API void _nmd_append_Ew(_nmd_string_info* const si) { if (si->instruction->modrm.fields.mod == 0b11) _nmd_append_string(si, _nmd_reg16[si->instruction->modrm.fields.rm]); else _nmd_append_modrm_upper(si, "word"); } NMD_ASSEMBLY_API void _nmd_append_Ed(_nmd_string_info* const si) { if (si->instruction->modrm.fields.mod == 0b11) _nmd_append_string(si, _nmd_reg32[si->instruction->modrm.fields.rm]); else _nmd_append_modrm_upper(si, "dword"); } NMD_ASSEMBLY_API void _nmd_append_Eq(_nmd_string_info* const si) { if (si->instruction->modrm.fields.mod == 0b11) _nmd_append_string(si, _nmd_reg64[si->instruction->modrm.fields.rm]); else _nmd_append_modrm_upper(si, "qword"); } NMD_ASSEMBLY_API void _nmd_append_Rv(_nmd_string_info* const si) { _nmd_append_string(si, (si->instruction->rex_w_prefix ? _nmd_reg64 : (si->instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? _nmd_reg16 : _nmd_reg32))[si->instruction->modrm.fields.rm]); } NMD_ASSEMBLY_API void _nmd_append_Gv(_nmd_string_info* const si) { if (si->instruction->prefixes & NMD_X86_PREFIXES_REX_R) { _nmd_append_string(si, _nmd_regrx[si->instruction->modrm.fields.reg]); if (!(si->instruction->prefixes & NMD_X86_PREFIXES_REX_W)) *si->buffer++ = 'd'; } else _nmd_append_string(si, ((si->instruction->rex_w_prefix) ? _nmd_reg64 : ((si->instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && si->instruction->mode != NMD_X86_MODE_16) || (si->instruction->mode == NMD_X86_MODE_16 && !(si->instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE)) ? _nmd_reg16 : _nmd_reg32))[si->instruction->modrm.fields.reg]); } NMD_ASSEMBLY_API void _nmd_append_Gy(_nmd_string_info* const si) { _nmd_append_string(si, (si->instruction->rex_w_prefix ? _nmd_reg64 : _nmd_reg32)[si->instruction->modrm.fields.reg]); } NMD_ASSEMBLY_API void _nmd_append_Gb(_nmd_string_info* const si) { if (si->instruction->prefixes & NMD_X86_PREFIXES_REX_R) _nmd_append_string(si, _nmd_regrx[si->instruction->modrm.fields.reg]), *si->buffer++ = 'b'; else _nmd_append_string(si, (si->instruction->has_rex ? _nmd_reg8_x64 : _nmd_reg8)[si->instruction->modrm.fields.reg]); } NMD_ASSEMBLY_API void _nmd_append_Gw(_nmd_string_info* const si) { _nmd_append_string(si, _nmd_reg16[si->instruction->modrm.fields.reg]); } NMD_ASSEMBLY_API void _nmd_append_W(_nmd_string_info* const si) { if (si->instruction->modrm.fields.mod == 0b11) _nmd_append_string(si, "xmm"), *si->buffer++ = (char)('0' + si->instruction->modrm.fields.rm); else _nmd_append_modrm_upper(si, "xmmword"); } #ifndef NMD_ASSEMBLY_DISABLE_FORMATTER_ATT_SYNTAX NMD_ASSEMBLY_API char* _nmd_format_operand_to_att(char* operand, _nmd_string_info* si) { char* next_operand = (char*)_nmd_strchr(operand, ','); const char* operand_end = next_operand ? next_operand : si->buffer; /* Memory operand. */ const char* memory_operand = _nmd_strchr(operand, '['); if (memory_operand && memory_operand < operand_end) { memory_operand++; const char* segment_reg = _nmd_strchr(operand, ':'); if (segment_reg) { if (segment_reg == operand + 2) _nmd_insert_char(operand, '%'), si->buffer++, operand += 4; else { *operand++ = '%'; *operand++ = *(segment_reg - 2); *operand++ = 's'; *operand++ = ':'; } } /* Handle displacement. */ char* displacement = operand; do { displacement++; displacement = (char*)_nmd_find_number(displacement, operand_end); } while (displacement && ((*(displacement - 1) != '+' && *(displacement - 1) != '-' && *(displacement - 1) != '[') || !_nmd_is_number(displacement, operand_end - 2))); bool is_there_base_or_index = true; char memory_operand_buffer[96]; if (displacement) { if (*(displacement - 1) != '[') displacement--; else is_there_base_or_index = false; char* i = (char*)memory_operand; char* j = memory_operand_buffer; for (; i < displacement; i++, j++) *j = *i; *j = '\0'; if (*displacement == '+') displacement++; for (; *displacement != ']'; displacement++, operand++) *operand = *displacement; } /* Handle base, index and scale. */ if (is_there_base_or_index) { *operand++ = '('; char* base_or_index = operand; if (displacement) { char* s = memory_operand_buffer; for (; *s; s++, operand++) *operand = *s; } else { for (; *memory_operand != ']'; operand++, memory_operand++) *operand = *memory_operand; } _nmd_insert_char(base_or_index, '%'); operand++; *operand++ = ')'; for (; *base_or_index != ')'; base_or_index++) { if (*base_or_index == '+' || *base_or_index == '*') { if (*base_or_index == '+') _nmd_insert_char(base_or_index + 1, '%'), operand++; *base_or_index = ','; } } operand = base_or_index; operand++; } if (next_operand) { /* Move second operand to the left until the comma. */ operand_end = _nmd_strchr(operand, ','); for (; *operand_end != '\0'; operand++, operand_end++) *operand = *operand_end; *operand = '\0'; operand_end = operand; while (*operand_end != ',') operand_end--; } else *operand = '\0', operand_end = operand; si->buffer = operand; return (char*)operand_end; } else /* Immediate or register operand. */ { _nmd_insert_char(operand, _nmd_is_number(operand, operand_end) ? '$' : '%'); si->buffer++; return (char*)operand_end + 1; } } #endif /* NMD_ASSEMBLY_DISABLE_FORMATTER_ATT_SYNTAX */ /* Formats an instruction. This function may cause a crash if you modify 'instruction' manually. Parameters: - instruction [in] A pointer to a variable of type 'nmd_x86_instruction' describing the instruction to be formatted. - buffer [out] A pointer to buffer that receives the string. The buffer's recommended size is 128 bytes. - runtime_address [in] The instruction's runtime address. You may use 'NMD_X86_INVALID_RUNTIME_ADDRESS'. - flags [in] A mask of 'NMD_X86_FORMAT_FLAGS_XXX' that specifies how the function should format the instruction. If uncertain, use 'NMD_X86_FORMAT_FLAGS_DEFAULT'. */ NMD_ASSEMBLY_API void nmd_x86_format(const nmd_x86_instruction* instruction, char* buffer, uint64_t runtime_address, uint32_t flags) { if (!instruction->valid) { buffer[0] = '\0'; return; } _nmd_string_info si; si.buffer = buffer; si.instruction = instruction; si.runtime_address = runtime_address; si.flags = flags; #ifndef NMD_ASSEMBLY_DISABLE_FORMATTER_BYTES if (flags & NMD_X86_FORMAT_FLAGS_BYTES) { size_t i = 0; for (; i < instruction->length; i++) { uint8_t num = instruction->buffer[i] >> 4; *si.buffer++ = (char)((num > 9 ? 0x37 : '0') + num); num = instruction->buffer[i] & 0xf; *si.buffer++ = (char)((num > 9 ? 0x37 : '0') + num); *si.buffer++ = ' '; } const size_t num_padding_bytes = instruction->length < NMD_X86_FORMATTER_NUM_PADDING_BYTES ? (NMD_X86_FORMATTER_NUM_PADDING_BYTES - instruction->length) : 0; for (i = 0; i < num_padding_bytes * 3; i++) *si.buffer++ = ' '; } #endif /* NMD_ASSEMBLY_DISABLE_FORMATTER_BYTES */ const uint8_t op = instruction->opcode; if (instruction->prefixes & (NMD_X86_PREFIXES_REPEAT | NMD_X86_PREFIXES_REPEAT_NOT_ZERO) && (instruction->prefixes & NMD_X86_PREFIXES_LOCK || ((op == 0x86 || op == 0x87) && instruction->modrm.fields.mod != 0b11))) _nmd_append_string(&si, instruction->repeat_prefix ? "xrelease " : "xacquire "); else if (instruction->prefixes & NMD_X86_PREFIXES_REPEAT_NOT_ZERO && (instruction->opcode_size == 1 && (op == 0xc2 || op == 0xc3 || op == 0xe8 || op == 0xe9 || _NMD_R(op) == 7 || (op == 0xff && (instruction->modrm.fields.reg == 0b010 || instruction->modrm.fields.reg == 0b100))))) _nmd_append_string(&si, "bnd "); if (instruction->prefixes & NMD_X86_PREFIXES_LOCK) _nmd_append_string(&si, "lock "); const bool opszprfx = instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE; if (instruction->opcode_map == NMD_X86_OPCODE_MAP_DEFAULT) { #ifndef NMD_ASSEMBLY_DISABLE_FORMATTER_EVEX if (instruction->encoding == NMD_X86_ENCODING_EVEX) { } #endif /* NMD_ASSEMBLY_DISABLE_FORMATTER_EVEX */ #if !defined(NMD_ASSEMBLY_DISABLE_FORMATTER_EVEX) && !defined(NMD_ASSEMBLY_DISABLE_FORMATTER_VEX) else #endif #ifndef NMD_ASSEMBLY_DISABLE_FORMATTER_VEX if (instruction->encoding == NMD_X86_ENCODING_VEX) { if (instruction->vex.vex[0] == 0xc4) { if (instruction->opcode == 0x0c || instruction->opcode == 0x0d || instruction->opcode == 0x4a || instruction->opcode == 0x4b) { _nmd_append_string(&si, instruction->opcode == 0x0c ? "vblendps" : (instruction->opcode == 0x0c ? "vblendpd" : (instruction->opcode == 0x4a ? "vblendvps" : "vblendvpd"))); *si.buffer++ = ' '; _nmd_append_avx_register_reg(&si); *si.buffer++ = ','; _nmd_append_avx_vvvv_register(&si); *si.buffer++ = ','; _nmd_append_W(&si); *si.buffer++ = ','; if(instruction->opcode <= 0x0d) _nmd_append_number(&si, instruction->immediate); else { _nmd_append_string(&si, "xmm"); *si.buffer++ = (char)('0' + ((instruction->immediate & 0xf0) >> 4) % 8); } } else if (instruction->opcode == 0x40 || instruction->opcode == 0x41) { _nmd_append_string(&si, instruction->opcode == 0x40 ? "vdpps" : "vdppd"); *si.buffer++ = ' '; _nmd_append_avx_register_reg(&si); *si.buffer++ = ','; _nmd_append_avx_vvvv_register(&si); *si.buffer++ = ','; _nmd_append_W(&si); *si.buffer++ = ','; _nmd_append_number(&si, instruction->immediate); } else if (instruction->opcode == 0x17) { _nmd_append_string(&si, "vextractps "); _nmd_append_Ev(&si); *si.buffer++ = ','; _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_number(&si, instruction->immediate); } else if (instruction->opcode == 0x21) { _nmd_append_string(&si, "vinsertps "); _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_avx_vvvv_register(&si); *si.buffer++ = ','; _nmd_append_W(&si); *si.buffer++ = ','; _nmd_append_number(&si, instruction->immediate); } else if (instruction->opcode == 0x2a) { _nmd_append_string(&si, "vmovntdqa "); _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_modrm_upper_without_address_specifier(&si); } else if (instruction->opcode == 0x42) { _nmd_append_string(&si, "vmpsadbw "); _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_avx_vvvv_register(&si); *si.buffer++ = ','; if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, "xmm"), *si.buffer++ = (char)('0' + si.instruction->modrm.fields.rm); else _nmd_append_modrm_upper_without_address_specifier(&si); *si.buffer++ = ','; _nmd_append_number(&si, instruction->immediate); } } } #endif /* NMD_ASSEMBLY_DISABLE_FORMATTER_VEX */ #if (!defined(NMD_ASSEMBLY_DISABLE_FORMATTER_EVEX) || !defined(NMD_ASSEMBLY_DISABLE_FORMATTER_VEX)) && !defined(NMD_ASSEMBLY_DISABLE_FORMATTER_3DNOW) else #endif #ifndef NMD_ASSEMBLY_DISABLE_FORMATTER_3DNOW if (instruction->encoding == NMD_X86_ENCODING_3DNOW) { const char* mnemonic = 0; switch (instruction->opcode) { case 0x0c: mnemonic = "pi2fw"; break; case 0x0d: mnemonic = "pi2fd"; break; case 0x1c: mnemonic = "pf2iw"; break; case 0x1d: mnemonic = "pf2id"; break; case 0x8a: mnemonic = "pfnacc"; break; case 0x8e: mnemonic = "pfpnacc"; break; case 0x90: mnemonic = "pfcmpge"; break; case 0x94: mnemonic = "pfmin"; break; case 0x96: mnemonic = "pfrcp"; break; case 0x97: mnemonic = "pfrsqrt"; break; case 0x9a: mnemonic = "pfsub"; break; case 0x9e: mnemonic = "pfadd"; break; case 0xa0: mnemonic = "pfcmpgt"; break; case 0xa4: mnemonic = "pfmax"; break; case 0xa6: mnemonic = "pfrcpit1"; break; case 0xa7: mnemonic = "pfrsqit1"; break; case 0xaa: mnemonic = "pfsubr"; break; case 0xae: mnemonic = "pfacc"; break; case 0xb0: mnemonic = "pfcmpeq"; break; case 0xb4: mnemonic = "pfmul"; break; case 0xb6: mnemonic = "pfrcpit2"; break; case 0xb7: mnemonic = "pmulhrw"; break; case 0xbb: mnemonic = "pswapd"; break; case 0xbf: mnemonic = "pavgusb"; break; default: return; } _nmd_append_string(&si, mnemonic); *si.buffer++ = ' '; _nmd_append_Pq(&si); *si.buffer++ = ','; _nmd_append_Qq(&si); } #endif /* NMD_ASSEMBLY_DISABLE_FORMATTER_3DNOW */ #if !defined(NMD_ASSEMBLY_DISABLE_FORMATTER_EVEX) || !defined(NMD_ASSEMBLY_DISABLE_FORMATTER_VEX) || !defined(NMD_ASSEMBLY_DISABLE_FORMATTER_3DNOW) else /*if (instruction->encoding == INSTRUCTION_ENCODING_LEGACY) */ #endif { if (op >= 0x88 && op <= 0x8c) /* mov [88,8c] */ { _nmd_append_string(&si, "mov "); if (op == 0x8b) { _nmd_append_Gv(&si); *si.buffer++ = ','; _nmd_append_Ev(&si); } else if (op == 0x89) { _nmd_append_Ev(&si); *si.buffer++ = ','; _nmd_append_Gv(&si); } else if (op == 0x88) { _nmd_append_Eb(&si); *si.buffer++ = ','; _nmd_append_Gb(&si); } else if (op == 0x8a) { _nmd_append_Gb(&si); *si.buffer++ = ','; _nmd_append_Eb(&si); } else if (op == 0x8c) { if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, (si.instruction->rex_w_prefix ? _nmd_reg64 : (si.instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE || instruction->mode == NMD_X86_MODE_16 ? _nmd_reg16 : _nmd_reg32))[si.instruction->modrm.fields.rm]); else _nmd_append_modrm_upper(&si, "word"); *si.buffer++ = ','; _nmd_append_string(&si, _nmd_segment_reg[instruction->modrm.fields.reg]); } } else if (op == 0x68 || op == 0x6A) /* push */ { _nmd_append_string(&si, "push "); if (op == 0x6a) { if (flags & NMD_X86_FORMAT_FLAGS_SIGNED_NUMBER_MEMORY_VIEW && instruction->immediate >= 0x80) _nmd_append_signed_number_memory_view(&si); else _nmd_append_signed_number(&si, (int8_t)instruction->immediate, false); } else _nmd_append_number(&si, instruction->immediate); } else if (op == 0xff) /* Opcode extensions Group 5 */ { _nmd_append_string(&si, _nmd_opcode_extensions_grp5[instruction->modrm.fields.reg]); *si.buffer++ = ' '; if (instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, (si.instruction->rex_w_prefix ? _nmd_reg64 : (opszprfx ? _nmd_reg16 : _nmd_reg32))[si.instruction->modrm.fields.rm]); else _nmd_append_modrm_upper(&si, (instruction->modrm.fields.reg == 0b011 || instruction->modrm.fields.reg == 0b101) ? "fword" : (instruction->mode == NMD_X86_MODE_64 && ((instruction->modrm.fields.reg >= 0b010 && instruction->modrm.fields.reg <= 0b110) || (instruction->prefixes & NMD_X86_PREFIXES_REX_W && instruction->modrm.fields.reg <= 0b010)) ? "qword" : (opszprfx ? "word" : "dword"))); } else if (_NMD_R(op) < 4 && (_NMD_C(op) < 6 || (_NMD_C(op) >= 8 && _NMD_C(op) < 0xE))) /* add,adc,and,xor,or,sbb,sub,cmp */ { _nmd_append_string(&si, _nmd_op1_opcode_map_mnemonics[_NMD_R((_NMD_C(op) > 6 ? op + 0x40 : op))]); *si.buffer++ = ' '; switch (op % 8) { case 0: _nmd_append_Eb(&si); *si.buffer++ = ','; _nmd_append_Gb(&si); break; case 1: _nmd_append_Ev(&si); *si.buffer++ = ','; _nmd_append_Gv(&si); break; case 2: _nmd_append_Gb(&si); *si.buffer++ = ','; _nmd_append_Eb(&si); break; case 3: _nmd_append_Gv(&si); *si.buffer++ = ','; _nmd_append_Ev(&si); break; case 4: _nmd_append_string(&si, "al,"); _nmd_append_number(&si, instruction->immediate); break; case 5: _nmd_append_string(&si, instruction->rex_w_prefix ? "rax" : (opszprfx ? "ax" : "eax")); *si.buffer++ = ','; _nmd_append_number(&si, instruction->immediate); break; } } else if (_NMD_R(op) == 4 || _NMD_R(op) == 5) /* inc,dec,push,pop [0x40, 0x5f] */ { _nmd_append_string(&si, _NMD_C(op) < 8 ? (_NMD_R(op) == 4 ? "inc " : "push ") : (_NMD_R(op) == 4 ? "dec " : "pop ")); _nmd_append_string(&si, (instruction->prefixes & NMD_X86_PREFIXES_REX_B ? (opszprfx ? _nmd_regrxw : _nmd_regrx) : (opszprfx ? (instruction->mode == NMD_X86_MODE_16 ? _nmd_reg32 : _nmd_reg16) : ((instruction->mode == NMD_X86_MODE_32 ? _nmd_reg32 : (instruction->mode == NMD_X86_MODE_64 ? _nmd_reg64 : _nmd_reg16)))))[op % 8]); } else if (op >= 0x80 && op < 0x84) /* add,adc,and,xor,or,sbb,sub,cmp [80,83] */ { _nmd_append_string(&si, _nmd_opcode_extensions_grp1[instruction->modrm.fields.reg]); *si.buffer++ = ' '; if (op == 0x80 || op == 0x82) _nmd_append_Eb(&si); else _nmd_append_Ev(&si); *si.buffer++ = ','; if (op == 0x83) { if ((instruction->modrm.fields.reg == 0b001 || instruction->modrm.fields.reg == 0b100 || instruction->modrm.fields.reg == 0b110) && instruction->immediate >= 0x80) _nmd_append_number(&si, (instruction->prefixes & NMD_X86_PREFIXES_REX_W ? 0xFFFFFFFFFFFFFF00 : (instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE || instruction->mode == NMD_X86_MODE_16 ? 0xFF00 : 0xFFFFFF00)) | instruction->immediate); else _nmd_append_signed_number(&si, (int8_t)(instruction->immediate), false); } else _nmd_append_number(&si, instruction->immediate); } else if (op == 0xe8 || op == 0xe9 || op == 0xeb) /* call,jmp */ { _nmd_append_string(&si, op == 0xe8 ? "call " : "jmp "); if (op == 0xeb) _nmd_append_relative_address8(&si); else _nmd_append_relative_address16_32(&si); } else if (op >= 0xA0 && op < 0xA4) /* mov [a0, a4] */ { _nmd_append_string(&si, "mov "); if (op == 0xa0) { _nmd_append_string(&si, "al,"); _nmd_append_modrm_memory_prefix(&si, "byte"); *si.buffer++ = '['; _nmd_append_number(&si, (instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE || instruction->mode == NMD_X86_MODE_16 ? 0xFFFF : 0xFFFFFFFFFFFFFFFF) & instruction->immediate); *si.buffer++ = ']'; } else if (op == 0xa1) { _nmd_append_string(&si, instruction->rex_w_prefix ? "rax," : (opszprfx ? "ax," : "eax,")); _nmd_append_modrm_memory_prefix(&si, instruction->rex_w_prefix ? "qword" : (opszprfx ? "word" : "dword")); *si.buffer++ = '['; _nmd_append_number(&si, (instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE || instruction->mode == NMD_X86_MODE_16 ? 0xFFFF : 0xFFFFFFFFFFFFFFFF) & instruction->immediate); *si.buffer++ = ']'; } else if (op == 0xa2) { _nmd_append_modrm_memory_prefix(&si, "byte"); *si.buffer++ = '['; _nmd_append_number(&si, (instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE || instruction->mode == NMD_X86_MODE_16 ? 0xFFFF : 0xFFFFFFFFFFFFFFFF) & instruction->immediate); _nmd_append_string(&si, "],al"); } else if (op == 0xa3) { _nmd_append_modrm_memory_prefix(&si, instruction->rex_w_prefix ? "qword" : (opszprfx ? "word" : "dword")); *si.buffer++ = '['; _nmd_append_number(&si, (instruction->prefixes & NMD_X86_PREFIXES_ADDRESS_SIZE_OVERRIDE || instruction->mode == NMD_X86_MODE_16 ? 0xFFFF : 0xFFFFFFFFFFFFFFFF) & instruction->immediate); _nmd_append_string(&si, "],"); _nmd_append_string(&si, instruction->rex_w_prefix ? "rax" : (opszprfx ? "ax" : "eax")); } } else if(op == 0xcc) /* int3 */ _nmd_append_string(&si, "int3"); else if (op == 0x8d) /* lea */ { _nmd_append_string(&si, "lea "); _nmd_append_Gv(&si); *si.buffer++ = ','; _nmd_append_modrm_upper_without_address_specifier(&si); } else if (op == 0x8f) /* pop */ { _nmd_append_string(&si, "pop "); if (instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, (opszprfx ? _nmd_reg16 : _nmd_reg32)[instruction->modrm.fields.rm]); else _nmd_append_modrm_upper(&si, instruction->mode == NMD_X86_MODE_64 && !(instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) ? "qword" : (opszprfx ? "word" : "dword")); } else if (_NMD_R(op) == 7) /* conditional jump [70,7f]*/ { *si.buffer++ = 'j'; _nmd_append_string(&si, _nmd_condition_suffixes[_NMD_C(op)]); *si.buffer++ = ' '; _nmd_append_relative_address8(&si); } else if (op == 0xa8) /* test */ { _nmd_append_string(&si, "test al,"); _nmd_append_number(&si, instruction->immediate); } else if (op == 0xa9) /* test */ { _nmd_append_string(&si, instruction->rex_w_prefix ? "test rax" : (opszprfx ? "test ax" : "test eax")); *si.buffer++ = ','; _nmd_append_number(&si, instruction->immediate); } else if (op == 0x90) { if (instruction->prefixes & NMD_X86_PREFIXES_REPEAT) _nmd_append_string(&si, "pause"); else if (instruction->prefixes & NMD_X86_PREFIXES_REX_B) _nmd_append_string(&si, instruction->prefixes & NMD_X86_PREFIXES_REX_W ? "xchg r8,rax" : "xchg r8d,eax"); else _nmd_append_string(&si, "nop"); } else if(op == 0xc3) _nmd_append_string(&si, "ret"); else if (_NMD_R(op) == 0xb) /* mov [b0, bf] */ { _nmd_append_string(&si, "mov "); if (instruction->prefixes & NMD_X86_PREFIXES_REX_B) _nmd_append_string(&si, _nmd_regrx[op % 8]), * si.buffer++ = _NMD_C(op) < 8 ? 'b' : 'd'; else _nmd_append_string(&si, (_NMD_C(op) < 8 ? (instruction->has_rex ? _nmd_reg8_x64 : _nmd_reg8) : (instruction->rex_w_prefix ? _nmd_reg64 : (opszprfx ? _nmd_reg16 : _nmd_reg32)))[op % 8]); *si.buffer++ = ','; _nmd_append_number(&si, instruction->immediate); } else if (op == 0xfe) /* inc,dec */ { _nmd_append_string(&si, instruction->modrm.fields.reg == 0b000 ? "inc " : "dec "); _nmd_append_Eb(&si); } else if (op == 0xf6 || op == 0xf7) /* test,test,not,neg,mul,imul,div,idiv */ { _nmd_append_string(&si, _nmd_opcode_extensions_grp3[instruction->modrm.fields.reg]); *si.buffer++ = ' '; if (op == 0xf6) _nmd_append_Eb(&si); else _nmd_append_Ev(&si); if (instruction->modrm.fields.reg <= 0b001) { *si.buffer++ = ','; _nmd_append_number(&si, instruction->immediate); } } else if (op == 0x69 || op == 0x6B) { _nmd_append_string(&si, "imul "); _nmd_append_Gv(&si); *si.buffer++ = ','; _nmd_append_Ev(&si); *si.buffer++ = ','; if (op == 0x6b) { if (si.flags & NMD_X86_FORMAT_FLAGS_SIGNED_NUMBER_MEMORY_VIEW && instruction->immediate >= 0x80) _nmd_append_signed_number_memory_view(&si); else _nmd_append_signed_number(&si, (int8_t)instruction->immediate, false); } else _nmd_append_number(&si, instruction->immediate); } else if (op >= 0x84 && op <= 0x87) { _nmd_append_string(&si, op > 0x85 ? "xchg " : "test "); if (op % 2 == 0) { _nmd_append_Eb(&si); *si.buffer++ = ','; _nmd_append_Gb(&si); } else { _nmd_append_Ev(&si); *si.buffer++ = ','; _nmd_append_Gv(&si); } } else if (op == 0x8e) { _nmd_append_string(&si, "mov "); _nmd_append_string(&si, _nmd_segment_reg[instruction->modrm.fields.reg]); *si.buffer++ = ','; _nmd_append_Ew(&si); } else if (op >= 0x91 && op <= 0x97) { _nmd_append_string(&si, "xchg "); if (instruction->prefixes & NMD_X86_PREFIXES_REX_B) { _nmd_append_string(&si, _nmd_regrx[_NMD_C(op)]); if (!(instruction->prefixes & NMD_X86_PREFIXES_REX_W)) *si.buffer++ = 'd'; } else _nmd_append_string(&si, (instruction->prefixes & NMD_X86_PREFIXES_REX_W ? _nmd_reg64 : (opszprfx ? _nmd_reg16 : _nmd_reg32))[_NMD_C(op)]); _nmd_append_string(&si, (instruction->prefixes & NMD_X86_PREFIXES_REX_W ? ",rax" : (opszprfx ? ",ax" : ",eax"))); } else if (op == 0x9A) { _nmd_append_string(&si, "call far "); _nmd_append_number(&si, (uint64_t)(*(uint16_t*)((char*)(&instruction->immediate) + (instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? 2 : 4)))); *si.buffer++ = ':'; _nmd_append_number(&si, (uint64_t)(opszprfx ? *((uint16_t*)(&instruction->immediate)) : *((uint32_t*)(&instruction->immediate)))); } else if ((op >= 0x6c && op <= 0x6f) || (op >= 0xa4 && op <= 0xa7) || (op >= 0xaa && op <= 0xaf)) { if (instruction->prefixes & NMD_X86_PREFIXES_REPEAT) _nmd_append_string(&si, "rep "); else if (instruction->prefixes & NMD_X86_PREFIXES_REPEAT_NOT_ZERO) _nmd_append_string(&si, "repne "); const char* str = 0; switch (op) { case 0x6c: case 0x6d: str = "ins"; break; case 0x6e: case 0x6f: str = "outs"; break; case 0xa4: case 0xa5: str = "movs"; break; case 0xa6: case 0xa7: str = "cmps"; break; case 0xaa: case 0xab: str = "stos"; break; case 0xac: case 0xad: str = "lods"; break; case 0xae: case 0xaf: str = "scas"; break; } _nmd_append_string(&si, str); *si.buffer++ = (op % 2 == 0) ? 'b' : (opszprfx ? 'w' : 'd'); } else if (op == 0xC0 || op == 0xC1 || (_NMD_R(op) == 0xd && _NMD_C(op) < 4)) { _nmd_append_string(&si, _nmd_opcode_extensions_grp2[instruction->modrm.fields.reg]); *si.buffer++ = ' '; if (op % 2 == 0) _nmd_append_Eb(&si); else _nmd_append_Ev(&si); *si.buffer++ = ','; if (_NMD_R(op) == 0xc) _nmd_append_number(&si, instruction->immediate); else if (_NMD_C(op) < 2) _nmd_append_number(&si, 1); else _nmd_append_string(&si, "cl"); } else if (op == 0xc2) { _nmd_append_string(&si, "ret "); _nmd_append_number(&si, instruction->immediate); } else if (op >= 0xe0 && op <= 0xe3) { const char* mnemonics[] = { "loopne", "loope", "loop" }; _nmd_append_string(&si, op == 0xe3 ? (instruction->mode == NMD_X86_MODE_64 ? "jrcxz" : "jecxz") : mnemonics[_NMD_C(op)]); *si.buffer++ = ' '; _nmd_append_relative_address8(&si); } else if (op == 0xea) { _nmd_append_string(&si, "jmp far "); _nmd_append_number(&si, (uint64_t)(*(uint16_t*)(((uint8_t*)(&instruction->immediate) + 4)))); *si.buffer++ = ':'; _nmd_append_number(&si, (uint64_t)(*(uint32_t*)(&instruction->immediate))); } else if (op == 0xca) { _nmd_append_string(&si, "retf "); _nmd_append_number(&si, instruction->immediate); } else if (op == 0xcd) { _nmd_append_string(&si, "int "); _nmd_append_number(&si, instruction->immediate); } else if (op == 0x63) { if (instruction->mode == NMD_X86_MODE_64) { _nmd_append_string(&si, "movsxd "); _nmd_append_string(&si, (instruction->mode == NMD_X86_MODE_64 ? (instruction->prefixes & NMD_X86_PREFIXES_REX_R ? _nmd_regrx : _nmd_reg64) : (opszprfx ? _nmd_reg16 : _nmd_reg32))[instruction->modrm.fields.reg]); *si.buffer++ = ','; if (instruction->modrm.fields.mod == 0b11) { if (instruction->prefixes & NMD_X86_PREFIXES_REX_B) _nmd_append_string(&si, _nmd_regrx[instruction->modrm.fields.rm]), * si.buffer++ = 'd'; else _nmd_append_string(&si, ((instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && instruction->mode == NMD_X86_MODE_32) || (instruction->mode == NMD_X86_MODE_16 && !(instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE)) ? _nmd_reg16 : _nmd_reg32)[instruction->modrm.fields.rm]); } else _nmd_append_modrm_upper(&si, (instruction->rex_w_prefix && !(instruction->prefixes & NMD_X86_PREFIXES_REX_W)) ? "qword" : ((instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && instruction->mode == NMD_X86_MODE_32) || (instruction->mode == NMD_X86_MODE_16 && !(instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE)) ? "word" : "dword")); } else { _nmd_append_string(&si, "arpl "); _nmd_append_Ew(&si); *si.buffer++ = ','; _nmd_append_Gw(&si); } } else if (op == 0xc4 || op == 0xc5) { _nmd_append_string(&si, op == 0xc4 ? "les" : "lds"); *si.buffer++ = ' '; _nmd_append_Gv(&si); *si.buffer++ = ','; if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, (si.instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? _nmd_reg16 : _nmd_reg32)[si.instruction->modrm.fields.rm]); else _nmd_append_modrm_upper(&si, si.instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? "dword" : "fword"); } else if (op == 0xc6 || op == 0xc7) { _nmd_append_string(&si, instruction->modrm.fields.reg == 0b000 ? "mov " : (op == 0xc6 ? "xabort " : "xbegin ")); if (instruction->modrm.fields.reg == 0b111) { if (op == 0xc6) _nmd_append_number(&si, instruction->immediate); else _nmd_append_relative_address16_32(&si); } else { if (op == 0xc6) _nmd_append_Eb(&si); else _nmd_append_Ev(&si); *si.buffer++ = ','; _nmd_append_number(&si, instruction->immediate); } } else if (op == 0xc8) { _nmd_append_string(&si, "enter "); _nmd_append_number(&si, (uint64_t)(*(uint16_t*)(&instruction->immediate))); *si.buffer++ = ','; _nmd_append_number(&si, (uint64_t)(*((uint8_t*)(&instruction->immediate) + 2))); } else if (op == 0xd4) { _nmd_append_string(&si, "aam "); _nmd_append_number(&si, instruction->immediate); } else if (op == 0xd5) { _nmd_append_string(&si, "aad "); _nmd_append_number(&si, instruction->immediate); } else if (op >= 0xd8 && op <= 0xdf) { *si.buffer++ = 'f'; if (instruction->modrm.modrm < 0xc0) { _nmd_append_string(&si, _nmd_escape_opcodes[_NMD_C(op) - 8][instruction->modrm.fields.reg]); *si.buffer++ = ' '; switch (op) { case 0xd8: case 0xda: _nmd_append_modrm_upper(&si, "dword"); break; case 0xd9: _nmd_append_modrm_upper(&si, instruction->modrm.fields.reg & 0b100 ? (instruction->modrm.fields.reg & 0b001 ? "word" : (instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? "m14" : "m28")) : "dword"); break; case 0xdb: _nmd_append_modrm_upper(&si, instruction->modrm.fields.reg & 0b100 ? "tbyte" : "dword"); break; case 0xdc: _nmd_append_modrm_upper(&si, "qword"); break; case 0xdd: _nmd_append_modrm_upper(&si, instruction->modrm.fields.reg & 0b100 ? ((instruction->modrm.fields.reg & 0b111) == 0b111 ? "word" : "byte") : "qword"); break; case 0xde: _nmd_append_modrm_upper(&si, "word"); break; case 0xdf: _nmd_append_modrm_upper(&si, instruction->modrm.fields.reg & 0b100 ? (instruction->modrm.fields.reg & 0b001 ? "qword" : "tbyte") : "word"); break; } } else { switch (op) { case 0xd8: _nmd_append_string(&si, _nmd_escape_opcodesD8[(_NMD_R(instruction->modrm.modrm) - 0xc) * 2 + (_NMD_C(instruction->modrm.modrm) > 7 ? 1 : 0)]); _nmd_append_string(&si, " st(0),st("); *si.buffer++ = (char)('0' + instruction->modrm.modrm % 8), * si.buffer++ = ')'; break; case 0xd9: if (_NMD_R(instruction->modrm.modrm) == 0xc) { _nmd_append_string(&si, _NMD_C(instruction->modrm.modrm) < 8 ? "ld" : "xch"); _nmd_append_string(&si, " st(0),st("); *si.buffer++ = (char)('0' + instruction->modrm.modrm % 8), * si.buffer++ = ')'; } else if (instruction->modrm.modrm >= 0xd8 && instruction->modrm.modrm <= 0xdf) { _nmd_append_string(&si, "stpnce st("); *si.buffer++ = (char)('0' + instruction->modrm.modrm % 8); _nmd_append_string(&si, "),st(0)"); } else { const char* str = 0; switch (instruction->modrm.modrm) { case 0xd0: str = "nop"; break; case 0xe0: str = "chs"; break; case 0xe1: str = "abs"; break; case 0xe4: str = "tst"; break; case 0xe5: str = "xam"; break; case 0xe8: str = "ld1"; break; case 0xe9: str = "ldl2t"; break; case 0xea: str = "ldl2e"; break; case 0xeb: str = "ldpi"; break; case 0xec: str = "ldlg2"; break; case 0xed: str = "ldln2"; break; case 0xee: str = "ldz"; break; case 0xf0: str = "2xm1"; break; case 0xf1: str = "yl2x"; break; case 0xf2: str = "ptan"; break; case 0xf3: str = "patan"; break; case 0xf4: str = "xtract"; break; case 0xf5: str = "prem1"; break; case 0xf6: str = "decstp"; break; case 0xf7: str = "incstp"; break; case 0xf8: str = "prem"; break; case 0xf9: str = "yl2xp1"; break; case 0xfa: str = "sqrt"; break; case 0xfb: str = "sincos"; break; case 0xfc: str = "rndint"; break; case 0xfd: str = "scale"; break; case 0xfe: str = "sin"; break; case 0xff: str = "cos"; break; } _nmd_append_string(&si, str); } break; case 0xda: if (instruction->modrm.modrm == 0xe9) _nmd_append_string(&si, "ucompp"); else { const char* mnemonics[4] = { "cmovb", "cmovbe", "cmove", "cmovu" }; _nmd_append_string(&si, mnemonics[(_NMD_R(instruction->modrm.modrm) - 0xc) + (_NMD_C(instruction->modrm.modrm) > 7 ? 2 : 0)]); _nmd_append_string(&si, " st(0),st("); *si.buffer++ = (char)('0' + instruction->modrm.modrm % 8); *si.buffer++ = ')'; } break; case 0xdb: if (_NMD_R(instruction->modrm.modrm) == 0xe && _NMD_C(instruction->modrm.modrm) < 8) { const char* mnemonics[] = { "eni8087_nop", "disi8087_nop", "nclex", "ninit", "setpm287_nop" }; _nmd_append_string(&si, mnemonics[_NMD_C(instruction->modrm.modrm)]); } else { if (instruction->modrm.modrm >= 0xe0) _nmd_append_string(&si, instruction->modrm.modrm < 0xf0 ? "ucomi" : "comi"); else { _nmd_append_string(&si, "cmovn"); if (instruction->modrm.modrm < 0xc8) *si.buffer++ = 'b'; else if (instruction->modrm.modrm < 0xd0) *si.buffer++ = 'e'; else if (instruction->modrm.modrm >= 0xd8) *si.buffer++ = 'u'; else _nmd_append_string(&si, "be"); } _nmd_append_string(&si, " st(0),st("); *si.buffer++ = (char)('0' + instruction->modrm.modrm % 8); *si.buffer++ = ')'; } break; case 0xdc: if (_NMD_R(instruction->modrm.modrm) == 0xc) _nmd_append_string(&si, _NMD_C(instruction->modrm.modrm) > 7 ? "mul" : "add"); else { _nmd_append_string(&si, _NMD_R(instruction->modrm.modrm) == 0xd ? "com" : (_NMD_R(instruction->modrm.modrm) == 0xe ? "subr" : "div")); if (_NMD_R(instruction->modrm.modrm) == 0xd && _NMD_C(instruction->modrm.modrm) >= 8) { if (_NMD_R(instruction->modrm.modrm) >= 8) *si.buffer++ = 'p'; } else { if (_NMD_R(instruction->modrm.modrm) < 8) *si.buffer++ = 'r'; } } if (_NMD_R(instruction->modrm.modrm) == 0xd) { _nmd_append_string(&si, " st(0),st("); *si.buffer++ = (char)('0' + instruction->modrm.modrm % 8); *si.buffer++ = ')'; } else { _nmd_append_string(&si, " st("); *si.buffer++ = (char)('0' + instruction->modrm.modrm % 8); _nmd_append_string(&si, "),st(0)"); } break; case 0xdd: if (_NMD_R(instruction->modrm.modrm) == 0xc) _nmd_append_string(&si, _NMD_C(instruction->modrm.modrm) < 8 ? "free" : "xch"); else { _nmd_append_string(&si, instruction->modrm.modrm < 0xe0 ? "st" : "ucom"); if (_NMD_C(instruction->modrm.modrm) >= 8) *si.buffer++ = 'p'; } _nmd_append_string(&si, " st("); *si.buffer++ = (char)('0' + instruction->modrm.modrm % 8); *si.buffer++ = ')'; break; case 0xde: if (instruction->modrm.modrm == 0xd9) _nmd_append_string(&si, "compp"); else { if (instruction->modrm.modrm >= 0xd0 && instruction->modrm.modrm <= 0xd7) { _nmd_append_string(&si, "comp st(0),st("); *si.buffer++ = (char)('0' + instruction->modrm.modrm % 8); *si.buffer++ = ')'; } else { if (_NMD_R(instruction->modrm.modrm) == 0xc) _nmd_append_string(&si, _NMD_C(instruction->modrm.modrm) < 8 ? "add" : "mul"); else { _nmd_append_string(&si, instruction->modrm.modrm < 0xf0 ? "sub" : "div"); if (_NMD_R(instruction->modrm.modrm) < 8 || (_NMD_R(instruction->modrm.modrm) >= 0xe && _NMD_C(instruction->modrm.modrm) < 8)) *si.buffer++ = 'r'; } _nmd_append_string(&si, "p st("); *si.buffer++ = (char)('0' + instruction->modrm.modrm % 8); _nmd_append_string(&si, "),st(0)"); } } break; case 0xdf: if (instruction->modrm.modrm == 0xe0) _nmd_append_string(&si, "nstsw ax"); else { if (instruction->modrm.modrm >= 0xe8) { if (instruction->modrm.modrm < 0xf0) *si.buffer++ = 'u'; _nmd_append_string(&si, "comip"); _nmd_append_string(&si, " st(0),st("); *si.buffer++ = (char)('0' + instruction->modrm.modrm % 8); *si.buffer++ = ')'; } else { _nmd_append_string(&si, instruction->modrm.modrm < 0xc8 ? "freep" : (instruction->modrm.modrm >= 0xd0 ? "stp" : "xch")); _nmd_append_string(&si, " st("); *si.buffer++ = (char)('0' + instruction->modrm.modrm % 8); *si.buffer++ = ')'; } } break; } } } else if (op == 0xe4 || op == 0xe5) { _nmd_append_string(&si, "in "); _nmd_append_string(&si, op == 0xe4 ? "al" : (opszprfx ? "ax" : "eax")); *si.buffer++ = ','; _nmd_append_number(&si, instruction->immediate); } else if (op == 0xe6 || op == 0xe7) { _nmd_append_string(&si, "out "); _nmd_append_number(&si, instruction->immediate); *si.buffer++ = ','; _nmd_append_string(&si, op == 0xe6 ? "al" : (opszprfx ? "ax" : "eax")); } else if (op == 0xec || op == 0xed) { _nmd_append_string(&si, "in "); _nmd_append_string(&si, op == 0xec ? "al" : (opszprfx ? "ax" : "eax")); _nmd_append_string(&si, ",dx"); } else if (op == 0xee || op == 0xef) { _nmd_append_string(&si, "out dx,"); _nmd_append_string(&si, op == 0xee ? "al" : (opszprfx ? "ax" : "eax")); } else if (op == 0x62) { _nmd_append_string(&si, "bound "); _nmd_append_Gv(&si); *si.buffer++ = ','; _nmd_append_modrm_upper(&si, opszprfx ? "dword" : "qword"); } else /* Try to parse all opcodes not parsed by the checks above. */ { const char* str = 0; switch (instruction->opcode) { case 0x9c: { if (opszprfx) str = (instruction->mode == NMD_X86_MODE_16) ? "pushfd" : "pushf"; else str = (instruction->mode == NMD_X86_MODE_16) ? "pushf" : ((instruction->mode == NMD_X86_MODE_32) ? "pushfd" : "pushfq"); break; } case 0x9d: { if (opszprfx) str = (instruction->mode == NMD_X86_MODE_16) ? "popfd" : "popf"; else str = (instruction->mode == NMD_X86_MODE_16) ? "popf" : ((instruction->mode == NMD_X86_MODE_32) ? "popfd" : "popfq"); break; } case 0x60: str = _NMD_GET_BY_MODE_OPSZPRFX(instruction->mode, opszprfx, "pusha", "pushad"); break; case 0x61: str = _NMD_GET_BY_MODE_OPSZPRFX(instruction->mode, opszprfx, "popa", "popad"); break; case 0xcb: str = "retf"; break; case 0xc9: str = "leave"; break; case 0xf1: str = "int1"; break; case 0x06: str = "push es"; break; case 0x16: str = "push ss"; break; case 0x1e: str = "push ds"; break; case 0x0e: str = "push cs"; break; case 0x07: str = "pop es"; break; case 0x17: str = "pop ss"; break; case 0x1f: str = "pop ds"; break; case 0x27: str = "daa"; break; case 0x37: str = "aaa"; break; case 0x2f: str = "das"; break; case 0x3f: str = "aas"; break; case 0xd7: str = "xlat"; break; case 0x9b: str = "fwait"; break; case 0xf4: str = "hlt"; break; case 0xf5: str = "cmc"; break; case 0x9e: str = "sahf"; break; case 0x9f: str = "lahf"; break; case 0xce: str = "into"; break; case 0xcf: if (instruction->rex_w_prefix) str = "iretq"; else if (instruction->mode == NMD_X86_MODE_16) str = opszprfx ? "iretd" : "iret"; else str = opszprfx ? "iret" : "iretd"; break; case 0x98: if (instruction->prefixes & NMD_X86_PREFIXES_REX_W) str = "cdqe"; else if (instruction->mode == NMD_X86_MODE_16) str = opszprfx ? "cwde" : "cbw"; else str = opszprfx ? "cbw" : "cwde"; break; case 0x99: if (instruction->prefixes & NMD_X86_PREFIXES_REX_W) str = "cqo"; else if (instruction->mode == NMD_X86_MODE_16) str = opszprfx ? "cdq" : "cwd"; else str = opszprfx ? "cwd" : "cdq"; break; case 0xd6: str = "salc"; break; case 0xf8: str = "clc"; break; case 0xf9: str = "stc"; break; case 0xfa: str = "cli"; break; case 0xfb: str = "sti"; break; case 0xfc: str = "cld"; break; case 0xfd: str = "std"; break; default: return; } _nmd_append_string(&si, str); } } } else if (instruction->opcode_map == NMD_X86_OPCODE_MAP_0F) { if (_NMD_R(op) == 8) { *si.buffer++ = 'j'; _nmd_append_string(&si, _nmd_condition_suffixes[_NMD_C(op)]); *si.buffer++ = ' '; _nmd_append_relative_address16_32(&si); } else if(op == 0x05) _nmd_append_string(&si, "syscall"); else if(op == 0xa2) _nmd_append_string(&si, "cpuid"); else if (_NMD_R(op) == 4) { _nmd_append_string(&si, "cmov"); _nmd_append_string(&si, _nmd_condition_suffixes[_NMD_C(op)]); *si.buffer++ = ' '; _nmd_append_Gv(&si); *si.buffer++ = ','; _nmd_append_Ev(&si); } else if (op >= 0x10 && op <= 0x17) { if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) { const char* prefix66_mnemonics[] = { "movupd", "movupd", "movlpd", "movlpd", "unpcklpd", "unpckhpd", "movhpd", "movhpd" }; _nmd_append_string(&si, prefix66_mnemonics[_NMD_C(op)]); *si.buffer++ = ' '; switch (_NMD_C(op)) { case 0: _nmd_append_Vx(&si); *si.buffer++ = ','; _nmd_append_W(&si); break; case 1: _nmd_append_W(&si); *si.buffer++ = ','; _nmd_append_Vx(&si); break; case 2: case 6: _nmd_append_Vdq(&si); *si.buffer++ = ','; if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, "xmm"), * si.buffer++ = (char)('0' + si.instruction->modrm.fields.rm); else _nmd_append_modrm_upper(&si, "qword"); break; default: break; } } else if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT) { const char* prefixF3_mnemonics[] = { "movss", "movss", "movsldup", 0, 0, 0, "movshdup" }; _nmd_append_string(&si, prefixF3_mnemonics[_NMD_C(op)]); *si.buffer++ = ' '; switch (_NMD_C(op)) { case 0: _nmd_append_Vdq(&si); *si.buffer++ = ','; if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, "xmm"), * si.buffer++ = (char)('0' + si.instruction->modrm.fields.rm); else _nmd_append_modrm_upper(&si, "dword"); break; case 1: if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, "xmm"), * si.buffer++ = (char)('0' + si.instruction->modrm.fields.rm); else _nmd_append_modrm_upper(&si, "dword"); *si.buffer++ = ','; _nmd_append_Vdq(&si); break; case 2: case 6: _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_W(&si); break; } } else if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) { const char* prefixF2_mnemonics[] = { "movsd", "movsd", "movddup" }; _nmd_append_string(&si, prefixF2_mnemonics[_NMD_C(op)]); *si.buffer++ = ' '; switch (_NMD_C(op)) { case 0: case 2: _nmd_append_Vdq(&si); *si.buffer++ = ','; if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, "xmm"), * si.buffer++ = (char)('0' + si.instruction->modrm.fields.rm); else _nmd_append_modrm_upper(&si, "qword"); break; case 1: if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, "xmm"), * si.buffer++ = (char)('0' + si.instruction->modrm.fields.rm); else _nmd_append_modrm_upper(&si, "qword"); *si.buffer++ = ','; _nmd_append_Vdq(&si); break; } } else { const char* no_prefix_mnemonics[] = { "movups", "movups", "movlps", "movlps", "unpcklps", "unpckhps", "movhps", "movhps" }; if (op == 0x12 && instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, "movhlps"); else if (op == 0x16 && instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, "movlhps"); else _nmd_append_string(&si, no_prefix_mnemonics[_NMD_C(op)]); *si.buffer++ = ' '; switch (_NMD_C(op)) { case 0: _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_W(&si); break; case 1: _nmd_append_W(&si); *si.buffer++ = ','; _nmd_append_Vdq(&si); break; case 2: case 6: _nmd_append_Vdq(&si); *si.buffer++ = ','; if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, "xmm"), * si.buffer++ = (char)('0' + si.instruction->modrm.fields.rm); else _nmd_append_modrm_upper(&si, "qword"); break; default: break; }; } switch (_NMD_C(op)) { case 3: case 7: if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, "xmm"), * si.buffer++ = (char)('0' + si.instruction->modrm.fields.rm); else _nmd_append_modrm_upper(&si, "qword"); *si.buffer++ = ','; _nmd_append_Vdq(&si); break; case 4: case 5: _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_W(&si); break; }; } else if (_NMD_R(op) == 6 || (op >= 0x74 && op <= 0x76)) { if (op == 0x6e) { _nmd_append_string(&si, "movd "); if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) *si.buffer++ = 'x'; _nmd_append_Pq(&si); *si.buffer++ = ','; if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, _nmd_reg32[si.instruction->modrm.fields.rm]); else _nmd_append_modrm_upper(&si, "dword"); } else { if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) { const char* prefix66_mnemonics[] = { "punpcklbw", "punpcklwd", "punpckldq", "packsswb", "pcmpgtb", "pcmpgtw", "pcmpgtd", "packuswb", "punpckhbw", "punpckhwd", "punpckhdq", "packssdw", "punpcklqdq", "punpckhqdq", "movd", "movdqa" }; _nmd_append_string(&si, op == 0x74 ? "pcmpeqb" : (op == 0x75 ? "pcmpeqw" : (op == 0x76 ? "pcmpeqd" : prefix66_mnemonics[op % 0x10]))); *si.buffer++ = ' '; _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_W(&si); } else if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT) { _nmd_append_string(&si, "movdqu "); _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_W(&si); } else { const char* no_prefix_mnemonics[] = { "punpcklbw", "punpcklwd", "punpckldq", "packsswb", "pcmpgtb", "pcmpgtw", "pcmpgtd", "packuswb", "punpckhbw", "punpckhwd", "punpckhdq", "packssdw", 0, 0, "movd", "movq" }; _nmd_append_string(&si, op == 0x74 ? "pcmpeqb" : (op == 0x75 ? "pcmpeqw" : (op == 0x76 ? "pcmpeqd" : no_prefix_mnemonics[op % 0x10]))); *si.buffer++ = ' '; _nmd_append_Pq(&si); *si.buffer++ = ','; _nmd_append_Qq(&si); } } } else if (op == 0x00) { _nmd_append_string(&si, _nmd_opcode_extensions_grp6[instruction->modrm.fields.reg]); *si.buffer++ = ' '; if (_NMD_R(instruction->modrm.modrm) == 0xc) _nmd_append_Ev(&si); else _nmd_append_Ew(&si); } else if (op == 0x01) { if (instruction->modrm.fields.mod == 0b11) { if (instruction->modrm.fields.reg == 0b000) _nmd_append_string(&si, _nmd_opcode_extensions_grp7_reg0[instruction->modrm.fields.rm]); else if (instruction->modrm.fields.reg == 0b001) _nmd_append_string(&si, _nmd_opcode_extensions_grp7_reg1[instruction->modrm.fields.rm]); else if (instruction->modrm.fields.reg == 0b010) _nmd_append_string(&si, _nmd_opcode_extensions_grp7_reg2[instruction->modrm.fields.rm]); else if (instruction->modrm.fields.reg == 0b011) { _nmd_append_string(&si, _nmd_opcode_extensions_grp7_reg3[instruction->modrm.fields.rm]); if (instruction->modrm.fields.rm == 0b000 || instruction->modrm.fields.rm == 0b010 || instruction->modrm.fields.rm == 0b111) _nmd_append_string(&si, instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? "ax" : "eax"); if (instruction->modrm.fields.rm == 0b111) _nmd_append_string(&si, ",ecx"); } else if (instruction->modrm.fields.reg == 0b100) _nmd_append_string(&si, "smsw "), _nmd_append_string(&si, (instruction->rex_w_prefix ? _nmd_reg64 : (instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? _nmd_reg16 : _nmd_reg32))[instruction->modrm.fields.rm]); else if (instruction->modrm.fields.reg == 0b101) { if (instruction->prefixes & NMD_X86_PREFIXES_REPEAT) _nmd_append_string(&si, instruction->modrm.fields.rm == 0b000 ? "setssbsy" : "saveprevssp"); else _nmd_append_string(&si, instruction->modrm.fields.rm == 0b111 ? "wrpkru" : "rdpkru"); } else if (instruction->modrm.fields.reg == 0b110) _nmd_append_string(&si, "lmsw "), _nmd_append_string(&si, _nmd_reg16[instruction->modrm.fields.rm]); else if (instruction->modrm.fields.reg == 0b111) { _nmd_append_string(&si, _nmd_opcode_extensions_grp7_reg7[instruction->modrm.fields.rm]); if (instruction->modrm.fields.rm == 0b100) _nmd_append_string(&si, instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? "ax" : "eax"); } } else { if (instruction->modrm.fields.reg == 0b101) { _nmd_append_string(&si, "rstorssp "); _nmd_append_modrm_upper(&si, "qword"); } else { _nmd_append_string(&si, _nmd_opcode_extensions_grp7[instruction->modrm.fields.reg]); *si.buffer++ = ' '; if (si.instruction->modrm.fields.reg == 0b110) _nmd_append_Ew(&si); else _nmd_append_modrm_upper(&si, si.instruction->modrm.fields.reg == 0b111 ? "byte" : si.instruction->modrm.fields.reg == 0b100 ? "word" : "fword"); } } } else if (op == 0x02 || op == 0x03) { _nmd_append_string(&si, op == 0x02 ? "lar" : "lsl"); *si.buffer++ = ' '; _nmd_append_Gv(&si); *si.buffer++ = ','; if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, (opszprfx ? _nmd_reg16 : _nmd_reg32)[si.instruction->modrm.fields.rm]); else _nmd_append_modrm_upper(&si, "word"); } else if (op == 0x0d) { if (instruction->modrm.fields.mod == 0b11) { _nmd_append_string(&si, "nop "); _nmd_append_string(&si, (instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? _nmd_reg16 : _nmd_reg32)[instruction->modrm.fields.rm]); *si.buffer++ = ','; _nmd_append_string(&si, (instruction->prefixes & NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? _nmd_reg16 : _nmd_reg32)[instruction->modrm.fields.reg]); } else { _nmd_append_string(&si, "prefetch"); if (instruction->modrm.fields.reg == 0b001) *si.buffer++ = 'w'; else if (instruction->modrm.fields.reg == 0b010) _nmd_append_string(&si, "wt1"); *si.buffer++ = ' '; _nmd_append_modrm_upper(&si, "byte"); } } else if (op == 0x18) { if (instruction->modrm.fields.mod == 0b11 || instruction->modrm.fields.reg >= 0b100) { _nmd_append_string(&si, "nop "); _nmd_append_Ev(&si); } else { if (instruction->modrm.fields.reg == 0b000) _nmd_append_string(&si, "prefetchnta"); else { _nmd_append_string(&si, "prefetcht"); *si.buffer++ = (char)('0' + (instruction->modrm.fields.reg - 1)); } *si.buffer++ = ' '; _nmd_append_Eb(&si); } } else if (op == 0x19) { _nmd_append_string(&si, "nop "); _nmd_append_Ev(&si); *si.buffer++ = ','; _nmd_append_Gv(&si); } else if (op == 0x1A) { if (instruction->modrm.fields.mod == 0b11) { _nmd_append_string(&si, "nop "); _nmd_append_Ev(&si); *si.buffer++ = ','; _nmd_append_Gv(&si); } else { if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) _nmd_append_string(&si, "bndmov"); else if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT) _nmd_append_string(&si, "bndcl"); else if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) _nmd_append_string(&si, "bndcu"); else _nmd_append_string(&si, "bndldx"); _nmd_append_string(&si, " bnd"); *si.buffer++ = (char)('0' + instruction->modrm.fields.reg); *si.buffer++ = ','; if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) *si.buffer++ = 'q'; _nmd_append_Ev(&si); } } else if (op == 0x1B) { if (instruction->modrm.fields.mod == 0b11) { _nmd_append_string(&si, "nop "); _nmd_append_Ev(&si); *si.buffer++ = ','; _nmd_append_Gv(&si); } else { if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) _nmd_append_string(&si, "bndmov"); else if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT) _nmd_append_string(&si, "bndmk"); else if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) _nmd_append_string(&si, "bndcn"); else _nmd_append_string(&si, "bndstx"); *si.buffer++ = ' '; _nmd_append_Ev(&si); *si.buffer++ = ','; _nmd_append_string(&si, "bnd"); *si.buffer++ = (char)('0' + instruction->modrm.fields.reg); } } else if (op >= 0x1c && op <= 0x1f) { if (op == 0x1e && instruction->modrm.modrm == 0xfa) _nmd_append_string(&si, "endbr64"); else if (op == 0x1e && instruction->modrm.modrm == 0xfb) _nmd_append_string(&si, "endbr32"); else { _nmd_append_string(&si, "nop "); _nmd_append_Ev(&si); *si.buffer++ = ','; _nmd_append_Gv(&si); } } else if (op >= 0x20 && op <= 0x23) { _nmd_append_string(&si, "mov "); if (op < 0x22) { _nmd_append_string(&si, (instruction->mode == NMD_X86_MODE_64 ? _nmd_reg64 : _nmd_reg32)[instruction->modrm.fields.rm]); _nmd_append_string(&si, op == 0x20 ? ",cr" : ",dr"); *si.buffer++ = (char)('0' + instruction->modrm.fields.reg); } else { _nmd_append_string(&si, op == 0x22 ? "cr" : "dr"); *si.buffer++ = (char)('0' + instruction->modrm.fields.reg); *si.buffer++ = ','; _nmd_append_string(&si, (instruction->mode == NMD_X86_MODE_64 ? _nmd_reg64 : _nmd_reg32)[instruction->modrm.fields.rm]); } } else if (op >= 0x28 && op <= 0x2f) { if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) { const char* prefix66_mnemonics[] = { "movapd", "movapd", "cvtpi2pd", "movntpd", "cvttpd2pi", "cvtpd2pi", "ucomisd", "comisd" }; _nmd_append_string(&si, prefix66_mnemonics[op % 8]); *si.buffer++ = ' '; switch (op % 8) { case 0: _nmd_append_Vx(&si); *si.buffer++ = ','; _nmd_append_W(&si); break; case 1: _nmd_append_W(&si); *si.buffer++ = ','; _nmd_append_Vx(&si); break; case 2: _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_Qq(&si); break; case 4: case 5: _nmd_append_Pq(&si); *si.buffer++ = ','; _nmd_append_W(&si); break; case 6: _nmd_append_Vdq(&si); *si.buffer++ = ','; if (instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, "xmm"), * si.buffer++ = (char)('0' + instruction->modrm.fields.rm); else _nmd_append_modrm_upper(&si, "qword"); break; case 7: _nmd_append_Vdq(&si); *si.buffer++ = ','; if (instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, "xmm"), * si.buffer++ = (char)('0' + instruction->modrm.fields.rm); else _nmd_append_modrm_upper(&si, "qword"); default: break; } } else if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT) { const char* prefixF3_mnemonics[] = { 0, 0, "cvtsi2ss", "movntss", "cvttss2si", "cvtss2si", 0, 0 }; _nmd_append_string(&si, prefixF3_mnemonics[op % 8]); *si.buffer++ = ' '; switch (op % 8) { case 3: _nmd_append_modrm_upper(&si, "dword"); *si.buffer++ = ','; _nmd_append_Vdq(&si); break; case 4: case 5: _nmd_append_Gv(&si); *si.buffer++ = ','; if (instruction->modrm.fields.mod == 0b11) _nmd_append_Udq(&si); else _nmd_append_modrm_upper(&si, "dword"); break; case 2: case 6: _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_Ev(&si); break; } } else if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) { const char* prefixF2_mnemonics[] = { 0, 0, "cvtsi2sd", "movntsd", "cvttsd2si", "cvtsd2si", 0, 0 }; _nmd_append_string(&si, prefixF2_mnemonics[op % 8]); *si.buffer++ = ' '; switch (op % 8) { case 2: _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_Ev(&si); break; case 3: _nmd_append_modrm_upper(&si, "qword"); *si.buffer++ = ','; _nmd_append_Vdq(&si); break; case 4: case 5: _nmd_append_Gv(&si); *si.buffer++ = ','; if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, "xmm"), * si.buffer++ = (char)('0' + si.instruction->modrm.fields.rm); else _nmd_append_modrm_upper(&si, "qword"); break; } } else { const char* no_prefix_mnemonics[] = { "movaps", "movaps", "cvtpi2ps", "movntps", "cvttps2pi", "cvtps2pi", "ucomiss", "comiss" }; _nmd_append_string(&si, no_prefix_mnemonics[op % 8]); *si.buffer++ = ' '; switch (op % 8) { case 0: _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_W(&si); break; case 1: _nmd_append_W(&si); *si.buffer++ = ','; _nmd_append_Vdq(&si); break; case 4: case 5: _nmd_append_Pq(&si); *si.buffer++ = ','; if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, "xmm"), * si.buffer++ = (char)('0' + si.instruction->modrm.fields.rm); else _nmd_append_modrm_upper(&si, "qword"); break; case 2: _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_Qq(&si); break; case 6: case 7: _nmd_append_Vdq(&si); *si.buffer++ = ','; if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, "xmm"), * si.buffer++ = (char)('0' + si.instruction->modrm.fields.rm); else _nmd_append_modrm_upper(&si, "dword"); break; default: break; }; } if (!(instruction->prefixes & (NMD_X86_PREFIXES_REPEAT | NMD_X86_PREFIXES_REPEAT_NOT_ZERO)) && (op % 8) == 3) { _nmd_append_modrm_upper(&si, "xmmword"); *si.buffer++ = ','; _nmd_append_Vdq(&si); } } else if (_NMD_R(op) == 5) { if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) { const char* prefix66_mnemonics[] = { "movmskpd", "sqrtpd", 0, 0, "andpd", "andnpd", "orpd", "xorpd", "addpd", "mulpd", "cvtpd2ps", "cvtps2dq", "subpd", "minpd", "divpd", "maxpd" }; _nmd_append_string(&si, prefix66_mnemonics[op % 0x10]); *si.buffer++ = ' '; if (op == 0x50) _nmd_append_string(&si, _nmd_reg32[instruction->modrm.fields.reg]); else _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_W(&si); } else if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT) { const char* prefixF3_mnemonics[] = { 0, "sqrtss", "rsqrtss", "rcpss", 0, 0, 0, 0, "addss", "mulss", "cvtss2sd", "cvttps2dq", "subss", "minss", "divss", "maxss" }; _nmd_append_string(&si, prefixF3_mnemonics[op % 0x10]); *si.buffer++ = ' '; _nmd_append_Vdq(&si); *si.buffer++ = ','; if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, "xmm"), * si.buffer++ = (char)('0' + si.instruction->modrm.fields.rm); else _nmd_append_modrm_upper(&si, op == 0x5b ? "xmmword" : "dword"); } else if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) { const char* prefixF2_mnemonics[] = { 0, "sqrtsd", 0, 0, 0, 0, 0, 0, "addsd", "mulsd", "cvtsd2ss", 0, "subsd", "minsd", "divsd", "maxsd" }; _nmd_append_string(&si, prefixF2_mnemonics[op % 0x10]); *si.buffer++ = ' '; _nmd_append_Vdq(&si); *si.buffer++ = ','; if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, "xmm"), * si.buffer++ = (char)('0' + si.instruction->modrm.fields.rm); else _nmd_append_modrm_upper(&si, "qword"); } else { const char* no_prefix_mnemonics[] = { "movmskps", "sqrtps", "rsqrtps", "rcpps", "andps", "andnps", "orps", "xorps", "addps", "mulps", "cvtps2pd", "cvtdq2ps", "subps", "minps", "divps", "maxps" }; _nmd_append_string(&si, no_prefix_mnemonics[op % 0x10]); *si.buffer++ = ' '; if (op == 0x50) { _nmd_append_string(&si, _nmd_reg32[instruction->modrm.fields.reg]); *si.buffer++ = ','; _nmd_append_Udq(&si); } else { _nmd_append_Vdq(&si); *si.buffer++ = ','; if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, "xmm"), * si.buffer++ = (char)('0' + si.instruction->modrm.fields.rm); else _nmd_append_modrm_upper(&si, op == 0x5a ? "qword" : "xmmword"); } } } else if (op == 0x70) { _nmd_append_string(&si, instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? "pshufd" : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? "pshufhw" : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO ? "pshuflw" : "pshufw"))); *si.buffer++ = ' '; if (!(instruction->prefixes & (NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE | NMD_X86_PREFIXES_REPEAT | NMD_X86_PREFIXES_REPEAT_NOT_ZERO))) { _nmd_append_Pq(&si); *si.buffer++ = ','; _nmd_append_Qq(&si); } else { _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_W(&si); } *si.buffer++ = ','; _nmd_append_number(&si, instruction->immediate); } else if (op >= 0x71 && op <= 0x73) { if (instruction->modrm.fields.reg % 2 == 1) _nmd_append_string(&si, instruction->modrm.fields.reg == 0b111 ? "pslldq" : "psrldq"); else { const char* mnemonics[] = { "psrl", "psra", "psll" }; _nmd_append_string(&si, mnemonics[(instruction->modrm.fields.reg >> 1) - 1]); *si.buffer++ = op == 0x71 ? 'w' : (op == 0x72 ? 'd' : 'q'); } *si.buffer++ = ' '; if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) _nmd_append_Udq(&si); else _nmd_append_Nq(&si); *si.buffer++ = ','; _nmd_append_number(&si, instruction->immediate); } else if (op == 0x78) { if (!instruction->simd_prefix) { _nmd_append_string(&si, "vmread "); _nmd_append_Ey(&si); *si.buffer++ = ','; _nmd_append_Gy(&si); } else { if(instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) _nmd_append_string(&si, "extrq "); else { _nmd_append_string(&si, "insertq "); _nmd_append_Vdq(&si); *si.buffer++ = ','; } _nmd_append_Udq(&si); *si.buffer++ = ','; _nmd_append_number(&si, instruction->immediate & 0x00FF); *si.buffer++ = ','; _nmd_append_number(&si, (instruction->immediate & 0xFF00) >> 8); } } else if (op == 0x79) { if (!instruction->simd_prefix) { _nmd_append_string(&si, "vmwrite "); _nmd_append_Gy(&si); *si.buffer++ = ','; _nmd_append_Ey(&si); } else { _nmd_append_string(&si, instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? "extrq " : "insertq "); _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_Udq(&si); } } else if (op == 0x7c || op == 0x7d) { _nmd_append_string(&si, op == 0x7c ? "haddp" : "hsubp"); *si.buffer++ = instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? 'd' : 's'; *si.buffer++ = ' '; _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_W(&si); } else if (op == 0x7e) { _nmd_append_string(&si, instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? "movq " : "movd "); if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT) { _nmd_append_Vdq(&si); *si.buffer++ = ','; if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_Udq(&si); else _nmd_append_modrm_upper(&si, "qword"); } else { if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, _nmd_reg32[instruction->modrm.fields.rm]); else _nmd_append_modrm_upper(&si, "dword"); *si.buffer++ = ','; if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) _nmd_append_Vdq(&si); else _nmd_append_Pq(&si); } } else if (op == 0x7f) { _nmd_append_string(&si, instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? "movdqu" : (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? "movdqa" : "movq")); *si.buffer++ = ' '; if (instruction->prefixes & (NMD_X86_PREFIXES_REPEAT | NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE)) { _nmd_append_W(&si); *si.buffer++ = ','; _nmd_append_Vdq(&si); } else { if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_Nq(&si); else _nmd_append_modrm_upper(&si, "qword"); *si.buffer++ = ','; _nmd_append_Pq(&si); } } else if (_NMD_R(op) == 9) { _nmd_append_string(&si, "set"); _nmd_append_string(&si, _nmd_condition_suffixes[_NMD_C(op)]); *si.buffer++ = ' '; _nmd_append_Eb(&si); } else if ((_NMD_R(op) == 0xA || _NMD_R(op) == 0xB) && op % 8 == 3) { _nmd_append_string(&si, op == 0xa3 ? "bt" : (op == 0xb3 ? "btr" : (op == 0xab ? "bts" : "btc"))); *si.buffer++ = ' '; _nmd_append_Ev(&si); *si.buffer++ = ','; _nmd_append_Gv(&si); } else if (_NMD_R(op) == 0xA && (op % 8 == 4 || op % 8 == 5)) { _nmd_append_string(&si, op > 0xA8 ? "shrd" : "shld"); *si.buffer++ = ' '; _nmd_append_Ev(&si); *si.buffer++ = ','; _nmd_append_Gv(&si); *si.buffer++ = ','; if (op % 8 == 4) _nmd_append_number(&si, instruction->immediate); else _nmd_append_string(&si, "cl"); } else if (op == 0xb4 || op == 0xb5) { _nmd_append_string(&si, op == 0xb4 ? "lfs " : "lgs "); _nmd_append_Gv(&si); *si.buffer++ = ','; _nmd_append_modrm_upper(&si, "fword"); } else if (op == 0xbc || op == 0xbd) { _nmd_append_string(&si, instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? (op == 0xbc ? "tzcnt" : "lzcnt") : (op == 0xbc ? "bsf" : "bsr")); *si.buffer++ = ' '; _nmd_append_Gv(&si); *si.buffer++ = ','; _nmd_append_Ev(&si); } else if (op == 0xa6) { const char* mnemonics[] = { "montmul", "xsha1", "xsha256" }; _nmd_append_string(&si, mnemonics[instruction->modrm.fields.reg]); } else if (op == 0xa7) { const char* mnemonics[] = { "xstorerng", "xcryptecb", "xcryptcbc", "xcryptctr", "xcryptcfb", "xcryptofb" }; _nmd_append_string(&si, mnemonics[instruction->modrm.fields.reg]); } else if (op == 0xae) { if (instruction->modrm.fields.mod == 0b11) { if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) _nmd_append_string(&si, "pcommit"); else if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT) { _nmd_append_string(&si, "incsspd "); _nmd_append_string(&si, _nmd_reg32[instruction->modrm.fields.rm]); } else { const char* mnemonics[] = { "rdfsbase", "rdgsbase", "wrfsbase", "wrgsbase", 0, "lfence", "mfence", "sfence" }; _nmd_append_string(&si, mnemonics[instruction->modrm.fields.reg]); } } else { if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) { _nmd_append_string(&si, instruction->modrm.fields.reg == 0b110 ? "clwb " : "clflushopt "); _nmd_append_modrm_upper(&si, "byte"); } else if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT) { _nmd_append_string(&si, instruction->modrm.fields.reg == 0b100 ? "ptwrite " : "clrssbsy "); _nmd_append_modrm_upper(&si, instruction->modrm.fields.reg == 0b100 ? "dword" : "qword"); } else { const char* mnemonics[] = { "fxsave", "fxrstor", "ldmxcsr", "stmxcsr", "xsave", "xrstor", "xsaveopt", "clflush" }; _nmd_append_string(&si, mnemonics[instruction->modrm.fields.reg]); *si.buffer++ = ' '; _nmd_append_modrm_upper(&si, "dword"); } } } else if (op == 0xaf) { _nmd_append_string(&si, "imul "); _nmd_append_Gv(&si); *si.buffer++ = ','; _nmd_append_Ev(&si); } else if (op == 0xb0 || op == 0xb1) { _nmd_append_string(&si, "cmpxchg "); if (op == 0xb0) { _nmd_append_Eb(&si); *si.buffer++ = ','; _nmd_append_Gb(&si); } else { _nmd_append_Ev(&si); *si.buffer++ = ','; _nmd_append_Gv(&si); } } else if (op == 0xb2) { _nmd_append_string(&si, "lss "); _nmd_append_Gv(&si); *si.buffer++ = ','; _nmd_append_modrm_upper(&si, "fword"); } else if (_NMD_R(op) == 0xb && (op % 8) >= 6) { _nmd_append_string(&si, op > 0xb8 ? "movsx " : "movzx "); _nmd_append_Gv(&si); *si.buffer++ = ','; if ((op % 8) == 6) _nmd_append_Eb(&si); else _nmd_append_Ew(&si); } else if (op == 0xb8) { _nmd_append_string(&si, "popcnt "); _nmd_append_Gv(&si); *si.buffer++ = ','; _nmd_append_Ev(&si); } else if (op == 0xba) { const char* mnemonics[] = { "bt","bts","btr","btc" }; _nmd_append_string(&si, mnemonics[instruction->modrm.fields.reg - 4]); *si.buffer++ = ' '; _nmd_append_Ev(&si); *si.buffer++ = ','; _nmd_append_number(&si, instruction->immediate); } else if (op == 0xc0 || op == 0xc1) { _nmd_append_string(&si, "xadd "); if (op == 0xc0) { _nmd_append_Eb(&si); *si.buffer++ = ','; _nmd_append_Gb(&si); } else { _nmd_append_Ev(&si); *si.buffer++ = ','; _nmd_append_Gv(&si); } } else if (op == 0xc2) { _nmd_append_string(&si, instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? "cmppd" : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? "cmpss" : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO ? "cmpsd" : "cmpps"))); *si.buffer++ = ' '; _nmd_append_Vdq(&si); *si.buffer++ = ','; if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_Udq(&si); else _nmd_append_modrm_upper(&si, instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? "dword" : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO ? "qword" : "xmmword")); *si.buffer++ = ','; _nmd_append_number(&si, instruction->immediate); } else if (op == 0xc3) { _nmd_append_string(&si, "movnti "); _nmd_append_modrm_upper(&si, "dword"); *si.buffer++ = ','; _nmd_append_string(&si, _nmd_reg32[instruction->modrm.fields.reg]); } else if (op == 0xc4) { _nmd_append_string(&si, "pinsrw "); if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) _nmd_append_Vdq(&si); else _nmd_append_Pq(&si); *si.buffer++ = ','; if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, _nmd_reg32[si.instruction->modrm.fields.rm]); else _nmd_append_modrm_upper(&si, "word"); *si.buffer++ = ','; _nmd_append_number(&si, instruction->immediate); } else if (op == 0xc5) { _nmd_append_string(&si, "pextrw "); _nmd_append_string(&si, _nmd_reg32[si.instruction->modrm.fields.reg]); *si.buffer++ = ','; if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) _nmd_append_Udq(&si); else _nmd_append_Nq(&si); *si.buffer++ = ','; _nmd_append_number(&si, instruction->immediate); } else if (op == 0xc6) { _nmd_append_string(&si, "shufp"); *si.buffer++ = instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? 'd' : 's'; *si.buffer++ = ' '; _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_W(&si); *si.buffer++ = ','; _nmd_append_number(&si, instruction->immediate); } else if (op == 0xC7) { if (instruction->modrm.fields.reg == 0b001) { _nmd_append_string(&si, "cmpxchg8b "); _nmd_append_modrm_upper(&si, "qword"); } else if (instruction->modrm.fields.reg <= 0b101) { const char* mnemonics[] = { "xrstors", "xsavec", "xsaves" }; _nmd_append_string(&si, mnemonics[instruction->modrm.fields.reg - 3]); *si.buffer++ = ' '; _nmd_append_Eb(&si); } else if (instruction->modrm.fields.reg == 0b110) { if (instruction->modrm.fields.mod == 0b11) { _nmd_append_string(&si, "rdrand "); _nmd_append_Rv(&si); } else { _nmd_append_string(&si, instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? "vmclear" : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? "vmxon" : "vmptrld")); *si.buffer++ = ' '; _nmd_append_modrm_upper(&si, "qword"); } } else /* reg == 0b111 */ { if (instruction->modrm.fields.mod == 0b11) { _nmd_append_string(&si, "rdseed "); _nmd_append_Rv(&si); } else { _nmd_append_string(&si, "vmptrst "); _nmd_append_modrm_upper(&si, "qword"); } } } else if (op >= 0xc8 && op <= 0xcf) { _nmd_append_string(&si, "bswap "); _nmd_append_string(&si, (opszprfx ? _nmd_reg16 : _nmd_reg32)[op % 8]); } else if (op == 0xd0) { _nmd_append_string(&si, "addsubp"); *si.buffer++ = instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? 'd' : 's'; *si.buffer++ = ' '; _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_W(&si); } else if (op == 0xd6) { _nmd_append_string(&si, instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? "movq" : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? "movq2dq" : "movdq2q")); *si.buffer++ = ' '; if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT) { _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_Nq(&si); } else if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) { _nmd_append_Pq(&si); *si.buffer++ = ','; _nmd_append_Udq(&si); } else { if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_Udq(&si); else _nmd_append_modrm_upper(&si, "qword"); *si.buffer++ = ','; _nmd_append_Vdq(&si); } } else if (op == 0xd7) { _nmd_append_string(&si, "pmovmskb "); _nmd_append_string(&si, _nmd_reg32[instruction->modrm.fields.reg]); *si.buffer++ = ','; if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) _nmd_append_Udq(&si); else _nmd_append_Nq(&si); } else if (op == 0xe6) { _nmd_append_string(&si, instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? "cvttpd2dq" : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? "cvtdq2pd" : "cvtpd2dq")); *si.buffer++ = ' '; _nmd_append_Vdq(&si); *si.buffer++ = ','; if (si.instruction->modrm.fields.mod == 0b11) _nmd_append_Udq(&si); else _nmd_append_modrm_upper(&si, instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? "qword" : "xmmword"); } else if (op == 0xe7) { _nmd_append_string(&si, instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? "movntdq" : "movntq"); *si.buffer++ = ' '; _nmd_append_modrm_upper(&si, instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? "xmmword" : "qword"); *si.buffer++ = ','; if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) _nmd_append_Vdq(&si); else _nmd_append_Pq(&si); } else if (op == 0xf0) { _nmd_append_string(&si, "lddqu "); _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_modrm_upper(&si, "xmmword"); } else if (op == 0xf7) { _nmd_append_string(&si, instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? "maskmovdqu " : "maskmovq "); if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) { _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_Udq(&si); } else { _nmd_append_Pq(&si); *si.buffer++ = ','; _nmd_append_Nq(&si); } } else if (op >= 0xd1 && op <= 0xfe) { const char* mnemonics[] = { "srlw", "srld", "srlq", "addq", "mullw", 0, 0, "subusb", "subusw", "minub", "and", "addusb", "addusw", "maxub", "andn", "avgb", "sraw", "srad", "avgw", "mulhuw", "mulhw", 0, 0, "subsb", "subsw", "minsw", "or", "addsb", "addsw", "maxsw", "xor", 0, "sllw", "slld", "sllq", "muludq", "maddwd", "sadbw", 0, "subb", "subw", "subd", "subq", "addb", "addw", "addd" }; *si.buffer++ = 'p'; _nmd_append_string(&si, mnemonics[op - 0xd1]); *si.buffer++ = ' '; if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) { _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_W(&si); } else { _nmd_append_Pq(&si); *si.buffer++ = ','; _nmd_append_Qq(&si); } } else if (op == 0xb9 || op == 0xff) { _nmd_append_string(&si, op == 0xb9 ? "ud1 " : "ud0 "); _nmd_append_string(&si, _nmd_reg32[instruction->modrm.fields.reg]); *si.buffer++ = ','; if (instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, (instruction->mode == NMD_X86_MODE_64 ? _nmd_reg64 : _nmd_reg32)[instruction->modrm.fields.rm]); else _nmd_append_modrm_upper(&si, "dword"); } else { const char* str = 0; switch (op) { case 0x31: str = "rdtsc"; break; case 0x07: str = "sysret"; break; case 0x06: str = "clts"; break; case 0x08: str = "invd"; break; case 0x09: str = "wbinvd"; break; case 0x0b: str = "ud2"; break; case 0x0e: str = "femms"; break; case 0x30: str = "wrmsr"; break; case 0x32: str = "rdmsr"; break; case 0x33: str = "rdpmc"; break; case 0x34: str = "sysenter"; break; case 0x35: str = "sysexit"; break; case 0x37: str = "getsec"; break; case 0x77: str = "emms"; break; case 0xa0: str = "push fs"; break; case 0xa1: str = "pop fs"; break; case 0xa8: str = "push gs"; break; case 0xa9: str = "pop gs"; break; case 0xaa: str = "rsm"; break; default: return; } _nmd_append_string(&si, str); } } else if (instruction->opcode_map == NMD_X86_OPCODE_MAP_0F38) { if ((_NMD_R(op) == 2 || _NMD_R(op) == 3) && _NMD_C(op) <= 5) { const char* mnemonics[] = { "pmovsxbw", "pmovsxbd", "pmovsxbq", "pmovsxwd", "pmovsxwq", "pmovsxdq" }; _nmd_append_string(&si, mnemonics[_NMD_C(op)]); if (_NMD_R(op) == 3) *(si.buffer - 4) = 'z'; *si.buffer++ = ' '; _nmd_append_Vdq(&si); *si.buffer++ = ','; if (instruction->modrm.fields.mod == 0b11) _nmd_append_Udq(&si); else _nmd_append_modrm_upper(&si, _NMD_C(op) == 5 ? "qword" : (_NMD_C(op) % 3 == 0 ? "qword" : (_NMD_C(op) % 3 == 1 ? "dword" : "word"))); } else if (op >= 0x80 && op <= 0x83) { _nmd_append_string(&si, op == 0x80 ? "invept" : (op == 0x81 ? "invvpid" : "invpcid")); *si.buffer++ = ' '; _nmd_append_Gy(&si); *si.buffer++ = ','; _nmd_append_modrm_upper(&si, "xmmword"); } else if (op >= 0xc8 && op <= 0xcd) { const char* mnemonics[] = { "sha1nexte", "sha1msg1", "sha1msg2", "sha256rnds2", "sha256msg1", "sha256msg2" }; _nmd_append_string(&si, mnemonics[op - 0xc8]); *si.buffer++ = ' '; _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_W(&si); } else if (op == 0xcf) { _nmd_append_string(&si, "gf2p8mulb "); _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_W(&si); } else if (op == 0xf0 || op == 0xf1) { _nmd_append_string(&si, instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO ? "crc32" : "movbe"); *si.buffer++ = ' '; if (op == 0xf0) { if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) { _nmd_append_string(&si, _nmd_reg32[instruction->modrm.fields.reg]); *si.buffer++ = ','; _nmd_append_Eb(&si); } else { _nmd_append_Gv(&si); *si.buffer++ = ','; _nmd_append_Ev(&si); } } else { if (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) { _nmd_append_string(&si, _nmd_reg32[instruction->modrm.fields.reg]); *si.buffer++ = ','; if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) _nmd_append_Ew(&si); else _nmd_append_Ey(&si); } else { _nmd_append_Ev(&si); *si.buffer++ = ','; _nmd_append_Gv(&si); } } } else if (op == 0xf6) { _nmd_append_string(&si, instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? "adcx" : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? "adox" : (instruction->rex_w_prefix ? "wrssq" : "wrssd"))); *si.buffer++ = ' '; if (!instruction->simd_prefix) { _nmd_append_Ey(&si); *si.buffer++ = ','; _nmd_append_Gy(&si); } else { _nmd_append_Gy(&si); *si.buffer++ = ','; _nmd_append_Ey(&si); } } else if (op == 0xf5) { _nmd_append_string(&si, instruction->rex_w_prefix ? "wrussq " : "wrussd "); _nmd_append_modrm_upper(&si, instruction->rex_w_prefix ? "qword" : "dword"); *si.buffer++ = ','; _nmd_append_string(&si, (instruction->rex_w_prefix ? _nmd_reg64 : _nmd_reg32)[instruction->modrm.fields.reg]); } else if (op == 0xf8) { _nmd_append_string(&si, instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE ? "movdir64b" : (instruction->simd_prefix == NMD_X86_PREFIXES_REPEAT ? "enqcmd" : "enqcmds")); *si.buffer++ = ' '; _nmd_append_string(&si, (instruction->mode == NMD_X86_MODE_64 ? _nmd_reg64 : (instruction->mode == NMD_X86_MODE_16 ? _nmd_reg16 : _nmd_reg32))[instruction->modrm.fields.rm]); *si.buffer++ = ','; _nmd_append_modrm_upper(&si, "zmmword"); } else if (op == 0xf9) { _nmd_append_string(&si, "movdiri "); _nmd_append_modrm_upper_without_address_specifier(&si); *si.buffer++ = ','; _nmd_append_string(&si, _nmd_reg32[instruction->modrm.fields.rm]); } else { if (op == 0x40) _nmd_append_string(&si, "pmulld"); else if (op == 0x41) _nmd_append_string(&si, "phminposuw"); else if (op >= 0xdb && op <= 0xdf) { const char* mnemonics[] = { "aesimc", "aesenc", "aesenclast", "aesdec", "aesdeclast" }; _nmd_append_string(&si, mnemonics[op - 0xdb]); } else if (op == 0x37) _nmd_append_string(&si, "pcmpgtq"); else if (_NMD_R(op) == 2) { const char* mnemonics[] = { "pmuldq", "pcmpeqq", "movntdqa", "packusdw" }; _nmd_append_string(&si, mnemonics[_NMD_C(op) - 8]); } else if (_NMD_R(op) == 3) { const char* mnemonics[] = { "pminsb", "pminsd", "pminuw", "pminud", "pmaxsb", "pmaxsd", "pmaxuw", "pmaxud" }; _nmd_append_string(&si, mnemonics[_NMD_C(op) - 8]); } else if (op < 0x10) { const char* mnemonics[] = { "pshufb", "phaddw", "phaddd", "phaddsw", "pmaddubsw", "phsubw", "phsubd", "phsubsw", "psignb", "psignw", "psignd", "pmulhrsw", "permilpsv", "permilpdv", "testpsv", "testpdv" }; _nmd_append_string(&si, mnemonics[op]); } else if (op < 0x18) _nmd_append_string(&si, op == 0x10 ? "pblendvb" : (op == 0x14 ? "blendvps" : (op == 0x15 ? "blendvpd" : "ptest"))); else { _nmd_append_string(&si, "pabs"); *si.buffer++ = op == 0x1c ? 'b' : (op == 0x1d ? 'w' : 'd'); } *si.buffer++ = ' '; if (instruction->simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) { _nmd_append_Vdq(&si); *si.buffer++ = ','; _nmd_append_W(&si); } else { _nmd_append_Pq(&si); *si.buffer++ = ','; _nmd_append_Qq(&si); } } } else if (instruction->opcode_map == NMD_X86_OPCODE_MAP_0F3A) { if (_NMD_R(op) == 1) { const char* mnemonics[] = { "pextrb", "pextrw", "pextrd", "extractps" }; _nmd_append_string(&si, mnemonics[op - 0x14]); *si.buffer++ = ' '; if (instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, (si.instruction->rex_w_prefix ? _nmd_reg64 : _nmd_reg32)[instruction->modrm.fields.rm]); else { if (op == 0x14) _nmd_append_modrm_upper(&si, "byte"); else if (op == 0x15) _nmd_append_modrm_upper(&si, "word"); else if (op == 0x16) _nmd_append_Ey(&si); else _nmd_append_modrm_upper(&si, "dword"); } *si.buffer++ = ','; _nmd_append_Vdq(&si); } else if (_NMD_R(op) == 2) { _nmd_append_string(&si, op == 0x20 ? "pinsrb" : (op == 0x21 ? "insertps" : "pinsrd")); *si.buffer++ = ' '; _nmd_append_Vdq(&si); *si.buffer++ = ','; if (op == 0x20) { if (instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, _nmd_reg32[instruction->modrm.fields.rm]); else _nmd_append_modrm_upper(&si, "byte"); } else if (op == 0x21) { if (instruction->modrm.fields.mod == 0b11) _nmd_append_Udq(&si); else _nmd_append_modrm_upper(&si, "dword"); } else _nmd_append_Ey(&si); } else { if (op < 0x10) { const char* mnemonics[] = { "roundps", "roundpd", "roundss", "roundsd", "blendps", "blendpd", "pblendw", "palignr" }; _nmd_append_string(&si, mnemonics[op - 8]); } else if (_NMD_R(op) == 4) { const char* mnemonics[] = { "dpps", "dppd", "mpsadbw", 0, "pclmulqdq" }; _nmd_append_string(&si, mnemonics[_NMD_C(op)]); } else if (_NMD_R(op) == 6) { const char* mnemonics[] = { "pcmpestrm", "pcmpestri", "pcmpistrm", "pcmpistri" }; _nmd_append_string(&si, mnemonics[_NMD_C(op)]); } else if (op > 0x80) _nmd_append_string(&si, op == 0xcc ? "sha1rnds4" : (op == 0xce ? "gf2p8affineqb" : (op == 0xcf ? "gf2p8affineinvqb" : "aeskeygenassist"))); *si.buffer++ = ' '; if (op == 0xf && !(instruction->prefixes & (NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE | NMD_X86_PREFIXES_REPEAT | NMD_X86_PREFIXES_REPEAT_NOT_ZERO))) { _nmd_append_Pq(&si); *si.buffer++ = ','; _nmd_append_Qq(&si); } else { _nmd_append_Vdq(&si); *si.buffer++ = ','; if (instruction->modrm.fields.mod == 0b11) _nmd_append_string(&si, "xmm"), * si.buffer++ = (char)('0' + instruction->modrm.fields.rm); else _nmd_append_modrm_upper(&si, op == 0xa ? "dword" : (op == 0xb ? "qword" : "xmmword")); } } *si.buffer++ = ','; _nmd_append_number(&si, instruction->immediate); } #ifndef NMD_ASSEMBLY_DISABLE_FORMATTER_ATT_SYNTAX if (flags & NMD_X86_FORMAT_FLAGS_ATT_SYNTAX) { *si.buffer = '\0'; char* operand = (char*)_nmd_reverse_strchr(buffer, ' '); if (operand && *(operand - 1) != ' ') /* If the instruction has a ' '(space character) and the left character of 'operand' is not ' '(space) the instruction has operands. */ { /* If there is a memory operand. */ const char* memory_operand = _nmd_strchr(buffer, '['); if (memory_operand) { /* If the memory operand has pointer size. */ char* tmp2 = (char*)memory_operand - (*(memory_operand - 1) == ':' ? 7 : 4); if (_nmd_strstr(tmp2, "ptr") == tmp2) { /* Find the ' '(space) that is after two ' '(spaces). */ tmp2 -= 2; while (*tmp2 != ' ') tmp2--; operand = tmp2; } } const char* const first_operand_const = operand; char* first_operand = operand + 1; char* second_operand = 0; /* Convert each operand to AT&T syntax. */ do { operand++; operand = _nmd_format_operand_to_att(operand, &si); if (*operand == ',') second_operand = operand; } while (*operand); /* Swap operands. */ if (second_operand) /* At least two operands. */ { /* Copy first operand to 'tmp_buffer'. */ char tmp_buffer[64]; char* i = tmp_buffer; char* j = first_operand; for (; j < second_operand; i++, j++) *i = *j; *i = '\0'; /* Copy second operand to first operand. */ for (i = second_operand + 1; *i; first_operand++, i++) *first_operand = *i; *first_operand++ = ','; /* 'first_operand' is now the second operand. */ /* Copy 'tmp_buffer' to second operand. */ for (i = tmp_buffer; *first_operand; i++, first_operand++) *first_operand = *i; } /* Memory operands change the mnemonic string(e.g. 'mov eax, dword ptr [ebx]' -> 'movl (%ebx), %eax'). */ if (memory_operand && !_nmd_strstr(first_operand_const - 4, "lea")) { const char* r_char = _nmd_strchr(first_operand_const, 'r'); const char* e_char = _nmd_strchr(first_operand_const, 'e'); const char* call_str = _nmd_strstr(first_operand_const - 5, "call"); const char* jmp_str = _nmd_strstr(first_operand_const - 4, "jmp"); _nmd_insert_char(first_operand_const, (instruction->mode == NMD_X86_MODE_64 && ((r_char && *(r_char - 1) == '%') || call_str || jmp_str)) ? 'q' : (instruction->mode == NMD_X86_MODE_32 && ((e_char && *(e_char - 1) == '%') || call_str || jmp_str) ? 'l' : 'b')); si.buffer++; } } } #endif /* NMD_ASSEMBLY_DISABLE_FORMATTER_ATT_SYNTAX */ size_t string_length = si.buffer - buffer; #ifndef NMD_ASSEMBLY_DISABLE_FORMATTER_UPPERCASE if (flags & NMD_X86_FORMAT_FLAGS_UPPERCASE) { size_t i = 0; for (; i < string_length; i++) { if (_NMD_IS_LOWERCASE(buffer[i])) buffer[i] -= 0x20; /* Capitalize letter. */ } } #endif /* NMD_ASSEMBLY_DISABLE_FORMATTER_UPPERCASE */ #ifndef NMD_ASSEMBLY_DISABLE_FORMATTER_COMMA_SPACES if (flags & NMD_X86_FORMAT_FLAGS_COMMA_SPACES) { size_t i = 0; for (; i < string_length; i++) { if (buffer[i] == ',') { /* Move all characters after the comma one position to the right. */ size_t j = string_length; for (; j > i; j--) buffer[j] = buffer[j - 1]; buffer[i + 1] = ' '; si.buffer++, string_length++; } } } #endif /* NMD_ASSEMBLY_DISABLE_FORMATTER_COMMA_SPACES */ #ifndef NMD_ASSEMBLY_DISABLE_FORMATTER_OPERATOR_SPACES if (flags & NMD_X86_FORMAT_FLAGS_OPERATOR_SPACES) { size_t i = 0; for (; i < string_length; i++) { if (buffer[i] == '+' || (buffer[i] == '-' && buffer[i - 1] != ' ' && buffer[i - 1] != '(')) { /* Move all characters after the operator two positions to the right. */ size_t j = string_length + 1; for (; j > i; j--) buffer[j] = buffer[j - 2]; buffer[i + 1] = buffer[i]; buffer[i] = ' '; buffer[i + 2] = ' '; si.buffer += 2, string_length += 2; i++; } } } #endif /* NMD_ASSEMBLY_DISABLE_FORMATTER_OPERATOR_SPACES */ *si.buffer = '\0'; } #endif /* NMD_ASSEMBLY_IMPLEMENTATION */ ================================================ FILE: overlays/Example/Example.cpp ================================================ #include "Example.h" using namespace OF; void Example::Setup() { InitFramework(device, spriteBatch, window); box = CreateBox(100, 100, 100, 100); } void Example::Render() { CheckMouseEvents(); DrawBox(box, 255, 0, 0, 255); } ================================================ FILE: overlays/Example/Example.h ================================================ #pragma once #include "IRenderCallback.h" #include "OverlayFramework.h" class Example : public IRenderCallback { public: void Setup(); void Render(); private: OF::Box* box; }; ================================================ FILE: overlays/PauseTheGame/PauseTheGame.cpp ================================================ #include "PauseTheGame.h" using namespace OF; void PauseTheGame::Setup() { InitFramework(device, spriteBatch, window); ReadConfigFile(&keybind); pauseWindow = CreateBox(ofWindowWidth / 2 - 200, ofWindowHeight / 2 - 100, 400, 200); topBar = CreateBox(pauseWindow, 0, 0, pauseWindow->width, 7); bottomBar = CreateBox(pauseWindow, 0, pauseWindow->height, pauseWindow->width, 7); font = LoadFont("hook_fonts\\OpenSans-22.spritefont"); barTexture = LoadTexture("hook_textures\\bar.png"); rotatedBarTexture = LoadTexture("hook_textures\\bar_rotated.png"); SetFont(font); } void PauseTheGame::Render() { while (gamePaused) { if (MsgWaitForMultipleObjects(0, nullptr, FALSE, 100, QS_ALLINPUT) == WAIT_OBJECT_0) { if (CheckHotkey(keybind)) { gamePaused = false; return; } MSG msg; if (GetMessage(&msg, NULL, 0, 0) != -1) { TranslateMessage(&msg); DispatchMessage(&msg); } } } if (CheckHotkey(keybind)) { gamePaused = true; DrawBox(pauseWindow, 0, 0, 0, 240); DrawBox(topBar, barTexture); DrawBox(bottomBar, rotatedBarTexture); DrawText(pauseWindow, "Game paused.", 100, 80); } } void PauseTheGame::ReadConfigFile(unsigned int* keybind) { configFile.open(configFileName, std::fstream::in); if (configFile.is_open()) { std::string line = ""; getline(configFile, line); if (line.length() < 3) { *keybind = 'P'; } else { std::stringstream stringStream(line.substr(2, line.length())); logger.Log("Read keybind line: %s", line); stringStream >> std::hex >> *keybind; logger.Log("Keybind is: 0x%x", *keybind); } configFile.close(); } else { logger.Log("Using default keybind"); configFile.open(configFileName, std::fstream::out); if (configFile.is_open()) { configFile << "0x50"; configFile.close(); } } } ================================================ FILE: overlays/PauseTheGame/PauseTheGame.h ================================================ #pragma once #include #include "IRenderCallback.h" #include "OverlayFramework.h" #include "Logger.h" class PauseTheGame : public IRenderCallback { public: void Setup(); void Render(); private: Logger logger{ "PauseTheGame" }; std::fstream configFile; std::string configFileName = "pause_keybind.txt"; unsigned int keybind = 'P'; OF::Box* pauseWindow = nullptr; OF::Box* topBar = nullptr; OF::Box* bottomBar = nullptr; int font = 0; int barTexture = 0; int rotatedBarTexture = 0; bool gamePaused = false; void ReadConfigFile(unsigned int* keybind); }; ================================================ FILE: overlays/RiseDpsMeter/RiseDpsMeter.cpp ================================================ #include "RiseDpsMeter.h" using namespace OF; void RiseDpsMeter::Setup() { InitFramework(device, spriteBatch, window); int defaultXPos = ofWindowWidth / 2; int defaultYPos = ofWindowHeight / 2; ReadConfigFile(&defaultXPos, &defaultYPos); dpsMeterWindow = CreateBox(defaultXPos, defaultYPos, 400, 180); dpsMeterWindowDivider = CreateBox(dpsMeterWindow, 23, dpsMeterWindow->height - 40, dpsMeterWindow->width - 46, 1); placeholderWindow = CreateBox(defaultXPos, defaultYPos, dpsMeterWindow->width, dpsMeterWindow->height); placeholderOkButton = CreateBox(placeholderWindow, placeholderWindow->width / 2 - 30, placeholderWindow->height - 40, 60, 30); placeholderOkButtonBorder = CreateBox(placeholderWindow, placeholderWindow->width / 2 - 27, placeholderWindow->height - 17, 55, 2); cornerWindow = CreateBox(0, 0, 50, 50); int columnWidth = 1; int numColumns = floor(((float)dpsMeterWindowDivider->width) / columnWidth) - (columnWidth * 2); for (int i = 0; i < numColumns; i++) { graphColumns.push_back(CreateBox(dpsMeterWindow, i * columnWidth + columnWidth + 25, dpsMeterWindow->height - 41, columnWidth, 0)); } font = LoadFont("hook_fonts\\OpenSans-22.spritefont"); SetFont(font); SetPointerOffsets(); } void RiseDpsMeter::Render() { CheckMouseEvents(); CheckHotkeys(); ReadMemory(); if (playerData[0].totalDamage != 0) { if (timerUpdateDps.Check()) { UpdateDamageStats(); UpdateGraph(); } if (!userDisabledDpsMeter) { DrawDpsMeter(); } } if (showPlaceholder) { DrawPlaceholder(); } if (showCornerText) { if (timerCornerText.Check()) { showCornerText = false; } DrawCornerText(); } } void RiseDpsMeter::DrawDpsMeter() { std::ostringstream dpsString; dpsString << std::fixed << std::setprecision(1) << playerData[0].averageDps; DrawBox(dpsMeterWindow, 0, 0, 0, 130); DrawBox(dpsMeterWindowDivider, 255, 255, 255, 255); for (auto box : graphColumns) { DrawBox(box, 125, 125, 255, 255); } DrawText(dpsMeterWindow, "DPS: " + dpsString.str(), 20, dpsMeterWindow->height - 32, 0.6f); DrawText(dpsMeterWindow, "High: " + std::to_string(playerData[0].mostDamageInOneSecond), 162, dpsMeterWindow->height - 32, 0.6f); DrawText(dpsMeterWindow, "Total: " + std::to_string(playerData[0].totalDamage), 287, dpsMeterWindow->height - 32, 0.6f); } void RiseDpsMeter::DrawPlaceholder() { DrawBox(placeholderWindow, 0, 0, 0, 170); DrawText(placeholderWindow, " (Hold Left Alt and drag to move)\n" "Move me to a suitable location then click ok.\n " "The window will auto-hide.", 23, 45, 0.6f); int color = 170; if (placeholderOkButton->hover) { color = 255; } DrawBox(placeholderOkButton, 0, 0, 0, 0); DrawBox(placeholderOkButtonBorder, color, color, color, 255); DrawText(placeholderOkButton, "Ok", 14, -3, 0.7f, color, color, color); if (placeholderOkButton->clicked) { showPlaceholder = false; dpsMeterWindow->x = placeholderWindow->x; dpsMeterWindow->y = placeholderWindow->y; WriteToConfigFile(); } } void RiseDpsMeter::DrawCornerText() { DrawText(cornerWindow, "RiseDpsMeter v2.0 loaded", 0, 0, 0.5f); } void RiseDpsMeter::UpdateDamageStats() { for (auto& player : playerData) { if (player.dpsHistory.size() > 21600) { player.dpsHistory.erase(player.dpsHistory.begin()); } player.dpsHistory.push_back(player.totalDamage - player.previousTotalDamage); player.previousTotalDamage = player.totalDamage; if (player.dpsHistory.back() > player.mostDamageInOneSecond) { player.mostDamageInOneSecond = player.dpsHistory.back(); } player.averageDps = 0; for (auto dps : player.dpsHistory) { player.averageDps += dps; } player.averageDps /= player.dpsHistory.size(); } } void RiseDpsMeter::UpdateGraph() { for (int i = graphColumns.size() - 1, j = playerData[0].dpsHistory.size() - 1; i > -1 && j > -1; i--, j--) { if (playerData[0].dpsHistory[j] != 0) { graphColumns[i]->height = MapIntToRange(playerData[0].dpsHistory[j], 0, playerData[0].mostDamageInOneSecond, 0, 130); graphColumns[i]->y = dpsMeterWindow->height - 41 - graphColumns[i]->height; } if (i != graphColumns.size() - 1 && j != playerData[0].dpsHistory.size() - 1 && playerData[0].dpsHistory[j + 1] == 0) { graphColumns[i + 1]->height = graphColumns[i]->height * 0.8; graphColumns[i + 1]->y = dpsMeterWindow->height - 41 - graphColumns[i + 1]->height; } } } void RiseDpsMeter::ReadMemory() { for (auto& player : playerData) { ReadPlayerDamage(&player); } } void RiseDpsMeter::ReadPlayerDamage(PlayerData* playerData) { if (playerData->timerVerifyDamageAddress.Check()) { FindDamageMemoryAddress(playerData); } if (playerData->damageAddressIsFound) { MemoryUtils::MemCopy( (uintptr_t)&playerData->totalDamage, playerData->damageMemoryAddress, sizeof(uint64_t)); } else { ResetState(); } } void RiseDpsMeter::FindDamageMemoryAddress(PlayerData* playerData) { if (playerData->damagePointerOffsets.size() > 0) { playerData->damageMemoryAddress = MemoryUtils::ReadPointerChain(playerData->damagePointerOffsets); } if (playerData->damageMemoryAddress == 0) { playerData->damageAddressIsFound = false; } else { playerData->damageAddressIsFound = true; } } void RiseDpsMeter::SetPointerOffsets() { playerData.resize(1); playerData[0].damagePointerOffsets = { 0x0f6e7550, 0xd8, 0x110, 0x20, 0x20, 0x138, 0x5c8, 0x18 }; } void RiseDpsMeter::CheckHotkeys() { if (CheckHotkey('P', VK_LSHIFT)) { placeholderWindow->x = ofWindowWidth / 2; placeholderWindow->y = ofWindowHeight / 2; dpsMeterWindow->x = ofWindowWidth / 2; dpsMeterWindow->y = ofWindowHeight / 2; } else if (CheckHotkey('P')) { if (userDisabledDpsMeter) { userDisabledDpsMeter = false; } else { userDisabledDpsMeter = true; } } if (CheckHotkey(UNBOUND, VK_LMENU)) { dpsMeterWindow->draggable = true; placeholderWindow->draggable = true; } else { dpsMeterWindow->draggable = false; placeholderWindow->draggable = false; } } void RiseDpsMeter::WriteToConfigFile() { dpsMeterConfigFile.open(configFileName, std::fstream::out); if (dpsMeterConfigFile.is_open() && dpsMeterWindow != nullptr) { dpsMeterConfigFile << dpsMeterWindow->x << " " << dpsMeterWindow->y << std::endl; dpsMeterConfigFile.close(); } } void RiseDpsMeter::ReadConfigFile(int* x, int* y) { dpsMeterConfigFile.open(configFileName, std::fstream::in); if (dpsMeterConfigFile.is_open()) { std::string line = ""; getline(dpsMeterConfigFile, line); std::stringstream stringStream(line); std::istream_iterator begin(stringStream); std::istream_iterator end; std::vector values(begin, end); if (values.size() >= 2) { *x = std::stoi(values[0]); *y = std::stoi(values[1]); } dpsMeterConfigFile.close(); } else { showPlaceholder = true; } } void RiseDpsMeter::ResetState() { for (auto box : graphColumns) { box->height = 0; } for (auto& player : playerData) { player.Reset(); } timerUpdateDps.Reset(); } RiseDpsMeter::~RiseDpsMeter() { WriteToConfigFile(); } ================================================ FILE: overlays/RiseDpsMeter/RiseDpsMeter.h ================================================ #pragma once #include #include #include #include #include #include #include #include "IRenderCallback.h" #include "OverlayFramework.h" #include "MemoryUtils.h" class Timer { public: Timer(unsigned int millis) { interval = millis; } bool Check() { auto now = std::chrono::system_clock::now(); if (resetOnNextCheck) { lastExecutionTime = now; resetOnNextCheck = false; return false; } auto diff = std::chrono::duration_cast(now - lastExecutionTime); if (diff.count() >= interval) { lastExecutionTime = now; return true; } return false; } void Reset() { resetOnNextCheck = true; } private: unsigned int interval = 0; bool resetOnNextCheck = true; std::chrono::system_clock::time_point lastExecutionTime; }; class RiseDpsMeter : public IRenderCallback { public: void Setup(); void Render(); ~RiseDpsMeter(); private: struct PlayerData { uint64_t totalDamage = 0; uint64_t previousTotalDamage = 0; uint64_t mostDamageInOneSecond = 0; double averageDps = 0.0; uintptr_t damageMemoryAddress = 0; std::vector damagePointerOffsets; bool damageAddressIsFound = false; Timer timerVerifyDamageAddress{ 10000 }; std::vector dpsHistory; void Reset() { totalDamage = 0; previousTotalDamage = 0; mostDamageInOneSecond = 0; averageDps = 0; dpsHistory.clear(); } }; std::vector playerData; std::fstream dpsMeterConfigFile; std::string configFileName = "rise_dps_meter.cfg"; OF::Box* cornerWindow = nullptr; OF::Box* dpsMeterWindow = nullptr; OF::Box* dpsMeterWindowDivider = nullptr; OF::Box* placeholderWindow = nullptr; OF::Box* placeholderOkButton = nullptr; OF::Box* placeholderOkButtonBorder = nullptr; std::vector graphColumns; Timer timerUpdateDps{ 1000 }; Timer timerCornerText{ 3000 }; bool showCornerText = true; bool showPlaceholder = false; bool showDpsMeter = false; bool userDisabledDpsMeter = false; int font = -1; void DrawDpsMeter(); void DrawPlaceholder(); void DrawCornerText(); void UpdateDamageStats(); void UpdateGraph(); void ReadMemory(); void ReadPlayerDamage(PlayerData* playerStats); void FindDamageMemoryAddress(PlayerData* playerStats); void SetPointerOffsets(); void CheckHotkeys(); void WriteToConfigFile(); void ReadConfigFile(int* x, int* y); void ResetState(); }; ================================================ FILE: packages.config ================================================  ================================================ FILE: src/DirectXHook.cpp ================================================ #include "DirectXHook.h" #include "RiseDpsMeter/RiseDpsMeter.h" #include "Example/Example.h" #include "PauseTheGame/PauseTheGame.h" static DirectXHook* hookInstance = nullptr; /* * Note: The non-member functions in this file are defined as such because * you are not allowed to pass around pointers to member functions. */ /* * Present will get hooked and detour to this function. * Present is part of the final rendering stage in DirectX. * We need to hook this so we can grab the pointer to the game's swapchain and use it to render. * We also place our own rendering code within this function call. * https://docs.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgiswapchain-present */ HRESULT __stdcall OnPresent(IDXGISwapChain* pThis, UINT syncInterval, UINT flags) { hookInstance->renderer->OnPresent(pThis, syncInterval, flags); return ((Present)hookInstance->presentReturnAddress)(pThis, syncInterval, flags); } /* * ResizeBuffers will get hooked and detour to this function. * ResizeBuffers usually gets called by the game when the window resizes. * We need to hook this so we can release our references to various resources when it's called. * If we don't do this then the game will most likely crash. * https://docs.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgiswapchain-resizebuffers */ HRESULT __stdcall OnResizeBuffers(IDXGISwapChain* pThis, UINT bufferCount, UINT width, UINT height, DXGI_FORMAT newFormat, UINT swapChainFlags) { hookInstance->renderer->OnResizeBuffers(pThis, bufferCount, width, height, newFormat, swapChainFlags); return ((ResizeBuffers)hookInstance->resizeBuffersReturnAddress)(pThis, bufferCount, width, height, newFormat, swapChainFlags); } /* * ExecuteCommandLists will get hooked and detour to this function. * ExecuteCommandLists gets called when work is to be submitted to the GPU. * We need to hook this so we can grab the command queue and use it to create the D3D11On12 device in DirectX 12 games. * https://learn.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12commandqueue-executecommandlists */ void __stdcall OnExecuteCommandLists(ID3D12CommandQueue* pThis, UINT numCommandLists, const ID3D12CommandList** ppCommandLists) { if (pThis->GetDesc().Type == D3D12_COMMAND_LIST_TYPE_DIRECT) { hookInstance->renderer->SetCommandQueue(pThis); //hookInstance->UnhookCommandQueue(); } ((ExecuteCommandLists)hookInstance->executeCommandListsReturnAddress)(pThis, numCommandLists, ppCommandLists); } void GetCommandQueue() { ID3D12CommandQueue* dummyCommandQueue = hookInstance->CreateDummyCommandQueue(); hookInstance->HookCommandQueue(dummyCommandQueue, (uintptr_t)&OnExecuteCommandLists, &hookInstance->executeCommandListsReturnAddress); } DirectXHook::DirectXHook(ID3DRenderer* renderer) { this->renderer = renderer; hookInstance = this; } void DirectXHook::Hook() { logger.Log("OnPresent: %p", &OnPresent); logger.Log("OnResizeBuffers: %p", &OnResizeBuffers); renderer->SetGetCommandQueueCallback(&GetCommandQueue); IDXGISwapChain* dummySwapChain = CreateDummySwapChain(); HookSwapChain(dummySwapChain, (uintptr_t)&OnPresent, (uintptr_t)&OnResizeBuffers, &presentReturnAddress, &resizeBuffersReturnAddress); } void DirectXHook::SetDrawExampleTriangle(bool doDraw) { ((Renderer*)renderer)->SetDrawExampleTriangle(doDraw); } void DirectXHook::AddRenderCallback(IRenderCallback* object) { renderer->AddRenderCallback(object); } IDXGISwapChain* DirectXHook::CreateDummySwapChain() { WNDCLASSEX wc { 0 }; wc.cbSize = sizeof(wc); wc.lpfnWndProc = DefWindowProc; wc.lpszClassName = TEXT("dummy class"); RegisterClassExA(&wc); HWND hwnd = CreateWindow(wc.lpszClassName, TEXT(""), WS_DISABLED, 0, 0, 0, 0, NULL, NULL, NULL, nullptr); DXGI_SWAP_CHAIN_DESC desc{ 0 }; desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; desc.SampleDesc.Count = 1; desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; desc.BufferCount = 1; desc.OutputWindow = hwnd; desc.Windowed = TRUE; desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1 }; ID3D11Device* dummyDevice = nullptr; IDXGISwapChain* dummySwapChain = nullptr; HRESULT result = D3D11CreateDeviceAndSwapChain( NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, featureLevels, 1, D3D11_SDK_VERSION, &desc, &dummySwapChain, &dummyDevice, NULL, NULL); DestroyWindow(desc.OutputWindow); UnregisterClass(wc.lpszClassName, GetModuleHandle(nullptr)); //dummySwapChain->Release(); //dummyDevice->Release(); if (FAILED(result)) { _com_error error(result); logger.Log("D3D11CreateDeviceAndSwapChain failed: %s", error.ErrorMessage()); return nullptr; } logger.Log("D3D11CreateDeviceAndSwapChain succeeded"); return dummySwapChain; } //IDXGISwapChain* DirectXHook::CreateDummySwapChain(ID3D11Device* dummyDevice) //{ // IDXGIDevice2* pDXGIDevice; // CheckSuccess(dummyDevice->QueryInterface(__uuidof(IDXGIDevice2), (void**)&pDXGIDevice)); // // IDXGIAdapter* pDXGIAdapter; // CheckSuccess(pDXGIDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&pDXGIAdapter)); // // WNDCLASSEX wc { 0 }; // wc.cbSize = sizeof(wc); // wc.lpfnWndProc = DefWindowProc; // wc.lpszClassName = TEXT("dummy class"); // RegisterClassExA(&wc); // HWND hwnd = CreateWindow(wc.lpszClassName, TEXT(""), WS_DISABLED, 0, 0, 0, 0, NULL, NULL, NULL, nullptr); // // DXGI_SWAP_CHAIN_DESC1 desc{ 0 }; // desc.Width = 1; // desc.Height = 1; // desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; // desc.Stereo = FALSE; // desc.SampleDesc = { 1, 0 }; // desc.BufferUsage = DXGI_USAGE_BACK_BUFFER; // desc.BufferCount = 2; // desc.Scaling = DXGI_SCALING_STRETCH; // desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; // desc.Flags = DXGI_SWAP_CHAIN_FLAG_DISPLAY_ONLY; // // IDXGIFactory2* pIDXGIFactory = nullptr; // CheckSuccess(pDXGIAdapter->GetParent(__uuidof(IDXGIFactory2), (void**)&pIDXGIFactory)); // // IDXGISwapChain* dummySwapChain = nullptr; // IDXGISwapChain1* dummySwapChain1 = nullptr; // CheckSuccess(pIDXGIFactory->CreateSwapChainForHwnd( // dummyDevice, // hwnd, // &desc, // NULL, // NULL, // &dummySwapChain1)); // // DestroyWindow(hwnd); // UnregisterClass(wc.lpszClassName, GetModuleHandle(nullptr)); // // CheckSuccess(dummySwapChain1->QueryInterface(__uuidof(IDXGISwapChain), (void**)&dummySwapChain)); // //dummySwapChain1->Release(); // return dummySwapChain; //} //ID3D11Device* DirectXHook::CreateDummyD3D11Device() //{ // D3D_FEATURE_LEVEL featureLevels[] = // { // D3D_FEATURE_LEVEL_11_0, // D3D_FEATURE_LEVEL_11_1 // }; // // ID3D11Device* dummyDevice = nullptr; // CheckSuccess(D3D11CreateDevice( // NULL, // D3D_DRIVER_TYPE_HARDWARE, // NULL, // 0, // featureLevels, // 2, // D3D11_SDK_VERSION, // &dummyDevice, // NULL, // NULL)); // // return dummyDevice; //} ID3D12CommandQueue* DirectXHook::CreateDummyCommandQueue() { D3D12_COMMAND_QUEUE_DESC queueDesc {}; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; ID3D12Device* d12Device = nullptr; D3D12CreateDevice(NULL, D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), (void**)&d12Device); ID3D12CommandQueue* dummyCommandQueue; d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&dummyCommandQueue)); logger.Log("Command queue: %p", dummyCommandQueue); return dummyCommandQueue; } void DirectXHook::HookSwapChain( IDXGISwapChain* dummySwapChain, uintptr_t presentDetourFunction, uintptr_t resizeBuffersDetourFunction, uintptr_t* presentReturnAddress, uintptr_t* resizeBuffersReturnAddress) { int vmtPresentOffset = 8; int vmtResizeBuffersOffset = 13; size_t numBytes = sizeof(size_t); uintptr_t vmtBaseAddress = (*(uintptr_t*)dummySwapChain); uintptr_t vmtPresentIndex = (vmtBaseAddress + (numBytes * vmtPresentOffset)); uintptr_t vmtResizeBuffersIndex = (vmtBaseAddress + (numBytes * vmtResizeBuffersOffset)); logger.Log("SwapChain VMT base address: %p", vmtBaseAddress); logger.Log("SwapChain VMT Present index: %p", vmtPresentIndex); logger.Log("SwapChain VMT ResizeBuffers index: %p", vmtResizeBuffersIndex); MemoryUtils::ToggleMemoryProtection(false, vmtPresentIndex, numBytes); MemoryUtils::ToggleMemoryProtection(false, vmtResizeBuffersIndex, numBytes); uintptr_t presentAddress = (*(uintptr_t*)vmtPresentIndex); uintptr_t resizeBuffersAddress = (*(uintptr_t*)vmtResizeBuffersIndex); logger.Log("Present address: %p", presentAddress); logger.Log("ResizeBuffers address: %p", resizeBuffersAddress); MemoryUtils::ToggleMemoryProtection(true, vmtPresentIndex, numBytes); MemoryUtils::ToggleMemoryProtection(true, vmtResizeBuffersIndex, numBytes); MemoryUtils::PlaceHook(presentAddress, presentDetourFunction, presentReturnAddress); MemoryUtils::PlaceHook(resizeBuffersAddress, resizeBuffersDetourFunction, resizeBuffersReturnAddress); dummySwapChain->Release(); } void DirectXHook::HookCommandQueue( ID3D12CommandQueue* dummyCommandQueue, uintptr_t executeCommandListsDetourFunction, uintptr_t* executeCommandListsReturnAddress) { int vmtExecuteCommandListsOffset = 10; size_t numBytes = 8; uintptr_t vmtBaseAddress = (*(uintptr_t*)dummyCommandQueue); uintptr_t vmtExecuteCommandListsIndex = (vmtBaseAddress + (numBytes * vmtExecuteCommandListsOffset)); logger.Log("CommandQueue VMT base address: %p", vmtBaseAddress); logger.Log("ExecuteCommandLists index: %p", vmtExecuteCommandListsIndex); MemoryUtils::ToggleMemoryProtection(false, vmtExecuteCommandListsIndex, numBytes); executeCommandListsAddress = (*(uintptr_t*)vmtExecuteCommandListsIndex); MemoryUtils::ToggleMemoryProtection(true, vmtExecuteCommandListsIndex, numBytes); logger.Log("ExecuteCommandLists address: %p", executeCommandListsAddress); bool hookIsPresent = MemoryUtils::IsAddressHooked(executeCommandListsAddress); if (hookIsPresent) { logger.Log("Hook already present in ExecuteCommandLists"); } MemoryUtils::PlaceHook(executeCommandListsAddress, executeCommandListsDetourFunction, executeCommandListsReturnAddress); dummyCommandQueue->Release(); } void DirectXHook::UnhookCommandQueue() { MemoryUtils::Unhook(executeCommandListsAddress); } ================================================ FILE: src/DllMain.cpp ================================================ #include #include "DirectXHook.h" #include "Logger.h" #include "MemoryUtils.h" #include "Example/Example.h" #include "UniversalProxyDLL.h" static Logger logger{ "DllMain" }; void OpenDebugTerminal() { std::fstream terminalEnableFile; terminalEnableFile.open("hook_enable_terminal.txt", std::fstream::in); if (terminalEnableFile.is_open()) { if (AllocConsole()) { freopen_s((FILE**)stdout, "CONOUT$", "w", stdout); SetWindowText(GetConsoleWindow(), "DirectXHook"); } terminalEnableFile.close(); } } DWORD WINAPI HookThread(LPVOID lpParam) { static Renderer renderer; static DirectXHook dxHook(&renderer); static Example example; dxHook.AddRenderCallback(&example); dxHook.Hook(); return 0; } BOOL WINAPI DllMain(HMODULE module, DWORD reason, LPVOID) { if (reason == DLL_PROCESS_ATTACH) { OpenDebugTerminal(); UPD::MuteLogging(); UPD::CreateProxy(module); CreateThread(0, 0, &HookThread, 0, 0, NULL); } return 1; } ================================================ FILE: src/Renderer.cpp ================================================ #include "Renderer.h" using namespace Microsoft::WRL; using namespace DirectX; void Renderer::OnPresent(IDXGISwapChain* pThis, UINT syncInterval, UINT flags) { if (mustInitializeD3DResources) { if (!InitD3DResources(pThis)) { return; } mustInitializeD3DResources = false; } Render(); } void Renderer::OnResizeBuffers(IDXGISwapChain* pThis, UINT bufferCount, UINT width, UINT height, DXGI_FORMAT newFormat, UINT swapChainFlags) { logger.Log("ResizeBuffers was called!"); ReleaseViewsBuffersAndContext(); mustInitializeD3DResources = true; } void Renderer::SetDrawExampleTriangle(bool doDraw) { drawExamples = doDraw; } void Renderer::AddRenderCallback(IRenderCallback* object) { callbackObject = object; callbackInitialized = false; } void Renderer::SetCommandQueue(ID3D12CommandQueue* commandQueue) { this->commandQueue = commandQueue; } void Renderer::SetGetCommandQueueCallback(void (*callback)()) { callbackGetCommandQueue = callback; } bool Renderer::InitD3DResources(IDXGISwapChain* swapChain) { logger.Log("Initializing D3D resources..."); try { if (!isDeviceRetrieved) { this->swapChain = swapChain; isDeviceRetrieved = RetrieveD3DDeviceFromSwapChain(); } if (WaitForCommandQueueIfRunningD3D12()) { return false; } GetSwapChainDescription(); GetBufferCount(); GetSwapchainWindowInfo(); CreateViewport(); InitD3D(); } catch (std::string errorMsg) { logger.Log(errorMsg); return false; } firstTimeInitPerformed = true; logger.Log("Successfully initialized D3D resources"); return true; } bool Renderer::RetrieveD3DDeviceFromSwapChain() { logger.Log("Retrieving D3D device..."); bool d3d11DeviceRetrieved = SUCCEEDED(swapChain->GetDevice(__uuidof(ID3D11Device), (void**)d3d11Device.GetAddressOf())); if (d3d11DeviceRetrieved) { logger.Log("Retrieved D3D11 device"); return true; } bool d3d12DeviceRetrieved = SUCCEEDED(swapChain->GetDevice(__uuidof(ID3D12Device), (void**)d3d12Device.GetAddressOf())); if (d3d12DeviceRetrieved) { logger.Log("Retrieved D3D12 device"); isRunningD3D12 = true; return true; } throw("Failed to retrieve D3D device"); } void Renderer::GetSwapChainDescription() { ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC)); swapChain->GetDesc(&swapChainDesc); } void Renderer::GetBufferCount() { if (isRunningD3D12) { bufferCount = swapChainDesc.BufferCount; } else { bufferCount = 1; } } void Renderer::GetSwapchainWindowInfo() { RECT hwndRect; GetClientRect(swapChainDesc.OutputWindow, &hwndRect); windowWidth = hwndRect.right - hwndRect.left; windowHeight = hwndRect.bottom - hwndRect.top; logger.Log("Window width: %i", windowWidth); logger.Log("Window height: %i", windowHeight); window = swapChainDesc.OutputWindow; } void Renderer::CreateViewport() { ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT)); viewport.Width = windowWidth; viewport.Height = windowHeight; viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; viewport.TopLeftX = 0; viewport.TopLeftY = 0; } void Renderer::InitD3D() { if (!isRunningD3D12) { InitD3D11(); } else { InitD3D12(); } } void Renderer::InitD3D11() { logger.Log("Initializing D3D11..."); if (!firstTimeInitPerformed) { CreateD3D11Context(); CreateSpriteBatch(); } CreateD3D11RenderTargetView(); logger.Log("Initialized D3D11"); } void Renderer::CreateD3D11Context() { d3d11Device->GetImmediateContext(&d3d11Context); } void Renderer::CreateSpriteBatch() { spriteBatch = std::make_shared(d3d11Context.Get()); } void Renderer::CreateD3D11RenderTargetView() { ComPtr backbuffer; swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)backbuffer.GetAddressOf()); d3d11RenderTargetViews = std::vector>(1, nullptr); d3d11Device->CreateRenderTargetView(backbuffer.Get(), nullptr, d3d11RenderTargetViews[0].GetAddressOf()); backbuffer.ReleaseAndGetAddressOf(); } void Renderer::InitD3D12() { logger.Log("Initializing D3D12..."); if (!firstTimeInitPerformed) { CreateD3D11On12Device(); CheckSuccess(swapChain->QueryInterface(__uuidof(IDXGISwapChain3), &swapChain3)); CreateSpriteBatch(); } CreateD3D12Buffers(); logger.Log("Initialized D3D12"); } bool Renderer::WaitForCommandQueueIfRunningD3D12() { if (isRunningD3D12) { if (commandQueue.Get() == nullptr) { logger.Log("Waiting for command queue..."); if (!getCommandQueueCalled && callbackGetCommandQueue != nullptr) { callbackGetCommandQueue(); getCommandQueueCalled = true; } return true; } } return false; } void Renderer::CreateD3D11On12Device() { D3D_FEATURE_LEVEL featureLevels = { D3D_FEATURE_LEVEL_11_0 }; bool d3d11On12DeviceCreated = CheckSuccess( D3D11On12CreateDevice( d3d12Device.Get(), NULL, &featureLevels, 1, reinterpret_cast(commandQueue.GetAddressOf()), 1, 0, d3d11Device.GetAddressOf(), d3d11Context.GetAddressOf(), nullptr)); bool d3d11On12DeviceChecked = CheckSuccess(d3d11Device.As(&d3d11On12Device)); if (!d3d11On12DeviceCreated || !d3d11On12DeviceChecked) { throw("Failed to create D3D11On12 device"); } } void Renderer::CreateD3D12Buffers() { d3d12RenderTargets = std::vector>(bufferCount, nullptr); d3d11WrappedBackBuffers = std::vector>(bufferCount, nullptr); d3d11RenderTargetViews = std::vector>(bufferCount, nullptr); ComPtr rtvHeap = CreateD3D12RtvHeap(); D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle(rtvHeap->GetCPUDescriptorHandleForHeapStart()); UINT rtvDescriptorSize = d3d12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); for (UINT i = 0; i < bufferCount; i++) { CreateD3D12RenderTargetView(i, rtvHandle); CreateD3D11WrappedBackBuffer(i); CreateD3D11RenderTargetViewWithWrappedBackBuffer(i); rtvHandle.ptr = SIZE_T(INT64(rtvHandle.ptr) + INT64(1) * INT64(rtvDescriptorSize)); } } ComPtr Renderer::CreateD3D12RtvHeap() { ComPtr rtvHeap; D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; rtvHeapDesc.NumDescriptors = bufferCount; rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; CheckSuccess(d3d12Device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(rtvHeap.GetAddressOf()))); return rtvHeap; } void Renderer::CreateD3D12RenderTargetView(UINT bufferIndex, D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle) { if (!CheckSuccess(swapChain->GetBuffer(bufferIndex, IID_PPV_ARGS(&d3d12RenderTargets[bufferIndex])))) { throw("Failed to create D3D12 render target view"); } d3d12Device->CreateRenderTargetView(d3d12RenderTargets[bufferIndex].Get(), nullptr, rtvHandle); } void Renderer::CreateD3D11WrappedBackBuffer(UINT bufferIndex) { D3D11_RESOURCE_FLAGS d3d11Flags = { D3D11_BIND_RENDER_TARGET }; if (!CheckSuccess( d3d11On12Device->CreateWrappedResource( d3d12RenderTargets[bufferIndex].Get(), &d3d11Flags, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT, IID_PPV_ARGS(&d3d11WrappedBackBuffers[bufferIndex])))) { throw "Failed to create D3D11 wrapped backbuffer"; } } void Renderer::CreateD3D11RenderTargetViewWithWrappedBackBuffer(UINT bufferIndex) { if (!CheckSuccess( d3d11Device->CreateRenderTargetView( d3d11WrappedBackBuffers[bufferIndex].Get(), nullptr, d3d11RenderTargetViews[bufferIndex].GetAddressOf()))) { throw "Failed to create D3D11 render target view"; } } void Renderer::Render() { PreRender(); if (drawExamples) { if (!examplesLoaded) { CreatePipeline(); CreateExampleTriangle(); CreateExampleFont(); examplesLoaded = true; } DrawExampleTriangle(); DrawExampleText(); } RenderCallbacks(); PostRender(); } void Renderer::PreRender() { if (isRunningD3D12) { bufferIndex = swapChain3->GetCurrentBackBufferIndex(); d3d11On12Device->AcquireWrappedResources(d3d11WrappedBackBuffers[bufferIndex].GetAddressOf(), 1); } d3d11Context->OMSetRenderTargets(1, d3d11RenderTargetViews[bufferIndex].GetAddressOf(), 0); d3d11Context->RSSetViewports(1, &viewport); } void Renderer::RenderCallbacks() { if (callbackObject != nullptr) { if (!callbackInitialized) { callbackObject->Init(d3d11Device, d3d11Context, spriteBatch, window); callbackObject->Setup(); callbackInitialized = true; } spriteBatch->Begin(SpriteSortMode_BackToFront); callbackObject->Render(); spriteBatch->End(); } } void Renderer::PostRender() { if (isRunningD3D12) { d3d11On12Device->ReleaseWrappedResources(d3d11WrappedBackBuffers[bufferIndex].GetAddressOf(), 1); d3d11Context->Flush(); } } // Creates the necessary things for rendering the examples void Renderer::CreatePipeline() { ComPtr vertexShaderBlob = LoadShader(shaderData, "vs_5_0", "VS").Get(); ComPtr pixelShaderTexturesBlob = LoadShader(shaderData, "ps_5_0", "PSTex").Get(); ComPtr pixelShaderBlob = LoadShader(shaderData, "ps_5_0", "PS").Get(); d3d11Device->CreateVertexShader( vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), nullptr, vertexShader.GetAddressOf()); d3d11Device->CreatePixelShader( pixelShaderTexturesBlob->GetBufferPointer(), pixelShaderTexturesBlob->GetBufferSize(), nullptr, pixelShaderTextures.GetAddressOf()); d3d11Device->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), nullptr, pixelShader.GetAddressOf()); D3D11_INPUT_ELEMENT_DESC inputLayoutDesc[3] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 } }; d3d11Device->CreateInputLayout( inputLayoutDesc, ARRAYSIZE(inputLayoutDesc), vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), inputLayout.GetAddressOf()); D3D11_SAMPLER_DESC samplerDesc; ZeroMemory(&samplerDesc, sizeof(D3D11_SAMPLER_DESC)); samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; samplerDesc.MinLOD = 0; samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; d3d11Device->CreateSamplerState(&samplerDesc, &samplerState); D3D11_TEXTURE2D_DESC dsDesc; dsDesc.Width = windowWidth; dsDesc.Height = windowHeight; dsDesc.MipLevels = 1; dsDesc.ArraySize = 1; dsDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; dsDesc.SampleDesc.Count = 1; dsDesc.SampleDesc.Quality = 0; dsDesc.Usage = D3D11_USAGE_DEFAULT; dsDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; dsDesc.CPUAccessFlags = 0; dsDesc.MiscFlags = 0; d3d11Device->CreateTexture2D(&dsDesc, 0, depthStencilBuffer.GetAddressOf()); d3d11Device->CreateDepthStencilView(depthStencilBuffer.Get(), 0, depthStencilView.GetAddressOf()); } ComPtr Renderer::LoadShader(const char* shader, std::string targetShaderVersion, std::string shaderEntry) { logger.Log("Loading shader: %s", shaderEntry.c_str()); ComPtr errorBlob = nullptr; ComPtr shaderBlob; D3DCompile( shader, strlen(shader), 0, nullptr, nullptr, shaderEntry.c_str(), targetShaderVersion.c_str(), D3DCOMPILE_ENABLE_STRICTNESS, 0, shaderBlob.GetAddressOf(), errorBlob.GetAddressOf()); if (errorBlob) { char error[256]{ 0 }; memcpy(error, errorBlob->GetBufferPointer(), errorBlob->GetBufferSize()); logger.Log("Shader error: %s", error); return nullptr; } return shaderBlob; } void Renderer::CreateExampleTriangle() { // Create the vertex buffer Vertex vertices[] = { { XMFLOAT3(0.0f, 0.1f, 0.0f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f), XMFLOAT2(0.5f, 0.0f) }, { XMFLOAT3(0.1f, -0.1f, 0.1f), XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f), XMFLOAT2(1.0f, 0.5f) }, { XMFLOAT3(-0.1f, -0.1f, 0.1f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f), XMFLOAT2(0.0f, 0.5f) }, { XMFLOAT3(0.0f, -0.1f, -0.1f), XMFLOAT4(1.0f, 0.0f, 1.0f, 1.0f), XMFLOAT2(1.0f, 0.5f) } }; D3D11_BUFFER_DESC vbDesc = { 0 }; ZeroMemory(&vbDesc, sizeof(D3D11_BUFFER_DESC)); vbDesc.ByteWidth = sizeof(Vertex) * ARRAYSIZE(vertices); vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; vbDesc.Usage = D3D11_USAGE_DEFAULT; vbDesc.StructureByteStride = sizeof(Vertex); D3D11_SUBRESOURCE_DATA vbData = { vertices, 0, 0 }; d3d11Device->CreateBuffer(&vbDesc, &vbData, vertexBuffer.GetAddressOf()); // Create the index buffer unsigned int indices[] = { 0, 2, 1, 0, 3, 2, 0, 1, 3, 1, 2, 3 }; triangleNumIndices = ARRAYSIZE(indices); D3D11_BUFFER_DESC ibDesc; ZeroMemory(&ibDesc, sizeof(ibDesc)); ibDesc.ByteWidth = sizeof(unsigned int) * ARRAYSIZE(indices); ibDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; ibDesc.Usage = D3D11_USAGE_DEFAULT; ibDesc.CPUAccessFlags = 0; ibDesc.MiscFlags = 0; D3D11_SUBRESOURCE_DATA ibData = { indices, 0, 0 }; d3d11Device->CreateBuffer(&ibDesc, &ibData, indexBuffer.GetAddressOf()); // Create the constant buffer // We need to send the world view projection (WVP) matrix to the shader D3D11_BUFFER_DESC cbDesc = { 0 }; ZeroMemory(&cbDesc, sizeof(D3D11_BUFFER_DESC)); cbDesc.ByteWidth = sizeof(ConstantBufferData); cbDesc.Usage = D3D11_USAGE_DYNAMIC; cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; cbDesc.MiscFlags = 0; cbDesc.StructureByteStride = 0; D3D11_SUBRESOURCE_DATA cbData = { &constantBufferData, 0, 0 }; d3d11Device->CreateBuffer(&cbDesc, &cbData, constantBuffer.GetAddressOf()); // Create the rasterizer state. // We need to control which face of a shape is culled, and we need to know which order to set our indices D3D11_RASTERIZER_DESC rsDesc; ZeroMemory(&rsDesc, sizeof(D3D11_RASTERIZER_DESC)); rsDesc.FillMode = D3D11_FILL_SOLID; rsDesc.CullMode = D3D11_CULL_BACK; rsDesc.FrontCounterClockwise = FALSE; rsDesc.DepthClipEnable = TRUE; d3d11Device->CreateRasterizerState(&rsDesc, rasterizerState.GetAddressOf()); // Create the depth stencil state D3D11_DEPTH_STENCIL_DESC dsDesc; ZeroMemory(&dsDesc, sizeof(D3D11_DEPTH_STENCIL_DESC)); dsDesc.DepthEnable = true; dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; dsDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; d3d11Device->CreateDepthStencilState(&dsDesc, depthStencilState.GetAddressOf()); } void Renderer::CreateExampleFont() { std::fstream file = std::fstream(".\\hook_fonts\\OpenSans-22.spritefont"); if (!file.fail()) { file.close(); exampleFont = std::make_shared(d3d11Device.Get(), L".\\hook_fonts\\OpenSans-22.spritefont"); } else { logger.Log("Failed to load the example font"); } } void Renderer::DrawExampleTriangle() { d3d11Context->OMSetRenderTargets(1, d3d11RenderTargetViews[bufferIndex].GetAddressOf(), depthStencilView.Get()); d3d11Context->ClearDepthStencilView(depthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); trianglePos = XMVectorSet ( XMVectorGetX(trianglePos) + triangleVelX, XMVectorGetY(trianglePos) + triangleVelY, XMVectorGetZ(trianglePos), 1.0f ); int hit = 0; // Check if the triangle hits an edge of the screen if (triangleNdc.x > 0.96f) { triangleVelX = -triangleSpeed; hit++; } else if (triangleNdc.x < -0.96f) { triangleVelX = triangleSpeed; hit++; } if (triangleNdc.y > 0.90f) { triangleVelY = -triangleSpeed; hit++; } else if (triangleNdc.y < -0.90f) { triangleVelY = triangleSpeed; hit++; } if (hit == 2) { logger.Log("Hit the corner!"); } triangleCounter += 0.01f; triangleRotX = cos(triangleCounter) * 2; triangleRotY = sin(triangleCounter) * 2; XMMATRIX world = XMMatrixIdentity(); XMMATRIX translation = XMMatrixTranslation(XMVectorGetX(trianglePos), XMVectorGetY(trianglePos), XMVectorGetZ(trianglePos)); XMMATRIX rotationX = XMMatrixRotationX(triangleRotX); XMMATRIX rotationY = XMMatrixRotationY(triangleRotY); XMMATRIX rotationZ = XMMatrixRotationZ(triangleRotZ); XMMATRIX rotation = rotationX * rotationY * rotationZ; XMMATRIX scale = XMMatrixScaling(triangleScale.x, triangleScale.y, triangleScale.z); world = scale * rotation * translation; XMMATRIX view = XMMatrixLookAtLH(XMVECTOR{ 0.0f, 0.0f, -5.5f }, XMVECTOR{ 0.0f, 0.0f, 0.0f }, XMVECTOR{ 0.0f, 1.0f, 0.0f }); XMMATRIX projection = XMMatrixPerspectiveFovLH(1.3, ((float)windowWidth / (float)windowHeight), 0.1f, 1000.0f); // Get the triangle's screen space (NDC) from its world space, used for collision checking and text positioning XMVECTOR clipSpacePos = XMVector4Transform((XMVector4Transform(trianglePos, view)), projection); XMStoreFloat3 ( &triangleNdc, { XMVectorGetX(clipSpacePos) / XMVectorGetW(clipSpacePos), XMVectorGetY(clipSpacePos) / XMVectorGetW(clipSpacePos), XMVectorGetZ(clipSpacePos) / XMVectorGetW(clipSpacePos) } ); constantBufferData.wvp = XMMatrixTranspose(world * view * projection); // Map the constant buffer on the GPU D3D11_MAPPED_SUBRESOURCE mappedResource; d3d11Context->Map(constantBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); memcpy(mappedResource.pData, &constantBufferData, sizeof(ConstantBufferData)); d3d11Context->Unmap(constantBuffer.Get(), 0); d3d11Context->VSSetShader(vertexShader.Get(), nullptr, 0); d3d11Context->PSSetShader(pixelShader.Get(), nullptr, 0); d3d11Context->IASetInputLayout(inputLayout.Get()); d3d11Context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); d3d11Context->RSSetState(rasterizerState.Get()); d3d11Context->OMSetDepthStencilState(depthStencilState.Get(), 0); d3d11Context->VSSetConstantBuffers(0, 1, constantBuffer.GetAddressOf()); UINT stride = sizeof(Vertex); UINT offset = 0; d3d11Context->IASetVertexBuffers(0, 1, vertexBuffer.GetAddressOf(), &stride, &offset); d3d11Context->IASetIndexBuffer(indexBuffer.Get(), DXGI_FORMAT_R32_UINT, 0); d3d11Context->DrawIndexed(triangleNumIndices, 0, 0); } void Renderer::DrawExampleText() { if (exampleFont == nullptr) return; const char* text = "Hello, World!"; const char* text2 = "This is a DirectX hook."; XMFLOAT2 stringSize1, stringSize2; XMVECTOR textVector = exampleFont->MeasureString(text); XMVECTOR textVector2 = exampleFont->MeasureString(text2); XMStoreFloat2(&stringSize1, textVector); XMStoreFloat2(&stringSize2, textVector2); XMFLOAT2 textPos1 = XMFLOAT2 ( (windowWidth / 2) * (triangleNdc.x + 1) - (stringSize1.x / 2), (windowHeight - ((windowHeight / 2) * (triangleNdc.y + 1))) - (stringSize1.y / 2) - 150 ); XMFLOAT2 textPos2 = XMFLOAT2 ( (windowWidth / 2) * (triangleNdc.x + 1) - (stringSize2.x / 2), (windowHeight - ((windowHeight / 2) * (triangleNdc.y + 1))) - (stringSize2.y / 2) + 150 ); spriteBatch->Begin(); exampleFont->DrawString(spriteBatch.get(), text, textPos1); exampleFont->DrawString(spriteBatch.get(), text2, textPos2); spriteBatch->End(); } void Renderer::ReleaseViewsBuffersAndContext() { for (int i = 0; i < bufferCount; i++) { if (d3d12Device.Get() == nullptr) { d3d11RenderTargetViews[i].ReleaseAndGetAddressOf(); } else { d3d11RenderTargetViews[i].ReleaseAndGetAddressOf(); d3d12RenderTargets[i].ReleaseAndGetAddressOf(); d3d11WrappedBackBuffers[i].ReleaseAndGetAddressOf(); } } if (d3d11Context.Get() != nullptr) { d3d11Context->Flush(); } } bool Renderer::CheckSuccess(HRESULT hr) { if (SUCCEEDED(hr)) { return true; } _com_error err(hr); logger.Log("%s", err.ErrorMessage()); return false; } ================================================ FILE: src/Shaders.hlsl ================================================ // These are some generic shaders that we need to render the example triangle // Make sure that this file is excluded from the build to avoid compile time errors! R""( Texture2D tex; SamplerState sampleType; cbuffer constantBuffer { matrix wvp; }; struct VS_Input { float4 pos : POSITION; float4 color : COLOR; float2 texcoord : TEXCOORD; }; struct VS_Output { float4 pos : SV_POSITION; float4 color : COLOR; float2 texcoord : TEXCOORD; }; VS_Output VS(VS_Input input) { VS_Output vsout; vsout.pos = mul(input.pos, wvp); vsout.color = input.color; vsout.texcoord = input.texcoord; return vsout; } float4 PSTex(VS_Output input) : SV_Target { float4 textureColor; textureColor = tex.Sample(sampleType, input.texcoord); return textureColor; } float4 PS(VS_Output input) : SV_Target { return input.color; } )""