diff --git a/Examples/DemoDll/DemoDll.vcxproj b/Examples/DemoDll/DemoDll.vcxproj new file mode 100644 index 0000000..f826192 --- /dev/null +++ b/Examples/DemoDll/DemoDll.vcxproj @@ -0,0 +1,109 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {19B2E75C-385A-40BF-8FAE-2F5E1E24E2EC} + {1bc93793-694f-48fe-9372-81e2b05556fd} + v4.5 + 12.0 + Debug + Win32 + DemoDrv + 10.0 + + + + Windows10 + true + ClangCL + StaticLibrary + KMDF + Universal + false + + + Windows10 + false + ClangCL + StaticLibrary + KMDF + Universal + false + + + + + + + + + + + DbgengKernelDebugger + false + $(IncludePath);$(KMDF_INC_PATH)$(KMDF_VER_PATH) + $(LLVMInstallDir)\bin;$(ExecutablePath); + + + DbgengKernelDebugger + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(IncludePath);$(KMDF_INC_PATH)$(KMDF_VER_PATH) + $(LLVMInstallDir)\bin;$(ExecutablePath); + + + + stdcpp17 + false + false + false + -mcmodel=large -c %(AdditionalOptions) + false + + + DriverEntry + + + + + stdcpp17 + false + Disabled + false + false + -mcmodel=large %(AdditionalOptions) + Async + true + false + Default + Default + + + DriverEntry + + + $(IntDir)ignore\$(MSBuildProjectName).log + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Examples/DemoDll/DemoDll.vcxproj.filters b/Examples/DemoDll/DemoDll.vcxproj.filters new file mode 100644 index 0000000..102fcae --- /dev/null +++ b/Examples/DemoDll/DemoDll.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {92e25b44-aaeb-40a2-b8c9-7eab6c210e8d} + + + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/DemoDrv/DemoDrv.vcxproj.user b/Examples/DemoDll/DemoDll.vcxproj.user similarity index 100% rename from DemoDrv/DemoDrv.vcxproj.user rename to Examples/DemoDll/DemoDll.vcxproj.user diff --git a/DemoDrv/Theodosius.h b/Examples/DemoDll/Theodosius.h similarity index 100% rename from DemoDrv/Theodosius.h rename to Examples/DemoDll/Theodosius.h diff --git a/Examples/DemoDll/main.cpp b/Examples/DemoDll/main.cpp new file mode 100644 index 0000000..6075d4c --- /dev/null +++ b/Examples/DemoDll/main.cpp @@ -0,0 +1,28 @@ +#include "Theodosius.h" + +extern "C" int MessageBoxA( + unsigned hWnd, + char* lpText, + char* lpCaption, + unsigned uType +); + +void UsermodeNoObfuscation() +{ + for (auto idx = 0u; idx < 5; ++idx) + MessageBoxA(0, "Demo", "Hello From Non-Obfuscated Routine!", 0); +} + +MutateRoutine +void UsermodeMutateDemo() +{ + MessageBoxA(0, "Demo", "Hello From Mutated Routine!", 0); +} + +ObfuscateRoutine +extern "C" int ModuleEntry() +{ + MessageBoxA(0, "Demo", "Hello From Obfuscated Routine!", 0); + UsermodeMutateDemo(); + UsermodeNoObfuscation(); +} \ No newline at end of file diff --git a/DemoDrv/DemoDrv.vcxproj b/Examples/DemoDrv/DemoDrv.vcxproj similarity index 98% rename from DemoDrv/DemoDrv.vcxproj rename to Examples/DemoDrv/DemoDrv.vcxproj index a9c8224..938b631 100644 --- a/DemoDrv/DemoDrv.vcxproj +++ b/Examples/DemoDrv/DemoDrv.vcxproj @@ -25,7 +25,7 @@ Windows10 true ClangCL - DynamicLibrary + StaticLibrary KMDF Universal false diff --git a/DemoDrv/DemoDrv.vcxproj.filters b/Examples/DemoDrv/DemoDrv.vcxproj.filters similarity index 100% rename from DemoDrv/DemoDrv.vcxproj.filters rename to Examples/DemoDrv/DemoDrv.vcxproj.filters diff --git a/Examples/DemoDrv/DemoDrv.vcxproj.user b/Examples/DemoDrv/DemoDrv.vcxproj.user new file mode 100644 index 0000000..88a5509 --- /dev/null +++ b/Examples/DemoDrv/DemoDrv.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/DemoDrv/DriverEntry.cpp b/Examples/DemoDrv/DriverEntry.cpp similarity index 100% rename from DemoDrv/DriverEntry.cpp rename to Examples/DemoDrv/DriverEntry.cpp diff --git a/Examples/DemoDrv/Theodosius.h b/Examples/DemoDrv/Theodosius.h new file mode 100644 index 0000000..a1d30bc --- /dev/null +++ b/Examples/DemoDrv/Theodosius.h @@ -0,0 +1,3 @@ +#pragma once +#define ObfuscateRoutine __declspec(code_seg(".theo"), noinline) +#define MutateRoutine __declspec(code_seg(".theo1"), noinline) \ No newline at end of file diff --git a/DemoDrv/Types.h b/Examples/DemoDrv/Types.h similarity index 100% rename from DemoDrv/Types.h rename to Examples/DemoDrv/Types.h diff --git a/Examples/Theodosius-Examples.sln b/Examples/Theodosius-Examples.sln new file mode 100644 index 0000000..96cc6c6 --- /dev/null +++ b/Examples/Theodosius-Examples.sln @@ -0,0 +1,43 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30907.101 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DemoDll", "DemoDll\DemoDll.vcxproj", "{19B2E75C-385A-40BF-8FAE-2F5E1E24E2EC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DemoDrv", "DemoDrv\DemoDrv.vcxproj", "{A9959D7F-E405-4380-A1B4-4CE8DD929397}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Theodosius-VDM", "Theodosius-Kernel\Theodosius-VDM\Theodosius-VDM.vcxproj", "{B3A57EE2-364D-42FA-A827-33F43136B549}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Theodosius-MSREXEC", "Theodosius-Kernel\Theodosius-MSREXEC\Theodosius-MSREXEC.vcxproj", "{0043C2E6-7080-4363-BD50-298A4C51562F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {19B2E75C-385A-40BF-8FAE-2F5E1E24E2EC}.Debug|x64.ActiveCfg = Debug|x64 + {19B2E75C-385A-40BF-8FAE-2F5E1E24E2EC}.Debug|x64.Build.0 = Debug|x64 + {19B2E75C-385A-40BF-8FAE-2F5E1E24E2EC}.Release|x64.ActiveCfg = Release|x64 + {19B2E75C-385A-40BF-8FAE-2F5E1E24E2EC}.Release|x64.Build.0 = Release|x64 + {A9959D7F-E405-4380-A1B4-4CE8DD929397}.Debug|x64.ActiveCfg = Debug|x64 + {A9959D7F-E405-4380-A1B4-4CE8DD929397}.Debug|x64.Build.0 = Debug|x64 + {A9959D7F-E405-4380-A1B4-4CE8DD929397}.Release|x64.ActiveCfg = Release|x64 + {A9959D7F-E405-4380-A1B4-4CE8DD929397}.Release|x64.Build.0 = Release|x64 + {B3A57EE2-364D-42FA-A827-33F43136B549}.Debug|x64.ActiveCfg = Debug|x64 + {B3A57EE2-364D-42FA-A827-33F43136B549}.Debug|x64.Build.0 = Debug|x64 + {B3A57EE2-364D-42FA-A827-33F43136B549}.Release|x64.ActiveCfg = Release|x64 + {B3A57EE2-364D-42FA-A827-33F43136B549}.Release|x64.Build.0 = Release|x64 + {0043C2E6-7080-4363-BD50-298A4C51562F}.Debug|x64.ActiveCfg = Debug|x64 + {0043C2E6-7080-4363-BD50-298A4C51562F}.Debug|x64.Build.0 = Debug|x64 + {0043C2E6-7080-4363-BD50-298A4C51562F}.Release|x64.ActiveCfg = Release|x64 + {0043C2E6-7080-4363-BD50-298A4C51562F}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4E9E0E63-4158-4F7F-A1A9-B81A0C57E1D1} + EndGlobalSection +EndGlobal diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Theodosius-MSREXEC.vcxproj b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Theodosius-MSREXEC.vcxproj new file mode 100644 index 0000000..48f8190 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Theodosius-MSREXEC.vcxproj @@ -0,0 +1,278 @@ + + + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {0043C2E6-7080-4363-BD50-298A4C51562F} + Theodosius + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + true + $(ProjectDir);$(IncludePath) + + + false + $(ProjectDir);$(IncludePath) + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions);ZYAN_NO_LIBC;ZYDIS_NO_LIBC;ZYCORE_STATIC_DEFINE;ZYDIS_STATIC_DEFINE;_CRT_SECURE_NO_WARNINGS + true + stdcpp17 + + + Console + true + Zydis.lib;Zycore.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions);ZYAN_NO_LIBC;ZYDIS_NO_LIBC;ZYCORE_STATIC_DEFINE;ZYDIS_STATIC_DEFINE;_CRT_SECURE_NO_WARNINGS + true + stdcpp17 + + + Console + true + true + true + Zydis.lib;Zycore.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Document + + + + + + + \ No newline at end of file diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Theodosius-MSREXEC.vcxproj.filters b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Theodosius-MSREXEC.vcxproj.filters new file mode 100644 index 0000000..d9502c7 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Theodosius-MSREXEC.vcxproj.filters @@ -0,0 +1,589 @@ + + + + + {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 + + + {8d07ce7e-3b56-4b27-bb05-d12987f22384} + + + {77c3f715-9d9f-488e-a1d5-542124a490b0} + + + {c89c1fbb-39b5-4954-9774-0c2600773705} + + + {db8b5110-ec16-4fc2-80cc-7241ccbfec1c} + + + {c51e3b93-1496-49d7-838f-825d75b29ee6} + + + {d28d9202-4139-42a0-9f49-71beb5e01670} + + + {a847dc8c-08a3-4ea7-a20d-157963dd41a8} + + + {706001e9-56f5-41d2-b209-9f5543d0bd11} + + + {a8e52093-e1b2-4ef3-b427-ebea8772bbbf} + + + {da6ded33-7d62-4f83-b8e7-4d343fe49cd7} + + + {244a52bf-80cb-43ac-ac0d-a6aad89b9eb0} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\core + + + Source Files\asmjit\x86 + + + Source Files\asmjit\x86 + + + Source Files\asmjit\x86 + + + Source Files\asmjit\x86 + + + Source Files\asmjit\x86 + + + Source Files\asmjit\x86 + + + Source Files\asmjit\x86 + + + Source Files\asmjit\x86 + + + Source Files\asmjit\x86 + + + Source Files\asmjit\x86 + + + Source Files\asmjit\x86 + + + Source Files + + + Source Files + + + + + Header Files\Zydis\Generated + + + Header Files\Zydis\Generated + + + Header Files\Zydis\Generated + + + Header Files\Zydis\Generated + + + Header Files\Zydis\Generated + + + Header Files\Zydis\Internal + + + Header Files\Zydis\Internal + + + Header Files\Zydis\Internal + + + Header Files\Zydis\Internal + + + Header Files\Zydis\Internal + + + Header Files\Zydis\Internal + + + Header Files + + + Header Files + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore\API + + + Header Files\Zycore\API + + + Header Files\Zycore\API + + + Header Files\Zycore\API + + + Header Files\Zycore\API + + + Header Files\Zydis + + + Header Files\Zycore + + + Header Files + + + Header Files + + + Header Files + + + Header Files\asmjit + + + Header Files\asmjit + + + Header Files\asmjit + + + Header Files\asmjit + + + Header Files\asmjit + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\core + + + Header Files\asmjit\x86 + + + Header Files\asmjit\x86 + + + Header Files\asmjit\x86 + + + Header Files\asmjit\x86 + + + Header Files\asmjit\x86 + + + Header Files\asmjit\x86 + + + Header Files\asmjit\x86 + + + Header Files\asmjit\x86 + + + Header Files\asmjit\x86 + + + Header Files\asmjit\x86 + + + Header Files\asmjit\x86 + + + Header Files\asmjit\x86 + + + Header Files\asmjit\x86 + + + Header Files\asmjit\x86 + + + Header Files\asmjit\x86 + + + Header Files\asmjit\x86 + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Theodosius-MSREXEC.vcxproj.user b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Theodosius-MSREXEC.vcxproj.user new file mode 100644 index 0000000..e9f3ec8 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Theodosius-MSREXEC.vcxproj.user @@ -0,0 +1,13 @@ + + + + + + WindowsLocalDebugger + + + + + WindowsLocalDebugger + + \ No newline at end of file diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore.lib b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore.lib new file mode 100644 index 0000000..b36a938 Binary files /dev/null and b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore.lib differ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Memory.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Memory.h new file mode 100644 index 0000000..c5fa8a9 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Memory.h @@ -0,0 +1,134 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * @brief + */ + +#ifndef ZYCORE_API_MEMORY_H +#define ZYCORE_API_MEMORY_H + +#include +#include +#include +#include + +#if defined(ZYAN_WINDOWS) +# include +#elif defined(ZYAN_POSIX) +# include +#else +# error "Unsupported platform detected" +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/** + * Defines the `ZyanMemoryPageProtection` enum. + */ +typedef enum ZyanMemoryPageProtection_ +{ +#if defined(ZYAN_WINDOWS) + + ZYAN_PAGE_READONLY = PAGE_READONLY, + ZYAN_PAGE_READWRITE = PAGE_READWRITE, + ZYAN_PAGE_EXECUTE = PAGE_EXECUTE, + ZYAN_PAGE_EXECUTE_READ = PAGE_EXECUTE_READ, + ZYAN_PAGE_EXECUTE_READWRITE = PAGE_EXECUTE_READWRITE + +#elif defined(ZYAN_POSIX) + + ZYAN_PAGE_READONLY = PROT_READ, + ZYAN_PAGE_READWRITE = PROT_READ | PROT_WRITE, + ZYAN_PAGE_EXECUTE = PROT_EXEC, + ZYAN_PAGE_EXECUTE_READ = PROT_EXEC | PROT_READ, + ZYAN_PAGE_EXECUTE_READWRITE = PROT_EXEC | PROT_READ | PROT_WRITE + +#endif +} ZyanMemoryPageProtection; + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the system page size. + * + * @return The system page size. + */ +ZYCORE_EXPORT ZyanU32 ZyanMemoryGetSystemPageSize(); + +/** + * Returns the system allocation granularity. + * + * The system allocation granularity specifies the minimum amount of bytes which can be allocated + * at a specific address by a single call of `ZyanMemoryVirtualAlloc`. + * + * This value is typically 64KiB on Windows systems and equal to the page size on most POSIX + * platforms. + * + * @return The system allocation granularity. + */ +ZYCORE_EXPORT ZyanU32 ZyanMemoryGetSystemAllocationGranularity(); + +/* ---------------------------------------------------------------------------------------------- */ +/* Memory management */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Changes the memory protection value of one or more pages. + * + * @param address The start address aligned to a page boundary. + * @param size The size. + * @param protection The new page protection value. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanMemoryVirtualProtect(void* address, ZyanUSize size, + ZyanMemoryPageProtection protection); + +/** + * Releases one or more memory pages starting at the given address. + * + * @param address The start address aligned to a page boundary. + * @param size The size. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanMemoryVirtualFree(void* address, ZyanUSize size); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#endif /* ZYCORE_API_MEMORY_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Process.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Process.h new file mode 100644 index 0000000..0b6a5c6 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Process.h @@ -0,0 +1,67 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * @brief + */ + +#ifndef ZYCORE_API_PROCESS_H +#define ZYCORE_API_PROCESS_H + +#include +#include +#include + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + + + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * @brief Flushes the process instruction cache. + * + * @param address The address. + * @param size The size. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanProcessFlushInstructionCache(void* address, ZyanUSize size); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#endif /* ZYCORE_API_PROCESS_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Synchronization.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Synchronization.h new file mode 100644 index 0000000..8414a44 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Synchronization.h @@ -0,0 +1,133 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * @brief + */ + +#ifndef ZYCORE_API_SYNCHRONIZATION_H +#define ZYCORE_API_SYNCHRONIZATION_H + +#ifndef ZYAN_NO_LIBC + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +#if defined(ZYAN_POSIX) + +#include + +/* ---------------------------------------------------------------------------------------------- */ +/* Critical Section */ +/* ---------------------------------------------------------------------------------------------- */ + +typedef pthread_mutex_t ZyanCriticalSection; + +/* ---------------------------------------------------------------------------------------------- */ + +#elif defined(ZYAN_WINDOWS) + +#include + +/* ---------------------------------------------------------------------------------------------- */ +/* Critical Section */ +/* ---------------------------------------------------------------------------------------------- */ + +typedef CRITICAL_SECTION ZyanCriticalSection; + +/* ---------------------------------------------------------------------------------------------- */ + +#else +# error "Unsupported platform detected" +#endif + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Critical Section */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Initializes a critical section. + * + * @param critical_section A pointer to the `ZyanCriticalSection` struct. + */ +ZYCORE_EXPORT ZyanStatus ZyanCriticalSectionInitialize(ZyanCriticalSection* critical_section); + +/** + * Enters a critical section. + * + * @param critical_section A pointer to the `ZyanCriticalSection` struct. + */ +ZYCORE_EXPORT ZyanStatus ZyanCriticalSectionEnter(ZyanCriticalSection* critical_section); + +/** + * Tries to enter a critical section. + * + * @param critical_section A pointer to the `ZyanCriticalSection` struct. + * + * @return Returns `ZYAN_TRUE` if the critical section was successfully entered or `ZYAN_FALSE`, + * if not. + */ +ZYCORE_EXPORT ZyanBool ZyanCriticalSectionTryEnter(ZyanCriticalSection* critical_section); + +/** + * Leaves a critical section. + * + * @param critical_section A pointer to the `ZyanCriticalSection` struct. + */ +ZYCORE_EXPORT ZyanStatus ZyanCriticalSectionLeave(ZyanCriticalSection* critical_section); + +/** + * Deletes a critical section. + * + * @param critical_section A pointer to the `ZyanCriticalSection` struct. + */ +ZYCORE_EXPORT ZyanStatus ZyanCriticalSectionDelete(ZyanCriticalSection* critical_section); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYAN_NO_LIBC */ + +#endif /* ZYCORE_API_SYNCHRONIZATION_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Terminal.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Terminal.h new file mode 100644 index 0000000..17dc384 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Terminal.h @@ -0,0 +1,163 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file Provides cross-platform terminal helper functions. + * @brief + */ + +#ifndef ZYCORE_API_TERMINAL_H +#define ZYCORE_API_TERMINAL_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ZYAN_NO_LIBC + +/* ============================================================================================== */ +/* VT100 CSI SGR sequences */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +#define ZYAN_VT100SGR_RESET "\033[0m" + +/* ---------------------------------------------------------------------------------------------- */ +/* Foreground colors */ +/* ---------------------------------------------------------------------------------------------- */ + +#define ZYAN_VT100SGR_FG_DEFAULT "\033[39m" + +#define ZYAN_VT100SGR_FG_BLACK "\033[30m" +#define ZYAN_VT100SGR_FG_RED "\033[31m" +#define ZYAN_VT100SGR_FG_GREEN "\033[32m" +#define ZYAN_VT100SGR_FG_YELLOW "\033[33m" +#define ZYAN_VT100SGR_FG_BLUE "\033[34m" +#define ZYAN_VT100SGR_FG_MAGENTA "\033[35m" +#define ZYAN_VT100SGR_FG_CYAN "\033[36m" +#define ZYAN_VT100SGR_FG_WHITE "\033[37m" +#define ZYAN_VT100SGR_FG_BRIGHT_BLACK "\033[90m" +#define ZYAN_VT100SGR_FG_BRIGHT_RED "\033[91m" +#define ZYAN_VT100SGR_FG_BRIGHT_GREEN "\033[92m" +#define ZYAN_VT100SGR_FG_BRIGHT_YELLOW "\033[93m" +#define ZYAN_VT100SGR_FG_BRIGHT_BLUE "\033[94m" +#define ZYAN_VT100SGR_FG_BRIGHT_MAGENTA "\033[95m" +#define ZYAN_VT100SGR_FG_BRIGHT_CYAN "\033[96m" +#define ZYAN_VT100SGR_FG_BRIGHT_WHITE "\033[97m" + +/* ---------------------------------------------------------------------------------------------- */ +/* Background color */ +/* ---------------------------------------------------------------------------------------------- */ + +#define ZYAN_VT100SGR_BG_DEFAULT "\033[49m" + +#define ZYAN_VT100SGR_BG_BLACK "\033[40m" +#define ZYAN_VT100SGR_BG_RED "\033[41m" +#define ZYAN_VT100SGR_BG_GREEN "\033[42m" +#define ZYAN_VT100SGR_BG_YELLOW "\033[43m" +#define ZYAN_VT100SGR_BG_BLUE "\033[44m" +#define ZYAN_VT100SGR_BG_MAGENTA "\033[45m" +#define ZYAN_VT100SGR_BG_CYAN "\033[46m" +#define ZYAN_VT100SGR_BG_WHITE "\033[47m" +#define ZYAN_VT100SGR_BG_BRIGHT_BLACK "\033[100m" +#define ZYAN_VT100SGR_BG_BRIGHT_RED "\033[101m" +#define ZYAN_VT100SGR_BG_BRIGHT_GREEN "\033[102m" +#define ZYAN_VT100SGR_BG_BRIGHT_YELLOW "\033[103m" +#define ZYAN_VT100SGR_BG_BRIGHT_BLUE "\033[104m" +#define ZYAN_VT100SGR_BG_BRIGHT_MAGENTA "\033[105m" +#define ZYAN_VT100SGR_BG_BRIGHT_CYAN "\033[106m" +#define ZYAN_VT100SGR_BG_BRIGHT_WHITE "\033[107m" + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/** + * Declares the `ZyanStandardStream` enum. + */ +typedef enum ZyanStandardStream_ +{ + /** + * The default input stream. + */ + ZYAN_STDSTREAM_IN, + /** + * The default output stream. + */ + ZYAN_STDSTREAM_OUT, + /** + * The default error stream. + */ + ZYAN_STDSTREAM_ERR +} ZyanStandardStream; + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/** + * Enables VT100 ansi escape codes for the given stream. + * + * @param stream Either `ZYAN_STDSTREAM_OUT` or `ZYAN_STDSTREAM_ERR`. + * + * @return A zyan status code. + * + * This functions returns `ZYAN_STATUS_SUCCESS` on all non-Windows systems without performing any + * operations, assuming that VT100 is supported by default. + * + * On Windows systems, VT100 functionality is only supported on Windows 10 build 1607 (anniversary + * update) and later. + */ +ZYCORE_EXPORT ZyanStatus ZyanTerminalEnableVT100(ZyanStandardStream stream); + +/** + * Checks, if the given standard stream reads from or writes to a terminal. + * + * @param stream The standard stream to check. + * + * @return `ZYAN_STATUS_TRUE`, if the stream is bound to a terminal, `ZYAN_STATUS_FALSE` if not, + * or another zyan status code if an error occured. + */ +ZYCORE_EXPORT ZyanStatus ZyanTerminalIsTTY(ZyanStandardStream stream); + +/* ============================================================================================== */ + +#endif // ZYAN_NO_LIBC + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_API_TERMINAL_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Thread.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Thread.h new file mode 100644 index 0000000..b1ec085 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Thread.h @@ -0,0 +1,244 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * @brief + */ + +#ifndef ZYCORE_API_THREAD_H +#define ZYCORE_API_THREAD_H + +#ifndef ZYAN_NO_LIBC + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +#if defined(ZYAN_POSIX) + +#include + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZyanThread` data-type. + */ +typedef pthread_t ZyanThread; + +/** + * Defines the `ZyanThreadId` data-type. + */ +typedef ZyanU64 ZyanThreadId; + +/* ---------------------------------------------------------------------------------------------- */ +/* Thread Local Storage (TLS) */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZyanThreadTlsIndex` data-type. + */ +typedef pthread_key_t ZyanThreadTlsIndex; + +/** + * Defines the `ZyanThreadTlsCallback` function prototype. + */ +typedef void(*ZyanThreadTlsCallback)(void* data); + +/** + * Declares a Thread Local Storage (TLS) callback function. + * + * @param name The callback function name. + * @param param_type The callback data parameter type. + * @param param_name The callback data parameter name. + */ +#define ZYAN_THREAD_DECLARE_TLS_CALLBACK(name, param_type, param_name) \ + void name(param_type* param_name) + +/* ---------------------------------------------------------------------------------------------- */ + +#elif defined(ZYAN_WINDOWS) + +#include + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZyanThread` data-type. + */ +typedef HANDLE ZyanThread; + +/** + * Defines the `ZyanThreadId` data-type. + */ +typedef DWORD ZyanThreadId; + +/* ---------------------------------------------------------------------------------------------- */ +/* Thread Local Storage (TLS) */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZyanThreadTlsIndex` data-type. + */ +typedef DWORD ZyanThreadTlsIndex; + +/** + * Defines the `ZyanThreadTlsCallback` function prototype. + */ +typedef PFLS_CALLBACK_FUNCTION ZyanThreadTlsCallback; + +/** + * Declares a Thread Local Storage (TLS) callback function. + * + * @param name The callback function name. + * @param param_type The callback data parameter type. + * @param param_name The callback data parameter name. + */ +#define ZYAN_THREAD_DECLARE_TLS_CALLBACK(name, param_type, param_name) \ + VOID NTAPI name(param_type* param_name) + +/* ---------------------------------------------------------------------------------------------- */ + +#else +# error "Unsupported platform detected" +#endif + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the handle of the current thread. + * + * @param thread Receives the handle of the current thread. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanThreadGetCurrentThread(ZyanThread* thread); + +/** + * Returns the unique id of the current thread. + * + * @param thread_id Receives the unique id of the current thread. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanThreadGetCurrentThreadId(ZyanThreadId* thread_id); + +/* ---------------------------------------------------------------------------------------------- */ +/* Thread Local Storage (TLS) */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Allocates a new Thread Local Storage (TLS) slot. + * + * @param index Receives the TLS slot index. + * @param destructor A pointer to a destructor callback which is invoked to finalize the data + * in the TLS slot or `ZYAN_NULL`, if not needed. + * + * The maximum available number of TLS slots is implementation specific and different on each + * platform: + * - Windows + * - A total amount of 128 slots per process are guaranteed + * - POSIX + * - A total amount of 128 slots per process are guaranteed + * - Some systems guarantee larger amounts like e.g. 1024 slots per process + * + * Note that the invocation rules for the destructor callback are implementation specific and + * different on each platform: + * - Windows + * - The callback is invoked when a thread exits + * - The callback is invoked when the process exits + * - The callback is invoked when the TLS slot is released + * - POSIX + * - The callback is invoked when a thread exits and the stored value is not null + * - The callback is NOT invoked when the process exits + * - The callback is NOT invoked when the TLS slot is released + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanThreadTlsAlloc(ZyanThreadTlsIndex* index, + ZyanThreadTlsCallback destructor); + +/** + * Releases a Thread Local Storage (TLS) slot. + * + * @param index The TLS slot index. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanThreadTlsFree(ZyanThreadTlsIndex index); + +/** + * Returns the value inside the given Thread Local Storage (TLS) slot for the + * calling thread. + * + * @param index The TLS slot index. + * @param data Receives the value inside the given Thread Local Storage + * (TLS) slot for the calling thread. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanThreadTlsGetValue(ZyanThreadTlsIndex index, void** data); + +/** + * Set the value of the given Thread Local Storage (TLS) slot for the calling thread. + * + * @param index The TLS slot index. + * @param data The value to store inside the given Thread Local Storage (TLS) slot for the + * calling thread + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanThreadTlsSetValue(ZyanThreadTlsIndex index, void* data); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYAN_NO_LIBC */ + +#endif /* ZYCORE_API_THREAD_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Allocator.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Allocator.h new file mode 100644 index 0000000..6435171 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Allocator.h @@ -0,0 +1,143 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * @brief + */ + +#ifndef ZYCORE_ALLOCATOR_H +#define ZYCORE_ALLOCATOR_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +struct ZyanAllocator_; + +/** + * Defines the `ZyanAllocatorAllocate` function prototype. + * + * @param allocator A pointer to the `ZyanAllocator` instance. + * @param p Receives a pointer to the first memory block sufficient to hold an + * array of `n` elements with a size of `element_size`. + * @param element_size The size of a single element. + * @param n The number of elements to allocate storage for. + * + * @return A zyan status code. + * + * This prototype is used for the `allocate()` and `reallocate()` functions. + * + * The result of the `reallocate()` function is undefined, if `p` does not point to a memory block + * previously obtained by `(re-)allocate()`. + */ +typedef ZyanStatus (*ZyanAllocatorAllocate)(struct ZyanAllocator_* allocator, void** p, + ZyanUSize element_size, ZyanUSize n); + +/** + * Defines the `ZyanAllocatorDeallocate` function prototype. + * + * @param allocator A pointer to the `ZyanAllocator` instance. + * @param p The pointer obtained from `(re-)allocate()`. + * @param element_size The size of a single element. + * @param n The number of elements earlier passed to `(re-)allocate()`. + * + * @return A zyan status code. + */ +typedef ZyanStatus (*ZyanAllocatorDeallocate)(struct ZyanAllocator_* allocator, void* p, + ZyanUSize element_size, ZyanUSize n); + +/** + * Defines the `ZyanAllocator` struct. + * + * This is the base class for all custom allocator implementations. + * + * All fields in this struct should be considered as "private". Any changes may lead to unexpected + * behavior. + */ +typedef struct ZyanAllocator_ +{ + /** + * The allocate function. + */ + ZyanAllocatorAllocate allocate; + /** + * The reallocate function. + */ + ZyanAllocatorAllocate reallocate; + /** + * The deallocate function. + */ + ZyanAllocatorDeallocate deallocate; +} ZyanAllocator; + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/** + * Initializes the given `ZyanAllocator` instance. + * + * @param allocator A pointer to the `ZyanAllocator` instance. + * @param allocate The allocate function. + * @param reallocate The reallocate function. + * @param deallocate The deallocate function. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanAllocatorInit(ZyanAllocator* allocator, ZyanAllocatorAllocate allocate, + ZyanAllocatorAllocate reallocate, ZyanAllocatorDeallocate deallocate); + +#ifndef ZYAN_NO_LIBC + +/** + * Returns the default `ZyanAllocator` instance. + * + * @return A pointer to the default `ZyanAllocator` instance. + * + * The default allocator uses the default memory manager to allocate memory on the heap. + * + * You should in no case modify the returned allocator instance to avoid unexpected behavior. + */ +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanAllocator* ZyanAllocatorDefault(void); + +#endif // ZYAN_NO_LIBC + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_ALLOCATOR_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/ArgParse.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/ArgParse.h new file mode 100644 index 0000000..5d389cb --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/ArgParse.h @@ -0,0 +1,173 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Joel Hoener + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Implements command-line argument parsing. + */ + +#ifndef ZYCORE_ARGPARSE_H +#define ZYCORE_ARGPARSE_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Structs and other types */ +/* ============================================================================================== */ + +/** + * Definition of a single argument. + */ +typedef struct ZyanArgParseDefinition_ +{ + /** + * The argument name, e.g. `--help`. + * + * Must start with either one or two dashes. Single dash arguments must consist of a single + * character, (e.g. `-n`), double-dash arguments can be of arbitrary length. + */ + const char* name; + /** + * Whether the argument is boolean or expects a value. + */ + ZyanBool boolean; + /** + * Whether this argument is required (error if missing). + */ + ZyanBool required; +} ZyanArgParseDefinition; + +/** + * Configuration for argument parsing. + */ +typedef struct ZyanArgParseConfig_ +{ + /** + * `argv` argument passed to `main` by LibC. + */ + const char** argv; + /** + * `argc` argument passed to `main` by LibC. + */ + ZyanUSize argc; + /** + * Minimum # of accepted unnamed / anonymous arguments. + */ + ZyanUSize min_unnamed_args; + /** + * Maximum # of accepted unnamed / anonymous arguments. + */ + ZyanUSize max_unnamed_args; + /** + * Argument definition array, or `ZYAN_NULL`. + * + * Expects a pointer to an array of `ZyanArgParseDefinition` instances. The array is + * terminated by setting the `.name` field of the last element to `ZYAN_NULL`. If no named + * arguments should be parsed, you can also set this to `ZYAN_NULL`. + */ + ZyanArgParseDefinition* args; +} ZyanArgParseConfig; + +/** + * Information about a parsed argument. + */ +typedef struct ZyanArgParseArg_ +{ + /** + * Corresponding argument definition, or `ZYAN_NULL` for unnamed args. + * + * This pointer is borrowed from the `cfg` pointer passed to `ZyanArgParse`. + */ + const ZyanArgParseDefinition* def; + /** + * Whether the argument has a value (is non-boolean). + */ + ZyanBool has_value; + /** + * If `has_value == true`, then the argument value. + * + * This is a view into the `argv` string array passed to `ZyanArgParse` via the `cfg` argument. + */ + ZyanStringView value; +} ZyanArgParseArg; + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +#ifndef ZYAN_NO_LIBC + +/** + * Parse arguments according to a `ZyanArgParseConfig` definition. + * + * @param cfg Argument parser config to use. + * @param parsed Receives the parsed output. Vector of `ZyanArgParseArg`. Ownership is + * transferred to the user. Input is expected to be uninitialized. On error, + * the vector remains uninitialized. + * @param error_token On error, if it makes sense, receives the argument fragment causing the + * error. Optional, may be `ZYAN_NULL`. The pointer borrows into the `cfg` + * struct and doesn't have to be freed by the user. + * + * @return A `ZyanStatus` status determining whether the parsing succeeded. + */ +ZYCORE_EXPORT ZyanStatus ZyanArgParse(const ZyanArgParseConfig *cfg, ZyanVector* parsed, + const char** error_token); + +#endif + +/** + * Parse arguments according to a `ZyanArgParseConfig` definition. + * + * This version allows specification of a custom memory allocator and thus supports no-libc. + * + * @param cfg Argument parser config to use. + * @param parsed Receives the parsed output. Vector of `ZyanArgParseArg`. Ownership is + * transferred to the user. Input is expected to be uninitialized. On error, + * the vector remains uninitialized. + * @param error_token On error, if it makes sense, receives the argument fragment causing the + * error. Optional, may be `ZYAN_NULL`. The pointer borrows into the `cfg` + * struct and doesn't have to be freed by the user. + * @param allocator The `ZyanAllocator` to be used for allocating the output vector's data. + * + * @return A `ZyanStatus` status determining whether the parsing succeeded. + */ +ZYCORE_EXPORT ZyanStatus ZyanArgParseEx(const ZyanArgParseConfig *cfg, ZyanVector* parsed, + const char** error_token, ZyanAllocator* allocator); + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_ARGPARSE_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Bitset.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Bitset.h new file mode 100644 index 0000000..8c7eb1f --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Bitset.h @@ -0,0 +1,484 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Implements the bitset class. + */ + +#ifndef ZYCORE_BITSET_H +#define ZYCORE_BITSET_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/** + * Defines the `ZyanVector` struct. + * + * All fields in this struct should be considered as "private". Any changes may lead to unexpected + * behavior. + */ +typedef struct ZyanBitset_ +{ + /** + * The bitset size. + */ + ZyanUSize size; + /** + * The bitset data. + */ + ZyanVector bits; +} ZyanBitset; + +/** + * Defines the `ZyanBitsetByteOperation` function prototype. + * + * @param v1 A pointer to the first byte. This value receives the result after performing the + * desired operation. + * @param v2 A pointer to the second byte. + * + * @return A zyan status code. + * + * This function is used to perform byte-wise operations on two `ZyanBitset` instances. + */ +typedef ZyanStatus (*ZyanBitsetByteOperation)(ZyanU8* v1, const ZyanU8* v2); + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Constructor and destructor */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +/** + * Initializes the given `ZyanBitset` instance. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param count The initial amount of bits. + * + * @return A zyan status code. + * + * The space for the bitset is dynamically allocated by the default allocator using the default + * growth factor of `2.0f` and the default shrink threshold of `0.5f`. + */ +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanBitsetInit(ZyanBitset* bitset, ZyanUSize count); + +#endif // ZYAN_NO_LIBC + +/** + * Initializes the given `ZyanBitset` instance and sets a custom `allocator` and memory + * allocation/deallocation parameters. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param count The initial amount of bits. + * @param allocator A pointer to a `ZyanAllocator` instance. + * @param growth_factor The growth factor (from `1.0f` to `x.xf`). + * @param shrink_threshold The shrink threshold (from `0.0f` to `1.0f`). + * + * @return A zyan status code. + * + * A growth factor of `1.0f` disables overallocation and a shrink threshold of `0.0f` disables + * dynamic shrinking. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetInitEx(ZyanBitset* bitset, ZyanUSize count, + ZyanAllocator* allocator, float growth_factor, float shrink_threshold); + +/** + * Initializes the given `ZyanBitset` instance and configures it to use a custom user + * defined buffer with a fixed size. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param count The initial amount of bits. + * @param buffer A pointer to the buffer that is used as storage for the bits. + * @param capacity The maximum capacity (number of bytes) of the buffer. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetInitBuffer(ZyanBitset* bitset, ZyanUSize count, void* buffer, + ZyanUSize capacity); + +/** + * Destroys the given `ZyanBitset` instance. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetDestroy(ZyanBitset* bitset); + +/* ---------------------------------------------------------------------------------------------- */ +/* Logical operations */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Performs a byte-wise `operation` for every byte in the given `ZyanBitset` instances. + * + * @param destination A pointer to the `ZyanBitset` instance that is used as the first input and + * as the destination. + * @param source A pointer to the `ZyanBitset` instance that is used as the second input. + * @param operation A pointer to the function that performs the desired operation. + * + * @return A zyan status code. + * + * The `operation` callback is invoked once for every byte in the smallest of the `ZyanBitset` + * instances. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetPerformByteOperation(ZyanBitset* destination, + const ZyanBitset* source, ZyanBitsetByteOperation operation); + +/** + * Performs a logical `AND` operation on the given `ZyanBitset` instances. + * + * @param destination A pointer to the `ZyanBitset` instance that is used as the first input and + * as the destination. + * @param source A pointer to the `ZyanBitset` instance that is used as the second input. + * + * @return A zyan status code. + * + * If the destination bitmask contains more bits than the source one, the state of the remaining + * bits will be undefined. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetAND(ZyanBitset* destination, const ZyanBitset* source); + +/** + * Performs a logical `OR` operation on the given `ZyanBitset` instances. + * + * @param destination A pointer to the `ZyanBitset` instance that is used as the first input and + * as the destination. + * @param source A pointer to the `ZyanBitset` instance that is used as the second input. + * + * @return A zyan status code. + * + * If the destination bitmask contains more bits than the source one, the state of the remaining + * bits will be undefined. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetOR (ZyanBitset* destination, const ZyanBitset* source); + +/** + * Performs a logical `XOR` operation on the given `ZyanBitset` instances. + * + * @param destination A pointer to the `ZyanBitset` instance that is used as the first input and + * as the destination. + * @param source A pointer to the `ZyanBitset` instance that is used as the second input. + * + * @return A zyan status code. + * + * If the destination bitmask contains more bits than the source one, the state of the remaining + * bits will be undefined. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetXOR(ZyanBitset* destination, const ZyanBitset* source); + +/** + * Flips all bits of the given `ZyanBitset` instance. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetFlip(ZyanBitset* bitset); + +/* ---------------------------------------------------------------------------------------------- */ +/* Bit access */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Sets the bit at `index` of the given `ZyanBitset` instance to `1`. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param index The bit index. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetSet(ZyanBitset* bitset, ZyanUSize index); + +/** + * Sets the bit at `index` of the given `ZyanBitset` instance to `0`. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param index The bit index. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetReset(ZyanBitset* bitset, ZyanUSize index); + +/** + * Sets the bit at `index` of the given `ZyanBitset` instance to the specified `value`. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param index The bit index. + * @param value The new value. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetAssign(ZyanBitset* bitset, ZyanUSize index, ZyanBool value); + +/** + * Toggles the bit at `index` of the given `ZyanBitset` instance. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param index The bit index. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetToggle(ZyanBitset* bitset, ZyanUSize index); + +/** + * Returns the value of the bit at `index`. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param index The bit index. + * + * @return `ZYAN_STATUS_TRUE`, if the bit is set or `ZYAN_STATUS_FALSE`, if not, Another zyan + * status code, if an error occured. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetTest(ZyanBitset* bitset, ZyanUSize index); + +/** + * Returns the value of the most significant bit. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return `ZYAN_STATUS_TRUE`, if the bit is set or `ZYAN_STATUS_FALSE`, if not. Another zyan + * status code, if an error occured. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetTestMSB(ZyanBitset* bitset); + +/** + * Returns the value of the least significant bit. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return `ZYAN_STATUS_TRUE`, if the bit is set or `ZYAN_STATUS_FALSE`, if not. Another zyan + * status code, if an error occured. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetTestLSB(ZyanBitset* bitset); + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Sets all bits of the given `ZyanBitset` instance to `1`. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetSetAll(ZyanBitset* bitset); + +/** + * Sets all bits of the given `ZyanBitset` instance to `0`. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetResetAll(ZyanBitset* bitset); + +/* ---------------------------------------------------------------------------------------------- */ +/* Size management */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Adds a new bit at the end of the bitset. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param value The value of the new bit. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetPush(ZyanBitset* bitset, ZyanBool value); + +/** + * Removes the last bit of the bitset. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetPop(ZyanBitset* bitset); + +/** + * Deletes all bits of the given `ZyanBitset` instance. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetClear(ZyanBitset* bitset); + +/* ---------------------------------------------------------------------------------------------- */ +/* Memory management */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Changes the capacity of the given `ZyanBitset` instance. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param count The new capacity (number of bits). + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetReserve(ZyanBitset* bitset, ZyanUSize count); + +/** + * Shrinks the capacity of the given bitset to match it's size. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetShrinkToFit(ZyanBitset* bitset); + +/* ---------------------------------------------------------------------------------------------- */ +/* Information */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the current size of the bitset in bits. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param size Receives the size of the bitset in bits. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetGetSize(const ZyanBitset* bitset, ZyanUSize* size); + +/** + * Returns the current capacity of the bitset in bits. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param capacity Receives the size of the bitset in bits. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetGetCapacity(const ZyanBitset* bitset, ZyanUSize* capacity); + +/** + * Returns the current size of the bitset in bytes. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param size Receives the size of the bitset in bytes. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetGetSizeBytes(const ZyanBitset* bitset, ZyanUSize* size); + +/** + * Returns the current capacity of the bitset in bytes. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param capacity Receives the size of the bitset in bytes. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetGetCapacityBytes(const ZyanBitset* bitset, ZyanUSize* capacity); + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the amount of bits set in the given bitset. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param count Receives the amount of bits set in the given bitset. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetCount(const ZyanBitset* bitset, ZyanUSize* count); + +/** + * Checks, if all bits of the given bitset are set. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return `ZYAN_STATUS_TRUE`, if all bits are set, `ZYAN_STATUS_FALSE`, if not. Another zyan + * status code, if an error occured. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetAll(const ZyanBitset* bitset); + +/** + * Checks, if at least one bit of the given bitset is set. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return `ZYAN_STATUS_TRUE`, if at least one bit is set, `ZYAN_STATUS_FALSE`, if not. Another + * zyan status code, if an error occured. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetAny(const ZyanBitset* bitset); + +/** + * Checks, if none bits of the given bitset are set. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return `ZYAN_STATUS_TRUE`, if none bits are set, `ZYAN_STATUS_FALSE`, if not. Another zyan + * status code, if an error occured. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetNone(const ZyanBitset* bitset); + +///* ---------------------------------------------------------------------------------------------- */ +// +///** +// * Returns a 32-bit unsigned integer representation of the data. +// * +// * @param bitset A pointer to the `ZyanBitset` instance. +// * @param value Receives the 32-bit unsigned integer representation of the data. +// * +// * @return A zyan status code. +// */ +//ZYCORE_EXPORT ZyanStatus ZyanBitsetToU32(const ZyanBitset* bitset, ZyanU32* value); +// +///** +// * Returns a 64-bit unsigned integer representation of the data. +// * +// * @param bitset A pointer to the `ZyanBitset` instance. +// * @param value Receives the 64-bit unsigned integer representation of the data. +// * +// * @return A zyan status code. +// */ +//ZYCORE_EXPORT ZyanStatus ZyanBitsetToU64(const ZyanBitset* bitset, ZyanU64* value); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_BITSET_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Comparison.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Comparison.h new file mode 100644 index 0000000..6d8b518 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Comparison.h @@ -0,0 +1,316 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Defines prototypes of general-purpose comparison functions. + */ + +#ifndef ZYCORE_COMPARISON_H +#define ZYCORE_COMPARISON_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/** + * Defines the `ZyanEqualityComparison` function prototype. + * + * @param left A pointer to the first element. + * @param right A pointer to the second element. + * + * @return This function should return `ZYAN_TRUE` if the `left` element equals the `right` one + * or `ZYAN_FALSE`, if not. + */ +typedef ZyanBool (*ZyanEqualityComparison)(const void* left, const void* right); + +/** + * Defines the `ZyanComparison` function prototype. + * + * @param left A pointer to the first element. + * @param right A pointer to the second element. + * + * @return This function should return values in the following range: + * `left == right -> result == 0` + * `left < right -> result < 0` + * `left > right -> result > 0` + */ +typedef ZyanI32 (*ZyanComparison)(const void* left, const void* right); + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Equality comparison functions */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Declares a generic equality comparison function for an integral data-type. + * + * @param name The name of the function. + * @param type The name of the integral data-type. + */ +#define ZYAN_DECLARE_EQUALITY_COMPARISON(name, type) \ + ZyanBool name(const type* left, const type* right) \ + { \ + ZYAN_ASSERT(left); \ + ZYAN_ASSERT(right); \ + \ + return (*left == *right) ? ZYAN_TRUE : ZYAN_FALSE; \ + } + +/** + * Declares a generic equality comparison function that compares a single integral + * data-type field of a struct. + * + * @param name The name of the function. + * @param type The name of the integral data-type. + * @param field_name The name of the struct field. + */ +#define ZYAN_DECLARE_EQUALITY_COMPARISON_FOR_FIELD(name, type, field_name) \ + ZyanBool name(const type* left, const type* right) \ + { \ + ZYAN_ASSERT(left); \ + ZYAN_ASSERT(right); \ + \ + return (left->field_name == right->field_name) ? ZYAN_TRUE : ZYAN_FALSE; \ + } + +/* ---------------------------------------------------------------------------------------------- */ +/* Comparison functions */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Declares a generic comparison function for an integral data-type. + * + * @param name The name of the function. + * @param type The name of the integral data-type. + */ +#define ZYAN_DECLARE_COMPARISON(name, type) \ + ZyanI32 name(const type* left, const type* right) \ + { \ + ZYAN_ASSERT(left); \ + ZYAN_ASSERT(right); \ + \ + if (*left < *right) \ + { \ + return -1; \ + } \ + if (*left > *right) \ + { \ + return 1; \ + } \ + return 0; \ + } + +/** + * Declares a generic comparison function that compares a single integral data-type field + * of a struct. + * + * @param name The name of the function. + * @param type The name of the integral data-type. + * @param field_name The name of the struct field. + */ +#define ZYAN_DECLARE_COMPARISON_FOR_FIELD(name, type, field_name) \ + ZyanI32 name(const type* left, const type* right) \ + { \ + ZYAN_ASSERT(left); \ + ZYAN_ASSERT(right); \ + \ + if (left->field_name < right->field_name) \ + { \ + return -1; \ + } \ + if (left->field_name > right->field_name) \ + { \ + return 1; \ + } \ + return 0; \ + } + + /* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Default equality comparison functions */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines a default equality comparison function for pointer values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if + * not. + */ +ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsPointer, void* const) + +/** + * Defines a default equality comparison function for `ZyanBool` values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if + * not. + */ +ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsBool, ZyanBool) + +/** + * Defines a default equality comparison function for 8-bit numeric values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if + * not. + */ +ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsNumeric8, ZyanU8) + +/** + * Defines a default equality comparison function for 16-bit numeric values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if + * not. + */ +ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsNumeric16, ZyanU16) + +/** + * Defines a default equality comparison function for 32-bit numeric values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if + * not. + */ +ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsNumeric32, ZyanU32) + +/** + * Defines a default equality comparison function for 64-bit numeric values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if + * not. + */ +ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsNumeric64, ZyanU64) + +/* ---------------------------------------------------------------------------------------------- */ +/* Default comparison functions */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines a default comparison function for pointer values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is + * less than the `right` one, or `1` if the `left` value is greater than the `right` one. + */ +ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanComparePointer, void* const) + +/** + * Defines a default comparison function for `ZyanBool` values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is + * less than the `right` one, or `1` if the `left` value is greater than the `right` one. + */ +ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareBool, ZyanBool) + +/** + * Defines a default comparison function for 8-bit numeric values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is + * less than the `right` one, or `1` if the `left` value is greater than the `right` one. + */ +ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareNumeric8, ZyanU8) + +/** + * Defines a default comparison function for 16-bit numeric values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is + * less than the `right` one, or `1` if the `left` value is greater than the `right` one. + */ +ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareNumeric16, ZyanU16) + +/** + * Defines a default comparison function for 32-bit numeric values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is + * less than the `right` one, or `1` if the `left` value is greater than the `right` one. + */ +ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareNumeric32, ZyanU32) + +/** + * Defines a default comparison function for 64-bit numeric values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is + * less than the `right` one, or `1` if the `left` value is greater than the `right` one. + */ +ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareNumeric64, ZyanU64) + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_COMPARISON_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Defines.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Defines.h new file mode 100644 index 0000000..65afbaa --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Defines.h @@ -0,0 +1,443 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd, Joel Hoener + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * General helper and platform detection macros. + */ + +#ifndef ZYCORE_DEFINES_H +#define ZYCORE_DEFINES_H + +/* ============================================================================================== */ +/* Meta macros */ +/* ============================================================================================== */ + +/** + * Concatenates two values using the stringify operator (`##`). + * + * @param x The first value. + * @param y The second value. + * + * @return The combined string of the given values. + */ +#define ZYAN_MACRO_CONCAT(x, y) x ## y + +/** + * Concatenates two values using the stringify operator (`##`) and expands the value to + * be used in another macro. + * + * @param x The first value. + * @param y The second value. + * + * @return The combined string of the given values. + */ +#define ZYAN_MACRO_CONCAT_EXPAND(x, y) ZYAN_MACRO_CONCAT(x, y) + +/* ============================================================================================== */ +/* Compiler detection */ +/* ============================================================================================== */ + +#if defined(__clang__) +# define ZYAN_CLANG +# define ZYAN_GNUC +#elif defined(__ICC) || defined(__INTEL_COMPILER) +# define ZYAN_ICC +#elif defined(__GNUC__) || defined(__GNUG__) +# define ZYAN_GCC +# define ZYAN_GNUC +#elif defined(_MSC_VER) +# define ZYAN_MSVC +#elif defined(__BORLANDC__) +# define ZYAN_BORLAND +#else +# define ZYAN_UNKNOWN_COMPILER +#endif + +/* ============================================================================================== */ +/* Platform detection */ +/* ============================================================================================== */ + +#if defined(_WIN32) +# define ZYAN_WINDOWS +#elif defined(__EMSCRIPTEN__) +# define ZYAN_EMSCRIPTEN +#elif defined(__APPLE__) +# define ZYAN_APPLE +# define ZYAN_POSIX +#elif defined(__linux) +# define ZYAN_LINUX +# define ZYAN_POSIX +#elif defined(__FreeBSD__) +# define ZYAN_FREEBSD +# define ZYAN_POSIX +#elif defined(sun) || defined(__sun) +# define ZYAN_SOLARIS +# define ZYAN_POSIX +#elif defined(__unix) +# define ZYAN_UNIX +# define ZYAN_POSIX +#elif defined(__posix) +# define ZYAN_POSIX +#else +# define ZYAN_UNKNOWN_PLATFORM +#endif + +/* ============================================================================================== */ +/* Kernel mode detection */ +/* ============================================================================================== */ + +#if (defined(ZYAN_WINDOWS) && defined(_KERNEL_MODE)) || \ + (defined(ZYAN_APPLE) && defined(KERNEL)) || \ + (defined(ZYAN_LINUX) && defined(__KERNEL__)) || \ + (defined(__FreeBSD_kernel__)) +# define ZYAN_KERNEL +#else +# define ZYAN_USER +#endif + +/* ============================================================================================== */ +/* Architecture detection */ +/* ============================================================================================== */ + +#if defined(_M_AMD64) || defined(__x86_64__) +# define ZYAN_X64 +#elif defined(_M_IX86) || defined(__i386__) +# define ZYAN_X86 +#elif defined(_M_ARM64) || defined(__aarch64__) +# define ZYAN_AARCH64 +#elif defined(_M_ARM) || defined(_M_ARMT) || defined(__arm__) || defined(__thumb__) +# define ZYAN_ARM +#elif defined(__EMSCRIPTEN__) + // Nothing to do, `ZYAN_EMSCRIPTEN` is both platform and arch macro for this one. +#else +# error "Unsupported architecture detected" +#endif + +/* ============================================================================================== */ +/* Debug/Release detection */ +/* ============================================================================================== */ + +#if defined(ZYAN_MSVC) || defined(ZYAN_BORLAND) +# ifdef _DEBUG +# define ZYAN_DEBUG +# else +# define ZYAN_RELEASE +# endif +#elif defined(ZYAN_GNUC) || defined(ZYAN_ICC) +# ifdef NDEBUG +# define ZYAN_RELEASE +# else +# define ZYAN_DEBUG +# endif +#else +# define ZYAN_RELEASE +#endif + +/* ============================================================================================== */ +/* Misc compatibility macros */ +/* ============================================================================================== */ + +#if defined(ZYAN_CLANG) +# define ZYAN_NO_SANITIZE(what) __attribute__((no_sanitize(what))) +#else +# define ZYAN_NO_SANITIZE(what) +#endif + +#if defined(ZYAN_MSVC) || defined(ZYAN_BORLAND) +# define ZYAN_INLINE __inline +#else +# define ZYAN_INLINE static inline +#endif + +/* ============================================================================================== */ +/* Debugging and optimization macros */ +/* ============================================================================================== */ + +/** + * Runtime debug assertion. + */ +#if defined(ZYAN_NO_LIBC) +# define ZYAN_ASSERT(condition) (void)(condition) +#elif defined(ZYAN_WINDOWS) && defined(ZYAN_KERNEL) +# include +# define ZYAN_ASSERT(condition) NT_ASSERT(condition) +#else +# include +# define ZYAN_ASSERT(condition) assert(condition) +#endif + +/** + * Compiler-time assertion. + */ +#if __STDC_VERSION__ >= 201112L && !defined(__cplusplus) +# define ZYAN_STATIC_ASSERT(x) _Static_assert(x, #x) +#elif (defined(__cplusplus) && __cplusplus >= 201103L) || \ + (defined(__cplusplus) && defined (_MSC_VER) && (_MSC_VER >= 1600)) || \ + (defined (_MSC_VER) && (_MSC_VER >= 1800)) +# define ZYAN_STATIC_ASSERT(x) static_assert(x, #x) +#else +# define ZYAN_STATIC_ASSERT(x) \ + typedef int ZYAN_MACRO_CONCAT_EXPAND(ZYAN_SASSERT_, __COUNTER__) [(x) ? 1 : -1] +#endif + +/** + * Marks the current code path as unreachable. + */ +#if defined(ZYAN_RELEASE) +# if defined(ZYAN_CLANG) // GCC eagerly evals && RHS, we have to use nested ifs. +# if __has_builtin(__builtin_unreachable) +# define ZYAN_UNREACHABLE __builtin_unreachable() +# else +# define ZYAN_UNREACHABLE for(;;) +# endif +# elif defined(ZYAN_GCC) && ((__GNUC__ == 4 && __GNUC_MINOR__ > 4) || __GNUC__ > 4) +# define ZYAN_UNREACHABLE __builtin_unreachable() +# elif defined(ZYAN_ICC) +# ifdef ZYAN_WINDOWS +# include // "missing return statement" workaround +# define ZYAN_UNREACHABLE __assume(0); (void)abort() +# else +# define ZYAN_UNREACHABLE __builtin_unreachable() +# endif +# elif defined(ZYAN_MSVC) +# define ZYAN_UNREACHABLE __assume(0) +# else +# define ZYAN_UNREACHABLE for(;;) +# endif +#elif defined(ZYAN_NO_LIBC) +# define ZYAN_UNREACHABLE for(;;) +#elif defined(ZYAN_WINDOWS) && defined(ZYAN_KERNEL) +# define ZYAN_UNREACHABLE { __fastfail(0); for(;;){} } +#else +# include +# define ZYAN_UNREACHABLE { assert(0); abort(); } +#endif + +/* ============================================================================================== */ +/* Utils */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* General purpose */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Marks the specified parameter as unused. + * + * @param x The name of the unused parameter. + */ +#define ZYAN_UNUSED(x) (void)(x) + +/** + * Intentional fallthrough. + */ +#if defined(ZYAN_GCC) && __GNUC__ >= 7 +# define ZYAN_FALLTHROUGH __attribute__((fallthrough)) +#else +# define ZYAN_FALLTHROUGH +#endif + +/** + * Declares a bitfield. + * + * @param x The size (in bits) of the bitfield. + */ +#define ZYAN_BITFIELD(x) : x + +/** + * Marks functions that require libc (cannot be used with `ZYAN_NO_LIBC`). + */ +#define ZYAN_REQUIRES_LIBC + +/** + * Decorator for `printf`-style functions. + * + * @param format_index The 1-based index of the format string parameter. + * @param first_to_check The 1-based index of the format arguments parameter. + */ +#if defined(__RESHARPER__) +# define ZYAN_PRINTF_ATTR(format_index, first_to_check) \ + [[gnu::format(printf, format_index, first_to_check)]] +#elif defined(ZYAN_GCC) +# define ZYAN_PRINTF_ATTR(format_index, first_to_check) \ + __attribute__((format(printf, format_index, first_to_check))) +#else +# define ZYAN_PRINTF_ATTR(format_index, first_to_check) +#endif + +/** + * Decorator for `wprintf`-style functions. + * + * @param format_index The 1-based index of the format string parameter. + * @param first_to_check The 1-based index of the format arguments parameter. + */ +#if defined(__RESHARPER__) +# define ZYAN_WPRINTF_ATTR(format_index, first_to_check) \ + [[rscpp::format(wprintf, format_index, first_to_check)]] +#else +# define ZYAN_WPRINTF_ATTR(format_index, first_to_check) +#endif + +/* ---------------------------------------------------------------------------------------------- */ +/* Arrays */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the length (number of elements) of an array. + * + * @param a The name of the array. + * + * @return The number of elements of the given array. + */ +#define ZYAN_ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0])) + +/* ---------------------------------------------------------------------------------------------- */ +/* Arithmetic */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the smaller value of `a` or `b`. + * + * @param a The first value. + * @param b The second value. + * + * @return The smaller value of `a` or `b`. + */ +#define ZYAN_MIN(a, b) (((a) < (b)) ? (a) : (b)) + +/** + * Returns the bigger value of `a` or `b`. + * + * @param a The first value. + * @param b The second value. + * + * @return The bigger value of `a` or `b`. + */ +#define ZYAN_MAX(a, b) (((a) > (b)) ? (a) : (b)) + +/** + * Returns the absolute value of `a`. + * + * @param a The value. + * + * @return The absolute value of `a`. + */ +#define ZYAN_ABS(a) (((a) < 0) ? -(a) : (a)) + +/** + * Checks, if the given value is a power of 2. + * + * @param x The value. + * + * @return `ZYAN_TRUE`, if the given value is a power of 2 or `ZYAN_FALSE`, if not. + * + * Note that this macro always returns `ZYAN_TRUE` for `x == 0`. + */ +#define ZYAN_IS_POWER_OF_2(x) (((x) & ((x) - 1)) == 0) + +/** + * Checks, if the given value is properly aligned. + * + * Note that this macro only works for powers of 2. + */ +#define ZYAN_IS_ALIGNED_TO(x, align) (((x) & ((align) - 1)) == 0) + +/** + * Aligns the value to the nearest given alignment boundary (by rounding it up). + * + * @param x The value. + * @param align The desired alignment. + * + * @return The aligned value. + * + * Note that this macro only works for powers of 2. + */ +#define ZYAN_ALIGN_UP(x, align) (((x) + (align) - 1) & ~((align) - 1)) + +/** + * Aligns the value to the nearest given alignment boundary (by rounding it down). + * + * @param x The value. + * @param align The desired alignment. + * + * @return The aligned value. + * + * Note that this macro only works for powers of 2. + */ +#define ZYAN_ALIGN_DOWN(x, align) (((x) - 1) & ~((align) - 1)) + +/* ---------------------------------------------------------------------------------------------- */ +/* Bit operations */ +/* ---------------------------------------------------------------------------------------------- */ + +/* + * Checks, if the bit at index `b` is required to present the ordinal value `n`. + * + * @param n The ordinal value. + * @param b The bit index. + * + * @return `ZYAN_TRUE`, if the bit at index `b` is required to present the ordinal value `n` or + * `ZYAN_FALSE`, if not. + * + * Note that this macro always returns `ZYAN_FALSE` for `n == 0`. + */ +#define ZYAN_NEEDS_BIT(n, b) (((unsigned long)(n) >> (b)) > 0) + +/* + * Returns the number of bits required to represent the ordinal value `n`. + * + * @param n The ordinal value. + * + * @return The number of bits required to represent the ordinal value `n`. + * + * Note that this macro returns `0` for `n == 0`. + */ +#define ZYAN_BITS_TO_REPRESENT(n) \ + ( \ + ZYAN_NEEDS_BIT(n, 0) + ZYAN_NEEDS_BIT(n, 1) + \ + ZYAN_NEEDS_BIT(n, 2) + ZYAN_NEEDS_BIT(n, 3) + \ + ZYAN_NEEDS_BIT(n, 4) + ZYAN_NEEDS_BIT(n, 5) + \ + ZYAN_NEEDS_BIT(n, 6) + ZYAN_NEEDS_BIT(n, 7) + \ + ZYAN_NEEDS_BIT(n, 8) + ZYAN_NEEDS_BIT(n, 9) + \ + ZYAN_NEEDS_BIT(n, 10) + ZYAN_NEEDS_BIT(n, 11) + \ + ZYAN_NEEDS_BIT(n, 12) + ZYAN_NEEDS_BIT(n, 13) + \ + ZYAN_NEEDS_BIT(n, 14) + ZYAN_NEEDS_BIT(n, 15) + \ + ZYAN_NEEDS_BIT(n, 16) + ZYAN_NEEDS_BIT(n, 17) + \ + ZYAN_NEEDS_BIT(n, 18) + ZYAN_NEEDS_BIT(n, 19) + \ + ZYAN_NEEDS_BIT(n, 20) + ZYAN_NEEDS_BIT(n, 21) + \ + ZYAN_NEEDS_BIT(n, 22) + ZYAN_NEEDS_BIT(n, 23) + \ + ZYAN_NEEDS_BIT(n, 24) + ZYAN_NEEDS_BIT(n, 25) + \ + ZYAN_NEEDS_BIT(n, 26) + ZYAN_NEEDS_BIT(n, 27) + \ + ZYAN_NEEDS_BIT(n, 28) + ZYAN_NEEDS_BIT(n, 29) + \ + ZYAN_NEEDS_BIT(n, 30) + ZYAN_NEEDS_BIT(n, 31) \ + ) + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#endif /* ZYCORE_DEFINES_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Format.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Format.h new file mode 100644 index 0000000..b0401e6 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Format.h @@ -0,0 +1,286 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Provides helper functions for performant number to string conversion. + */ + +#ifndef ZYCORE_FORMAT_H +#define ZYCORE_FORMAT_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Helpers */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Get the absolute value of a 64 bit int. + * + * @param x The value to process. + * @return The absolute, unsigned value. + * + * This gracefully deals with the special case of `x` being `INT_MAX`. + */ +ZYAN_INLINE ZyanU64 ZyanAbsI64(ZyanI64 x) +{ + // INT_MIN special case. Can't use the value directly because GCC thinks + // it's too big for an INT64 literal, however is perfectly happy to accept + // this expression. This is also hit INT64_MIN is defined in `stdint.h`. + if (x == (-0x7fffffffffffffff - 1)) + { + return 0x8000000000000000u; + } + + return (ZyanU64)(x < 0 ? -x : x); +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Insertion */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Inserts formatted text in the destination string at the given `index`. + * + * @param string The destination string. + * @param index The insert index. + * @param format The format string. + * @param ... The format arguments. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYAN_PRINTF_ATTR(3, 4) +ZYCORE_EXPORT ZyanStatus ZyanStringInsertFormat(ZyanString* string, ZyanUSize index, + const char* format, ...); + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Formats the given unsigned ordinal `value` to its decimal text-representation and + * inserts it to the `string`. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The insert index. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length`. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringInsertDecU(ZyanString* string, ZyanUSize index, ZyanU64 value, + ZyanU8 padding_length); + +/** + * Formats the given signed ordinal `value` to its decimal text-representation and + * inserts it to the `string`. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The insert index. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length`. + * @param force_sign Set `ZYAN_TRUE`, to force printing of the `+` sign for positive numbers. + * @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringInsertDecS(ZyanString* string, ZyanUSize index, ZyanI64 value, + ZyanU8 padding_length, ZyanBool force_sign, const ZyanString* prefix); + +/** + * Formats the given unsigned ordinal `value` to its hexadecimal text-representation and + * inserts it to the `string`. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The insert index. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length`. + * @param uppercase Set `ZYAN_TRUE` to use uppercase letters ('A'-'F') instead of lowercase + * ones ('a'-'f'). + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringInsertHexU(ZyanString* string, ZyanUSize index, ZyanU64 value, + ZyanU8 padding_length, ZyanBool uppercase); + +/** + * Formats the given signed ordinal `value` to its hexadecimal text-representation and + * inserts it to the `string`. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The insert index. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length`. + * @param uppercase Set `ZYAN_TRUE` to use uppercase letters ('A'-'F') instead of lowercase + * ones ('a'-'f'). + * @param force_sign Set `ZYAN_TRUE`, to force printing of the `+` sign for positive numbers. + * @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringInsertHexS(ZyanString* string, ZyanUSize index, ZyanI64 value, + ZyanU8 padding_length, ZyanBool uppercase, ZyanBool force_sign, const ZyanString* prefix); + +/* ---------------------------------------------------------------------------------------------- */ +/* Appending */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +/** + * Appends formatted text to the destination string. + * + * @param string The destination string. + * @param format The format string. + * @param ... The format arguments. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYAN_PRINTF_ATTR(2, 3) +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanStringAppendFormat( + ZyanString* string, const char* format, ...); + +#endif // ZYAN_NO_LIBC + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Formats the given unsigned ordinal `value` to its decimal text-representation and + * appends it to the `string`. + * + * @param string A pointer to the `ZyanString` instance. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length`. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringAppendDecU(ZyanString* string, ZyanU64 value, + ZyanU8 padding_length); + +/** + * Formats the given signed ordinal `value` to its decimal text-representation and + * appends it to the `string`. + * + * @param string A pointer to the `ZyanString` instance. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length`. + * @param force_sign Set `ZYAN_TRUE`, to force printing of the `+` sign for positive numbers. + * @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringAppendDecS(ZyanString* string, ZyanI64 value, + ZyanU8 padding_length, ZyanBool force_sign, const ZyanStringView* prefix); + +/** + * Formats the given unsigned ordinal `value` to its hexadecimal text-representation and + * appends it to the `string`. + * + * @param string A pointer to the `ZyanString` instance. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length`. + * @param uppercase Set `ZYAN_TRUE` to use uppercase letters ('A'-'F') instead of lowercase + * ones ('a'-'f'). + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringAppendHexU(ZyanString* string, ZyanU64 value, + ZyanU8 padding_length, ZyanBool uppercase); + +/** + * Formats the given signed ordinal `value` to its hexadecimal text-representation and + * appends it to the `string`. + * + * @param string A pointer to the `ZyanString` instance. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length`. + * @param uppercase Set `ZYAN_TRUE` to use uppercase letters ('A'-'F') instead of lowercase + * ones ('a'-'f'). + * @param force_sign Set `ZYAN_TRUE`, to force printing of the `+` sign for positive numbers. + * @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringAppendHexS(ZyanString* string, ZyanI64 value, + ZyanU8 padding_length, ZyanBool uppercase, ZyanBool force_sign, const ZyanStringView* prefix); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif // ZYCORE_FORMAT_H diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/LibC.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/LibC.h new file mode 100644 index 0000000..cb0b2f3 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/LibC.h @@ -0,0 +1,511 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd, Joel Hoener + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Provides a simple LibC abstraction and fallback routines. + */ + +#ifndef ZYCORE_LIBC_H +#define ZYCORE_LIBC_H + +#ifndef ZYAN_CUSTOM_LIBC + +// Include a custom LibC header and define `ZYAN_CUSTOM_LIBC` to provide your own LibC +// replacement functions + +#ifndef ZYAN_NO_LIBC + +/* ============================================================================================== */ +/* LibC is available */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* errno.h */ +/* ---------------------------------------------------------------------------------------------- */ + +#include + +#define ZYAN_ERRNO errno + +/* ---------------------------------------------------------------------------------------------- */ +/* stdarg.h */ +/* ---------------------------------------------------------------------------------------------- */ + +#include + +/** + * Defines the `ZyanVAList` datatype. + */ +typedef va_list ZyanVAList; + +#define ZYAN_VA_START va_start +#define ZYAN_VA_ARG va_arg +#define ZYAN_VA_END va_end +#define ZYAN_VA_COPY(dest, source) va_copy((dest), (source)) + +/* ---------------------------------------------------------------------------------------------- */ +/* stdio.h */ +/* ---------------------------------------------------------------------------------------------- */ + +#include + +#define ZYAN_FPUTS fputs +#define ZYAN_FPUTC fputc +#define ZYAN_FPRINTF fprintf +#define ZYAN_PRINTF printf +#define ZYAN_PUTC putc +#define ZYAN_PUTS puts +#define ZYAN_SCANF scanf +#define ZYAN_SSCANF sscanf +#define ZYAN_VSNPRINTF vsnprintf + +/** + * Defines the `ZyanFile` datatype. + */ +typedef FILE ZyanFile; + +#define ZYAN_STDIN stdin +#define ZYAN_STDOUT stdout +#define ZYAN_STDERR stderr + +/* ---------------------------------------------------------------------------------------------- */ +/* stdlib.h */ +/* ---------------------------------------------------------------------------------------------- */ + +#include +#define ZYAN_CALLOC calloc +#define ZYAN_FREE free +#define ZYAN_MALLOC malloc +#define ZYAN_REALLOC realloc + +/* ---------------------------------------------------------------------------------------------- */ +/* string.h */ +/* ---------------------------------------------------------------------------------------------- */ + +#include +#define ZYAN_MEMCHR memchr +#define ZYAN_MEMCMP memcmp +#define ZYAN_MEMCPY memcpy +#define ZYAN_MEMMOVE memmove +#define ZYAN_MEMSET memset +#define ZYAN_STRCAT strcat +#define ZYAN_STRCHR strchr +#define ZYAN_STRCMP strcmp +#define ZYAN_STRCOLL strcoll +#define ZYAN_STRCPY strcpy +#define ZYAN_STRCSPN strcspn +#define ZYAN_STRLEN strlen +#define ZYAN_STRNCAT strncat +#define ZYAN_STRNCMP strncmp +#define ZYAN_STRNCPY strncpy +#define ZYAN_STRPBRK strpbrk +#define ZYAN_STRRCHR strrchr +#define ZYAN_STRSPN strspn +#define ZYAN_STRSTR strstr +#define ZYAN_STRTOK strtok +#define ZYAN_STRXFRM strxfrm + +/* ---------------------------------------------------------------------------------------------- */ + +#else // if ZYAN_NO_LIBC + +/* ============================================================================================== */ +/* No LibC available, use our own functions */ +/* ============================================================================================== */ + +#include +#include + +/* + * These implementations are by no means optimized and will be outperformed by pretty much any + * libc implementation out there. We do not aim towards providing competetive implementations here, + * but towards providing a last resort fallback for environments without a working libc. + */ + +/* ---------------------------------------------------------------------------------------------- */ +/* stdarg.h */ +/* ---------------------------------------------------------------------------------------------- */ + +#if defined(ZYAN_MSVC) || defined(ZYAN_ICC) + +/** + * Defines the `ZyanVAList` datatype. + */ +typedef char* ZyanVAList; + +# define ZYAN_VA_START __crt_va_start +# define ZYAN_VA_ARG __crt_va_arg +# define ZYAN_VA_END __crt_va_end +# define ZYAN_VA_COPY(destination, source) ((destination) = (source)) + +#elif defined(ZYAN_GNUC) + +/** + * Defines the `ZyanVAList` datatype. + */ +typedef __builtin_va_list ZyanVAList; + +# define ZYAN_VA_START(v, l) __builtin_va_start(v, l) +# define ZYAN_VA_END(v) __builtin_va_end(v) +# define ZYAN_VA_ARG(v, l) __builtin_va_arg(v, l) +# define ZYAN_VA_COPY(d, s) __builtin_va_copy(d, s) + +#else +# error "Unsupported compiler for no-libc mode." +#endif + +/* ---------------------------------------------------------------------------------------------- */ +/* stdio.h */ +/* ---------------------------------------------------------------------------------------------- */ + +// ZYAN_INLINE int ZYAN_VSNPRINTF (char* const buffer, ZyanUSize const count, +// char const* const format, ZyanVAList args) +// { +// // We cant provide a fallback implementation for this function +// ZYAN_UNUSED(buffer); +// ZYAN_UNUSED(count); +// ZYAN_UNUSED(format); +// ZYAN_UNUSED(args); +// return ZYAN_NULL; +// } + +/* ---------------------------------------------------------------------------------------------- */ +/* stdlib.h */ +/* ---------------------------------------------------------------------------------------------- */ + +// ZYAN_INLINE void* ZYAN_CALLOC(ZyanUSize nitems, ZyanUSize size) +// { +// // We cant provide a fallback implementation for this function +// ZYAN_UNUSED(nitems); +// ZYAN_UNUSED(size); +// return ZYAN_NULL; +// } +// +// ZYAN_INLINE void ZYAN_FREE(void *p) +// { +// // We cant provide a fallback implementation for this function +// ZYAN_UNUSED(p); +// } +// +// ZYAN_INLINE void* ZYAN_MALLOC(ZyanUSize n) +// { +// // We cant provide a fallback implementation for this function +// ZYAN_UNUSED(n); +// return ZYAN_NULL; +// } +// +// ZYAN_INLINE void* ZYAN_REALLOC(void* p, ZyanUSize n) +// { +// // We cant provide a fallback implementation for this function +// ZYAN_UNUSED(p); +// ZYAN_UNUSED(n); +// return ZYAN_NULL; +// } + +/* ---------------------------------------------------------------------------------------------- */ +/* string.h */ +/* ---------------------------------------------------------------------------------------------- */ + +ZYAN_INLINE void* ZYAN_MEMCHR(const void* str, int c, ZyanUSize n) +{ + const ZyanU8* p = (ZyanU8*)str; + while (n--) + { + if (*p != (ZyanU8)c) + { + p++; + } else + { + return (void*)p; + } + } + return 0; +} + +ZYAN_INLINE int ZYAN_MEMCMP(const void* s1, const void* s2, ZyanUSize n) +{ + const ZyanU8* p1 = s1, *p2 = s2; + while (n--) + { + if (*p1 != *p2) + { + return *p1 - *p2; + } + p1++, p2++; + } + return 0; +} + +ZYAN_INLINE void* ZYAN_MEMCPY(void* dst, const void* src, ZyanUSize n) +{ + volatile ZyanU8* dp = dst; + const ZyanU8* sp = src; + while (n--) + { + *dp++ = *sp++; + } + return dst; +} + +ZYAN_INLINE void* ZYAN_MEMMOVE(void* dst, const void* src, ZyanUSize n) +{ + volatile ZyanU8* pd = dst; + const ZyanU8* ps = src; + if (ps < pd) + { + for (pd += n, ps += n; n--;) + { + *--pd = *--ps; + } + } else + { + while (n--) + { + *pd++ = *ps++; + } + } + return dst; +} + +ZYAN_INLINE void* ZYAN_MEMSET(void* dst, int val, ZyanUSize n) +{ + volatile ZyanU8* p = dst; + while (n--) + { + *p++ = (unsigned char)val; + } + return dst; +} + +ZYAN_INLINE char* ZYAN_STRCAT(char* dest, const char* src) +{ + char* ret = dest; + while (*dest) + { + dest++; + } + while ((*dest++ = *src++)); + return ret; +} + +ZYAN_INLINE char* ZYAN_STRCHR(const char* s, int c) +{ + while (*s != (char)c) + { + if (!*s++) + { + return 0; + } + } + return (char*)s; +} + +ZYAN_INLINE int ZYAN_STRCMP(const char* s1, const char* s2) +{ + while (*s1 && (*s1 == *s2)) + { + s1++, s2++; + } + return *(const ZyanU8*)s1 - *(const ZyanU8*)s2; +} + +ZYAN_INLINE int ZYAN_STRCOLL(const char *s1, const char *s2) +{ + // TODO: Implement + + ZYAN_UNUSED(s1); + ZYAN_UNUSED(s2); + + return 0; +} + +ZYAN_INLINE char* ZYAN_STRCPY(char* dest, const char* src) +{ + char* ret = dest; + while ((*dest++ = *src++)); + return ret; +} + +ZYAN_INLINE ZyanUSize ZYAN_STRCSPN(const char *s1, const char *s2) +{ + ZyanUSize ret = 0; + while (*s1) + { + if (ZYAN_STRCHR(s2, *s1)) + { + return ret; + } + s1++, ret++; + } + return ret; +} + +ZYAN_INLINE ZyanUSize ZYAN_STRLEN(const char* str) +{ + const char* p = str; + while (*str) + { + ++str; + } + return str - p; +} + +ZYAN_INLINE char* ZYAN_STRNCAT(char* dest, const char* src, ZyanUSize n) +{ + char* ret = dest; + while (*dest) + { + dest++; + } + while (n--) + { + if (!(*dest++ = *src++)) + { + return ret; + } + } + *dest = 0; + return ret; +} + +ZYAN_INLINE int ZYAN_STRNCMP(const char* s1, const char* s2, ZyanUSize n) +{ + while (n--) + { + if (*s1++ != *s2++) + { + return *(unsigned char*)(s1 - 1) - *(unsigned char*)(s2 - 1); + } + } + return 0; +} + +ZYAN_INLINE char* ZYAN_STRNCPY(char* dest, const char* src, ZyanUSize n) +{ + char* ret = dest; + do + { + if (!n--) + { + return ret; + } + } while ((*dest++ = *src++)); + while (n--) + { + *dest++ = 0; + } + return ret; +} + +ZYAN_INLINE char* ZYAN_STRPBRK(const char* s1, const char* s2) +{ + while (*s1) + { + if(ZYAN_STRCHR(s2, *s1++)) + { + return (char*)--s1; + } + } + return 0; +} + +ZYAN_INLINE char* ZYAN_STRRCHR(const char* s, int c) +{ + char* ret = 0; + do + { + if (*s == (char)c) + { + ret = (char*)s; + } + } while (*s++); + return ret; +} + +ZYAN_INLINE ZyanUSize ZYAN_STRSPN(const char* s1, const char* s2) +{ + ZyanUSize ret = 0; + while (*s1 && ZYAN_STRCHR(s2, *s1++)) + { + ret++; + } + return ret; +} + +ZYAN_INLINE char* ZYAN_STRSTR(const char* s1, const char* s2) +{ + const ZyanUSize n = ZYAN_STRLEN(s2); + while (*s1) + { + if (!ZYAN_MEMCMP(s1++, s2, n)) + { + return (char*)(s1 - 1); + } + } + return 0; +} + +ZYAN_INLINE char* ZYAN_STRTOK(char* str, const char* delim) +{ + static char* p = 0; + if (str) + { + p = str; + } else + if (!p) + { + return 0; + } + str = p + ZYAN_STRSPN(p, delim); + p = str + ZYAN_STRCSPN(str, delim); + if (p == str) + { + return p = 0; + } + p = *p ? *p = 0, p + 1 : 0; + return str; +} + +ZYAN_INLINE ZyanUSize ZYAN_STRXFRM(char* dest, const char* src, ZyanUSize n) +{ + const ZyanUSize n2 = ZYAN_STRLEN(src); + if (n > n2) + { + ZYAN_STRCPY(dest, src); + } + return n2; +} + +/* ---------------------------------------------------------------------------------------------- */ + +#endif + +#endif + +/* ============================================================================================== */ + +#endif /* ZYCORE_LIBC_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/List.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/List.h new file mode 100644 index 0000000..015a324 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/List.h @@ -0,0 +1,574 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Implements a doubly linked list. + */ + +#ifndef ZYCORE_LIST_H +#define ZYCORE_LIST_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/** + * Defines the `ZyanListNode` struct. + * + * All fields in this struct should be considered as "private". Any changes may lead to unexpected + * behavior. + */ +typedef struct ZyanListNode_ +{ + /** + * A pointer to the previous list node. + */ + struct ZyanListNode_* prev; + /** + * A pointer to the next list node. + */ + struct ZyanListNode_* next; +} ZyanListNode; + +/** + * Defines the `ZyanList` struct. + * + * All fields in this struct should be considered as "private". Any changes may lead to unexpected + * behavior. + */ +typedef struct ZyanList_ +{ + /** + * The memory allocator. + */ + ZyanAllocator* allocator; + /** + * The current number of elements in the list. + */ + ZyanUSize size; + /** + * The size of a single element in bytes. + */ + ZyanUSize element_size; + /** + * The element destructor callback. + */ + ZyanMemberProcedure destructor; + /** + * The head node. + */ + ZyanListNode* head; + /** + * The tail node. + */ + ZyanListNode* tail; + /** + * The data buffer. + * + * Only used for instances created by `ZyanListInitCustomBuffer`. + */ + void* buffer; + /** + * The data buffer capacity (number of bytes). + * + * Only used for instances created by `ZyanListInitCustomBuffer`. + */ + ZyanUSize capacity; + /** + * The first unused node. + * + * When removing a node, the first-unused value is updated to point at the removed node and the + * next node of the removed node will be updated to point at the old first-unused node. + * + * When appending the memory of the first unused-node is recycled to store the new node. The + * value of the first-unused node is then updated to point at the reused nodes next node. + * + * If the first-unused value is `ZYAN_NULL`, any new node will be "allocated" behind the tail + * node (if there is enough space left in the fixed size buffer). + * + * Only used for instances created by `ZyanListInitCustomBuffer`. + */ + ZyanListNode* first_unused; +} ZyanList; + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines an uninitialized `ZyanList` instance. + */ +#define ZYAN_LIST_INITIALIZER \ + { \ + /* allocator */ ZYAN_NULL, \ + /* size */ 0, \ + /* element_size */ 0, \ + /* head */ ZYAN_NULL, \ + /* destructor */ ZYAN_NULL, \ + /* tail */ ZYAN_NULL, \ + /* buffer */ ZYAN_NULL, \ + /* capacity */ 0, \ + /* first_unused */ ZYAN_NULL \ + } + +/* ---------------------------------------------------------------------------------------------- */ +/* Helper macros */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the data value of the given `node`. + * + * @param type The desired value type. + * @param node A pointer to the `ZyanListNode` struct. + * + * @result The data value of the given `node`. + * + * Note that this function is unsafe and might dereference a null-pointer. + */ +#ifdef __cplusplus +#define ZYAN_LIST_GET(type, node) \ + (*reinterpret_cast(ZyanListGetNodeData(node))) +#else +#define ZYAN_LIST_GET(type, node) \ + (*(const type*)ZyanListGetNodeData(node)) +#endif + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Constructor and destructor */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +/** + * Initializes the given `ZyanList` instance. + * + * @param list A pointer to the `ZyanList` instance. + * @param element_size The size of a single element in bytes. + * @param destructor A destructor callback that is invoked every time an item is deleted, or + * `ZYAN_NULL` if not needed. + * + * @return A zyan status code. + * + * The memory for the list elements is dynamically allocated by the default allocator. + * + * Finalization with `ZyanListDestroy` is required for all instances created by this function. + */ +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanListInit(ZyanList* list, ZyanUSize element_size, + ZyanMemberProcedure destructor); + +#endif // ZYAN_NO_LIBC + +/** + * Initializes the given `ZyanList` instance and sets a custom `allocator`. + * + * @param list A pointer to the `ZyanList` instance. + * @param element_size The size of a single element in bytes. + * @param destructor A destructor callback that is invoked every time an item is deleted, or + * `ZYAN_NULL` if not needed. + * @param allocator A pointer to a `ZyanAllocator` instance. + * + * @return A zyan status code. + * + * Finalization with `ZyanListDestroy` is required for all instances created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanListInitEx(ZyanList* list, ZyanUSize element_size, + ZyanMemberProcedure destructor, ZyanAllocator* allocator); + +/** + * Initializes the given `ZyanList` instance and configures it to use a custom user + * defined buffer with a fixed size. + * + * @param list A pointer to the `ZyanList` instance. + * @param element_size The size of a single element in bytes. + * @param destructor A destructor callback that is invoked every time an item is deleted, or + * `ZYAN_NULL` if not needed. + * @param buffer A pointer to the buffer that is used as storage for the elements. + * @param capacity The maximum capacity (number of bytes) of the buffer including the + * space required for the list-nodes. + * + * @return A zyan status code. + * + * The buffer capacity required to store `n` elements of type `T` is be calculated by: + * `size = n * sizeof(ZyanListNode) + n * sizeof(T)` + * + * Finalization is not required for instances created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanListInitCustomBuffer(ZyanList* list, ZyanUSize element_size, + ZyanMemberProcedure destructor, void* buffer, ZyanUSize capacity); + +/** + * Destroys the given `ZyanList` instance. + * + * @param list A pointer to the `ZyanList` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListDestroy(ZyanList* list); + +/* ---------------------------------------------------------------------------------------------- */ +/* Duplication */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +/** + * Initializes a new `ZyanList` instance by duplicating an existing list. + * + * @param destination A pointer to the (uninitialized) destination `ZyanList` instance. + * @param source A pointer to the source list. + * + * @return A zyan status code. + * + * The memory for the list is dynamically allocated by the default allocator. + * + * Finalization with `ZyanListDestroy` is required for all instances created by this function. + */ +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanListDuplicate(ZyanList* destination, + const ZyanList* source); + +#endif // ZYAN_NO_LIBC + +/** + * Initializes a new `ZyanList` instance by duplicating an existing list and sets a + * custom `allocator`. + * + * @param destination A pointer to the (uninitialized) destination `ZyanList` instance. + * @param source A pointer to the source list. + * @param allocator A pointer to a `ZyanAllocator` instance. + * + * @return A zyan status code. + + * Finalization with `ZyanListDestroy` is required for all instances created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanListDuplicateEx(ZyanList* destination, const ZyanList* source, + ZyanAllocator* allocator); + +/** + * Initializes a new `ZyanList` instance by duplicating an existing list and + * configures it to use a custom user defined buffer with a fixed size. + * + * @param destination A pointer to the (uninitialized) destination `ZyanList` instance. + * @param source A pointer to the source list. + * @param buffer A pointer to the buffer that is used as storage for the elements. + * @param capacity The maximum capacity (number of bytes) of the buffer including the + * space required for the list-nodes. + + * This function will fail, if the capacity of the buffer is not sufficient + * to store all elements of the source list. + * + * @return A zyan status code. + * + * The buffer capacity required to store `n` elements of type `T` is be calculated by: + * `size = n * sizeof(ZyanListNode) + n * sizeof(T)` + * + * Finalization is not required for instances created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanListDuplicateCustomBuffer(ZyanList* destination, + const ZyanList* source, void* buffer, ZyanUSize capacity); + +/* ---------------------------------------------------------------------------------------------- */ +/* Item access */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns a pointer to the first `ZyanListNode` struct of the given list. + * + * @param list A pointer to the `ZyanList` instance. + * @param node Receives a pointer to the first `ZyanListNode` struct of the list. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListGetHeadNode(const ZyanList* list, const ZyanListNode** node); + +/** + * Returns a pointer to the last `ZyanListNode` struct of the given list. + * + * @param list A pointer to the `ZyanList` instance. + * @param node Receives a pointer to the last `ZyanListNode` struct of the list. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListGetTailNode(const ZyanList* list, const ZyanListNode** node); + +/** + * Receives a pointer to the previous `ZyanListNode` struct linked to the passed one. + * + * @param node Receives a pointer to the previous `ZyanListNode` struct linked to the passed + * one. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListGetPrevNode(const ZyanListNode** node); + +/** + * Receives a pointer to the next `ZyanListNode` struct linked to the passed one. + * + * @param node Receives a pointer to the next `ZyanListNode` struct linked to the passed one. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListGetNextNode(const ZyanListNode** node); + +/** + * Returns a constant pointer to the data of the given `node`. + * + * @param node A pointer to the `ZyanListNode` struct. + * + * @return A constant pointer to the the data of the given `node` or `ZYAN_NULL`, if an error + * occured. + * + * Take a look at `ZyanListGetNodeDataEx`, if you need a function that returns a zyan status code. + */ +ZYCORE_EXPORT const void* ZyanListGetNodeData(const ZyanListNode* node); + +/** + * Returns a constant pointer to the data of the given `node`.. + * + * @param node A pointer to the `ZyanListNode` struct. + * @param value Receives a constant pointer to the data of the given `node`. + * + * Take a look at `ZyanListGetNodeData`, if you need a function that directly returns a pointer. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListGetNodeDataEx(const ZyanListNode* node, const void** value); + +/** + * Returns a mutable pointer to the data of the given `node`. + * + * @param node A pointer to the `ZyanListNode` struct. + * + * @return A mutable pointer to the the data of the given `node` or `ZYAN_NULL`, if an error + * occured. + * + * Take a look at `ZyanListGetPointerMutableEx` instead, if you need a function that returns a + * zyan status code. + */ +ZYCORE_EXPORT void* ZyanListGetNodeDataMutable(const ZyanListNode* node); + +/** + * Returns a mutable pointer to the data of the given `node`.. + * + * @param node A pointer to the `ZyanListNode` struct. + * @param value Receives a mutable pointer to the data of the given `node`. + * + * Take a look at `ZyanListGetNodeDataMutable`, if you need a function that directly returns a + * pointer. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListGetNodeDataMutableEx(const ZyanListNode* node, void** value); + +/** + * Assigns a new data value to the given `node`. + * + * @param list A pointer to the `ZyanList` instance. + * @param node A pointer to the `ZyanListNode` struct. + * @param value The value to assign. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListSetNodeData(const ZyanList* list, const ZyanListNode* node, + const void* value); + +/* ---------------------------------------------------------------------------------------------- */ +/* Insertion */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Adds a new `item` to the end of the list. + * + * @param list A pointer to the `ZyanList` instance. + * @param item A pointer to the item to add. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListPushBack(ZyanList* list, const void* item); + +/** + * Adds a new `item` to the beginning of the list. + * + * @param list A pointer to the `ZyanList` instance. + * @param item A pointer to the item to add. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListPushFront(ZyanList* list, const void* item); + +/** + * Constructs an `item` in-place at the end of the list. + * + * @param list A pointer to the `ZyanList` instance. + * @param item Receives a pointer to the new item. + * @param constructor The constructor callback or `ZYAN_NULL`. The new item will be in + * undefined state, if no constructor was passed. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListEmplaceBack(ZyanList* list, void** item, + ZyanMemberFunction constructor); + +/** + * Constructs an `item` in-place at the beginning of the list. + * + * @param list A pointer to the `ZyanList` instance. + * @param item Receives a pointer to the new item. + * @param constructor The constructor callback or `ZYAN_NULL`. The new item will be in + * undefined state, if no constructor was passed. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListEmplaceFront(ZyanList* list, void** item, + ZyanMemberFunction constructor); + +/* ---------------------------------------------------------------------------------------------- */ +/* Deletion */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Removes the last element of the list. + * + * @param list A pointer to the `ZyanList` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListPopBack(ZyanList* list); + +/** + * Removes the firstelement of the list. + * + * @param list A pointer to the `ZyanList` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListPopFront(ZyanList* list); + +/** + * Removes the given `node` from the list. + * + * @param list A pointer to the `ZyanList` instance. + * @param node A pointer to the `ZyanListNode` struct. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListRemove(ZyanList* list, const ZyanListNode* node); + +/** + * Removes multiple nodes from the list. + * + * @param list A pointer to the `ZyanList` instance. + * @param first A pointer to the first node. + * @param last A pointer to the last node. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListRemoveRange(ZyanList* list, const ZyanListNode* first, + const ZyanListNode* last); + +/** + * Erases all elements of the list. + * + * @param list A pointer to the `ZyanList` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListClear(ZyanList* list); + +/* ---------------------------------------------------------------------------------------------- */ +/* Searching */ +/* ---------------------------------------------------------------------------------------------- */ + +// TODO: + +/* ---------------------------------------------------------------------------------------------- */ +/* Memory management */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Resizes the given `ZyanList` instance. + * + * @param list A pointer to the `ZyanList` instance. + * @param size The new size of the list. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListResize(ZyanList* list, ZyanUSize size); + +/** + * Resizes the given `ZyanList` instance. + * + * @param list A pointer to the `ZyanList` instance. + * @param size The new size of the list. + * @param initializer A pointer to a value to be used as initializer for new items. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListResizeEx(ZyanList* list, ZyanUSize size, const void* initializer); + +/* ---------------------------------------------------------------------------------------------- */ +/* Information */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the current size of the list. + * + * @param list A pointer to the `ZyanList` instance. + * @param size Receives the size of the list. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListGetSize(const ZyanList* list, ZyanUSize* size); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_VECTOR_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Object.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Object.h new file mode 100644 index 0000000..d015cef --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Object.h @@ -0,0 +1,84 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Defines some generic object-related datatypes. + */ + +#ifndef ZYCORE_OBJECT_H +#define ZYCORE_OBJECT_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/** + * Defines the `ZyanMemberProcedure` function prototype. + * + * @param object A pointer to the object. + */ +typedef void (*ZyanMemberProcedure)(void* object); + +/** + * Defines the `ZyanConstMemberProcedure` function prototype. + * + * @param object A pointer to the object. + */ +typedef void (*ZyanConstMemberProcedure)(const void* object); + +/** + * Defines the `ZyanMemberFunction` function prototype. + * + * @param object A pointer to the object. + * + * @return A zyan status code. + */ +typedef ZyanStatus (*ZyanMemberFunction)(void* object); + +/** + * Defines the `ZyanConstMemberFunction` function prototype. + * + * @param object A pointer to the object. + * + * @return A zyan status code. + */ +typedef ZyanStatus (*ZyanConstMemberFunction)(const void* object); + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_OBJECT_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Status.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Status.h new file mode 100644 index 0000000..b0d7fdf --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Status.h @@ -0,0 +1,287 @@ +/*************************************************************************************************** + + Zyan Core Library (Zyan-C) + + Original Author : Florian Bernd, Joel Hoener + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Status code definitions and check macros. + */ + +#ifndef ZYCORE_STATUS_H +#define ZYCORE_STATUS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/** + * Defines the `ZyanStatus` data type. + */ +typedef ZyanU32 ZyanStatus; + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Definition */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines a zyan status code. + * + * @param error `1`, if the status code signals an error or `0`, if not. + * @param module The module id. + * @param code The actual code. + * + * @return The zyan status code. + */ +#define ZYAN_MAKE_STATUS(error, module, code) \ + (ZyanStatus)((((error) & 0x01u) << 31u) | (((module) & 0x7FFu) << 20u) | ((code) & 0xFFFFFu)) + +/* ---------------------------------------------------------------------------------------------- */ +/* Checks */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Checks if a zyan operation was successful. + * + * @param status The zyan status-code to check. + * + * @return `ZYAN_TRUE`, if the operation succeeded or `ZYAN_FALSE`, if not. + */ +#define ZYAN_SUCCESS(status) \ + (!((status) & 0x80000000u)) + +/** + * Checks if a zyan operation failed. + * + * @param status The zyan status-code to check. + * + * @return `ZYAN_TRUE`, if the operation failed or `ZYAN_FALSE`, if not. + */ +#define ZYAN_FAILED(status) \ + ((status) & 0x80000000u) + +/** + * Checks if a zyan operation was successful and returns with the status-code, if not. + * + * @param status The zyan status-code to check. + */ +#define ZYAN_CHECK(status) \ + do \ + { \ + const ZyanStatus status_047620348 = (status); \ + if (!ZYAN_SUCCESS(status_047620348)) \ + { \ + return status_047620348; \ + } \ + } while (0) + +/* ---------------------------------------------------------------------------------------------- */ +/* Information */ +/* ---------------------------------------------------------------------------------------------- */ + + /** + * Returns the module id of a zyan status-code. + * + * @param status The zyan status-code. + * + * @return The module id of the zyan status-code. + */ +#define ZYAN_STATUS_MODULE(status) \ + (((status) >> 20) & 0x7FFu) + + /** + * Returns the code of a zyan status-code. + * + * @param status The zyan status-code. + * + * @return The code of the zyan status-code. + */ +#define ZYAN_STATUS_CODE(status) \ + ((status) & 0xFFFFFu) + +/* ============================================================================================== */ +/* Status codes */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Module IDs */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * The zycore generic module id. + */ +#define ZYAN_MODULE_ZYCORE 0x001u + +/** + * The zycore arg-parse submodule id. + */ +#define ZYAN_MODULE_ARGPARSE 0x003u + +/** + * The base module id for user-defined status codes. + */ +#define ZYAN_MODULE_USER 0x3FFu + +/* ---------------------------------------------------------------------------------------------- */ +/* Status codes (general purpose) */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * The operation completed successfully. + */ +#define ZYAN_STATUS_SUCCESS \ + ZYAN_MAKE_STATUS(0u, ZYAN_MODULE_ZYCORE, 0x00u) + +/** + * The operation failed with an generic error. + */ +#define ZYAN_STATUS_FAILED \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x01u) + +/** + * The operation completed successfully and returned `ZYAN_TRUE`. + */ +#define ZYAN_STATUS_TRUE \ + ZYAN_MAKE_STATUS(0u, ZYAN_MODULE_ZYCORE, 0x02u) + +/** + * The operation completed successfully and returned `ZYAN_FALSE`. + */ +#define ZYAN_STATUS_FALSE \ + ZYAN_MAKE_STATUS(0u, ZYAN_MODULE_ZYCORE, 0x03u) + +/** + * An invalid argument was passed to a function. + */ +#define ZYAN_STATUS_INVALID_ARGUMENT \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x04u) + +/** + * An attempt was made to perform an invalid operation. + */ +#define ZYAN_STATUS_INVALID_OPERATION \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x05u) + +/** + * Insufficient privileges to perform the requested operation. + */ +#define ZYAN_STATUS_ACCESS_DENIED \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x06u) + +/** + * The requested entity was not found. + */ +#define ZYAN_STATUS_NOT_FOUND \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x07u) + +/** + * An index passed to a function was out of bounds. + */ +#define ZYAN_STATUS_OUT_OF_RANGE \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x08u) + +/** + * A buffer passed to a function was too small to complete the requested operation. + */ +#define ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x09u) + +/** + * Insufficient memory to perform the operation. + */ +#define ZYAN_STATUS_NOT_ENOUGH_MEMORY \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x0Au) + +/** + * An unknown error occurred during a system function call. + */ +#define ZYAN_STATUS_BAD_SYSTEMCALL \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x0Bu) + +/** + * The process ran out of resources while performing an operation. + */ +#define ZYAN_STATUS_OUT_OF_RESOURCES \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x0Cu) + +/** + * A dependency library was not found or does have an unexpected version number or + * feature-set. + */ +#define ZYAN_STATUS_MISSING_DEPENDENCY \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x0Du) + +/* ---------------------------------------------------------------------------------------------- */ +/* Status codes (arg parse) */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Argument was not expected. + */ +#define ZYAN_STATUS_ARG_NOT_UNDERSTOOD \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x00u) + +/** + * Too few arguments were provided. + */ +#define ZYAN_STATUS_TOO_FEW_ARGS \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x01u) + +/** + * Too many arguments were provided. + */ +#define ZYAN_STATUS_TOO_MANY_ARGS \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x02u) + +/** + * An argument that expected a value misses its value. + */ +#define ZYAN_STATUS_ARG_MISSES_VALUE \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x03u) + +/** +* A required argument is missing. +*/ +#define ZYAN_STATUS_REQUIRED_ARG_MISSING \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x04u) + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_STATUS_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/String.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/String.h new file mode 100644 index 0000000..c3157bc --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/String.h @@ -0,0 +1,1012 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Implements a string type. + */ + +#ifndef ZYCORE_STRING_H +#define ZYCORE_STRING_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Constants */ +/* ============================================================================================== */ + +/** + * The initial minimum capacity (number of characters) for all dynamically allocated + * string instances - not including the terminating '\0'-character. + */ +#define ZYAN_STRING_MIN_CAPACITY 32 + +/** + * The default growth factor for all string instances. + */ +#define ZYAN_STRING_DEFAULT_GROWTH_FACTOR 2.00f + +/** + * The default shrink threshold for all string instances. + */ +#define ZYAN_STRING_DEFAULT_SHRINK_THRESHOLD 0.25f + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* String flags */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZyanStringFlags` datatype. + */ +typedef ZyanU8 ZyanStringFlags; + +/** + * The string uses a custom user-defined buffer with a fixed capacity. + */ +#define ZYAN_STRING_HAS_FIXED_CAPACITY 0x01 // (1 << 0) + +/* ---------------------------------------------------------------------------------------------- */ +/* String */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZyanString` struct. + * + * The `ZyanString` type is implemented as a size-prefixed string - which allows for a lot of + * performance optimizations. + * Nevertheless null-termination is guaranteed at all times to provide maximum compatibility with + * default C-style strings (use `ZyanStringGetData` to access the C-style string). + * + * All fields in this struct should be considered as "private". Any changes may lead to unexpected + * behavior. + */ +typedef struct ZyanString_ +{ + /** + * String flags. + */ + ZyanStringFlags flags; + /** + * The vector that contains the actual string. + */ + ZyanVector vector; +} ZyanString; + +/* ---------------------------------------------------------------------------------------------- */ +/* View */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZyanStringView` struct. + * + * The `ZyanStringView` type provides a view inside a string (`ZyanString` instances, null- + * terminated C-style strings, or even not-null-terminated custom strings). A view is immutable + * by design and can't be directly converted to a C-style string. + * + * Views might become invalid (e.g. pointing to invalid memory), if the underlying string gets + * destroyed or resized. + * + * The `ZYAN_STRING_TO_VIEW` macro can be used to cast a `ZyanString` to a `ZyanStringView` pointer + * without any runtime overhead. + * Casting a view to a normal string is not supported and will lead to unexpected behavior (use + * `ZyanStringDuplicate` to create a deep-copy instead). + * + * All fields in this struct should be considered as "private". Any changes may lead to unexpected + * behavior. + */ +typedef struct ZyanStringView_ +{ + /** + * The string data. + * + * The view internally re-uses the normal string struct to allow casts without any runtime + * overhead. + */ + ZyanString string; +} ZyanStringView; + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines an uninitialized `ZyanString` instance. + */ +#define ZYAN_STRING_INITIALIZER \ + { \ + /* flags */ 0, \ + /* vector */ ZYAN_VECTOR_INITIALIZER \ + } + +/* ---------------------------------------------------------------------------------------------- */ +/* Helper macros */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Casts a `ZyanString` pointer to a constant `ZyanStringView` pointer. + */ +#define ZYAN_STRING_TO_VIEW(string) (const ZyanStringView*)(string) + +/** + * Defines a `ZyanStringView` struct that provides a view into a static C-style string. + * + * @param string The C-style string. + */ +#define ZYAN_DEFINE_STRING_VIEW(string) \ + { \ + /* string */ \ + { \ + /* flags */ 0, \ + /* vector */ \ + { \ + /* allocator */ ZYAN_NULL, \ + /* growth_factor */ 1.0f, \ + /* shrink_threshold */ 0.0f, \ + /* size */ sizeof(string), \ + /* capacity */ sizeof(string), \ + /* element_size */ sizeof(char), \ + /* destructor */ ZYAN_NULL, \ + /* data */ (char*)(string) \ + } \ + } \ + } + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Constructor and destructor */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +/** + * Initializes the given `ZyanString` instance. + * + * @param string A pointer to the `ZyanString` instance. + * @param capacity The initial capacity (number of characters). + * + * @return A zyan status code. + * + * The memory for the string is dynamically allocated by the default allocator using the default + * growth factor of `2.0f` and the default shrink threshold of `0.25f`. + * + * The allocated buffer will be at least one character larger than the given `capacity`, to reserve + * space for the terminating '\0'. + * + * Finalization with `ZyanStringDestroy` is required for all strings created by this function. + */ +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanStringInit(ZyanString* string, ZyanUSize capacity); + +#endif // ZYAN_NO_LIBC + +/** + * Initializes the given `ZyanString` instance and sets a custom `allocator` and memory + * allocation/deallocation parameters. + * + * @param string A pointer to the `ZyanString` instance. + * @param capacity The initial capacity (number of characters). + * @param allocator A pointer to a `ZyanAllocator` instance. + * @param growth_factor The growth factor (from `1.0f` to `x.xf`). + * @param shrink_threshold The shrink threshold (from `0.0f` to `1.0f`). + * + * @return A zyan status code. + * + * A growth factor of `1.0f` disables overallocation and a shrink threshold of `0.0f` disables + * dynamic shrinking. + * + * The allocated buffer will be at least one character larger than the given `capacity`, to reserve + * space for the terminating '\0'. + * + * Finalization with `ZyanStringDestroy` is required for all strings created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringInitEx(ZyanString* string, ZyanUSize capacity, + ZyanAllocator* allocator, float growth_factor, float shrink_threshold); + +/** + * Initializes the given `ZyanString` instance and configures it to use a custom user + * defined buffer with a fixed size. + * + * @param string A pointer to the `ZyanString` instance. + * @param buffer A pointer to the buffer that is used as storage for the string. + * @param capacity The maximum capacity (number of characters) of the buffer, including + * the terminating '\0'. + * + * @return A zyan status code. + * + * Finalization is not required for strings created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringInitCustomBuffer(ZyanString* string, char* buffer, + ZyanUSize capacity); + +/** + * Destroys the given `ZyanString` instance. + * + * @param string A pointer to the `ZyanString` instance. + * + * @return A zyan status code. + * + */ +ZYCORE_EXPORT ZyanStatus ZyanStringDestroy(ZyanString* string); + +/* ---------------------------------------------------------------------------------------------- */ +/* Duplication */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +/** + * Initializes a new `ZyanString` instance by duplicating an existing string. + * + * @param destination A pointer to the (uninitialized) destination `ZyanString` instance. + * @param source A pointer to the source string. + * @param capacity The initial capacity (number of characters). + * + * This value is automatically adjusted to the size of the source string, if + * a smaller value was passed. + * + * @return A zyan status code. + * + * The behavior of this function is undefined, if `source` is a view into the `destination` + * string or `destination` points to an already initialized `ZyanString` instance. + * + * The memory for the string is dynamically allocated by the default allocator using the default + * growth factor of `2.0f` and the default shrink threshold of `0.25f`. + * + * The allocated buffer will be at least one character larger than the given `capacity`, to reserve + * space for the terminating '\0'. + * + * Finalization with `ZyanStringDestroy` is required for all strings created by this function. + */ +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanStringDuplicate(ZyanString* destination, + const ZyanStringView* source, ZyanUSize capacity); + +#endif // ZYAN_NO_LIBC + +/** + * Initializes a new `ZyanString` instance by duplicating an existing string and sets a + * custom `allocator` and memory allocation/deallocation parameters. + * + * @param destination A pointer to the (uninitialized) destination `ZyanString` instance. + * @param source A pointer to the source string. + * @param capacity The initial capacity (number of characters). + + * This value is automatically adjusted to the size of the source + * string, if a smaller value was passed. + * @param allocator A pointer to a `ZyanAllocator` instance. + * @param growth_factor The growth factor (from `1.0f` to `x.xf`). + * @param shrink_threshold The shrink threshold (from `0.0f` to `1.0f`). + * + * @return A zyan status code. + * + * The behavior of this function is undefined, if `source` is a view into the `destination` + * string or `destination` points to an already initialized `ZyanString` instance. + * + * A growth factor of `1.0f` disables overallocation and a shrink threshold of `0.0f` disables + * dynamic shrinking. + * + * The allocated buffer will be at least one character larger than the given `capacity`, to reserve + * space for the terminating '\0'. + * + * Finalization with `ZyanStringDestroy` is required for all strings created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringDuplicateEx(ZyanString* destination, + const ZyanStringView* source, ZyanUSize capacity, ZyanAllocator* allocator, + float growth_factor, float shrink_threshold); + +/** + * Initializes a new `ZyanString` instance by duplicating an existing string and + * configures it to use a custom user defined buffer with a fixed size. + * + * @param destination A pointer to the (uninitialized) destination `ZyanString` instance. + * @param source A pointer to the source string. + * @param buffer A pointer to the buffer that is used as storage for the string. + * @param capacity The maximum capacity (number of characters) of the buffer, including the + * terminating '\0'. + + * This function will fail, if the capacity of the buffer is less or equal to + * the size of the source string. + * + * @return A zyan status code. + * + * The behavior of this function is undefined, if `source` is a view into the `destination` + * string or `destination` points to an already initialized `ZyanString` instance. + * + * Finalization is not required for strings created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringDuplicateCustomBuffer(ZyanString* destination, + const ZyanStringView* source, char* buffer, ZyanUSize capacity); + +/* ---------------------------------------------------------------------------------------------- */ +/* Concatenation */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +/** + * Initializes a new `ZyanString` instance by concatenating two existing strings. + * + * @param destination A pointer to the (uninitialized) destination `ZyanString` instance. + * + * This function will fail, if the destination `ZyanString` instance equals + * one of the source strings. + * @param s1 A pointer to the first source string. + * @param s2 A pointer to the second source string. + * @param capacity The initial capacity (number of characters). + + * This value is automatically adjusted to the combined size of the source + * strings, if a smaller value was passed. + * + * @return A zyan status code. + * + * The behavior of this function is undefined, if `s1` or `s2` are views into the `destination` + * string or `destination` points to an already initialized `ZyanString` instance. + * + * The memory for the string is dynamically allocated by the default allocator using the default + * growth factor of `2.0f` and the default shrink threshold of `0.25f`. + * + * The allocated buffer will be at least one character larger than the given `capacity`, to reserve + * space for the terminating '\0'. + * + * Finalization with `ZyanStringDestroy` is required for all strings created by this function. + */ +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanStringConcat(ZyanString* destination, + const ZyanStringView* s1, const ZyanStringView* s2, ZyanUSize capacity); + +#endif // ZYAN_NO_LIBC + +/** + * Initializes a new `ZyanString` instance by concatenating two existing strings and sets + * a custom `allocator` and memory allocation/deallocation parameters. + * + * @param destination A pointer to the (uninitialized) destination `ZyanString` instance. + * + * This function will fail, if the destination `ZyanString` instance + * equals one of the source strings. + * @param s1 A pointer to the first source string. + * @param s2 A pointer to the second source string. + * @param capacity The initial capacity (number of characters). + * + * This value is automatically adjusted to the combined size of the + * source strings, if a smaller value was passed. + * @param allocator A pointer to a `ZyanAllocator` instance. + * @param growth_factor The growth factor (from `1.0f` to `x.xf`). + * @param shrink_threshold The shrink threshold (from `0.0f` to `1.0f`). + * + * @return A zyan status code. + * + * The behavior of this function is undefined, if `s1` or `s2` are views into the `destination` + * string or `destination` points to an already initialized `ZyanString` instance. + * + * A growth factor of `1.0f` disables overallocation and a shrink threshold of `0.0f` disables + * dynamic shrinking. + * + * The allocated buffer will be at least one character larger than the given `capacity`, to reserve + * space for the terminating '\0'. + * + * Finalization with `ZyanStringDestroy` is required for all strings created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringConcatEx(ZyanString* destination, const ZyanStringView* s1, + const ZyanStringView* s2, ZyanUSize capacity, ZyanAllocator* allocator, float growth_factor, + float shrink_threshold); + +/** + * Initializes a new `ZyanString` instance by concatenating two existing strings and + * configures it to use a custom user defined buffer with a fixed size. + * + * @param destination A pointer to the (uninitialized) destination `ZyanString` instance. + * + * This function will fail, if the destination `ZyanString` instance equals + * one of the source strings. + * @param s1 A pointer to the first source string. + * @param s2 A pointer to the second source string. + * @param buffer A pointer to the buffer that is used as storage for the string. + * @param capacity The maximum capacity (number of characters) of the buffer. + * + * This function will fail, if the capacity of the buffer is less or equal to + * the combined size of the source strings. + * + * @return A zyan status code. + * + * The behavior of this function is undefined, if `s1` or `s2` are views into the `destination` + * string or `destination` points to an already initialized `ZyanString` instance. + * + * Finalization is not required for strings created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringConcatCustomBuffer(ZyanString* destination, + const ZyanStringView* s1, const ZyanStringView* s2, char* buffer, ZyanUSize capacity); + +/* ---------------------------------------------------------------------------------------------- */ +/* Views */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns a view inside an existing view/string. + * + * @param view A pointer to the `ZyanStringView` instance. + * @param source A pointer to the source string. + * + * @return A zyan status code. + * + * The `ZYAN_STRING_TO_VEW` macro can be used to pass any `ZyanString` instance as value for the + * `source` string. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringViewInsideView(ZyanStringView* view, + const ZyanStringView* source); + +/** + * Returns a view inside an existing view/string starting from the given `index`. + * + * @param view A pointer to the `ZyanStringView` instance. + * @param source A pointer to the source string. + * @param index The start index. + * @param count The number of characters. + * + * @return A zyan status code. + * + * The `ZYAN_STRING_TO_VEW` macro can be used to pass any `ZyanString` instance as value for the + * `source` string. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringViewInsideViewEx(ZyanStringView* view, + const ZyanStringView* source, ZyanUSize index, ZyanUSize count); + +/** + * Returns a view inside a null-terminated C-style string. + * + * @param view A pointer to the `ZyanStringView` instance. + * @param string The C-style string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringViewInsideBuffer(ZyanStringView* view, const char* string); + +/** + * Returns a view inside a character buffer with custom length. + * + * @param view A pointer to the `ZyanStringView` instance. + * @param buffer A pointer to the buffer containing the string characters. + * @param length The length of the string (number of characters). + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringViewInsideBufferEx(ZyanStringView* view, const char* buffer, + ZyanUSize length); + +/** + * Returns the size (number of characters) of the view. + * + * @param view A pointer to the `ZyanStringView` instance. + * @param size Receives the size (number of characters) of the view. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringViewGetSize(const ZyanStringView* view, ZyanUSize* size); + +/** + * Returns the C-style string of the given `ZyanString` instance. + * + * @warning The string is not guaranteed to be null terminated! + * + * @param string A pointer to the `ZyanStringView` instance. + * @param value Receives a pointer to the C-style string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringViewGetData(const ZyanStringView* view, const char** buffer); + +/* ---------------------------------------------------------------------------------------------- */ +/* Character access */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the character at the given `index`. + * + * @param string A pointer to the `ZyanStringView` instance. + * @param index The character index. + * @param value Receives the desired character of the string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringGetChar(const ZyanStringView* string, ZyanUSize index, + char* value); + +/** + * Returns a pointer to the character at the given `index`. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The character index. + * @param value Receives a pointer to the desired character in the string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringGetCharMutable(ZyanString* string, ZyanUSize index, + char** value); + +/** + * Assigns a new value to the character at the given `index`. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The character index. + * @param value The character to assign. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringSetChar(ZyanString* string, ZyanUSize index, char value); + +/* ---------------------------------------------------------------------------------------------- */ +/* Insertion */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Inserts the content of the source string in the destination string at the given `index`. + * + * @param destination The destination string. + * @param index The insert index. + * @param source The source string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringInsert(ZyanString* destination, ZyanUSize index, + const ZyanStringView* source); + +/** + * Inserts `count` characters of the source string in the destination string at the given + * `index`. + * + * @param destination The destination string. + * @param destination_index The insert index. + * @param source The source string. + * @param source_index The index of the first character to be inserted from the source + * string. + * @param count The number of chars to insert from the source string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringInsertEx(ZyanString* destination, ZyanUSize destination_index, + const ZyanStringView* source, ZyanUSize source_index, ZyanUSize count); + +/* ---------------------------------------------------------------------------------------------- */ +/* Appending */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Appends the content of the source string to the end of the destination string. + * + * @param destination The destination string. + * @param source The source string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringAppend(ZyanString* destination, const ZyanStringView* source); + +/** + * Appends `count` characters of the source string to the end of the destination string. + * + * @param destination The destination string. + * @param source The source string. + * @param source_index The index of the first character to be appended from the source string. + * @param count The number of chars to append from the source string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringAppendEx(ZyanString* destination, const ZyanStringView* source, + ZyanUSize source_index, ZyanUSize count); + +/* ---------------------------------------------------------------------------------------------- */ +/* Deletion */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Deletes characters from the given string, starting at `index`. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The index of the first character to delete. + * @param count The number of characters to delete. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringDelete(ZyanString* string, ZyanUSize index, ZyanUSize count); + +/** + * Deletes all remaining characters from the given string, starting at `index`. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The index of the first character to delete. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringTruncate(ZyanString* string, ZyanUSize index); + +/** + * Erases the given string. + * + * @param string A pointer to the `ZyanString` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringClear(ZyanString* string); + +/* ---------------------------------------------------------------------------------------------- */ +/* Searching */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Searches for the first occurrence of `needle` in the given `haystack` starting from the + * left. + * + * @param haystack The string to search in. + * @param needle The sub-string to search for. + * @param found_index A pointer to a variable that receives the index of the first occurrence of + * `needle`. + * + * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occured. + * + * The `found_index` is set to `-1`, if the needle was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringLPos(const ZyanStringView* haystack, + const ZyanStringView* needle, ZyanISize* found_index); + +/** + * Searches for the first occurrence of `needle` in the given `haystack` starting from the + * left. + * + * @param haystack The string to search in. + * @param needle The sub-string to search for. + * @param found_index A pointer to a variable that receives the index of the first occurrence of + * `needle`. + * @param index The start index. + * @param count The maximum number of characters to iterate, beginning from the start + * `index`. + * + * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occured. + * + * The `found_index` is set to `-1`, if the needle was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringLPosEx(const ZyanStringView* haystack, + const ZyanStringView* needle, ZyanISize* found_index, ZyanUSize index, ZyanUSize count); + +/** + * Performs a case-insensitive search for the first occurrence of `needle` in the given + * `haystack` starting from the left. + * + * @param haystack The string to search in. + * @param needle The sub-string to search for. + * @param found_index A pointer to a variable that receives the index of the first occurrence of + * `needle`. + * + * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occured. + * + * The `found_index` is set to `-1`, if the needle was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringLPosI(const ZyanStringView* haystack, + const ZyanStringView* needle, ZyanISize* found_index); + +/** + * Performs a case-insensitive search for the first occurrence of `needle` in the given + * `haystack` starting from the left. + * + * @param haystack The string to search in. + * @param needle The sub-string to search for. + * @param found_index A pointer to a variable that receives the index of the first occurrence of + * `needle`. + * @param index The start index. + * @param count The maximum number of characters to iterate, beginning from the start + * `index`. + * + * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occured. + * + * The `found_index` is set to `-1`, if the needle was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringLPosIEx(const ZyanStringView* haystack, + const ZyanStringView* needle, ZyanISize* found_index, ZyanUSize index, ZyanUSize count); + +/** + * Searches for the first occurrence of `needle` in the given `haystack` starting from the + * right. + * + * @param haystack The string to search in. + * @param needle The sub-string to search for. + * @param found_index A pointer to a variable that receives the index of the first occurrence of + * `needle`. + * + * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occured. + * + * The `found_index` is set to `-1`, if the needle was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringRPos(const ZyanStringView* haystack, + const ZyanStringView* needle, ZyanISize* found_index); + +/** + * Searches for the first occurrence of `needle` in the given `haystack` starting from the + * right. + * + * @param haystack The string to search in. + * @param needle The sub-string to search for. + * @param found_index A pointer to a variable that receives the index of the first occurrence of + * `needle`. + * @param index The start index. + * @param count The maximum number of characters to iterate, beginning from the start + * `index`. + * + * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occured. + * + * The `found_index` is set to `-1`, if the needle was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringRPosEx(const ZyanStringView* haystack, + const ZyanStringView* needle, ZyanISize* found_index, ZyanUSize index, ZyanUSize count); + +/** + * Performs a case-insensitive search for the first occurrence of `needle` in the given + * `haystack` starting from the right. + * + * @param haystack The string to search in. + * @param needle The sub-string to search for. + * @param found_index A pointer to a variable that receives the index of the first occurrence of + * `needle`. + * + * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occured. + * + * The `found_index` is set to `-1`, if the needle was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringRPosI(const ZyanStringView* haystack, + const ZyanStringView* needle, ZyanISize* found_index); + +/** + * Performs a case-insensitive search for the first occurrence of `needle` in the given + * `haystack` starting from the right. + * + * @param haystack The string to search in. + * @param needle The sub-string to search for. + * @param found_index A pointer to a variable that receives the index of the first occurrence of + * `needle`. + * @param index The start index. + * @param count The maximum number of characters to iterate, beginning from the start + * `index`. + * + * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occured. + * + * The `found_index` is set to `-1`, if the needle was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringRPosIEx(const ZyanStringView* haystack, + const ZyanStringView* needle, ZyanISize* found_index, ZyanUSize index, ZyanUSize count); + +/* ---------------------------------------------------------------------------------------------- */ +/* Comparing */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Compares two strings. + * + * @param s1 The first string + * @param s2 The second string. + * @param result Receives the comparison result. + * + * Values: + * - `result < 0` -> The first character that does not match has a lower value + * in `s1` than in `s2`. + * - `result == 0` -> The contents of both strings are equal. + * - `result > 0` -> The first character that does not match has a greater value + * in `s1` than in `s2`. + * + * @return `ZYAN_STATUS_TRUE`, if the strings are equal, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occured. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringCompare(const ZyanStringView* s1, const ZyanStringView* s2, + ZyanI32* result); + +/** + * Performs a case-insensitive comparison of two strings. + * + * @param s1 The first string + * @param s2 The second string. + * @param result Receives the comparison result. + * + * Values: + * - `result < 0` -> The first character that does not match has a lower value + * in `s1` than in `s2`. + * - `result == 0` -> The contents of both strings are equal. + * - `result > 0` -> The first character that does not match has a greater value + * in `s1` than in `s2`. + * + * @return `ZYAN_STATUS_TRUE`, if the strings are equal, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occured. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringCompareI(const ZyanStringView* s1, const ZyanStringView* s2, + ZyanI32* result); + +/* ---------------------------------------------------------------------------------------------- */ +/* Case conversion */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Converts the given string to lowercase letters. + * + * @param string A pointer to the `ZyanString` instance. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringToLowerCase(ZyanString* string); + +/** + * Converts `count` characters of the given string to lowercase letters. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The start index. + * @param count The number of characters to convert, beginning from the start `index`. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringToLowerCaseEx(ZyanString* string, ZyanUSize index, + ZyanUSize count); + +/** + * Converts the given string to uppercase letters. + * + * @param string A pointer to the `ZyanString` instance. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringToUpperCase(ZyanString* string); + +/** + * Converts `count` characters of the given string to uppercase letters. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The start index. + * @param count The number of characters to convert, beginning from the start `index`. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringToUpperCaseEx(ZyanString* string, ZyanUSize index, + ZyanUSize count); + +/* ---------------------------------------------------------------------------------------------- */ +/* Memory management */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Resizes the given `ZyanString` instance. + * + * @param string A pointer to the `ZyanString` instance. + * @param size The new size of the string. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringResize(ZyanString* string, ZyanUSize size); + +/** + * Changes the capacity of the given `ZyanString` instance. + * + * @param string A pointer to the `ZyanString` instance. + * @param capacity The new minimum capacity of the string. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringReserve(ZyanString* string, ZyanUSize capacity); + +/** + * Shrinks the capacity of the given string to match it's size. + * + * @param string A pointer to the `ZyanString` instance. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringShrinkToFit(ZyanString* string); + +/* ---------------------------------------------------------------------------------------------- */ +/* Information */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the current capacity of the string. + * + * @param string A pointer to the `ZyanString` instance. + * @param capacity Receives the size of the string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringGetCapacity(const ZyanString* string, ZyanUSize* capacity); + +/** + * Returns the current size (number of characters) of the string (excluding the + * terminating zero character). + * + * @param string A pointer to the `ZyanString` instance. + * @param size Receives the size (number of characters) of the string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringGetSize(const ZyanString* string, ZyanUSize* size); + +/** + * Returns the C-style string of the given `ZyanString` instance. + * + * @param string A pointer to the `ZyanString` instance. + * @param value Receives a pointer to the C-style string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringGetData(const ZyanString* string, const char** value); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif // ZYCORE_STRING_H diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Types.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Types.h new file mode 100644 index 0000000..74fe905 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Types.h @@ -0,0 +1,195 @@ +/*************************************************************************************************** + + Zyan Core Library (Zyan-C) + + Original Author : Florian Bernd, Joel Hoener + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Includes and defines some default data types. + */ + +#ifndef ZYCORE_TYPES_H +#define ZYCORE_TYPES_H + +#include + +/* ============================================================================================== */ +/* Integer types */ +/* ============================================================================================== */ + +#if defined(ZYAN_NO_LIBC) || \ + (defined(ZYAN_MSVC) && defined(ZYAN_KERNEL)) // The WDK LibC lacks stdint.h. + // No LibC mode, use compiler built-in types / macros. +# if defined(ZYAN_MSVC) || defined(ZYAN_ICC) + typedef unsigned __int8 ZyanU8; + typedef unsigned __int16 ZyanU16; + typedef unsigned __int32 ZyanU32; + typedef unsigned __int64 ZyanU64; + typedef signed __int8 ZyanI8; + typedef signed __int16 ZyanI16; + typedef signed __int32 ZyanI32; + typedef signed __int64 ZyanI64; +# if _WIN64 + typedef ZyanU64 ZyanUSize; + typedef ZyanI64 ZyanISize; + typedef ZyanU64 ZyanUPointer; + typedef ZyanI64 ZyanIPointer; +# else + typedef ZyanU32 ZyanUSize; + typedef ZyanI32 ZyanISize; + typedef ZyanU32 ZyanUPointer; + typedef ZyanI32 ZyanIPointer; +# endif +# elif defined(ZYAN_GNUC) + typedef __UINT8_TYPE__ ZyanU8; + typedef __UINT16_TYPE__ ZyanU16; + typedef __UINT32_TYPE__ ZyanU32; + typedef __UINT64_TYPE__ ZyanU64; + typedef __INT8_TYPE__ ZyanI8; + typedef __INT16_TYPE__ ZyanI16; + typedef __INT32_TYPE__ ZyanI32; + typedef __INT64_TYPE__ ZyanI64; + typedef __SIZE_TYPE__ ZyanUSize; + typedef __PTRDIFF_TYPE__ ZyanISize; + typedef __UINTPTR_TYPE__ ZyanUPointer; + typedef __INTPTR_TYPE__ ZyanIPointer; +# else +# error "Unsupported compiler for no-libc mode." +# endif +#else + // If is LibC present, we use stdint types. +# include +# include + typedef uint8_t ZyanU8; + typedef uint16_t ZyanU16; + typedef uint32_t ZyanU32; + typedef uint64_t ZyanU64; + typedef int8_t ZyanI8; + typedef int16_t ZyanI16; + typedef int32_t ZyanI32; + typedef int64_t ZyanI64; + typedef size_t ZyanUSize; + typedef ptrdiff_t ZyanISize; + typedef uintptr_t ZyanUPointer; + typedef intptr_t ZyanIPointer; +#endif + +// Verify size assumptions. +ZYAN_STATIC_ASSERT(sizeof(ZyanU8 ) == 1 ); +ZYAN_STATIC_ASSERT(sizeof(ZyanU16 ) == 2 ); +ZYAN_STATIC_ASSERT(sizeof(ZyanU32 ) == 4 ); +ZYAN_STATIC_ASSERT(sizeof(ZyanU64 ) == 8 ); +ZYAN_STATIC_ASSERT(sizeof(ZyanI8 ) == 1 ); +ZYAN_STATIC_ASSERT(sizeof(ZyanI16 ) == 2 ); +ZYAN_STATIC_ASSERT(sizeof(ZyanI32 ) == 4 ); +ZYAN_STATIC_ASSERT(sizeof(ZyanI64 ) == 8 ); +ZYAN_STATIC_ASSERT(sizeof(ZyanUSize ) == sizeof(void*)); // TODO: This one is incorrect! +ZYAN_STATIC_ASSERT(sizeof(ZyanISize ) == sizeof(void*)); // TODO: This one is incorrect! +ZYAN_STATIC_ASSERT(sizeof(ZyanUPointer) == sizeof(void*)); +ZYAN_STATIC_ASSERT(sizeof(ZyanIPointer) == sizeof(void*)); + +// Verify signedness assumptions (relies on size checks above). +ZYAN_STATIC_ASSERT((ZyanI8 )-1 >> 1 < (ZyanI8 )((ZyanU8 )-1 >> 1)); +ZYAN_STATIC_ASSERT((ZyanI16)-1 >> 1 < (ZyanI16)((ZyanU16)-1 >> 1)); +ZYAN_STATIC_ASSERT((ZyanI32)-1 >> 1 < (ZyanI32)((ZyanU32)-1 >> 1)); +ZYAN_STATIC_ASSERT((ZyanI64)-1 >> 1 < (ZyanI64)((ZyanU64)-1 >> 1)); + +/* ============================================================================================== */ +/* Pointer */ +/* ============================================================================================== */ + +/** + * Defines the `ZyanVoidPointer` data-type. + */ +typedef char* ZyanVoidPointer; + +/** + * Defines the `ZyanConstVoidPointer` data-type. + */ +typedef const void* ZyanConstVoidPointer; + +#define ZYAN_NULL ((void*)0) + +/* ============================================================================================== */ +/* Logic types */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Boolean */ +/* ---------------------------------------------------------------------------------------------- */ + +#define ZYAN_FALSE 0 +#define ZYAN_TRUE 1 + +/** + * Defines the `ZyanBool` data-type. + * + * Represents a default boolean data-type where `0` is interpreted as `false` and all other values + * as `true`. + */ +typedef ZyanU8 ZyanBool; + +/* ---------------------------------------------------------------------------------------------- */ +/* Ternary */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZyanTernary` data-type. + * + * The `ZyanTernary` is a balanced ternary type that uses three truth values indicating `true`, + * `false` and an indeterminate third value. + */ +typedef ZyanI8 ZyanTernary; + +#define ZYAN_TERNARY_FALSE (-1) +#define ZYAN_TERNARY_UNKNOWN 0x00 +#define ZYAN_TERNARY_TRUE 0x01 + +/* ============================================================================================== */ +/* String types */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* C-style strings */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZyanCharPointer` data-type. + * + * This type is most often used to represent null-terminated strings aka. C-style strings. + */ +typedef char* ZyanCharPointer; + +/** + * Defines the `ZyanConstCharPointer` data-type. + * + * This type is most often used to represent null-terminated strings aka. C-style strings. + */ +typedef const char* ZyanConstCharPointer; + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#endif /* ZYCORE_TYPES_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Vector.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Vector.h new file mode 100644 index 0000000..47e728c --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Vector.h @@ -0,0 +1,723 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Implements the vector container class. + */ + +#ifndef ZYCORE_VECTOR_H +#define ZYCORE_VECTOR_H + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Constants */ +/* ============================================================================================== */ + +/** + * The initial minimum capacity (number of elements) for all dynamically allocated vector + * instances. + */ +#define ZYAN_VECTOR_MIN_CAPACITY 1 + +/** + * The default growth factor for all vector instances. + */ +#define ZYAN_VECTOR_DEFAULT_GROWTH_FACTOR 2.00f + +/** + * The default shrink threshold for all vector instances. + */ +#define ZYAN_VECTOR_DEFAULT_SHRINK_THRESHOLD 0.25f + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/** + * Defines the `ZyanVector` struct. + * + * All fields in this struct should be considered as "private". Any changes may lead to unexpected + * behavior. + */ +typedef struct ZyanVector_ +{ + /** + * The memory allocator. + */ + ZyanAllocator* allocator; + /** + * The growth factor. + */ + float growth_factor; + /** + * The shrink threshold. + */ + float shrink_threshold; + /** + * The current number of elements in the vector. + */ + ZyanUSize size; + /** + * The maximum capacity (number of elements). + */ + ZyanUSize capacity; + /** + * The size of a single element in bytes. + */ + ZyanUSize element_size; + /** + * The element destructor callback. + */ + ZyanMemberProcedure destructor; + /** + * The data pointer. + */ + void* data; +} ZyanVector; + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines an uninitialized `ZyanVector` instance. + */ +#define ZYAN_VECTOR_INITIALIZER \ + { \ + /* allocator */ ZYAN_NULL, \ + /* growth_factor */ 0.0f, \ + /* shrink_threshold */ 0.0f, \ + /* size */ 0, \ + /* capacity */ 0, \ + /* element_size */ 0, \ + /* destructor */ ZYAN_NULL, \ + /* data */ ZYAN_NULL \ + } + +/* ---------------------------------------------------------------------------------------------- */ +/* Helper macros */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the value of the element at the given `index`. + * + * @param type The desired value type. + * @param vector A pointer to the `ZyanVector` instance. + * @param index The element index. + * + * @result The value of the desired element in the vector. + * + * Note that this function is unsafe and might dereference a null-pointer. + */ +#ifdef __cplusplus +#define ZYAN_VECTOR_GET(type, vector, index) \ + (*reinterpret_cast(ZyanVectorGet(vector, index))) +#else +#define ZYAN_VECTOR_GET(type, vector, index) \ + (*(const type*)ZyanVectorGet(vector, index)) +#endif + +/** + * Loops through all elements of the vector. + * + * @param type The desired value type. + * @param vector A pointer to the `ZyanVector` instance. + * @param item_name The name of the iterator item. + * @param body The body to execute for each item in the vector. + */ +#define ZYAN_VECTOR_FOREACH(type, vector, item_name, body) \ + { \ + const ZyanUSize ZYAN_MACRO_CONCAT_EXPAND(size_d50d3303, item_name) = (vector)->size; \ + for (ZyanUSize ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name) = 0; \ + ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name) < \ + ZYAN_MACRO_CONCAT_EXPAND(size_d50d3303, item_name); \ + ++ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name)) \ + { \ + const type item_name = ZYAN_VECTOR_GET(type, vector, \ + ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name)); \ + body \ + } \ + } + +/** + * Loops through all elements of the vector. + * + * @param type The desired value type. + * @param vector A pointer to the `ZyanVector` instance. + * @param item_name The name of the iterator item. + * @param body The body to execute for each item in the vector. + */ +#define ZYAN_VECTOR_FOREACH_MUTABLE(type, vector, item_name, body) \ + { \ + const ZyanUSize ZYAN_MACRO_CONCAT_EXPAND(size_d50d3303, item_name) = (vector)->size; \ + for (ZyanUSize ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name) = 0; \ + ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name) < \ + ZYAN_MACRO_CONCAT_EXPAND(size_d50d3303, item_name); \ + ++ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name)) \ + { \ + type* const item_name = ZyanVectorGetMutable(vector, \ + ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name)); \ + body \ + } \ + } + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Constructor and destructor */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +/** + * Initializes the given `ZyanVector` instance. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param element_size The size of a single element in bytes. + * @param capacity The initial capacity (number of elements). + * @param destructor A destructor callback that is invoked every time an item is deleted, or + * `ZYAN_NULL` if not needed. + * + * @return A zyan status code. + * + * The memory for the vector elements is dynamically allocated by the default allocator using the + * default growth factor of `2.0f` and the default shrink threshold of `0.25f`. + * + * Finalization with `ZyanVectorDestroy` is required for all instances created by this function. + */ +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanVectorInit(ZyanVector* vector, + ZyanUSize element_size, ZyanUSize capacity, ZyanMemberProcedure destructor); + +#endif // ZYAN_NO_LIBC + +/** + * Initializes the given `ZyanVector` instance and sets a custom `allocator` and memory + * allocation/deallocation parameters. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param element_size The size of a single element in bytes. + * @param capacity The initial capacity (number of elements). + * @param destructor A destructor callback that is invoked every time an item is deleted, + * or `ZYAN_NULL` if not needed. + * @param allocator A pointer to a `ZyanAllocator` instance. + * @param growth_factor The growth factor (from `1.0f` to `x.xf`). + * @param shrink_threshold The shrink threshold (from `0.0f` to `1.0f`). + * + * @return A zyan status code. + * + * A growth factor of `1.0f` disables overallocation and a shrink threshold of `0.0f` disables + * dynamic shrinking. + * + * Finalization with `ZyanVectorDestroy` is required for all instances created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorInitEx(ZyanVector* vector, ZyanUSize element_size, + ZyanUSize capacity, ZyanMemberProcedure destructor, ZyanAllocator* allocator, + float growth_factor, float shrink_threshold); + +/** + * Initializes the given `ZyanVector` instance and configures it to use a custom user + * defined buffer with a fixed size. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param element_size The size of a single element in bytes. + * @param buffer A pointer to the buffer that is used as storage for the elements. + * @param capacity The maximum capacity (number of elements) of the buffer. + * @param destructor A destructor callback that is invoked every time an item is deleted, or + * `ZYAN_NULL` if not needed. + * + * @return A zyan status code. + * + * Finalization is not required for instances created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorInitCustomBuffer(ZyanVector* vector, ZyanUSize element_size, + void* buffer, ZyanUSize capacity, ZyanMemberProcedure destructor); + +/** + * Destroys the given `ZyanVector` instance. + * + * @param vector A pointer to the `ZyanVector` instance.. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorDestroy(ZyanVector* vector); + +/* ---------------------------------------------------------------------------------------------- */ +/* Duplication */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +/** + * Initializes a new `ZyanVector` instance by duplicating an existing vector. + * + * @param destination A pointer to the (uninitialized) destination `ZyanVector` instance. + * @param source A pointer to the source vector. + * @param capacity The initial capacity (number of elements). + * + * This value is automatically adjusted to the size of the source vector, if + * a smaller value was passed. + * + * @return A zyan status code. + * + * The memory for the vector is dynamically allocated by the default allocator using the default + * growth factor of `2.0f` and the default shrink threshold of `0.25f`. + * + * Finalization with `ZyanVectorDestroy` is required for all instances created by this function. + */ +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanVectorDuplicate(ZyanVector* destination, + const ZyanVector* source, ZyanUSize capacity); + +#endif // ZYAN_NO_LIBC + +/** + * Initializes a new `ZyanVector` instance by duplicating an existing vector and sets a + * custom `allocator` and memory allocation/deallocation parameters. + * + * @param destination A pointer to the (uninitialized) destination `ZyanVector` instance. + * @param source A pointer to the source vector. + * @param capacity The initial capacity (number of elements). + + * This value is automatically adjusted to the size of the source + * vector, if a smaller value was passed. + * @param allocator A pointer to a `ZyanAllocator` instance. + * @param growth_factor The growth factor (from `1.0f` to `x.xf`). + * @param shrink_threshold The shrink threshold (from `0.0f` to `1.0f`). + * + * @return A zyan status code. + * + * A growth factor of `1.0f` disables overallocation and a shrink threshold of `0.0f` disables + * dynamic shrinking. + * + * Finalization with `ZyanVectorDestroy` is required for all instances created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorDuplicateEx(ZyanVector* destination, const ZyanVector* source, + ZyanUSize capacity, ZyanAllocator* allocator, float growth_factor, float shrink_threshold); + +/** + * Initializes a new `ZyanVector` instance by duplicating an existing vector and + * configures it to use a custom user defined buffer with a fixed size. + * + * @param destination A pointer to the (uninitialized) destination `ZyanVector` instance. + * @param source A pointer to the source vector. + * @param buffer A pointer to the buffer that is used as storage for the elements. + * @param capacity The maximum capacity (number of elements) of the buffer. + + * This function will fail, if the capacity of the buffer is less than the + * size of the source vector. + * + * @return A zyan status code. + * + * Finalization is not required for instances created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorDuplicateCustomBuffer(ZyanVector* destination, + const ZyanVector* source, void* buffer, ZyanUSize capacity); + +/* ---------------------------------------------------------------------------------------------- */ +/* Element access */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns a constant pointer to the element at the given `index`. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The element index. + * + * @return A constant pointer to the desired element in the vector or `ZYAN_NULL`, if an error + * occured. + * + * Note that the returned pointer might get invalid when the vector is resized by either a manual + * call to the memory-management functions or implicitly by inserting or removing elements. + * + * Take a look at `ZyanVectorGetPointer` instead, if you need a function that returns a zyan status + * code. + */ +ZYCORE_EXPORT const void* ZyanVectorGet(const ZyanVector* vector, ZyanUSize index); + +/** + * Returns a mutable pointer to the element at the given `index`. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The element index. + * + * @return A mutable pointer to the desired element in the vector or `ZYAN_NULL`, if an error + * occured. + * + * Note that the returned pointer might get invalid when the vector is resized by either a manual + * call to the memory-management functions or implicitly by inserting or removing elements. + * + * Take a look at `ZyanVectorGetPointerMutable` instead, if you need a function that returns a + * zyan status code. + */ +ZYCORE_EXPORT void* ZyanVectorGetMutable(const ZyanVector* vector, ZyanUSize index); + +/** + * Returns a constant pointer to the element at the given `index`. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The element index. + * @param value Receives a constant pointer to the desired element in the vector. + * + * Note that the returned pointer might get invalid when the vector is resized by either a manual + * call to the memory-management functions or implicitly by inserting or removing elements. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorGetPointer(const ZyanVector* vector, ZyanUSize index, + const void** value); + +/** + * Returns a mutable pointer to the element at the given `index`. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The element index. + * @param value Receives a mutable pointer to the desired element in the vector. + * + * Note that the returned pointer might get invalid when the vector is resized by either a manual + * call to the memory-management functions or implicitly by inserting or removing elements. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorGetPointerMutable(const ZyanVector* vector, ZyanUSize index, + void** value); + +/** + * Assigns a new value to the element at the given `index`. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The value index. + * @param value The value to assign. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorSet(ZyanVector* vector, ZyanUSize index, + const void* value); + +/* ---------------------------------------------------------------------------------------------- */ +/* Insertion */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Adds a new `element` to the end of the vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param element A pointer to the element to add. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorPushBack(ZyanVector* vector, const void* element); + +/** + * Inserts an `element` at the given `index` of the vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The insert index. + * @param element A pointer to the element to insert. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorInsert(ZyanVector* vector, ZyanUSize index, + const void* element); + +/** + * Inserts multiple `elements` at the given `index` of the vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The insert index. + * @param elements A pointer to the first element. + * @param count The number of elements to insert. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorInsertRange(ZyanVector* vector, ZyanUSize index, + const void* elements, ZyanUSize count); + +/** + * Constructs an `element` in-place at the end of the vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param element Receives a pointer to the new element. + * @param constructor The constructor callback or `ZYAN_NULL`. The new element will be in + * undefined state, if no constructor was passed. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorEmplace(ZyanVector* vector, void** element, + ZyanMemberFunction constructor); + +/** + * Constructs an `element` in-place and inserts it at the given `index` of the vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The insert index. + * @param element Receives a pointer to the new element. + * @param constructor The constructor callback or `ZYAN_NULL`. The new element will be in + * undefined state, if no constructor was passed. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorEmplaceEx(ZyanVector* vector, ZyanUSize index, + void** element, ZyanMemberFunction constructor); + +/* ---------------------------------------------------------------------------------------------- */ +/* Utils */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Swaps the element at `index_first` with the element at `index_second`. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index_first The index of the first element. + * @param index_second The index of the second element. + * + * @return A zyan status code. + * + * This function requires the vector to have spare capacity for one temporary element. Call + * `ZyanVectorReserve` before this function to increase capacity, if needed. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorSwapElements(ZyanVector* vector, ZyanUSize index_first, + ZyanUSize index_second); + +/* ---------------------------------------------------------------------------------------------- */ +/* Deletion */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Deletes the element at the given `index` of the vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The element index. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorDelete(ZyanVector* vector, ZyanUSize index); + +/** + * Deletes multiple elements from the given vector, starting at `index`. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The index of the first element to delete. + * @param count The number of elements to delete. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorDeleteRange(ZyanVector* vector, ZyanUSize index, + ZyanUSize count); + +/** + * Removes the last element of the vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorPopBack(ZyanVector* vector); + +/** + * Erases all elements of the given vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorClear(ZyanVector* vector); + +/* ---------------------------------------------------------------------------------------------- */ +/* Searching */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Sequentially searches for the first occurrence of `element` in the given vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param element A pointer to the element to search for. + * @param found_index A pointer to a variable that receives the index of the found element. + * @param comparison The comparison function to use. + * + * @return `ZYAN_STATUS_TRUE` if the element was found, `ZYAN_STATUS_FALSE` if not or a generic + * zyan status code if an error occured. + * + * The `found_index` is set to `-1`, if the element was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorFind(const ZyanVector* vector, const void* element, + ZyanISize* found_index, ZyanEqualityComparison comparison); + +/** + * Sequentially searches for the first occurrence of `element` in the given vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param element A pointer to the element to search for. + * @param found_index A pointer to a variable that receives the index of the found element. + * @param comparison The comparison function to use. + * @param index The start index. + * @param count The maximum number of elements to iterate, beginning from the start `index`. + * + * @return `ZYAN_STATUS_TRUE` if the element was found, `ZYAN_STATUS_FALSE` if not or a generic + * zyan status code if an error occured. + * + * The `found_index` is set to `-1`, if the element was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorFindEx(const ZyanVector* vector, const void* element, + ZyanISize* found_index, ZyanEqualityComparison comparison, ZyanUSize index, ZyanUSize count); + +/** + * Searches for the first occurrence of `element` in the given vector using a binary- + * search algorithm. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param element A pointer to the element to search for. + * @param found_index A pointer to a variable that receives the index of the found element. + * @param comparison The comparison function to use. + * + * @return `ZYAN_STATUS_TRUE` if the element was found, `ZYAN_STATUS_FALSE` if not or a generic + * zyan status code if an error occured. + * + * If found, `found_index` contains the zero-based index of `element`. If not found, `found_index` + * contains the index of the first entry larger than `element`. + * + * This function requires all elements in the vector to be strictly ordered (sorted). + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorBinarySearch(const ZyanVector* vector, const void* element, + ZyanUSize* found_index, ZyanComparison comparison); + +/** + * Searches for the first occurrence of `element` in the given vector using a binary- + * search algorithm. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param element A pointer to the element to search for. + * @param found_index A pointer to a variable that receives the index of the found element. + * @param comparison The comparison function to use. + * @param index The start index. + * @param count The maximum number of elements to iterate, beginning from the start `index`. + * + * @return `ZYAN_STATUS_TRUE` if the element was found, `ZYAN_STATUS_FALSE` if not or a generic + * zyan status code if an error occured. + * + * If found, `found_index` contains the zero-based index of `element`. If not found, `found_index` + * contains the index of the first entry larger than `element`. + * + * This function requires all elements in the vector to be strictly ordered (sorted). + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorBinarySearchEx(const ZyanVector* vector, const void* element, + ZyanUSize* found_index, ZyanComparison comparison, ZyanUSize index, ZyanUSize count); + +/* ---------------------------------------------------------------------------------------------- */ +/* Memory management */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Resizes the given `ZyanVector` instance. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param size The new size of the vector. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorResize(ZyanVector* vector, ZyanUSize size); + +/** + * Resizes the given `ZyanVector` instance. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param size The new size of the vector. + * @param initializer A pointer to a value to be used as initializer for new items. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorResizeEx(ZyanVector* vector, ZyanUSize size, + const void* initializer); + +/** + * Changes the capacity of the given `ZyanVector` instance. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param capacity The new minimum capacity of the vector. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorReserve(ZyanVector* vector, ZyanUSize capacity); + +/** + * Shrinks the capacity of the given vector to match it's size. + * + * @param vector A pointer to the `ZyanVector` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorShrinkToFit(ZyanVector* vector); + +/* ---------------------------------------------------------------------------------------------- */ +/* Information */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the current capacity of the vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param capacity Receives the size of the vector. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorGetCapacity(const ZyanVector* vector, ZyanUSize* capacity); + +/** + * Returns the current size of the vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param size Receives the size of the vector. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorGetSize(const ZyanVector* vector, ZyanUSize* size); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_VECTOR_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Zycore.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Zycore.h new file mode 100644 index 0000000..e136acf --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Zycore.h @@ -0,0 +1,111 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Master include file, including everything else. + */ + +#ifndef ZYCORE_H +#define ZYCORE_H + +#include +#include + +// TODO: + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Constants */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * A macro that defines the zycore version. + */ +#define ZYCORE_VERSION (ZyanU64)0x0001000000000000 + +/* ---------------------------------------------------------------------------------------------- */ +/* Helper macros */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Extracts the major-part of the zycore version. + * + * @param version The zycore version value + */ +#define ZYCORE_VERSION_MAJOR(version) (ZyanU16)((version & 0xFFFF000000000000) >> 48) + +/** + * Extracts the minor-part of the zycore version. + * + * @param version The zycore version value + */ +#define ZYCORE_VERSION_MINOR(version) (ZyanU16)((version & 0x0000FFFF00000000) >> 32) + +/** + * Extracts the patch-part of the zycore version. + * + * @param version The zycore version value + */ +#define ZYCORE_VERSION_PATCH(version) (ZyanU16)((version & 0x00000000FFFF0000) >> 16) + +/** + * Extracts the build-part of the zycore version. + * + * @param version The zycore version value + */ +#define ZYCORE_VERSION_BUILD(version) (ZyanU16)(version & 0x000000000000FFFF) + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/** + * Returns the zycore version. + * + * @return The zycore version. + * + * Use the macros provided in this file to extract the major, minor, patch and build part from the + * returned version value. + */ +ZYCORE_EXPORT ZyanU64 ZycoreGetVersion(void); + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/ZycoreExportConfig.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/ZycoreExportConfig.h new file mode 100644 index 0000000..f050d37 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/ZycoreExportConfig.h @@ -0,0 +1,42 @@ + +#ifndef ZYCORE_EXPORT_H +#define ZYCORE_EXPORT_H + +#ifdef ZYCORE_STATIC_DEFINE +# define ZYCORE_EXPORT +# define ZYCORE_NO_EXPORT +#else +# ifndef ZYCORE_EXPORT +# ifdef Zycore_EXPORTS + /* We are building this library */ +# define ZYCORE_EXPORT __declspec(dllexport) +# else + /* We are using this library */ +# define ZYCORE_EXPORT __declspec(dllimport) +# endif +# endif + +# ifndef ZYCORE_NO_EXPORT +# define ZYCORE_NO_EXPORT +# endif +#endif + +#ifndef ZYCORE_DEPRECATED +# define ZYCORE_DEPRECATED __declspec(deprecated) +#endif + +#ifndef ZYCORE_DEPRECATED_EXPORT +# define ZYCORE_DEPRECATED_EXPORT ZYCORE_EXPORT ZYCORE_DEPRECATED +#endif + +#ifndef ZYCORE_DEPRECATED_NO_EXPORT +# define ZYCORE_DEPRECATED_NO_EXPORT ZYCORE_NO_EXPORT ZYCORE_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef ZYCORE_NO_DEPRECATED +# define ZYCORE_NO_DEPRECATED +# endif +#endif + +#endif /* ZYCORE_EXPORT_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis.lib b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis.lib new file mode 100644 index 0000000..42ca9b6 Binary files /dev/null and b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis.lib differ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Decoder.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Decoder.h new file mode 100644 index 0000000..8cfbb0c --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Decoder.h @@ -0,0 +1,237 @@ +/*************************************************************************************************** + + Zyan Disassembler Library (Zydis) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Functions for decoding instructions. + */ + +#ifndef ZYDIS_DECODER_H +#define ZYDIS_DECODER_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Decoder mode */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisDecoderMode` enum. + */ +typedef enum ZydisDecoderMode_ +{ + /** + * Enables minimal instruction decoding without semantic analysis. + * + * This mode provides access to the mnemonic, the instruction-length, the effective + * operand-size, the effective address-width, some attributes (e.g. `ZYDIS_ATTRIB_IS_RELATIVE`) + * and all of the information in the `raw` field of the `ZydisDecodedInstruction` struct. + * + * Operands, most attributes and other specific information (like `AVX` info) are not + * accessible in this mode. + * + * This mode is NOT enabled by default. + */ + ZYDIS_DECODER_MODE_MINIMAL, + /** + * Enables the `AMD`-branch mode. + * + * Intel ignores the operand-size override-prefix (`0x66`) for all branches with 32-bit + * immediates and forces the operand-size of the instruction to 64-bit in 64-bit mode. + * In `AMD`-branch mode `0x66` is not ignored and changes the operand-size and the size of the + * immediate to 16-bit. + * + * This mode is NOT enabled by default. + */ + ZYDIS_DECODER_MODE_AMD_BRANCHES, + /** + * Enables `KNC` compatibility-mode. + * + * `KNC` and `KNL+` chips are sharing opcodes and encodings for some mask-related instructions. + * Enable this mode to use the old `KNC` specifications (different mnemonics, operands, ..). + * + * This mode is NOT enabled by default. + */ + ZYDIS_DECODER_MODE_KNC, + /** + * Enables the `MPX` mode. + * + * The `MPX` isa-extension reuses (overrides) some of the widenop instruction opcodes. + * + * This mode is enabled by default. + */ + ZYDIS_DECODER_MODE_MPX, + /** + * Enables the `CET` mode. + * + * The `CET` isa-extension reuses (overrides) some of the widenop instruction opcodes. + * + * This mode is enabled by default. + */ + ZYDIS_DECODER_MODE_CET, + /** + * Enables the `LZCNT` mode. + * + * The `LZCNT` isa-extension reuses (overrides) some of the widenop instruction opcodes. + * + * This mode is enabled by default. + */ + ZYDIS_DECODER_MODE_LZCNT, + /** + * Enables the `TZCNT` mode. + * + * The `TZCNT` isa-extension reuses (overrides) some of the widenop instruction opcodes. + * + * This mode is enabled by default. + */ + ZYDIS_DECODER_MODE_TZCNT, + /** + * Enables the `WBNOINVD` mode. + * + * The `WBINVD` instruction is interpreted as `WBNOINVD` on ICL chips, if a `F3` prefix is + * used. + * + * This mode is disabled by default. + */ + ZYDIS_DECODER_MODE_WBNOINVD, + /** + * Enables the `CLDEMOTE` mode. + * + * The `CLDEMOTE` isa-extension reuses (overrides) some of the widenop instruction opcodes. + * + * This mode is enabled by default. + */ + ZYDIS_DECODER_MODE_CLDEMOTE, + + /** + * Maximum value of this enum. + */ + ZYDIS_DECODER_MODE_MAX_VALUE = ZYDIS_DECODER_MODE_CLDEMOTE, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_DECODER_MODE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_DECODER_MODE_MAX_VALUE) +} ZydisDecoderMode; + +/* ---------------------------------------------------------------------------------------------- */ +/* Decoder struct */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisDecoder` struct. + * + * All fields in this struct should be considered as "private". Any changes may lead to unexpected + * behavior. + */ +typedef struct ZydisDecoder_ +{ + /** + * The machine mode. + */ + ZydisMachineMode machine_mode; + /** + * The address width. + */ + ZydisAddressWidth address_width; + /** + * The decoder mode array. + */ + ZyanBool decoder_mode[ZYDIS_DECODER_MODE_MAX_VALUE + 1]; +} ZydisDecoder; + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/** + * @addtogroup decoder Decoder + * Functions allowing decoding of instruction bytes to a machine interpretable struct. + * @{ + */ + +/** + * Initializes the given `ZydisDecoder` instance. + * + * @param decoder A pointer to the `ZydisDecoder` instance. + * @param machine_mode The machine mode. + * @param address_width The address width. + * + * @return A zyan status code. + */ +ZYDIS_EXPORT ZyanStatus ZydisDecoderInit(ZydisDecoder* decoder, ZydisMachineMode machine_mode, + ZydisAddressWidth address_width); + +/** + * Enables or disables the specified decoder-mode. + * + * @param decoder A pointer to the `ZydisDecoder` instance. + * @param mode The decoder mode. + * @param enabled `ZYAN_TRUE` to enable, or `ZYAN_FALSE` to disable the specified decoder-mode. + * + * @return A zyan status code. + */ +ZYDIS_EXPORT ZyanStatus ZydisDecoderEnableMode(ZydisDecoder* decoder, ZydisDecoderMode mode, + ZyanBool enabled); + +/** + * Decodes the instruction in the given input `buffer`. + * + * @param decoder A pointer to the `ZydisDecoder` instance. + * @param buffer A pointer to the input buffer. + * @param length The length of the input buffer. Note that this can be bigger than the + * actual size of the instruction -- you don't have to know the size up + * front. This length is merely used to prevent Zydis from doing + * out-of-bounds reads on your buffer. + * @param instruction A pointer to the `ZydisDecodedInstruction` struct, that receives the + * details about the decoded instruction. + * + * @return A zyan status code. + */ +ZYDIS_EXPORT ZyanStatus ZydisDecoderDecodeBuffer(const ZydisDecoder* decoder, + const void* buffer, ZyanUSize length, ZydisDecodedInstruction* instruction); + +/** @} */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYDIS_DECODER_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/DecoderTypes.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/DecoderTypes.h new file mode 100644 index 0000000..45f5300 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/DecoderTypes.h @@ -0,0 +1,1528 @@ +/*************************************************************************************************** + + Zyan Disassembler Library (Zydis) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Defines the basic `ZydisDecodedInstruction` and `ZydisDecodedOperand` structs. + */ + +#ifndef ZYDIS_INSTRUCTIONINFO_H +#define ZYDIS_INSTRUCTIONINFO_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Decoded operand */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Memory type */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisMemoryOperandType` enum. + */ +typedef enum ZydisMemoryOperandType_ +{ + ZYDIS_MEMOP_TYPE_INVALID, + /** + * Normal memory operand. + */ + ZYDIS_MEMOP_TYPE_MEM, + /** + * The memory operand is only used for address-generation. No real memory-access is + * caused. + */ + ZYDIS_MEMOP_TYPE_AGEN, + /** + * A memory operand using `SIB` addressing form, where the index register is not used + * in address calculation and scale is ignored. No real memory-access is caused. + */ + ZYDIS_MEMOP_TYPE_MIB, + + /** + * Maximum value of this enum. + */ + ZYDIS_MEMOP_TYPE_MAX_VALUE = ZYDIS_MEMOP_TYPE_MIB, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_MEMOP_TYPE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_MEMOP_TYPE_MAX_VALUE) +} ZydisMemoryOperandType; + +/* ---------------------------------------------------------------------------------------------- */ +/* Decoded operand */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisDecodedOperand` struct. + */ +typedef struct ZydisDecodedOperand_ +{ + /** + * The operand-id. + */ + ZyanU8 id; + /** + * The type of the operand. + */ + ZydisOperandType type; + /** + * The visibility of the operand. + */ + ZydisOperandVisibility visibility; + /** + * The operand-actions. + */ + ZydisOperandActions actions; + /** + * The operand-encoding. + */ + ZydisOperandEncoding encoding; + /** + * The logical size of the operand (in bits). + */ + ZyanU16 size; + /** + * The element-type. + */ + ZydisElementType element_type; + /** + * The size of a single element. + */ + ZydisElementSize element_size; + /** + * The number of elements. + */ + ZyanU16 element_count; + /** + * Extended info for register-operands. + */ + struct ZydisDecodedOperandReg_ + { + /** + * The register value. + */ + ZydisRegister value; + // TODO: AVX512_4VNNIW MULTISOURCE registers + } reg; + /** + * Extended info for memory-operands. + */ + struct ZydisDecodedOperandMem_ + { + /** + * The type of the memory operand. + */ + ZydisMemoryOperandType type; + /** + * The segment register. + */ + ZydisRegister segment; + /** + * The base register. + */ + ZydisRegister base; + /** + * The index register. + */ + ZydisRegister index; + /** + * The scale factor. + */ + ZyanU8 scale; + /** + * Extended info for memory-operands with displacement. + */ + struct ZydisDecodedOperandMemDisp_ + { + /** + * Signals, if the displacement value is used. + */ + ZyanBool has_displacement; + /** + * The displacement value + */ + ZyanI64 value; + } disp; + } mem; + /** + * Extended info for pointer-operands. + */ + struct ZydisDecodedOperandPtr_ + { + ZyanU16 segment; + ZyanU32 offset; + } ptr; + /** + * Extended info for immediate-operands. + */ + struct ZydisDecodedOperandImm_ + { + /** + * Signals, if the immediate value is signed. + */ + ZyanBool is_signed; + /** + * Signals, if the immediate value contains a relative offset. You can use + * `ZydisCalcAbsoluteAddress` to determine the absolute address value. + */ + ZyanBool is_relative; + /** + * The immediate value. + */ + union ZydisDecodedOperandImmValue_ + { + ZyanU64 u; + ZyanI64 s; + } value; + } imm; +} ZydisDecodedOperand; + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Decoded instruction */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Instruction attributes */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisInstructionAttributes` data-type. + */ +typedef ZyanU64 ZydisInstructionAttributes; + +/** + * The instruction has the `ModRM` byte. + */ +#define ZYDIS_ATTRIB_HAS_MODRM 0x0000000000000001 // (1 << 0) +/** + * The instruction has the `SIB` byte. + */ +#define ZYDIS_ATTRIB_HAS_SIB 0x0000000000000002 // (1 << 1) +/** + * The instruction has the `REX` prefix. + */ +#define ZYDIS_ATTRIB_HAS_REX 0x0000000000000004 // (1 << 2) +/** + * The instruction has the `XOP` prefix. + */ +#define ZYDIS_ATTRIB_HAS_XOP 0x0000000000000008 // (1 << 3) +/** + * The instruction has the `VEX` prefix. + */ +#define ZYDIS_ATTRIB_HAS_VEX 0x0000000000000010 // (1 << 4) +/** + * The instruction has the `EVEX` prefix. + */ +#define ZYDIS_ATTRIB_HAS_EVEX 0x0000000000000020 // (1 << 5) +/** + * The instruction has the `MVEX` prefix. + */ +#define ZYDIS_ATTRIB_HAS_MVEX 0x0000000000000040 // (1 << 6) +/** + * The instruction has one or more operands with position-relative offsets. + */ +#define ZYDIS_ATTRIB_IS_RELATIVE 0x0000000000000080 // (1 << 7) +/** + * The instruction is privileged. + * + * Privileged instructions are any instructions that require a current ring level below 3. + */ +#define ZYDIS_ATTRIB_IS_PRIVILEGED 0x0000000000000100 // (1 << 8) + +/** + * The instruction accesses one or more CPU-flags. + */ +#define ZYDIS_ATTRIB_CPUFLAG_ACCESS 0x0000001000000000 // (1 << 36) // TODO: rebase + +/** + * The instruction may conditionally read the general CPU state. + */ +#define ZYDIS_ATTRIB_CPU_STATE_CR 0x0000002000000000 // (1 << 37) // TODO: rebase +/** + * The instruction may conditionally write the general CPU state. + */ +#define ZYDIS_ATTRIB_CPU_STATE_CW 0x0000004000000000 // (1 << 38) // TODO: rebase +/** + * The instruction may conditionally read the FPU state (X87, MMX). + */ +#define ZYDIS_ATTRIB_FPU_STATE_CR 0x0000008000000000 // (1 << 39) // TODO: rebase +/** + * The instruction may conditionally write the FPU state (X87, MMX). + */ +#define ZYDIS_ATTRIB_FPU_STATE_CW 0x0000010000000000 // (1 << 40) // TODO: rebase +/** + * The instruction may conditionally read the XMM state (AVX, AVX2, AVX-512). + */ +#define ZYDIS_ATTRIB_XMM_STATE_CR 0x0000020000000000 // (1 << 41) // TODO: rebase +/** + * The instruction may conditionally write the XMM state (AVX, AVX2, AVX-512). + */ +#define ZYDIS_ATTRIB_XMM_STATE_CW 0x0000040000000000 // (1 << 42) // TODO: rebase + +/** + * The instruction accepts the `LOCK` prefix (`0xF0`). + */ +#define ZYDIS_ATTRIB_ACCEPTS_LOCK 0x0000000000000200 // (1 << 9) +/** + * The instruction accepts the `REP` prefix (`0xF3`). + */ +#define ZYDIS_ATTRIB_ACCEPTS_REP 0x0000000000000400 // (1 << 10) +/** + * The instruction accepts the `REPE`/`REPZ` prefix (`0xF3`). + */ +#define ZYDIS_ATTRIB_ACCEPTS_REPE 0x0000000000000800 // (1 << 11) +/** + * The instruction accepts the `REPE`/`REPZ` prefix (`0xF3`). + */ +#define ZYDIS_ATTRIB_ACCEPTS_REPZ 0x0000000000000800 // (1 << 11) +/** + * The instruction accepts the `REPNE`/`REPNZ` prefix (`0xF2`). + */ +#define ZYDIS_ATTRIB_ACCEPTS_REPNE 0x0000000000001000 // (1 << 12) +/** + * The instruction accepts the `REPNE`/`REPNZ` prefix (`0xF2`). + */ +#define ZYDIS_ATTRIB_ACCEPTS_REPNZ 0x0000000000001000 // (1 << 12) +/** + * The instruction accepts the `BND` prefix (`0xF2`). + */ +#define ZYDIS_ATTRIB_ACCEPTS_BND 0x0000000000002000 // (1 << 13) +/** + * The instruction accepts the `XACQUIRE` prefix (`0xF2`). + */ +#define ZYDIS_ATTRIB_ACCEPTS_XACQUIRE 0x0000000000004000 // (1 << 14) +/** + * The instruction accepts the `XRELEASE` prefix (`0xF3`). + */ +#define ZYDIS_ATTRIB_ACCEPTS_XRELEASE 0x0000000000008000 // (1 << 15) +/** + * The instruction accepts the `XACQUIRE`/`XRELEASE` prefixes (`0xF2`, `0xF3`) + * without the `LOCK` prefix (`0x0F`). + */ +#define ZYDIS_ATTRIB_ACCEPTS_HLE_WITHOUT_LOCK 0x0000000000010000 // (1 << 16) +/** + * The instruction accepts branch hints (0x2E, 0x3E). + */ +#define ZYDIS_ATTRIB_ACCEPTS_BRANCH_HINTS 0x0000000000020000 // (1 << 17) +/** + * The instruction accepts segment prefixes (`0x2E`, `0x36`, `0x3E`, `0x26`, + * `0x64`, `0x65`). + */ +#define ZYDIS_ATTRIB_ACCEPTS_SEGMENT 0x0000000000040000 // (1 << 18) +/** + * The instruction has the `LOCK` prefix (`0xF0`). + */ +#define ZYDIS_ATTRIB_HAS_LOCK 0x0000000000080000 // (1 << 19) +/** + * The instruction has the `REP` prefix (`0xF3`). + */ +#define ZYDIS_ATTRIB_HAS_REP 0x0000000000100000 // (1 << 20) +/** + * The instruction has the `REPE`/`REPZ` prefix (`0xF3`). + */ +#define ZYDIS_ATTRIB_HAS_REPE 0x0000000000200000 // (1 << 21) +/** + * The instruction has the `REPE`/`REPZ` prefix (`0xF3`). + */ +#define ZYDIS_ATTRIB_HAS_REPZ 0x0000000000200000 // (1 << 21) +/** + * The instruction has the `REPNE`/`REPNZ` prefix (`0xF2`). + */ +#define ZYDIS_ATTRIB_HAS_REPNE 0x0000000000400000 // (1 << 22) +/** + * The instruction has the `REPNE`/`REPNZ` prefix (`0xF2`). + */ +#define ZYDIS_ATTRIB_HAS_REPNZ 0x0000000000400000 // (1 << 22) +/** + * The instruction has the `BND` prefix (`0xF2`). + */ +#define ZYDIS_ATTRIB_HAS_BND 0x0000000000800000 // (1 << 23) +/** + * The instruction has the `XACQUIRE` prefix (`0xF2`). + */ +#define ZYDIS_ATTRIB_HAS_XACQUIRE 0x0000000001000000 // (1 << 24) +/** + * The instruction has the `XRELEASE` prefix (`0xF3`). + */ +#define ZYDIS_ATTRIB_HAS_XRELEASE 0x0000000002000000 // (1 << 25) +/** + * The instruction has the branch-not-taken hint (`0x2E`). + */ +#define ZYDIS_ATTRIB_HAS_BRANCH_NOT_TAKEN 0x0000000004000000 // (1 << 26) +/** + * The instruction has the branch-taken hint (`0x3E`). + */ +#define ZYDIS_ATTRIB_HAS_BRANCH_TAKEN 0x0000000008000000 // (1 << 27) +/** + * The instruction has a segment modifier. + */ +#define ZYDIS_ATTRIB_HAS_SEGMENT 0x00000003F0000000 +/** + * The instruction has the `CS` segment modifier (`0x2E`). + */ +#define ZYDIS_ATTRIB_HAS_SEGMENT_CS 0x0000000010000000 // (1 << 28) +/** + * The instruction has the `SS` segment modifier (`0x36`). + */ +#define ZYDIS_ATTRIB_HAS_SEGMENT_SS 0x0000000020000000 // (1 << 29) +/** + * The instruction has the `DS` segment modifier (`0x3E`). + */ +#define ZYDIS_ATTRIB_HAS_SEGMENT_DS 0x0000000040000000 // (1 << 30) +/** + * The instruction has the `ES` segment modifier (`0x26`). + */ +#define ZYDIS_ATTRIB_HAS_SEGMENT_ES 0x0000000080000000 // (1 << 31) +/** + * The instruction has the `FS` segment modifier (`0x64`). + */ +#define ZYDIS_ATTRIB_HAS_SEGMENT_FS 0x0000000100000000 // (1 << 32) +/** + * The instruction has the `GS` segment modifier (`0x65`). + */ +#define ZYDIS_ATTRIB_HAS_SEGMENT_GS 0x0000000200000000 // (1 << 33) +/** + * The instruction has the operand-size override prefix (`0x66`). + */ +#define ZYDIS_ATTRIB_HAS_OPERANDSIZE 0x0000000400000000 // (1 << 34) // TODO: rename +/** + * The instruction has the address-size override prefix (`0x67`). + */ +#define ZYDIS_ATTRIB_HAS_ADDRESSSIZE 0x0000000800000000 // (1 << 35) // TODO: rename + +/* ---------------------------------------------------------------------------------------------- */ +/* R/E/FLAGS info */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisCPUFlags` data-type. + */ +typedef ZyanU32 ZydisCPUFlags; + +/** + * Defines the `ZydisCPUFlag` data-type. + */ +typedef ZyanU8 ZydisCPUFlag; + +/** + * Carry flag. + */ +#define ZYDIS_CPUFLAG_CF 0 +/** + * Parity flag. + */ +#define ZYDIS_CPUFLAG_PF 2 +/** + * Adjust flag. + */ +#define ZYDIS_CPUFLAG_AF 4 +/** + * Zero flag. + */ +#define ZYDIS_CPUFLAG_ZF 6 +/** + * Sign flag. + */ +#define ZYDIS_CPUFLAG_SF 7 +/** + * Trap flag. + */ +#define ZYDIS_CPUFLAG_TF 8 +/** + * Interrupt enable flag. + */ +#define ZYDIS_CPUFLAG_IF 9 +/** + * Direction flag. + */ +#define ZYDIS_CPUFLAG_DF 10 +/** + * Overflow flag. + */ +#define ZYDIS_CPUFLAG_OF 11 +/** + * I/O privilege level flag. + */ +#define ZYDIS_CPUFLAG_IOPL 12 +/** + * Nested task flag. + */ +#define ZYDIS_CPUFLAG_NT 14 +/** + * Resume flag. + */ +#define ZYDIS_CPUFLAG_RF 16 +/** + * Virtual 8086 mode flag. + */ +#define ZYDIS_CPUFLAG_VM 17 +/** + * Alignment check. + */ +#define ZYDIS_CPUFLAG_AC 18 +/** + * Virtual interrupt flag. + */ +#define ZYDIS_CPUFLAG_VIF 19 +/** + * Virtual interrupt pending. + */ +#define ZYDIS_CPUFLAG_VIP 20 +/** + * Able to use CPUID instruction. + */ +#define ZYDIS_CPUFLAG_ID 21 + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * FPU condition-code flag 0. + * + * DEPRECATED. This flag is not actually part of `FLAGS/EFLAGS/RFLAGS` and will be removed in the + * next major release. Please refer to the `fpu_flags_read`/`fpu_flags_written` field instead and + * use one of the `ZYDIS_FPUFLAG_XXX` masks to check for specific a flag. + */ +#define ZYDIS_CPUFLAG_C0 22 +/** + * FPU condition-code flag 1. + * + * DEPRECATED. This flag is not actually part of `FLAGS/EFLAGS/RFLAGS` and will be removed in the + * next major release. Please refer to the `fpu_flags_read`/`fpu_flags_written` field instead and + * use one of the `ZYDIS_FPUFLAG_XXX` masks to check for specific a flag. + */ +#define ZYDIS_CPUFLAG_C1 23 +/** + * FPU condition-code flag 2. + * + * DEPRECATED. This flag is not actually part of `FLAGS/EFLAGS/RFLAGS` and will be removed in the + * next major release. Please refer to the `fpu_flags_read`/`fpu_flags_written` field instead and + * use one of the `ZYDIS_FPUFLAG_XXX` masks to check for specific a flag. + */ +#define ZYDIS_CPUFLAG_C2 24 +/** + * FPU condition-code flag 3. + * + * DEPRECATED. This flag is not actually part of `FLAGS/EFLAGS/RFLAGS` and will be removed in the + * next major release. Please refer to the `fpu_flags_read`/`fpu_flags_written` field instead and + * use one of the `ZYDIS_FPUFLAG_XXX` masks to check for specific a flag. + */ +#define ZYDIS_CPUFLAG_C3 25 + +/** + * DEPRECATED. This define will be removed in the next major release. + */ +#define ZYDIS_CPUFLAG_MAX_VALUE ZYDIS_CPUFLAG_C3 + + /////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Defines the `ZydisFPUFlags` data-type. + */ +typedef ZyanU8 ZydisFPUFlags; + +/** + * FPU condition-code flag 0. + */ +#define ZYDIS_FPUFLAG_C0 0x00 // (1 << 0) +/** + * FPU condition-code flag 1. + */ +#define ZYDIS_FPUFLAG_C1 0x01 // (1 << 1) + /** + * FPU condition-code flag 2. + */ +#define ZYDIS_FPUFLAG_C2 0x02 // (1 << 2) +/** + * FPU condition-code flag 3. + */ +#define ZYDIS_FPUFLAG_C3 0x04 // (1 << 3) + +/** + * Defines the `ZydisCPUFlagAction` enum. + * + * DEPRECATED. This enum will be removed in the next major release. + */ +typedef enum ZydisCPUFlagAction_ +{ + /** + * The CPU flag is not touched by the instruction. + */ + ZYDIS_CPUFLAG_ACTION_NONE, + /** + * The CPU flag is tested (read). + */ + ZYDIS_CPUFLAG_ACTION_TESTED, + /** + * The CPU flag is tested and modified afterwards (read-write). + */ + ZYDIS_CPUFLAG_ACTION_TESTED_MODIFIED, + /** + * The CPU flag is modified (write). + */ + ZYDIS_CPUFLAG_ACTION_MODIFIED, + /** + * The CPU flag is set to 0 (write). + */ + ZYDIS_CPUFLAG_ACTION_SET_0, + /** + * The CPU flag is set to 1 (write). + */ + ZYDIS_CPUFLAG_ACTION_SET_1, + /** + * The CPU flag is undefined (write). + */ + ZYDIS_CPUFLAG_ACTION_UNDEFINED, + + /** + * Maximum value of this enum. + */ + ZYDIS_CPUFLAG_ACTION_MAX_VALUE = ZYDIS_CPUFLAG_ACTION_UNDEFINED, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_CPUFLAG_ACTION_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_CPUFLAG_ACTION_MAX_VALUE) +} ZydisCPUFlagAction; + +/* ---------------------------------------------------------------------------------------------- */ +/* Branch types */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisBranchType` enum. + */ +typedef enum ZydisBranchType_ +{ + /** + * The instruction is not a branch instruction. + */ + ZYDIS_BRANCH_TYPE_NONE, + /** + * The instruction is a short (8-bit) branch instruction. + */ + ZYDIS_BRANCH_TYPE_SHORT, + /** + * The instruction is a near (16-bit or 32-bit) branch instruction. + */ + ZYDIS_BRANCH_TYPE_NEAR, + /** + * The instruction is a far (inter-segment) branch instruction. + */ + ZYDIS_BRANCH_TYPE_FAR, + + /** + * Maximum value of this enum. + */ + ZYDIS_BRANCH_TYPE_MAX_VALUE = ZYDIS_BRANCH_TYPE_FAR, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_BRANCH_TYPE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_BRANCH_TYPE_MAX_VALUE) +} ZydisBranchType; + +/* ---------------------------------------------------------------------------------------------- */ +/* SSE/AVX exception-class */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisExceptionClass` enum. + */ +typedef enum ZydisExceptionClass_ +{ + ZYDIS_EXCEPTION_CLASS_NONE, + // TODO: FP Exceptions + ZYDIS_EXCEPTION_CLASS_SSE1, + ZYDIS_EXCEPTION_CLASS_SSE2, + ZYDIS_EXCEPTION_CLASS_SSE3, + ZYDIS_EXCEPTION_CLASS_SSE4, + ZYDIS_EXCEPTION_CLASS_SSE5, + ZYDIS_EXCEPTION_CLASS_SSE7, + ZYDIS_EXCEPTION_CLASS_AVX1, + ZYDIS_EXCEPTION_CLASS_AVX2, + ZYDIS_EXCEPTION_CLASS_AVX3, + ZYDIS_EXCEPTION_CLASS_AVX4, + ZYDIS_EXCEPTION_CLASS_AVX5, + ZYDIS_EXCEPTION_CLASS_AVX6, + ZYDIS_EXCEPTION_CLASS_AVX7, + ZYDIS_EXCEPTION_CLASS_AVX8, + ZYDIS_EXCEPTION_CLASS_AVX11, + ZYDIS_EXCEPTION_CLASS_AVX12, + ZYDIS_EXCEPTION_CLASS_E1, + ZYDIS_EXCEPTION_CLASS_E1NF, + ZYDIS_EXCEPTION_CLASS_E2, + ZYDIS_EXCEPTION_CLASS_E2NF, + ZYDIS_EXCEPTION_CLASS_E3, + ZYDIS_EXCEPTION_CLASS_E3NF, + ZYDIS_EXCEPTION_CLASS_E4, + ZYDIS_EXCEPTION_CLASS_E4NF, + ZYDIS_EXCEPTION_CLASS_E5, + ZYDIS_EXCEPTION_CLASS_E5NF, + ZYDIS_EXCEPTION_CLASS_E6, + ZYDIS_EXCEPTION_CLASS_E6NF, + ZYDIS_EXCEPTION_CLASS_E7NM, + ZYDIS_EXCEPTION_CLASS_E7NM128, + ZYDIS_EXCEPTION_CLASS_E9NF, + ZYDIS_EXCEPTION_CLASS_E10, + ZYDIS_EXCEPTION_CLASS_E10NF, + ZYDIS_EXCEPTION_CLASS_E11, + ZYDIS_EXCEPTION_CLASS_E11NF, + ZYDIS_EXCEPTION_CLASS_E12, + ZYDIS_EXCEPTION_CLASS_E12NP, + ZYDIS_EXCEPTION_CLASS_K20, + ZYDIS_EXCEPTION_CLASS_K21, + ZYDIS_EXCEPTION_CLASS_AMXE1, + ZYDIS_EXCEPTION_CLASS_AMXE2, + ZYDIS_EXCEPTION_CLASS_AMXE3, + ZYDIS_EXCEPTION_CLASS_AMXE4, + ZYDIS_EXCEPTION_CLASS_AMXE5, + ZYDIS_EXCEPTION_CLASS_AMXE6, + + /** + * Maximum value of this enum. + */ + ZYDIS_EXCEPTION_CLASS_MAX_VALUE = ZYDIS_EXCEPTION_CLASS_AMXE6, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_EXCEPTION_CLASS_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_EXCEPTION_CLASS_MAX_VALUE) +} ZydisExceptionClass; + +/* ---------------------------------------------------------------------------------------------- */ +/* AVX mask mode */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisMaskMode` enum. + */ +typedef enum ZydisMaskMode_ +{ + ZYDIS_MASK_MODE_INVALID, + /** + * Masking is disabled for the current instruction (`K0` register is used). + */ + ZYDIS_MASK_MODE_DISABLED, + /** + * The embedded mask register is used as a merge-mask. + */ + ZYDIS_MASK_MODE_MERGING, + /** + * The embedded mask register is used as a zero-mask. + */ + ZYDIS_MASK_MODE_ZEROING, + /** + * The embedded mask register is used as a control-mask (element selector). + */ + ZYDIS_MASK_MODE_CONTROL, + /** + * The embedded mask register is used as a zeroing control-mask (element selector). + */ + ZYDIS_MASK_MODE_CONTROL_ZEROING, + + /** + * Maximum value of this enum. + */ + ZYDIS_MASK_MODE_MAX_VALUE = ZYDIS_MASK_MODE_CONTROL_ZEROING, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_MASK_MODE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_MASK_MODE_MAX_VALUE) +} ZydisMaskMode; + +/* ---------------------------------------------------------------------------------------------- */ +/* AVX broadcast-mode */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisBroadcastMode` enum. + */ +typedef enum ZydisBroadcastMode_ +{ + ZYDIS_BROADCAST_MODE_INVALID, + ZYDIS_BROADCAST_MODE_1_TO_2, + ZYDIS_BROADCAST_MODE_1_TO_4, + ZYDIS_BROADCAST_MODE_1_TO_8, + ZYDIS_BROADCAST_MODE_1_TO_16, + ZYDIS_BROADCAST_MODE_1_TO_32, + ZYDIS_BROADCAST_MODE_1_TO_64, + ZYDIS_BROADCAST_MODE_2_TO_4, + ZYDIS_BROADCAST_MODE_2_TO_8, + ZYDIS_BROADCAST_MODE_2_TO_16, + ZYDIS_BROADCAST_MODE_4_TO_8, + ZYDIS_BROADCAST_MODE_4_TO_16, + ZYDIS_BROADCAST_MODE_8_TO_16, + + /** + * Maximum value of this enum. + */ + ZYDIS_BROADCAST_MODE_MAX_VALUE = ZYDIS_BROADCAST_MODE_8_TO_16, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_BROADCAST_MODE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_BROADCAST_MODE_MAX_VALUE) +} ZydisBroadcastMode; + +/* ---------------------------------------------------------------------------------------------- */ +/* AVX rounding-mode */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisRoundingMode` enum. + */ +typedef enum ZydisRoundingMode_ +{ + ZYDIS_ROUNDING_MODE_INVALID, + /** + * Round to nearest. + */ + ZYDIS_ROUNDING_MODE_RN, + /** + * Round down. + */ + ZYDIS_ROUNDING_MODE_RD, + /** + * Round up. + */ + ZYDIS_ROUNDING_MODE_RU, + /** + * Round towards zero. + */ + ZYDIS_ROUNDING_MODE_RZ, + + /** + * Maximum value of this enum. + */ + ZYDIS_ROUNDING_MODE_MAX_VALUE = ZYDIS_ROUNDING_MODE_RZ, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_ROUNDING_MODE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_ROUNDING_MODE_MAX_VALUE) +} ZydisRoundingMode; + +/* ---------------------------------------------------------------------------------------------- */ +/* KNC swizzle-mode */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisSwizzleMode` enum. + */ +typedef enum ZydisSwizzleMode_ +{ + ZYDIS_SWIZZLE_MODE_INVALID, + ZYDIS_SWIZZLE_MODE_DCBA, + ZYDIS_SWIZZLE_MODE_CDAB, + ZYDIS_SWIZZLE_MODE_BADC, + ZYDIS_SWIZZLE_MODE_DACB, + ZYDIS_SWIZZLE_MODE_AAAA, + ZYDIS_SWIZZLE_MODE_BBBB, + ZYDIS_SWIZZLE_MODE_CCCC, + ZYDIS_SWIZZLE_MODE_DDDD, + + /** + * Maximum value of this enum. + */ + ZYDIS_SWIZZLE_MODE_MAX_VALUE = ZYDIS_SWIZZLE_MODE_DDDD, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_SWIZZLE_MODE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_SWIZZLE_MODE_MAX_VALUE) +} ZydisSwizzleMode; + +/* ---------------------------------------------------------------------------------------------- */ +/* KNC conversion-mode */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisConversionMode` enum. + */ +typedef enum ZydisConversionMode_ +{ + ZYDIS_CONVERSION_MODE_INVALID, + ZYDIS_CONVERSION_MODE_FLOAT16, + ZYDIS_CONVERSION_MODE_SINT8, + ZYDIS_CONVERSION_MODE_UINT8, + ZYDIS_CONVERSION_MODE_SINT16, + ZYDIS_CONVERSION_MODE_UINT16, + + /** + * Maximum value of this enum. + */ + ZYDIS_CONVERSION_MODE_MAX_VALUE = ZYDIS_CONVERSION_MODE_UINT16, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_CONVERSION_MODE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_CONVERSION_MODE_MAX_VALUE) +} ZydisConversionMode; + +/* ---------------------------------------------------------------------------------------------- */ +/* Legacy prefix type */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisPrefixType` enum. + */ +typedef enum ZydisPrefixType_ +{ + /** + * The prefix is ignored by the instruction. + * + * This applies to all prefixes that are not accepted by the instruction in general or the + * ones that are overwritten by a prefix of the same group closer to the instruction opcode. + */ + ZYDIS_PREFIX_TYPE_IGNORED, + /** + * The prefix is effectively used by the instruction. + */ + ZYDIS_PREFIX_TYPE_EFFECTIVE, + /** + * The prefix is used as a mandatory prefix. + * + * A mandatory prefix is interpreted as an opcode extension and has no further effect on the + * instruction. + */ + ZYDIS_PREFIX_TYPE_MANDATORY, + + /** + * Maximum value of this enum. + */ + ZYDIS_PREFIX_TYPE_MAX_VALUE = ZYDIS_PREFIX_TYPE_MANDATORY, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_PREFIX_TYPE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_PREFIX_TYPE_MAX_VALUE) +} ZydisPrefixType; + +// TODO: Check effective for 66/67 prefixes (currently defaults to EFFECTIVE) + +/* ---------------------------------------------------------------------------------------------- */ +/* Decoded instruction */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Information about a decoded instruction. + */ +typedef struct ZydisDecodedInstruction_ +{ + /** + * The machine mode used to decode this instruction. + */ + ZydisMachineMode machine_mode; + /** + * The instruction-mnemonic. + */ + ZydisMnemonic mnemonic; + /** + * The length of the decoded instruction. + */ + ZyanU8 length; + /** + * The instruction-encoding (`LEGACY`, `3DNOW`, `VEX`, `EVEX`, `XOP`). + */ + ZydisInstructionEncoding encoding; + /** + * The opcode-map. + */ + ZydisOpcodeMap opcode_map; + /** + * The instruction-opcode. + */ + ZyanU8 opcode; + /** + * The stack width. + */ + ZyanU8 stack_width; + /** + * The effective operand width. + */ + ZyanU8 operand_width; + /** + * The effective address width. + */ + ZyanU8 address_width; + /** + * The number of instruction-operands. + */ + ZyanU8 operand_count; + /** + * Detailed info for all instruction operands. + * + * Explicit operands are guaranteed to be in the front and ordered as they are printed + * by the formatter in Intel mode. No assumptions can be made about the order of hidden + * operands, except that they always located behind the explicit operands. + */ + ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT]; + /** + * Instruction attributes. + */ + ZydisInstructionAttributes attributes; + /** + * Information about accessed CPU flags. + * + * DEPRECATED. This field will be removed in the next major release. Please use the + * `cpu_flags_read`/`cpu_flags_written` or `fpu_flags_read`/`fpu_flags_written` fields + * instead. + */ + struct ZydisDecodedInstructionAccessedFlags_ + { + /** + * The CPU-flag action. + * + * Use `ZydisGetAccessedFlagsByAction` to get a mask with all flags matching a specific + * action. + */ + ZydisCPUFlagAction action; + } accessed_flags[ZYDIS_CPUFLAG_MAX_VALUE + 1]; + /** + * A mask containing the CPU flags read by the instruction. + * + * The bits in this mask correspond to the actual bits in the `FLAGS/EFLAGS/RFLAGS` + * register. + * + * This mask includes the actions `TESTED` and `TESTED_MODIFIED`. + */ + ZydisCPUFlags cpu_flags_read; + /** + * A mask containing the CPU flags written by the instruction. + * + * The bits in this mask correspond to the actual bits in the `FLAGS/EFLAGS/RFLAGS` + * register. + * + * This mask includes the actions `TESTED_MODIFIED`, `SET_0`, `SET_1` and `UNDEFINED`. + */ + ZydisCPUFlags cpu_flags_written; + /** + * A mask containing the FPU flags read by the instruction. + */ + ZydisFPUFlags fpu_flags_read; + /** + * A mask containing the FPU flags written by the instruction. + */ + ZydisFPUFlags fpu_flags_written; + /** + * Extended info for `AVX` instructions. + */ + struct ZydisDecodedInstructionAvx_ + { + /** + * The `AVX` vector-length. + */ + ZyanU16 vector_length; + /** + * Info about the embedded writemask-register (`AVX-512` and `KNC` only). + */ + struct ZydisDecodedInstructionAvxMask_ + { + /** + * The masking mode. + */ + ZydisMaskMode mode; + /** + * The mask register. + */ + ZydisRegister reg; + } mask; + /** + * Contains info about the `AVX` broadcast. + */ + struct ZydisDecodedInstructionAvxBroadcast_ + { + /** + * Signals, if the broadcast is a static broadcast. + * + * This is the case for instructions with inbuilt broadcast functionality, which is + * always active and not controlled by the `EVEX/MVEX.RC` bits. + */ + ZyanBool is_static; + /** + * The `AVX` broadcast-mode. + */ + ZydisBroadcastMode mode; + } broadcast; + /** + * Contains info about the `AVX` rounding. + */ + struct ZydisDecodedInstructionAvxRounding_ + { + /** + * The `AVX` rounding-mode. + */ + ZydisRoundingMode mode; + } rounding; + /** + * Contains info about the `AVX` register-swizzle (`KNC` only). + */ + struct ZydisDecodedInstructionAvxSwizzle_ + { + /** + * The `AVX` register-swizzle mode. + */ + ZydisSwizzleMode mode; + } swizzle; + /** + * Contains info about the `AVX` data-conversion (`KNC` only). + */ + struct ZydisDecodedInstructionAvxConversion_ + { + /** + * The `AVX` data-conversion mode. + */ + ZydisConversionMode mode; + } conversion; + /** + * Signals, if the `SAE` (suppress-all-exceptions) functionality is + * enabled for the instruction. + */ + ZyanBool has_sae; + /** + * Signals, if the instruction has a memory-eviction-hint (`KNC` only). + */ + ZyanBool has_eviction_hint; + // TODO: publish EVEX tuple-type and MVEX functionality + } avx; + /** + * Meta info. + */ + struct ZydisDecodedInstructionMeta_ + { + /** + * The instruction category. + */ + ZydisInstructionCategory category; + /** + * The ISA-set. + */ + ZydisISASet isa_set; + /** + * The ISA-set extension. + */ + ZydisISAExt isa_ext; + /** + * The branch type. + */ + ZydisBranchType branch_type; + /** + * The exception class. + */ + ZydisExceptionClass exception_class; + } meta; + /** + * Detailed info about different instruction-parts like `ModRM`, `SIB` or + * encoding-prefixes. + */ + struct ZydisDecodedInstructionRaw_ + { + /** + * The number of legacy prefixes. + */ + ZyanU8 prefix_count; + /** + * Detailed info about the legacy prefixes (including `REX`). + */ + struct ZydisDecodedInstructionRawPrefixes_ + { + /** + * The prefix type. + */ + ZydisPrefixType type; + /** + * The prefix byte. + */ + ZyanU8 value; + } prefixes[ZYDIS_MAX_INSTRUCTION_LENGTH]; + /** + * Detailed info about the `REX` prefix. + */ + struct ZydisDecodedInstructionRawRex_ + { + /** + * 64-bit operand-size promotion. + */ + ZyanU8 W; + /** + * Extension of the `ModRM.reg` field. + */ + ZyanU8 R; + /** + * Extension of the `SIB.index` field. + */ + ZyanU8 X; + /** + * Extension of the `ModRM.rm`, `SIB.base`, or `opcode.reg` field. + */ + ZyanU8 B; + /** + * The offset of the effective `REX` byte, relative to the beginning of the + * instruction, in bytes. + * + * This offset always points to the "effective" `REX` prefix (the one closest to the + * instruction opcode), if multiple `REX` prefixes are present. + * + * Note that the `REX` byte can be the first byte of the instruction, which would lead + * to an offset of `0`. Please refer to the instruction attributes to check for the + * presence of the `REX` prefix. + */ + ZyanU8 offset; + } rex; + /** + * Detailed info about the `XOP` prefix. + */ + struct ZydisDecodedInstructionRawXop_ + { + /** + * Extension of the `ModRM.reg` field (inverted). + */ + ZyanU8 R; + /** + * Extension of the `SIB.index` field (inverted). + */ + ZyanU8 X; + /** + * Extension of the `ModRM.rm`, `SIB.base`, or `opcode.reg` field (inverted). + */ + ZyanU8 B; + /** + * Opcode-map specifier. + */ + ZyanU8 m_mmmm; + /** + * 64-bit operand-size promotion or opcode-extension. + */ + ZyanU8 W; + /** + * `NDS`/`NDD` (non-destructive-source/destination) register + * specifier (inverted). + */ + ZyanU8 vvvv; + /** + * Vector-length specifier. + */ + ZyanU8 L; + /** + * Compressed legacy prefix. + */ + ZyanU8 pp; + /** + * The offset of the first xop byte, relative to the beginning of + * the instruction, in bytes. + */ + ZyanU8 offset; + } xop; + /** + * Detailed info about the `VEX` prefix. + */ + struct ZydisDecodedInstructionRawVex_ + { + /** + * Extension of the `ModRM.reg` field (inverted). + */ + ZyanU8 R; + /** + * Extension of the `SIB.index` field (inverted). + */ + ZyanU8 X; + /** + * Extension of the `ModRM.rm`, `SIB.base`, or `opcode.reg` field (inverted). + */ + ZyanU8 B; + /** + * Opcode-map specifier. + */ + ZyanU8 m_mmmm; + /** + * 64-bit operand-size promotion or opcode-extension. + */ + ZyanU8 W; + /** + * `NDS`/`NDD` (non-destructive-source/destination) register specifier + * (inverted). + */ + ZyanU8 vvvv; + /** + * Vector-length specifier. + */ + ZyanU8 L; + /** + * Compressed legacy prefix. + */ + ZyanU8 pp; + /** + * The offset of the first `VEX` byte, relative to the beginning of the instruction, in + * bytes. + */ + ZyanU8 offset; + /** + * The size of the `VEX` prefix, in bytes. + */ + ZyanU8 size; + } vex; + /** + * Detailed info about the `EVEX` prefix. + */ + struct ZydisDecodedInstructionRawEvex_ + { + /** + * Extension of the `ModRM.reg` field (inverted). + */ + ZyanU8 R; + /** + * Extension of the `SIB.index/vidx` field (inverted). + */ + ZyanU8 X; + /** + * Extension of the `ModRM.rm` or `SIB.base` field (inverted). + */ + ZyanU8 B; + /** + * High-16 register specifier modifier (inverted). + */ + ZyanU8 R2; + /** + * Opcode-map specifier. + */ + ZyanU8 mm; + /** + * 64-bit operand-size promotion or opcode-extension. + */ + ZyanU8 W; + /** + * `NDS`/`NDD` (non-destructive-source/destination) register specifier + * (inverted). + */ + ZyanU8 vvvv; + /** + * Compressed legacy prefix. + */ + ZyanU8 pp; + /** + * Zeroing/Merging. + */ + ZyanU8 z; + /** + * Vector-length specifier or rounding-control (most significant bit). + */ + ZyanU8 L2; + /** + * Vector-length specifier or rounding-control (least significant bit). + */ + ZyanU8 L; + /** + * Broadcast/RC/SAE context. + */ + ZyanU8 b; + /** + * High-16 `NDS`/`VIDX` register specifier. + */ + ZyanU8 V2; + /** + * Embedded opmask register specifier. + */ + ZyanU8 aaa; + /** + * The offset of the first evex byte, relative to the beginning of the + * instruction, in bytes. + */ + ZyanU8 offset; + } evex; + /** + * Detailed info about the `MVEX` prefix. + */ + struct ZydisDecodedInstructionRawMvex_ + { + /** + * Extension of the `ModRM.reg` field (inverted). + */ + ZyanU8 R; + /** + * Extension of the `SIB.index/vidx` field (inverted). + */ + ZyanU8 X; + /** + * Extension of the `ModRM.rm` or `SIB.base` field (inverted). + */ + ZyanU8 B; + /** + * High-16 register specifier modifier (inverted). + */ + ZyanU8 R2; + /** + * Opcode-map specifier. + */ + ZyanU8 mmmm; + /** + * 64-bit operand-size promotion or opcode-extension. + */ + ZyanU8 W; + /** + * `NDS`/`NDD` (non-destructive-source/destination) register specifier + * (inverted). + */ + ZyanU8 vvvv; + /** + * Compressed legacy prefix. + */ + ZyanU8 pp; + /** + * Non-temporal/eviction hint. + */ + ZyanU8 E; + /** + * Swizzle/broadcast/up-convert/down-convert/static-rounding controls. + */ + ZyanU8 SSS; + /** + * High-16 `NDS`/`VIDX` register specifier. + */ + ZyanU8 V2; + /** + * Embedded opmask register specifier. + */ + ZyanU8 kkk; + /** + * The offset of the first mvex byte, relative to the beginning of the + * instruction, in bytes. + */ + ZyanU8 offset; + } mvex; + /** + * Detailed info about the `ModRM` byte. + */ + struct ZydisDecodedInstructionModRm_ + { + /** + * The addressing mode. + */ + ZyanU8 mod; + /** + * Register specifier or opcode-extension. + */ + ZyanU8 reg; + /** + * Register specifier or opcode-extension. + */ + ZyanU8 rm; + /** + * The offset of the `ModRM` byte, relative to the beginning of the + * instruction, in bytes. + */ + ZyanU8 offset; + } modrm; + /** + * Detailed info about the `SIB` byte. + */ + struct ZydisDecodedInstructionRawSib_ + { + /** + * The scale factor. + */ + ZyanU8 scale; + /** + * The index-register specifier. + */ + ZyanU8 index; + /** + * The base-register specifier. + */ + ZyanU8 base; + /** + * The offset of the `SIB` byte, relative to the beginning of the + * instruction, in bytes. + */ + ZyanU8 offset; + } sib; + /** + * Detailed info about displacement-bytes. + */ + struct ZydisDecodedInstructionRawDisp_ + { + /** + * The displacement value + */ + ZyanI64 value; + /** + * The physical displacement size, in bits. + */ + ZyanU8 size; + // TODO: publish cd8 scale + /** + * The offset of the displacement data, relative to the beginning of the + * instruction, in bytes. + */ + ZyanU8 offset; + } disp; + /** + * Detailed info about immediate-bytes. + */ + struct ZydisDecodedInstructionRawImm_ + { + /** + * Signals, if the immediate value is signed. + */ + ZyanBool is_signed; + /** + * Signals, if the immediate value contains a relative offset. You can use + * `ZydisCalcAbsoluteAddress` to determine the absolute address value. + */ + ZyanBool is_relative; + /** + * The immediate value. + */ + union ZydisDecodedInstructionRawImmValue_ + { + ZyanU64 u; + ZyanI64 s; + } value; + /** + * The physical immediate size, in bits. + */ + ZyanU8 size; + /** + * The offset of the immediate data, relative to the beginning of the + * instruction, in bytes. + */ + ZyanU8 offset; + } imm[2]; + } raw; +} ZydisDecodedInstruction; + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYDIS_INSTRUCTIONINFO_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Formatter.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Formatter.h new file mode 100644 index 0000000..c68bcde --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Formatter.h @@ -0,0 +1,1179 @@ +/*************************************************************************************************** + + Zyan Disassembler Library (Zydis) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Functions for formatting instructions to human-readable text. + */ + +#ifndef ZYDIS_FORMATTER_H +#define ZYDIS_FORMATTER_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Constants */ +/* ============================================================================================== */ + +/** + * Use this constant as value for `runtime_address` in `ZydisFormatterFormatInstruction(Ex)` + * or `ZydisFormatterFormatOperand(Ex)` to print relative values for all addresses. + */ +#define ZYDIS_RUNTIME_ADDRESS_NONE (ZyanU64)(-1) + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Formatter style */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisFormatterStyle` enum. + */ +typedef enum ZydisFormatterStyle_ +{ + /** + * Generates `AT&T`-style disassembly. + */ + ZYDIS_FORMATTER_STYLE_ATT, + /** + * Generates `Intel`-style disassembly. + */ + ZYDIS_FORMATTER_STYLE_INTEL, + /** + * Generates `MASM`-style disassembly that is directly accepted as input for + * the `MASM` assembler. + * + * The runtime-address is ignored in this mode. + */ + ZYDIS_FORMATTER_STYLE_INTEL_MASM, + + /** + * Maximum value of this enum. + */ + ZYDIS_FORMATTER_STYLE_MAX_VALUE = ZYDIS_FORMATTER_STYLE_INTEL_MASM, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_FORMATTER_STYLE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_FORMATTER_STYLE_MAX_VALUE) +} ZydisFormatterStyle; + +/* ---------------------------------------------------------------------------------------------- */ +/* Properties */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisFormatterProperty` enum. + */ +typedef enum ZydisFormatterProperty_ +{ + /* ---------------------------------------------------------------------------------------- */ + /* General */ + /* ---------------------------------------------------------------------------------------- */ + + /** + * Controls the printing of effective operand-size suffixes (`AT&T`) or operand-sizes + * of memory operands (`INTEL`). + * + * Pass `ZYAN_TRUE` as value to force the formatter to always print the size, or `ZYAN_FALSE` + * to only print it if needed. + */ + ZYDIS_FORMATTER_PROP_FORCE_SIZE, + /** + * Controls the printing of segment prefixes. + * + * Pass `ZYAN_TRUE` as value to force the formatter to always print the segment register of + * memory-operands or `ZYAN_FALSE` to omit implicit `DS`/`SS` segments. + */ + ZYDIS_FORMATTER_PROP_FORCE_SEGMENT, + /** + * Controls the printing of branch addresses. + * + * Pass `ZYAN_TRUE` as value to force the formatter to always print relative branch addresses + * or `ZYAN_FALSE` to use absolute addresses, if a runtime-address different to + * `ZYDIS_RUNTIME_ADDRESS_NONE` was passed. + */ + ZYDIS_FORMATTER_PROP_FORCE_RELATIVE_BRANCHES, + /** + * Controls the printing of `EIP`/`RIP`-relative addresses. + * + * Pass `ZYAN_TRUE` as value to force the formatter to always print relative addresses for + * `EIP`/`RIP`-relative operands or `ZYAN_FALSE` to use absolute addresses, if a runtime- + * address different to `ZYDIS_RUNTIME_ADDRESS_NONE` was passed. + */ + ZYDIS_FORMATTER_PROP_FORCE_RELATIVE_RIPREL, + /** + * Controls the printing of branch-instructions sizes. + * + * Pass `ZYAN_TRUE` as value to print the size (`short`, `near`) of branch + * instructions or `ZYAN_FALSE` to hide it. + * + * Note that the `far`/`l` modifier is always printed. + */ + ZYDIS_FORMATTER_PROP_PRINT_BRANCH_SIZE, + + /** + * Controls the printing of instruction prefixes. + * + * Pass `ZYAN_TRUE` as value to print all instruction-prefixes (even ignored or duplicate + * ones) or `ZYAN_FALSE` to only print prefixes that are effectively used by the instruction. + */ + ZYDIS_FORMATTER_PROP_DETAILED_PREFIXES, + + /* ---------------------------------------------------------------------------------------- */ + /* Numeric values */ + /* ---------------------------------------------------------------------------------------- */ + + /** + * Controls the base of address values. + */ + ZYDIS_FORMATTER_PROP_ADDR_BASE, + /** + * Controls the signedness of relative addresses. Absolute addresses are + * always unsigned. + */ + ZYDIS_FORMATTER_PROP_ADDR_SIGNEDNESS, + /** + * Controls the padding of absolute address values. + * + * Pass `ZYDIS_PADDING_DISABLED` to disable padding, `ZYDIS_PADDING_AUTO` to padd all + * addresses to the current stack width (hexadecimal only), or any other integer value for + * custom padding. + */ + ZYDIS_FORMATTER_PROP_ADDR_PADDING_ABSOLUTE, + /** + * Controls the padding of relative address values. + * + * Pass `ZYDIS_PADDING_DISABLED` to disable padding, `ZYDIS_PADDING_AUTO` to padd all + * addresses to the current stack width (hexadecimal only), or any other integer value for + * custom padding. + */ + ZYDIS_FORMATTER_PROP_ADDR_PADDING_RELATIVE, + + /* ---------------------------------------------------------------------------------------- */ + + /** + * Controls the base of displacement values. + */ + ZYDIS_FORMATTER_PROP_DISP_BASE, + /** + * Controls the signedness of displacement values. + */ + ZYDIS_FORMATTER_PROP_DISP_SIGNEDNESS, + /** + * Controls the padding of displacement values. + * + * Pass `ZYDIS_PADDING_DISABLED` to disable padding, or any other integer value for custom + * padding. + */ + ZYDIS_FORMATTER_PROP_DISP_PADDING, + + /* ---------------------------------------------------------------------------------------- */ + + /** + * Controls the base of immediate values. + */ + ZYDIS_FORMATTER_PROP_IMM_BASE, + /** + * Controls the signedness of immediate values. + * + * Pass `ZYDIS_SIGNEDNESS_AUTO` to automatically choose the most suitable mode based on the + * operands `ZydisDecodedOperand.imm.is_signed` attribute. + */ + ZYDIS_FORMATTER_PROP_IMM_SIGNEDNESS, + /** + * Controls the padding of immediate values. + * + * Pass `ZYDIS_PADDING_DISABLED` to disable padding, `ZYDIS_PADDING_AUTO` to padd all + * immediates to the operand-width (hexadecimal only), or any other integer value for custom + * padding. + */ + ZYDIS_FORMATTER_PROP_IMM_PADDING, + + /* ---------------------------------------------------------------------------------------- */ + /* Text formatting */ + /* ---------------------------------------------------------------------------------------- */ + + /** + * Controls the letter-case for prefixes. + * + * Pass `ZYAN_TRUE` as value to format in uppercase or `ZYAN_FALSE` to format in lowercase. + */ + ZYDIS_FORMATTER_PROP_UPPERCASE_PREFIXES, + /** + * Controls the letter-case for the mnemonic. + * + * Pass `ZYAN_TRUE` as value to format in uppercase or `ZYAN_FALSE` to format in lowercase. + */ + ZYDIS_FORMATTER_PROP_UPPERCASE_MNEMONIC, + /** + * Controls the letter-case for registers. + * + * Pass `ZYAN_TRUE` as value to format in uppercase or `ZYAN_FALSE` to format in lowercase. + */ + ZYDIS_FORMATTER_PROP_UPPERCASE_REGISTERS, + /** + * Controls the letter-case for typecasts. + * + * Pass `ZYAN_TRUE` as value to format in uppercase or `ZYAN_FALSE` to format in lowercase. + */ + ZYDIS_FORMATTER_PROP_UPPERCASE_TYPECASTS, + /** + * Controls the letter-case for decorators. + * + * Pass `ZYAN_TRUE` as value to format in uppercase or `ZYAN_FALSE` to format in lowercase. + */ + ZYDIS_FORMATTER_PROP_UPPERCASE_DECORATORS, + + /* ---------------------------------------------------------------------------------------- */ + /* Number formatting */ + /* ---------------------------------------------------------------------------------------- */ + + /** + * Controls the prefix for decimal values. + * + * Pass a pointer to a null-terminated C-style string with a maximum length of 10 characters + * to set a custom prefix, or `ZYAN_NULL` to disable it. + * + * The string is deep-copied into an internal buffer. + */ + ZYDIS_FORMATTER_PROP_DEC_PREFIX, + /** + * Controls the suffix for decimal values. + * + * Pass a pointer to a null-terminated C-style string with a maximum length of 10 characters + * to set a custom suffix, or `ZYAN_NULL` to disable it. + * + * The string is deep-copied into an internal buffer. + */ + ZYDIS_FORMATTER_PROP_DEC_SUFFIX, + + /* ---------------------------------------------------------------------------------------- */ + + /** + * Controls the letter-case of hexadecimal values. + * + * Pass `ZYAN_TRUE` as value to format in uppercase and `ZYAN_FALSE` to format in lowercase. + * + * The default value is `ZYAN_TRUE`. + */ + ZYDIS_FORMATTER_PROP_HEX_UPPERCASE, + /** + * Controls the prefix for hexadecimal values. + * + * Pass a pointer to a null-terminated C-style string with a maximum length of 10 characters + * to set a custom prefix, or `ZYAN_NULL` to disable it. + * + * The string is deep-copied into an internal buffer. + */ + ZYDIS_FORMATTER_PROP_HEX_PREFIX, + /** + * Controls the suffix for hexadecimal values. + * + * Pass a pointer to a null-terminated C-style string with a maximum length of 10 characters + * to set a custom suffix, or `ZYAN_NULL` to disable it. + * + * The string is deep-copied into an internal buffer. + */ + ZYDIS_FORMATTER_PROP_HEX_SUFFIX, + + /* ---------------------------------------------------------------------------------------- */ + + /** + * Maximum value of this enum. + */ + ZYDIS_FORMATTER_PROP_MAX_VALUE = ZYDIS_FORMATTER_PROP_HEX_SUFFIX, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_FORMATTER_PROP_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_FORMATTER_PROP_MAX_VALUE) +} ZydisFormatterProperty; + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisNumericBase` enum. + */ +typedef enum ZydisNumericBase_ +{ + /** + * Decimal system. + */ + ZYDIS_NUMERIC_BASE_DEC, + /** + * Hexadecimal system. + */ + ZYDIS_NUMERIC_BASE_HEX, + + /** + * Maximum value of this enum. + */ + ZYDIS_NUMERIC_BASE_MAX_VALUE = ZYDIS_NUMERIC_BASE_HEX, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_NUMERIC_BASE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_NUMERIC_BASE_MAX_VALUE) +} ZydisNumericBase; + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisSignedness` enum. + */ +typedef enum ZydisSignedness_ +{ + /** + * Automatically choose the most suitable mode based on the operands + * ZydisDecodedOperand.imm.is_signed` attribute. + */ + ZYDIS_SIGNEDNESS_AUTO, + /** + * Force signed values. + */ + ZYDIS_SIGNEDNESS_SIGNED, + /** + * Force unsigned values. + */ + ZYDIS_SIGNEDNESS_UNSIGNED, + + /** + * Maximum value of this enum. + */ + ZYDIS_SIGNEDNESS_MAX_VALUE = ZYDIS_SIGNEDNESS_UNSIGNED, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_SIGNEDNESS_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_SIGNEDNESS_MAX_VALUE) +} ZydisSignedness; + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisPadding` enum. + */ +typedef enum ZydisPadding_ +{ + /** + * Disables padding. + */ + ZYDIS_PADDING_DISABLED = 0, + /** + * Padds the value to the current stack-width for addresses, or to the + * operand-width for immediate values (hexadecimal only). + */ + ZYDIS_PADDING_AUTO = (-1), + + /** + * Maximum value of this enum. + */ + ZYDIS_PADDING_MAX_VALUE = ZYDIS_PADDING_AUTO, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_PADDING_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_PADDING_MAX_VALUE) +} ZydisPadding; + +/* ---------------------------------------------------------------------------------------------- */ +/* Function types */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisFormatterFunction` enum. + * + * Do NOT change the order of the values this enum or the function fields inside the + * `ZydisFormatter` struct. + */ +typedef enum ZydisFormatterFunction_ +{ + /* ---------------------------------------------------------------------------------------- */ + /* Instruction */ + /* ---------------------------------------------------------------------------------------- */ + + /** + * This function is invoked before the formatter formats an instruction. + */ + ZYDIS_FORMATTER_FUNC_PRE_INSTRUCTION, + /** + * This function is invoked after the formatter formatted an instruction. + */ + ZYDIS_FORMATTER_FUNC_POST_INSTRUCTION, + + /* ---------------------------------------------------------------------------------------- */ + + /** + * This function refers to the main formatting function. + * + * Replacing this function allows for complete custom formatting, but indirectly disables all + * other hooks except for `ZYDIS_FORMATTER_FUNC_PRE_INSTRUCTION` and + * `ZYDIS_FORMATTER_FUNC_POST_INSTRUCTION`. + */ + ZYDIS_FORMATTER_FUNC_FORMAT_INSTRUCTION, + + /* ---------------------------------------------------------------------------------------- */ + /* Operands */ + /* ---------------------------------------------------------------------------------------- */ + + /** + * This function is invoked before the formatter formats an operand. + */ + ZYDIS_FORMATTER_FUNC_PRE_OPERAND, + /** + * This function is invoked after the formatter formatted an operand. + */ + ZYDIS_FORMATTER_FUNC_POST_OPERAND, + + /* ---------------------------------------------------------------------------------------- */ + + /** + * This function is invoked to format a register operand. + */ + ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_REG, + /** + * This function is invoked to format a memory operand. + * + * Replacing this function might indirectly disable some specific calls to the + * `ZYDIS_FORMATTER_FUNC_PRINT_TYPECAST`, `ZYDIS_FORMATTER_FUNC_PRINT_SEGMENT`, + * `ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_ABS` and `ZYDIS_FORMATTER_FUNC_PRINT_DISP` functions. + */ + ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_MEM, + /** + * This function is invoked to format a pointer operand. + */ + ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_PTR, + /** + * This function is invoked to format an immediate operand. + * + * Replacing this function might indirectly disable some specific calls to the + * `ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_ABS`, `ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_REL` and + * `ZYDIS_FORMATTER_FUNC_PRINT_IMM` functions. + */ + ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_IMM, + + /* ---------------------------------------------------------------------------------------- */ + /* Elemental tokens */ + /* ---------------------------------------------------------------------------------------- */ + + /** + * This function is invoked to print the instruction mnemonic. + */ + ZYDIS_FORMATTER_FUNC_PRINT_MNEMONIC, + + /* ---------------------------------------------------------------------------------------- */ + + /** + * This function is invoked to print a register. + */ + ZYDIS_FORMATTER_FUNC_PRINT_REGISTER, + /** + * This function is invoked to print absolute addresses. + * + * Conditionally invoked, if a runtime-address different to `ZYDIS_RUNTIME_ADDRESS_NONE` was + * passed: + * - `IMM` operands with relative address (e.g. `JMP`, `CALL`, ...) + * - `MEM` operands with `EIP`/`RIP`-relative address (e.g. `MOV RAX, [RIP+0x12345678]`) + * + * Always invoked for: + * - `MEM` operands with absolute address (e.g. `MOV RAX, [0x12345678]`) + */ + ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_ABS, + /** + * This function is invoked to print relative addresses. + * + * Conditionally invoked, if `ZYDIS_RUNTIME_ADDRESS_NONE` was passed as runtime-address: + * - `IMM` operands with relative address (e.g. `JMP`, `CALL`, ...) + */ + ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_REL, + /** + * This function is invoked to print a memory displacement value. + * + * If the memory displacement contains an address and a runtime-address different to + * `ZYDIS_RUNTIME_ADDRESS_NONE` was passed, `ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_ABS` is called + * instead. + */ + ZYDIS_FORMATTER_FUNC_PRINT_DISP, + /** + * This function is invoked to print an immediate value. + * + * If the immediate contains an address and a runtime-address different to + * `ZYDIS_RUNTIME_ADDRESS_NONE` was passed, `ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_ABS` is called + * instead. + * + * If the immediate contains an address and `ZYDIS_RUNTIME_ADDRESS_NONE` was passed as + * runtime-address, `ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_REL` is called instead. + */ + ZYDIS_FORMATTER_FUNC_PRINT_IMM, + + /* ---------------------------------------------------------------------------------------- */ + /* Optional tokens */ + /* ---------------------------------------------------------------------------------------- */ + + /** + * This function is invoked to print the size of a memory operand (`INTEL` only). + */ + ZYDIS_FORMATTER_FUNC_PRINT_TYPECAST, + /** + * This function is invoked to print the segment-register of a memory operand. + */ + ZYDIS_FORMATTER_FUNC_PRINT_SEGMENT, + /** + * This function is invoked to print the instruction prefixes. + */ + ZYDIS_FORMATTER_FUNC_PRINT_PREFIXES, + /** + * This function is invoked after formatting an operand to print a `EVEX`/`MVEX` + * decorator. + */ + ZYDIS_FORMATTER_FUNC_PRINT_DECORATOR, + + /* ---------------------------------------------------------------------------------------- */ + + /** + * Maximum value of this enum. + */ + ZYDIS_FORMATTER_FUNC_MAX_VALUE = ZYDIS_FORMATTER_FUNC_PRINT_DECORATOR, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_FORMATTER_FUNC_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_FORMATTER_FUNC_MAX_VALUE) +} ZydisFormatterFunction; + +/* ---------------------------------------------------------------------------------------------- */ +/* Decorator types */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisDecorator` enum. + */ +typedef enum ZydisDecorator_ +{ + ZYDIS_DECORATOR_INVALID, + /** + * The embedded-mask decorator. + */ + ZYDIS_DECORATOR_MASK, + /** + * The broadcast decorator. + */ + ZYDIS_DECORATOR_BC, + /** + * The rounding-control decorator. + */ + ZYDIS_DECORATOR_RC, + /** + * The suppress-all-exceptions decorator. + */ + ZYDIS_DECORATOR_SAE, + /** + * The register-swizzle decorator. + */ + ZYDIS_DECORATOR_SWIZZLE, + /** + * The conversion decorator. + */ + ZYDIS_DECORATOR_CONVERSION, + /** + * The eviction-hint decorator. + */ + ZYDIS_DECORATOR_EH, + + /** + * Maximum value of this enum. + */ + ZYDIS_DECORATOR_MAX_VALUE = ZYDIS_DECORATOR_EH, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_DECORATOR_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_DECORATOR_MAX_VALUE) +} ZydisDecorator; + +/* ---------------------------------------------------------------------------------------------- */ +/* Formatter context */ +/* ---------------------------------------------------------------------------------------------- */ + +typedef struct ZydisFormatter_ ZydisFormatter; + +/** + * Defines the `ZydisFormatterContext` struct. + */ +typedef struct ZydisFormatterContext_ +{ + /** + * A pointer to the `ZydisDecodedInstruction` struct. + */ + const ZydisDecodedInstruction* instruction; + /** + * A pointer to the `ZydisDecodedOperand` struct. + */ + const ZydisDecodedOperand* operand; + /** + * The runtime address of the instruction. + */ + ZyanU64 runtime_address; + /** + * A pointer to user-defined data. + */ + void* user_data; +} ZydisFormatterContext; + +/* ---------------------------------------------------------------------------------------------- */ +/* Function prototypes */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisFormatterFunc` function prototype. + * + * @param formatter A pointer to the `ZydisFormatter` instance. + * @param buffer A pointer to the `ZydisFormatterBuffer` struct. + * @param context A pointer to the `ZydisFormatterContext` struct. + * + * @return A zyan status code. + * + * Returning a status code other than `ZYAN_STATUS_SUCCESS` will immediately cause the formatting + * process to fail (see exceptions below). + * + * Returning `ZYDIS_STATUS_SKIP_TOKEN` is valid for functions of the following types and will + * instruct the formatter to omit the whole operand: + * - `ZYDIS_FORMATTER_FUNC_PRE_OPERAND` + * - `ZYDIS_FORMATTER_FUNC_POST_OPERAND` + * - `ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_REG` + * - `ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_MEM` + * - `ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_PTR` + * - `ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_IMM` + * + * This function prototype is used by functions of the following types: + * - `ZYDIS_FORMATTER_FUNC_PRE_INSTRUCTION` + * - `ZYDIS_FORMATTER_FUNC_POST_INSTRUCTION` + * - `ZYDIS_FORMATTER_FUNC_PRE_OPERAND` + * - `ZYDIS_FORMATTER_FUNC_POST_OPERAND` + * - `ZYDIS_FORMATTER_FUNC_FORMAT_INSTRUCTION` + * - `ZYDIS_FORMATTER_FUNC_PRINT_MNEMONIC` + * - `ZYDIS_FORMATTER_FUNC_PRINT_PREFIXES` + * - `ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_REG` + * - `ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_MEM` + * - `ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_PTR` + * - `ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_IMM` + * - `ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_ABS` + * - `ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_REL` + * - `ZYDIS_FORMATTER_FUNC_PRINT_DISP` + * - `ZYDIS_FORMATTER_FUNC_PRINT_IMM` + * - `ZYDIS_FORMATTER_FUNC_PRINT_TYPECAST` + * - `ZYDIS_FORMATTER_FUNC_PRINT_SEGMENT` + */ +typedef ZyanStatus (*ZydisFormatterFunc)(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + + /** + * Defines the `ZydisFormatterRegisterFunc` function prototype. + * + * @param formatter A pointer to the `ZydisFormatter` instance. + * @param buffer A pointer to the `ZydisFormatterBuffer` struct. + * @param context A pointer to the `ZydisFormatterContext` struct. + * @param reg The register. + * + * @return Returning a status code other than `ZYAN_STATUS_SUCCESS` will immediately cause the + * formatting process to fail. + * + * This function prototype is used by functions of the following types: + * - `ZYDIS_FORMATTER_FUNC_PRINT_REGISTER`. + */ +typedef ZyanStatus (*ZydisFormatterRegisterFunc)(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisRegister reg); + +/** + * Defines the `ZydisFormatterDecoratorFunc` function prototype. + * + * @param formatter A pointer to the `ZydisFormatter` instance. + * @param buffer A pointer to the `ZydisFormatterBuffer` struct. + * @param context A pointer to the `ZydisFormatterContext` struct. + * @param decorator The decorator type. + * + * @return Returning a status code other than `ZYAN_STATUS_SUCCESS` will immediately cause the + * formatting process to fail. + * + * This function type is used for: + * - `ZYDIS_FORMATTER_FUNC_PRINT_DECORATOR` + */ +typedef ZyanStatus (*ZydisFormatterDecoratorFunc)(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisDecorator decorator); + +/* ---------------------------------------------------------------------------------------------- */ +/* Formatter struct */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisFormatter` struct. + * + * All fields in this struct should be considered as "private". Any changes may lead to unexpected + * behavior. + * + * Do NOT change the order of the function fields or the values of the `ZydisFormatterFunction` + * enum. + */ +struct ZydisFormatter_ +{ + /** + * The formatter style. + */ + ZydisFormatterStyle style; + /** + * The `ZYDIS_FORMATTER_PROP_FORCE_SIZE` property. + */ + ZyanBool force_memory_size; + /** + * The `ZYDIS_FORMATTER_PROP_FORCE_SEGMENT` property. + */ + ZyanBool force_memory_segment; + /** + * The `ZYDIS_FORMATTER_PROP_FORCE_RELATIVE_BRANCHES` property. + */ + ZyanBool force_relative_branches; + /** + * The `ZYDIS_FORMATTER_PROP_FORCE_RELATIVE_RIPREL` property. + */ + ZyanBool force_relative_riprel; + /** + * The `ZYDIS_FORMATTER_PROP_PRINT_BRANCH_SIZE` property. + */ + ZyanBool print_branch_size; + /** + * The `ZYDIS_FORMATTER_DETAILED_PREFIXES` property. + */ + ZyanBool detailed_prefixes; + /** + * The `ZYDIS_FORMATTER_ADDR_BASE` property. + */ + ZydisNumericBase addr_base; + /** + * The `ZYDIS_FORMATTER_ADDR_SIGNEDNESS` property. + */ + ZydisSignedness addr_signedness; + /** + * The `ZYDIS_FORMATTER_ADDR_PADDING_ABSOLUTE` property. + */ + ZydisPadding addr_padding_absolute; + /** + * The `ZYDIS_FORMATTER_ADDR_PADDING_RELATIVE` property. + */ + ZydisPadding addr_padding_relative; + /** + * The `ZYDIS_FORMATTER_DISP_BASE` property. + */ + ZydisNumericBase disp_base; + /** + * The `ZYDIS_FORMATTER_DISP_SIGNEDNESS` property. + */ + ZydisSignedness disp_signedness; + /** + * The `ZYDIS_FORMATTER_DISP_PADDING` property. + */ + ZydisPadding disp_padding; + /** + * The `ZYDIS_FORMATTER_IMM_BASE` property. + */ + ZydisNumericBase imm_base; + /** + * The `ZYDIS_FORMATTER_IMM_SIGNEDNESS` property. + */ + ZydisSignedness imm_signedness; + /** + * The `ZYDIS_FORMATTER_IMM_PADDING` property. + */ + ZydisPadding imm_padding; + /** + * The `ZYDIS_FORMATTER_UPPERCASE_PREFIXES` property. + */ + ZyanI32 case_prefixes; + /** + * The `ZYDIS_FORMATTER_UPPERCASE_MNEMONIC` property. + */ + ZyanI32 case_mnemonic; + /** + * The `ZYDIS_FORMATTER_UPPERCASE_REGISTERS` property. + */ + ZyanI32 case_registers; + /** + * The `ZYDIS_FORMATTER_UPPERCASE_TYPECASTS` property. + */ + ZyanI32 case_typecasts; + /** + * The `ZYDIS_FORMATTER_UPPERCASE_DECORATORS` property. + */ + ZyanI32 case_decorators; + /** + * The `ZYDIS_FORMATTER_HEX_UPPERCASE` property. + */ + ZyanBool hex_uppercase; + /** + * The number formats for all numeric bases. + * + * Index 0 = prefix + * Index 1 = suffix + */ + struct + { + /** + * A pointer to the `ZyanStringView` to use as prefix/suffix. + */ + const ZyanStringView* string; + /** + * The `ZyanStringView` to use as prefix/suffix + */ + ZyanStringView string_data; + /** + * The actual string data. + */ + char buffer[11]; + } number_format[ZYDIS_NUMERIC_BASE_MAX_VALUE + 1][2]; + /** + * The `ZYDIS_FORMATTER_FUNC_PRE_INSTRUCTION` function. + */ + ZydisFormatterFunc func_pre_instruction; + /** + * The `ZYDIS_FORMATTER_FUNC_POST_INSTRUCTION` function. + */ + ZydisFormatterFunc func_post_instruction; + /** + * The `ZYDIS_FORMATTER_FUNC_FORMAT_INSTRUCTION` function. + */ + ZydisFormatterFunc func_format_instruction; + /** + * The `ZYDIS_FORMATTER_FUNC_PRE_OPERAND` function. + */ + ZydisFormatterFunc func_pre_operand; + /** + * The `ZYDIS_FORMATTER_FUNC_POST_OPERAND` function. + */ + ZydisFormatterFunc func_post_operand; + /** + * The `ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_REG` function. + */ + ZydisFormatterFunc func_format_operand_reg; + /** + * The `ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_MEM` function. + */ + ZydisFormatterFunc func_format_operand_mem; + /** + * The `ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_PTR` function. + */ + ZydisFormatterFunc func_format_operand_ptr; + /** + * The `ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_IMM` function. + */ + ZydisFormatterFunc func_format_operand_imm; + /** + * The `ZYDIS_FORMATTER_FUNC_PRINT_MNEMONIC function. + */ + ZydisFormatterFunc func_print_mnemonic; + /** + * The `ZYDIS_FORMATTER_FUNC_PRINT_REGISTER` function. + */ + ZydisFormatterRegisterFunc func_print_register; + /** + * The `ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_ABS` function. + */ + ZydisFormatterFunc func_print_address_abs; + /** + * The `ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_REL` function. + */ + ZydisFormatterFunc func_print_address_rel; + /** + * The `ZYDIS_FORMATTER_FUNC_PRINT_DISP` function. + */ + ZydisFormatterFunc func_print_disp; + /** + * The `ZYDIS_FORMATTER_FUNC_PRINT_IMM` function. + */ + ZydisFormatterFunc func_print_imm; + /** + * The `ZYDIS_FORMATTER_FUNC_PRINT_TYPECAST` function. + */ + ZydisFormatterFunc func_print_typecast; + /** + * The `ZYDIS_FORMATTER_FUNC_PRINT_SEGMENT` function. + */ + ZydisFormatterFunc func_print_segment; + /** + * The `ZYDIS_FORMATTER_FUNC_PRINT_PREFIXES` function. + */ + ZydisFormatterFunc func_print_prefixes; + /** + * The `ZYDIS_FORMATTER_FUNC_PRINT_DECORATOR` function. + */ + ZydisFormatterDecoratorFunc func_print_decorator; +}; + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/** + * @addtogroup formatter Formatter + * Functions allowing formatting of previously decoded instructions to human readable text. + * @{ + */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Initialization */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Initializes the given `ZydisFormatter` instance. + * + * @param formatter A pointer to the `ZydisFormatter` instance. + * @param style The base formatter style (either `AT&T` or `Intel` style). + * + * @return A zyan status code. + */ +ZYDIS_EXPORT ZyanStatus ZydisFormatterInit(ZydisFormatter* formatter, ZydisFormatterStyle style); + +/* ---------------------------------------------------------------------------------------------- */ +/* Setter */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Changes the value of the specified formatter `property`. + * + * @param formatter A pointer to the `ZydisFormatter` instance. + * @param property The id of the formatter-property. + * @param value The new value. + * + * @return A zyan status code. + * + * This function returns `ZYAN_STATUS_INVALID_OPERATION` if a property can't be changed for the + * current formatter-style. + */ +ZYDIS_EXPORT ZyanStatus ZydisFormatterSetProperty(ZydisFormatter* formatter, + ZydisFormatterProperty property, ZyanUPointer value); + +/** + * Replaces a formatter function with a custom callback and/or retrieves the currently + * used function. + * + * @param formatter A pointer to the `ZydisFormatter` instance. + * @param type The formatter function-type. + * @param callback A pointer to a variable that contains the pointer of the callback function + * and receives the pointer of the currently used function. + * + * @return A zyan status code. + * + * Call this function with `callback` pointing to a `ZYAN_NULL` value to retrieve the currently + * used function without replacing it. + * + * This function returns `ZYAN_STATUS_INVALID_OPERATION` if a function can't be replaced for the + * current formatter-style. + */ +ZYDIS_EXPORT ZyanStatus ZydisFormatterSetHook(ZydisFormatter* formatter, + ZydisFormatterFunction type, const void** callback); + +/* ---------------------------------------------------------------------------------------------- */ +/* Formatting */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Formats the given instruction and writes it into the output buffer. + * + * @param formatter A pointer to the `ZydisFormatter` instance. + * @param instruction A pointer to the `ZydisDecodedInstruction` struct. + * @param buffer A pointer to the output buffer. + * @param length The length of the output buffer (in characters). + * @param runtime_address The runtime address of the instruction or `ZYDIS_RUNTIME_ADDRESS_NONE` + * to print relative addresses. + * + * @return A zyan status code. + */ +ZYDIS_EXPORT ZyanStatus ZydisFormatterFormatInstruction(const ZydisFormatter* formatter, + const ZydisDecodedInstruction* instruction, char* buffer, ZyanUSize length, + ZyanU64 runtime_address); + +/** + * Formats the given instruction and writes it into the output buffer. + * + * @param formatter A pointer to the `ZydisFormatter` instance. + * @param instruction A pointer to the `ZydisDecodedInstruction` struct. + * @param buffer A pointer to the output buffer. + * @param length The length of the output buffer (in characters). + * @param runtime_address The runtime address of the instruction or `ZYDIS_RUNTIME_ADDRESS_NONE` + * to print relative addresses. + * @param user_data A pointer to user-defined data which can be used in custom formatter + * callbacks. + * + * @return A zyan status code. + */ +ZYDIS_EXPORT ZyanStatus ZydisFormatterFormatInstructionEx(const ZydisFormatter* formatter, + const ZydisDecodedInstruction* instruction, char* buffer, ZyanUSize length, + ZyanU64 runtime_address, void* user_data); + +/** + * Formats the given operand and writes it into the output buffer. + * + * @param formatter A pointer to the `ZydisFormatter` instance. + * @param instruction A pointer to the `ZydisDecodedInstruction` struct. + * @param index The index of the operand to format. + * @param buffer A pointer to the output buffer. + * @param length The length of the output buffer (in characters). + * @param runtime_address The runtime address of the instruction or `ZYDIS_RUNTIME_ADDRESS_NONE` + * to print relative addresses. + * + * @return A zyan status code. + * + * Use `ZydisFormatterFormatInstruction` or `ZydisFormatterFormatInstructionEx` to format a + * complete instruction. + */ +ZYDIS_EXPORT ZyanStatus ZydisFormatterFormatOperand(const ZydisFormatter* formatter, + const ZydisDecodedInstruction* instruction, ZyanU8 index, char* buffer, ZyanUSize length, + ZyanU64 runtime_address); + +/** + * Formats the given operand and writes it into the output buffer. + * + * @param formatter A pointer to the `ZydisFormatter` instance. + * @param instruction A pointer to the `ZydisDecodedInstruction` struct. + * @param index The index of the operand to format. + * @param buffer A pointer to the output buffer. + * @param length The length of the output buffer (in characters). + * @param runtime_address The runtime address of the instruction or `ZYDIS_RUNTIME_ADDRESS_NONE` + * to print relative addresses. + * @param user_data A pointer to user-defined data which can be used in custom formatter + * callbacks. + * + * @return A zyan status code. + * + * Use `ZydisFormatterFormatInstruction` or `ZydisFormatterFormatInstructionEx` to format a + * complete instruction. + */ +ZYDIS_EXPORT ZyanStatus ZydisFormatterFormatOperandEx(const ZydisFormatter* formatter, + const ZydisDecodedInstruction* instruction, ZyanU8 index, char* buffer, ZyanUSize length, + ZyanU64 runtime_address, void* user_data); + +/* ---------------------------------------------------------------------------------------------- */ +/* Tokenizing */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Tokenizes the given instruction and writes it into the output buffer. + * + * @param formatter A pointer to the `ZydisFormatter` instance. + * @param instruction A pointer to the `ZydisDecodedInstruction` struct. + * @param buffer A pointer to the output buffer. + * @param length The length of the output buffer (in bytes). + * @param runtime_address The runtime address of the instruction or `ZYDIS_RUNTIME_ADDRESS_NONE` + * to print relative addresses. + * @param token Receives a pointer to the first token in the output buffer. + * + * @return A zyan status code. + */ +ZYDIS_EXPORT ZyanStatus ZydisFormatterTokenizeInstruction(const ZydisFormatter* formatter, + const ZydisDecodedInstruction* instruction, void* buffer, ZyanUSize length, + ZyanU64 runtime_address, ZydisFormatterTokenConst** token); + +/** + * Tokenizes the given instruction and writes it into the output buffer. + * + * @param formatter A pointer to the `ZydisFormatter` instance. + * @param instruction A pointer to the `ZydisDecodedInstruction` struct. + * @param buffer A pointer to the output buffer. + * @param length The length of the output buffer (in bytes). + * @param runtime_address The runtime address of the instruction or `ZYDIS_RUNTIME_ADDRESS_NONE` + * to print relative addresses. + * @param token Receives a pointer to the first token in the output buffer. + * @param user_data A pointer to user-defined data which can be used in custom formatter + * callbacks. + * + * @return A zyan status code. + */ +ZYDIS_EXPORT ZyanStatus ZydisFormatterTokenizeInstructionEx(const ZydisFormatter* formatter, + const ZydisDecodedInstruction* instruction, void* buffer, ZyanUSize length, + ZyanU64 runtime_address, ZydisFormatterTokenConst** token, void* user_data); + +/** + * Tokenizes the given operand and writes it into the output buffer. + * + * @param formatter A pointer to the `ZydisFormatter` instance. + * @param instruction A pointer to the `ZydisDecodedInstruction` struct. + * @param index The index of the operand to format. + * @param buffer A pointer to the output buffer. + * @param length The length of the output buffer (in bytes). + * @param runtime_address The runtime address of the instruction or `ZYDIS_RUNTIME_ADDRESS_NONE` + * to print relative addresses. + * @param token Receives a pointer to the first token in the output buffer. + * + * @return A zyan status code. + * + * Use `ZydisFormatterTokenizeInstruction` or `ZydisFormatterTokenizeInstructionEx` to tokenize a + * complete instruction. + */ +ZYDIS_EXPORT ZyanStatus ZydisFormatterTokenizeOperand(const ZydisFormatter* formatter, + const ZydisDecodedInstruction* instruction, ZyanU8 index, void* buffer, ZyanUSize length, + ZyanU64 runtime_address, ZydisFormatterTokenConst** token); + +/** + * Tokenizes the given operand and writes it into the output buffer. + * + * @param formatter A pointer to the `ZydisFormatter` instance. + * @param instruction A pointer to the `ZydisDecodedInstruction` struct. + * @param index The index of the operand to format. + * @param buffer A pointer to the output buffer. + * @param length The length of the output buffer (in bytes). + * @param runtime_address The runtime address of the instruction or `ZYDIS_RUNTIME_ADDRESS_NONE` + * to print relative addresses. + * @param token Receives a pointer to the first token in the output buffer. + * @param user_data A pointer to user-defined data which can be used in custom formatter + * callbacks. + * + * @return A zyan status code. + * + * Use `ZydisFormatterTokenizeInstruction` or `ZydisFormatterTokenizeInstructionEx` to tokenize a + * complete instruction. + */ +ZYDIS_EXPORT ZyanStatus ZydisFormatterTokenizeOperandEx(const ZydisFormatter* formatter, + const ZydisDecodedInstruction* instruction, ZyanU8 index, void* buffer, ZyanUSize length, + ZyanU64 runtime_address, ZydisFormatterTokenConst** token, void* user_data); + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * @} + */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYDIS_FORMATTER_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/FormatterBuffer.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/FormatterBuffer.h new file mode 100644 index 0000000..2ae2efe --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/FormatterBuffer.h @@ -0,0 +1,306 @@ +/*************************************************************************************************** + + Zyan Disassembler Library (Zydis) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Implements the `ZydisFormatterToken` type and provides functions to use it. + */ + +#ifndef ZYDIS_FORMATTER_TOKEN_H +#define ZYDIS_FORMATTER_TOKEN_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Constants */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Token types */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * @biref Defines the `ZydisTokenType` data-type. + */ +typedef ZyanU8 ZydisTokenType; + +#define ZYDIS_TOKEN_INVALID 0x00 +/** + * A whitespace character. + */ +#define ZYDIS_TOKEN_WHITESPACE 0x01 +/** + * A delimiter character (like `','`, `':'`, `'+'`, `'-'`, `'*'`). + */ +#define ZYDIS_TOKEN_DELIMITER 0x02 +/** + * An opening parenthesis character (like `'('`, `'['`, `'{'`). + */ +#define ZYDIS_TOKEN_PARENTHESIS_OPEN 0x03 +/** + * A closing parenthesis character (like `')'`, `']'`, `'}'`). + */ +#define ZYDIS_TOKEN_PARENTHESIS_CLOSE 0x04 +/** + * A prefix literal (like `"LOCK"`, `"REP"`). + */ +#define ZYDIS_TOKEN_PREFIX 0x05 +/** + * A mnemonic literal (like `"MOV"`, `"VCMPPSD"`, `"LCALL"`). + */ +#define ZYDIS_TOKEN_MNEMONIC 0x06 +/** + * A register literal (like `"RAX"`, `"DS"`, `"%ECX"`). + */ +#define ZYDIS_TOKEN_REGISTER 0x07 +/** + * An absolute address literal (like `0x00400000`). + */ +#define ZYDIS_TOKEN_ADDRESS_ABS 0x08 +/** + * A relative address literal (like `-0x100`). + */ +#define ZYDIS_TOKEN_ADDRESS_REL 0x09 +/** + * A displacement literal (like `0xFFFFFFFF`, `-0x100`, `+0x1234`). + */ +#define ZYDIS_TOKEN_DISPLACEMENT 0x0A +/** + * An immediate literal (like `0xC0`, `-0x1234`, `$0x0000`). + */ +#define ZYDIS_TOKEN_IMMEDIATE 0x0B +/** + * A typecast literal (like `DWORD PTR`). + */ +#define ZYDIS_TOKEN_TYPECAST 0x0C +/** + * A decorator literal (like `"Z"`, `"1TO4"`). + */ +#define ZYDIS_TOKEN_DECORATOR 0x0D +/** + * A symbol literal. + */ +#define ZYDIS_TOKEN_SYMBOL 0x0E + +/** + * The base for user-defined token types. + */ +#define ZYDIS_TOKEN_USER 0x80 + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Token */ +/* ---------------------------------------------------------------------------------------------- */ + +#pragma pack(push, 1) + +/** + * Defines the `ZydisFormatterToken` struct. + * + * All fields in this struct should be considered as "private". Any changes may lead to unexpected + * behavior. + */ +typedef struct ZydisFormatterToken_ +{ + /** + * The token type. + */ + ZydisTokenType type; + /** + * An offset to the next token, or `0`. + */ + ZyanU8 next; +} ZydisFormatterToken; + +#pragma pack(pop) + +/** + * Defines the `ZydisFormatterTokenConst` data-type. + */ +typedef const ZydisFormatterToken ZydisFormatterTokenConst; + +/* ---------------------------------------------------------------------------------------------- */ +/* Buffer */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisFormatterBuffer` struct. + * + * All fields in this struct should be considered as "private". Any changes may + * lead to unexpected behavior. + */ +typedef struct ZydisFormatterBuffer_ +{ + /** + * `ZYAN_TRUE`, if the buffer contains a token stream or `ZYAN_FALSE, if it + * contains a simple string. + */ + ZyanBool is_token_list; + /** + * The remaining capacity of the buffer. + */ + ZyanUSize capacity; + /** + * The `ZyanString` instance that refers to the literal value of the most + * recently added token. + */ + ZyanString string; +} ZydisFormatterBuffer; + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Token */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the `type` and the string `value` of the given `token`. + * + * @param token A pointer to the `ZydisFormatterToken` struct. + * @param type Receives the token type. + * @param value Receives a pointer to the string value of the token. + * + * @return A zyan status code. + */ +ZYDIS_EXPORT ZyanStatus ZydisFormatterTokenGetValue(const ZydisFormatterToken* token, + ZydisTokenType* type, ZyanConstCharPointer* value); + +/** + * Obtains the next `token` linked to the passed one. + * + * @param token Receives a pointer to the next `ZydisFormatterToken` struct + * linked to the passed one. + * + * @return A zyan status code. + */ +ZYDIS_EXPORT ZyanStatus ZydisFormatterTokenNext(ZydisFormatterTokenConst** token); + +/* ---------------------------------------------------------------------------------------------- */ +/* Buffer */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the current (most recently added) token. + * + * @param buffer A pointer to the `ZydisFormatterBuffer` struct. + * @param token Receives a pointer to the current token. + * + * @return A zyan status code. + * + * This function returns `ZYAN_STATUS_INVALID_OPERATION`, if the buffer does not contain at least + * one token. + */ +ZYDIS_EXPORT ZyanStatus ZydisFormatterBufferGetToken(const ZydisFormatterBuffer* buffer, + ZydisFormatterTokenConst** token); + +/** + * Returns the `ZyanString` instance associated with the given buffer. + * + * @param buffer A pointer to the `ZydisFormatterBuffer` struct. + * @param string Receives a pointer to the `ZyanString` instance associated with the given + * buffer. + * + * @return A zyan status code. + * + * This function returns `ZYAN_STATUS_INVALID_OPERATION`, if the buffer does not contain at least + * one token. + * + * The returned string always refers to the literal value of the current (most recently added) + * token and will remain valid until the buffer is destroyed. + */ +ZYDIS_EXPORT ZyanStatus ZydisFormatterBufferGetString(ZydisFormatterBuffer* buffer, + ZyanString** string); + +/** + * Appends a new token to the `buffer`. + * + * @param buffer A pointer to the `ZydisFormatterBuffer` struct. + * @param type The type of the new token. + * + * @return A zyan status code. + * + * Note that the `ZyanString` instance returned by `ZydisFormatterBufferGetString` will + * automatically be updated by calling this function. + */ +ZYDIS_EXPORT ZyanStatus ZydisFormatterBufferAppend(ZydisFormatterBuffer* buffer, + ZydisTokenType type); + +/** + * Returns a snapshot of the buffer-state. + * + * @param buffer A pointer to the `ZydisFormatterBuffer` struct. + * @param state Receives a snapshot of the buffer-state. + * + * @return A zyan status code. + * + * Note that the buffer-state is saved inside the buffer itself and thus becomes invalid as soon + * as the buffer gets overwritten or destroyed. + */ +ZYDIS_EXPORT ZyanStatus ZydisFormatterBufferRemember(const ZydisFormatterBuffer* buffer, + ZyanUPointer* state); + +/** + * Restores a previously saved buffer-state. + * + * @param buffer A pointer to the `ZydisFormatterBuffer` struct. + * @param state The buffer-state to restore. + * + * @return A zyan status code. + * + * All tokens added after obtaining the given `state` snapshot will be removed. This function + * does NOT restore any string content. + * + * Note that the `ZyanString` instance returned by `ZydisFormatterBufferGetString` will + * automatically be updated by calling this function. + */ +ZYDIS_EXPORT ZyanStatus ZydisFormatterBufferRestore(ZydisFormatterBuffer* buffer, + ZyanUPointer state); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYDIS_FORMATTER_TOKEN_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumISAExt.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumISAExt.h new file mode 100644 index 0000000..6de33b7 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumISAExt.h @@ -0,0 +1,98 @@ +/** + * Defines the `ZydisISAExt` enum. + */ +typedef enum ZydisISAExt_ +{ + ZYDIS_ISA_EXT_INVALID, + ZYDIS_ISA_EXT_ADOX_ADCX, + ZYDIS_ISA_EXT_AES, + ZYDIS_ISA_EXT_AMD3DNOW, + ZYDIS_ISA_EXT_AMD3DNOW_PREFETCH, + ZYDIS_ISA_EXT_AMD_INVLPGB, + ZYDIS_ISA_EXT_AMX_BF16, + ZYDIS_ISA_EXT_AMX_INT8, + ZYDIS_ISA_EXT_AMX_TILE, + ZYDIS_ISA_EXT_AVX, + ZYDIS_ISA_EXT_AVX2, + ZYDIS_ISA_EXT_AVX2GATHER, + ZYDIS_ISA_EXT_AVX512EVEX, + ZYDIS_ISA_EXT_AVX512VEX, + ZYDIS_ISA_EXT_AVXAES, + ZYDIS_ISA_EXT_BASE, + ZYDIS_ISA_EXT_BMI1, + ZYDIS_ISA_EXT_BMI2, + ZYDIS_ISA_EXT_CET, + ZYDIS_ISA_EXT_CLDEMOTE, + ZYDIS_ISA_EXT_CLFLUSHOPT, + ZYDIS_ISA_EXT_CLFSH, + ZYDIS_ISA_EXT_CLWB, + ZYDIS_ISA_EXT_CLZERO, + ZYDIS_ISA_EXT_ENQCMD, + ZYDIS_ISA_EXT_F16C, + ZYDIS_ISA_EXT_FMA, + ZYDIS_ISA_EXT_FMA4, + ZYDIS_ISA_EXT_GFNI, + ZYDIS_ISA_EXT_INVPCID, + ZYDIS_ISA_EXT_KNC, + ZYDIS_ISA_EXT_KNCE, + ZYDIS_ISA_EXT_KNCV, + ZYDIS_ISA_EXT_LONGMODE, + ZYDIS_ISA_EXT_LZCNT, + ZYDIS_ISA_EXT_MCOMMIT, + ZYDIS_ISA_EXT_MMX, + ZYDIS_ISA_EXT_MONITOR, + ZYDIS_ISA_EXT_MONITORX, + ZYDIS_ISA_EXT_MOVBE, + ZYDIS_ISA_EXT_MOVDIR, + ZYDIS_ISA_EXT_MPX, + ZYDIS_ISA_EXT_PADLOCK, + ZYDIS_ISA_EXT_PAUSE, + ZYDIS_ISA_EXT_PCLMULQDQ, + ZYDIS_ISA_EXT_PCONFIG, + ZYDIS_ISA_EXT_PKU, + ZYDIS_ISA_EXT_PREFETCHWT1, + ZYDIS_ISA_EXT_PT, + ZYDIS_ISA_EXT_RDPID, + ZYDIS_ISA_EXT_RDPRU, + ZYDIS_ISA_EXT_RDRAND, + ZYDIS_ISA_EXT_RDSEED, + ZYDIS_ISA_EXT_RDTSCP, + ZYDIS_ISA_EXT_RDWRFSGS, + ZYDIS_ISA_EXT_RTM, + ZYDIS_ISA_EXT_SERIALIZE, + ZYDIS_ISA_EXT_SGX, + ZYDIS_ISA_EXT_SGX_ENCLV, + ZYDIS_ISA_EXT_SHA, + ZYDIS_ISA_EXT_SMAP, + ZYDIS_ISA_EXT_SMX, + ZYDIS_ISA_EXT_SNP, + ZYDIS_ISA_EXT_SSE, + ZYDIS_ISA_EXT_SSE2, + ZYDIS_ISA_EXT_SSE3, + ZYDIS_ISA_EXT_SSE4, + ZYDIS_ISA_EXT_SSE4A, + ZYDIS_ISA_EXT_SSSE3, + ZYDIS_ISA_EXT_SVM, + ZYDIS_ISA_EXT_TBM, + ZYDIS_ISA_EXT_TSX_LDTRK, + ZYDIS_ISA_EXT_VAES, + ZYDIS_ISA_EXT_VMFUNC, + ZYDIS_ISA_EXT_VPCLMULQDQ, + ZYDIS_ISA_EXT_VTX, + ZYDIS_ISA_EXT_WAITPKG, + ZYDIS_ISA_EXT_X87, + ZYDIS_ISA_EXT_XOP, + ZYDIS_ISA_EXT_XSAVE, + ZYDIS_ISA_EXT_XSAVEC, + ZYDIS_ISA_EXT_XSAVEOPT, + ZYDIS_ISA_EXT_XSAVES, + + /** + * Maximum value of this enum. + */ + ZYDIS_ISA_EXT_MAX_VALUE = ZYDIS_ISA_EXT_XSAVES, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_ISA_EXT_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_ISA_EXT_MAX_VALUE) +} ZydisISAExt; diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumISASet.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumISASet.h new file mode 100644 index 0000000..c04242c --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumISASet.h @@ -0,0 +1,184 @@ +/** + * Defines the `ZydisISASet` enum. + */ +typedef enum ZydisISASet_ +{ + ZYDIS_ISA_SET_INVALID, + ZYDIS_ISA_SET_ADOX_ADCX, + ZYDIS_ISA_SET_AES, + ZYDIS_ISA_SET_AMD, + ZYDIS_ISA_SET_AMD3DNOW, + ZYDIS_ISA_SET_AMX_BF16, + ZYDIS_ISA_SET_AMX_INT8, + ZYDIS_ISA_SET_AMX_TILE, + ZYDIS_ISA_SET_AVX, + ZYDIS_ISA_SET_AVX2, + ZYDIS_ISA_SET_AVX2GATHER, + ZYDIS_ISA_SET_AVX512BW_128, + ZYDIS_ISA_SET_AVX512BW_128N, + ZYDIS_ISA_SET_AVX512BW_256, + ZYDIS_ISA_SET_AVX512BW_512, + ZYDIS_ISA_SET_AVX512BW_KOP, + ZYDIS_ISA_SET_AVX512CD_128, + ZYDIS_ISA_SET_AVX512CD_256, + ZYDIS_ISA_SET_AVX512CD_512, + ZYDIS_ISA_SET_AVX512DQ_128, + ZYDIS_ISA_SET_AVX512DQ_128N, + ZYDIS_ISA_SET_AVX512DQ_256, + ZYDIS_ISA_SET_AVX512DQ_512, + ZYDIS_ISA_SET_AVX512DQ_KOP, + ZYDIS_ISA_SET_AVX512DQ_SCALAR, + ZYDIS_ISA_SET_AVX512ER_512, + ZYDIS_ISA_SET_AVX512ER_SCALAR, + ZYDIS_ISA_SET_AVX512F_128, + ZYDIS_ISA_SET_AVX512F_128N, + ZYDIS_ISA_SET_AVX512F_256, + ZYDIS_ISA_SET_AVX512F_512, + ZYDIS_ISA_SET_AVX512F_KOP, + ZYDIS_ISA_SET_AVX512F_SCALAR, + ZYDIS_ISA_SET_AVX512PF_512, + ZYDIS_ISA_SET_AVX512_4FMAPS_512, + ZYDIS_ISA_SET_AVX512_4FMAPS_SCALAR, + ZYDIS_ISA_SET_AVX512_4VNNIW_512, + ZYDIS_ISA_SET_AVX512_BF16_128, + ZYDIS_ISA_SET_AVX512_BF16_256, + ZYDIS_ISA_SET_AVX512_BF16_512, + ZYDIS_ISA_SET_AVX512_BITALG_128, + ZYDIS_ISA_SET_AVX512_BITALG_256, + ZYDIS_ISA_SET_AVX512_BITALG_512, + ZYDIS_ISA_SET_AVX512_GFNI_128, + ZYDIS_ISA_SET_AVX512_GFNI_256, + ZYDIS_ISA_SET_AVX512_GFNI_512, + ZYDIS_ISA_SET_AVX512_IFMA_128, + ZYDIS_ISA_SET_AVX512_IFMA_256, + ZYDIS_ISA_SET_AVX512_IFMA_512, + ZYDIS_ISA_SET_AVX512_VAES_128, + ZYDIS_ISA_SET_AVX512_VAES_256, + ZYDIS_ISA_SET_AVX512_VAES_512, + ZYDIS_ISA_SET_AVX512_VBMI2_128, + ZYDIS_ISA_SET_AVX512_VBMI2_256, + ZYDIS_ISA_SET_AVX512_VBMI2_512, + ZYDIS_ISA_SET_AVX512_VBMI_128, + ZYDIS_ISA_SET_AVX512_VBMI_256, + ZYDIS_ISA_SET_AVX512_VBMI_512, + ZYDIS_ISA_SET_AVX512_VNNI_128, + ZYDIS_ISA_SET_AVX512_VNNI_256, + ZYDIS_ISA_SET_AVX512_VNNI_512, + ZYDIS_ISA_SET_AVX512_VP2INTERSECT_128, + ZYDIS_ISA_SET_AVX512_VP2INTERSECT_256, + ZYDIS_ISA_SET_AVX512_VP2INTERSECT_512, + ZYDIS_ISA_SET_AVX512_VPCLMULQDQ_128, + ZYDIS_ISA_SET_AVX512_VPCLMULQDQ_256, + ZYDIS_ISA_SET_AVX512_VPCLMULQDQ_512, + ZYDIS_ISA_SET_AVX512_VPOPCNTDQ_128, + ZYDIS_ISA_SET_AVX512_VPOPCNTDQ_256, + ZYDIS_ISA_SET_AVX512_VPOPCNTDQ_512, + ZYDIS_ISA_SET_AVXAES, + ZYDIS_ISA_SET_AVX_GFNI, + ZYDIS_ISA_SET_BMI1, + ZYDIS_ISA_SET_BMI2, + ZYDIS_ISA_SET_CET, + ZYDIS_ISA_SET_CLDEMOTE, + ZYDIS_ISA_SET_CLFLUSHOPT, + ZYDIS_ISA_SET_CLFSH, + ZYDIS_ISA_SET_CLWB, + ZYDIS_ISA_SET_CLZERO, + ZYDIS_ISA_SET_CMOV, + ZYDIS_ISA_SET_CMPXCHG16B, + ZYDIS_ISA_SET_ENQCMD, + ZYDIS_ISA_SET_F16C, + ZYDIS_ISA_SET_FAT_NOP, + ZYDIS_ISA_SET_FCMOV, + ZYDIS_ISA_SET_FMA, + ZYDIS_ISA_SET_FMA4, + ZYDIS_ISA_SET_FXSAVE, + ZYDIS_ISA_SET_FXSAVE64, + ZYDIS_ISA_SET_GFNI, + ZYDIS_ISA_SET_I186, + ZYDIS_ISA_SET_I286PROTECTED, + ZYDIS_ISA_SET_I286REAL, + ZYDIS_ISA_SET_I386, + ZYDIS_ISA_SET_I486, + ZYDIS_ISA_SET_I486REAL, + ZYDIS_ISA_SET_I86, + ZYDIS_ISA_SET_INVPCID, + ZYDIS_ISA_SET_KNCE, + ZYDIS_ISA_SET_KNCJKBR, + ZYDIS_ISA_SET_KNCSTREAM, + ZYDIS_ISA_SET_KNCV, + ZYDIS_ISA_SET_KNC_MISC, + ZYDIS_ISA_SET_KNC_PF_HINT, + ZYDIS_ISA_SET_LAHF, + ZYDIS_ISA_SET_LONGMODE, + ZYDIS_ISA_SET_LZCNT, + ZYDIS_ISA_SET_MCOMMIT, + ZYDIS_ISA_SET_MONITOR, + ZYDIS_ISA_SET_MONITORX, + ZYDIS_ISA_SET_MOVBE, + ZYDIS_ISA_SET_MOVDIR, + ZYDIS_ISA_SET_MPX, + ZYDIS_ISA_SET_PADLOCK_ACE, + ZYDIS_ISA_SET_PADLOCK_PHE, + ZYDIS_ISA_SET_PADLOCK_PMM, + ZYDIS_ISA_SET_PADLOCK_RNG, + ZYDIS_ISA_SET_PAUSE, + ZYDIS_ISA_SET_PCLMULQDQ, + ZYDIS_ISA_SET_PCONFIG, + ZYDIS_ISA_SET_PENTIUMMMX, + ZYDIS_ISA_SET_PENTIUMREAL, + ZYDIS_ISA_SET_PKU, + ZYDIS_ISA_SET_POPCNT, + ZYDIS_ISA_SET_PPRO, + ZYDIS_ISA_SET_PREFETCHWT1, + ZYDIS_ISA_SET_PREFETCH_NOP, + ZYDIS_ISA_SET_PT, + ZYDIS_ISA_SET_RDPID, + ZYDIS_ISA_SET_RDPMC, + ZYDIS_ISA_SET_RDPRU, + ZYDIS_ISA_SET_RDRAND, + ZYDIS_ISA_SET_RDSEED, + ZYDIS_ISA_SET_RDTSCP, + ZYDIS_ISA_SET_RDWRFSGS, + ZYDIS_ISA_SET_RTM, + ZYDIS_ISA_SET_SERIALIZE, + ZYDIS_ISA_SET_SGX, + ZYDIS_ISA_SET_SGX_ENCLV, + ZYDIS_ISA_SET_SHA, + ZYDIS_ISA_SET_SMAP, + ZYDIS_ISA_SET_SMX, + ZYDIS_ISA_SET_SSE, + ZYDIS_ISA_SET_SSE2, + ZYDIS_ISA_SET_SSE2MMX, + ZYDIS_ISA_SET_SSE3, + ZYDIS_ISA_SET_SSE3X87, + ZYDIS_ISA_SET_SSE4, + ZYDIS_ISA_SET_SSE42, + ZYDIS_ISA_SET_SSE4A, + ZYDIS_ISA_SET_SSEMXCSR, + ZYDIS_ISA_SET_SSE_PREFETCH, + ZYDIS_ISA_SET_SSSE3, + ZYDIS_ISA_SET_SSSE3MMX, + ZYDIS_ISA_SET_SVM, + ZYDIS_ISA_SET_TBM, + ZYDIS_ISA_SET_TSX_LDTRK, + ZYDIS_ISA_SET_VAES, + ZYDIS_ISA_SET_VMFUNC, + ZYDIS_ISA_SET_VPCLMULQDQ, + ZYDIS_ISA_SET_VTX, + ZYDIS_ISA_SET_WAITPKG, + ZYDIS_ISA_SET_X87, + ZYDIS_ISA_SET_XOP, + ZYDIS_ISA_SET_XSAVE, + ZYDIS_ISA_SET_XSAVEC, + ZYDIS_ISA_SET_XSAVEOPT, + ZYDIS_ISA_SET_XSAVES, + + /** + * Maximum value of this enum. + */ + ZYDIS_ISA_SET_MAX_VALUE = ZYDIS_ISA_SET_XSAVES, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_ISA_SET_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_ISA_SET_MAX_VALUE) +} ZydisISASet; diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumInstructionCategory.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumInstructionCategory.h new file mode 100644 index 0000000..755afbc --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumInstructionCategory.h @@ -0,0 +1,117 @@ +/** + * Defines the `ZydisInstructionCategory` enum. + */ +typedef enum ZydisInstructionCategory_ +{ + ZYDIS_CATEGORY_INVALID, + ZYDIS_CATEGORY_ADOX_ADCX, + ZYDIS_CATEGORY_AES, + ZYDIS_CATEGORY_AMD3DNOW, + ZYDIS_CATEGORY_AMX_TILE, + ZYDIS_CATEGORY_AVX, + ZYDIS_CATEGORY_AVX2, + ZYDIS_CATEGORY_AVX2GATHER, + ZYDIS_CATEGORY_AVX512, + ZYDIS_CATEGORY_AVX512_4FMAPS, + ZYDIS_CATEGORY_AVX512_4VNNIW, + ZYDIS_CATEGORY_AVX512_BITALG, + ZYDIS_CATEGORY_AVX512_VBMI, + ZYDIS_CATEGORY_AVX512_VP2INTERSECT, + ZYDIS_CATEGORY_BINARY, + ZYDIS_CATEGORY_BITBYTE, + ZYDIS_CATEGORY_BLEND, + ZYDIS_CATEGORY_BMI1, + ZYDIS_CATEGORY_BMI2, + ZYDIS_CATEGORY_BROADCAST, + ZYDIS_CATEGORY_CALL, + ZYDIS_CATEGORY_CET, + ZYDIS_CATEGORY_CLDEMOTE, + ZYDIS_CATEGORY_CLFLUSHOPT, + ZYDIS_CATEGORY_CLWB, + ZYDIS_CATEGORY_CLZERO, + ZYDIS_CATEGORY_CMOV, + ZYDIS_CATEGORY_COMPRESS, + ZYDIS_CATEGORY_COND_BR, + ZYDIS_CATEGORY_CONFLICT, + ZYDIS_CATEGORY_CONVERT, + ZYDIS_CATEGORY_DATAXFER, + ZYDIS_CATEGORY_DECIMAL, + ZYDIS_CATEGORY_ENQCMD, + ZYDIS_CATEGORY_EXPAND, + ZYDIS_CATEGORY_FCMOV, + ZYDIS_CATEGORY_FLAGOP, + ZYDIS_CATEGORY_FMA4, + ZYDIS_CATEGORY_GATHER, + ZYDIS_CATEGORY_GFNI, + ZYDIS_CATEGORY_IFMA, + ZYDIS_CATEGORY_INTERRUPT, + ZYDIS_CATEGORY_IO, + ZYDIS_CATEGORY_IOSTRINGOP, + ZYDIS_CATEGORY_KMASK, + ZYDIS_CATEGORY_KNC, + ZYDIS_CATEGORY_KNCMASK, + ZYDIS_CATEGORY_KNCSCALAR, + ZYDIS_CATEGORY_LOGICAL, + ZYDIS_CATEGORY_LOGICAL_FP, + ZYDIS_CATEGORY_LZCNT, + ZYDIS_CATEGORY_MISC, + ZYDIS_CATEGORY_MMX, + ZYDIS_CATEGORY_MOVDIR, + ZYDIS_CATEGORY_MPX, + ZYDIS_CATEGORY_NOP, + ZYDIS_CATEGORY_PADLOCK, + ZYDIS_CATEGORY_PCLMULQDQ, + ZYDIS_CATEGORY_PCONFIG, + ZYDIS_CATEGORY_PKU, + ZYDIS_CATEGORY_POP, + ZYDIS_CATEGORY_PREFETCH, + ZYDIS_CATEGORY_PREFETCHWT1, + ZYDIS_CATEGORY_PT, + ZYDIS_CATEGORY_PUSH, + ZYDIS_CATEGORY_RDPID, + ZYDIS_CATEGORY_RDPRU, + ZYDIS_CATEGORY_RDRAND, + ZYDIS_CATEGORY_RDSEED, + ZYDIS_CATEGORY_RDWRFSGS, + ZYDIS_CATEGORY_RET, + ZYDIS_CATEGORY_ROTATE, + ZYDIS_CATEGORY_SCATTER, + ZYDIS_CATEGORY_SEGOP, + ZYDIS_CATEGORY_SEMAPHORE, + ZYDIS_CATEGORY_SERIALIZE, + ZYDIS_CATEGORY_SETCC, + ZYDIS_CATEGORY_SGX, + ZYDIS_CATEGORY_SHA, + ZYDIS_CATEGORY_SHIFT, + ZYDIS_CATEGORY_SMAP, + ZYDIS_CATEGORY_SSE, + ZYDIS_CATEGORY_STRINGOP, + ZYDIS_CATEGORY_STTNI, + ZYDIS_CATEGORY_SYSCALL, + ZYDIS_CATEGORY_SYSRET, + ZYDIS_CATEGORY_SYSTEM, + ZYDIS_CATEGORY_TBM, + ZYDIS_CATEGORY_TSX_LDTRK, + ZYDIS_CATEGORY_UFMA, + ZYDIS_CATEGORY_UNCOND_BR, + ZYDIS_CATEGORY_VAES, + ZYDIS_CATEGORY_VBMI2, + ZYDIS_CATEGORY_VFMA, + ZYDIS_CATEGORY_VPCLMULQDQ, + ZYDIS_CATEGORY_VTX, + ZYDIS_CATEGORY_WAITPKG, + ZYDIS_CATEGORY_WIDENOP, + ZYDIS_CATEGORY_X87_ALU, + ZYDIS_CATEGORY_XOP, + ZYDIS_CATEGORY_XSAVE, + ZYDIS_CATEGORY_XSAVEOPT, + + /** + * Maximum value of this enum. + */ + ZYDIS_CATEGORY_MAX_VALUE = ZYDIS_CATEGORY_XSAVEOPT, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_CATEGORY_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_CATEGORY_MAX_VALUE) +} ZydisInstructionCategory; diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumMnemonic.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumMnemonic.h new file mode 100644 index 0000000..899efb8 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumMnemonic.h @@ -0,0 +1,1643 @@ +/** + * Defines the `ZydisMnemonic` enum. + */ +typedef enum ZydisMnemonic_ +{ + ZYDIS_MNEMONIC_INVALID, + ZYDIS_MNEMONIC_AAA, + ZYDIS_MNEMONIC_AAD, + ZYDIS_MNEMONIC_AAM, + ZYDIS_MNEMONIC_AAS, + ZYDIS_MNEMONIC_ADC, + ZYDIS_MNEMONIC_ADCX, + ZYDIS_MNEMONIC_ADD, + ZYDIS_MNEMONIC_ADDPD, + ZYDIS_MNEMONIC_ADDPS, + ZYDIS_MNEMONIC_ADDSD, + ZYDIS_MNEMONIC_ADDSS, + ZYDIS_MNEMONIC_ADDSUBPD, + ZYDIS_MNEMONIC_ADDSUBPS, + ZYDIS_MNEMONIC_ADOX, + ZYDIS_MNEMONIC_AESDEC, + ZYDIS_MNEMONIC_AESDECLAST, + ZYDIS_MNEMONIC_AESENC, + ZYDIS_MNEMONIC_AESENCLAST, + ZYDIS_MNEMONIC_AESIMC, + ZYDIS_MNEMONIC_AESKEYGENASSIST, + ZYDIS_MNEMONIC_AND, + ZYDIS_MNEMONIC_ANDN, + ZYDIS_MNEMONIC_ANDNPD, + ZYDIS_MNEMONIC_ANDNPS, + ZYDIS_MNEMONIC_ANDPD, + ZYDIS_MNEMONIC_ANDPS, + ZYDIS_MNEMONIC_ARPL, + ZYDIS_MNEMONIC_BEXTR, + ZYDIS_MNEMONIC_BLCFILL, + ZYDIS_MNEMONIC_BLCI, + ZYDIS_MNEMONIC_BLCIC, + ZYDIS_MNEMONIC_BLCMSK, + ZYDIS_MNEMONIC_BLCS, + ZYDIS_MNEMONIC_BLENDPD, + ZYDIS_MNEMONIC_BLENDPS, + ZYDIS_MNEMONIC_BLENDVPD, + ZYDIS_MNEMONIC_BLENDVPS, + ZYDIS_MNEMONIC_BLSFILL, + ZYDIS_MNEMONIC_BLSI, + ZYDIS_MNEMONIC_BLSIC, + ZYDIS_MNEMONIC_BLSMSK, + ZYDIS_MNEMONIC_BLSR, + ZYDIS_MNEMONIC_BNDCL, + ZYDIS_MNEMONIC_BNDCN, + ZYDIS_MNEMONIC_BNDCU, + ZYDIS_MNEMONIC_BNDLDX, + ZYDIS_MNEMONIC_BNDMK, + ZYDIS_MNEMONIC_BNDMOV, + ZYDIS_MNEMONIC_BNDSTX, + ZYDIS_MNEMONIC_BOUND, + ZYDIS_MNEMONIC_BSF, + ZYDIS_MNEMONIC_BSR, + ZYDIS_MNEMONIC_BSWAP, + ZYDIS_MNEMONIC_BT, + ZYDIS_MNEMONIC_BTC, + ZYDIS_MNEMONIC_BTR, + ZYDIS_MNEMONIC_BTS, + ZYDIS_MNEMONIC_BZHI, + ZYDIS_MNEMONIC_CALL, + ZYDIS_MNEMONIC_CBW, + ZYDIS_MNEMONIC_CDQ, + ZYDIS_MNEMONIC_CDQE, + ZYDIS_MNEMONIC_CLAC, + ZYDIS_MNEMONIC_CLC, + ZYDIS_MNEMONIC_CLD, + ZYDIS_MNEMONIC_CLDEMOTE, + ZYDIS_MNEMONIC_CLEVICT0, + ZYDIS_MNEMONIC_CLEVICT1, + ZYDIS_MNEMONIC_CLFLUSH, + ZYDIS_MNEMONIC_CLFLUSHOPT, + ZYDIS_MNEMONIC_CLGI, + ZYDIS_MNEMONIC_CLI, + ZYDIS_MNEMONIC_CLRSSBSY, + ZYDIS_MNEMONIC_CLTS, + ZYDIS_MNEMONIC_CLWB, + ZYDIS_MNEMONIC_CLZERO, + ZYDIS_MNEMONIC_CMC, + ZYDIS_MNEMONIC_CMOVB, + ZYDIS_MNEMONIC_CMOVBE, + ZYDIS_MNEMONIC_CMOVL, + ZYDIS_MNEMONIC_CMOVLE, + ZYDIS_MNEMONIC_CMOVNB, + ZYDIS_MNEMONIC_CMOVNBE, + ZYDIS_MNEMONIC_CMOVNL, + ZYDIS_MNEMONIC_CMOVNLE, + ZYDIS_MNEMONIC_CMOVNO, + ZYDIS_MNEMONIC_CMOVNP, + ZYDIS_MNEMONIC_CMOVNS, + ZYDIS_MNEMONIC_CMOVNZ, + ZYDIS_MNEMONIC_CMOVO, + ZYDIS_MNEMONIC_CMOVP, + ZYDIS_MNEMONIC_CMOVS, + ZYDIS_MNEMONIC_CMOVZ, + ZYDIS_MNEMONIC_CMP, + ZYDIS_MNEMONIC_CMPPD, + ZYDIS_MNEMONIC_CMPPS, + ZYDIS_MNEMONIC_CMPSB, + ZYDIS_MNEMONIC_CMPSD, + ZYDIS_MNEMONIC_CMPSQ, + ZYDIS_MNEMONIC_CMPSS, + ZYDIS_MNEMONIC_CMPSW, + ZYDIS_MNEMONIC_CMPXCHG, + ZYDIS_MNEMONIC_CMPXCHG16B, + ZYDIS_MNEMONIC_CMPXCHG8B, + ZYDIS_MNEMONIC_COMISD, + ZYDIS_MNEMONIC_COMISS, + ZYDIS_MNEMONIC_CPUID, + ZYDIS_MNEMONIC_CQO, + ZYDIS_MNEMONIC_CRC32, + ZYDIS_MNEMONIC_CVTDQ2PD, + ZYDIS_MNEMONIC_CVTDQ2PS, + ZYDIS_MNEMONIC_CVTPD2DQ, + ZYDIS_MNEMONIC_CVTPD2PI, + ZYDIS_MNEMONIC_CVTPD2PS, + ZYDIS_MNEMONIC_CVTPI2PD, + ZYDIS_MNEMONIC_CVTPI2PS, + ZYDIS_MNEMONIC_CVTPS2DQ, + ZYDIS_MNEMONIC_CVTPS2PD, + ZYDIS_MNEMONIC_CVTPS2PI, + ZYDIS_MNEMONIC_CVTSD2SI, + ZYDIS_MNEMONIC_CVTSD2SS, + ZYDIS_MNEMONIC_CVTSI2SD, + ZYDIS_MNEMONIC_CVTSI2SS, + ZYDIS_MNEMONIC_CVTSS2SD, + ZYDIS_MNEMONIC_CVTSS2SI, + ZYDIS_MNEMONIC_CVTTPD2DQ, + ZYDIS_MNEMONIC_CVTTPD2PI, + ZYDIS_MNEMONIC_CVTTPS2DQ, + ZYDIS_MNEMONIC_CVTTPS2PI, + ZYDIS_MNEMONIC_CVTTSD2SI, + ZYDIS_MNEMONIC_CVTTSS2SI, + ZYDIS_MNEMONIC_CWD, + ZYDIS_MNEMONIC_CWDE, + ZYDIS_MNEMONIC_DAA, + ZYDIS_MNEMONIC_DAS, + ZYDIS_MNEMONIC_DEC, + ZYDIS_MNEMONIC_DELAY, + ZYDIS_MNEMONIC_DIV, + ZYDIS_MNEMONIC_DIVPD, + ZYDIS_MNEMONIC_DIVPS, + ZYDIS_MNEMONIC_DIVSD, + ZYDIS_MNEMONIC_DIVSS, + ZYDIS_MNEMONIC_DPPD, + ZYDIS_MNEMONIC_DPPS, + ZYDIS_MNEMONIC_EMMS, + ZYDIS_MNEMONIC_ENCLS, + ZYDIS_MNEMONIC_ENCLU, + ZYDIS_MNEMONIC_ENCLV, + ZYDIS_MNEMONIC_ENDBR32, + ZYDIS_MNEMONIC_ENDBR64, + ZYDIS_MNEMONIC_ENQCMD, + ZYDIS_MNEMONIC_ENQCMDS, + ZYDIS_MNEMONIC_ENTER, + ZYDIS_MNEMONIC_EXTRACTPS, + ZYDIS_MNEMONIC_EXTRQ, + ZYDIS_MNEMONIC_F2XM1, + ZYDIS_MNEMONIC_FABS, + ZYDIS_MNEMONIC_FADD, + ZYDIS_MNEMONIC_FADDP, + ZYDIS_MNEMONIC_FBLD, + ZYDIS_MNEMONIC_FBSTP, + ZYDIS_MNEMONIC_FCHS, + ZYDIS_MNEMONIC_FCMOVB, + ZYDIS_MNEMONIC_FCMOVBE, + ZYDIS_MNEMONIC_FCMOVE, + ZYDIS_MNEMONIC_FCMOVNB, + ZYDIS_MNEMONIC_FCMOVNBE, + ZYDIS_MNEMONIC_FCMOVNE, + ZYDIS_MNEMONIC_FCMOVNU, + ZYDIS_MNEMONIC_FCMOVU, + ZYDIS_MNEMONIC_FCOM, + ZYDIS_MNEMONIC_FCOMI, + ZYDIS_MNEMONIC_FCOMIP, + ZYDIS_MNEMONIC_FCOMP, + ZYDIS_MNEMONIC_FCOMPP, + ZYDIS_MNEMONIC_FCOS, + ZYDIS_MNEMONIC_FDECSTP, + ZYDIS_MNEMONIC_FDISI8087_NOP, + ZYDIS_MNEMONIC_FDIV, + ZYDIS_MNEMONIC_FDIVP, + ZYDIS_MNEMONIC_FDIVR, + ZYDIS_MNEMONIC_FDIVRP, + ZYDIS_MNEMONIC_FEMMS, + ZYDIS_MNEMONIC_FENI8087_NOP, + ZYDIS_MNEMONIC_FFREE, + ZYDIS_MNEMONIC_FFREEP, + ZYDIS_MNEMONIC_FIADD, + ZYDIS_MNEMONIC_FICOM, + ZYDIS_MNEMONIC_FICOMP, + ZYDIS_MNEMONIC_FIDIV, + ZYDIS_MNEMONIC_FIDIVR, + ZYDIS_MNEMONIC_FILD, + ZYDIS_MNEMONIC_FIMUL, + ZYDIS_MNEMONIC_FINCSTP, + ZYDIS_MNEMONIC_FIST, + ZYDIS_MNEMONIC_FISTP, + ZYDIS_MNEMONIC_FISTTP, + ZYDIS_MNEMONIC_FISUB, + ZYDIS_MNEMONIC_FISUBR, + ZYDIS_MNEMONIC_FLD, + ZYDIS_MNEMONIC_FLD1, + ZYDIS_MNEMONIC_FLDCW, + ZYDIS_MNEMONIC_FLDENV, + ZYDIS_MNEMONIC_FLDL2E, + ZYDIS_MNEMONIC_FLDL2T, + ZYDIS_MNEMONIC_FLDLG2, + ZYDIS_MNEMONIC_FLDLN2, + ZYDIS_MNEMONIC_FLDPI, + ZYDIS_MNEMONIC_FLDZ, + ZYDIS_MNEMONIC_FMUL, + ZYDIS_MNEMONIC_FMULP, + ZYDIS_MNEMONIC_FNCLEX, + ZYDIS_MNEMONIC_FNINIT, + ZYDIS_MNEMONIC_FNOP, + ZYDIS_MNEMONIC_FNSAVE, + ZYDIS_MNEMONIC_FNSTCW, + ZYDIS_MNEMONIC_FNSTENV, + ZYDIS_MNEMONIC_FNSTSW, + ZYDIS_MNEMONIC_FPATAN, + ZYDIS_MNEMONIC_FPREM, + ZYDIS_MNEMONIC_FPREM1, + ZYDIS_MNEMONIC_FPTAN, + ZYDIS_MNEMONIC_FRNDINT, + ZYDIS_MNEMONIC_FRSTOR, + ZYDIS_MNEMONIC_FSCALE, + ZYDIS_MNEMONIC_FSETPM287_NOP, + ZYDIS_MNEMONIC_FSIN, + ZYDIS_MNEMONIC_FSINCOS, + ZYDIS_MNEMONIC_FSQRT, + ZYDIS_MNEMONIC_FST, + ZYDIS_MNEMONIC_FSTP, + ZYDIS_MNEMONIC_FSTPNCE, + ZYDIS_MNEMONIC_FSUB, + ZYDIS_MNEMONIC_FSUBP, + ZYDIS_MNEMONIC_FSUBR, + ZYDIS_MNEMONIC_FSUBRP, + ZYDIS_MNEMONIC_FTST, + ZYDIS_MNEMONIC_FUCOM, + ZYDIS_MNEMONIC_FUCOMI, + ZYDIS_MNEMONIC_FUCOMIP, + ZYDIS_MNEMONIC_FUCOMP, + ZYDIS_MNEMONIC_FUCOMPP, + ZYDIS_MNEMONIC_FWAIT, + ZYDIS_MNEMONIC_FXAM, + ZYDIS_MNEMONIC_FXCH, + ZYDIS_MNEMONIC_FXRSTOR, + ZYDIS_MNEMONIC_FXRSTOR64, + ZYDIS_MNEMONIC_FXSAVE, + ZYDIS_MNEMONIC_FXSAVE64, + ZYDIS_MNEMONIC_FXTRACT, + ZYDIS_MNEMONIC_FYL2X, + ZYDIS_MNEMONIC_FYL2XP1, + ZYDIS_MNEMONIC_GETSEC, + ZYDIS_MNEMONIC_GF2P8AFFINEINVQB, + ZYDIS_MNEMONIC_GF2P8AFFINEQB, + ZYDIS_MNEMONIC_GF2P8MULB, + ZYDIS_MNEMONIC_HADDPD, + ZYDIS_MNEMONIC_HADDPS, + ZYDIS_MNEMONIC_HLT, + ZYDIS_MNEMONIC_HSUBPD, + ZYDIS_MNEMONIC_HSUBPS, + ZYDIS_MNEMONIC_IDIV, + ZYDIS_MNEMONIC_IMUL, + ZYDIS_MNEMONIC_IN, + ZYDIS_MNEMONIC_INC, + ZYDIS_MNEMONIC_INCSSPD, + ZYDIS_MNEMONIC_INCSSPQ, + ZYDIS_MNEMONIC_INSB, + ZYDIS_MNEMONIC_INSD, + ZYDIS_MNEMONIC_INSERTPS, + ZYDIS_MNEMONIC_INSERTQ, + ZYDIS_MNEMONIC_INSW, + ZYDIS_MNEMONIC_INT, + ZYDIS_MNEMONIC_INT1, + ZYDIS_MNEMONIC_INT3, + ZYDIS_MNEMONIC_INTO, + ZYDIS_MNEMONIC_INVD, + ZYDIS_MNEMONIC_INVEPT, + ZYDIS_MNEMONIC_INVLPG, + ZYDIS_MNEMONIC_INVLPGA, + ZYDIS_MNEMONIC_INVLPGB, + ZYDIS_MNEMONIC_INVPCID, + ZYDIS_MNEMONIC_INVVPID, + ZYDIS_MNEMONIC_IRET, + ZYDIS_MNEMONIC_IRETD, + ZYDIS_MNEMONIC_IRETQ, + ZYDIS_MNEMONIC_JB, + ZYDIS_MNEMONIC_JBE, + ZYDIS_MNEMONIC_JCXZ, + ZYDIS_MNEMONIC_JECXZ, + ZYDIS_MNEMONIC_JKNZD, + ZYDIS_MNEMONIC_JKZD, + ZYDIS_MNEMONIC_JL, + ZYDIS_MNEMONIC_JLE, + ZYDIS_MNEMONIC_JMP, + ZYDIS_MNEMONIC_JNB, + ZYDIS_MNEMONIC_JNBE, + ZYDIS_MNEMONIC_JNL, + ZYDIS_MNEMONIC_JNLE, + ZYDIS_MNEMONIC_JNO, + ZYDIS_MNEMONIC_JNP, + ZYDIS_MNEMONIC_JNS, + ZYDIS_MNEMONIC_JNZ, + ZYDIS_MNEMONIC_JO, + ZYDIS_MNEMONIC_JP, + ZYDIS_MNEMONIC_JRCXZ, + ZYDIS_MNEMONIC_JS, + ZYDIS_MNEMONIC_JZ, + ZYDIS_MNEMONIC_KADDB, + ZYDIS_MNEMONIC_KADDD, + ZYDIS_MNEMONIC_KADDQ, + ZYDIS_MNEMONIC_KADDW, + ZYDIS_MNEMONIC_KAND, + ZYDIS_MNEMONIC_KANDB, + ZYDIS_MNEMONIC_KANDD, + ZYDIS_MNEMONIC_KANDN, + ZYDIS_MNEMONIC_KANDNB, + ZYDIS_MNEMONIC_KANDND, + ZYDIS_MNEMONIC_KANDNQ, + ZYDIS_MNEMONIC_KANDNR, + ZYDIS_MNEMONIC_KANDNW, + ZYDIS_MNEMONIC_KANDQ, + ZYDIS_MNEMONIC_KANDW, + ZYDIS_MNEMONIC_KCONCATH, + ZYDIS_MNEMONIC_KCONCATL, + ZYDIS_MNEMONIC_KEXTRACT, + ZYDIS_MNEMONIC_KMERGE2L1H, + ZYDIS_MNEMONIC_KMERGE2L1L, + ZYDIS_MNEMONIC_KMOV, + ZYDIS_MNEMONIC_KMOVB, + ZYDIS_MNEMONIC_KMOVD, + ZYDIS_MNEMONIC_KMOVQ, + ZYDIS_MNEMONIC_KMOVW, + ZYDIS_MNEMONIC_KNOT, + ZYDIS_MNEMONIC_KNOTB, + ZYDIS_MNEMONIC_KNOTD, + ZYDIS_MNEMONIC_KNOTQ, + ZYDIS_MNEMONIC_KNOTW, + ZYDIS_MNEMONIC_KOR, + ZYDIS_MNEMONIC_KORB, + ZYDIS_MNEMONIC_KORD, + ZYDIS_MNEMONIC_KORQ, + ZYDIS_MNEMONIC_KORTEST, + ZYDIS_MNEMONIC_KORTESTB, + ZYDIS_MNEMONIC_KORTESTD, + ZYDIS_MNEMONIC_KORTESTQ, + ZYDIS_MNEMONIC_KORTESTW, + ZYDIS_MNEMONIC_KORW, + ZYDIS_MNEMONIC_KSHIFTLB, + ZYDIS_MNEMONIC_KSHIFTLD, + ZYDIS_MNEMONIC_KSHIFTLQ, + ZYDIS_MNEMONIC_KSHIFTLW, + ZYDIS_MNEMONIC_KSHIFTRB, + ZYDIS_MNEMONIC_KSHIFTRD, + ZYDIS_MNEMONIC_KSHIFTRQ, + ZYDIS_MNEMONIC_KSHIFTRW, + ZYDIS_MNEMONIC_KTESTB, + ZYDIS_MNEMONIC_KTESTD, + ZYDIS_MNEMONIC_KTESTQ, + ZYDIS_MNEMONIC_KTESTW, + ZYDIS_MNEMONIC_KUNPCKBW, + ZYDIS_MNEMONIC_KUNPCKDQ, + ZYDIS_MNEMONIC_KUNPCKWD, + ZYDIS_MNEMONIC_KXNOR, + ZYDIS_MNEMONIC_KXNORB, + ZYDIS_MNEMONIC_KXNORD, + ZYDIS_MNEMONIC_KXNORQ, + ZYDIS_MNEMONIC_KXNORW, + ZYDIS_MNEMONIC_KXOR, + ZYDIS_MNEMONIC_KXORB, + ZYDIS_MNEMONIC_KXORD, + ZYDIS_MNEMONIC_KXORQ, + ZYDIS_MNEMONIC_KXORW, + ZYDIS_MNEMONIC_LAHF, + ZYDIS_MNEMONIC_LAR, + ZYDIS_MNEMONIC_LDDQU, + ZYDIS_MNEMONIC_LDMXCSR, + ZYDIS_MNEMONIC_LDS, + ZYDIS_MNEMONIC_LDTILECFG, + ZYDIS_MNEMONIC_LEA, + ZYDIS_MNEMONIC_LEAVE, + ZYDIS_MNEMONIC_LES, + ZYDIS_MNEMONIC_LFENCE, + ZYDIS_MNEMONIC_LFS, + ZYDIS_MNEMONIC_LGDT, + ZYDIS_MNEMONIC_LGS, + ZYDIS_MNEMONIC_LIDT, + ZYDIS_MNEMONIC_LLDT, + ZYDIS_MNEMONIC_LLWPCB, + ZYDIS_MNEMONIC_LMSW, + ZYDIS_MNEMONIC_LODSB, + ZYDIS_MNEMONIC_LODSD, + ZYDIS_MNEMONIC_LODSQ, + ZYDIS_MNEMONIC_LODSW, + ZYDIS_MNEMONIC_LOOP, + ZYDIS_MNEMONIC_LOOPE, + ZYDIS_MNEMONIC_LOOPNE, + ZYDIS_MNEMONIC_LSL, + ZYDIS_MNEMONIC_LSS, + ZYDIS_MNEMONIC_LTR, + ZYDIS_MNEMONIC_LWPINS, + ZYDIS_MNEMONIC_LWPVAL, + ZYDIS_MNEMONIC_LZCNT, + ZYDIS_MNEMONIC_MASKMOVDQU, + ZYDIS_MNEMONIC_MASKMOVQ, + ZYDIS_MNEMONIC_MAXPD, + ZYDIS_MNEMONIC_MAXPS, + ZYDIS_MNEMONIC_MAXSD, + ZYDIS_MNEMONIC_MAXSS, + ZYDIS_MNEMONIC_MCOMMIT, + ZYDIS_MNEMONIC_MFENCE, + ZYDIS_MNEMONIC_MINPD, + ZYDIS_MNEMONIC_MINPS, + ZYDIS_MNEMONIC_MINSD, + ZYDIS_MNEMONIC_MINSS, + ZYDIS_MNEMONIC_MONITOR, + ZYDIS_MNEMONIC_MONITORX, + ZYDIS_MNEMONIC_MONTMUL, + ZYDIS_MNEMONIC_MOV, + ZYDIS_MNEMONIC_MOVAPD, + ZYDIS_MNEMONIC_MOVAPS, + ZYDIS_MNEMONIC_MOVBE, + ZYDIS_MNEMONIC_MOVD, + ZYDIS_MNEMONIC_MOVDDUP, + ZYDIS_MNEMONIC_MOVDIR64B, + ZYDIS_MNEMONIC_MOVDIRI, + ZYDIS_MNEMONIC_MOVDQ2Q, + ZYDIS_MNEMONIC_MOVDQA, + ZYDIS_MNEMONIC_MOVDQU, + ZYDIS_MNEMONIC_MOVHLPS, + ZYDIS_MNEMONIC_MOVHPD, + ZYDIS_MNEMONIC_MOVHPS, + ZYDIS_MNEMONIC_MOVLHPS, + ZYDIS_MNEMONIC_MOVLPD, + ZYDIS_MNEMONIC_MOVLPS, + ZYDIS_MNEMONIC_MOVMSKPD, + ZYDIS_MNEMONIC_MOVMSKPS, + ZYDIS_MNEMONIC_MOVNTDQ, + ZYDIS_MNEMONIC_MOVNTDQA, + ZYDIS_MNEMONIC_MOVNTI, + ZYDIS_MNEMONIC_MOVNTPD, + ZYDIS_MNEMONIC_MOVNTPS, + ZYDIS_MNEMONIC_MOVNTQ, + ZYDIS_MNEMONIC_MOVNTSD, + ZYDIS_MNEMONIC_MOVNTSS, + ZYDIS_MNEMONIC_MOVQ, + ZYDIS_MNEMONIC_MOVQ2DQ, + ZYDIS_MNEMONIC_MOVSB, + ZYDIS_MNEMONIC_MOVSD, + ZYDIS_MNEMONIC_MOVSHDUP, + ZYDIS_MNEMONIC_MOVSLDUP, + ZYDIS_MNEMONIC_MOVSQ, + ZYDIS_MNEMONIC_MOVSS, + ZYDIS_MNEMONIC_MOVSW, + ZYDIS_MNEMONIC_MOVSX, + ZYDIS_MNEMONIC_MOVSXD, + ZYDIS_MNEMONIC_MOVUPD, + ZYDIS_MNEMONIC_MOVUPS, + ZYDIS_MNEMONIC_MOVZX, + ZYDIS_MNEMONIC_MPSADBW, + ZYDIS_MNEMONIC_MUL, + ZYDIS_MNEMONIC_MULPD, + ZYDIS_MNEMONIC_MULPS, + ZYDIS_MNEMONIC_MULSD, + ZYDIS_MNEMONIC_MULSS, + ZYDIS_MNEMONIC_MULX, + ZYDIS_MNEMONIC_MWAIT, + ZYDIS_MNEMONIC_MWAITX, + ZYDIS_MNEMONIC_NEG, + ZYDIS_MNEMONIC_NOP, + ZYDIS_MNEMONIC_NOT, + ZYDIS_MNEMONIC_OR, + ZYDIS_MNEMONIC_ORPD, + ZYDIS_MNEMONIC_ORPS, + ZYDIS_MNEMONIC_OUT, + ZYDIS_MNEMONIC_OUTSB, + ZYDIS_MNEMONIC_OUTSD, + ZYDIS_MNEMONIC_OUTSW, + ZYDIS_MNEMONIC_PABSB, + ZYDIS_MNEMONIC_PABSD, + ZYDIS_MNEMONIC_PABSW, + ZYDIS_MNEMONIC_PACKSSDW, + ZYDIS_MNEMONIC_PACKSSWB, + ZYDIS_MNEMONIC_PACKUSDW, + ZYDIS_MNEMONIC_PACKUSWB, + ZYDIS_MNEMONIC_PADDB, + ZYDIS_MNEMONIC_PADDD, + ZYDIS_MNEMONIC_PADDQ, + ZYDIS_MNEMONIC_PADDSB, + ZYDIS_MNEMONIC_PADDSW, + ZYDIS_MNEMONIC_PADDUSB, + ZYDIS_MNEMONIC_PADDUSW, + ZYDIS_MNEMONIC_PADDW, + ZYDIS_MNEMONIC_PALIGNR, + ZYDIS_MNEMONIC_PAND, + ZYDIS_MNEMONIC_PANDN, + ZYDIS_MNEMONIC_PAUSE, + ZYDIS_MNEMONIC_PAVGB, + ZYDIS_MNEMONIC_PAVGUSB, + ZYDIS_MNEMONIC_PAVGW, + ZYDIS_MNEMONIC_PBLENDVB, + ZYDIS_MNEMONIC_PBLENDW, + ZYDIS_MNEMONIC_PCLMULQDQ, + ZYDIS_MNEMONIC_PCMPEQB, + ZYDIS_MNEMONIC_PCMPEQD, + ZYDIS_MNEMONIC_PCMPEQQ, + ZYDIS_MNEMONIC_PCMPEQW, + ZYDIS_MNEMONIC_PCMPESTRI, + ZYDIS_MNEMONIC_PCMPESTRM, + ZYDIS_MNEMONIC_PCMPGTB, + ZYDIS_MNEMONIC_PCMPGTD, + ZYDIS_MNEMONIC_PCMPGTQ, + ZYDIS_MNEMONIC_PCMPGTW, + ZYDIS_MNEMONIC_PCMPISTRI, + ZYDIS_MNEMONIC_PCMPISTRM, + ZYDIS_MNEMONIC_PCONFIG, + ZYDIS_MNEMONIC_PDEP, + ZYDIS_MNEMONIC_PEXT, + ZYDIS_MNEMONIC_PEXTRB, + ZYDIS_MNEMONIC_PEXTRD, + ZYDIS_MNEMONIC_PEXTRQ, + ZYDIS_MNEMONIC_PEXTRW, + ZYDIS_MNEMONIC_PF2ID, + ZYDIS_MNEMONIC_PF2IW, + ZYDIS_MNEMONIC_PFACC, + ZYDIS_MNEMONIC_PFADD, + ZYDIS_MNEMONIC_PFCMPEQ, + ZYDIS_MNEMONIC_PFCMPGE, + ZYDIS_MNEMONIC_PFCMPGT, + ZYDIS_MNEMONIC_PFCPIT1, + ZYDIS_MNEMONIC_PFMAX, + ZYDIS_MNEMONIC_PFMIN, + ZYDIS_MNEMONIC_PFMUL, + ZYDIS_MNEMONIC_PFNACC, + ZYDIS_MNEMONIC_PFPNACC, + ZYDIS_MNEMONIC_PFRCP, + ZYDIS_MNEMONIC_PFRCPIT2, + ZYDIS_MNEMONIC_PFRSQIT1, + ZYDIS_MNEMONIC_PFSQRT, + ZYDIS_MNEMONIC_PFSUB, + ZYDIS_MNEMONIC_PFSUBR, + ZYDIS_MNEMONIC_PHADDD, + ZYDIS_MNEMONIC_PHADDSW, + ZYDIS_MNEMONIC_PHADDW, + ZYDIS_MNEMONIC_PHMINPOSUW, + ZYDIS_MNEMONIC_PHSUBD, + ZYDIS_MNEMONIC_PHSUBSW, + ZYDIS_MNEMONIC_PHSUBW, + ZYDIS_MNEMONIC_PI2FD, + ZYDIS_MNEMONIC_PI2FW, + ZYDIS_MNEMONIC_PINSRB, + ZYDIS_MNEMONIC_PINSRD, + ZYDIS_MNEMONIC_PINSRQ, + ZYDIS_MNEMONIC_PINSRW, + ZYDIS_MNEMONIC_PMADDUBSW, + ZYDIS_MNEMONIC_PMADDWD, + ZYDIS_MNEMONIC_PMAXSB, + ZYDIS_MNEMONIC_PMAXSD, + ZYDIS_MNEMONIC_PMAXSW, + ZYDIS_MNEMONIC_PMAXUB, + ZYDIS_MNEMONIC_PMAXUD, + ZYDIS_MNEMONIC_PMAXUW, + ZYDIS_MNEMONIC_PMINSB, + ZYDIS_MNEMONIC_PMINSD, + ZYDIS_MNEMONIC_PMINSW, + ZYDIS_MNEMONIC_PMINUB, + ZYDIS_MNEMONIC_PMINUD, + ZYDIS_MNEMONIC_PMINUW, + ZYDIS_MNEMONIC_PMOVMSKB, + ZYDIS_MNEMONIC_PMOVSXBD, + ZYDIS_MNEMONIC_PMOVSXBQ, + ZYDIS_MNEMONIC_PMOVSXBW, + ZYDIS_MNEMONIC_PMOVSXDQ, + ZYDIS_MNEMONIC_PMOVSXWD, + ZYDIS_MNEMONIC_PMOVSXWQ, + ZYDIS_MNEMONIC_PMOVZXBD, + ZYDIS_MNEMONIC_PMOVZXBQ, + ZYDIS_MNEMONIC_PMOVZXBW, + ZYDIS_MNEMONIC_PMOVZXDQ, + ZYDIS_MNEMONIC_PMOVZXWD, + ZYDIS_MNEMONIC_PMOVZXWQ, + ZYDIS_MNEMONIC_PMULDQ, + ZYDIS_MNEMONIC_PMULHRSW, + ZYDIS_MNEMONIC_PMULHRW, + ZYDIS_MNEMONIC_PMULHUW, + ZYDIS_MNEMONIC_PMULHW, + ZYDIS_MNEMONIC_PMULLD, + ZYDIS_MNEMONIC_PMULLW, + ZYDIS_MNEMONIC_PMULUDQ, + ZYDIS_MNEMONIC_POP, + ZYDIS_MNEMONIC_POPA, + ZYDIS_MNEMONIC_POPAD, + ZYDIS_MNEMONIC_POPCNT, + ZYDIS_MNEMONIC_POPF, + ZYDIS_MNEMONIC_POPFD, + ZYDIS_MNEMONIC_POPFQ, + ZYDIS_MNEMONIC_POR, + ZYDIS_MNEMONIC_PREFETCH, + ZYDIS_MNEMONIC_PREFETCHNTA, + ZYDIS_MNEMONIC_PREFETCHT0, + ZYDIS_MNEMONIC_PREFETCHT1, + ZYDIS_MNEMONIC_PREFETCHT2, + ZYDIS_MNEMONIC_PREFETCHW, + ZYDIS_MNEMONIC_PREFETCHWT1, + ZYDIS_MNEMONIC_PSADBW, + ZYDIS_MNEMONIC_PSHUFB, + ZYDIS_MNEMONIC_PSHUFD, + ZYDIS_MNEMONIC_PSHUFHW, + ZYDIS_MNEMONIC_PSHUFLW, + ZYDIS_MNEMONIC_PSHUFW, + ZYDIS_MNEMONIC_PSIGNB, + ZYDIS_MNEMONIC_PSIGND, + ZYDIS_MNEMONIC_PSIGNW, + ZYDIS_MNEMONIC_PSLLD, + ZYDIS_MNEMONIC_PSLLDQ, + ZYDIS_MNEMONIC_PSLLQ, + ZYDIS_MNEMONIC_PSLLW, + ZYDIS_MNEMONIC_PSMASH, + ZYDIS_MNEMONIC_PSRAD, + ZYDIS_MNEMONIC_PSRAW, + ZYDIS_MNEMONIC_PSRLD, + ZYDIS_MNEMONIC_PSRLDQ, + ZYDIS_MNEMONIC_PSRLQ, + ZYDIS_MNEMONIC_PSRLW, + ZYDIS_MNEMONIC_PSUBB, + ZYDIS_MNEMONIC_PSUBD, + ZYDIS_MNEMONIC_PSUBQ, + ZYDIS_MNEMONIC_PSUBSB, + ZYDIS_MNEMONIC_PSUBSW, + ZYDIS_MNEMONIC_PSUBUSB, + ZYDIS_MNEMONIC_PSUBUSW, + ZYDIS_MNEMONIC_PSUBW, + ZYDIS_MNEMONIC_PSWAPD, + ZYDIS_MNEMONIC_PTEST, + ZYDIS_MNEMONIC_PTWRITE, + ZYDIS_MNEMONIC_PUNPCKHBW, + ZYDIS_MNEMONIC_PUNPCKHDQ, + ZYDIS_MNEMONIC_PUNPCKHQDQ, + ZYDIS_MNEMONIC_PUNPCKHWD, + ZYDIS_MNEMONIC_PUNPCKLBW, + ZYDIS_MNEMONIC_PUNPCKLDQ, + ZYDIS_MNEMONIC_PUNPCKLQDQ, + ZYDIS_MNEMONIC_PUNPCKLWD, + ZYDIS_MNEMONIC_PUSH, + ZYDIS_MNEMONIC_PUSHA, + ZYDIS_MNEMONIC_PUSHAD, + ZYDIS_MNEMONIC_PUSHF, + ZYDIS_MNEMONIC_PUSHFD, + ZYDIS_MNEMONIC_PUSHFQ, + ZYDIS_MNEMONIC_PVALIDATE, + ZYDIS_MNEMONIC_PXOR, + ZYDIS_MNEMONIC_RCL, + ZYDIS_MNEMONIC_RCPPS, + ZYDIS_MNEMONIC_RCPSS, + ZYDIS_MNEMONIC_RCR, + ZYDIS_MNEMONIC_RDFSBASE, + ZYDIS_MNEMONIC_RDGSBASE, + ZYDIS_MNEMONIC_RDMSR, + ZYDIS_MNEMONIC_RDPID, + ZYDIS_MNEMONIC_RDPKRU, + ZYDIS_MNEMONIC_RDPMC, + ZYDIS_MNEMONIC_RDPRU, + ZYDIS_MNEMONIC_RDRAND, + ZYDIS_MNEMONIC_RDSEED, + ZYDIS_MNEMONIC_RDSSPD, + ZYDIS_MNEMONIC_RDSSPQ, + ZYDIS_MNEMONIC_RDTSC, + ZYDIS_MNEMONIC_RDTSCP, + ZYDIS_MNEMONIC_RET, + ZYDIS_MNEMONIC_RMPADJUST, + ZYDIS_MNEMONIC_RMPUPDATE, + ZYDIS_MNEMONIC_ROL, + ZYDIS_MNEMONIC_ROR, + ZYDIS_MNEMONIC_RORX, + ZYDIS_MNEMONIC_ROUNDPD, + ZYDIS_MNEMONIC_ROUNDPS, + ZYDIS_MNEMONIC_ROUNDSD, + ZYDIS_MNEMONIC_ROUNDSS, + ZYDIS_MNEMONIC_RSM, + ZYDIS_MNEMONIC_RSQRTPS, + ZYDIS_MNEMONIC_RSQRTSS, + ZYDIS_MNEMONIC_RSTORSSP, + ZYDIS_MNEMONIC_SAHF, + ZYDIS_MNEMONIC_SALC, + ZYDIS_MNEMONIC_SAR, + ZYDIS_MNEMONIC_SARX, + ZYDIS_MNEMONIC_SAVEPREVSSP, + ZYDIS_MNEMONIC_SBB, + ZYDIS_MNEMONIC_SCASB, + ZYDIS_MNEMONIC_SCASD, + ZYDIS_MNEMONIC_SCASQ, + ZYDIS_MNEMONIC_SCASW, + ZYDIS_MNEMONIC_SERIALIZE, + ZYDIS_MNEMONIC_SETB, + ZYDIS_MNEMONIC_SETBE, + ZYDIS_MNEMONIC_SETL, + ZYDIS_MNEMONIC_SETLE, + ZYDIS_MNEMONIC_SETNB, + ZYDIS_MNEMONIC_SETNBE, + ZYDIS_MNEMONIC_SETNL, + ZYDIS_MNEMONIC_SETNLE, + ZYDIS_MNEMONIC_SETNO, + ZYDIS_MNEMONIC_SETNP, + ZYDIS_MNEMONIC_SETNS, + ZYDIS_MNEMONIC_SETNZ, + ZYDIS_MNEMONIC_SETO, + ZYDIS_MNEMONIC_SETP, + ZYDIS_MNEMONIC_SETS, + ZYDIS_MNEMONIC_SETSSBSY, + ZYDIS_MNEMONIC_SETZ, + ZYDIS_MNEMONIC_SFENCE, + ZYDIS_MNEMONIC_SGDT, + ZYDIS_MNEMONIC_SHA1MSG1, + ZYDIS_MNEMONIC_SHA1MSG2, + ZYDIS_MNEMONIC_SHA1NEXTE, + ZYDIS_MNEMONIC_SHA1RNDS4, + ZYDIS_MNEMONIC_SHA256MSG1, + ZYDIS_MNEMONIC_SHA256MSG2, + ZYDIS_MNEMONIC_SHA256RNDS2, + ZYDIS_MNEMONIC_SHL, + ZYDIS_MNEMONIC_SHLD, + ZYDIS_MNEMONIC_SHLX, + ZYDIS_MNEMONIC_SHR, + ZYDIS_MNEMONIC_SHRD, + ZYDIS_MNEMONIC_SHRX, + ZYDIS_MNEMONIC_SHUFPD, + ZYDIS_MNEMONIC_SHUFPS, + ZYDIS_MNEMONIC_SIDT, + ZYDIS_MNEMONIC_SKINIT, + ZYDIS_MNEMONIC_SLDT, + ZYDIS_MNEMONIC_SLWPCB, + ZYDIS_MNEMONIC_SMSW, + ZYDIS_MNEMONIC_SPFLT, + ZYDIS_MNEMONIC_SQRTPD, + ZYDIS_MNEMONIC_SQRTPS, + ZYDIS_MNEMONIC_SQRTSD, + ZYDIS_MNEMONIC_SQRTSS, + ZYDIS_MNEMONIC_STAC, + ZYDIS_MNEMONIC_STC, + ZYDIS_MNEMONIC_STD, + ZYDIS_MNEMONIC_STGI, + ZYDIS_MNEMONIC_STI, + ZYDIS_MNEMONIC_STMXCSR, + ZYDIS_MNEMONIC_STOSB, + ZYDIS_MNEMONIC_STOSD, + ZYDIS_MNEMONIC_STOSQ, + ZYDIS_MNEMONIC_STOSW, + ZYDIS_MNEMONIC_STR, + ZYDIS_MNEMONIC_STTILECFG, + ZYDIS_MNEMONIC_SUB, + ZYDIS_MNEMONIC_SUBPD, + ZYDIS_MNEMONIC_SUBPS, + ZYDIS_MNEMONIC_SUBSD, + ZYDIS_MNEMONIC_SUBSS, + ZYDIS_MNEMONIC_SWAPGS, + ZYDIS_MNEMONIC_SYSCALL, + ZYDIS_MNEMONIC_SYSENTER, + ZYDIS_MNEMONIC_SYSEXIT, + ZYDIS_MNEMONIC_SYSRET, + ZYDIS_MNEMONIC_T1MSKC, + ZYDIS_MNEMONIC_TDPBF16PS, + ZYDIS_MNEMONIC_TDPBSSD, + ZYDIS_MNEMONIC_TDPBSUD, + ZYDIS_MNEMONIC_TDPBUSD, + ZYDIS_MNEMONIC_TDPBUUD, + ZYDIS_MNEMONIC_TEST, + ZYDIS_MNEMONIC_TILELOADD, + ZYDIS_MNEMONIC_TILELOADDT1, + ZYDIS_MNEMONIC_TILERELEASE, + ZYDIS_MNEMONIC_TILESTORED, + ZYDIS_MNEMONIC_TILEZERO, + ZYDIS_MNEMONIC_TLBSYNC, + ZYDIS_MNEMONIC_TPAUSE, + ZYDIS_MNEMONIC_TZCNT, + ZYDIS_MNEMONIC_TZCNTI, + ZYDIS_MNEMONIC_TZMSK, + ZYDIS_MNEMONIC_UCOMISD, + ZYDIS_MNEMONIC_UCOMISS, + ZYDIS_MNEMONIC_UD0, + ZYDIS_MNEMONIC_UD1, + ZYDIS_MNEMONIC_UD2, + ZYDIS_MNEMONIC_UMONITOR, + ZYDIS_MNEMONIC_UMWAIT, + ZYDIS_MNEMONIC_UNPCKHPD, + ZYDIS_MNEMONIC_UNPCKHPS, + ZYDIS_MNEMONIC_UNPCKLPD, + ZYDIS_MNEMONIC_UNPCKLPS, + ZYDIS_MNEMONIC_V4FMADDPS, + ZYDIS_MNEMONIC_V4FMADDSS, + ZYDIS_MNEMONIC_V4FNMADDPS, + ZYDIS_MNEMONIC_V4FNMADDSS, + ZYDIS_MNEMONIC_VADDNPD, + ZYDIS_MNEMONIC_VADDNPS, + ZYDIS_MNEMONIC_VADDPD, + ZYDIS_MNEMONIC_VADDPS, + ZYDIS_MNEMONIC_VADDSD, + ZYDIS_MNEMONIC_VADDSETSPS, + ZYDIS_MNEMONIC_VADDSS, + ZYDIS_MNEMONIC_VADDSUBPD, + ZYDIS_MNEMONIC_VADDSUBPS, + ZYDIS_MNEMONIC_VAESDEC, + ZYDIS_MNEMONIC_VAESDECLAST, + ZYDIS_MNEMONIC_VAESENC, + ZYDIS_MNEMONIC_VAESENCLAST, + ZYDIS_MNEMONIC_VAESIMC, + ZYDIS_MNEMONIC_VAESKEYGENASSIST, + ZYDIS_MNEMONIC_VALIGND, + ZYDIS_MNEMONIC_VALIGNQ, + ZYDIS_MNEMONIC_VANDNPD, + ZYDIS_MNEMONIC_VANDNPS, + ZYDIS_MNEMONIC_VANDPD, + ZYDIS_MNEMONIC_VANDPS, + ZYDIS_MNEMONIC_VBLENDMPD, + ZYDIS_MNEMONIC_VBLENDMPS, + ZYDIS_MNEMONIC_VBLENDPD, + ZYDIS_MNEMONIC_VBLENDPS, + ZYDIS_MNEMONIC_VBLENDVPD, + ZYDIS_MNEMONIC_VBLENDVPS, + ZYDIS_MNEMONIC_VBROADCASTF128, + ZYDIS_MNEMONIC_VBROADCASTF32X2, + ZYDIS_MNEMONIC_VBROADCASTF32X4, + ZYDIS_MNEMONIC_VBROADCASTF32X8, + ZYDIS_MNEMONIC_VBROADCASTF64X2, + ZYDIS_MNEMONIC_VBROADCASTF64X4, + ZYDIS_MNEMONIC_VBROADCASTI128, + ZYDIS_MNEMONIC_VBROADCASTI32X2, + ZYDIS_MNEMONIC_VBROADCASTI32X4, + ZYDIS_MNEMONIC_VBROADCASTI32X8, + ZYDIS_MNEMONIC_VBROADCASTI64X2, + ZYDIS_MNEMONIC_VBROADCASTI64X4, + ZYDIS_MNEMONIC_VBROADCASTSD, + ZYDIS_MNEMONIC_VBROADCASTSS, + ZYDIS_MNEMONIC_VCMPPD, + ZYDIS_MNEMONIC_VCMPPS, + ZYDIS_MNEMONIC_VCMPSD, + ZYDIS_MNEMONIC_VCMPSS, + ZYDIS_MNEMONIC_VCOMISD, + ZYDIS_MNEMONIC_VCOMISS, + ZYDIS_MNEMONIC_VCOMPRESSPD, + ZYDIS_MNEMONIC_VCOMPRESSPS, + ZYDIS_MNEMONIC_VCVTDQ2PD, + ZYDIS_MNEMONIC_VCVTDQ2PS, + ZYDIS_MNEMONIC_VCVTFXPNTDQ2PS, + ZYDIS_MNEMONIC_VCVTFXPNTPD2DQ, + ZYDIS_MNEMONIC_VCVTFXPNTPD2UDQ, + ZYDIS_MNEMONIC_VCVTFXPNTPS2DQ, + ZYDIS_MNEMONIC_VCVTFXPNTPS2UDQ, + ZYDIS_MNEMONIC_VCVTFXPNTUDQ2PS, + ZYDIS_MNEMONIC_VCVTNE2PS2BF16, + ZYDIS_MNEMONIC_VCVTNEPS2BF16, + ZYDIS_MNEMONIC_VCVTPD2DQ, + ZYDIS_MNEMONIC_VCVTPD2PS, + ZYDIS_MNEMONIC_VCVTPD2QQ, + ZYDIS_MNEMONIC_VCVTPD2UDQ, + ZYDIS_MNEMONIC_VCVTPD2UQQ, + ZYDIS_MNEMONIC_VCVTPH2PS, + ZYDIS_MNEMONIC_VCVTPS2DQ, + ZYDIS_MNEMONIC_VCVTPS2PD, + ZYDIS_MNEMONIC_VCVTPS2PH, + ZYDIS_MNEMONIC_VCVTPS2QQ, + ZYDIS_MNEMONIC_VCVTPS2UDQ, + ZYDIS_MNEMONIC_VCVTPS2UQQ, + ZYDIS_MNEMONIC_VCVTQQ2PD, + ZYDIS_MNEMONIC_VCVTQQ2PS, + ZYDIS_MNEMONIC_VCVTSD2SI, + ZYDIS_MNEMONIC_VCVTSD2SS, + ZYDIS_MNEMONIC_VCVTSD2USI, + ZYDIS_MNEMONIC_VCVTSI2SD, + ZYDIS_MNEMONIC_VCVTSI2SS, + ZYDIS_MNEMONIC_VCVTSS2SD, + ZYDIS_MNEMONIC_VCVTSS2SI, + ZYDIS_MNEMONIC_VCVTSS2USI, + ZYDIS_MNEMONIC_VCVTTPD2DQ, + ZYDIS_MNEMONIC_VCVTTPD2QQ, + ZYDIS_MNEMONIC_VCVTTPD2UDQ, + ZYDIS_MNEMONIC_VCVTTPD2UQQ, + ZYDIS_MNEMONIC_VCVTTPS2DQ, + ZYDIS_MNEMONIC_VCVTTPS2QQ, + ZYDIS_MNEMONIC_VCVTTPS2UDQ, + ZYDIS_MNEMONIC_VCVTTPS2UQQ, + ZYDIS_MNEMONIC_VCVTTSD2SI, + ZYDIS_MNEMONIC_VCVTTSD2USI, + ZYDIS_MNEMONIC_VCVTTSS2SI, + ZYDIS_MNEMONIC_VCVTTSS2USI, + ZYDIS_MNEMONIC_VCVTUDQ2PD, + ZYDIS_MNEMONIC_VCVTUDQ2PS, + ZYDIS_MNEMONIC_VCVTUQQ2PD, + ZYDIS_MNEMONIC_VCVTUQQ2PS, + ZYDIS_MNEMONIC_VCVTUSI2SD, + ZYDIS_MNEMONIC_VCVTUSI2SS, + ZYDIS_MNEMONIC_VDBPSADBW, + ZYDIS_MNEMONIC_VDIVPD, + ZYDIS_MNEMONIC_VDIVPS, + ZYDIS_MNEMONIC_VDIVSD, + ZYDIS_MNEMONIC_VDIVSS, + ZYDIS_MNEMONIC_VDPBF16PS, + ZYDIS_MNEMONIC_VDPPD, + ZYDIS_MNEMONIC_VDPPS, + ZYDIS_MNEMONIC_VERR, + ZYDIS_MNEMONIC_VERW, + ZYDIS_MNEMONIC_VEXP223PS, + ZYDIS_MNEMONIC_VEXP2PD, + ZYDIS_MNEMONIC_VEXP2PS, + ZYDIS_MNEMONIC_VEXPANDPD, + ZYDIS_MNEMONIC_VEXPANDPS, + ZYDIS_MNEMONIC_VEXTRACTF128, + ZYDIS_MNEMONIC_VEXTRACTF32X4, + ZYDIS_MNEMONIC_VEXTRACTF32X8, + ZYDIS_MNEMONIC_VEXTRACTF64X2, + ZYDIS_MNEMONIC_VEXTRACTF64X4, + ZYDIS_MNEMONIC_VEXTRACTI128, + ZYDIS_MNEMONIC_VEXTRACTI32X4, + ZYDIS_MNEMONIC_VEXTRACTI32X8, + ZYDIS_MNEMONIC_VEXTRACTI64X2, + ZYDIS_MNEMONIC_VEXTRACTI64X4, + ZYDIS_MNEMONIC_VEXTRACTPS, + ZYDIS_MNEMONIC_VFIXUPIMMPD, + ZYDIS_MNEMONIC_VFIXUPIMMPS, + ZYDIS_MNEMONIC_VFIXUPIMMSD, + ZYDIS_MNEMONIC_VFIXUPIMMSS, + ZYDIS_MNEMONIC_VFIXUPNANPD, + ZYDIS_MNEMONIC_VFIXUPNANPS, + ZYDIS_MNEMONIC_VFMADD132PD, + ZYDIS_MNEMONIC_VFMADD132PS, + ZYDIS_MNEMONIC_VFMADD132SD, + ZYDIS_MNEMONIC_VFMADD132SS, + ZYDIS_MNEMONIC_VFMADD213PD, + ZYDIS_MNEMONIC_VFMADD213PS, + ZYDIS_MNEMONIC_VFMADD213SD, + ZYDIS_MNEMONIC_VFMADD213SS, + ZYDIS_MNEMONIC_VFMADD231PD, + ZYDIS_MNEMONIC_VFMADD231PS, + ZYDIS_MNEMONIC_VFMADD231SD, + ZYDIS_MNEMONIC_VFMADD231SS, + ZYDIS_MNEMONIC_VFMADD233PS, + ZYDIS_MNEMONIC_VFMADDPD, + ZYDIS_MNEMONIC_VFMADDPS, + ZYDIS_MNEMONIC_VFMADDSD, + ZYDIS_MNEMONIC_VFMADDSS, + ZYDIS_MNEMONIC_VFMADDSUB132PD, + ZYDIS_MNEMONIC_VFMADDSUB132PS, + ZYDIS_MNEMONIC_VFMADDSUB213PD, + ZYDIS_MNEMONIC_VFMADDSUB213PS, + ZYDIS_MNEMONIC_VFMADDSUB231PD, + ZYDIS_MNEMONIC_VFMADDSUB231PS, + ZYDIS_MNEMONIC_VFMADDSUBPD, + ZYDIS_MNEMONIC_VFMADDSUBPS, + ZYDIS_MNEMONIC_VFMSUB132PD, + ZYDIS_MNEMONIC_VFMSUB132PS, + ZYDIS_MNEMONIC_VFMSUB132SD, + ZYDIS_MNEMONIC_VFMSUB132SS, + ZYDIS_MNEMONIC_VFMSUB213PD, + ZYDIS_MNEMONIC_VFMSUB213PS, + ZYDIS_MNEMONIC_VFMSUB213SD, + ZYDIS_MNEMONIC_VFMSUB213SS, + ZYDIS_MNEMONIC_VFMSUB231PD, + ZYDIS_MNEMONIC_VFMSUB231PS, + ZYDIS_MNEMONIC_VFMSUB231SD, + ZYDIS_MNEMONIC_VFMSUB231SS, + ZYDIS_MNEMONIC_VFMSUBADD132PD, + ZYDIS_MNEMONIC_VFMSUBADD132PS, + ZYDIS_MNEMONIC_VFMSUBADD213PD, + ZYDIS_MNEMONIC_VFMSUBADD213PS, + ZYDIS_MNEMONIC_VFMSUBADD231PD, + ZYDIS_MNEMONIC_VFMSUBADD231PS, + ZYDIS_MNEMONIC_VFMSUBADDPD, + ZYDIS_MNEMONIC_VFMSUBADDPS, + ZYDIS_MNEMONIC_VFMSUBPD, + ZYDIS_MNEMONIC_VFMSUBPS, + ZYDIS_MNEMONIC_VFMSUBSD, + ZYDIS_MNEMONIC_VFMSUBSS, + ZYDIS_MNEMONIC_VFNMADD132PD, + ZYDIS_MNEMONIC_VFNMADD132PS, + ZYDIS_MNEMONIC_VFNMADD132SD, + ZYDIS_MNEMONIC_VFNMADD132SS, + ZYDIS_MNEMONIC_VFNMADD213PD, + ZYDIS_MNEMONIC_VFNMADD213PS, + ZYDIS_MNEMONIC_VFNMADD213SD, + ZYDIS_MNEMONIC_VFNMADD213SS, + ZYDIS_MNEMONIC_VFNMADD231PD, + ZYDIS_MNEMONIC_VFNMADD231PS, + ZYDIS_MNEMONIC_VFNMADD231SD, + ZYDIS_MNEMONIC_VFNMADD231SS, + ZYDIS_MNEMONIC_VFNMADDPD, + ZYDIS_MNEMONIC_VFNMADDPS, + ZYDIS_MNEMONIC_VFNMADDSD, + ZYDIS_MNEMONIC_VFNMADDSS, + ZYDIS_MNEMONIC_VFNMSUB132PD, + ZYDIS_MNEMONIC_VFNMSUB132PS, + ZYDIS_MNEMONIC_VFNMSUB132SD, + ZYDIS_MNEMONIC_VFNMSUB132SS, + ZYDIS_MNEMONIC_VFNMSUB213PD, + ZYDIS_MNEMONIC_VFNMSUB213PS, + ZYDIS_MNEMONIC_VFNMSUB213SD, + ZYDIS_MNEMONIC_VFNMSUB213SS, + ZYDIS_MNEMONIC_VFNMSUB231PD, + ZYDIS_MNEMONIC_VFNMSUB231PS, + ZYDIS_MNEMONIC_VFNMSUB231SD, + ZYDIS_MNEMONIC_VFNMSUB231SS, + ZYDIS_MNEMONIC_VFNMSUBPD, + ZYDIS_MNEMONIC_VFNMSUBPS, + ZYDIS_MNEMONIC_VFNMSUBSD, + ZYDIS_MNEMONIC_VFNMSUBSS, + ZYDIS_MNEMONIC_VFPCLASSPD, + ZYDIS_MNEMONIC_VFPCLASSPS, + ZYDIS_MNEMONIC_VFPCLASSSD, + ZYDIS_MNEMONIC_VFPCLASSSS, + ZYDIS_MNEMONIC_VFRCZPD, + ZYDIS_MNEMONIC_VFRCZPS, + ZYDIS_MNEMONIC_VFRCZSD, + ZYDIS_MNEMONIC_VFRCZSS, + ZYDIS_MNEMONIC_VGATHERDPD, + ZYDIS_MNEMONIC_VGATHERDPS, + ZYDIS_MNEMONIC_VGATHERPF0DPD, + ZYDIS_MNEMONIC_VGATHERPF0DPS, + ZYDIS_MNEMONIC_VGATHERPF0HINTDPD, + ZYDIS_MNEMONIC_VGATHERPF0HINTDPS, + ZYDIS_MNEMONIC_VGATHERPF0QPD, + ZYDIS_MNEMONIC_VGATHERPF0QPS, + ZYDIS_MNEMONIC_VGATHERPF1DPD, + ZYDIS_MNEMONIC_VGATHERPF1DPS, + ZYDIS_MNEMONIC_VGATHERPF1QPD, + ZYDIS_MNEMONIC_VGATHERPF1QPS, + ZYDIS_MNEMONIC_VGATHERQPD, + ZYDIS_MNEMONIC_VGATHERQPS, + ZYDIS_MNEMONIC_VGETEXPPD, + ZYDIS_MNEMONIC_VGETEXPPS, + ZYDIS_MNEMONIC_VGETEXPSD, + ZYDIS_MNEMONIC_VGETEXPSS, + ZYDIS_MNEMONIC_VGETMANTPD, + ZYDIS_MNEMONIC_VGETMANTPS, + ZYDIS_MNEMONIC_VGETMANTSD, + ZYDIS_MNEMONIC_VGETMANTSS, + ZYDIS_MNEMONIC_VGF2P8AFFINEINVQB, + ZYDIS_MNEMONIC_VGF2P8AFFINEQB, + ZYDIS_MNEMONIC_VGF2P8MULB, + ZYDIS_MNEMONIC_VGMAXABSPS, + ZYDIS_MNEMONIC_VGMAXPD, + ZYDIS_MNEMONIC_VGMAXPS, + ZYDIS_MNEMONIC_VGMINPD, + ZYDIS_MNEMONIC_VGMINPS, + ZYDIS_MNEMONIC_VHADDPD, + ZYDIS_MNEMONIC_VHADDPS, + ZYDIS_MNEMONIC_VHSUBPD, + ZYDIS_MNEMONIC_VHSUBPS, + ZYDIS_MNEMONIC_VINSERTF128, + ZYDIS_MNEMONIC_VINSERTF32X4, + ZYDIS_MNEMONIC_VINSERTF32X8, + ZYDIS_MNEMONIC_VINSERTF64X2, + ZYDIS_MNEMONIC_VINSERTF64X4, + ZYDIS_MNEMONIC_VINSERTI128, + ZYDIS_MNEMONIC_VINSERTI32X4, + ZYDIS_MNEMONIC_VINSERTI32X8, + ZYDIS_MNEMONIC_VINSERTI64X2, + ZYDIS_MNEMONIC_VINSERTI64X4, + ZYDIS_MNEMONIC_VINSERTPS, + ZYDIS_MNEMONIC_VLDDQU, + ZYDIS_MNEMONIC_VLDMXCSR, + ZYDIS_MNEMONIC_VLOADUNPACKHD, + ZYDIS_MNEMONIC_VLOADUNPACKHPD, + ZYDIS_MNEMONIC_VLOADUNPACKHPS, + ZYDIS_MNEMONIC_VLOADUNPACKHQ, + ZYDIS_MNEMONIC_VLOADUNPACKLD, + ZYDIS_MNEMONIC_VLOADUNPACKLPD, + ZYDIS_MNEMONIC_VLOADUNPACKLPS, + ZYDIS_MNEMONIC_VLOADUNPACKLQ, + ZYDIS_MNEMONIC_VLOG2PS, + ZYDIS_MNEMONIC_VMASKMOVDQU, + ZYDIS_MNEMONIC_VMASKMOVPD, + ZYDIS_MNEMONIC_VMASKMOVPS, + ZYDIS_MNEMONIC_VMAXPD, + ZYDIS_MNEMONIC_VMAXPS, + ZYDIS_MNEMONIC_VMAXSD, + ZYDIS_MNEMONIC_VMAXSS, + ZYDIS_MNEMONIC_VMCALL, + ZYDIS_MNEMONIC_VMCLEAR, + ZYDIS_MNEMONIC_VMFUNC, + ZYDIS_MNEMONIC_VMINPD, + ZYDIS_MNEMONIC_VMINPS, + ZYDIS_MNEMONIC_VMINSD, + ZYDIS_MNEMONIC_VMINSS, + ZYDIS_MNEMONIC_VMLAUNCH, + ZYDIS_MNEMONIC_VMLOAD, + ZYDIS_MNEMONIC_VMMCALL, + ZYDIS_MNEMONIC_VMOVAPD, + ZYDIS_MNEMONIC_VMOVAPS, + ZYDIS_MNEMONIC_VMOVD, + ZYDIS_MNEMONIC_VMOVDDUP, + ZYDIS_MNEMONIC_VMOVDQA, + ZYDIS_MNEMONIC_VMOVDQA32, + ZYDIS_MNEMONIC_VMOVDQA64, + ZYDIS_MNEMONIC_VMOVDQU, + ZYDIS_MNEMONIC_VMOVDQU16, + ZYDIS_MNEMONIC_VMOVDQU32, + ZYDIS_MNEMONIC_VMOVDQU64, + ZYDIS_MNEMONIC_VMOVDQU8, + ZYDIS_MNEMONIC_VMOVHLPS, + ZYDIS_MNEMONIC_VMOVHPD, + ZYDIS_MNEMONIC_VMOVHPS, + ZYDIS_MNEMONIC_VMOVLHPS, + ZYDIS_MNEMONIC_VMOVLPD, + ZYDIS_MNEMONIC_VMOVLPS, + ZYDIS_MNEMONIC_VMOVMSKPD, + ZYDIS_MNEMONIC_VMOVMSKPS, + ZYDIS_MNEMONIC_VMOVNRAPD, + ZYDIS_MNEMONIC_VMOVNRAPS, + ZYDIS_MNEMONIC_VMOVNRNGOAPD, + ZYDIS_MNEMONIC_VMOVNRNGOAPS, + ZYDIS_MNEMONIC_VMOVNTDQ, + ZYDIS_MNEMONIC_VMOVNTDQA, + ZYDIS_MNEMONIC_VMOVNTPD, + ZYDIS_MNEMONIC_VMOVNTPS, + ZYDIS_MNEMONIC_VMOVQ, + ZYDIS_MNEMONIC_VMOVSD, + ZYDIS_MNEMONIC_VMOVSHDUP, + ZYDIS_MNEMONIC_VMOVSLDUP, + ZYDIS_MNEMONIC_VMOVSS, + ZYDIS_MNEMONIC_VMOVUPD, + ZYDIS_MNEMONIC_VMOVUPS, + ZYDIS_MNEMONIC_VMPSADBW, + ZYDIS_MNEMONIC_VMPTRLD, + ZYDIS_MNEMONIC_VMPTRST, + ZYDIS_MNEMONIC_VMREAD, + ZYDIS_MNEMONIC_VMRESUME, + ZYDIS_MNEMONIC_VMRUN, + ZYDIS_MNEMONIC_VMSAVE, + ZYDIS_MNEMONIC_VMULPD, + ZYDIS_MNEMONIC_VMULPS, + ZYDIS_MNEMONIC_VMULSD, + ZYDIS_MNEMONIC_VMULSS, + ZYDIS_MNEMONIC_VMWRITE, + ZYDIS_MNEMONIC_VMXOFF, + ZYDIS_MNEMONIC_VMXON, + ZYDIS_MNEMONIC_VORPD, + ZYDIS_MNEMONIC_VORPS, + ZYDIS_MNEMONIC_VP2INTERSECTD, + ZYDIS_MNEMONIC_VP2INTERSECTQ, + ZYDIS_MNEMONIC_VP4DPWSSD, + ZYDIS_MNEMONIC_VP4DPWSSDS, + ZYDIS_MNEMONIC_VPABSB, + ZYDIS_MNEMONIC_VPABSD, + ZYDIS_MNEMONIC_VPABSQ, + ZYDIS_MNEMONIC_VPABSW, + ZYDIS_MNEMONIC_VPACKSSDW, + ZYDIS_MNEMONIC_VPACKSSWB, + ZYDIS_MNEMONIC_VPACKSTOREHD, + ZYDIS_MNEMONIC_VPACKSTOREHPD, + ZYDIS_MNEMONIC_VPACKSTOREHPS, + ZYDIS_MNEMONIC_VPACKSTOREHQ, + ZYDIS_MNEMONIC_VPACKSTORELD, + ZYDIS_MNEMONIC_VPACKSTORELPD, + ZYDIS_MNEMONIC_VPACKSTORELPS, + ZYDIS_MNEMONIC_VPACKSTORELQ, + ZYDIS_MNEMONIC_VPACKUSDW, + ZYDIS_MNEMONIC_VPACKUSWB, + ZYDIS_MNEMONIC_VPADCD, + ZYDIS_MNEMONIC_VPADDB, + ZYDIS_MNEMONIC_VPADDD, + ZYDIS_MNEMONIC_VPADDQ, + ZYDIS_MNEMONIC_VPADDSB, + ZYDIS_MNEMONIC_VPADDSETCD, + ZYDIS_MNEMONIC_VPADDSETSD, + ZYDIS_MNEMONIC_VPADDSW, + ZYDIS_MNEMONIC_VPADDUSB, + ZYDIS_MNEMONIC_VPADDUSW, + ZYDIS_MNEMONIC_VPADDW, + ZYDIS_MNEMONIC_VPALIGNR, + ZYDIS_MNEMONIC_VPAND, + ZYDIS_MNEMONIC_VPANDD, + ZYDIS_MNEMONIC_VPANDN, + ZYDIS_MNEMONIC_VPANDND, + ZYDIS_MNEMONIC_VPANDNQ, + ZYDIS_MNEMONIC_VPANDQ, + ZYDIS_MNEMONIC_VPAVGB, + ZYDIS_MNEMONIC_VPAVGW, + ZYDIS_MNEMONIC_VPBLENDD, + ZYDIS_MNEMONIC_VPBLENDMB, + ZYDIS_MNEMONIC_VPBLENDMD, + ZYDIS_MNEMONIC_VPBLENDMQ, + ZYDIS_MNEMONIC_VPBLENDMW, + ZYDIS_MNEMONIC_VPBLENDVB, + ZYDIS_MNEMONIC_VPBLENDW, + ZYDIS_MNEMONIC_VPBROADCASTB, + ZYDIS_MNEMONIC_VPBROADCASTD, + ZYDIS_MNEMONIC_VPBROADCASTMB2Q, + ZYDIS_MNEMONIC_VPBROADCASTMW2D, + ZYDIS_MNEMONIC_VPBROADCASTQ, + ZYDIS_MNEMONIC_VPBROADCASTW, + ZYDIS_MNEMONIC_VPCLMULQDQ, + ZYDIS_MNEMONIC_VPCMOV, + ZYDIS_MNEMONIC_VPCMPB, + ZYDIS_MNEMONIC_VPCMPD, + ZYDIS_MNEMONIC_VPCMPEQB, + ZYDIS_MNEMONIC_VPCMPEQD, + ZYDIS_MNEMONIC_VPCMPEQQ, + ZYDIS_MNEMONIC_VPCMPEQW, + ZYDIS_MNEMONIC_VPCMPESTRI, + ZYDIS_MNEMONIC_VPCMPESTRM, + ZYDIS_MNEMONIC_VPCMPGTB, + ZYDIS_MNEMONIC_VPCMPGTD, + ZYDIS_MNEMONIC_VPCMPGTQ, + ZYDIS_MNEMONIC_VPCMPGTW, + ZYDIS_MNEMONIC_VPCMPISTRI, + ZYDIS_MNEMONIC_VPCMPISTRM, + ZYDIS_MNEMONIC_VPCMPLTD, + ZYDIS_MNEMONIC_VPCMPQ, + ZYDIS_MNEMONIC_VPCMPUB, + ZYDIS_MNEMONIC_VPCMPUD, + ZYDIS_MNEMONIC_VPCMPUQ, + ZYDIS_MNEMONIC_VPCMPUW, + ZYDIS_MNEMONIC_VPCMPW, + ZYDIS_MNEMONIC_VPCOMB, + ZYDIS_MNEMONIC_VPCOMD, + ZYDIS_MNEMONIC_VPCOMPRESSB, + ZYDIS_MNEMONIC_VPCOMPRESSD, + ZYDIS_MNEMONIC_VPCOMPRESSQ, + ZYDIS_MNEMONIC_VPCOMPRESSW, + ZYDIS_MNEMONIC_VPCOMQ, + ZYDIS_MNEMONIC_VPCOMUB, + ZYDIS_MNEMONIC_VPCOMUD, + ZYDIS_MNEMONIC_VPCOMUQ, + ZYDIS_MNEMONIC_VPCOMUW, + ZYDIS_MNEMONIC_VPCOMW, + ZYDIS_MNEMONIC_VPCONFLICTD, + ZYDIS_MNEMONIC_VPCONFLICTQ, + ZYDIS_MNEMONIC_VPDPBUSD, + ZYDIS_MNEMONIC_VPDPBUSDS, + ZYDIS_MNEMONIC_VPDPWSSD, + ZYDIS_MNEMONIC_VPDPWSSDS, + ZYDIS_MNEMONIC_VPERM2F128, + ZYDIS_MNEMONIC_VPERM2I128, + ZYDIS_MNEMONIC_VPERMB, + ZYDIS_MNEMONIC_VPERMD, + ZYDIS_MNEMONIC_VPERMF32X4, + ZYDIS_MNEMONIC_VPERMI2B, + ZYDIS_MNEMONIC_VPERMI2D, + ZYDIS_MNEMONIC_VPERMI2PD, + ZYDIS_MNEMONIC_VPERMI2PS, + ZYDIS_MNEMONIC_VPERMI2Q, + ZYDIS_MNEMONIC_VPERMI2W, + ZYDIS_MNEMONIC_VPERMIL2PD, + ZYDIS_MNEMONIC_VPERMIL2PS, + ZYDIS_MNEMONIC_VPERMILPD, + ZYDIS_MNEMONIC_VPERMILPS, + ZYDIS_MNEMONIC_VPERMPD, + ZYDIS_MNEMONIC_VPERMPS, + ZYDIS_MNEMONIC_VPERMQ, + ZYDIS_MNEMONIC_VPERMT2B, + ZYDIS_MNEMONIC_VPERMT2D, + ZYDIS_MNEMONIC_VPERMT2PD, + ZYDIS_MNEMONIC_VPERMT2PS, + ZYDIS_MNEMONIC_VPERMT2Q, + ZYDIS_MNEMONIC_VPERMT2W, + ZYDIS_MNEMONIC_VPERMW, + ZYDIS_MNEMONIC_VPEXPANDB, + ZYDIS_MNEMONIC_VPEXPANDD, + ZYDIS_MNEMONIC_VPEXPANDQ, + ZYDIS_MNEMONIC_VPEXPANDW, + ZYDIS_MNEMONIC_VPEXTRB, + ZYDIS_MNEMONIC_VPEXTRD, + ZYDIS_MNEMONIC_VPEXTRQ, + ZYDIS_MNEMONIC_VPEXTRW, + ZYDIS_MNEMONIC_VPGATHERDD, + ZYDIS_MNEMONIC_VPGATHERDQ, + ZYDIS_MNEMONIC_VPGATHERQD, + ZYDIS_MNEMONIC_VPGATHERQQ, + ZYDIS_MNEMONIC_VPHADDBD, + ZYDIS_MNEMONIC_VPHADDBQ, + ZYDIS_MNEMONIC_VPHADDBW, + ZYDIS_MNEMONIC_VPHADDD, + ZYDIS_MNEMONIC_VPHADDDQ, + ZYDIS_MNEMONIC_VPHADDSW, + ZYDIS_MNEMONIC_VPHADDUBD, + ZYDIS_MNEMONIC_VPHADDUBQ, + ZYDIS_MNEMONIC_VPHADDUBW, + ZYDIS_MNEMONIC_VPHADDUDQ, + ZYDIS_MNEMONIC_VPHADDUWD, + ZYDIS_MNEMONIC_VPHADDUWQ, + ZYDIS_MNEMONIC_VPHADDW, + ZYDIS_MNEMONIC_VPHADDWD, + ZYDIS_MNEMONIC_VPHADDWQ, + ZYDIS_MNEMONIC_VPHMINPOSUW, + ZYDIS_MNEMONIC_VPHSUBBW, + ZYDIS_MNEMONIC_VPHSUBD, + ZYDIS_MNEMONIC_VPHSUBDQ, + ZYDIS_MNEMONIC_VPHSUBSW, + ZYDIS_MNEMONIC_VPHSUBW, + ZYDIS_MNEMONIC_VPHSUBWD, + ZYDIS_MNEMONIC_VPINSRB, + ZYDIS_MNEMONIC_VPINSRD, + ZYDIS_MNEMONIC_VPINSRQ, + ZYDIS_MNEMONIC_VPINSRW, + ZYDIS_MNEMONIC_VPLZCNTD, + ZYDIS_MNEMONIC_VPLZCNTQ, + ZYDIS_MNEMONIC_VPMACSDD, + ZYDIS_MNEMONIC_VPMACSDQH, + ZYDIS_MNEMONIC_VPMACSDQL, + ZYDIS_MNEMONIC_VPMACSSDD, + ZYDIS_MNEMONIC_VPMACSSDQH, + ZYDIS_MNEMONIC_VPMACSSDQL, + ZYDIS_MNEMONIC_VPMACSSWD, + ZYDIS_MNEMONIC_VPMACSSWW, + ZYDIS_MNEMONIC_VPMACSWD, + ZYDIS_MNEMONIC_VPMACSWW, + ZYDIS_MNEMONIC_VPMADCSSWD, + ZYDIS_MNEMONIC_VPMADCSWD, + ZYDIS_MNEMONIC_VPMADD231D, + ZYDIS_MNEMONIC_VPMADD233D, + ZYDIS_MNEMONIC_VPMADD52HUQ, + ZYDIS_MNEMONIC_VPMADD52LUQ, + ZYDIS_MNEMONIC_VPMADDUBSW, + ZYDIS_MNEMONIC_VPMADDWD, + ZYDIS_MNEMONIC_VPMASKMOVD, + ZYDIS_MNEMONIC_VPMASKMOVQ, + ZYDIS_MNEMONIC_VPMAXSB, + ZYDIS_MNEMONIC_VPMAXSD, + ZYDIS_MNEMONIC_VPMAXSQ, + ZYDIS_MNEMONIC_VPMAXSW, + ZYDIS_MNEMONIC_VPMAXUB, + ZYDIS_MNEMONIC_VPMAXUD, + ZYDIS_MNEMONIC_VPMAXUQ, + ZYDIS_MNEMONIC_VPMAXUW, + ZYDIS_MNEMONIC_VPMINSB, + ZYDIS_MNEMONIC_VPMINSD, + ZYDIS_MNEMONIC_VPMINSQ, + ZYDIS_MNEMONIC_VPMINSW, + ZYDIS_MNEMONIC_VPMINUB, + ZYDIS_MNEMONIC_VPMINUD, + ZYDIS_MNEMONIC_VPMINUQ, + ZYDIS_MNEMONIC_VPMINUW, + ZYDIS_MNEMONIC_VPMOVB2M, + ZYDIS_MNEMONIC_VPMOVD2M, + ZYDIS_MNEMONIC_VPMOVDB, + ZYDIS_MNEMONIC_VPMOVDW, + ZYDIS_MNEMONIC_VPMOVM2B, + ZYDIS_MNEMONIC_VPMOVM2D, + ZYDIS_MNEMONIC_VPMOVM2Q, + ZYDIS_MNEMONIC_VPMOVM2W, + ZYDIS_MNEMONIC_VPMOVMSKB, + ZYDIS_MNEMONIC_VPMOVQ2M, + ZYDIS_MNEMONIC_VPMOVQB, + ZYDIS_MNEMONIC_VPMOVQD, + ZYDIS_MNEMONIC_VPMOVQW, + ZYDIS_MNEMONIC_VPMOVSDB, + ZYDIS_MNEMONIC_VPMOVSDW, + ZYDIS_MNEMONIC_VPMOVSQB, + ZYDIS_MNEMONIC_VPMOVSQD, + ZYDIS_MNEMONIC_VPMOVSQW, + ZYDIS_MNEMONIC_VPMOVSWB, + ZYDIS_MNEMONIC_VPMOVSXBD, + ZYDIS_MNEMONIC_VPMOVSXBQ, + ZYDIS_MNEMONIC_VPMOVSXBW, + ZYDIS_MNEMONIC_VPMOVSXDQ, + ZYDIS_MNEMONIC_VPMOVSXWD, + ZYDIS_MNEMONIC_VPMOVSXWQ, + ZYDIS_MNEMONIC_VPMOVUSDB, + ZYDIS_MNEMONIC_VPMOVUSDW, + ZYDIS_MNEMONIC_VPMOVUSQB, + ZYDIS_MNEMONIC_VPMOVUSQD, + ZYDIS_MNEMONIC_VPMOVUSQW, + ZYDIS_MNEMONIC_VPMOVUSWB, + ZYDIS_MNEMONIC_VPMOVW2M, + ZYDIS_MNEMONIC_VPMOVWB, + ZYDIS_MNEMONIC_VPMOVZXBD, + ZYDIS_MNEMONIC_VPMOVZXBQ, + ZYDIS_MNEMONIC_VPMOVZXBW, + ZYDIS_MNEMONIC_VPMOVZXDQ, + ZYDIS_MNEMONIC_VPMOVZXWD, + ZYDIS_MNEMONIC_VPMOVZXWQ, + ZYDIS_MNEMONIC_VPMULDQ, + ZYDIS_MNEMONIC_VPMULHD, + ZYDIS_MNEMONIC_VPMULHRSW, + ZYDIS_MNEMONIC_VPMULHUD, + ZYDIS_MNEMONIC_VPMULHUW, + ZYDIS_MNEMONIC_VPMULHW, + ZYDIS_MNEMONIC_VPMULLD, + ZYDIS_MNEMONIC_VPMULLQ, + ZYDIS_MNEMONIC_VPMULLW, + ZYDIS_MNEMONIC_VPMULTISHIFTQB, + ZYDIS_MNEMONIC_VPMULUDQ, + ZYDIS_MNEMONIC_VPOPCNTB, + ZYDIS_MNEMONIC_VPOPCNTD, + ZYDIS_MNEMONIC_VPOPCNTQ, + ZYDIS_MNEMONIC_VPOPCNTW, + ZYDIS_MNEMONIC_VPOR, + ZYDIS_MNEMONIC_VPORD, + ZYDIS_MNEMONIC_VPORQ, + ZYDIS_MNEMONIC_VPPERM, + ZYDIS_MNEMONIC_VPREFETCH0, + ZYDIS_MNEMONIC_VPREFETCH1, + ZYDIS_MNEMONIC_VPREFETCH2, + ZYDIS_MNEMONIC_VPREFETCHE0, + ZYDIS_MNEMONIC_VPREFETCHE1, + ZYDIS_MNEMONIC_VPREFETCHE2, + ZYDIS_MNEMONIC_VPREFETCHENTA, + ZYDIS_MNEMONIC_VPREFETCHNTA, + ZYDIS_MNEMONIC_VPROLD, + ZYDIS_MNEMONIC_VPROLQ, + ZYDIS_MNEMONIC_VPROLVD, + ZYDIS_MNEMONIC_VPROLVQ, + ZYDIS_MNEMONIC_VPRORD, + ZYDIS_MNEMONIC_VPRORQ, + ZYDIS_MNEMONIC_VPRORVD, + ZYDIS_MNEMONIC_VPRORVQ, + ZYDIS_MNEMONIC_VPROTB, + ZYDIS_MNEMONIC_VPROTD, + ZYDIS_MNEMONIC_VPROTQ, + ZYDIS_MNEMONIC_VPROTW, + ZYDIS_MNEMONIC_VPSADBW, + ZYDIS_MNEMONIC_VPSBBD, + ZYDIS_MNEMONIC_VPSBBRD, + ZYDIS_MNEMONIC_VPSCATTERDD, + ZYDIS_MNEMONIC_VPSCATTERDQ, + ZYDIS_MNEMONIC_VPSCATTERQD, + ZYDIS_MNEMONIC_VPSCATTERQQ, + ZYDIS_MNEMONIC_VPSHAB, + ZYDIS_MNEMONIC_VPSHAD, + ZYDIS_MNEMONIC_VPSHAQ, + ZYDIS_MNEMONIC_VPSHAW, + ZYDIS_MNEMONIC_VPSHLB, + ZYDIS_MNEMONIC_VPSHLD, + ZYDIS_MNEMONIC_VPSHLDD, + ZYDIS_MNEMONIC_VPSHLDQ, + ZYDIS_MNEMONIC_VPSHLDVD, + ZYDIS_MNEMONIC_VPSHLDVQ, + ZYDIS_MNEMONIC_VPSHLDVW, + ZYDIS_MNEMONIC_VPSHLDW, + ZYDIS_MNEMONIC_VPSHLQ, + ZYDIS_MNEMONIC_VPSHLW, + ZYDIS_MNEMONIC_VPSHRDD, + ZYDIS_MNEMONIC_VPSHRDQ, + ZYDIS_MNEMONIC_VPSHRDVD, + ZYDIS_MNEMONIC_VPSHRDVQ, + ZYDIS_MNEMONIC_VPSHRDVW, + ZYDIS_MNEMONIC_VPSHRDW, + ZYDIS_MNEMONIC_VPSHUFB, + ZYDIS_MNEMONIC_VPSHUFBITQMB, + ZYDIS_MNEMONIC_VPSHUFD, + ZYDIS_MNEMONIC_VPSHUFHW, + ZYDIS_MNEMONIC_VPSHUFLW, + ZYDIS_MNEMONIC_VPSIGNB, + ZYDIS_MNEMONIC_VPSIGND, + ZYDIS_MNEMONIC_VPSIGNW, + ZYDIS_MNEMONIC_VPSLLD, + ZYDIS_MNEMONIC_VPSLLDQ, + ZYDIS_MNEMONIC_VPSLLQ, + ZYDIS_MNEMONIC_VPSLLVD, + ZYDIS_MNEMONIC_VPSLLVQ, + ZYDIS_MNEMONIC_VPSLLVW, + ZYDIS_MNEMONIC_VPSLLW, + ZYDIS_MNEMONIC_VPSRAD, + ZYDIS_MNEMONIC_VPSRAQ, + ZYDIS_MNEMONIC_VPSRAVD, + ZYDIS_MNEMONIC_VPSRAVQ, + ZYDIS_MNEMONIC_VPSRAVW, + ZYDIS_MNEMONIC_VPSRAW, + ZYDIS_MNEMONIC_VPSRLD, + ZYDIS_MNEMONIC_VPSRLDQ, + ZYDIS_MNEMONIC_VPSRLQ, + ZYDIS_MNEMONIC_VPSRLVD, + ZYDIS_MNEMONIC_VPSRLVQ, + ZYDIS_MNEMONIC_VPSRLVW, + ZYDIS_MNEMONIC_VPSRLW, + ZYDIS_MNEMONIC_VPSUBB, + ZYDIS_MNEMONIC_VPSUBD, + ZYDIS_MNEMONIC_VPSUBQ, + ZYDIS_MNEMONIC_VPSUBRD, + ZYDIS_MNEMONIC_VPSUBRSETBD, + ZYDIS_MNEMONIC_VPSUBSB, + ZYDIS_MNEMONIC_VPSUBSETBD, + ZYDIS_MNEMONIC_VPSUBSW, + ZYDIS_MNEMONIC_VPSUBUSB, + ZYDIS_MNEMONIC_VPSUBUSW, + ZYDIS_MNEMONIC_VPSUBW, + ZYDIS_MNEMONIC_VPTERNLOGD, + ZYDIS_MNEMONIC_VPTERNLOGQ, + ZYDIS_MNEMONIC_VPTEST, + ZYDIS_MNEMONIC_VPTESTMB, + ZYDIS_MNEMONIC_VPTESTMD, + ZYDIS_MNEMONIC_VPTESTMQ, + ZYDIS_MNEMONIC_VPTESTMW, + ZYDIS_MNEMONIC_VPTESTNMB, + ZYDIS_MNEMONIC_VPTESTNMD, + ZYDIS_MNEMONIC_VPTESTNMQ, + ZYDIS_MNEMONIC_VPTESTNMW, + ZYDIS_MNEMONIC_VPUNPCKHBW, + ZYDIS_MNEMONIC_VPUNPCKHDQ, + ZYDIS_MNEMONIC_VPUNPCKHQDQ, + ZYDIS_MNEMONIC_VPUNPCKHWD, + ZYDIS_MNEMONIC_VPUNPCKLBW, + ZYDIS_MNEMONIC_VPUNPCKLDQ, + ZYDIS_MNEMONIC_VPUNPCKLQDQ, + ZYDIS_MNEMONIC_VPUNPCKLWD, + ZYDIS_MNEMONIC_VPXOR, + ZYDIS_MNEMONIC_VPXORD, + ZYDIS_MNEMONIC_VPXORQ, + ZYDIS_MNEMONIC_VRANGEPD, + ZYDIS_MNEMONIC_VRANGEPS, + ZYDIS_MNEMONIC_VRANGESD, + ZYDIS_MNEMONIC_VRANGESS, + ZYDIS_MNEMONIC_VRCP14PD, + ZYDIS_MNEMONIC_VRCP14PS, + ZYDIS_MNEMONIC_VRCP14SD, + ZYDIS_MNEMONIC_VRCP14SS, + ZYDIS_MNEMONIC_VRCP23PS, + ZYDIS_MNEMONIC_VRCP28PD, + ZYDIS_MNEMONIC_VRCP28PS, + ZYDIS_MNEMONIC_VRCP28SD, + ZYDIS_MNEMONIC_VRCP28SS, + ZYDIS_MNEMONIC_VRCPPS, + ZYDIS_MNEMONIC_VRCPSS, + ZYDIS_MNEMONIC_VREDUCEPD, + ZYDIS_MNEMONIC_VREDUCEPS, + ZYDIS_MNEMONIC_VREDUCESD, + ZYDIS_MNEMONIC_VREDUCESS, + ZYDIS_MNEMONIC_VRNDFXPNTPD, + ZYDIS_MNEMONIC_VRNDFXPNTPS, + ZYDIS_MNEMONIC_VRNDSCALEPD, + ZYDIS_MNEMONIC_VRNDSCALEPS, + ZYDIS_MNEMONIC_VRNDSCALESD, + ZYDIS_MNEMONIC_VRNDSCALESS, + ZYDIS_MNEMONIC_VROUNDPD, + ZYDIS_MNEMONIC_VROUNDPS, + ZYDIS_MNEMONIC_VROUNDSD, + ZYDIS_MNEMONIC_VROUNDSS, + ZYDIS_MNEMONIC_VRSQRT14PD, + ZYDIS_MNEMONIC_VRSQRT14PS, + ZYDIS_MNEMONIC_VRSQRT14SD, + ZYDIS_MNEMONIC_VRSQRT14SS, + ZYDIS_MNEMONIC_VRSQRT23PS, + ZYDIS_MNEMONIC_VRSQRT28PD, + ZYDIS_MNEMONIC_VRSQRT28PS, + ZYDIS_MNEMONIC_VRSQRT28SD, + ZYDIS_MNEMONIC_VRSQRT28SS, + ZYDIS_MNEMONIC_VRSQRTPS, + ZYDIS_MNEMONIC_VRSQRTSS, + ZYDIS_MNEMONIC_VSCALEFPD, + ZYDIS_MNEMONIC_VSCALEFPS, + ZYDIS_MNEMONIC_VSCALEFSD, + ZYDIS_MNEMONIC_VSCALEFSS, + ZYDIS_MNEMONIC_VSCALEPS, + ZYDIS_MNEMONIC_VSCATTERDPD, + ZYDIS_MNEMONIC_VSCATTERDPS, + ZYDIS_MNEMONIC_VSCATTERPF0DPD, + ZYDIS_MNEMONIC_VSCATTERPF0DPS, + ZYDIS_MNEMONIC_VSCATTERPF0HINTDPD, + ZYDIS_MNEMONIC_VSCATTERPF0HINTDPS, + ZYDIS_MNEMONIC_VSCATTERPF0QPD, + ZYDIS_MNEMONIC_VSCATTERPF0QPS, + ZYDIS_MNEMONIC_VSCATTERPF1DPD, + ZYDIS_MNEMONIC_VSCATTERPF1DPS, + ZYDIS_MNEMONIC_VSCATTERPF1QPD, + ZYDIS_MNEMONIC_VSCATTERPF1QPS, + ZYDIS_MNEMONIC_VSCATTERQPD, + ZYDIS_MNEMONIC_VSCATTERQPS, + ZYDIS_MNEMONIC_VSHUFF32X4, + ZYDIS_MNEMONIC_VSHUFF64X2, + ZYDIS_MNEMONIC_VSHUFI32X4, + ZYDIS_MNEMONIC_VSHUFI64X2, + ZYDIS_MNEMONIC_VSHUFPD, + ZYDIS_MNEMONIC_VSHUFPS, + ZYDIS_MNEMONIC_VSQRTPD, + ZYDIS_MNEMONIC_VSQRTPS, + ZYDIS_MNEMONIC_VSQRTSD, + ZYDIS_MNEMONIC_VSQRTSS, + ZYDIS_MNEMONIC_VSTMXCSR, + ZYDIS_MNEMONIC_VSUBPD, + ZYDIS_MNEMONIC_VSUBPS, + ZYDIS_MNEMONIC_VSUBRPD, + ZYDIS_MNEMONIC_VSUBRPS, + ZYDIS_MNEMONIC_VSUBSD, + ZYDIS_MNEMONIC_VSUBSS, + ZYDIS_MNEMONIC_VTESTPD, + ZYDIS_MNEMONIC_VTESTPS, + ZYDIS_MNEMONIC_VUCOMISD, + ZYDIS_MNEMONIC_VUCOMISS, + ZYDIS_MNEMONIC_VUNPCKHPD, + ZYDIS_MNEMONIC_VUNPCKHPS, + ZYDIS_MNEMONIC_VUNPCKLPD, + ZYDIS_MNEMONIC_VUNPCKLPS, + ZYDIS_MNEMONIC_VXORPD, + ZYDIS_MNEMONIC_VXORPS, + ZYDIS_MNEMONIC_VZEROALL, + ZYDIS_MNEMONIC_VZEROUPPER, + ZYDIS_MNEMONIC_WBINVD, + ZYDIS_MNEMONIC_WRFSBASE, + ZYDIS_MNEMONIC_WRGSBASE, + ZYDIS_MNEMONIC_WRMSR, + ZYDIS_MNEMONIC_WRPKRU, + ZYDIS_MNEMONIC_WRSSD, + ZYDIS_MNEMONIC_WRSSQ, + ZYDIS_MNEMONIC_WRUSSD, + ZYDIS_MNEMONIC_WRUSSQ, + ZYDIS_MNEMONIC_XABORT, + ZYDIS_MNEMONIC_XADD, + ZYDIS_MNEMONIC_XBEGIN, + ZYDIS_MNEMONIC_XCHG, + ZYDIS_MNEMONIC_XCRYPT_CBC, + ZYDIS_MNEMONIC_XCRYPT_CFB, + ZYDIS_MNEMONIC_XCRYPT_CTR, + ZYDIS_MNEMONIC_XCRYPT_ECB, + ZYDIS_MNEMONIC_XCRYPT_OFB, + ZYDIS_MNEMONIC_XEND, + ZYDIS_MNEMONIC_XGETBV, + ZYDIS_MNEMONIC_XLAT, + ZYDIS_MNEMONIC_XOR, + ZYDIS_MNEMONIC_XORPD, + ZYDIS_MNEMONIC_XORPS, + ZYDIS_MNEMONIC_XRESLDTRK, + ZYDIS_MNEMONIC_XRSTOR, + ZYDIS_MNEMONIC_XRSTOR64, + ZYDIS_MNEMONIC_XRSTORS, + ZYDIS_MNEMONIC_XRSTORS64, + ZYDIS_MNEMONIC_XSAVE, + ZYDIS_MNEMONIC_XSAVE64, + ZYDIS_MNEMONIC_XSAVEC, + ZYDIS_MNEMONIC_XSAVEC64, + ZYDIS_MNEMONIC_XSAVEOPT, + ZYDIS_MNEMONIC_XSAVEOPT64, + ZYDIS_MNEMONIC_XSAVES, + ZYDIS_MNEMONIC_XSAVES64, + ZYDIS_MNEMONIC_XSETBV, + ZYDIS_MNEMONIC_XSHA1, + ZYDIS_MNEMONIC_XSHA256, + ZYDIS_MNEMONIC_XSTORE, + ZYDIS_MNEMONIC_XSUSLDTRK, + ZYDIS_MNEMONIC_XTEST, + + /** + * Maximum value of this enum. + */ + ZYDIS_MNEMONIC_MAX_VALUE = ZYDIS_MNEMONIC_XTEST, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_MNEMONIC_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_MNEMONIC_MAX_VALUE) +} ZydisMnemonic; \ No newline at end of file diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumRegister.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumRegister.h new file mode 100644 index 0000000..3135fe0 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumRegister.h @@ -0,0 +1,301 @@ +/** + * Defines the `ZydisRegister` enum. + */ +typedef enum ZydisRegister_ +{ + ZYDIS_REGISTER_NONE, + + // General purpose registers 8-bit + ZYDIS_REGISTER_AL, + ZYDIS_REGISTER_CL, + ZYDIS_REGISTER_DL, + ZYDIS_REGISTER_BL, + ZYDIS_REGISTER_AH, + ZYDIS_REGISTER_CH, + ZYDIS_REGISTER_DH, + ZYDIS_REGISTER_BH, + ZYDIS_REGISTER_SPL, + ZYDIS_REGISTER_BPL, + ZYDIS_REGISTER_SIL, + ZYDIS_REGISTER_DIL, + ZYDIS_REGISTER_R8B, + ZYDIS_REGISTER_R9B, + ZYDIS_REGISTER_R10B, + ZYDIS_REGISTER_R11B, + ZYDIS_REGISTER_R12B, + ZYDIS_REGISTER_R13B, + ZYDIS_REGISTER_R14B, + ZYDIS_REGISTER_R15B, + // General purpose registers 16-bit + ZYDIS_REGISTER_AX, + ZYDIS_REGISTER_CX, + ZYDIS_REGISTER_DX, + ZYDIS_REGISTER_BX, + ZYDIS_REGISTER_SP, + ZYDIS_REGISTER_BP, + ZYDIS_REGISTER_SI, + ZYDIS_REGISTER_DI, + ZYDIS_REGISTER_R8W, + ZYDIS_REGISTER_R9W, + ZYDIS_REGISTER_R10W, + ZYDIS_REGISTER_R11W, + ZYDIS_REGISTER_R12W, + ZYDIS_REGISTER_R13W, + ZYDIS_REGISTER_R14W, + ZYDIS_REGISTER_R15W, + // General purpose registers 32-bit + ZYDIS_REGISTER_EAX, + ZYDIS_REGISTER_ECX, + ZYDIS_REGISTER_EDX, + ZYDIS_REGISTER_EBX, + ZYDIS_REGISTER_ESP, + ZYDIS_REGISTER_EBP, + ZYDIS_REGISTER_ESI, + ZYDIS_REGISTER_EDI, + ZYDIS_REGISTER_R8D, + ZYDIS_REGISTER_R9D, + ZYDIS_REGISTER_R10D, + ZYDIS_REGISTER_R11D, + ZYDIS_REGISTER_R12D, + ZYDIS_REGISTER_R13D, + ZYDIS_REGISTER_R14D, + ZYDIS_REGISTER_R15D, + // General purpose registers 64-bit + ZYDIS_REGISTER_RAX, + ZYDIS_REGISTER_RCX, + ZYDIS_REGISTER_RDX, + ZYDIS_REGISTER_RBX, + ZYDIS_REGISTER_RSP, + ZYDIS_REGISTER_RBP, + ZYDIS_REGISTER_RSI, + ZYDIS_REGISTER_RDI, + ZYDIS_REGISTER_R8, + ZYDIS_REGISTER_R9, + ZYDIS_REGISTER_R10, + ZYDIS_REGISTER_R11, + ZYDIS_REGISTER_R12, + ZYDIS_REGISTER_R13, + ZYDIS_REGISTER_R14, + ZYDIS_REGISTER_R15, + // Floating point legacy registers + ZYDIS_REGISTER_ST0, + ZYDIS_REGISTER_ST1, + ZYDIS_REGISTER_ST2, + ZYDIS_REGISTER_ST3, + ZYDIS_REGISTER_ST4, + ZYDIS_REGISTER_ST5, + ZYDIS_REGISTER_ST6, + ZYDIS_REGISTER_ST7, + ZYDIS_REGISTER_X87CONTROL, + ZYDIS_REGISTER_X87STATUS, + ZYDIS_REGISTER_X87TAG, + // Floating point multimedia registers + ZYDIS_REGISTER_MM0, + ZYDIS_REGISTER_MM1, + ZYDIS_REGISTER_MM2, + ZYDIS_REGISTER_MM3, + ZYDIS_REGISTER_MM4, + ZYDIS_REGISTER_MM5, + ZYDIS_REGISTER_MM6, + ZYDIS_REGISTER_MM7, + // Floating point vector registers 128-bit + ZYDIS_REGISTER_XMM0, + ZYDIS_REGISTER_XMM1, + ZYDIS_REGISTER_XMM2, + ZYDIS_REGISTER_XMM3, + ZYDIS_REGISTER_XMM4, + ZYDIS_REGISTER_XMM5, + ZYDIS_REGISTER_XMM6, + ZYDIS_REGISTER_XMM7, + ZYDIS_REGISTER_XMM8, + ZYDIS_REGISTER_XMM9, + ZYDIS_REGISTER_XMM10, + ZYDIS_REGISTER_XMM11, + ZYDIS_REGISTER_XMM12, + ZYDIS_REGISTER_XMM13, + ZYDIS_REGISTER_XMM14, + ZYDIS_REGISTER_XMM15, + ZYDIS_REGISTER_XMM16, + ZYDIS_REGISTER_XMM17, + ZYDIS_REGISTER_XMM18, + ZYDIS_REGISTER_XMM19, + ZYDIS_REGISTER_XMM20, + ZYDIS_REGISTER_XMM21, + ZYDIS_REGISTER_XMM22, + ZYDIS_REGISTER_XMM23, + ZYDIS_REGISTER_XMM24, + ZYDIS_REGISTER_XMM25, + ZYDIS_REGISTER_XMM26, + ZYDIS_REGISTER_XMM27, + ZYDIS_REGISTER_XMM28, + ZYDIS_REGISTER_XMM29, + ZYDIS_REGISTER_XMM30, + ZYDIS_REGISTER_XMM31, + // Floating point vector registers 256-bit + ZYDIS_REGISTER_YMM0, + ZYDIS_REGISTER_YMM1, + ZYDIS_REGISTER_YMM2, + ZYDIS_REGISTER_YMM3, + ZYDIS_REGISTER_YMM4, + ZYDIS_REGISTER_YMM5, + ZYDIS_REGISTER_YMM6, + ZYDIS_REGISTER_YMM7, + ZYDIS_REGISTER_YMM8, + ZYDIS_REGISTER_YMM9, + ZYDIS_REGISTER_YMM10, + ZYDIS_REGISTER_YMM11, + ZYDIS_REGISTER_YMM12, + ZYDIS_REGISTER_YMM13, + ZYDIS_REGISTER_YMM14, + ZYDIS_REGISTER_YMM15, + ZYDIS_REGISTER_YMM16, + ZYDIS_REGISTER_YMM17, + ZYDIS_REGISTER_YMM18, + ZYDIS_REGISTER_YMM19, + ZYDIS_REGISTER_YMM20, + ZYDIS_REGISTER_YMM21, + ZYDIS_REGISTER_YMM22, + ZYDIS_REGISTER_YMM23, + ZYDIS_REGISTER_YMM24, + ZYDIS_REGISTER_YMM25, + ZYDIS_REGISTER_YMM26, + ZYDIS_REGISTER_YMM27, + ZYDIS_REGISTER_YMM28, + ZYDIS_REGISTER_YMM29, + ZYDIS_REGISTER_YMM30, + ZYDIS_REGISTER_YMM31, + // Floating point vector registers 512-bit + ZYDIS_REGISTER_ZMM0, + ZYDIS_REGISTER_ZMM1, + ZYDIS_REGISTER_ZMM2, + ZYDIS_REGISTER_ZMM3, + ZYDIS_REGISTER_ZMM4, + ZYDIS_REGISTER_ZMM5, + ZYDIS_REGISTER_ZMM6, + ZYDIS_REGISTER_ZMM7, + ZYDIS_REGISTER_ZMM8, + ZYDIS_REGISTER_ZMM9, + ZYDIS_REGISTER_ZMM10, + ZYDIS_REGISTER_ZMM11, + ZYDIS_REGISTER_ZMM12, + ZYDIS_REGISTER_ZMM13, + ZYDIS_REGISTER_ZMM14, + ZYDIS_REGISTER_ZMM15, + ZYDIS_REGISTER_ZMM16, + ZYDIS_REGISTER_ZMM17, + ZYDIS_REGISTER_ZMM18, + ZYDIS_REGISTER_ZMM19, + ZYDIS_REGISTER_ZMM20, + ZYDIS_REGISTER_ZMM21, + ZYDIS_REGISTER_ZMM22, + ZYDIS_REGISTER_ZMM23, + ZYDIS_REGISTER_ZMM24, + ZYDIS_REGISTER_ZMM25, + ZYDIS_REGISTER_ZMM26, + ZYDIS_REGISTER_ZMM27, + ZYDIS_REGISTER_ZMM28, + ZYDIS_REGISTER_ZMM29, + ZYDIS_REGISTER_ZMM30, + ZYDIS_REGISTER_ZMM31, + // Matrix registers + ZYDIS_REGISTER_TMM0, + ZYDIS_REGISTER_TMM1, + ZYDIS_REGISTER_TMM2, + ZYDIS_REGISTER_TMM3, + ZYDIS_REGISTER_TMM4, + ZYDIS_REGISTER_TMM5, + ZYDIS_REGISTER_TMM6, + ZYDIS_REGISTER_TMM7, + // Flags registers + ZYDIS_REGISTER_FLAGS, + ZYDIS_REGISTER_EFLAGS, + ZYDIS_REGISTER_RFLAGS, + // Instruction-pointer registers + ZYDIS_REGISTER_IP, + ZYDIS_REGISTER_EIP, + ZYDIS_REGISTER_RIP, + // Segment registers + ZYDIS_REGISTER_ES, + ZYDIS_REGISTER_CS, + ZYDIS_REGISTER_SS, + ZYDIS_REGISTER_DS, + ZYDIS_REGISTER_FS, + ZYDIS_REGISTER_GS, + // Table registers + ZYDIS_REGISTER_GDTR, + ZYDIS_REGISTER_LDTR, + ZYDIS_REGISTER_IDTR, + ZYDIS_REGISTER_TR, + // Test registers + ZYDIS_REGISTER_TR0, + ZYDIS_REGISTER_TR1, + ZYDIS_REGISTER_TR2, + ZYDIS_REGISTER_TR3, + ZYDIS_REGISTER_TR4, + ZYDIS_REGISTER_TR5, + ZYDIS_REGISTER_TR6, + ZYDIS_REGISTER_TR7, + // Control registers + ZYDIS_REGISTER_CR0, + ZYDIS_REGISTER_CR1, + ZYDIS_REGISTER_CR2, + ZYDIS_REGISTER_CR3, + ZYDIS_REGISTER_CR4, + ZYDIS_REGISTER_CR5, + ZYDIS_REGISTER_CR6, + ZYDIS_REGISTER_CR7, + ZYDIS_REGISTER_CR8, + ZYDIS_REGISTER_CR9, + ZYDIS_REGISTER_CR10, + ZYDIS_REGISTER_CR11, + ZYDIS_REGISTER_CR12, + ZYDIS_REGISTER_CR13, + ZYDIS_REGISTER_CR14, + ZYDIS_REGISTER_CR15, + // Debug registers + ZYDIS_REGISTER_DR0, + ZYDIS_REGISTER_DR1, + ZYDIS_REGISTER_DR2, + ZYDIS_REGISTER_DR3, + ZYDIS_REGISTER_DR4, + ZYDIS_REGISTER_DR5, + ZYDIS_REGISTER_DR6, + ZYDIS_REGISTER_DR7, + ZYDIS_REGISTER_DR8, + ZYDIS_REGISTER_DR9, + ZYDIS_REGISTER_DR10, + ZYDIS_REGISTER_DR11, + ZYDIS_REGISTER_DR12, + ZYDIS_REGISTER_DR13, + ZYDIS_REGISTER_DR14, + ZYDIS_REGISTER_DR15, + // Mask registers + ZYDIS_REGISTER_K0, + ZYDIS_REGISTER_K1, + ZYDIS_REGISTER_K2, + ZYDIS_REGISTER_K3, + ZYDIS_REGISTER_K4, + ZYDIS_REGISTER_K5, + ZYDIS_REGISTER_K6, + ZYDIS_REGISTER_K7, + // Bound registers + ZYDIS_REGISTER_BND0, + ZYDIS_REGISTER_BND1, + ZYDIS_REGISTER_BND2, + ZYDIS_REGISTER_BND3, + ZYDIS_REGISTER_BNDCFG, + ZYDIS_REGISTER_BNDSTATUS, + // Uncategorized + ZYDIS_REGISTER_MXCSR, + ZYDIS_REGISTER_PKRU, + ZYDIS_REGISTER_XCR0, + + /** + * Maximum value of this enum. + */ + ZYDIS_REGISTER_MAX_VALUE = ZYDIS_REGISTER_XCR0, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_REGISTER_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_REGISTER_MAX_VALUE) +} ZydisRegister; diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/DecoderData.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/DecoderData.h new file mode 100644 index 0000000..db6cf53 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/DecoderData.h @@ -0,0 +1,331 @@ +/*************************************************************************************************** + + Zyan Disassembler Library (Zydis) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +#ifndef ZYDIS_INTERNAL_DECODERDATA_H +#define ZYDIS_INTERNAL_DECODERDATA_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +// MSVC does not like types other than (un-)signed int for bit-fields +#ifdef ZYAN_MSVC +# pragma warning(push) +# pragma warning(disable:4214) +#endif + +#pragma pack(push, 1) + +/* ---------------------------------------------------------------------------------------------- */ +/* Decoder tree */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisDecoderTreeNodeType` data-type. + */ +typedef ZyanU8 ZydisDecoderTreeNodeType; + +/** + * Values that represent zydis decoder tree node types. + */ +enum ZydisDecoderTreeNodeTypes +{ + ZYDIS_NODETYPE_INVALID = 0x00, + /** + * Reference to an instruction-definition. + */ + ZYDIS_NODETYPE_DEFINITION_MASK = 0x80, + /** + * Reference to an XOP-map filter. + */ + ZYDIS_NODETYPE_FILTER_XOP = 0x01, + /** + * Reference to an VEX-map filter. + */ + ZYDIS_NODETYPE_FILTER_VEX = 0x02, + /** + * Reference to an EVEX/MVEX-map filter. + */ + ZYDIS_NODETYPE_FILTER_EMVEX = 0x03, + /** + * Reference to an opcode filter. + */ + ZYDIS_NODETYPE_FILTER_OPCODE = 0x04, + /** + * Reference to an instruction-mode filter. + */ + ZYDIS_NODETYPE_FILTER_MODE = 0x05, + /** + * Reference to an compacted instruction-mode filter. + */ + ZYDIS_NODETYPE_FILTER_MODE_COMPACT = 0x06, + /** + * Reference to a ModRM.mod filter. + */ + ZYDIS_NODETYPE_FILTER_MODRM_MOD = 0x07, + /** + * Reference to a compacted ModRM.mod filter. + */ + ZYDIS_NODETYPE_FILTER_MODRM_MOD_COMPACT = 0x08, + /** + * Reference to a ModRM.reg filter. + */ + ZYDIS_NODETYPE_FILTER_MODRM_REG = 0x09, + /** + * Reference to a ModRM.rm filter. + */ + ZYDIS_NODETYPE_FILTER_MODRM_RM = 0x0A, + /** + * Reference to a PrefixGroup1 filter. + */ + ZYDIS_NODETYPE_FILTER_PREFIX_GROUP1 = 0x0B, + /** + * Reference to a mandatory-prefix filter. + */ + ZYDIS_NODETYPE_FILTER_MANDATORY_PREFIX = 0x0C, + /** + * Reference to an operand-size filter. + */ + ZYDIS_NODETYPE_FILTER_OPERAND_SIZE = 0x0D, + /** + * Reference to an address-size filter. + */ + ZYDIS_NODETYPE_FILTER_ADDRESS_SIZE = 0x0E, + /** + * Reference to a vector-length filter. + */ + ZYDIS_NODETYPE_FILTER_VECTOR_LENGTH = 0x0F, + /** + * Reference to an REX/VEX/EVEX.W filter. + */ + ZYDIS_NODETYPE_FILTER_REX_W = 0x10, + /** + * Reference to an REX/VEX/EVEX.B filter. + */ + ZYDIS_NODETYPE_FILTER_REX_B = 0x11, + /** + * Reference to an EVEX.b filter. + */ + ZYDIS_NODETYPE_FILTER_EVEX_B = 0x12, + /** + * Reference to an MVEX.E filter. + */ + ZYDIS_NODETYPE_FILTER_MVEX_E = 0x13, + /** + * Reference to a AMD-mode filter. + */ + ZYDIS_NODETYPE_FILTER_MODE_AMD = 0x14, + /** + * Reference to a KNC-mode filter. + */ + ZYDIS_NODETYPE_FILTER_MODE_KNC = 0x15, + /** + * Reference to a MPX-mode filter. + */ + ZYDIS_NODETYPE_FILTER_MODE_MPX = 0x16, + /** + * Reference to a CET-mode filter. + */ + ZYDIS_NODETYPE_FILTER_MODE_CET = 0x17, + /** + * Reference to a LZCNT-mode filter. + */ + ZYDIS_NODETYPE_FILTER_MODE_LZCNT = 0x18, + /** + * Reference to a TZCNT-mode filter. + */ + ZYDIS_NODETYPE_FILTER_MODE_TZCNT = 0x19, + /** + * Reference to a WBNOINVD-mode filter. + */ + ZYDIS_NODETYPE_FILTER_MODE_WBNOINVD = 0x1A, + /** + * Reference to a CLDEMOTE-mode filter. + */ + ZYDIS_NODETYPE_FILTER_MODE_CLDEMOTE = 0x1B +}; + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisDecoderTreeNodeValue` data-type. + */ +typedef ZyanU16 ZydisDecoderTreeNodeValue; + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisDecoderTreeNode` struct. + */ +typedef struct ZydisDecoderTreeNode_ +{ + ZydisDecoderTreeNodeType type; + ZydisDecoderTreeNodeValue value; +} ZydisDecoderTreeNode; + +/* ---------------------------------------------------------------------------------------------- */ + +#pragma pack(pop) + +#ifdef ZYAN_MSVC +# pragma warning(pop) +#endif + +/* ---------------------------------------------------------------------------------------------- */ +/* Physical instruction encoding info */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisInstructionEncodingFlags` data-type. + */ +typedef ZyanU8 ZydisInstructionEncodingFlags; + +/** + * The instruction has an optional modrm byte. + */ +#define ZYDIS_INSTR_ENC_FLAG_HAS_MODRM 0x01 + +/** + * The instruction has an optional displacement value. + */ +#define ZYDIS_INSTR_ENC_FLAG_HAS_DISP 0x02 + +/** + * The instruction has an optional immediate value. + */ +#define ZYDIS_INSTR_ENC_FLAG_HAS_IMM0 0x04 + +/** + * The instruction has a second optional immediate value. + */ +#define ZYDIS_INSTR_ENC_FLAG_HAS_IMM1 0x08 + +/** + * The instruction ignores the value of `modrm.mod` and always assumes `modrm.mod == 3` + * ("reg, reg" - form). + * + * Instructions with this flag can't have a SIB byte or a displacement value. + */ +#define ZYDIS_INSTR_ENC_FLAG_FORCE_REG_FORM 0x10 + +/** + * Defines the `ZydisInstructionEncodingInfo` struct. + */ +typedef struct ZydisInstructionEncodingInfo_ +{ + /** + * Contains flags with information about the physical instruction-encoding. + */ + ZydisInstructionEncodingFlags flags; + /** + * Displacement info. + */ + struct + { + /** + * The size of the displacement value. + */ + ZyanU8 size[3]; + } disp; + /** + * Immediate info. + */ + struct + { + /** + * The size of the immediate value. + */ + ZyanU8 size[3]; + /** + * Signals, if the value is signed. + */ + ZyanBool is_signed; + /** + * Signals, if the value is a relative offset. + */ + ZyanBool is_relative; + } imm[2]; +} ZydisInstructionEncodingInfo; + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Decoder tree */ +/* ---------------------------------------------------------------------------------------------- */ + +extern const ZydisDecoderTreeNode zydis_decoder_tree_root; + +/** + * Returns the root node of the instruction tree. + * + * @return The root node of the instruction tree. + */ +ZYAN_INLINE const ZydisDecoderTreeNode* ZydisDecoderTreeGetRootNode(void) +{ + return &zydis_decoder_tree_root; +} + +/** + * Returns the child node of `parent` specified by `index`. + * + * @param parent The parent node. + * @param index The index of the child node to retrieve. + * + * @return The specified child node. + */ +ZYDIS_NO_EXPORT const ZydisDecoderTreeNode* ZydisDecoderTreeGetChildNode( + const ZydisDecoderTreeNode* parent, ZyanU16 index); + +/** + * Returns information about optional instruction parts (like modrm, displacement or + * immediates) for the instruction that is linked to the given `node`. + * + * @param node The instruction definition node. + * @param info A pointer to the `ZydisInstructionParts` struct. + */ +ZYDIS_NO_EXPORT void ZydisGetInstructionEncodingInfo(const ZydisDecoderTreeNode* node, + const ZydisInstructionEncodingInfo** info); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYDIS_INTERNAL_DECODERDATA_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/FormatterATT.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/FormatterATT.h new file mode 100644 index 0000000..08b7134 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/FormatterATT.h @@ -0,0 +1,178 @@ +/*************************************************************************************************** + + Zyan Disassembler Library (Zydis) + + Original Author : Florian Bernd, Joel Hoener + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Implements the `AT&T` style instruction-formatter. + */ + +#ifndef ZYDIS_FORMATTER_ATT_H +#define ZYDIS_FORMATTER_ATT_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Formatter functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Instruction */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZydisFormatterATTFormatInstruction(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +/* ---------------------------------------------------------------------------------------------- */ +/* Operands */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZydisFormatterATTFormatOperandMEM(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +/* ---------------------------------------------------------------------------------------------- */ +/* Elemental tokens */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZydisFormatterATTPrintMnemonic(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +ZyanStatus ZydisFormatterATTPrintRegister(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisRegister reg); + +ZyanStatus ZydisFormatterATTPrintDISP(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +ZyanStatus ZydisFormatterATTPrintIMM(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Fomatter presets */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* AT&T */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * The default formatter configuration for `AT&T` style disassembly. + */ +static const ZydisFormatter FORMATTER_ATT = +{ + /* style */ ZYDIS_FORMATTER_STYLE_ATT, + /* force_memory_size */ ZYAN_FALSE, + /* force_memory_seg */ ZYAN_FALSE, + /* force_relative_branches */ ZYAN_FALSE, + /* force_relative_riprel */ ZYAN_FALSE, + /* print_branch_size */ ZYAN_FALSE, + /* detailed_prefixes */ ZYAN_FALSE, + /* addr_base */ ZYDIS_NUMERIC_BASE_HEX, + /* addr_signedness */ ZYDIS_SIGNEDNESS_SIGNED, + /* addr_padding_absolute */ ZYDIS_PADDING_AUTO, + /* addr_padding_relative */ 2, + /* disp_base */ ZYDIS_NUMERIC_BASE_HEX, + /* disp_signedness */ ZYDIS_SIGNEDNESS_SIGNED, + /* disp_padding */ 2, + /* imm_base */ ZYDIS_NUMERIC_BASE_HEX, + /* imm_signedness */ ZYDIS_SIGNEDNESS_AUTO, + /* imm_padding */ 2, + /* case_prefixes */ ZYDIS_LETTER_CASE_DEFAULT, + /* case_mnemonic */ ZYDIS_LETTER_CASE_DEFAULT, + /* case_registers */ ZYDIS_LETTER_CASE_DEFAULT, + /* case_typecasts */ ZYDIS_LETTER_CASE_DEFAULT, + /* case_decorators */ ZYDIS_LETTER_CASE_DEFAULT, + /* hex_uppercase */ ZYAN_TRUE, + /* number_format */ + { + // ZYDIS_NUMERIC_BASE_DEC + { + // Prefix + { + /* string */ ZYAN_NULL, + /* string_data */ ZYAN_DEFINE_STRING_VIEW(""), + /* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + }, + // Suffix + { + /* string */ ZYAN_NULL, + /* string_data */ ZYAN_DEFINE_STRING_VIEW(""), + /* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + }, + // ZYDIS_NUMERIC_BASE_HEX + { + // Prefix + { + /* string */ &FORMATTER_ATT.number_format[ + ZYDIS_NUMERIC_BASE_HEX][0].string_data, + /* string_data */ ZYAN_DEFINE_STRING_VIEW("0x"), + /* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + }, + // Suffix + { + /* string */ ZYAN_NULL, + /* string_data */ ZYAN_DEFINE_STRING_VIEW(""), + /* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + } + }, + /* func_pre_instruction */ ZYAN_NULL, + /* func_post_instruction */ ZYAN_NULL, + /* func_format_instruction */ &ZydisFormatterATTFormatInstruction, + /* func_pre_operand */ ZYAN_NULL, + /* func_post_operand */ ZYAN_NULL, + /* func_format_operand_reg */ &ZydisFormatterBaseFormatOperandREG, + /* func_format_operand_mem */ &ZydisFormatterATTFormatOperandMEM, + /* func_format_operand_ptr */ &ZydisFormatterBaseFormatOperandPTR, + /* func_format_operand_imm */ &ZydisFormatterBaseFormatOperandIMM, + /* func_print_mnemonic */ &ZydisFormatterATTPrintMnemonic, + /* func_print_register */ &ZydisFormatterATTPrintRegister, + /* func_print_address_abs */ &ZydisFormatterBasePrintAddressABS, + /* func_print_address_rel */ &ZydisFormatterBasePrintAddressREL, + /* func_print_disp */ &ZydisFormatterATTPrintDISP, + /* func_print_imm */ &ZydisFormatterATTPrintIMM, + /* func_print_typecast */ ZYAN_NULL, + /* func_print_segment */ &ZydisFormatterBasePrintSegment, + /* func_print_prefixes */ &ZydisFormatterBasePrintPrefixes, + /* func_print_decorator */ &ZydisFormatterBasePrintDecorator +}; + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif // ZYDIS_FORMATTER_ATT_H diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/FormatterBase.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/FormatterBase.h new file mode 100644 index 0000000..0a61747 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/FormatterBase.h @@ -0,0 +1,318 @@ +/*************************************************************************************************** + + Zyan Disassembler Library (Zydis) + + Original Author : Florian Bernd, Joel Hoener + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Provides formatter functions that are shared between the different formatters. + */ + +#ifndef ZYDIS_FORMATTER_BASE_H +#define ZYDIS_FORMATTER_BASE_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* String */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Appends an unsigned numeric value to the given string. + * + * @param formatter A pointer to the `ZydisFormatter` instance. + * @param base The numeric base. + * @param str The destination string. + * @param value The value. + * @param padding_length The padding length. + */ +#define ZYDIS_STRING_APPEND_NUM_U(formatter, base, str, value, padding_length) \ + switch (base) \ + { \ + case ZYDIS_NUMERIC_BASE_DEC: \ + ZYAN_CHECK(ZydisStringAppendDecU(str, value, padding_length, \ + (formatter)->number_format[base][0].string, \ + (formatter)->number_format[base][1].string)); \ + break; \ + case ZYDIS_NUMERIC_BASE_HEX: \ + ZYAN_CHECK(ZydisStringAppendHexU(str, value, padding_length, \ + (formatter)->hex_uppercase, \ + (formatter)->number_format[base][0].string, \ + (formatter)->number_format[base][1].string)); \ + break; \ + default: \ + return ZYAN_STATUS_INVALID_ARGUMENT; \ + } + +/** + * Appends a signed numeric value to the given string. + * + * @param formatter A pointer to the `ZydisFormatter` instance. + * @param base The numeric base. + * @param str The destination string. + * @param value The value. + * @param padding_length The padding length. + * @param force_sign Forces printing of the '+' sign for positive numbers. + */ +#define ZYDIS_STRING_APPEND_NUM_S(formatter, base, str, value, padding_length, force_sign) \ + switch (base) \ + { \ + case ZYDIS_NUMERIC_BASE_DEC: \ + ZYAN_CHECK(ZydisStringAppendDecS(str, value, padding_length, force_sign, \ + (formatter)->number_format[base][0].string, \ + (formatter)->number_format[base][1].string)); \ + break; \ + case ZYDIS_NUMERIC_BASE_HEX: \ + ZYAN_CHECK(ZydisStringAppendHexS(str, value, padding_length, \ + (formatter)->hex_uppercase, force_sign, \ + (formatter)->number_format[base][0].string, \ + (formatter)->number_format[base][1].string)); \ + break; \ + default: \ + return ZYAN_STATUS_INVALID_ARGUMENT; \ + } + +/* ---------------------------------------------------------------------------------------------- */ +/* Buffer */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Invokes the `ZydisFormatterBufferAppend` routine, if tokenization is enabled for the + * current pass. + * + * @param buffer A pointer to the `ZydisFormatterBuffer` struct. + * @param type The token type. + * + * Using this macro instead of direct calls to `ZydisFormatterBufferAppend` greatly improves the + * performance for non-tokenizing passes. + */ +#define ZYDIS_BUFFER_APPEND_TOKEN(buffer, type) \ + if ((buffer)->is_token_list) \ + { \ + ZYAN_CHECK(ZydisFormatterBufferAppend(buffer, type)); \ + } + +/** + * Returns a snapshot of the buffer-state. + * + * @param buffer A pointer to the `ZydisFormatterBuffer` struct. + * @param state Receives a snapshot of the buffer-state. + * + * Using this macro instead of direct calls to `ZydisFormatterBufferRemember` improves the + * performance for non-tokenizing passes. + */ +#define ZYDIS_BUFFER_REMEMBER(buffer, state) \ + if ((buffer)->is_token_list) \ + { \ + (state) = (ZyanUPointer)(buffer)->string.vector.data; \ + } else \ + { \ + (state) = (ZyanUPointer)(buffer)->string.vector.size; \ + } + +/** + * Appends a string (`STR_`-prefix) or a predefined token-list (`TOK_`-prefix). + * + * @param buffer A pointer to the `ZydisFormatterBuffer` struct. + * @param name The base name (without prefix) of the string- or token. + */ +#define ZYDIS_BUFFER_APPEND(buffer, name) \ + if ((buffer)->is_token_list) \ + { \ + ZYAN_CHECK(ZydisFormatterBufferAppendPredefined(buffer, TOK_ ## name)); \ + } else \ + { \ + ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_ ## name)); \ + } + +// TODO: Implement `letter_case` for predefined tokens + +/** + * Appends a string (`STR_`-prefix) or a predefined token-list (`TOK_`-prefix). + * + * @param buffer A pointer to the `ZydisFormatterBuffer` struct. + * @param name The base name (without prefix) of the string- or token. + * @param letter-case The desired letter-case. + */ +#define ZYDIS_BUFFER_APPEND_CASE(buffer, name, letter_case) \ + if ((buffer)->is_token_list) \ + { \ + ZYAN_CHECK(ZydisFormatterBufferAppendPredefined(buffer, TOK_ ## name)); \ + } else \ + { \ + ZYAN_CHECK(ZydisStringAppendShortCase(&buffer->string, &STR_ ## name, letter_case)); \ + } + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Helper functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Buffer */ +/* ---------------------------------------------------------------------------------------------- */ + +// MSVC does not like the C99 flexible-array extension +#ifdef ZYAN_MSVC +# pragma warning(push) +# pragma warning(disable:4200) +#endif + +#pragma pack(push, 1) + +typedef struct ZydisPredefinedToken_ +{ + ZyanU8 size; + ZyanU8 next; + ZyanU8 data[]; +} ZydisPredefinedToken; + +#pragma pack(pop) + +#ifdef ZYAN_MSVC +# pragma warning(pop) +#endif + +/** + * Appends a predefined token-list to the `buffer`. + * + * @param buffer A pointer to the `ZydisFormatterBuffer` struct. + * @param data A pointer to the `ZydisPredefinedToken` struct. + * + * @return A zycore status code. + * + * This function is internally used to improve performance while adding static strings or multiple + * tokens at once. + */ +ZYAN_INLINE ZyanStatus ZydisFormatterBufferAppendPredefined(ZydisFormatterBuffer* buffer, + const ZydisPredefinedToken* data) +{ + ZYAN_ASSERT(buffer); + ZYAN_ASSERT(data); + + const ZyanUSize len = buffer->string.vector.size; + ZYAN_ASSERT((len > 0) && (len < 256)); + if (buffer->capacity <= len + data->size) + { + return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; + } + + ZydisFormatterToken* const last = (ZydisFormatterToken*)buffer->string.vector.data - 1; + last->next = (ZyanU8)len; + + ZYAN_MEMCPY((ZyanU8*)buffer->string.vector.data + len, &data->data[0], data->size); + + const ZyanUSize delta = len + data->next; + buffer->capacity -= delta; + buffer->string.vector.data = (ZyanU8*)buffer->string.vector.data + delta; + buffer->string.vector.size = data->size - data->next; + buffer->string.vector.capacity = ZYAN_MIN(buffer->capacity, 255); + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the size to be used as explicit size suffix (`AT&T`) or explicit typecast + * (`INTEL`), if required. + * + * @param formatter A pointer to the `ZydisFormatter` instance. + * @param context A pointer to the `ZydisFormatterContext` struct. + * @param memop_id The operand-id of the instructions first memory operand. + * + * @return Returns the explicit size, if required, or `0`, if not needed. + * + * This function always returns a size different to `0`, if the `ZYDIS_FORMATTER_PROP_FORCE_SIZE` + * is set to `ZYAN_TRUE`. + */ +ZyanU32 ZydisFormatterHelperGetExplicitSize(const ZydisFormatter* formatter, + ZydisFormatterContext* context, ZyanU8 memop_id); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Formatter functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Operands */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZydisFormatterBaseFormatOperandREG(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +ZyanStatus ZydisFormatterBaseFormatOperandPTR(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +ZyanStatus ZydisFormatterBaseFormatOperandIMM(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +/* ---------------------------------------------------------------------------------------------- */ +/* Elemental tokens */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZydisFormatterBasePrintAddressABS(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +ZyanStatus ZydisFormatterBasePrintAddressREL(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +ZyanStatus ZydisFormatterBasePrintIMM(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +/* ---------------------------------------------------------------------------------------------- */ +/* Optional tokens */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZydisFormatterBasePrintSegment(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +ZyanStatus ZydisFormatterBasePrintPrefixes(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +ZyanStatus ZydisFormatterBasePrintDecorator(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisDecorator decorator); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif // ZYDIS_FORMATTER_BASE_H diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/FormatterIntel.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/FormatterIntel.h new file mode 100644 index 0000000..cd12d38 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/FormatterIntel.h @@ -0,0 +1,267 @@ +/*************************************************************************************************** + + Zyan Disassembler Library (Zydis) + + Original Author : Florian Bernd, Joel Hoener + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Implements the `INTEL` style instruction-formatter. + */ + +#ifndef ZYDIS_FORMATTER_INTEL_H +#define ZYDIS_FORMATTER_INTEL_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Formatter functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Intel */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZydisFormatterIntelFormatInstruction(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +ZyanStatus ZydisFormatterIntelFormatOperandMEM(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +ZyanStatus ZydisFormatterIntelPrintMnemonic(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +ZyanStatus ZydisFormatterIntelPrintRegister(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisRegister reg); + +ZyanStatus ZydisFormatterIntelPrintDISP(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +ZyanStatus ZydisFormatterIntelPrintTypecast(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +/* ---------------------------------------------------------------------------------------------- */ +/* MASM */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZydisFormatterIntelFormatInstructionMASM(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +ZyanStatus ZydisFormatterIntelPrintAddressMASM(const ZydisFormatter* formatter, + ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Fomatter presets */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* INTEL */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * The default formatter configuration for `INTEL` style disassembly. + */ +static const ZydisFormatter FORMATTER_INTEL = +{ + /* style */ ZYDIS_FORMATTER_STYLE_INTEL, + /* force_memory_size */ ZYAN_FALSE, + /* force_memory_seg */ ZYAN_FALSE, + /* force_relative_branches */ ZYAN_FALSE, + /* force_relative_riprel */ ZYAN_FALSE, + /* print_branch_size */ ZYAN_FALSE, + /* detailed_prefixes */ ZYAN_FALSE, + /* addr_base */ ZYDIS_NUMERIC_BASE_HEX, + /* addr_signedness */ ZYDIS_SIGNEDNESS_SIGNED, + /* addr_padding_absolute */ ZYDIS_PADDING_AUTO, + /* addr_padding_relative */ 2, + /* disp_base */ ZYDIS_NUMERIC_BASE_HEX, + /* disp_signedness */ ZYDIS_SIGNEDNESS_SIGNED, + /* disp_padding */ 2, + /* imm_base */ ZYDIS_NUMERIC_BASE_HEX, + /* imm_signedness */ ZYDIS_SIGNEDNESS_UNSIGNED, + /* imm_padding */ 2, + /* case_prefixes */ ZYDIS_LETTER_CASE_DEFAULT, + /* case_mnemonic */ ZYDIS_LETTER_CASE_DEFAULT, + /* case_registers */ ZYDIS_LETTER_CASE_DEFAULT, + /* case_typecasts */ ZYDIS_LETTER_CASE_DEFAULT, + /* case_decorators */ ZYDIS_LETTER_CASE_DEFAULT, + /* hex_uppercase */ ZYAN_TRUE, + /* number_format */ + { + // ZYDIS_NUMERIC_BASE_DEC + { + // Prefix + { + /* string */ ZYAN_NULL, + /* string_data */ ZYAN_DEFINE_STRING_VIEW(""), + /* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + }, + // Suffix + { + /* string */ ZYAN_NULL, + /* string_data */ ZYAN_DEFINE_STRING_VIEW(""), + /* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + }, + // ZYDIS_NUMERIC_BASE_HEX + { + // Prefix + { + /* string */ &FORMATTER_INTEL.number_format[ + ZYDIS_NUMERIC_BASE_HEX][0].string_data, + /* string_data */ ZYAN_DEFINE_STRING_VIEW("0x"), + /* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + }, + // Suffix + { + /* string */ ZYAN_NULL, + /* string_data */ ZYAN_DEFINE_STRING_VIEW(""), + /* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + } + }, + /* func_pre_instruction */ ZYAN_NULL, + /* func_post_instruction */ ZYAN_NULL, + /* func_format_instruction */ &ZydisFormatterIntelFormatInstruction, + /* func_pre_operand */ ZYAN_NULL, + /* func_post_operand */ ZYAN_NULL, + /* func_format_operand_reg */ &ZydisFormatterBaseFormatOperandREG, + /* func_format_operand_mem */ &ZydisFormatterIntelFormatOperandMEM, + /* func_format_operand_ptr */ &ZydisFormatterBaseFormatOperandPTR, + /* func_format_operand_imm */ &ZydisFormatterBaseFormatOperandIMM, + /* func_print_mnemonic */ &ZydisFormatterIntelPrintMnemonic, + /* func_print_register */ &ZydisFormatterIntelPrintRegister, + /* func_print_address_abs */ &ZydisFormatterBasePrintAddressABS, + /* func_print_address_rel */ &ZydisFormatterBasePrintAddressREL, + /* func_print_disp */ &ZydisFormatterIntelPrintDISP, + /* func_print_imm */ &ZydisFormatterBasePrintIMM, + /* func_print_typecast */ &ZydisFormatterIntelPrintTypecast, + /* func_print_segment */ &ZydisFormatterBasePrintSegment, + /* func_print_prefixes */ &ZydisFormatterBasePrintPrefixes, + /* func_print_decorator */ &ZydisFormatterBasePrintDecorator +}; + +/* ---------------------------------------------------------------------------------------------- */ +/* MASM */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * The default formatter configuration for `MASM` style disassembly. + */ +static const ZydisFormatter FORMATTER_INTEL_MASM = +{ + /* style */ ZYDIS_FORMATTER_STYLE_INTEL_MASM, + /* force_memory_size */ ZYAN_TRUE, + /* force_memory_seg */ ZYAN_FALSE, + /* force_relative_branches */ ZYAN_FALSE, + /* force_relative_riprel */ ZYAN_FALSE, + /* print_branch_size */ ZYAN_FALSE, + /* detailed_prefixes */ ZYAN_FALSE, + /* addr_base */ ZYDIS_NUMERIC_BASE_HEX, + /* addr_signedness */ ZYDIS_SIGNEDNESS_SIGNED, + /* addr_padding_absolute */ ZYDIS_PADDING_DISABLED, + /* addr_padding_relative */ ZYDIS_PADDING_DISABLED, + /* disp_base */ ZYDIS_NUMERIC_BASE_HEX, + /* disp_signedness */ ZYDIS_SIGNEDNESS_SIGNED, + /* disp_padding */ ZYDIS_PADDING_DISABLED, + /* imm_base */ ZYDIS_NUMERIC_BASE_HEX, + /* imm_signedness */ ZYDIS_SIGNEDNESS_AUTO, + /* imm_padding */ ZYDIS_PADDING_DISABLED, + /* case_prefixes */ ZYDIS_LETTER_CASE_DEFAULT, + /* case_mnemonic */ ZYDIS_LETTER_CASE_DEFAULT, + /* case_registers */ ZYDIS_LETTER_CASE_DEFAULT, + /* case_typecasts */ ZYDIS_LETTER_CASE_DEFAULT, + /* case_decorators */ ZYDIS_LETTER_CASE_DEFAULT, + /* hex_uppercase */ ZYAN_TRUE, + /* number_format */ + { + // ZYDIS_NUMERIC_BASE_DEC + { + // Prefix + { + /* string */ ZYAN_NULL, + /* string_data */ ZYAN_DEFINE_STRING_VIEW(""), + /* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + }, + // Suffix + { + /* string */ ZYAN_NULL, + /* string_data */ ZYAN_DEFINE_STRING_VIEW(""), + /* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + }, + // ZYDIS_NUMERIC_BASE_HEX + { + // Prefix + { + /* string */ ZYAN_NULL, + /* string_data */ ZYAN_DEFINE_STRING_VIEW(""), + /* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + }, + // Suffix + { + /* string */ &FORMATTER_INTEL_MASM.number_format[ + ZYDIS_NUMERIC_BASE_HEX][1].string_data, + /* string_data */ ZYAN_DEFINE_STRING_VIEW("h"), + /* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + } + } + }, + /* func_pre_instruction */ ZYAN_NULL, + /* func_post_instruction */ ZYAN_NULL, + /* func_format_instruction */ &ZydisFormatterIntelFormatInstructionMASM, + /* func_pre_operand */ ZYAN_NULL, + /* func_post_operand */ ZYAN_NULL, + /* func_format_operand_reg */ &ZydisFormatterBaseFormatOperandREG, + /* func_format_operand_mem */ &ZydisFormatterIntelFormatOperandMEM, + /* func_format_operand_ptr */ &ZydisFormatterBaseFormatOperandPTR, + /* func_format_operand_imm */ &ZydisFormatterBaseFormatOperandIMM, + /* func_print_mnemonic */ &ZydisFormatterIntelPrintMnemonic, + /* func_print_register */ &ZydisFormatterIntelPrintRegister, + /* func_print_address_abs */ &ZydisFormatterIntelPrintAddressMASM, + /* func_print_address_rel */ &ZydisFormatterIntelPrintAddressMASM, + /* func_print_disp */ &ZydisFormatterIntelPrintDISP, + /* func_print_imm */ &ZydisFormatterBasePrintIMM, + /* func_print_typecast */ &ZydisFormatterIntelPrintTypecast, + /* func_print_segment */ &ZydisFormatterBasePrintSegment, + /* func_print_prefixes */ &ZydisFormatterBasePrintPrefixes, + /* func_print_decorator */ &ZydisFormatterBasePrintDecorator +}; + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif // ZYDIS_FORMATTER_INTEL_H diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/SharedData.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/SharedData.h new file mode 100644 index 0000000..d8db4fb --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/SharedData.h @@ -0,0 +1,974 @@ +/*************************************************************************************************** + + Zyan Disassembler Library (Zydis) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +#ifndef ZYDIS_INTERNAL_SHAREDDATA_H +#define ZYDIS_INTERNAL_SHAREDDATA_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +// MSVC does not like types other than (un-)signed int for bit-fields +#ifdef ZYAN_MSVC +# pragma warning(push) +# pragma warning(disable:4214) +#endif + +#pragma pack(push, 1) + +/* ---------------------------------------------------------------------------------------------- */ +/* Operand definition */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisSemanticOperandType` enum. + */ +typedef enum ZydisSemanticOperandType_ +{ + ZYDIS_SEMANTIC_OPTYPE_UNUSED, + ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_REG, + ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_MEM, + ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_IMM1, + ZYDIS_SEMANTIC_OPTYPE_GPR8, + ZYDIS_SEMANTIC_OPTYPE_GPR16, + ZYDIS_SEMANTIC_OPTYPE_GPR32, + ZYDIS_SEMANTIC_OPTYPE_GPR64, + ZYDIS_SEMANTIC_OPTYPE_GPR16_32_64, + ZYDIS_SEMANTIC_OPTYPE_GPR32_32_64, + ZYDIS_SEMANTIC_OPTYPE_GPR16_32_32, + ZYDIS_SEMANTIC_OPTYPE_GPR_ASZ, + ZYDIS_SEMANTIC_OPTYPE_FPR, + ZYDIS_SEMANTIC_OPTYPE_MMX, + ZYDIS_SEMANTIC_OPTYPE_XMM, + ZYDIS_SEMANTIC_OPTYPE_YMM, + ZYDIS_SEMANTIC_OPTYPE_ZMM, + ZYDIS_SEMANTIC_OPTYPE_TMM, + ZYDIS_SEMANTIC_OPTYPE_BND, + ZYDIS_SEMANTIC_OPTYPE_SREG, + ZYDIS_SEMANTIC_OPTYPE_CR, + ZYDIS_SEMANTIC_OPTYPE_DR, + ZYDIS_SEMANTIC_OPTYPE_MASK, + ZYDIS_SEMANTIC_OPTYPE_MEM, + ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBX, + ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBY, + ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBZ, + ZYDIS_SEMANTIC_OPTYPE_IMM, + ZYDIS_SEMANTIC_OPTYPE_REL, + ZYDIS_SEMANTIC_OPTYPE_PTR, + ZYDIS_SEMANTIC_OPTYPE_AGEN, + ZYDIS_SEMANTIC_OPTYPE_MOFFS, + ZYDIS_SEMANTIC_OPTYPE_MIB, + + /** + * Maximum value of this enum. + */ + ZYDIS_SEMANTIC_OPTYPE_MAX_VALUE = ZYDIS_SEMANTIC_OPTYPE_MIB, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_SEMANTIC_OPTYPE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_SEMANTIC_OPTYPE_MAX_VALUE) +} ZydisSemanticOperandType; + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisInternalElementType` enum. + */ +typedef enum ZydisInternalElementType_ +{ + ZYDIS_IELEMENT_TYPE_INVALID, + ZYDIS_IELEMENT_TYPE_VARIABLE, + ZYDIS_IELEMENT_TYPE_STRUCT, + ZYDIS_IELEMENT_TYPE_INT, + ZYDIS_IELEMENT_TYPE_UINT, + ZYDIS_IELEMENT_TYPE_INT1, + ZYDIS_IELEMENT_TYPE_INT8, + ZYDIS_IELEMENT_TYPE_INT16, + ZYDIS_IELEMENT_TYPE_INT32, + ZYDIS_IELEMENT_TYPE_INT64, + ZYDIS_IELEMENT_TYPE_UINT8, + ZYDIS_IELEMENT_TYPE_UINT16, + ZYDIS_IELEMENT_TYPE_UINT32, + ZYDIS_IELEMENT_TYPE_UINT64, + ZYDIS_IELEMENT_TYPE_UINT128, + ZYDIS_IELEMENT_TYPE_UINT256, + ZYDIS_IELEMENT_TYPE_FLOAT16, + ZYDIS_IELEMENT_TYPE_FLOAT32, + ZYDIS_IELEMENT_TYPE_FLOAT64, + ZYDIS_IELEMENT_TYPE_FLOAT80, + ZYDIS_IELEMENT_TYPE_BCD80, + ZYDIS_IELEMENT_TYPE_CC3, + ZYDIS_IELEMENT_TYPE_CC5, + + /** + * Maximum value of this enum. + */ + ZYDIS_IELEMENT_TYPE_MAX_VALUE = ZYDIS_IELEMENT_TYPE_CC5, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_IELEMENT_TYPE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_IELEMENT_TYPE_MAX_VALUE) +} ZydisInternalElementType; + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisImplicitRegisterType` enum. + */ +typedef enum ZydisImplicitRegisterType_ +{ + ZYDIS_IMPLREG_TYPE_STATIC, + ZYDIS_IMPLREG_TYPE_GPR_OSZ, + ZYDIS_IMPLREG_TYPE_GPR_ASZ, + ZYDIS_IMPLREG_TYPE_GPR_SSZ, + ZYDIS_IMPLREG_TYPE_IP_ASZ, + ZYDIS_IMPLREG_TYPE_IP_SSZ, + ZYDIS_IMPLREG_TYPE_FLAGS_SSZ, + + /** + * Maximum value of this enum. + */ + ZYDIS_IMPLREG_TYPE_MAX_VALUE = ZYDIS_IMPLREG_TYPE_FLAGS_SSZ, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_IMPLREG_TYPE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_IMPLREG_TYPE_MAX_VALUE) +} ZydisImplicitRegisterType; + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisImplicitMemBase` enum. + */ +typedef enum ZydisImplicitMemBase_ +{ + ZYDIS_IMPLMEM_BASE_AGPR_REG, + ZYDIS_IMPLMEM_BASE_AGPR_RM, + ZYDIS_IMPLMEM_BASE_AAX, + ZYDIS_IMPLMEM_BASE_ADX, + ZYDIS_IMPLMEM_BASE_ABX, + ZYDIS_IMPLMEM_BASE_ASP, + ZYDIS_IMPLMEM_BASE_ABP, + ZYDIS_IMPLMEM_BASE_ASI, + ZYDIS_IMPLMEM_BASE_ADI, + + /** + * Maximum value of this enum. + */ + ZYDIS_IMPLMEM_BASE_MAX_VALUE = ZYDIS_IMPLMEM_BASE_ADI, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_IMPLMEM_BASE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_IMPLMEM_BASE_MAX_VALUE) +} ZydisImplicitMemBase; + +/* ---------------------------------------------------------------------------------------------- */ + +// MSVC does not correctly execute the `pragma pack(1)` compiler-directive, if we use the correct +// enum types +ZYAN_STATIC_ASSERT(ZYDIS_SEMANTIC_OPTYPE_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_OPERAND_VISIBILITY_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_OPERAND_ACTION_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_IELEMENT_TYPE_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_OPERAND_ENCODING_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_IMPLREG_TYPE_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_REGISTER_REQUIRED_BITS <= 16); +ZYAN_STATIC_ASSERT(ZYDIS_IMPLMEM_BASE_REQUIRED_BITS <= 8); + +/** + * Defines the `ZydisOperandDefinition` struct. + */ +typedef struct ZydisOperandDefinition_ +{ + ZyanU8 type ZYAN_BITFIELD(ZYDIS_SEMANTIC_OPTYPE_REQUIRED_BITS); + ZyanU8 visibility ZYAN_BITFIELD(ZYDIS_OPERAND_VISIBILITY_REQUIRED_BITS); + ZyanU8 actions ZYAN_BITFIELD(ZYDIS_OPERAND_ACTION_REQUIRED_BITS); + ZyanU16 size[3]; + ZyanU8 element_type ZYAN_BITFIELD(ZYDIS_IELEMENT_TYPE_REQUIRED_BITS); + union + { + ZyanU8 encoding ZYAN_BITFIELD(ZYDIS_OPERAND_ENCODING_REQUIRED_BITS); + struct + { + ZyanU8 type ZYAN_BITFIELD(ZYDIS_IMPLREG_TYPE_REQUIRED_BITS); + union + { + ZyanU16 reg ZYAN_BITFIELD(ZYDIS_REGISTER_REQUIRED_BITS); + ZyanU8 id ZYAN_BITFIELD(6); + } reg; + } reg; + struct + { + ZyanU8 seg ZYAN_BITFIELD(3); + ZyanU8 base ZYAN_BITFIELD(ZYDIS_IMPLMEM_BASE_REQUIRED_BITS); + } mem; + } op; +} ZydisOperandDefinition; + +/* ---------------------------------------------------------------------------------------------- */ +/* Instruction definition */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisReadWriteAction` enum. + */ +typedef enum ZydisReadWriteAction_ +{ + ZYDIS_RW_ACTION_NONE, + ZYDIS_RW_ACTION_READ, + ZYDIS_RW_ACTION_WRITE, + ZYDIS_RW_ACTION_READWRITE, + + /** + * Maximum value of this enum. + */ + ZYDIS_RW_ACTION_MAX_VALUE = ZYDIS_RW_ACTION_READWRITE, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_RW_ACTION_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_RW_ACTION_MAX_VALUE) +} ZydisReadWriteAction; + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisRegisterConstraint` enum. + */ +typedef enum ZydisRegisterConstraint_ +{ + ZYDIS_REG_CONSTRAINTS_UNUSED, + ZYDIS_REG_CONSTRAINTS_NONE, + ZYDIS_REG_CONSTRAINTS_GPR, + ZYDIS_REG_CONSTRAINTS_SR_DEST, + ZYDIS_REG_CONSTRAINTS_SR, + ZYDIS_REG_CONSTRAINTS_CR, + ZYDIS_REG_CONSTRAINTS_DR, + ZYDIS_REG_CONSTRAINTS_MASK, + ZYDIS_REG_CONSTRAINTS_BND, + ZYDIS_REG_CONSTRAINTS_VSIB, + ZYDIS_REG_CONSTRAINTS_NO_REL, + + /** + * Maximum value of this enum. + */ + ZYDIS_REG_CONSTRAINTS_MAX_VALUE = ZYDIS_REG_CONSTRAINTS_NO_REL, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_REG_CONSTRAINTS_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_REG_CONSTRAINTS_MAX_VALUE) +} ZydisRegisterConstraint; + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisInternalVectorLength` enum. + */ +typedef enum ZydisInternalVectorLength_ +{ + ZYDIS_IVECTOR_LENGTH_DEFAULT, + ZYDIS_IVECTOR_LENGTH_FIXED_128, + ZYDIS_IVECTOR_LENGTH_FIXED_256, + ZYDIS_IVECTOR_LENGTH_FIXED_512, + + /** + * Maximum value of this enum. + */ + ZYDIS_IVECTOR_LENGTH_MAX_VALUE = ZYDIS_IVECTOR_LENGTH_FIXED_512, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_IVECTOR_LENGTH_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_IVECTOR_LENGTH_MAX_VALUE) +} ZydisInternalVectorLength; + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisInternalElementSize` enum. + */ +typedef enum ZydisInternalElementSize_ +{ + ZYDIS_IELEMENT_SIZE_INVALID, + ZYDIS_IELEMENT_SIZE_8, + ZYDIS_IELEMENT_SIZE_16, + ZYDIS_IELEMENT_SIZE_32, + ZYDIS_IELEMENT_SIZE_64, + ZYDIS_IELEMENT_SIZE_128, + + /** + * Maximum value of this enum. + */ + ZYDIS_IELEMENT_SIZE_MAX_VALUE = ZYDIS_IELEMENT_SIZE_128, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_IELEMENT_SIZE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_IELEMENT_SIZE_MAX_VALUE) +} ZydisInternalElementSize; + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisEVEXFunctionality` enum. + */ +typedef enum ZydisEVEXFunctionality_ +{ + ZYDIS_EVEX_FUNC_INVALID, + /** + * `EVEX.b` enables broadcast functionality. + */ + ZYDIS_EVEX_FUNC_BC, + /** + * `EVEX.b` enables embedded-rounding functionality. + */ + ZYDIS_EVEX_FUNC_RC, + /** + * `EVEX.b` enables sae functionality. + */ + ZYDIS_EVEX_FUNC_SAE, + + /** + * Maximum value of this enum. + */ + ZYDIS_EVEX_FUNC_MAX_VALUE = ZYDIS_EVEX_FUNC_SAE, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_EVEX_FUNC_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_EVEX_FUNC_MAX_VALUE) +} ZydisEVEXFunctionality; + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisEVEXTupleType` enum. + */ +typedef enum ZydisEVEXTupleType_ +{ + ZYDIS_TUPLETYPE_INVALID, + /** + * Full Vector + */ + ZYDIS_TUPLETYPE_FV, + /** + * Half Vector + */ + ZYDIS_TUPLETYPE_HV, + /** + * Full Vector Mem + */ + ZYDIS_TUPLETYPE_FVM, + /** + * Tuple1 Scalar + */ + ZYDIS_TUPLETYPE_T1S, + /** + * Tuple1 Fixed + */ + ZYDIS_TUPLETYPE_T1F, + /** + * Tuple1 4x32 + */ + ZYDIS_TUPLETYPE_T1_4X, + /** + * Gather / Scatter + */ + ZYDIS_TUPLETYPE_GSCAT, + /** + * Tuple2 + */ + ZYDIS_TUPLETYPE_T2, + /** + * Tuple4 + */ + ZYDIS_TUPLETYPE_T4, + /** + * Tuple8 + */ + ZYDIS_TUPLETYPE_T8, + /** + * Half Mem + */ + ZYDIS_TUPLETYPE_HVM, + /** + * QuarterMem + */ + ZYDIS_TUPLETYPE_QVM, + /** + * OctMem + */ + ZYDIS_TUPLETYPE_OVM, + /** + * Mem128 + */ + ZYDIS_TUPLETYPE_M128, + /** + * MOVDDUP + */ + ZYDIS_TUPLETYPE_DUP, + + /** + * Maximum value of this enum. + */ + ZYDIS_TUPLETYPE_MAX_VALUE = ZYDIS_TUPLETYPE_DUP, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_TUPLETYPE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_TUPLETYPE_MAX_VALUE) +} ZydisEVEXTupleType; + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisMVEXFunctionality` enum. + */ +typedef enum ZydisMVEXFunctionality_ +{ + /** + * The `MVEX.SSS` value is ignored. + */ + ZYDIS_MVEX_FUNC_IGNORED, + /** + * `MVEX.SSS` must be `000b`. + */ + ZYDIS_MVEX_FUNC_INVALID, + /** + * `MVEX.SSS` controls embedded-rounding functionality. + */ + ZYDIS_MVEX_FUNC_RC, + /** + * `MVEX.SSS` controls sae functionality. + */ + ZYDIS_MVEX_FUNC_SAE, + /** + * No special operation (32bit float elements). + */ + ZYDIS_MVEX_FUNC_F_32, + /** + * No special operation (32bit uint elements). + */ + ZYDIS_MVEX_FUNC_I_32, + /** + * No special operation (64bit float elements). + */ + ZYDIS_MVEX_FUNC_F_64, + /** + * No special operation (64bit uint elements). + */ + ZYDIS_MVEX_FUNC_I_64, + /** + * Sf32(reg) or Si32(reg). + */ + ZYDIS_MVEX_FUNC_SWIZZLE_32, + /** + * Sf64(reg) or Si64(reg). + */ + ZYDIS_MVEX_FUNC_SWIZZLE_64, + /** + * Sf32(mem). + */ + ZYDIS_MVEX_FUNC_SF_32, + /** + * Sf32(mem) broadcast only. + */ + ZYDIS_MVEX_FUNC_SF_32_BCST, + /** + * Sf32(mem) broadcast 4to16 only. + */ + ZYDIS_MVEX_FUNC_SF_32_BCST_4TO16, + /** + * Sf64(mem). + */ + ZYDIS_MVEX_FUNC_SF_64, + /** + * Si32(mem). + */ + ZYDIS_MVEX_FUNC_SI_32, + /** + * Si32(mem) broadcast only. + */ + ZYDIS_MVEX_FUNC_SI_32_BCST, + /** + * Si32(mem) broadcast 4to16 only. + */ + ZYDIS_MVEX_FUNC_SI_32_BCST_4TO16, + /** + * Si64(mem). + */ + ZYDIS_MVEX_FUNC_SI_64, + /** + * Uf32. + */ + ZYDIS_MVEX_FUNC_UF_32, + /** + * Uf64. + */ + ZYDIS_MVEX_FUNC_UF_64, + /** + * Ui32. + */ + ZYDIS_MVEX_FUNC_UI_32, + /** + * Ui64. + */ + ZYDIS_MVEX_FUNC_UI_64, + /** + * Df32. + */ + ZYDIS_MVEX_FUNC_DF_32, + /** + * Df64. + */ + ZYDIS_MVEX_FUNC_DF_64, + /** + * Di32. + */ + ZYDIS_MVEX_FUNC_DI_32, + /** + * Di64. + */ + ZYDIS_MVEX_FUNC_DI_64, + + /** + * Maximum value of this enum. + */ + ZYDIS_MVEX_FUNC_MAX_VALUE = ZYDIS_MVEX_FUNC_DI_64, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_MVEX_FUNC_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_MVEX_FUNC_MAX_VALUE) +} ZydisMVEXFunctionality; + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisVEXStaticBroadcast` enum. + */ +typedef enum ZydisVEXStaticBroadcast +{ + ZYDIS_VEX_STATIC_BROADCAST_NONE, + ZYDIS_VEX_STATIC_BROADCAST_1_TO_2, + ZYDIS_VEX_STATIC_BROADCAST_1_TO_4, + ZYDIS_VEX_STATIC_BROADCAST_1_TO_8, + ZYDIS_VEX_STATIC_BROADCAST_1_TO_16, + ZYDIS_VEX_STATIC_BROADCAST_1_TO_32, + ZYDIS_VEX_STATIC_BROADCAST_2_TO_4, + + /** + * Maximum value of this enum. + */ + ZYDIS_VEX_STATIC_BROADCAST_MAX_VALUE = ZYDIS_VEX_STATIC_BROADCAST_2_TO_4, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_VEX_STATIC_BROADCAST_REQUIRED_BITS = + ZYAN_BITS_TO_REPRESENT(ZYDIS_VEX_STATIC_BROADCAST_MAX_VALUE) +} ZydisVEXStaticBroadcast; + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisEVEXStaticBroadcast` enum. + */ +typedef enum ZydisEVEXStaticBroadcast_ +{ + ZYDIS_EVEX_STATIC_BROADCAST_NONE, + ZYDIS_EVEX_STATIC_BROADCAST_1_TO_2, + ZYDIS_EVEX_STATIC_BROADCAST_1_TO_4, + ZYDIS_EVEX_STATIC_BROADCAST_1_TO_8, + ZYDIS_EVEX_STATIC_BROADCAST_1_TO_16, + ZYDIS_EVEX_STATIC_BROADCAST_1_TO_32, + ZYDIS_EVEX_STATIC_BROADCAST_1_TO_64, + ZYDIS_EVEX_STATIC_BROADCAST_2_TO_4, + ZYDIS_EVEX_STATIC_BROADCAST_2_TO_8, + ZYDIS_EVEX_STATIC_BROADCAST_2_TO_16, + ZYDIS_EVEX_STATIC_BROADCAST_4_TO_8, + ZYDIS_EVEX_STATIC_BROADCAST_4_TO_16, + ZYDIS_EVEX_STATIC_BROADCAST_8_TO_16, + + /** + * Maximum value of this enum. + */ + ZYDIS_EVEX_STATIC_BROADCAST_MAX_VALUE = ZYDIS_EVEX_STATIC_BROADCAST_8_TO_16, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_EVEX_STATIC_BROADCAST_REQUIRED_BITS = + ZYAN_BITS_TO_REPRESENT(ZYDIS_EVEX_STATIC_BROADCAST_MAX_VALUE) +} ZydisEVEXStaticBroadcast; + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisMVEXStaticBroadcast` enum. + */ +typedef enum ZydisMVEXStaticBroadcast_ +{ + ZYDIS_MVEX_STATIC_BROADCAST_NONE, + ZYDIS_MVEX_STATIC_BROADCAST_1_TO_8, + ZYDIS_MVEX_STATIC_BROADCAST_1_TO_16, + ZYDIS_MVEX_STATIC_BROADCAST_4_TO_8, + ZYDIS_MVEX_STATIC_BROADCAST_4_TO_16, + + /** + * Maximum value of this enum. + */ + ZYDIS_MVEX_STATIC_BROADCAST_MAX_VALUE = ZYDIS_MVEX_STATIC_BROADCAST_4_TO_16, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_MVEX_STATIC_BROADCAST_REQUIRED_BITS = + ZYAN_BITS_TO_REPRESENT(ZYDIS_MVEX_STATIC_BROADCAST_MAX_VALUE) +} ZydisMVEXStaticBroadcast; + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisMaskPolicy` enum. + */ +typedef enum ZydisMaskPolicy_ +{ + ZYDIS_MASK_POLICY_INVALID, + /** + * The instruction accepts mask-registers other than the default-mask (K0), but + * does not require them. + */ + ZYDIS_MASK_POLICY_ALLOWED, + /** + * The instruction requires a mask-register other than the default-mask (K0). + */ + ZYDIS_MASK_POLICY_REQUIRED, + /** + * The instruction does not allow a mask-register other than the default-mask (K0). + */ + ZYDIS_MASK_POLICY_FORBIDDEN, + + /** + * Maximum value of this enum. + */ + ZYDIS_MASK_POLICY_MAX_VALUE = ZYDIS_MASK_POLICY_FORBIDDEN, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_MASK_POLICY_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_MASK_POLICY_MAX_VALUE) +} ZydisMaskPolicy; + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisMaskOverride` enum. + */ +typedef enum ZydisMaskOverride_ +{ + ZYDIS_MASK_OVERRIDE_DEFAULT, + ZYDIS_MASK_OVERRIDE_ZEROING, + ZYDIS_MASK_OVERRIDE_CONTROL, + + /** + * Maximum value of this enum. + */ + ZYDIS_MASK_OVERRIDE_MAX_VALUE = ZYDIS_MASK_OVERRIDE_CONTROL, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_MASK_OVERRIDE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_MASK_OVERRIDE_MAX_VALUE) +} ZydisMaskOverride; + +/* ---------------------------------------------------------------------------------------------- */ + +// MSVC does not correctly execute the `pragma pack(1)` compiler-directive, if we use the correct +// enum types +ZYAN_STATIC_ASSERT(ZYDIS_MNEMONIC_REQUIRED_BITS <= 16); +ZYAN_STATIC_ASSERT(ZYDIS_CATEGORY_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_ISA_SET_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_ISA_EXT_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_BRANCH_TYPE_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_EXCEPTION_CLASS_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_REG_CONSTRAINTS_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_RW_ACTION_REQUIRED_BITS <= 8); + +#ifndef ZYDIS_MINIMAL_MODE +# define ZYDIS_INSTRUCTION_DEFINITION_BASE \ + ZyanU16 mnemonic ZYAN_BITFIELD(ZYDIS_MNEMONIC_REQUIRED_BITS); \ + ZyanU8 operand_count ZYAN_BITFIELD( 4); \ + ZyanU16 operand_reference ZYAN_BITFIELD(15); \ + ZyanU8 operand_size_map ZYAN_BITFIELD( 3); \ + ZyanU8 address_size_map ZYAN_BITFIELD( 2); \ + ZyanU8 flags_reference ZYAN_BITFIELD( 7); \ + ZyanBool requires_protected_mode ZYAN_BITFIELD( 1); \ + ZyanU8 category ZYAN_BITFIELD(ZYDIS_CATEGORY_REQUIRED_BITS); \ + ZyanU8 isa_set ZYAN_BITFIELD(ZYDIS_ISA_SET_REQUIRED_BITS); \ + ZyanU8 isa_ext ZYAN_BITFIELD(ZYDIS_ISA_EXT_REQUIRED_BITS); \ + ZyanU8 branch_type ZYAN_BITFIELD(ZYDIS_BRANCH_TYPE_REQUIRED_BITS); \ + ZyanU8 exception_class ZYAN_BITFIELD(ZYDIS_EXCEPTION_CLASS_REQUIRED_BITS); \ + ZyanU8 constr_REG ZYAN_BITFIELD(ZYDIS_REG_CONSTRAINTS_REQUIRED_BITS); \ + ZyanU8 constr_RM ZYAN_BITFIELD(ZYDIS_REG_CONSTRAINTS_REQUIRED_BITS); \ + ZyanU8 cpu_state ZYAN_BITFIELD(ZYDIS_RW_ACTION_REQUIRED_BITS); \ + ZyanU8 fpu_state ZYAN_BITFIELD(ZYDIS_RW_ACTION_REQUIRED_BITS); \ + ZyanU8 xmm_state ZYAN_BITFIELD(ZYDIS_RW_ACTION_REQUIRED_BITS) +#else +# define ZYDIS_INSTRUCTION_DEFINITION_BASE \ + ZyanU16 mnemonic ZYAN_BITFIELD(ZYDIS_MNEMONIC_REQUIRED_BITS); \ + ZyanU8 operand_size_map ZYAN_BITFIELD( 3); \ + ZyanU8 address_size_map ZYAN_BITFIELD( 2); \ + ZyanBool requires_protected_mode ZYAN_BITFIELD( 1); \ + ZyanU8 constr_REG ZYAN_BITFIELD(ZYDIS_REG_CONSTRAINTS_REQUIRED_BITS); \ + ZyanU8 constr_RM ZYAN_BITFIELD(ZYDIS_REG_CONSTRAINTS_REQUIRED_BITS) +#endif + +#define ZYDIS_INSTRUCTION_DEFINITION_BASE_VECTOR \ + ZYDIS_INSTRUCTION_DEFINITION_BASE; \ + ZyanU8 constr_NDSNDD ZYAN_BITFIELD(ZYDIS_REG_CONSTRAINTS_REQUIRED_BITS) + +#define ZYDIS_INSTRUCTION_DEFINITION_BASE_VECTOR_INTEL \ + ZYDIS_INSTRUCTION_DEFINITION_BASE_VECTOR; \ + ZyanBool is_gather ZYAN_BITFIELD( 1) + +/** + * Defines the `ZydisInstructionDefinition` struct. + */ +typedef struct ZydisInstructionDefinition_ +{ + ZYDIS_INSTRUCTION_DEFINITION_BASE; +} ZydisInstructionDefinition; + +/** + * Defines the `ZydisInstructionDefinitionLEGACY` struct. + */ +typedef struct ZydisInstructionDefinitionLEGACY_ +{ + ZYDIS_INSTRUCTION_DEFINITION_BASE; +#ifndef ZYDIS_MINIMAL_MODE + ZyanBool is_privileged ZYAN_BITFIELD( 1); +#endif + ZyanBool accepts_LOCK ZYAN_BITFIELD( 1); +#ifndef ZYDIS_MINIMAL_MODE + ZyanBool accepts_REP ZYAN_BITFIELD( 1); + ZyanBool accepts_REPEREPZ ZYAN_BITFIELD( 1); + ZyanBool accepts_REPNEREPNZ ZYAN_BITFIELD( 1); + ZyanBool accepts_BOUND ZYAN_BITFIELD( 1); + ZyanBool accepts_XACQUIRE ZYAN_BITFIELD( 1); + ZyanBool accepts_XRELEASE ZYAN_BITFIELD( 1); + ZyanBool accepts_hle_without_lock ZYAN_BITFIELD( 1); + ZyanBool accepts_branch_hints ZYAN_BITFIELD( 1); + ZyanBool accepts_segment ZYAN_BITFIELD( 1); +#endif +} ZydisInstructionDefinitionLEGACY; + +/** + * Defines the `ZydisInstructionDefinition3DNOW` struct. + */ +typedef struct ZydisInstructionDefinition3DNOW_ +{ + ZYDIS_INSTRUCTION_DEFINITION_BASE; +} ZydisInstructionDefinition3DNOW; + +/** + * Defines the `ZydisInstructionDefinitionXOP` struct. + */ +typedef struct ZydisInstructionDefinitionXOP_ +{ + ZYDIS_INSTRUCTION_DEFINITION_BASE_VECTOR; +} ZydisInstructionDefinitionXOP; + +// MSVC does not correctly execute the `pragma pack(1)` compiler-directive, if we use the correct +// enum types +ZYAN_STATIC_ASSERT(ZYDIS_VEX_STATIC_BROADCAST_REQUIRED_BITS <= 8); + +/** + * Defines the `ZydisInstructionDefinitionVEX` struct. + */ +typedef struct ZydisInstructionDefinitionVEX_ +{ + ZYDIS_INSTRUCTION_DEFINITION_BASE_VECTOR_INTEL; +#ifndef ZYDIS_MINIMAL_MODE + ZyanU8 broadcast ZYAN_BITFIELD(ZYDIS_VEX_STATIC_BROADCAST_REQUIRED_BITS); +#endif +} ZydisInstructionDefinitionVEX; + +#ifndef ZYDIS_DISABLE_AVX512 + +// MSVC does not correctly execute the `pragma pack(1)` compiler-directive, if we use the correct +// enum types +ZYAN_STATIC_ASSERT(ZYDIS_IVECTOR_LENGTH_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_TUPLETYPE_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_IELEMENT_SIZE_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_EVEX_FUNC_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_MASK_POLICY_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_MASK_OVERRIDE_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_EVEX_STATIC_BROADCAST_REQUIRED_BITS <= 8); + +/** + * Defines the `ZydisInstructionDefinitionEVEX` struct. + */ +typedef struct ZydisInstructionDefinitionEVEX_ +{ + ZYDIS_INSTRUCTION_DEFINITION_BASE_VECTOR_INTEL; +#ifndef ZYDIS_MINIMAL_MODE + ZyanU8 vector_length ZYAN_BITFIELD(ZYDIS_IVECTOR_LENGTH_REQUIRED_BITS); + ZyanU8 tuple_type ZYAN_BITFIELD(ZYDIS_TUPLETYPE_REQUIRED_BITS); + ZyanU8 element_size ZYAN_BITFIELD(ZYDIS_IELEMENT_SIZE_REQUIRED_BITS); + ZyanU8 functionality ZYAN_BITFIELD(ZYDIS_EVEX_FUNC_REQUIRED_BITS); +#endif + ZyanU8 mask_policy ZYAN_BITFIELD(ZYDIS_MASK_POLICY_REQUIRED_BITS); + ZyanBool accepts_zero_mask ZYAN_BITFIELD( 1); +#ifndef ZYDIS_MINIMAL_MODE + ZyanU8 mask_override ZYAN_BITFIELD(ZYDIS_MASK_OVERRIDE_REQUIRED_BITS); + ZyanU8 broadcast ZYAN_BITFIELD(ZYDIS_EVEX_STATIC_BROADCAST_REQUIRED_BITS); +#endif +} ZydisInstructionDefinitionEVEX; +#endif + +#ifndef ZYDIS_DISABLE_KNC + +// MSVC does not correctly execute the `pragma pack(1)` compiler-directive, if we use the correct +// enum types +ZYAN_STATIC_ASSERT(ZYDIS_MVEX_FUNC_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_MASK_POLICY_REQUIRED_BITS <= 8); +ZYAN_STATIC_ASSERT(ZYDIS_MVEX_STATIC_BROADCAST_REQUIRED_BITS <= 8); + +/** + * Defines the `ZydisInstructionDefinitionMVEX` struct. + */ +typedef struct ZydisInstructionDefinitionMVEX_ +{ + ZYDIS_INSTRUCTION_DEFINITION_BASE_VECTOR_INTEL; + ZyanU8 functionality ZYAN_BITFIELD(ZYDIS_MVEX_FUNC_REQUIRED_BITS); + ZyanU8 mask_policy ZYAN_BITFIELD(ZYDIS_MASK_POLICY_REQUIRED_BITS); +#ifndef ZYDIS_MINIMAL_MODE + ZyanBool has_element_granularity ZYAN_BITFIELD( 1); + ZyanU8 broadcast ZYAN_BITFIELD(ZYDIS_MVEX_STATIC_BROADCAST_REQUIRED_BITS); +#endif +} ZydisInstructionDefinitionMVEX; +#endif + +/* ---------------------------------------------------------------------------------------------- */ +/* Accessed CPU flags */ +/* ---------------------------------------------------------------------------------------------- */ + +typedef struct ZydisAccessedFlags_ +{ + ZydisCPUFlagAction action[ZYDIS_CPUFLAG_MAX_VALUE + 1]; + ZyanU32 cpu_flags_read ZYAN_BITFIELD(22); + ZyanU32 cpu_flags_written ZYAN_BITFIELD(22); + ZyanU8 fpu_flags_read ZYAN_BITFIELD( 4); + ZyanU8 fpu_flags_written ZYAN_BITFIELD( 4); +} ZydisAccessedFlags; + +/* ---------------------------------------------------------------------------------------------- */ + +#pragma pack(pop) + +#ifdef ZYAN_MSVC +# pragma warning(pop) +#endif + +/* ============================================================================================== */ +/* Functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Instruction definition */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the instruction-definition with the given `encoding` and `id`. + * + * @param encoding The instruction-encoding. + * @param id The definition-id. + * @param definition A pointer to the variable that receives a pointer to the instruction- + * definition. + */ +ZYDIS_NO_EXPORT void ZydisGetInstructionDefinition(ZydisInstructionEncoding encoding, + ZyanU16 id, const ZydisInstructionDefinition** definition); + +/* ---------------------------------------------------------------------------------------------- */ +/* Operand definition */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYDIS_MINIMAL_MODE +/** + * Returns the the operand-definitions for the given instruction-`definition`. + * + * @param definition A pointer to the instruction-definition. + * @param operand A pointer to the variable that receives a pointer to the first operand- + * definition of the instruction. + * + * @return The number of operands for the given instruction-definition. + */ +ZYDIS_NO_EXPORT ZyanU8 ZydisGetOperandDefinitions(const ZydisInstructionDefinition* definition, + const ZydisOperandDefinition** operand); +#endif + +/* ---------------------------------------------------------------------------------------------- */ +/* Element info */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYDIS_MINIMAL_MODE +/** + * Returns the actual type and size of an internal element-type. + * + * @param element The internal element type. + * @param type The actual element type. + * @param size The element size. + */ +ZYDIS_NO_EXPORT void ZydisGetElementInfo(ZydisInternalElementType element, ZydisElementType* type, + ZydisElementSize* size); +#endif + +/* ---------------------------------------------------------------------------------------------- */ +/* Accessed CPU flags */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYDIS_MINIMAL_MODE +/** + * Returns the the operand-definitions for the given instruction-`definition`. + * + * @param definition A pointer to the instruction-definition. + * @param flags A pointer to the variable that receives the `ZydisAccessedFlags` struct. + * + * @return `ZYAN_TRUE`, if the instruction accesses any flags, or `ZYAN_FALSE`, if not. + */ +ZYDIS_NO_EXPORT ZyanBool ZydisGetAccessedFlags(const ZydisInstructionDefinition* definition, + const ZydisAccessedFlags** flags); +#endif + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYDIS_INTERNAL_SHAREDDATA_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/String.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/String.h new file mode 100644 index 0000000..18ed812 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/String.h @@ -0,0 +1,464 @@ +/*************************************************************************************************** + + Zyan Disassembler Library (Zydis) + + Original Author : Florian Bernd, Joel Hoener + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Provides some internal, more performant, but unsafe helper functions for the `ZyanString` + * data-type. + * + * Most of these functions are very similar to the ones in `Zycore/String.h`, but inlined and + * without optional overhead like parameter-validation checks, etc ... + * + * The `ZyanString` data-type is able to dynamically allocate memory on the heap, but as `Zydis` is + * designed to be a non-'malloc'ing library, all functions in this file assume that the instances + * they are operating on are created with a user-defined static-buffer. + */ + +#ifndef ZYDIS_INTERNAL_STRING_H +#define ZYDIS_INTERNAL_STRING_H + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Letter Case */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisLetterCase` enum. + */ +typedef enum ZydisLetterCase_ +{ + /** + * Uses the given text "as is". + */ + ZYDIS_LETTER_CASE_DEFAULT, + /** + * Converts the given text to lowercase letters. + */ + ZYDIS_LETTER_CASE_LOWER, + /** + * Converts the given text to uppercase letters. + */ + ZYDIS_LETTER_CASE_UPPER, + + /** + * Maximum value of this enum. + */ + ZYDIS_LETTER_CASE_MAX_VALUE = ZYDIS_LETTER_CASE_UPPER, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_LETTER_CASE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_LETTER_CASE_MAX_VALUE) +} ZydisLetterCase; + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Internal macros */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Checks for a terminating '\0' character at the end of the string data. + */ +#define ZYDIS_STRING_ASSERT_NULLTERMINATION(string) \ + ZYAN_ASSERT(*(char*)((ZyanU8*)(string)->vector.data + (string)->vector.size - 1) == '\0'); + +/** + * Writes a terminating '\0' character at the end of the string data. + */ +#define ZYDIS_STRING_NULLTERMINATE(string) \ + *(char*)((ZyanU8*)(string)->vector.data + (string)->vector.size - 1) = '\0'; + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Internal Functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Appending */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Appends the content of the source string to the end of the destination string. + * + * @param destination The destination string. + * @param source The source string. + * + * @return A zyan status code. + */ +ZYAN_INLINE ZyanStatus ZydisStringAppend(ZyanString* destination, const ZyanStringView* source) +{ + ZYAN_ASSERT(destination && source); + ZYAN_ASSERT(!destination->vector.allocator); + ZYAN_ASSERT(destination->vector.size && source->string.vector.size); + + if (destination->vector.size + source->string.vector.size - 1 > destination->vector.capacity) + { + return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; + } + + ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1, + source->string.vector.data, source->string.vector.size - 1); + + destination->vector.size += source->string.vector.size - 1; + ZYDIS_STRING_NULLTERMINATE(destination); + + return ZYAN_STATUS_SUCCESS; +} + +/** + * Appends the content of the source string to the end of the destination + * string, converting the characters to the specified letter-case. + * + * @param destination The destination string. + * @param source The source string. + * @param letter_case The desired letter-case. + * + * @return A zyan status code. + */ +ZYAN_INLINE ZyanStatus ZydisStringAppendCase(ZyanString* destination, const ZyanStringView* source, + ZydisLetterCase letter_case) +{ + ZYAN_ASSERT(destination && source); + ZYAN_ASSERT(!destination->vector.allocator); + ZYAN_ASSERT(destination->vector.size && source->string.vector.size); + + if (destination->vector.size + source->string.vector.size - 1 > destination->vector.capacity) + { + return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; + } + + ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1, + source->string.vector.data, source->string.vector.size - 1); + + switch (letter_case) + { + case ZYDIS_LETTER_CASE_DEFAULT: + break; + case ZYDIS_LETTER_CASE_LOWER: + { + const ZyanUSize index = destination->vector.size - 1; + const ZyanUSize count = source->string.vector.size - 1; + char* s = (char*)destination->vector.data + index; + for (ZyanUSize i = index; i < index + count; ++i) + { + const char c = *s; + if ((c >= 'A') && (c <= 'Z')) + { + *s = c | 32; + } + ++s; + } + break; + } + case ZYDIS_LETTER_CASE_UPPER: + { + const ZyanUSize index = destination->vector.size - 1; + const ZyanUSize count = source->string.vector.size - 1; + char* s = (char*)destination->vector.data + index; + for (ZyanUSize i = index; i < index + count; ++i) + { + const char c = *s; + if ((c >= 'a') && (c <= 'z')) + { + *s = c & ~32; + } + ++s; + } + break; + } + default: + ZYAN_UNREACHABLE; + } + + destination->vector.size += source->string.vector.size - 1; + ZYDIS_STRING_NULLTERMINATE(destination); + + return ZYAN_STATUS_SUCCESS; +} + +/** + * Appends the content of the source short-string to the end of the destination string. + * + * @param destination The destination string. + * @param source The source string. + * + * @return A zyan status code. + */ +ZYAN_INLINE ZyanStatus ZydisStringAppendShort(ZyanString* destination, + const ZydisShortString* source) +{ + ZYAN_ASSERT(destination && source); + ZYAN_ASSERT(!destination->vector.allocator); + ZYAN_ASSERT(destination->vector.size && source->size); + + if (destination->vector.size + source->size > destination->vector.capacity) + { + return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; + } + + ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1, source->data, + (ZyanUSize)source->size + 1); + + destination->vector.size += source->size; + ZYDIS_STRING_ASSERT_NULLTERMINATION(destination); + + return ZYAN_STATUS_SUCCESS; +} + +/** + * Appends the content of the source short-string to the end of the destination string, + * converting the characters to the specified letter-case. + * + * @param destination The destination string. + * @param source The source string. + * @param letter_case The desired letter-case. + * + * @return A zyan status code. + */ +ZYAN_INLINE ZyanStatus ZydisStringAppendShortCase(ZyanString* destination, + const ZydisShortString* source, ZydisLetterCase letter_case) +{ + ZYAN_ASSERT(destination && source); + ZYAN_ASSERT(!destination->vector.allocator); + ZYAN_ASSERT(destination->vector.size && source->size); + + if (destination->vector.size + source->size > destination->vector.capacity) + { + return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; + } + + ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1, source->data, + (ZyanUSize)source->size + 1); + + switch (letter_case) + { + case ZYDIS_LETTER_CASE_DEFAULT: + break; + case ZYDIS_LETTER_CASE_LOWER: + { + const ZyanUSize index = destination->vector.size - 1; + const ZyanUSize count = source->size; + char* s = (char*)destination->vector.data + index; + for (ZyanUSize i = index; i < index + count; ++i) + { + const char c = *s; + if ((c >= 'A') && (c <= 'Z')) + { + *s = c | 32; + } + ++s; + } + break; + } + case ZYDIS_LETTER_CASE_UPPER: + { + const ZyanUSize index = destination->vector.size - 1; + const ZyanUSize count = source->size; + char* s = (char*)destination->vector.data + index; + for (ZyanUSize i = index; i < index + count; ++i) + { + const char c = *s; + if ((c >= 'a') && (c <= 'z')) + { + *s = c & ~32; + } + ++s; + } + break; + } + default: + ZYAN_UNREACHABLE; + } + + destination->vector.size += source->size; + ZYDIS_STRING_ASSERT_NULLTERMINATION(destination); + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Formatting */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Formats the given unsigned ordinal `value` to its decimal text-representation and + * appends it to the `string`. + * + * @param string A pointer to the `ZyanString` instance. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length`. + * @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed. + * @param suffix The string to use as suffix or `ZYAN_NULL`, if not needed. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZyanStatus ZydisStringAppendDecU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length, + const ZyanStringView* prefix, const ZyanStringView* suffix); + +/** + * Formats the given signed ordinal `value` to its decimal text-representation and + * appends it to the `string`. + * + * @param string A pointer to the `ZyanString` instance. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length`. + * @param force_sign Set `ZYAN_TRUE`, to force printing of the `+` sign for positive numbers. + * @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed. + * @param suffix The string to use as suffix or `ZYAN_NULL`, if not needed. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYAN_INLINE ZyanStatus ZydisStringAppendDecS(ZyanString* string, ZyanI64 value, + ZyanU8 padding_length, ZyanBool force_sign, const ZyanStringView* prefix, + const ZyanStringView* suffix) +{ + static const ZydisShortString str_add = ZYDIS_MAKE_SHORTSTRING("+"); + static const ZydisShortString str_sub = ZYDIS_MAKE_SHORTSTRING("-"); + + if (value < 0) + { + ZYAN_CHECK(ZydisStringAppendShort(string, &str_sub)); + if (prefix) + { + ZYAN_CHECK(ZydisStringAppend(string, prefix)); + } + return ZydisStringAppendDecU(string, ZyanAbsI64(value), padding_length, + (const ZyanStringView*)ZYAN_NULL, suffix); + } + + if (force_sign) + { + ZYAN_ASSERT(value >= 0); + ZYAN_CHECK(ZydisStringAppendShort(string, &str_add)); + } + return ZydisStringAppendDecU(string, value, padding_length, prefix, suffix); +} + +/** + * Formats the given unsigned ordinal `value` to its hexadecimal text-representation and + * appends it to the `string`. + * + * @param string A pointer to the `ZyanString` instance. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length`. + * @param uppercase Set `ZYAN_TRUE` to use uppercase letters ('A'-'F') instead of lowercase + * ones ('a'-'f'). + * @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed. + * @param suffix The string to use as suffix or `ZYAN_NULL`, if not needed. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZyanStatus ZydisStringAppendHexU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length, + ZyanBool uppercase, const ZyanStringView* prefix, const ZyanStringView* suffix); + +/** + * Formats the given signed ordinal `value` to its hexadecimal text-representation and + * appends it to the `string`. + * + * @param string A pointer to the string. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length` (the sign char is ignored). + * @param uppercase Set `ZYAN_TRUE` to print the hexadecimal value in uppercase letters + * instead of lowercase ones. + * @param force_sign Set to `ZYAN_TRUE`, to force printing of the `+` sign for positive + * numbers. + * @param prefix The string to use as prefix or `NULL`, if not needed. + * @param suffix The string to use as suffix or `NULL`, if not needed. + * + * @return `ZYAN_STATUS_SUCCESS`, if the function succeeded, or + * `ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE`, if the size of the buffer was not + * sufficient to append the given `value`. + * + * The string-buffer pointer is increased by the number of chars written, if the call was + * successful. + */ +ZYAN_INLINE ZyanStatus ZydisStringAppendHexS(ZyanString* string, ZyanI64 value, + ZyanU8 padding_length, ZyanBool uppercase, ZyanBool force_sign, const ZyanStringView* prefix, + const ZyanStringView* suffix) +{ + static const ZydisShortString str_add = ZYDIS_MAKE_SHORTSTRING("+"); + static const ZydisShortString str_sub = ZYDIS_MAKE_SHORTSTRING("-"); + + if (value < 0) + { + ZYAN_CHECK(ZydisStringAppendShort(string, &str_sub)); + if (prefix) + { + ZYAN_CHECK(ZydisStringAppend(string, prefix)); + } + return ZydisStringAppendHexU(string, ZyanAbsI64(value), padding_length, uppercase, + (const ZyanStringView*)ZYAN_NULL, suffix); + } + + if (force_sign) + { + ZYAN_ASSERT(value >= 0); + ZYAN_CHECK(ZydisStringAppendShort(string, &str_add)); + } + return ZydisStringAppendHexU(string, value, padding_length, uppercase, prefix, suffix); +} + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif // ZYDIS_INTERNAL_STRING_H diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/MetaInfo.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/MetaInfo.h new file mode 100644 index 0000000..6867d32 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/MetaInfo.h @@ -0,0 +1,88 @@ +/*************************************************************************************************** + + Zyan Disassembler Library (Zydis) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * @brief + */ + +#ifndef ZYDIS_METAINFO_H +#define ZYDIS_METAINFO_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +#include +#include +#include + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + + /** + * Returns the specified instruction category string. + * + * @param category The instruction category. + * + * @return The instruction category string or `ZYAN_NULL`, if an invalid category was passed. + */ +ZYDIS_EXPORT const char* ZydisCategoryGetString(ZydisInstructionCategory category); + +/** + * Returns the specified isa-set string. + * + * @param isa_set The isa-set. + * + * @return The isa-set string or `ZYAN_NULL`, if an invalid isa-set was passed. + */ +ZYDIS_EXPORT const char* ZydisISASetGetString(ZydisISASet isa_set); + +/** + * Returns the specified isa-extension string. + * + * @param isa_ext The isa-extension. + * + * @return The isa-extension string or `ZYAN_NULL`, if an invalid isa-extension was passed. + */ +ZYDIS_EXPORT const char* ZydisISAExtGetString(ZydisISAExt isa_ext); + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYDIS_METAINFO_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Mnemonic.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Mnemonic.h new file mode 100644 index 0000000..dd8fec8 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Mnemonic.h @@ -0,0 +1,88 @@ +/*************************************************************************************************** + + Zyan Disassembler Library (Zydis) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Mnemonic constant definitions and helper functions. + */ + +#ifndef ZYDIS_MNEMONIC_H +#define ZYDIS_MNEMONIC_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +#include + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/** + * @addtogroup mnemonic Mnemonic + * Functions for retrieving mnemonic names. + * @{ + */ + +/** + * Returns the specified instruction mnemonic string. + * + * @param mnemonic The mnemonic. + * + * @return The instruction mnemonic string or `ZYAN_NULL`, if an invalid mnemonic was passed. + */ +ZYDIS_EXPORT const char* ZydisMnemonicGetString(ZydisMnemonic mnemonic); + +/** + * Returns the specified instruction mnemonic as `ZydisShortString`. + * + * @param mnemonic The mnemonic. + * + * @return The instruction mnemonic string or `ZYAN_NULL`, if an invalid mnemonic was passed. + * + * The `buffer` of the returned struct is guaranteed to be zero-terminated in this special case. + */ +ZYDIS_EXPORT const ZydisShortString* ZydisMnemonicGetStringWrapped(ZydisMnemonic mnemonic); + +/** + * @} + */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYDIS_MNEMONIC_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Register.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Register.h new file mode 100644 index 0000000..0ff955f --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Register.h @@ -0,0 +1,293 @@ +/*************************************************************************************************** + + Zyan Disassembler Library (Zydis) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Utility functions and constants for registers. + */ + +#ifndef ZYDIS_REGISTER_H +#define ZYDIS_REGISTER_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Registers */ +/* ---------------------------------------------------------------------------------------------- */ + +#include + +/* ---------------------------------------------------------------------------------------------- */ +/* Register classes */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisRegisterClass` enum. + * + * Please note that this enum does not contain a matching entry for all values of the + * `ZydisRegister` enum, but only for those registers where it makes sense to logically group them + * for decoding/encoding purposes. + * + * These are mainly the registers that can be identified by an id within their corresponding + * register-class. The `IP` and `FLAGS` values are exceptions to this rule. + */ +typedef enum ZydisRegisterClass_ +{ + ZYDIS_REGCLASS_INVALID, + /** + * 8-bit general-purpose registers. + */ + ZYDIS_REGCLASS_GPR8, + /** + * 16-bit general-purpose registers. + */ + ZYDIS_REGCLASS_GPR16, + /** + * 32-bit general-purpose registers. + */ + ZYDIS_REGCLASS_GPR32, + /** + * 64-bit general-purpose registers. + */ + ZYDIS_REGCLASS_GPR64, + /** + * Floating point legacy registers. + */ + ZYDIS_REGCLASS_X87, + /** + * Floating point multimedia registers. + */ + ZYDIS_REGCLASS_MMX, + /** + * 128-bit vector registers. + */ + ZYDIS_REGCLASS_XMM, + /** + * 256-bit vector registers. + */ + ZYDIS_REGCLASS_YMM, + /** + * 512-bit vector registers. + */ + ZYDIS_REGCLASS_ZMM, + /** + * Matrix registers. + */ + ZYDIS_REGCLASS_TMM, + /* + * Flags registers. + */ + ZYDIS_REGCLASS_FLAGS, + /** + * Instruction-pointer registers. + */ + ZYDIS_REGCLASS_IP, + /** + * Segment registers. + */ + ZYDIS_REGCLASS_SEGMENT, + /** + * Test registers. + */ + ZYDIS_REGCLASS_TEST, + /** + * Control registers. + */ + ZYDIS_REGCLASS_CONTROL, + /** + * Debug registers. + */ + ZYDIS_REGCLASS_DEBUG, + /** + * Mask registers. + */ + ZYDIS_REGCLASS_MASK, + /** + * Bound registers. + */ + ZYDIS_REGCLASS_BOUND, + + /** + * Maximum value of this enum. + */ + ZYDIS_REGCLASS_MAX_VALUE = ZYDIS_REGCLASS_BOUND, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_REGCLASS_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_REGCLASS_MAX_VALUE) +} ZydisRegisterClass; + +/* ---------------------------------------------------------------------------------------------- */ +/* Register width */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisRegisterWidth` data-type. + */ +typedef ZyanU16 ZydisRegisterWidth; + +/* ---------------------------------------------------------------------------------------------- */ +/* Register context */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisRegisterContext` struct. + */ +typedef struct ZydisRegisterContext_ +{ + /** + * The values stored in the register context. + */ + ZyanU64 values[ZYDIS_REGISTER_MAX_VALUE + 1]; +} ZydisRegisterContext; + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/** + * @addtogroup register Register + * Functions allowing retrieval of information about registers. + * @{ + */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Register */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the register specified by the `register_class` and `id` tuple. + * + * @param register_class The register class. + * @param id The register id. + * + * @return The register specified by the `register_class` and `id` tuple or `ZYDIS_REGISTER_NONE`, + * if an invalid parameter was passed. + */ +ZYDIS_EXPORT ZydisRegister ZydisRegisterEncode(ZydisRegisterClass register_class, ZyanU8 id); + +/** + * Returns the id of the specified register. + * + * @param reg The register. + * + * @return The id of the specified register, or -1 if an invalid parameter was passed. + */ +ZYDIS_EXPORT ZyanI8 ZydisRegisterGetId(ZydisRegister reg); + +/** + * Returns the register-class of the specified register. + * + * @param reg The register. + * + * @return The register-class of the specified register. + */ +ZYDIS_EXPORT ZydisRegisterClass ZydisRegisterGetClass(ZydisRegister reg); + +/** + * Returns the width of the specified register. + * + * @param mode The active machine mode. + * @param reg The register. + * + * @return The width of the specified register, or `ZYDIS_REGISTER_NONE` if the register is + * invalid for the active machine-mode. + */ +ZYDIS_EXPORT ZydisRegisterWidth ZydisRegisterGetWidth(ZydisMachineMode mode, ZydisRegister reg); + +/** + * Returns the largest enclosing register of the given register. + * + * @param mode The active machine mode. + * @param reg The register. + * + * @return The largest enclosing register of the given register, or `ZYDIS_REGISTER_NONE` if the + * register is invalid for the active machine-mode or does not have an enclosing-register. + */ +ZYDIS_EXPORT ZydisRegister ZydisRegisterGetLargestEnclosing(ZydisMachineMode mode, + ZydisRegister reg); + +/** + * Returns the specified register string. + * + * @param reg The register. + * + * @return The register string or `ZYAN_NULL`, if an invalid register was passed. + */ +ZYDIS_EXPORT const char* ZydisRegisterGetString(ZydisRegister reg); + +/** + * Returns the specified register string as `ZydisShortString`. + * + * @param reg The register. + * + * @return The register string or `ZYAN_NULL`, if an invalid register was passed. + * + * The `buffer` of the returned struct is guaranteed to be zero-terminated in this special case. + */ +ZYDIS_EXPORT const ZydisShortString* ZydisRegisterGetStringWrapped(ZydisRegister reg); + +/* ---------------------------------------------------------------------------------------------- */ +/* Register class */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the width of the specified register-class. + * + * @param mode The active machine mode. + * @param register_class The register class. + * + * @return The width of the specified register. + */ +ZYDIS_EXPORT ZydisRegisterWidth ZydisRegisterClassGetWidth(ZydisMachineMode mode, + ZydisRegisterClass register_class); + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * @} + */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYDIS_REGISTER_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/SharedTypes.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/SharedTypes.h new file mode 100644 index 0000000..82a4121 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/SharedTypes.h @@ -0,0 +1,480 @@ +/*************************************************************************************************** + + Zyan Disassembler Library (Zydis) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Defines decoder/encoder-shared macros and types. + */ + +#ifndef ZYDIS_SHAREDTYPES_H +#define ZYDIS_SHAREDTYPES_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Constants */ +/* ---------------------------------------------------------------------------------------------- */ + +#define ZYDIS_MAX_INSTRUCTION_LENGTH 15 +#define ZYDIS_MAX_OPERAND_COUNT 10 + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Machine mode */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisMachineMode` enum. + */ +typedef enum ZydisMachineMode_ +{ + /** + * 64 bit mode. + */ + ZYDIS_MACHINE_MODE_LONG_64, + /** + * 32 bit protected mode. + */ + ZYDIS_MACHINE_MODE_LONG_COMPAT_32, + /** + * 16 bit protected mode. + */ + ZYDIS_MACHINE_MODE_LONG_COMPAT_16, + /** + * 32 bit protected mode. + */ + ZYDIS_MACHINE_MODE_LEGACY_32, + /** + * 16 bit protected mode. + */ + ZYDIS_MACHINE_MODE_LEGACY_16, + /** + * 16 bit real mode. + */ + ZYDIS_MACHINE_MODE_REAL_16, + + /** + * Maximum value of this enum. + */ + ZYDIS_MACHINE_MODE_MAX_VALUE = ZYDIS_MACHINE_MODE_REAL_16, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_MACHINE_MODE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_MACHINE_MODE_MAX_VALUE) +} ZydisMachineMode; + +/* ---------------------------------------------------------------------------------------------- */ +/* Address width */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisAddressWidth` enum. + */ +typedef enum ZydisAddressWidth_ +{ + ZYDIS_ADDRESS_WIDTH_16, + ZYDIS_ADDRESS_WIDTH_32, + ZYDIS_ADDRESS_WIDTH_64, + + /** + * Maximum value of this enum. + */ + ZYDIS_ADDRESS_WIDTH_MAX_VALUE = ZYDIS_ADDRESS_WIDTH_64, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_ADDRESS_WIDTH_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_ADDRESS_WIDTH_MAX_VALUE) +} ZydisAddressWidth; + +/* ---------------------------------------------------------------------------------------------- */ +/* Element type */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisElementType` enum. + */ +typedef enum ZydisElementType_ +{ + ZYDIS_ELEMENT_TYPE_INVALID, + /** + * A struct type. + */ + ZYDIS_ELEMENT_TYPE_STRUCT, + /** + * Unsigned integer value. + */ + ZYDIS_ELEMENT_TYPE_UINT, + /** + * Signed integer value. + */ + ZYDIS_ELEMENT_TYPE_INT, + /** + * 16-bit floating point value (`half`). + */ + ZYDIS_ELEMENT_TYPE_FLOAT16, + /** + * 32-bit floating point value (`single`). + */ + ZYDIS_ELEMENT_TYPE_FLOAT32, + /** + * 64-bit floating point value (`double`). + */ + ZYDIS_ELEMENT_TYPE_FLOAT64, + /** + * 80-bit floating point value (`extended`). + */ + ZYDIS_ELEMENT_TYPE_FLOAT80, + /** + * Binary coded decimal value. + */ + ZYDIS_ELEMENT_TYPE_LONGBCD, + /** + * A condition code (e.g. used by `CMPPD`, `VCMPPD`, ...). + */ + ZYDIS_ELEMENT_TYPE_CC, + + /** + * Maximum value of this enum. + */ + ZYDIS_ELEMENT_TYPE_MAX_VALUE = ZYDIS_ELEMENT_TYPE_CC, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_ELEMENT_TYPE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_ELEMENT_TYPE_MAX_VALUE) +} ZydisElementType; + +/* ---------------------------------------------------------------------------------------------- */ +/* Element size */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisElementSize` datatype. + */ +typedef ZyanU16 ZydisElementSize; + +/* ---------------------------------------------------------------------------------------------- */ +/* Operand type */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisOperandType` enum. + */ +typedef enum ZydisOperandType_ +{ + /** + * The operand is not used. + */ + ZYDIS_OPERAND_TYPE_UNUSED, + /** + * The operand is a register operand. + */ + ZYDIS_OPERAND_TYPE_REGISTER, + /** + * The operand is a memory operand. + */ + ZYDIS_OPERAND_TYPE_MEMORY, + /** + * The operand is a pointer operand with a segment:offset lvalue. + */ + ZYDIS_OPERAND_TYPE_POINTER, + /** + * The operand is an immediate operand. + */ + ZYDIS_OPERAND_TYPE_IMMEDIATE, + + /** + * Maximum value of this enum. + */ + ZYDIS_OPERAND_TYPE_MAX_VALUE = ZYDIS_OPERAND_TYPE_IMMEDIATE, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_OPERAND_TYPE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_OPERAND_TYPE_MAX_VALUE) +} ZydisOperandType; + +/* ---------------------------------------------------------------------------------------------- */ +/* Operand encoding */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisOperandEncoding` enum. + */ +typedef enum ZydisOperandEncoding_ +{ + ZYDIS_OPERAND_ENCODING_NONE, + ZYDIS_OPERAND_ENCODING_MODRM_REG, + ZYDIS_OPERAND_ENCODING_MODRM_RM, + ZYDIS_OPERAND_ENCODING_OPCODE, + ZYDIS_OPERAND_ENCODING_NDSNDD, + ZYDIS_OPERAND_ENCODING_IS4, + ZYDIS_OPERAND_ENCODING_MASK, + ZYDIS_OPERAND_ENCODING_DISP8, + ZYDIS_OPERAND_ENCODING_DISP16, + ZYDIS_OPERAND_ENCODING_DISP32, + ZYDIS_OPERAND_ENCODING_DISP64, + ZYDIS_OPERAND_ENCODING_DISP16_32_64, + ZYDIS_OPERAND_ENCODING_DISP32_32_64, + ZYDIS_OPERAND_ENCODING_DISP16_32_32, + ZYDIS_OPERAND_ENCODING_UIMM8, + ZYDIS_OPERAND_ENCODING_UIMM16, + ZYDIS_OPERAND_ENCODING_UIMM32, + ZYDIS_OPERAND_ENCODING_UIMM64, + ZYDIS_OPERAND_ENCODING_UIMM16_32_64, + ZYDIS_OPERAND_ENCODING_UIMM32_32_64, + ZYDIS_OPERAND_ENCODING_UIMM16_32_32, + ZYDIS_OPERAND_ENCODING_SIMM8, + ZYDIS_OPERAND_ENCODING_SIMM16, + ZYDIS_OPERAND_ENCODING_SIMM32, + ZYDIS_OPERAND_ENCODING_SIMM64, + ZYDIS_OPERAND_ENCODING_SIMM16_32_64, + ZYDIS_OPERAND_ENCODING_SIMM32_32_64, + ZYDIS_OPERAND_ENCODING_SIMM16_32_32, + ZYDIS_OPERAND_ENCODING_JIMM8, + ZYDIS_OPERAND_ENCODING_JIMM16, + ZYDIS_OPERAND_ENCODING_JIMM32, + ZYDIS_OPERAND_ENCODING_JIMM64, + ZYDIS_OPERAND_ENCODING_JIMM16_32_64, + ZYDIS_OPERAND_ENCODING_JIMM32_32_64, + ZYDIS_OPERAND_ENCODING_JIMM16_32_32, + + /** + * Maximum value of this enum. + */ + ZYDIS_OPERAND_ENCODING_MAX_VALUE = ZYDIS_OPERAND_ENCODING_JIMM16_32_32, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_OPERAND_ENCODING_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_OPERAND_ENCODING_MAX_VALUE) +} ZydisOperandEncoding; + +/* ---------------------------------------------------------------------------------------------- */ +/* Operand visibility */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisOperandVisibility` enum. + */ +typedef enum ZydisOperandVisibility_ +{ + ZYDIS_OPERAND_VISIBILITY_INVALID, + /** + * The operand is explicitly encoded in the instruction. + */ + ZYDIS_OPERAND_VISIBILITY_EXPLICIT, + /** + * The operand is part of the opcode, but listed as an operand. + */ + ZYDIS_OPERAND_VISIBILITY_IMPLICIT, + /** + * The operand is part of the opcode, and not typically listed as an operand. + */ + ZYDIS_OPERAND_VISIBILITY_HIDDEN, + + /** + * Maximum value of this enum. + */ + ZYDIS_OPERAND_VISIBILITY_MAX_VALUE = ZYDIS_OPERAND_VISIBILITY_HIDDEN, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_OPERAND_VISIBILITY_REQUIRED_BITS = + ZYAN_BITS_TO_REPRESENT(ZYDIS_OPERAND_VISIBILITY_MAX_VALUE) +} ZydisOperandVisibility; + +/* ---------------------------------------------------------------------------------------------- */ +/* Operand action */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisOperandAction` enum. + */ +typedef enum ZydisOperandAction_ +{ + /* ------------------------------------------------------------------------------------------ */ + /* Elemental actions */ + /* ------------------------------------------------------------------------------------------ */ + + /** + * The operand is read by the instruction. + */ + ZYDIS_OPERAND_ACTION_READ = 0x01, + /** + * The operand is written by the instruction (must write). + */ + ZYDIS_OPERAND_ACTION_WRITE = 0x02, + /** + * The operand is conditionally read by the instruction. + */ + ZYDIS_OPERAND_ACTION_CONDREAD = 0x04, + /** + * The operand is conditionally written by the instruction (may write). + */ + ZYDIS_OPERAND_ACTION_CONDWRITE = 0x08, + + /* ------------------------------------------------------------------------------------------ */ + /* Combined actions */ + /* ------------------------------------------------------------------------------------------ */ + + /** + * The operand is read (must read) and written by the instruction (must write). + */ + ZYDIS_OPERAND_ACTION_READWRITE = ZYDIS_OPERAND_ACTION_READ | ZYDIS_OPERAND_ACTION_WRITE, + /** + * The operand is conditionally read (may read) and conditionally written by + * the instruction (may write). + */ + ZYDIS_OPERAND_ACTION_CONDREAD_CONDWRITE = + ZYDIS_OPERAND_ACTION_CONDREAD | ZYDIS_OPERAND_ACTION_CONDWRITE, + /** + * The operand is read (must read) and conditionally written by the + * instruction (may write). + */ + ZYDIS_OPERAND_ACTION_READ_CONDWRITE = + ZYDIS_OPERAND_ACTION_READ | ZYDIS_OPERAND_ACTION_CONDWRITE, + /** + * The operand is written (must write) and conditionally read by the + * instruction (may read). + */ + ZYDIS_OPERAND_ACTION_CONDREAD_WRITE = + ZYDIS_OPERAND_ACTION_CONDREAD | ZYDIS_OPERAND_ACTION_WRITE, + + /** + * Mask combining all reading access flags. + */ + ZYDIS_OPERAND_ACTION_MASK_READ = ZYDIS_OPERAND_ACTION_READ | ZYDIS_OPERAND_ACTION_CONDREAD, + /** + * Mask combining all writing access flags. + */ + ZYDIS_OPERAND_ACTION_MASK_WRITE = ZYDIS_OPERAND_ACTION_WRITE | ZYDIS_OPERAND_ACTION_CONDWRITE, + + /* ------------------------------------------------------------------------------------------ */ + + /** + * The minimum number of bits required to represent all values of this bitset. + */ + ZYDIS_OPERAND_ACTION_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_OPERAND_ACTION_CONDWRITE) +} ZydisOperandAction; + +/** + * Defines the `ZydisOperandActions` data-type. + */ +typedef ZyanU8 ZydisOperandActions; + +/* ---------------------------------------------------------------------------------------------- */ +/* Instruction encoding */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisInstructionEncoding` enum. + */ +typedef enum ZydisInstructionEncoding_ +{ + /** + * The instruction uses the legacy encoding. + */ + ZYDIS_INSTRUCTION_ENCODING_LEGACY, + /** + * The instruction uses the AMD 3DNow-encoding. + */ + ZYDIS_INSTRUCTION_ENCODING_3DNOW, + /** + * The instruction uses the AMD XOP-encoding. + */ + ZYDIS_INSTRUCTION_ENCODING_XOP, + /** + * The instruction uses the VEX-encoding. + */ + ZYDIS_INSTRUCTION_ENCODING_VEX, + /** + * The instruction uses the EVEX-encoding. + */ + ZYDIS_INSTRUCTION_ENCODING_EVEX, + /** + * The instruction uses the MVEX-encoding. + */ + ZYDIS_INSTRUCTION_ENCODING_MVEX, + + /** + * Maximum value of this enum. + */ + ZYDIS_INSTRUCTION_ENCODING_MAX_VALUE = ZYDIS_INSTRUCTION_ENCODING_MVEX, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_INSTRUCTION_ENCODING_REQUIRED_BITS = + ZYAN_BITS_TO_REPRESENT(ZYDIS_INSTRUCTION_ENCODING_MAX_VALUE) +} ZydisInstructionEncoding; + +/* ---------------------------------------------------------------------------------------------- */ +/* Opcode map */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZydisOpcodeMap` enum. + */ +typedef enum ZydisOpcodeMap_ +{ + ZYDIS_OPCODE_MAP_DEFAULT, + ZYDIS_OPCODE_MAP_0F, + ZYDIS_OPCODE_MAP_0F38, + ZYDIS_OPCODE_MAP_0F3A, + ZYDIS_OPCODE_MAP_0F0F, + ZYDIS_OPCODE_MAP_XOP8, + ZYDIS_OPCODE_MAP_XOP9, + ZYDIS_OPCODE_MAP_XOPA, + + /** + * Maximum value of this enum. + */ + ZYDIS_OPCODE_MAP_MAX_VALUE = ZYDIS_OPCODE_MAP_XOPA, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_OPCODE_MAP_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_OPCODE_MAP_MAX_VALUE) +} ZydisOpcodeMap; + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYDIS_SHAREDTYPES_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/ShortString.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/ShortString.h new file mode 100644 index 0000000..bed45af --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/ShortString.h @@ -0,0 +1,90 @@ +/*************************************************************************************************** + + Zyan Disassembler Library (Zydis) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Defines the immutable and storage-efficient `ZydisShortString` struct, which + * is used to store strings in the generated tables. + */ + +#ifndef ZYDIS_SHORTSTRING_H +#define ZYDIS_SHORTSTRING_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +#pragma pack(push, 1) + +/** + * Defines the `ZydisShortString` struct. + * + * This compact struct is mainly used for internal string-tables to save up some bytes. + * + * All fields in this struct should be considered as "private". Any changes may lead to unexpected + * behavior. + */ +typedef struct ZydisShortString_ +{ + /** + * The buffer that contains the actual (null-terminated) string. + */ + const char* data; + /** + * The length (number of characters) of the string (without 0-termination). + */ + ZyanU8 size; +} ZydisShortString; + +#pragma pack(pop) + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/** + * Declares a `ZydisShortString` from a static C-style string. + * + * @param string The C-string constant. + */ +#define ZYDIS_MAKE_SHORTSTRING(string) \ + { string, sizeof(string) - 1 } + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYDIS_SHORTSTRING_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Status.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Status.h new file mode 100644 index 0000000..d2a75f3 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Status.h @@ -0,0 +1,159 @@ +/*************************************************************************************************** + + Zyan Disassembler Library (Zydis) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Status code definitions and check macros. + */ + +#ifndef ZYDIS_STATUS_H +#define ZYDIS_STATUS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Status codes */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Module IDs */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * The zydis module id. + */ +#define ZYAN_MODULE_ZYDIS 0x002u + +/* ---------------------------------------------------------------------------------------------- */ +/* Status codes */ +/* ---------------------------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Decoder */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * An attempt was made to read data from an input data-source that has no more + * data available. + */ +#define ZYDIS_STATUS_NO_MORE_DATA \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYDIS, 0x00u) + +/** + * An general error occured while decoding the current instruction. The + * instruction might be undefined. + */ +#define ZYDIS_STATUS_DECODING_ERROR \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYDIS, 0x01u) + +/** + * The instruction exceeded the maximum length of 15 bytes. + */ +#define ZYDIS_STATUS_INSTRUCTION_TOO_LONG \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYDIS, 0x02u) + +/** + * The instruction encoded an invalid register. + */ +#define ZYDIS_STATUS_BAD_REGISTER \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYDIS, 0x03u) + +/** + * A lock-prefix (F0) was found while decoding an instruction that does not + * support locking. + */ +#define ZYDIS_STATUS_ILLEGAL_LOCK \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYDIS, 0x04u) + +/** + * A legacy-prefix (F2, F3, 66) was found while decoding a XOP/VEX/EVEX/MVEX + * instruction. + */ +#define ZYDIS_STATUS_ILLEGAL_LEGACY_PFX \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYDIS, 0x05u) + +/** + * A rex-prefix was found while decoding a XOP/VEX/EVEX/MVEX instruction. + */ +#define ZYDIS_STATUS_ILLEGAL_REX \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYDIS, 0x06u) + +/** + * An invalid opcode-map value was found while decoding a XOP/VEX/EVEX/MVEX-prefix. + */ +#define ZYDIS_STATUS_INVALID_MAP \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYDIS, 0x07u) + +/** + * An error occured while decoding the EVEX-prefix. + */ +#define ZYDIS_STATUS_MALFORMED_EVEX \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYDIS, 0x08u) + +/** + * An error occured while decoding the MVEX-prefix. + */ +#define ZYDIS_STATUS_MALFORMED_MVEX \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYDIS, 0x09u) + +/** + * An invalid write-mask was specified for an EVEX/MVEX instruction. + */ +#define ZYDIS_STATUS_INVALID_MASK \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYDIS, 0x0Au) + +/* ---------------------------------------------------------------------------------------------- */ +/* Formatter */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returning this status code in some specified formatter callbacks will cause + * the formatter to omit the corresponding token. + * + * Valid callbacks: + * - `ZYDIS_FORMATTER_FUNC_PRE_OPERAND` + * - `ZYDIS_FORMATTER_FUNC_POST_OPERAND` + * - `ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_REG` + * - `ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_MEM` + * - `ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_PTR` + * - `ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_IMM` + */ +#define ZYDIS_STATUS_SKIP_TOKEN \ + ZYAN_MAKE_STATUS(0u, ZYAN_MODULE_ZYDIS, 0x0Bu) + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYDIS_STATUS_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Utils.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Utils.h new file mode 100644 index 0000000..aef9e96 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Utils.h @@ -0,0 +1,275 @@ +/*************************************************************************************************** + + Zyan Disassembler Library (Zydis) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Other utility functions. + */ + +#ifndef ZYDIS_UTILS_H +#define ZYDIS_UTILS_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Constants */ +/* ---------------------------------------------------------------------------------------------- */ + +#define ZYDIS_MAX_INSTRUCTION_SEGMENT_COUNT 9 + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/** + * Defines the `ZydisInstructionSegment` struct. + */ +typedef enum ZydisInstructionSegment_ +{ + ZYDIS_INSTR_SEGMENT_NONE, + /** + * The legacy prefixes (including ignored `REX` prefixes). + */ + ZYDIS_INSTR_SEGMENT_PREFIXES, + /** + * The effective `REX` prefix byte. + */ + ZYDIS_INSTR_SEGMENT_REX, + /** + * The `XOP` prefix bytes. + */ + ZYDIS_INSTR_SEGMENT_XOP, + /** + * The `VEX` prefix bytes. + */ + ZYDIS_INSTR_SEGMENT_VEX, + /** + * The `EVEX` prefix bytes. + */ + ZYDIS_INSTR_SEGMENT_EVEX, + /** + * The `MVEX` prefix bytes. + */ + ZYDIS_INSTR_SEGMENT_MVEX, + /** + * The opcode bytes. + */ + ZYDIS_INSTR_SEGMENT_OPCODE, + /** + * The `ModRM` byte. + */ + ZYDIS_INSTR_SEGMENT_MODRM, + /** + * The `SIB` byte. + */ + ZYDIS_INSTR_SEGMENT_SIB, + /** + * The displacement bytes. + */ + ZYDIS_INSTR_SEGMENT_DISPLACEMENT, + /** + * The immediate bytes. + */ + ZYDIS_INSTR_SEGMENT_IMMEDIATE, + + /** + * Maximum value of this enum. + */ + ZYDIS_INSTR_SEGMENT_MAX_VALUE = ZYDIS_INSTR_SEGMENT_IMMEDIATE, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_INSTR_SEGMENT_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_INSTR_SEGMENT_MAX_VALUE) +} ZydisInstructionSegment; + +/** + * Defines the `ZydisInstructionSegments` struct. + */ +typedef struct ZydisInstructionSegments_ +{ + /** + * The number of logical instruction segments. + */ + ZyanU8 count; + struct + { + /** + * The type of the segment. + */ + ZydisInstructionSegment type; + /** + * The offset of the segment relative to the start of the instruction (in bytes). + */ + ZyanU8 offset; + /** + * The size of the segment, in bytes. + */ + ZyanU8 size; + } segments[ZYDIS_MAX_INSTRUCTION_SEGMENT_COUNT]; +} ZydisInstructionSegments; + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/** + * @addtogroup utils Utils + * Miscellaneous utility functions. Address translation and other helpers. + * @{ + */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Address calculation */ +/* ---------------------------------------------------------------------------------------------- */ + +// TODO: Provide a function that works in minimal-mode and does not require a operand parameter + +/** + * Calculates the absolute address value for the given instruction operand. + * + * @param instruction A pointer to the `ZydisDecodedInstruction` struct. + * @param operand A pointer to the `ZydisDecodedOperand` struct. + * @param runtime_address The runtime address of the instruction. + * @param result_address A pointer to the memory that receives the absolute address. + * + * @return A zyan status code. + * + * You should use this function in the following cases: + * - `IMM` operands with relative address (e.g. `JMP`, `CALL`, ...) + * - `MEM` operands with `RIP`/`EIP`-relative address (e.g. `MOV RAX, [RIP+0x12345678]`) + * - `MEM` operands with absolute address (e.g. `MOV RAX, [0x12345678]`) + * - The displacement needs to get truncated and zero extended + */ +ZYDIS_EXPORT ZyanStatus ZydisCalcAbsoluteAddress(const ZydisDecodedInstruction* instruction, + const ZydisDecodedOperand* operand, ZyanU64 runtime_address, ZyanU64* result_address); + +/** + * Calculates the absolute address value for the given instruction operand. + * + * @param instruction A pointer to the `ZydisDecodedInstruction` struct. + * @param operand A pointer to the `ZydisDecodedOperand` struct. + * @param runtime_address The runtime address of the instruction. + * @param register_context A pointer to the `ZydisRegisterContext` struct. + * @param result_address A pointer to the memory that receives the absolute target-address. + * + * @return A zyan status code. + * + * This function behaves like `ZydisCalcAbsoluteAddress` but takes an additional register-context + * argument to allow calculation of addresses depending on runtime register values. + * + * Note that `IP/EIP/RIP` from the register-context will be ignored in favor of the passed + * runtime-address. + */ +ZYDIS_EXPORT ZyanStatus ZydisCalcAbsoluteAddressEx(const ZydisDecodedInstruction* instruction, + const ZydisDecodedOperand* operand, ZyanU64 runtime_address, + const ZydisRegisterContext* register_context, ZyanU64* result_address); + +/* ---------------------------------------------------------------------------------------------- */ +/* Accessed CPU flags */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns a mask of accessed CPU-flags matching the given `action`. + * + * @param instruction A pointer to the `ZydisDecodedInstruction` struct. + * @param action The CPU-flag action. + * @param flags Receives the flag mask. + * + * @return A zyan status code. + */ +ZYDIS_EXPORT ZyanStatus ZydisGetAccessedFlagsByAction(const ZydisDecodedInstruction* instruction, + ZydisCPUFlagAction action, ZydisCPUFlags* flags); + +/** + * Returns a mask of accessed CPU-flags that are read (tested) by the current instruction. + * + * DEPRECATED. This function will be removed in the next major release. Please refer to the + * `cpu_flags_read` or `fpu_flags_read` fields of the `ZydisDecodedInstruction` instead. + * + * @param instruction A pointer to the `ZydisDecodedInstruction` struct. + * @param flags Receives the flag mask. + * + * @return A zyan status code. + */ +ZYDIS_DEPRECATED_EXPORT ZyanStatus ZydisGetAccessedFlagsRead( + const ZydisDecodedInstruction* instruction, ZydisCPUFlags* flags); + +/** + * Returns a mask of accessed CPU-flags that are written (modified, undefined) by the current + * instruction. + * + * DEPRECATED. This function will be removed in the next major release. Please refer to the + * `cpu_flags_written` or `fpu_flags_written` fields of the `ZydisDecodedInstruction` instead. + * + * @param instruction A pointer to the `ZydisDecodedInstruction` struct. + * @param flags Receives the flag mask. + * + * @return A zyan status code. + */ +ZYDIS_DEPRECATED_EXPORT ZyanStatus ZydisGetAccessedFlagsWritten( + const ZydisDecodedInstruction* instruction, ZydisCPUFlags* flags); + +/* ---------------------------------------------------------------------------------------------- */ +/* Instruction segments */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns offsets and sizes of all logical instruction segments (e.g. `OPCODE`, + * `MODRM`, ...). + * + * @param instruction A pointer to the `ZydisDecodedInstruction` struct. + * @param segments Receives the instruction segments information. + * + * @return A zyan status code. + */ +ZYDIS_EXPORT ZyanStatus ZydisGetInstructionSegments(const ZydisDecodedInstruction* instruction, + ZydisInstructionSegments* segments); + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * @} + */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYDIS_UTILS_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Zydis.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Zydis.h new file mode 100644 index 0000000..a0d2d87 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Zydis.h @@ -0,0 +1,169 @@ +/*************************************************************************************************** + + Zyan Disassembler Library (Zydis) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Master include file, including everything else. + */ + +#ifndef ZYDIS_H +#define ZYDIS_H + +#include +#include + +#ifndef ZYDIS_DISABLE_DECODER +# include +# include +#endif + +#ifndef ZYDIS_DISABLE_FORMATTER +# include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Constants */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * A macro that defines the zydis version. + */ +#define ZYDIS_VERSION (ZyanU64)0x0003000100000000 + +/* ---------------------------------------------------------------------------------------------- */ +/* Helper macros */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Extracts the major-part of the zydis version. + * + * @param version The zydis version value + */ +#define ZYDIS_VERSION_MAJOR(version) (ZyanU16)(((version) & 0xFFFF000000000000) >> 48) + +/** + * Extracts the minor-part of the zydis version. + * + * @param version The zydis version value + */ +#define ZYDIS_VERSION_MINOR(version) (ZyanU16)(((version) & 0x0000FFFF00000000) >> 32) + +/** + * Extracts the patch-part of the zydis version. + * + * @param version The zydis version value + */ +#define ZYDIS_VERSION_PATCH(version) (ZyanU16)(((version) & 0x00000000FFFF0000) >> 16) + +/** + * Extracts the build-part of the zydis version. + * + * @param version The zydis version value + */ +#define ZYDIS_VERSION_BUILD(version) (ZyanU16)((version) & 0x000000000000FFFF) + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/** + * Defines the `ZydisFeature` enum. + */ +typedef enum ZydisFeature_ +{ + ZYDIS_FEATURE_DECODER, + ZYDIS_FEATURE_FORMATTER, + ZYDIS_FEATURE_AVX512, + ZYDIS_FEATURE_KNC, + + /** + * Maximum value of this enum. + */ + ZYDIS_FEATURE_MAX_VALUE = ZYDIS_FEATURE_KNC, + /** + * The minimum number of bits required to represent all values of this enum. + */ + ZYDIS_FEATURE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_FEATURE_MAX_VALUE) +} ZydisFeature; + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/** + * @addtogroup version Version + * Functions for checking the library version and build options. + * @{ + */ + +/** + * Returns the zydis version. + * + * @return The zydis version. + * + * Use the macros provided in this file to extract the major, minor, patch and build part from the + * returned version value. + */ +ZYDIS_EXPORT ZyanU64 ZydisGetVersion(void); + +/** + * Checks, if the specified feature is enabled in the current zydis library instance. + * + * @param feature The feature. + * + * @return `ZYAN_STATUS_TRUE` if the feature is enabled, `ZYAN_STATUS_FALSE` if not. Another + * zyan status code, if an error occured. + */ +ZYDIS_EXPORT ZyanStatus ZydisIsFeatureEnabled(ZydisFeature feature); + +/** + * @} + */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYDIS_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/ZydisExportConfig.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/ZydisExportConfig.h new file mode 100644 index 0000000..2e0b4a2 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/ZydisExportConfig.h @@ -0,0 +1,42 @@ + +#ifndef ZYDIS_EXPORT_H +#define ZYDIS_EXPORT_H + +#ifdef ZYDIS_STATIC_DEFINE +# define ZYDIS_EXPORT +# define ZYDIS_NO_EXPORT +#else +# ifndef ZYDIS_EXPORT +# ifdef Zydis_EXPORTS + /* We are building this library */ +# define ZYDIS_EXPORT __declspec(dllexport) +# else + /* We are using this library */ +# define ZYDIS_EXPORT __declspec(dllimport) +# endif +# endif + +# ifndef ZYDIS_NO_EXPORT +# define ZYDIS_NO_EXPORT +# endif +#endif + +#ifndef ZYDIS_DEPRECATED +# define ZYDIS_DEPRECATED __declspec(deprecated) +#endif + +#ifndef ZYDIS_DEPRECATED_EXPORT +# define ZYDIS_DEPRECATED_EXPORT ZYDIS_EXPORT ZYDIS_DEPRECATED +#endif + +#ifndef ZYDIS_DEPRECATED_NO_EXPORT +# define ZYDIS_DEPRECATED_NO_EXPORT ZYDIS_NO_EXPORT ZYDIS_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef ZYDIS_NO_DEPRECATED +# define ZYDIS_NO_DEPRECATED +# endif +#endif + +#endif /* ZYDIS_EXPORT_H */ diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit.natvis b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit.natvis new file mode 100644 index 0000000..b73d848 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit.natvis @@ -0,0 +1,201 @@ + + + + + + + + {_small.data, s8} + {_large.data, s8} + + + Small + Large + External + + (int)_small.type, d + _large.size, d + asmjit::String::kSSOCapacity, d + _large.capacity, d + _small.data, s8 + _large.data, s8 + + + + + {{ [size={_size, d} capacity={_capacity, d}] }} + + _size, d + _capacity, d + + _size + (($T1*)_data) + + + + + + + + + + + + + + + + + + + + + + + + + + [None] + [Reg] {{ id={_baseId, d} group={regGroup(), d} type={regType(), d} size={opSize(), d} }} + [Mem] {{ baseId={memBaseId(), d} indexId={memIndexId(), d} offset={(__int64)memOffset(), d} }} + [Imm] {{ val={immValue(), d} hex={immValue(), X} }} + [Label] {{ id={_baseId} }} + [Unknown] + + _signature, X + (asmjit::Operand_::OpType)opType() + opSize(), d + (asmjit::BaseReg::RegType)regType() + (asmjit::BaseReg::RegGroup)regGroup() + (asmjit::BaseReg::RegType)memBaseType() + (asmjit::BaseReg::RegType)memIndexType() + (asmjit::BaseMem::AddrType)memAddrType() + (bool)memRegHome() + _baseId + _data[0] + _data[1] + _data[0] + _data[1] + _data[0] + _data[1] + + + + + + + + + + + + + + + [RegValue {{ regType={regType()} indirect={isIndirect()} done={isDone()} }}] + [StackValue {{ indirect={isIndirect()} done={isDone()} }}] + [Unknown] + + + _data + (asmjit::Type::Id)(typeId()) + (asmjit::BaseReg::RegType)regType() + regId() + stackOffset() + + + + + + + + + + + + + + + + + + + + + + + + + [InstNode] + [SectionNode] + [LabelNode] + [AlignNode] + [EmbedDataNode] + [EmbedLabelNode] + [EmbedLabelDeltaNode] + [ConstPoolNode] + [CommentNode] + [SentinelNode] + [JumpNode] + [FuncNode] + [FuncRetNode] + [InvokeNode] + [UnknownNode {nodeType(), d}] + + + _prev + _next + + (asmjit::BaseNode::NodeType)_any._nodeType + (asmjit::BaseNode::Flags)_any._nodeFlags + + _position + _userDataU64 + _userDataPtr + _passData + _inlineComment, s8 + + ((asmjit::InstNode*)this)->_baseInst + _inst._opCount + _inst._opCapacity + ((asmjit::InstNode*)this)->_opArray, [_inst._opCount] + + ((asmjit::SectionNode*)this)->_id + ((asmjit::SectionNode*)this)->_nextSection + + ((asmjit::LabelNode*)this)->_id + + ((asmjit::AlignNode*)this)->_alignMode + ((asmjit::AlignNode*)this)->_alignment + + _embed._typeId, d + _embed._typeSize, d + ((asmjit::EmbedDataNode*)this)->_itemCount + ((asmjit::EmbedDataNode*)this)->_repeatCount + ((asmjit::EmbedDataNode*)this)->_inlineData + ((asmjit::EmbedDataNode*)this)->_externalData + + ((asmjit::EmbedLabelNode*)this)->_id + + ((asmjit::EmbedLabelDeltaNode*)this)->_id + ((asmjit::EmbedLabelDeltaNode*)this)->_baseId + ((asmjit::EmbedLabelDeltaNode*)this)->_dataSize + + ((asmjit::ConstPoolNode*)this)->_constPool + + (asmjit::SentinelNode::SentinelType)_sentinel._sentinelType + + ((asmjit::JumpNode*)this)->_annotation + + ((asmjit::FuncNode*)this)->_funcDetail + ((asmjit::FuncNode*)this)->_frame + ((asmjit::FuncNode*)this)->_exitNode + ((asmjit::FuncNode*)this)->_end + ((asmjit::FuncNode*)this)->_args, [((asmjit::FuncNode*)this)->_funcDetail._argCount] + + ((asmjit::InvokeNode*)this)->_funcDetail + ((asmjit::InvokeNode*)this)->_rets, [((asmjit::InvokeNode*)this)->_funcDetail._retCount] + ((asmjit::InvokeNode*)this)->_args, [((asmjit::InvokeNode*)this)->_funcDetail._argCount] + + + diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/asmjit-scope-begin.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/asmjit-scope-begin.h new file mode 100644 index 0000000..6ee5050 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/asmjit-scope-begin.h @@ -0,0 +1,35 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifdef _WIN32 + #pragma push_macro("min") + #pragma push_macro("max") + + #ifdef min + #undef min + #endif + + #ifdef max + #undef max + #endif +#endif diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/asmjit-scope-end.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/asmjit-scope-end.h new file mode 100644 index 0000000..447105a --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/asmjit-scope-end.h @@ -0,0 +1,27 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifdef _WIN32 + #pragma pop_macro("min") + #pragma pop_macro("max") +#endif diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/asmjit.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/asmjit.h new file mode 100644 index 0000000..400426c --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/asmjit.h @@ -0,0 +1,37 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_ASMJIT_H_INCLUDED +#define ASMJIT_ASMJIT_H_INCLUDED + +#include "./core.h" + +#ifdef ASMJIT_BUILD_X86 + #include "./x86.h" +#endif + +#ifdef ASMJIT_BUILD_ARM + #include "./arm.h" +#endif + +#endif // ASMJIT_ASMJIT_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core.h new file mode 100644 index 0000000..52540ab --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core.h @@ -0,0 +1,2063 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_H_INCLUDED +#define ASMJIT_CORE_H_INCLUDED + +//! Root namespace used by AsmJit. +namespace asmjit { + +// ============================================================================ +// [Documentation - mainpage] +// ============================================================================ + +//! \mainpage API Reference +//! +//! AsmJit C++ API reference documentation generated by Doxygen. +//! +//! AsmJit library uses one global namespace called \ref asmjit, which provides +//! the whole functionality. Core functionality is within \ref asmjit namespace +//! and architecture specific functionality is always in its own namespace. For +//! example \ref asmjit::x86 provides both 32-bit and 64-bit X86 code generation. +//! +//! \section main_groups Documentation Groups +//! +//! AsmJit documentation is structured into groups. Groups can be followed in +//! order to learn AsmJit, but knowledge from multiple groups is required to +//! use AsmJit properly: +//! +//! $$DOCS_GROUP_OVERVIEW$$ +//! +//! \note It's important to understand that in order to learn AsmJit all groups +//! are important. Some groups can be omitted if a particular tool is out of +//! interest - for example \ref asmjit_assembler users don't need to know about +//! \ref asmjit_builder, but it's not the opposite. \ref asmjit_builder users +//! must know about \ref asmjit_assembler as it also uses operands, labels, and +//! other concepts. Similarly \ref asmjit_compiler users must know how both \ref +//! asmjit_assembler and \ref asmjit_builder tools work. +//! +//! \section where_to_start Where To Start +//! +//! AsmJit \ref asmjit_core provides the following two classes that are essential +//! from the code generation perspective: +//! +//! - \ref CodeHolder provides functionality +//! to temporarily hold the generated code. It stores all the necessary +//! information about the code - code buffers, sections, labels, symbols, +//! and information about relocations. +//! +//! - \ref BaseEmitter provides interface used +//! by emitter implementations. The interface provides basic building blocks +//! that are then implemented by \ref BaseAssembler, \ref BaseBuilder, and +//! \ref BaseCompiler. +//! +//! Code emitters: +//! +//! - \ref asmjit_assembler - provides direct machine code generation. +//! +//! - \ref asmjit_builder - provides intermediate code generation that can +//! be processed before it's serialized to \ref BaseAssembler. +//! +//! - \ref asmjit_compiler - provides high-level code generation with built-in +//! register allocation. +//! +//! - \ref FuncNode - provides insight into how function looks from the Compiler +//! perspective and how it's stored in a node-list. +//! +//! \section main_recommendations Recommendations +//! +//! The following steps are recommended for all AsmJit users: +//! +//! - Make sure that you use \ref Logger, see \ref asmjit_logging. +//! +//! - Make sure that you use \ref ErrorHandler, see \ref asmjit_error_handling. +//! +//! - Instruction validation in your debug builds can reveal problems too. +//! AsmJit provides validation at instruction level, that can be enabled +//! by \ref BaseEmitter::addValidationOptions(). +//! +//! See \ref BaseEmitter::ValidationOptions for more details. +//! +//! - Make sure you put a breakpoint into \ref DebugUtils::errored() function +//! if you have a problem with AsmJit returning errors during instruction +//! encoding or register allocation. Having an active breakpoint there can +//! help to reveal the origin of the error, to inspect variables and other +//! conditions that caused to it. +//! +//! The reason for using \ref Logger and \ref ErrorHandler is that they provide +//! a very useful information about what's happening inside emitters. In many +//! cases the information provided by these two is crucial to quickly fix issues +//! that happen during development (for example wrong instruction, address, or +//! register used). In addition, output from \ref Logger is always necessary +//! when filling bug reports. In other words, using logging and proper error +//! handling can save a lot of time during the development. +//! +//! \section main_other Other Pages +//! +//! - Class List - List of classes sorted alphabetically +//! - AsmJit Namespace - List of symbols provided by `asmjit` namespace + +// ============================================================================ +// [Documentation - asmjit_build] +// ============================================================================ + +//! \defgroup asmjit_build Build Instructions +//! \brief Build instructions, supported environments, and feature selection. +//! +//! ### Overview +//! +//! AsmJit is designed to be easy embeddable in any project. However, it depends +//! on some compile-time definitions that can be used to enable or disable +//! features to decrease the resulting binary size. A typical way of building +//! AsmJit is to use [cmake](https://www.cmake.org), but it's also possible to +//! just include AsmJit source code in your project and to just build it. The +//! easiest way to include AsmJit in your project is to just include **src** +//! directory in your project and to define \ref ASMJIT_STATIC. AsmJit can be +//! just updated from time to time without any changes to this integration +//! process. Do not embed AsmJit's `test` files in such case as these are used +//! exclusively for testing. +//! +//! ### Supported C++ Compilers +//! +//! - Requirements: +//! +//! - AsmJit won't build without C++11 enabled. If you use older GCC or Clang +//! you would have to enable at least C++11 standard through compiler flags. +//! +//! - Tested: +//! +//! - **Clang** - Tested by Travis-CI - Clang 3.9+ (with C++11 enabled) is +//! officially supported (older Clang versions having C++11 support are +//! probably fine, but are not regularly tested). +//! +//! - **GNU** - Tested by Travis-CI - GCC 4.8+ (with C++11 enabled) is +//! officially supported. +//! +//! - **MINGW** - Tested by Travis-CI - Use the latest version, if possible. +//! +//! - **MSVC** - Tested by Travis-CI - VS2017+ is officially supported, VS2015 +//! is reported to work. +//! +//! - Untested: +//! +//! - **Intel** - No maintainers and no CI environment to regularly test +//! this compiler. +//! +//! - **Other** C++ compilers would require basic support in +//! [core/api-config.h](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/api-config.h). +//! +//! ### Supported Operating Systems and Platforms +//! +//! - Tested: +//! +//! - **Linux** - Tested by Travis-CI (any distribution is generally supported). +//! +//! - **OSX** - Tested by Travis-CI (any version is supported). +//! +//! - **Windows** - Tested by Travis-CI - (Windows 7+ is officially supported). +//! +//! - **Emscripten** - Works if compiled with \ref ASMJIT_NO_JIT. AsmJit +//! cannot generate WASM code, but can be used to generate X86/X64 code +//! within a browser, for example. +//! +//! - Untested: +//! +//! - **BSDs** - No maintainers, no CI environment to regularly test BSDs, +//! but they should work out of box. +//! +//! - **Haiku** - Not regularly tested, but reported to work. +//! +//! - **Other** operating systems would require some testing and support in +//! the following files: +//! - [core/api-config.h](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/api-config.h) +//! - [core/osutils.cpp](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/osutils.cpp) +//! - [core/virtmem.cpp](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/virtmem.cpp) +//! +//! ### Supported Backends / Architectures +//! +//! - **X86** - Both 32-bit and 64-bit backends tested by Travis-CI. +//! - **ARM** - Work-in-progress (not public at the moment). +//! +//! ### Static Builds and Embedding +//! +//! These definitions can be used to enable static library build. Embed is used +//! when AsmJit's source code is embedded directly in another project, implies +//! static build as well. +//! +//! - \ref ASMJIT_EMBED - Asmjit is embedded, implies \ref ASMJIT_STATIC. +//! - \ref ASMJIT_STATIC - Enable static-library build. +//! +//! \note Projects that use AsmJit statically must define \ref ASMJIT_STATIC in +//! all compilation units that use AsmJit, otherwise AsmJit would use dynamic +//! library imports in \ref ASMJIT_API decorator. The recommendation is to +//! define this macro across the whole project that uses AsmJit this way. +//! +//! ### Build Configuration +//! +//! These definitions control whether asserts are active or not. By default +//! AsmJit would autodetect build configuration from existing pre-processor +//! definitions, but this behavior can be overridden, for example to enable +//! debug asserts in release configuration. +//! +//! - \ref ASMJIT_BUILD_DEBUG - Overrides build configuration to debug, +//! asserts will be enabled in this case. +//! - \ref ASMJIT_BUILD_RELEASE - Overrides build configuration to release, +//! asserts will be disabled in this case. +//! +//! \note There is usually no need to override the build configuration. AsmJit +//! detects the build configuration by checking whether `NDEBUG` is defined and +//! automatically defines \ref ASMJIT_BUILD_RELEASE if configuration overrides +//! were not used. We only recommend using build configuration overrides in +//! special situations, like using AsmJit in release configuration with asserts +//! enabled for whatever reason. +//! +//! ### AsmJit Backends +//! +//! AsmJit currently supports only X86/X64 backend, but the plan is to add more +//! backends in the future. By default AsmJit builds only the host backend, which +//! is autodetected at compile-time, but this can be overridden. +//! +//! - \ref ASMJIT_BUILD_X86 - Always build X86 backend (X86 and X86_64). +//! - \ref ASMJIT_BUILD_ARM - Always build ARM backend (ARM and AArch64). +//! - \ref ASMJIT_BUILD_HOST - Always build the host backend. +//! +//! ### Features Selection +//! +//! AsmJit builds by defaults all supported features, which includes all emitters, +//! logging, instruction validation and introspection, and JIT memory allocation. +//! Features can be disabled at compile time by using `ASMJIT_NO_...` definitions. +//! +//! - \ref ASMJIT_NO_DEPRECATED - Disables deprecated API at compile time +//! so it won't be available and the compilation will fail if there is +//! attempt to use such API. This includes deprecated classes, namespaces, +//! enumerations, and functions. +//! +//! - \ref ASMJIT_NO_FOREIGN - Disables the support for foreign architectures. +//! If defined, it would internally set \ref ASMJIT_BUILD_HOST to true. +//! +//! - \ref ASMJIT_NO_BUILDER - Disables \ref asmjit_builder functionality +//! completely. This implies \ref ASMJIT_NO_COMPILER as \ref asmjit_compiler +//! cannot be used without \ref asmjit_builder. +//! +//! - \ref ASMJIT_NO_COMPILER - Disables \ref asmjit_compiler functionality +//! completely. +//! +//! - \ref ASMJIT_NO_JIT - Disables JIT memory management and \ref JitRuntime. +//! +//! - \ref ASMJIT_NO_LOGGING - Disables \ref Logger and \ref Formatter. +//! +//! - \ref ASMJIT_NO_TEXT - Disables everything that contains string +//! representation of AsmJit constants, should be used together with +//! \ref ASMJIT_NO_LOGGING as logging doesn't make sense without the +//! ability to quiry instruction names, register names, etc... +//! +//! - \ref ASMJIT_NO_VALIDATION - Disables validation API. +//! +//! - \ref ASMJIT_NO_INTROSPECTION - Disables instruction introspection API, +//! must be used together with \ref ASMJIT_NO_COMPILER as \ref asmjit_compiler +//! requires introspection for its liveness analysis and register allocation. +//! +//! \note It's not recommended to disable features if you plan to build AsmJit +//! as a shared library that will be used by multiple projects that you don't +//! control how AsmJit was built (for example AsmJit in a Linux distribution). +//! The possibility to disable certain features exists mainly for customized +//! AsmJit builds. + +// ============================================================================ +// [Documentation - asmjit_breaking_changes] +// ============================================================================ + +//! \defgroup asmjit_breaking_changes Breaking Changes +//! \brief Documentation of breaking changes +//! +//! ### Overview +//! +//! AsmJit is a live project that is being actively developed. Deprecating the +//! existing API in favor of a new one is preferred, but it's not always +//! possible if the changes are significant. AsmJit authors prefer to do +//! accumulated breaking changes at once instead of breaking the API often. +//! This page documents deprecated and removed APIs and should serve as a how-to +//! guide for people that want to port existing code to work with the newest AsmJit. +//! +//! ### Tips +//! +//! Useful tips before you start: +//! +//! - Visit our [Public Gitter Channel](https://gitter.im/asmjit/asmjit) if +//! you need a quick help. +//! +//! - Build AsmJit with `ASMJIT_NO_DEPRECATED` macro defined to make sure that +//! you are not using deprecated functionality at all. Deprecated functions +//! are decorated with `ASMJIT_DEPRECATED()` macro, but sometimes it's not +//! possible to decorate everything like classes, which are used by deprecated +//! functions as well, because some compilers would warn about that. If your +//! project compiles fine with `ASMJIT_NO_DEPRECATED` it's not using anything, +//! which was deprecated. +//! +//! ### Changes committed at 2020-05-30 +//! +//! AsmJit has been cleaned up significantly, many todo items have been fixed +//! and many functions and classes have been redesigned, some in an incompatible +//! way. +//! +//! Core changes: +//! +//! - \ref Imm operand has now only \ref Imm::value() and \ref Imm::valueAs() +//! functions that return its value content, and \ref Imm::setValue() function +//! that sets the content. Functions like `setI8()`, `setU8()` were deprecated. +//! +//! Old functions were deprecated, but code using them should still compile. +//! +//! - `ArchInfo` has been replaced with \ref Environment. Environment provides +//! more details about the architecture, but drops some properties that +//! were used by arch info - `gpSize(`) and `gpCount()`. `gpSize()` can +//! be replaced with `registerSize()` getter, which returns a native register +//! size of the architecture the environment uses. However, `gpCount()` was +//! removed - at the moment \ref ArchRegs can be used to access such properties. +//! +//! Some other functions were renamed, like `ArchInfo::isX86Family()` is +//! now \ref Environment::isFamilyX86(), etc. The reason for changing the +//! order was support for more propertries and all the accessors now +//! start with the type of the property, like \ref Environment::isPlatformWindows(). +//! +//! This function causes many other classes to provide `environment()` getter +//! instead of `archInfo()` getter. In addition, AsmJit now uses `arch()` to +//! get an architecture instead of `archId()`. `ArchInfo::kIdXXX` was renamed +//! to `Environment::kArchXXX`. +//! +//! Some functions were deprecated, some removed... +//! +//! - `CodeInfo` has been removed in favor of \ref Environment. If you used +//! `CodeInfo` to set architecture and base address, this is now possible +//! with \ref Environment and setting base address explicitly by \ref +//! CodeHolder::init() - the first argument is \ref Environment, and the +//! second argument is base address, which defaults to \ref +//! Globals::kNoBaseAddress. +//! +//! CodeInfo class was deprecated, but the code using it should still +//! compile with warnings. +//! +//! - \ref CallConv has been updated to offer a more unified way of representing +//! calling conventions - many calling conventions were abstracted to follow +//! standard naming like \ref CallConv::kIdCDecl or \ref CallConv::kIdStdCall. +//! +//! This change means that other APIs like \ref FuncDetail::init() now +//! require both, calling convention and target \ref Environment. +//! +//! - `Logging` namespace has been renamed to \ref Formatter, which now +//! provides general functionality for formatting in AsmJit. +//! +//! Logging namespace should still work, but its use is deprecated. +//! Unfortunately this will be without deprecation warnings, so please +//! make sure you don't use it. +//! +//! - `Data64`, `Data128`, and `Data256` structs were deprecated and should +//! no longer be used. There is no replacement, AsmJit users should simply +//! create their own structures if they need them or use the new repeated +//! embed API in emitters, see \ref BaseEmitter::embedDataArray(). +//! +//! Emitter changes: +//! +//! - \ref BaseEmitter::emit() function signature has been changed to accept +//! 3 operands by reference and the rest 3 operands as a continuous array. +//! This change is purely cosmetic and shouldn't affect users as emit() +//! has many overloads that dispatch to the right function. +//! +//! - \ref x86::Emitter (Assembler, Builder, Compiler) deprecates embed +//! utilities like `dint8()`, `duint8()`, `duint16()`, `dxmm()`, etc... +//! in favor of a new and more powerful \ref BaseEmitter::embedDataArray(). +//! This function also allows emitting repeated values and/or patterns, +//! which is used by helpers \ref BaseEmitter::embedUInt8(), and others... +//! +//! - Validation is now available through \ref BaseEmitter::ValidationOptions, +//! which can be enabled/disabled through \ref BaseEmitter::addValidationOptions() +//! and \ref BaseEmitter::clearValidationOptions(), respectively. Validation +//! options now separate between encoding and Builder/Compiler so it's possible +//! to choose the granularity required. +//! +//! Builder changes: +//! +//! - Internal functions for creating nodes were redesigned. They now accept +//! a pointer to the node created as a first parameter. These changes should +//! not affect AsmJit users as these functions were used internally. +//! +//! Compiler changes: +//! +//! - `FuncCallNode` has been renamed to \ref InvokeNode. Additionally, function +//! calls should now use \ref x86::Compiler::invoke() instead of `call()`. +//! The reason behind this is to remove the confusion between a `call` +//! instruction and AsmJit's `call()` intrinsic, which is now `invoke()`. +//! +//! - Creating new nodes also changed. Now the preferred way of invoking a +//! function is to call \ref x86::Compiler::invoke() where the first +//! argument is `InvokeNode**`. The function now returns an error and would +//! call \ref ErrorHandler in case of a failure. Error handling was +//! unspecified in the past - the function was marked noexcept, but called +//! error handler, which could throw. +//! +//! The reason behind this change is to make the API consistent with other +//! changes and to also make it possible to inspect the possible error. In +//! the previous API it returned a new node or `nullptr` in case of error, +//! which the user couldn't inspect unless there was an attached \ref +//! ErrorHandler. +//! +//! Samples: +//! +//! ``` +//! #include +//! using namespace asmjit; +//! +//! // The basic setup of JitRuntime and CodeHolder changed, use environment() +//! // instead of codeInfo(). +//! void basicSetup() { +//! JitRuntime rt; +//! CodeHolder code(rt.environment()); +//! } +//! +//! // Calling a function (Compiler) changed - use invoke() instead of call(). +//! void functionInvocation(x86::Compiler& cc) { +//! InvokeNode* invokeNode; +//! cc.invoke(&invokeNode, targetOperand, FuncSignatureT<...>(...)); +//! } +//! ``` + +// ============================================================================ +// [Documentation - asmjit_core] +// ============================================================================ + +//! \defgroup asmjit_core Core +//! \brief Globals, code storage, and emitter interface. +//! +//! ### Overview +//! +//! AsmJit library uses \ref CodeHolder to hold code during code generation and +//! emitters inheriting from \ref BaseEmitter to emit code. CodeHolder uses +//! containers to manage its data: +//! +//! - \ref Section - stores information about a code or data section. +//! - \ref CodeBuffer - stores actual code or data, part of \ref Section. +//! - \ref LabelEntry - stores information about a label - its name, offset, +//! section where it belongs to, and other bits. +//! - \ref LabelLink - stores information about yet unbound label, which was +//! already used by the assembler. +//! - \ref RelocEntry - stores information about a relocation. +//! - \ref AddressTableEntry - stores information about an address, which was +//! used in a jump or call. Such address may need relocation. +//! +//! To generate code you would need to instantiate at least the following classes: +//! +//! - \ref CodeHolder - to hold code during code generation. +//! - \ref BaseEmitter - to emit code into \ref CodeHolder. +//! - \ref Target (optional) - most likely \ref JitRuntime to keep the generated +//! code in executable memory. \ref Target can be customized by inheriting from +//! it. +//! +//! There are also other core classes that are important: +//! +//! - \ref Environment - describes where the code will run. Environment brings +//! the concept of target triples or tuples into AsmJit, which means that users +//! can specify target architecture, platform, and ABI. +//! - \ref Type - encapsulates lightweight type functionality that can be used +//! to describe primitive and vector types. Types are used by higher level +//! utilities, for example by \ref asmjit_function and \ref asmjit_compiler. +//! - \ref CpuInfo - encapsulates CPU information - stores both CPU information +//! and features described by \ref BaseFeatures. +//! +//! AsmJit also provides global constants: +//! +//! - \ref Globals - namespace that provides global constants. +//! - \ref ByteOrder - byte-order constants and functionality. +//! +//! \note CodeHolder examples use \ref x86::Assembler as abstract interfaces cannot +//! be used to generate code. +//! +//! ### CodeHolder & Emitters +//! +//! The example below shows how the mentioned classes interact to generate X86 code: +//! +//! ``` +//! #include +//! #include +//! +//! using namespace asmjit; +//! +//! // Signature of the generated function. +//! typedef int (*Func)(void); +//! +//! int main() { +//! JitRuntime rt; // Runtime specialized for JIT code execution. +//! +//! CodeHolder code; // Holds code and relocation information. +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! +//! x86::Assembler a(&code); // Create and attach x86::Assembler to code. +//! a.mov(x86::eax, 1); // Move one to eax register. +//! a.ret(); // Return from function. +//! // ===== x86::Assembler is no longer needed from here and can be destroyed ===== +//! +//! Func fn; // Holds address to the generated function. +//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime. +//! if (err) return 1; // Handle a possible error returned by AsmJit. +//! // ===== CodeHolder is no longer needed from here and can be destroyed ===== +//! +//! int result = fn(); // Execute the generated code. +//! printf("%d\n", result); // Print the resulting "1". +//! +//! // All classes use RAII, all resources will be released before `main()` returns, +//! // the generated function can be, however, released explicitly if you intend to +//! // reuse or keep the runtime alive, which you should in a production-ready code. +//! rt.release(fn); +//! +//! return 0; +//! } +//! ``` +//! +//! The example above used \ref x86::Assembler as an emitter. AsmJit provides the +//! following emitters that offer various levels of abstraction: +//! +//! - \ref asmjit_assembler - Low-level emitter that emits directly to \ref CodeBuffer. +//! - \ref asmjit_builder - Low-level emitter that emits to a \ref BaseNode list. +//! - \ref asmjit_compiler - High-level emitter that provides register allocation. +//! +//! ### Targets and JitRuntime +//! +//! AsmJit's \ref Target is an interface that provides basic target abstraction. +//! At the moment AsmJit provides only one implementation called \ref JitRuntime, +//! which as the name suggests provides JIT code target and execution runtime. +//! \ref JitRuntime provides all the necessary stuff to implement a simple JIT +//! compiler with basic memory management. It only provides \ref JitRuntime::add() +//! and \ref JitRuntime::release() functions that are used to either add code +//! to the runtime or release it. \ref JitRuntime doesn't do any decisions on +//! when the code should be released, the decision is up to the developer. +//! +//! See more at \ref asmjit_virtual_memory group. +//! +//! ### More About Environment +//! +//! In the previous example the \ref Environment is retrieved from \ref JitRuntime. +//! It's logical as \ref JitRuntime always returns an \ref Environment that is +//! compatible with the host. For example if your application runs in 64-bit mode +//! the \ref Environment returned will use \ref Environment::kArchX64 architecture +//! in contrast to \ref Environment::kArchX86, which will be used in 32-bit mode on +//! any X86 platform. +//! +//! AsmJit allows to setup the \ref Environment manually and to select a different +//! architecture and ABI when necessary. So let's do something else this time, let's +//! always generate a 32-bit code and print its binary representation. To do that, we +//! can create our own \ref Environment and initialize it to \ref Environment::kArchX86. +//! +//! ``` +//! #include +//! #include +//! +//! using namespace asmjit; +//! +//! int main(int argc, char* argv[]) { +//! using namespace asmjit::x86; +//! +//! // Create a custom environment initialized to 32-bit X86 architecture. +//! Environment env; +//! env.setArch(Environment::kArchX86); +//! +//! CodeHolder code; // Create a CodeHolder. +//! code.init(env); // Initialize CodeHolder with custom environment. +//! +//! // Generate a 32-bit function that sums 4 floats and looks like: +//! // void func(float* dst, const float* a, const float* b) +//! x86::Assembler a(&code); // Create and attach x86::Assembler to `code`. +//! +//! a.mov(eax, dword_ptr(esp, 4)); // Load the destination pointer. +//! a.mov(ecx, dword_ptr(esp, 8)); // Load the first source pointer. +//! a.mov(edx, dword_ptr(esp, 12)); // Load the second source pointer. +//! +//! a.movups(xmm0, ptr(ecx)); // Load 4 floats from [ecx] to XMM0. +//! a.movups(xmm1, ptr(edx)); // Load 4 floats from [edx] to XMM1. +//! a.addps(xmm0, xmm1); // Add 4 floats in XMM1 to XMM0. +//! a.movups(ptr(eax), xmm0); // Store the result to [eax]. +//! a.ret(); // Return from function. +//! +//! // We have no Runtime this time, it's on us what we do with the code. +//! // CodeHolder stores code in Section, which provides some basic properties +//! // and CodeBuffer structure. We are interested in section's CodeBuffer. +//! // +//! // NOTE: The first section is always '.text', it can be retrieved by +//! // code.sectionById(0) or simply by code.textSection(). +//! CodeBuffer& buffer = code.textSection()->buffer(); +//! +//! // Print the machine-code generated or do something else with it... +//! // 8B4424048B4C24048B5424040F28010F58010F2900C3 +//! for (size_t i = 0; i < buffer.length; i++) +//! printf("%02X", buffer.data[i]); +//! +//! return 0; +//! } +//! ``` +//! +//! ### Explicit Code Relocation +//! +//! In addition to \ref Environment, \ref CodeHolder can be configured to +//! specify a base-address (or a virtual base-address in a linker terminology), +//! which could be static (useful when you know the location where the target's +//! machine code will be) or dynamic. AsmJit assumes dynamic base-address by +//! default and relocates the code held by \ref CodeHolder to a user provided +//! address on-demand. To be able to relocate to a user provided address it needs +//! to store some information about relocations, which is represented by \ref +//! RelocEntry. Relocation entries are only required if you call external functions +//! from the generated code that cannot be encoded by using a 32-bit displacement +//! (64-bit displacements are not provided by aby supported architecture). +//! +//! There is also a concept called \ref LabelLink - label link is a lightweight +//! data structure that doesn't have any identifier and is stored in \ref LabelEntry +//! as a single-linked list. Label link represents either unbound yet used label +//! and cross-sections links (only relevant to code that uses multiple sections). +//! Since crossing sections is something that cannot be resolved immediately these +//! links persist until offsets of these sections are assigned and until +//! \ref CodeHolder::resolveUnresolvedLinks() is called. It's an error if you end +//! up with code that has unresolved label links after flattening. You can verify +//! it by calling \ref CodeHolder::hasUnresolvedLinks(), which inspects the value +//! returned by \ref CodeHolder::unresolvedLinkCount(). +//! +//! AsmJit can flatten code that uses multiple sections by assigning each section +//! an incrementing offset that respects its alignment. Use \ref CodeHolder::flatten() +//! to do that. After the sections are flattened their offsets and virtual-sizes +//! are adjusted to respect each section's buffer size and alignment. The \ref +//! CodeHolder::resolveUnresolvedLinks() function must be called before relocating +//! the code held by \ref CodeHolder. You can also flatten your code manually by +//! iterating over all sections and calculating their offsets (relative to base) +//! by your own algorithm. In that case \ref CodeHolder::flatten() should not be +//! called, however, \ref CodeHolder::resolveUnresolvedLinks() should be. +//! +//! The example below shows how to use a built-in virtual memory allocator +//! \ref JitAllocator instead of using \ref JitRuntime (just in case you want +//! to use your own memory management) and how to relocate the generated code +//! into your own memory block - you can use your own virtual memory allocator +//! if you prefer that, but that's OS specific and not covered by the documentation. +//! +//! The following code is similar to the previous one, but implements a function +//! working in both 32-bit and 64-bit environments: +//! +//! ``` +//! #include +//! #include +//! +//! using namespace asmjit; +//! +//! typedef void (*SumIntsFunc)(int* dst, const int* a, const int* b); +//! +//! int main() { +//! // Create a custom environment that matches the current host environment. +//! Environment env = hostEnvironment(); +//! +//! CodeHolder code; // Create a CodeHolder. +//! code.init(env); // Initialize CodeHolder with environment. +//! +//! x86::Assembler a(&code); // Create and attach x86::Assembler to `code`. +//! +//! // Signature: 'void func(int* dst, const int* a, const int* b)'. +//! x86::Gp dst; +//! x86::Gp src_a; +//! x86::Gp src_b; +//! +//! // Handle the difference between 32-bit and 64-bit calling conventions +//! // (arguments passed through stack vs. arguments passed by registers). +//! if (env.is32Bit()) { +//! dst = x86::eax; +//! src_a = x86::ecx; +//! src_b = x86::edx; +//! a.mov(dst , x86::dword_ptr(x86::esp, 4)); +//! a.mov(src_a, x86::dword_ptr(x86::esp, 8)); +//! a.mov(src_b, x86::dword_ptr(x86::esp, 12)); +//! } +//! else { +//! if (env.isPlatformWindows()) { +//! dst = x86::rcx; // First argument (destination pointer). +//! src_a = x86::rdx; // Second argument (source 'a' pointer). +//! src_b = x86::r8; // Third argument (source 'b' pointer). +//! } +//! else { +//! dst = x86::rdi; // First argument (destination pointer). +//! src_a = x86::rsi; // Second argument (source 'a' pointer). +//! src_b = x86::rdx; // Third argument (source 'b' pointer). +//! } +//! } +//! +//! a.movdqu(x86::xmm0, x86::ptr(src_a)); // Load 4 ints from [src_a] to XMM0. +//! a.movdqu(x86::xmm1, x86::ptr(src_b)); // Load 4 ints from [src_b] to XMM1. +//! a.paddd(x86::xmm0, x86::xmm1); // Add 4 ints in XMM1 to XMM0. +//! a.movdqu(x86::ptr(dst), x86::xmm0); // Store the result to [dst]. +//! a.ret(); // Return from function. +//! +//! // Even when we didn't use multiple sections AsmJit could insert one section +//! // called '.addrtab' (address table section), which would be filled by data +//! // required by relocations (absolute jumps and calls). You can omit this code +//! // if you are 100% sure your code doesn't contain multiple sections and +//! // such relocations. You can use `CodeHolder::hasAddressTable()` to verify +//! // whether the address table section does exist. +//! code.flatten(); +//! code.resolveUnresolvedLinks(); +//! +//! // After the code was generated it can be relocated manually to any memory +//! // location, however, we need to know it's size before we perform memory +//! // allocation. `CodeHolder::codeSize()` returns the worst estimated code +//! // size in case that relocations are not possible without trampolines (in +//! // that case some extra code at the end of the current code buffer is +//! // generated during relocation). +//! size_t estimatedSize = code.codeSize(); +//! +//! // Instead of rolling up our own memory allocator we can use the one AsmJit +//! // provides. It's decoupled so you don't need to use `JitRuntime` for that. +//! JitAllocator allocator; +//! +//! // Allocate an executable virtual memory and handle a possible failure. +//! void* p = allocator.alloc(estimatedSize); +//! if (!p) +//! return 0; +//! +//! // Now relocate the code to the address provided by the memory allocator. +//! // Please note that this DOESN'T COPY anything to `p`. This function will +//! // store the address in CodeHolder and use relocation entries to patch the +//! // existing code in all sections to respect the base address provided. +//! code.relocateToBase((uint64_t)p); +//! +//! // This is purely optional. There are cases in which the relocation can omit +//! // unneeded data, which would shrink the size of address table. If that +//! // happened the codeSize returned after relocateToBase() would be smaller +//! // than the originally `estimatedSize`. +//! size_t codeSize = code.codeSize(); +//! +//! // This will copy code from all sections to `p`. Iterating over all sections +//! // and calling `memcpy()` would work as well, however, this function supports +//! // additional options that can be used to also zero pad sections' virtual +//! // size, etc. +//! // +//! // With some additional features, copyFlattenData() does roughly this: +//! // for (Section* section : code.sections()) +//! // memcpy((uint8_t*)p + section->offset(), +//! // section->data(), +//! // section->bufferSize()); +//! code.copyFlattenedData(p, codeSize, CodeHolder::kCopyPadSectionBuffer); +//! +//! // Execute the generated function. +//! int inA[4] = { 4, 3, 2, 1 }; +//! int inB[4] = { 1, 5, 2, 8 }; +//! int out[4]; +//! +//! // This code uses AsmJit's ptr_as_func<> to cast between void* and SumIntsFunc. +//! ptr_as_func(p)(out, inA, inB); +//! +//! // Prints {5 8 4 9} +//! printf("{%d %d %d %d}\n", out[0], out[1], out[2], out[3]); +//! +//! // Release 'p' is it's no longer needed. It will be destroyed with 'vm' +//! // instance anyway, but it's a good practice to release it explicitly +//! // when you know that the function will not be needed anymore. +//! allocator.release(p); +//! +//! return 0; +//! } +//! ``` +//! +//! If you know the base-address in advance (before the code generation) it can +//! be passed as a second argument to \ref CodeHolder::init(). In that case the +//! Assembler will know the absolute position of each instruction and would be +//! able to use it during instruction encoding to prevent relocations where +//! possible. The following example shows how to configure the base address: +//! +//! ``` +//! #include +//! #include +//! +//! void initializeCodeHolder(CodeHolder& code) { +//! Environment env = hostEnvironment(); +//! uint64_t baseAddress = uint64_t(0x1234); +//! +//! // initialize CodeHolder with environment and custom base address. +//! code.init(env, baseAddress); +//! } +//! ``` +//! +//! ### Label Offsets and Links +//! +//! When a label that is not yet bound is used by the Assembler, it creates a +//! \ref LabelLink, which is then added to a \ref LabelEntry. These links are +//! also created if a label is used in a different section than in which it +//! was bound. Let's examine some functions that can be used to check whether +//! there are any unresolved links. +//! +//! ``` +//! #include +//! #include +//! +//! void labelLinksExample(CodeHolder& code, const Label& label) { +//! // Tests whether the `label` is bound. +//! bool isBound = code.isLabelBound(label); +//! printf("Label %u is %s\n", label.id(), isBound ? "bound" : "not bound"); +//! +//! // Returns true if the code contains either referenced, but unbound +//! // labels, or cross-section label links that are not resolved yet. +//! bool hasUnresolved = code.hasUnresolvedLinks(); // Boolean answer. +//! size_t nUnresolved = code.unresolvedLinkCount(); // Count of unresolved links. +//! +//! printf("Number of unresolved links: %zu\n", nUnresolved); +//! } +//! ``` +//! +//! There is no function that would return the number of unbound labels as this +//! is completely unimportant from CodeHolder's perspective. If a label is not +//! used then it doesn't matter whether it's bound or not, only actually used +//! labels matter. After a Label is bound it's possible to query its offset +//! offset relative to the start of the section where it was bound: +//! +//! ``` +//! #include +//! #include +//! +//! void labelOffsetExample(CodeHolder& code, const Label& label) { +//! // Label offset is known after it's bound. The offset provided is relative +//! // to the start of the section, see below for alternative. If the given +//! // label is not bound the offset returned will be zero. It's recommended +//! // to always check whether the label is bound before using its offset. +//! uint64_t sectionOffset = code.labelOffset(label); +//! printf("Label offset relative to section: %llu\n", (unsigned long long)sectionOffset); +//! +//! // If you use multiple sections and want the offset relative to the base. +//! // NOTE: This function expects that the section has already an offset and +//! // the label-link was resolved (if this is not true you will still get an +//! // offset relative to the start of the section). +//! uint64_t baseOffset = code.labelOffsetFromBase(label); +//! printf("Label offset relative to base: %llu\n", (unsigned long long)baseOffset); +//! } +//! ``` +//! +//! ### Sections +//! +//! AsmJit allows to create multiple sections within the same \ref CodeHolder. +//! A test-case [asmjit_test_x86_sections.cpp](https://github.com/asmjit/asmjit/blob/master/test/asmjit_test_x86_sections.cpp) +//! can be used as a reference point although the following example should +//! also provide a useful insight: +//! +//! ``` +//! #include +//! #include +//! +//! void sectionsExample(CodeHolder& code) { +//! // Text section is always provided as the first section. +//! Section* text = code.textSection(); // or code.sectionById(0); +//! +//! // To create another section use CodeHolder::newSection(). +//! Section* data; +//! Error err = code.newSection(&data, +//! ".data", // Section name +//! SIZE_MAX, // Name length if the name is not null terminated (or SIZE_MAX). +//! 0, // Section flags, see Section::Flags. +//! 8, // Section alignment, must be power of 2. +//! 0); // Section order value (optional, default 0). +//! +//! // When you switch sections in Assembler, Builder, or Compiler the cursor +//! // will always move to the end of that section. When you create an Assembler +//! // the cursor would be placed at the end of the first (.text) section, which +//! // is initially empty. +//! x86::Assembler a(&code); +//! Label L_Data = a.newLabel(); +//! +//! a.mov(x86::eax, x86::ebx); // Emits in .text section. +//! +//! a.section(data); // Switches to the end of .data section. +//! a.bind(L_Data); // Binds label in this .data section +//! a.db(0x01); // Emits byte in .data section. +//! +//! a.section(text); // Switches to the end of .text section. +//! a.add(x86::ebx, x86::eax); // Emits in .text section. +//! +//! // References a label in .text section, which was bound in .data section. +//! // This would create a LabelLink even when the L_Data is already bound, +//! // because the reference crosses sections. See below... +//! a.lea(x86::rsi, x86::ptr(L_Data)); +//! } +//! ``` +//! +//! The last line in the example above shows that a LabelLink would be created +//! even for bound labels that cross sections. In this case a referenced label +//! was bound in another section, which means that the link couldn't be resolved +//! at that moment. If your code uses sections, but you wish AsmJit to flatten +//! these sections (you don't plan to flatten them manually) then there is an +//! API for that. +//! +//! ``` +//! #include +//! #include +//! +//! // ... (continuing the previous example) ... +//! void sectionsExampleContinued(CodeHolder& code) { +//! // Suppose we have some code that contains multiple sections and +//! // we would like to flatten it by using AsmJit's built-in API: +//! Error err = code.flatten(); +//! if (err) { +//! // There are many reasons it can fail, so always handle a possible error. +//! printf("Failed to flatten the code: %s\n", DebugUtils::errorAsString(err)); +//! exit(1); +//! } +//! +//! // After flattening all sections would contain assigned offsets +//! // relative to base. Offsets are 64-bit unsigned integers so we +//! // cast them to `size_t` for simplicity. On 32-bit targets it's +//! // guaranteed that the offset cannot be greater than `2^32 - 1`. +//! printf("Data section offset %zu", size_t(data->offset())); +//! +//! // The flattening doesn't resolve unresolved label links, this +//! // has to be done manually as flattening can be done separately. +//! err = code.resolveUnresolvedLinks(); +//! if (err) { +//! // This is the kind of error that should always be handled... +//! printf("Failed to resolve label links: %s\n", DebugUtils::errorAsString(err)); +//! exit(1); +//! } +//! +//! if (code.hasUnresolvedLinks()) { +//! // This would mean either unbound label or some other issue. +//! printf("The code has %zu unbound labels\n", code.unresovedLinkCount()); +//! exit(1); +//! } +//! } +//! ``` + +// ============================================================================ +// [Documentation - asmjit_assembler] +// ============================================================================ + +//! \defgroup asmjit_assembler Assembler +//! \brief Assembler interface and operands. +//! +//! ### Overview +//! +//! AsmJit's Assembler is used to emit machine code directly into a \ref +//! CodeBuffer. In general, code generation with assembler requires the knowledge +//! of the following: +//! +//! - \ref BaseAssembler and architecture-specific assemblers: +//! - \ref x86::Assembler - Assembler specific to X86 architecture +//! - \ref Operand and its variations: +//! - \ref BaseReg - Base class for a register operand, inherited by: +//! - \ref x86::Reg - Register operand specific to X86 architecture. +//! - \ref BaseMem - Base class for a memory operand, inherited by: +//! - \ref x86::Mem - Memory operand specific to X86 architecture. +//! - \ref Imm - Immediate (value) operand. +//! - \ref Label - Label operand. +//! +//! \note Assembler examples use \ref x86::Assembler as abstract interfaces cannot +//! be used to generate code. +//! +//! ### Operand Basics +//! +//! Let's start with operands. \ref Operand is a data structure that defines a +//! data layout of any operand. It can be inherited, but any class inheriting +//! it cannot add any members to it, only the existing layout can be reused. +//! AsmJit allows to construct operands dynamically, to store them, and to query +//! a complete information about them at run-time. Operands are small (always 16 +//! bytes per \ref Operand) and can be copied and passed by value. Please never +//! allocate individual operands dynamically by using a `new` keyword - it would +//! work, but then you would have to be responsible for deleting such operands. +//! In AsmJit operands are always part of some other data structures like \ref +//! InstNode, which is part of \ref asmjit_builder tool. +//! +//! Operands contain only identifiers, but not pointers to any code-generation data. +//! For example \ref Label operand only provides label identifier, but not a pointer +//! to \ref LabelEntry structure. In AsmJit such IDs are used to link stuff together +//! without having to deal with pointers. +//! +//! AsmJit's operands all inherit from a base class called \ref Operand. Operands +//! have the following properties that are commonly accessible by getters and setters: +//! +//! - \ref Operand - Base operand, which only provides accessors that are common +//! to all operand types. +//! - \ref BaseReg - Describes either physical or virtual register. Physical +//! registers have id that matches the target's machine id directly whereas +//! virtual registers must be allocated into physical registers by a register +//! allocator pass. Register operand provides: +//! - Register Type - Unique id that describes each possible register provided +//! by the target architecture - for example X86 backend provides \ref +//! x86::Reg::RegType, which defines all variations of general purpose registers +//! (GPB-LO, GPB-HI, GPW, GPD, and GPQ) and all types of other registers like K, +//! MM, BND, XMM, YMM, and ZMM. +//! - Register Group - Groups multiple register types under a single group - for +//! example all general-purpose registers (of all sizes) on X86 are part of +//! \ref x86::Reg::kGroupGp and all SIMD registers (XMM, YMM, ZMM) are part +//! of \ref x86::Reg::kGroupVec. +//! - Register Size - Contains the size of the register in bytes. If the size +//! depends on the mode (32-bit vs 64-bit) then generally the higher size is +//! used (for example RIP register has size 8 by default). +//! - Register Id - Contains physical or virtual id of the register. +//! - \ref BaseMem - Used to reference a memory location. Memory operand provides: +//! - Base Register - A base register type and id (physical or virtual). +//! - Index Register - An index register type and id (physical or virtual). +//! - Offset - Displacement or absolute address to be referenced (32-bit if base +//! register is used and 64-bit if base register is not used). +//! - Flags that can describe various architecture dependent information (like +//! scale and segment-override on X86). +//! - \ref Imm - Immediate values are usually part of instructions (encoded within +//! the instruction itself) or data. +//! - \ref Label - used to reference a location in code or data. Labels must be +//! created by the \ref BaseEmitter or by \ref CodeHolder. Each label has its +//! unique id per \ref CodeHolder instance. +//! +//! ### Operand Manipulation +//! +//! AsmJit allows to construct operands dynamically, to store them, and to query +//! a complete information about them at run-time. Operands are small (always 16 +//! bytes per `Operand`) and should be always copied (by value) if you intend to +//! store them (don't create operands by using `new` keyword, it's not recommended). +//! Operands are safe to be passed to `memcpy()` and `memset()`, which becomes +//! handy when working with arrays of operands. If you set all members of an \ref +//! Operand to zero the operand would become NONE operand, which is the same as a +//! default constructed Operand. +//! +//! The example below illustrates how operands can be used and modified even +//! without using any other code generation classes. The example uses X86 +//! architecture-specific operands. +//! +//! ``` +//! #include +//! +//! using namespace asmjit; +//! +//! // Registers can be copied, it's a common practice. +//! x86::Gp dstRegByValue() { return x86::ecx; } +//! +//! void usingOperandsExample(x86::Assembler& a) { +//! // Gets `ecx` register returned by a function. +//! x86::Gp dst = dstRegByValue(); +//! // Gets `rax` register directly from the provided `x86` namespace. +//! x86::Gp src = x86::rax; +//! // Constructs `r10` dynamically. +//! x86::Gp idx = x86::gpq(10); +//! // Constructs [src + idx] memory address - referencing [rax + r10]. +//! x86::Mem m = x86::ptr(src, idx); +//! +//! // Examine `m`: Returns `x86::Reg::kTypeGpq`. +//! m.indexType(); +//! // Examine `m`: Returns 10 (`r10`). +//! m.indexId(); +//! +//! // Reconstruct `idx` stored in mem: +//! x86::Gp idx_2 = x86::Gp::fromTypeAndId(m.indexType(), m.indexId()); +//! +//! // True, `idx` and idx_2` are identical. +//! idx == idx_2; +//! +//! // Possible - op will still be the same as `m`. +//! Operand op = m; +//! // True (can be casted to BaseMem or architecture-specific Mem). +//! op.isMem(); +//! +//! // True, `op` is just a copy of `m`. +//! m == op; +//! +//! // Static cast is fine and valid here. +//! static_cast(op).addOffset(1); +//! // However, using `as()` to cast to a derived type is preferred. +//! op.as().addOffset(1); +//! // False, `op` now points to [rax + r10 + 2], which is not [rax + r10]. +//! m == op; +//! +//! // Emitting 'mov' - type safe way. +//! a.mov(dst, m); +//! // Not possible, `mov` doesn't provide mov(x86::Gp, Operand) overload. +//! a.mov(dst, op); +//! +//! // Type-unsafe, but possible. +//! a.emit(x86::Inst::kIdMov, dst, m); +//! // Also possible, `emit()` is typeless and can be used with raw Operand. +//! a.emit(x86::Inst::kIdMov, dst, op); +//! } +//! ``` +//! +//! Some operands have to be created explicitly by emitters. For example labels +//! must be created by \ref BaseEmitter::newLabel(), which creates a label entry +//! and returns a \ref Label operand with the id that refers to it. Such label +//! then can be used by emitters. +//! +//! ### Memory Operands +//! +//! Some architectures like X86 provide a complex memory addressing model that +//! allows to encode addresses having a BASE register, INDEX register with a +//! possible scale (left shift), and displacement (called offset in AsmJit). +//! Memory address on X86 can also specify memory segment (segment-override in +//! X86 terminology) and some instructions (gather / scatter) require INDEX to +//! be a \ref x86::Vec register instead of a general-purpose register. +//! +//! AsmJit allows to encode and work with all forms of addresses mentioned and +//! implemented by X86. In addition, it also allows to construct absolute 64-bit +//! memory address operands, which is only allowed in one form of 'mov' instruction. +//! +//! ``` +//! #include +//! +//! using namespace asmjit; +//! +//! void testX86Mem() { +//! // Makes it easier to access x86 stuff... +//! using namespace asmjit::x86; +//! +//! // BASE + OFFSET. +//! Mem a = ptr(rax); // a = [rax] +//! Mem b = ptr(rax, 15); // b = [rax + 15] +//! +//! // BASE + INDEX << SHIFT - Shift is in BITS as used by X86! +//! Mem c = ptr(rax, rbx); // c = [rax + rbx] +//! Mem d = ptr(rax, rbx, 2); // d = [rax + rbx << 2] +//! Mem e = ptr(rax, rbx, 2, 15); // e = [rax + rbx << 2 + 15] +//! +//! // BASE + VM (Vector Index) (encoded as MOD+VSIB). +//! Mem f = ptr(rax, xmm1); // f = [rax + xmm1] +//! Mem g = ptr(rax, xmm1, 2); // g = [rax + xmm1 << 2] +//! Mem h = ptr(rax, xmm1, 2, 15); // h = [rax + xmm1 << 2 + 15] +//! +//! // Absolute adddress: +//! uint64_t addr = (uint64_t)0x1234; +//! Mem i = ptr(addr); // i = [0x1234] +//! Mem j = ptr(addr, rbx); // j = [0x1234 + rbx] +//! Mem k = ptr(addr, rbx, 2); // k = [0x1234 + rbx << 2] +//! +//! // LABEL - Will be encoded as RIP (64-bit) or absolute address (32-bit). +//! Label L = ...; +//! Mem m = ptr(L); // m = [L] +//! Mem n = ptr(L, rbx); // n = [L + rbx] +//! Mem o = ptr(L, rbx, 2); // o = [L + rbx << 2] +//! Mem p = ptr(L, rbx, 2, 15); // p = [L + rbx << 2 + 15] +//! +//! // RIP - 64-bit only (RIP can't use INDEX). +//! Mem q = ptr(rip, 24); // q = [rip + 24] +//! } +//! ``` +//! +//! Memory operands can optionally contain memory size. This is required by +//! instructions where the memory size cannot be deduced from other operands, +//! like `inc` and `dec` on X86: +//! +//! ``` +//! #include +//! +//! using namespace asmjit; +//! +//! void testX86Mem() { +//! // The same as: dword ptr [rax + rbx]. +//! x86::Mem a = x86::dword_ptr(rax, rbx); +//! +//! // The same as: qword ptr [rdx + rsi << 0 + 1]. +//! x86::Mem b = x86::qword_ptr(rdx, rsi, 0, 1); +//! } +//! ``` +//! +//! Memory operands provide API that can be used to access its properties: +//! +//! ``` +//! #include +//! +//! using namespace asmjit; +//! +//! void testX86Mem() { +//! // The same as: dword ptr [rax + 12]. +//! x86::Mem mem = x86::dword_ptr(rax, 12); +//! +//! mem.hasBase(); // true. +//! mem.hasIndex(); // false. +//! mem.size(); // 4. +//! mem.offset(); // 12. +//! +//! mem.setSize(0); // Sets the size to 0 (makes it sizeless). +//! mem.addOffset(-1); // Adds -1 to the offset and makes it 11. +//! mem.setOffset(0); // Sets the offset to 0. +//! mem.setBase(rcx); // Changes BASE to RCX. +//! mem.setIndex(rax); // Changes INDEX to RAX. +//! mem.hasIndex(); // true. +//! } +//! // ... +//! ``` +//! +//! Making changes to memory operand is very comfortable when emitting loads +//! and stores: +//! +//! ``` +//! #include +//! +//! using namespace asmjit; +//! +//! void testX86Mem(CodeHolder& code) { +//! x86::Assembler a(code); // Your initialized x86::Assembler. +//! x86::Mem mSrc = x86::ptr(eax); // Construct [eax] memory operand. +//! +//! // One way of emitting bunch of loads is to use `mem.adjusted()`, which +//! // returns a new memory operand and keeps the source operand unchanged. +//! a.movaps(x86::xmm0, mSrc); // No adjustment needed to load [eax]. +//! a.movaps(x86::xmm1, mSrc.adjusted(16)); // Loads from [eax + 16]. +//! a.movaps(x86::xmm2, mSrc.adjusted(32)); // Loads from [eax + 32]. +//! a.movaps(x86::xmm3, mSrc.adjusted(48)); // Loads from [eax + 48]. +//! +//! // ... do something with xmm0-3 ... +//! +//! // Another way of adjusting memory is to change the operand in-place. +//! // If you want to keep the original operand you can simply clone it. +//! x86::Mem mDst = mSrc.clone(); // Clone mSrc. +//! +//! a.movaps(mDst, x86::xmm0); // Stores xmm0 to [eax]. +//! mDst.addOffset(16); // Adds 16 to `mDst`. +//! +//! a.movaps(mDst, x86::xmm1); // Stores to [eax + 16] . +//! mDst.addOffset(16); // Adds 16 to `mDst`. +//! +//! a.movaps(mDst, x86::xmm2); // Stores to [eax + 32]. +//! mDst.addOffset(16); // Adds 16 to `mDst`. +//! +//! a.movaps(mDst, x86::xmm3); // Stores to [eax + 48]. +//! } +//! ``` +//! +//! ### Assembler Examples +//! +//! - \ref x86::Assembler provides many X86/X64 examples. + +// ============================================================================ +// [Documentation - asmjit_builder] +// ============================================================================ + +//! \defgroup asmjit_builder Builder +//! \brief Builder interface, nodes, and passes. +//! +//! ### Overview +//! +//! Both \ref BaseBuilder and \ref BaseCompiler interfaces describe emitters +//! that emit into a representation that allows further processing. The code +//! stored in such representation is completely safe to be patched, simplified, +//! reordered, obfuscated, removed, injected, analyzed, or processed some other +//! way. Each instruction, label, directive, or other building block is stored +//! as \ref BaseNode (or derived class like \ref InstNode or \ref LabelNode) +//! and contains all the information necessary to pass that node later to the +//! assembler. +//! +//! \ref BaseBuilder is an emitter that inherits from \ref BaseEmitter interface. +//! It was designed to provide a maximum compatibility with the existing \ref +//! BaseAssembler emitter so users can move from assembler to builder when needed, +//! for example to implement post-processing, which is not possible with Assembler. +//! +//! ### Builder Nodes +//! +//! \ref BaseBuilder doesn't generate machine code directly, it uses an intermediate +//! representation based on nodes, however, it allows to serialize to \ref BaseAssembler +//! when the code is ready to be encoded. +//! +//! There are multiple node types used by both \ref BaseBuilder and \ref BaseCompiler : +//! +//! - Basic nodes: +//! - \ref BaseNode - Base class for all nodes. +//! - \ref InstNode - Represents an instruction node. +//! - \ref AlignNode - Represents an alignment directive (.align). +//! - \ref LabelNode - Represents a location where to bound a \ref Label. +//! +//! - Data nodes: +//! - \ref EmbedDataNode - Represents data. +//! - \ref EmbedLabelNode - Represents \ref Label address embedded as data. +//! - \ref EmbedLabelDeltaNode - Represents a difference of two labels +//! embedded in data. +//! - \ref ConstPoolNode - Represents a constant pool data embedded as data. +//! +//! - Informative nodes: +//! - \ref CommentNode - Represents a comment string, doesn't affect code +//! generation. +//! - \ref SentinelNode - A marker that can be used to remember certain +//! position in code or data, doesn't affect code generation. Used by +//! \ref FuncNode to mark the end of a function. +//! +//! - Other nodes are provided by \ref asmjit_compiler infrastructure. +//! +//! ### Builder Examples +//! +//! - \ref x86::Builder provides many X86/X64 examples. + +// ============================================================================ +// [Documentation - asmjit_compiler] +// ============================================================================ + +//! \defgroup asmjit_compiler Compiler +//! \brief Compiler interface. +//! +//! ### Overview +//! +//! \ref BaseCompiler is a high-level interface built on top of \ref BaseBuilder +//! interface, which provides register allocation and support for defining and +//! invoking functions. At the moment it's the easiest way of generating code +//! in AsmJit as most architecture and OS specifics is properly abstracted and +//! handled by AsmJit automatically. However, abstractions also mean restrictions, +//! which means that \ref BaseCompiler has more limitations than \ref BaseAssembler +//! or \ref BaseBuilder. +//! +//! Since \ref BaseCompiler provides register allocation it also establishes the +//! concept of functions - a function in Compiler sense is a unit in which virtual +//! registers are allocated into physical registers by the register allocator. +//! In addition, it enables to use such virtual registers in function invocations. +//! +//! \ref BaseCompiler automatically handles function calling conventions. It's +//! still architecture dependent, but makes the code generation much easies. +//! Functions are essential; the first-step to generate some code is to define a +//! signature of the function to be generated (before generating the function body +//! itself). Function arguments and return value(s) are handled by assigning +//! virtual registers to them. Similarly, function calls are handled the same way. +//! +//! ### Compiler Nodes +//! +//! \ref BaseCompiler adds some nodes that are required for function generation +//! and invocation: +//! +//! - \ref FuncNode - Represents a function definition. +//! - \ref FuncRetNode - Represents a function return. +//! - \ref InvokeNode - Represents a function invocation. +//! +//! \ref BaseCompiler also makes the use of passes (\ref Pass) and automatically +//! adds an architecture-dependent register allocator pass to the list of passes +//! when attached to \ref CodeHolder. +//! +//! ### Compiler Examples +//! +//! - \ref x86::Compiler provides many X86/X64 examples. +//! +//! ### Compiler Tips +//! +//! Users of AsmJit have done mistakes in the past, this section should provide +//! some useful tips for beginners: +//! +//! - Virtual registers in compiler are bound to a single function. At the +//! moment the implementation doesn't care whether a single virtual register +//! is used in multiple functions, but it sees it as two independent virtual +//! registers in that case. This means that virtual registers cannot be used +//! to implement global variables. Global variables are basically memory +//! addresses which functions can read from and write to, and they have to +//! be implemented in the same way. +//! +//! - Compiler provides a useful debugging functionality, which can be turned +//! on through \ref FormatOptions::Flags. Use \ref Logger::addFlags() to +//! turn on additional logging features when using Compiler. + +// ============================================================================ +// [Documentation - asmjit_function] +// ============================================================================ + +//! \defgroup asmjit_function Function +//! \brief Function definitions. +//! +//! ### Overview +//! +//! AsmJit provides functionality that can be used to define function signatures +//! and to calculate automatically optimal function frame that can be used directly +//! by a prolog and epilog insertion. This feature was exclusive to AsmJit's Compiler +//! for a very long time, but was abstracted out and is now available for all users +//! regardless of the emitter they use. The following use cases are possible: +//! +//! - Calculate function frame before the function is generated - this is the +//! only way available to \ref BaseAssembler users and it will be described +//! in this section. +//! +//! - Calculate function frame after the function is generated - this way is +//! generally used by \ref BaseBuilder and \ref BaseCompiler emitters and +//! this way is generally described in \ref asmjit_compiler section. +//! +//! The following concepts are used to describe and create functions in AsmJit: +//! +//! - \ref Type::Id - Type-id is an 8-bit value that describes a platform +//! independent type as we know from C/C++. It provides abstractions for +//! most common types like `int8_t`, `uint32_t`, `uintptr_t`, `float`, +//! `double`, and all possible vector types to match ISAs up to AVX512. +//! \ref Type::Id was introduced originally for \ref asmjit_compiler, but +//! it's now used by \ref FuncSignature as well. +//! +//! - \ref CallConv - Describes a calling convention - this class contains +//! instructions to assign registers and stack addresses to function +//! arguments and return value(s), but doesn't specify any function +//! signature itself. Calling conventions are architecture and OS dependent. +//! +//! - \ref FuncSignature - Describes a function signature, for example +//! `int func(int, int)`. FuncSignature contains a function calling convention +//! id, return value type, and function arguments. The signature itself is +//! platform independent and uses \ref Type::Id to describe types of function +//! arguments and function return value(s). +//! +//! - \ref FuncDetail - Architecture and ABI dependent information that describes +//! \ref CallConv and expanded \ref FuncSignature. Each function argument and +//! return value is represented as \ref FuncValue that contains the original +//! \ref Type::Id enriched with additional information that specifies whether +//! the value is passed or returned by register (and which register) or by +//! stack. Each value also contains some other metadata that provide additional +//! information required to handle it properly (for example whether a vector is +//! passed indirectly by a pointer as required by WIN64 calling convention). +//! +//! - \ref FuncFrame - Contains information about the function frame that can +//! be used by prolog/epilog inserter (PEI). Holds call stack size size and +//! alignment, local stack size and alignment, and various attributes that +//! describe how prolog and epilog should be constructed. `FuncFrame` doesn't +//! know anything about function's arguments or return values, it hold only +//! information necessary to create a valid and ABI conforming function prologs +//! and epilogs. +//! +//! - \ref FuncArgsAssignment - A helper class that can be used to reassign +//! function arguments into user specified registers. It's architecture and +//! ABI dependent mapping from function arguments described by \ref CallConv +//! and \ref FuncDetail into registers specified by the user. +//! +//! It's a lot of concepts where each represents one step in a function frame +//! calculation. It can be used to create function prologs, epilogs, and also +//! to calculate information necessary to perform function calls. + +// ============================================================================ +// [Documentation - asmjit_logging] +// ============================================================================ + +//! \defgroup asmjit_logging Logging +//! \brief Logging and formatting. +//! +//! ### Overview +//! +//! The initial phase of a project that generates machine code is not always smooth. +//! Failure cases are common not just at the beginning phase, but also during the +//! development or refactoring. AsmJit provides logging functionality to address +//! this issue. AsmJit does already a good job with function overloading to prevent +//! from emitting unencodable instructions, but it can't prevent from emitting machine +//! code that is correct at instruction level, but doesn't work when it's executed as +//! a whole. Logging has always been an important part of AsmJit's infrastructure and +//! looking at logs can sometimes reveal code generation issues quickly. +//! +//! AsmJit provides API for logging and formatting: +//! - \ref Logger - A logger that you can pass to \ref CodeHolder and all emitters +//! that inherit from \ref BaseEmitter. +//! - \ref FormatOptions - Formatting options that can change how instructions and +//! operands are formatted. +//! - \ref Formatter - A namespace that provides functions that can format input +//! data like \ref Operand, \ref BaseReg, \ref Label, and \ref BaseNode into +//! \ref String. +//! +//! AsmJit's \ref Logger serves the following purposes: +//! - Provides a basic foundation for logging. +//! - Abstract class leaving the implementation on users. The following built-in +//! inplementations are provided for simplicty: +//! - \ref FileLogger implements logging into a standard `FILE` stream. +//! - \ref StringLogger serializes all logs into a \ref String instance. +//! +//! AsmJit's \ref FormatOptions provides the following to customize the formatting of +//! instructions and operands through: +//! - \ref FormatOptions::Flags +//! - \ref FormatOptions::IndentationType +//! +//! ### Logging +//! +//! A \ref Logger is typically attached to a \ref CodeHolder, which propagates it +//! to all attached emitters automatically. The example below illustrates how to +//! use \ref FileLogger that outputs to standard output: +//! +//! ``` +//! #include +//! #include +//! +//! using namespace asmjit; +//! +//! int main() { +//! JitRuntime rt; // Runtime specialized for JIT code execution. +//! FileLogger logger(stdout); // Logger should always survive CodeHolder. +//! +//! CodeHolder code; // Holds code and relocation information. +//! code.init(rt.environment()); // Initialize to the same arch as JIT runtime. +//! code.setLogger(&logger); // Attach the `logger` to `code` holder. +//! +//! // ... code as usual, everything emitted will be logged to `stdout` ... +//! return 0; +//! } +//! ``` +//! +//! If output to FILE stream is not desired it's possible to use \ref StringLogger, +//! which concatenates everything into a multi-line string: +//! +//! ``` +//! #include +//! #include +//! #include +//! +//! using namespace asmjit; +//! +//! int main() { +//! JitRuntime rt; // Runtime specialized for JIT code execution. +//! StringLogger logger; // Logger should always survive CodeHolder. +//! +//! CodeHolder code; // Holds code and relocation information. +//! code.init(rt.environment()); // Initialize to the same arch as JIT runtime. +//! code.setLogger(&logger); // Attach the `logger` to `code` holder. +//! +//! // ... code as usual, logging will be concatenated to logger string ... +//! +//! // You can either use the string from StringLogger directly or you can +//! // move it. Logger::data() returns its content as null terminated char[]. +//! printf("Logger content: %s\n", logger.data()); +//! +//! // It can be moved into your own string like this: +//! String content = std::move(logger.content()); +//! printf("The same content: %s\n", content.data()); +//! +//! return 0; +//! } +//! ``` +//! +//! ### Formatting +//! +//! AsmJit uses \ref Formatter to format inputs that are then passed to \ref +//! Logger. Formatting is public and can be used by AsmJit users as well. The +//! most important thing to know regarding formatting is that \ref Formatter +//! always appends to the output string, so it can be used to build complex +//! strings without having to concatenate intermediate strings. +//! +//! The first example illustrates how to format operands: +//! +//! ``` +//! #include +//! #include +//! +//! using namespace asmjit; +//! +//! void logOperand(uint32_t arch, const Operand_& op) { +//! // The emitter is optional (named labels and virtual registers need it). +//! BaseEmitter* emitter = nullptr; +//! +//! // No flags by default. +//! uint32_t formatFlags = FormatOptions::kNoFlags; +//! +//! StringTmp<128> sb; +//! Formatter::formatOperand(sb, formatFlags, emitter, arch, op); +//! printf("%s\n", sb.data()); +//! } +//! +//! void formattingExample() { +//! using namespace x86; +//! +//! // Architecture is not part of operand, it must be passed explicitly. +//! // Format flags. We pass it explicitly also to 'logOperand' to make +//! // compatible with what AsmJit normally does. +//! uint32_t arch = Environment::kArchX64; +//! +//! log(arch, rax); // Prints 'rax'. +//! log(arch, ptr(rax, rbx, 2)); // Prints '[rax + rbx * 4]`. +//! log(arch, dword_ptr(rax, rbx, 2)); // Prints 'dword [rax + rbx * 4]`. +//! log(arch, imm(42)); // Prints '42'. +//! } +//! ``` +//! +//! Next example illustrates how to format whole instructions: +//! +//! ``` +//! #include +//! #include +//! #include +//! +//! using namespace asmjit; +//! +//! template +//! void logInstruction(uint32_t arch, const BaseInst& inst, Args&&... args) { +//! // The emitter is optional (named labels and virtual registers need it). +//! BaseEmitter* emitter = nullptr; +//! +//! // No flags by default. +//! uint32_t formatFlags = FormatOptions::kNoFlags; +//! +//! // The formatter expects operands in an array. +//! Operand_ operands { std::forward(args)... }; +//! +//! StringTmp<128> sb; +//! Formatter::formatInstruction( +//! sb, formatFlags, emitter, arch, inst, operands, sizeof...(args)); +//! printf("%s\n", sb.data()); +//! } +//! +//! void formattingExample() { +//! using namespace x86; +//! +//! // Architecture is not part of operand, it must be passed explicitly. +//! // Format flags. We pass it explicitly also to 'logOperand' to make +//! // compatible with what AsmJit normally does. +//! uint32_t arch = Environment::kArchX64; +//! +//! // Prints 'mov rax, rcx'. +//! logInstruction(arch, BaseInst(Inst::kIdMov), rax, rcx); +//! +//! // Prints 'vaddpd zmm0, zmm1, [rax] {1to8}'. +//! logInstruction(arch, +//! BaseInst(Inst::kIdVaddpd), +//! zmm0, zmm1, ptr(rax)._1toN()); +//! +//! // BaseInst abstracts instruction id, instruction options, and extraReg. +//! // Prints 'lock add [rax], rcx'. +//! logInstruction(arch, +//! BaseInst(Inst::kIdAdd, Inst::kOptionLock), +//! x86::ptr(rax), rcx); +//! +//! // Similarly an extra register (like AVX-512 selector) can be used. +//! // Prints 'vaddpd zmm0 {k2} {z}, zmm1, [rax]'. +//! logInstruction(arch, +//! BaseInst(Inst::kIdAdd, Inst::kOptionZMask, k2), +//! zmm0, zmm1, ptr(rax)); +//! } +//! ``` +//! +//! And finally, the example below illustrates how to use a built-in function +//! to format the content of \ref BaseBuilder, which consists of nodes: +//! +//! ``` +//! #include +//! #include +//! +//! using namespace asmjit; +//! +//! void formattingExample(BaseBuilder* builder) { +//! uint32_t formatFlags = FormatOptions::kNoFlags; +//! +//! // This also shows how temporary strings can be used. +//! StringTmp<512> sb; +//! +//! // FormatNodeList requires the String for output, formatting flags, which +//! // were zero (no extra flags), and the builder instance, which we have +//! // provided. An overloaded version also exists, which accepts begin and +//! // and end nodes, which can be used to only format a range of nodes. +//! Formatter::formatNodeList(sb, formatFlags, builder); +//! +//! // You can do whatever else with the string, it's always null terminated, +//! // so it can be passed to C functions like printf(). +//! printf("%s\n", sb.data()); +//! } +//! ``` + +// ============================================================================ +// [Documentation - asmjit_error_handling] +// ============================================================================ + +//! \defgroup asmjit_error_handling Error Handling +//! \brief Error handling. +//! +//! ### Overview +//! +//! AsmJit uses error codes to represent and return errors. Every function that +//! can fail returns an \ref Error code. Exceptions are never thrown by AsmJit +//! itself even in extreme conditions like out-of-memory, but it's possible to +//! override \ref ErrorHandler::handleError() to throw, in that case no error +//! will be returned and exception will be thrown instead. All functions where +//! this can happen are not marked `noexcept`. +//! +//! Errors should never be ignored, however, checking errors after each AsmJit +//! API call would simply overcomplicate the whole code generation experience. +//! \ref ErrorHandler exists to make the use of AsmJit API simpler as it allows +//! to customize how errors can be handled: +//! +//! - Record the error and continue (the way how the error is user-implemented). +//! - Throw an exception. AsmJit doesn't use exceptions and is completely +//! exception-safe, but it's perfectly legal to throw an exception from +//! the error handler. +//! - Use plain old C's `setjmp()` and `longjmp()`. Asmjit always puts Assembler, +//! Builder and Compiler to a consistent state before calling \ref +//! ErrorHandler::handleError(), so `longjmp()` can be used without issues to +//! cancel the code-generation if an error occurred. This method can be used if +//! exception handling in your project is turned off and you still want some +//! comfort. In most cases it should be safe as AsmJit uses \ref Zone memory +//! and the ownership of memory it allocates always ends with the instance that +//! allocated it. If using this approach please never jump outside the life-time +//! of \ref CodeHolder and \ref BaseEmitter. +//! +//! ### Using ErrorHandler +//! +//! An example of attaching \ref ErrorHandler to \ref CodeHolder. +//! +//! ``` +//! #include +//! #include +//! +//! using namespace asmjit; +//! +//! // A simple error handler implementation, extend according to your needs. +//! class MyErrorHandler : public ErrorHandler { +//! public: +//! void handleError(Error err, const char* message, BaseEmitter* origin) override { +//! printf("AsmJit error: %s\n", message); +//! } +//! }; +//! +//! int main() { +//! JitRuntime rt; +//! +//! MyErrorHandler myErrorHandler; +//! CodeHolder code; +//! +//! code.init(rt.environment()); +//! code.setErrorHandler(&myErrorHandler); +//! +//! x86::Assembler a(&code); +//! // ... code generation ... +//! +//! return 0; +//! } +//! ``` +//! +//! Useful classes in error handling group: +//! +//! - See \ref DebugUtils that provides utilities useful for debugging. +//! - See \ref Error that lists error codes that AsmJit uses. +//! - See \ref ErrorHandler for more details about error handling. + +// ============================================================================ +// [Documentation - asmjit_instruction_db] +// ============================================================================ + +//! \defgroup asmjit_instruction_db Instruction DB +//! \brief Instruction database (introspection, read/write, validation, ...). +//! +//! ### Overview +//! +//! AsmJit provides a public instruction database that can be used to query +//! information about a complete instruction. The instruction database requires +//! the knowledge of the following: +//! +//! - \ref BaseInst - Base instruction that contains instruction id, options, +//! and a possible extra-register that represents either REP prefix counter +//! or AVX-512 selector (mask). +//! - \ref Operand - Represents operands of an instruction. +//! +//! Each instruction can be then queried for the following information: +//! +//! - \ref InstRWInfo - Read/write information of instruction and its oprands. +//! - \ref OpRWInfo - Read/write information of a single operand, part of +//! \ref InstRWInfo data structure. +//! - \ref BaseFeatures - CPU features required to execute the instruction. +//! +//! In addition to query functionality AsmJit is also able to validate whether +//! an instruction and its operands are valid. This is useful for making sure +//! that what user tries to emit is correct and it can be also used by other +//! projects that parse user input, like AsmTK project. +//! +//! ### Query API +//! +//! The instruction query API is provided by \ref InstAPI namespace. The +//! following queries are possible: +//! +//! - \ref InstAPI::queryRWInfo() - queries read/write information of the +//! given instruction and its operands. Includes also CPU flags read/written. +//! +//! - \ref InstAPI::queryFeatures() - queries CPU features that are required +//! to execute the given instruction. A full instruction with operands must +//! be given as some architectures like X86 may require different features +//! for the same instruction based on its operands. +//! +//! - asmjit_test_x86_instinfo.cpp +//! can be also used as a reference about accessing instruction information. +//! +//! ### Validation API +//! +//! The instruction validation API is provided by \ref InstAPI namespace in the +//! similar fashion like the Query API, however, validation can also be turned +//! on at \ref BaseEmitter level. The following is possible: +//! +//! - \ref InstAPI::validate() - low-level instruction validation function +//! that is used internally by emitters if strict validation is enabled. +//! +//! - \ref BaseEmitter::addValidationOptions() - can be used to enable +//! validation at emitter level, see \ref BaseEmitter::ValidationOptions. + + +// ============================================================================ +// [Documentation - asmjit_virtual_memory] +// ============================================================================ + +//! \defgroup asmjit_virtual_memory Virtual Memory +//! \brief Virtual memory management. +//! +//! ### Overview +//! +//! AsmJit's virtual memory management is divided into two main categories: +//! +//! - Low level API that provides cross-platform abstractions for virtual +//! memory allocation. Implemented in \ref VirtMem namespace. +//! - High level API that makes it very easy to store generated code for +//! execution. See \ref JitRuntime, which is used by many examples for its +//! simplicity and easy integration with \ref CodeHolder. There is also +//! \ref JitAllocator, which lays somewhere between RAW memory allocation +//! and \ref JitRuntime. + +// ============================================================================ +// [Documentation - asmjit_zone_memory] +// ============================================================================ + +//! \defgroup asmjit_zone Zone Memory +//! \brief Zone memory allocator and containers. +//! +//! ### Overview +//! +//! AsmJit uses zone memory allocation (also known as Arena allocation) to allocate +//! most of the data it uses. It's a fast allocator that allows AsmJit to allocate +//! a lot of small data structures fast and without `malloc()` overhead. Since +//! code generators and all related classes are usually short-lived this approach +//! decreases memory usage and fragmentation as arena-based allocators always +//! allocate larger blocks of memory, which are then split into smaller chunks. +//! +//! Another advantage of zone memory allocation is that since the whole library +//! uses this strategy it's very easy to deallocate everything that a particular +//! instance is holding by simply releasing the memory the allocator holds. This +//! improves destruction time of such objects as there is no destruction at all. +//! Long-lived objects just reset its data in destructor or in their reset() +//! member function for a future reuse. For this purpose all containers in AsmJit +//! are also zone allocated. +//! +//! ### Zone Allocation +//! +//! - \ref Zone - Incremental zone memory allocator with minimum features. It +//! can only allocate memory without the possibility to return it back to +//! the allocator. +//! +//! - \ref ZoneTmp - A temporary \ref Zone with some initial static storage. +//! If the allocation requests fit the static storage allocated then there +//! will be no dynamic memory allocation during the lifetime of \ref ZoneTmp, +//! otherwise it would act as \ref Zone with one preallocated block on the +//! stack. +//! +//! - \ref ZoneAllocator - A wrapper of \ref Zone that provides the capability +//! of returning memory to the allocator. Such memory is stored in a pool for +//! later reuse. +//! +//! ### Zone Allocated Containers +//! +//! - \ref ZoneString - Zone allocated string. +//! - \ref ZoneHash - Zone allocated hash table. +//! - \ref ZoneTree - Zone allocated red-black tree. +//! - \ref ZoneList - Zone allocated double-linked list. +//! - \ref ZoneStack - Zone allocated stack. +//! - \ref ZoneVector - Zone allocated vector. +//! - \ref ZoneBitVector - Zone allocated vector of bits. +//! +//! ### Using Zone Allocated Containers +//! +//! The most common data structure exposed by AsmJit is \ref ZoneVector. It's very +//! similar to `std::vector`, but the implementation doesn't use exceptions and +//! uses the mentioned \ref ZoneAllocator for performance reasons. You don't have +//! to worry about allocations as you should not need to add items to AsmJit's +//! data structures directly as there should be API for all required operations. +//! +//! The following APIs in \ref CodeHolder returns \ref ZoneVector reference: +//! +//! ``` +//! using namespace asmjit; +//! +//! void example(CodeHolder& code) { +//! // Contains all emitters attached to CodeHolder. +//! const ZoneVector& emitters = code.emitters(); +//! +//! // Contains all section entries managed by CodeHolder. +//! const ZoneVector& sections = code.sections(); +//! +//! // Contains all label entries managed by CodeHolder. +//! const ZoneVector& labelEntries = code.labelEntries(); +//! +//! // Contains all relocation entries managed by CodeHolder. +//! const ZoneVector& relocEntries = code.relocEntries(); +//! } +//! ``` +//! +//! \ref ZoneVector has overloaded array access operator to make it possible +//! to access its elements through operator[]. Some standard functions like +//! \ref ZoneVector::empty(), \ref ZoneVector::size(), and \ref ZoneVector::data() +//! are provided as well. Vectors are also iterable through a range-based for loop: +//! +//! ``` +//! using namespace asmjit; +//! +//! void example(CodeHolder& code) { +//! for (LabelEntry* le : code.labelEntries()) { +//! printf("Label #%u {Bound=%s Offset=%llu}", +//! le->id(), +//! le->isBound() ? "true" : "false", +//! (unsigned long long)le->offset()); +//! } +//! } +//! ``` +//! +//! ### Design Considerations +//! +//! Zone-allocated containers do not store the allocator within the container. +//! This decision was made to reduce the footprint of such containers as AsmJit +//! tooling, especially Compiler's register allocation, may use many instances +//! of such containers to perform code analysis and register allocation. +//! +//! For example to append an item into a \ref ZoneVector it's required to pass +//! the allocator as the first argument, so it can be used in case that the +//! vector needs a reallocation. Such function also returns an error, which +//! must be propagated to the caller. +//! +//! ``` +//! using namespace asmjit +//! +//! Error example(ZoneAllocator* allocator) { +//! ZoneVector vector; +//! +//! // Unfortunately, allocator must be provided to all functions that mutate +//! // the vector. However, AsmJit users should never need to do this as all +//! // manipulation should be done through public API, which takes care of +//! // that. +//! for (int i = 0; i < 100; i++) { +//! ASMJIT_PROPAGATE(vector.append(allocator, i)); +//! } +//! +//! // By default vector's destructor doesn't release anything as it knows +//! // that its content is zone allocated. However, \ref ZoneVector::release +//! // can be used to explicitly release the vector data to the allocator if +//! // necessary +//! vector.release(allocator); +//! } +//! ``` +//! +//! Containers like \ref ZoneVector also provide a functionality to reserve a +//! certain number of items before any items are added to it. This approach is +//! used internally in most places as it allows to prepare space for data that +//! will be added to some container before the data itself was created. +//! +//! ``` +//! using namespace asmjit +//! +//! Error example(ZoneAllocator* allocator) { +//! ZoneVector vector; +//! +//! ASMJIT_PROPAGATE(vector.willGrow(100)); +//! for (int i = 0; i < 100; i++) { +//! // Cannot fail. +//! vector.appendUnsafe(allocator, i); +//! } +//! +//! vector.release(allocator); +//! } +//! ``` + +// ============================================================================ +// [Documentation - asmjit_utilities] +// ============================================================================ + +//! \defgroup asmjit_utilities Utilities +//! \brief Utility classes and functions. +//! +//! ### Overview +//! +//! AsmJit uses and provides utility classes and functions, that can be used +//! with AsmJit. The functionality can be divided into the following topics: +//! +//! ### String Functionality +//! +//! - \ref String - AsmJit's string container, which is used internally +//! and which doesn't use exceptions and has a stable layout, which is +//! not dependent on C++ standard library. +//! - \ref StringTmp - String that can have base storage allocated on +//! stack. The amount of storage on stack can be specified as a template +//! parameter. +//! - \ref FixedString - Fixed string container limited up to N characters. +//! +//! ### Code Generation Utilities +//! +//! - \ref ConstPool - Constant pool used by \ref BaseCompiler, but also +//! available to users that may find use of it. +//! +//! ### Support Functionality Used by AsmJit +//! +//! - \ref Support namespace provides many other utility functions and +//! classes that are used by AsmJit, and made public. + +// ============================================================================ +// [Documentation - asmjit_ backends] +// ============================================================================ + +//! \defgroup asmjit_x86 X86 Backend +//! \brief X86/X64 backend. + +// ============================================================================ +// [Documentation - asmjit_ra] +// ============================================================================ + +//! \cond INTERNAL +//! \defgroup asmjit_ra RA +//! \brief Register allocator internals. +//! \endcond + +} // {asmjit} + +// ============================================================================ +// [Core Headers] +// ============================================================================ + +#include "asmjit-scope-begin.h" +#include "core/archtraits.h" +#include "core/assembler.h" +#include "core/builder.h" +#include "core/codeholder.h" +#include "core/compiler.h" +#include "core/constpool.h" +#include "core/cpuinfo.h" +#include "core/datatypes.h" +#include "core/emitter.h" +#include "core/environment.h" +#include "core/errorhandler.h" +#include "core/features.h" +#include "core/formatter.h" +#include "core/func.h" +#include "core/globals.h" +#include "core/inst.h" +#include "core/jitallocator.h" +#include "core/jitruntime.h" +#include "core/logger.h" +#include "core/operand.h" +#include "core/osutils.h" +#include "core/string.h" +#include "core/support.h" +#include "core/target.h" +#include "core/type.h" +#include "core/virtmem.h" +#include "core/zone.h" +#include "core/zonehash.h" +#include "core/zonelist.h" +#include "core/zonetree.h" +#include "core/zonestack.h" +#include "core/zonestring.h" +#include "core/zonevector.h" +#include "asmjit-scope-end.h" + +// ============================================================================ +// [Deprecated] +// ============================================================================ + +#ifndef ASMJIT_NO_DEPRECATED +namespace asmjit { + +#ifndef ASMJIT_NO_COMPILER +ASMJIT_DEPRECATED("Use InvokeNode instead of FuncCallNode") +typedef InvokeNode FuncCallNode; +#endif // !ASMJIT_NO_COMPILER + +#ifndef ASMJIT_NO_LOGGING +namespace Logging { using namespace Formatter; } +#endif //! ASMJIT_NO_LOGGING + +} // {asmjit} +#endif // !ASMJIT_NO_DEPRECATED + +#endif // ASMJIT_CORE_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/api-build_p.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/api-build_p.h new file mode 100644 index 0000000..db37ca7 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/api-build_p.h @@ -0,0 +1,77 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_API_BUILD_P_H_INCLUDED +#define ASMJIT_CORE_API_BUILD_P_H_INCLUDED + +#define ASMJIT_EXPORTS + +// Only turn-off these warnings when building asmjit itself. +#ifdef _MSC_VER + #ifndef _CRT_SECURE_NO_DEPRECATE + #define _CRT_SECURE_NO_DEPRECATE + #endif + #ifndef _CRT_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_WARNINGS + #endif +#endif + +// Dependencies only required for asmjit build, but never exposed through public headers. +#ifdef _WIN32 + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #ifndef NOMINMAX + #define NOMINMAX + #endif + #include +#endif + +// ============================================================================ +// [asmjit::Build - Globals - Build-Only] +// ============================================================================ + +#include "./api-config.h" + +#if !defined(ASMJIT_BUILD_DEBUG) && defined(__GNUC__) && !defined(__clang__) + #define ASMJIT_FAVOR_SIZE __attribute__((__optimize__("Os"))) + #define ASMJIT_FAVOR_SPEED __attribute__((__optimize__("O3"))) +#elif ASMJIT_CXX_HAS_ATTRIBUTE(__minsize__, 0) + #define ASMJIT_FAVOR_SIZE __attribute__((__minsize__)) + #define ASMJIT_FAVOR_SPEED +#else + #define ASMJIT_FAVOR_SIZE + #define ASMJIT_FAVOR_SPEED +#endif + +// Make sure '#ifdef'ed unit tests are properly highlighted in IDE. +#if !defined(ASMJIT_TEST) && defined(__INTELLISENSE__) + #define ASMJIT_TEST +#endif + +// Include a unit testing package if this is a `asmjit_test_unit` build. +#if defined(ASMJIT_TEST) + #include "../../../test/broken.h" +#endif + +#endif // ASMJIT_CORE_API_BUILD_P_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/api-config.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/api-config.h new file mode 100644 index 0000000..aab3473 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/api-config.h @@ -0,0 +1,552 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_API_CONFIG_H_INCLUDED +#define ASMJIT_CORE_API_CONFIG_H_INCLUDED + +// ============================================================================ +// [asmjit::Version] +// ============================================================================ + +//! \addtogroup asmjit_core +//! \{ + +//! AsmJit library version in `(Major << 16) | (Minor << 8) | (Patch)` format. +#define ASMJIT_LIBRARY_VERSION 0x010400 /* 1.4.0 */ + +//! \} + +// ============================================================================ +// [asmjit::Build - Documentation] +// ============================================================================ + +// NOTE: Doxygen cannot document macros that are not defined, that's why we have +// to define them and then undefine them, so it won't use the macros with its +// own preprocessor. +#ifdef _DOXYGEN +namespace asmjit { + +//! \addtogroup asmjit_build +//! \{ + +//! Asmjit is embedded, implies \ref ASMJIT_STATIC. +#define ASMJIT_EMBED + +//! Enables static-library build. +#define ASMJIT_STATIC + +//! Defined when AsmJit's build configuration is 'Debug'. +//! +//! \note Can be defined explicitly to bypass autodetection. +#define ASMJIT_BUILD_DEBUG + +//! Defined when AsmJit's build configuration is 'Release'. +//! +//! \note Can be defined explicitly to bypass autodetection. +#define ASMJIT_BUILD_RELEASE + +//! Defined to build X86/X64 backend. +#define ASMJIT_BUILD_X86 + +//! Defined to build host backend autodetected at compile-time. +#define ASMJIT_BUILD_HOST + +//! Disables deprecated API at compile time. +#define ASMJIT_NO_DEPRECATED + +//! Disable non-host architectures entirely. +#define ASMJIT_NO_FOREIGN + +//! Disables \ref asmjit_builder functionality completely. +#define ASMJIT_NO_BUILDER + +//! Disables \ref asmjit_compiler functionality completely. +#define ASMJIT_NO_COMPILER + +//! Disables JIT memory management and \ref JitRuntime. +#define ASMJIT_NO_JIT + +//! Disables \ref Logger and \ref Formatter. +#define ASMJIT_NO_LOGGING + +//! Disables everything that contains text. +#define ASMJIT_NO_TEXT + +//! Disables instruction validation API. +#define ASMJIT_NO_VALIDATION + +//! Disables instruction introspection API. +#define ASMJIT_NO_INTROSPECTION + +// Avoid doxygen preprocessor using feature-selection definitions. +#undef ASMJIT_NO_BUILDER +#undef ASMJIT_NO_COMPILER +#undef ASMJIT_NO_JIT +#undef ASMJIT_NO_LOGGING +#undef ASMJIT_NO_TEXT +#undef ASMJIT_NO_VALIDATION +#undef ASMJIT_NO_INTROSPECTION + +//! \} + +} // {asmjit} +#endif // _DOXYGEN + +// Enable all features at IDE level, so it's properly highlighted and indexed. +#ifdef __INTELLISENSE__ + #ifndef ASMJIT_BUILD_X86 + #define ASMJIT_BUILD_X86 + #endif +#endif + +// ============================================================================ +// [asmjit::Dependencies] +// ============================================================================ + +// We really want std-types as globals. +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) + #include +#endif + + +// ============================================================================ +// [asmjit::Options] +// ============================================================================ + +// ASMJIT_NO_BUILDER implies ASMJIT_NO_COMPILER. +#if defined(ASMJIT_NO_BUILDER) && !defined(ASMJIT_NO_COMPILER) + #define ASMJIT_NO_COMPILER +#endif + +// Prevent compile-time errors caused by misconfiguration. +#if defined(ASMJIT_NO_TEXT) && !defined(ASMJIT_NO_LOGGING) + #pragma "ASMJIT_NO_TEXT can only be defined when ASMJIT_NO_LOGGING is defined." + #undef ASMJIT_NO_TEXT +#endif + +#if defined(ASMJIT_NO_INTROSPECTION) && !defined(ASMJIT_NO_COMPILER) + #pragma message("ASMJIT_NO_INTROSPECTION can only be defined when ASMJIT_NO_COMPILER is defined") + #undef ASMJIT_NO_INTROSPECTION +#endif + +// ============================================================================ +// [asmjit::Build - Globals - Deprecated] +// ============================================================================ + +#ifndef ASMJIT_NO_DEPRECATED + #if defined(ASMJIT_BUILD_EMBED) || defined(ASMJIT_BUILD_STATIC) + #if defined(ASMJIT_BUILD_EMBED) + #pragma message("'ASMJIT_BUILD_EMBED' is deprecated, use 'ASMJIT_STATIC'") + #endif + #if defined(ASMJIT_BUILD_STATIC) + #pragma message("'ASMJIT_BUILD_STATIC' is deprecated, use 'ASMJIT_STATIC'") + #endif + + #if !defined(ASMJIT_STATIC) + #define ASMJIT_STATIC + #endif + #endif +#endif // !ASMJIT_NO_DEPRECATED + +// ============================================================================ +// [asmjit::Build - Globals - Build Mode] +// ============================================================================ + +// Detect ASMJIT_BUILD_DEBUG and ASMJIT_BUILD_RELEASE if not defined. +#if !defined(ASMJIT_BUILD_DEBUG) && !defined(ASMJIT_BUILD_RELEASE) + #if !defined(NDEBUG) + #define ASMJIT_BUILD_DEBUG + #else + #define ASMJIT_BUILD_RELEASE + #endif +#endif + +// ============================================================================ +// [asmjit::Build - Globals - Target Architecture Information] +// ============================================================================ + +#if defined(_M_X64) || defined(__x86_64__) + #define ASMJIT_ARCH_X86 64 +#elif defined(_M_IX86) || defined(__X86__) || defined(__i386__) + #define ASMJIT_ARCH_X86 32 +#else + #define ASMJIT_ARCH_X86 0 +#endif + +#if defined(__arm64__) || defined(__aarch64__) +# define ASMJIT_ARCH_ARM 64 +#elif defined(_M_ARM) || defined(_M_ARMT) || defined(__arm__) || defined(__thumb__) || defined(__thumb2__) + #define ASMJIT_ARCH_ARM 32 +#else + #define ASMJIT_ARCH_ARM 0 +#endif + +#if defined(_MIPS_ARCH_MIPS64) || defined(__mips64) + #define ASMJIT_ARCH_MIPS 64 +#elif defined(_MIPS_ARCH_MIPS32) || defined(_M_MRX000) || defined(__mips__) + #define ASMJIT_ARCH_MIPS 32 +#else + #define ASMJIT_ARCH_MIPS 0 +#endif + +#define ASMJIT_ARCH_BITS (ASMJIT_ARCH_X86 | ASMJIT_ARCH_ARM | ASMJIT_ARCH_MIPS) +#if ASMJIT_ARCH_BITS == 0 + #undef ASMJIT_ARCH_BITS + #if defined (__LP64__) || defined(_LP64) + #define ASMJIT_ARCH_BITS 64 + #else + #define ASMJIT_ARCH_BITS 32 + #endif +#endif + +#if (defined(__ARMEB__)) || \ + (defined(__MIPSEB__)) || \ + (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + #define ASMJIT_ARCH_LE 0 + #define ASMJIT_ARCH_BE 1 +#else + #define ASMJIT_ARCH_LE 1 + #define ASMJIT_ARCH_BE 0 +#endif + +// ============================================================================ +// [asmjit::Build - Globals - Build Architectures Definitions] +// ============================================================================ + +#if !defined(ASMJIT_NO_FOREIGN) + // If 'ASMJIT_NO_FOREIGN' is not defined then all architectures will be built. + #if !defined(ASMJIT_BUILD_X86) + #define ASMJIT_BUILD_X86 + #endif +#else + // Detect architectures to build if building only for the host architecture. + #if ASMJIT_ARCH_X86 && !defined(ASMJIT_BUILD_X86) + #define ASMJIT_BUILD_X86 + #endif +#endif + +// Define 'ASMJIT_BUILD_HOST' if we know that host architecture will be built. +#if !defined(ASMJIT_BUILD_HOST) && ASMJIT_ARCH_X86 && defined(ASMJIT_BUILD_X86) + #define ASMJIT_BUILD_HOST +#endif + +// ============================================================================ +// [asmjit::Build - Globals - C++ Compiler and Features Detection] +// ============================================================================ + +#define ASMJIT_CXX_GNU 0 +#define ASMJIT_CXX_MAKE_VER(MAJOR, MINOR) ((MAJOR) * 1000 + (MINOR)) + +// Intel Compiler [pretends to be GNU or MSC, so it must be checked first]: +// - https://software.intel.com/en-us/articles/c0x-features-supported-by-intel-c-compiler +// - https://software.intel.com/en-us/articles/c14-features-supported-by-intel-c-compiler +// - https://software.intel.com/en-us/articles/c17-features-supported-by-intel-c-compiler +#if defined(__INTEL_COMPILER) + +// MSC Compiler: +// - https://msdn.microsoft.com/en-us/library/hh567368.aspx +// +// Version List: +// - 16.00.0 == VS2010 +// - 17.00.0 == VS2012 +// - 18.00.0 == VS2013 +// - 19.00.0 == VS2015 +// - 19.10.0 == VS2017 +#elif defined(_MSC_VER) && defined(_MSC_FULL_VER) + +// Clang Compiler [Pretends to be GNU, so it must be checked before]: +// - https://clang.llvm.org/cxx_status.html +#elif defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__) + +// GNU Compiler: +// - https://gcc.gnu.org/projects/cxx-status.html +#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) + + #undef ASMJIT_CXX_GNU + #define ASMJIT_CXX_GNU ASMJIT_CXX_MAKE_VER(__GNUC__, __GNUC_MINOR__) + +#endif + +// Compiler features detection macros. +#if defined(__clang__) && defined(__has_attribute) + #define ASMJIT_CXX_HAS_ATTRIBUTE(NAME, CHECK) (__has_attribute(NAME)) +#else + #define ASMJIT_CXX_HAS_ATTRIBUTE(NAME, CHECK) (!(!(CHECK))) +#endif + +// ============================================================================ +// [asmjit::Build - Globals - API Decorators & Language Extensions] +// ============================================================================ + +// API (Export / Import). +#if !defined(ASMJIT_STATIC) + #if defined(_WIN32) && (defined(_MSC_VER) || defined(__MINGW32__)) + #ifdef ASMJIT_EXPORTS + #define ASMJIT_API __declspec(dllexport) + #else + #define ASMJIT_API __declspec(dllimport) + #endif + #elif defined(_WIN32) && defined(__GNUC__) + #ifdef ASMJIT_EXPORTS + #define ASMJIT_API __attribute__((__dllexport__)) + #else + #define ASMJIT_API __attribute__((__dllimport__)) + #endif + #elif defined(__GNUC__) + #define ASMJIT_API __attribute__((__visibility__("default"))) + #endif +#endif + +#if !defined(ASMJIT_API) + #define ASMJIT_API +#endif + +#if !defined(ASMJIT_VARAPI) + #define ASMJIT_VARAPI extern ASMJIT_API +#endif + +// This is basically a workaround. When using MSVC and marking class as DLL +// export everything gets exported, which is unwanted in most projects. MSVC +// automatically exports typeinfo and vtable if at least one symbol of the +// class is exported. However, GCC has some strange behavior that even if +// one or more symbol is exported it doesn't export typeinfo unless the +// class itself is decorated with "visibility(default)" (i.e. ASMJIT_API). +#if !defined(_WIN32) && defined(__GNUC__) + #define ASMJIT_VIRTAPI ASMJIT_API +#else + #define ASMJIT_VIRTAPI +#endif + +// Function attributes. +#if !defined(ASMJIT_BUILD_DEBUG) && defined(__GNUC__) + #define ASMJIT_INLINE inline __attribute__((__always_inline__)) +#elif !defined(ASMJIT_BUILD_DEBUG) && defined(_MSC_VER) + #define ASMJIT_INLINE __forceinline +#else + #define ASMJIT_INLINE inline +#endif + +#if defined(__GNUC__) + #define ASMJIT_NOINLINE __attribute__((__noinline__)) + #define ASMJIT_NORETURN __attribute__((__noreturn__)) +#elif defined(_MSC_VER) + #define ASMJIT_NOINLINE __declspec(noinline) + #define ASMJIT_NORETURN __declspec(noreturn) +#else + #define ASMJIT_NOINLINE + #define ASMJIT_NORETURN +#endif + +// Calling conventions. +#if ASMJIT_ARCH_X86 == 32 && defined(__GNUC__) + #define ASMJIT_CDECL __attribute__((__cdecl__)) + #define ASMJIT_STDCALL __attribute__((__stdcall__)) + #define ASMJIT_FASTCALL __attribute__((__fastcall__)) + #define ASMJIT_REGPARM(N) __attribute__((__regparm__(N))) +#elif ASMJIT_ARCH_X86 == 32 && defined(_MSC_VER) + #define ASMJIT_CDECL __cdecl + #define ASMJIT_STDCALL __stdcall + #define ASMJIT_FASTCALL __fastcall + #define ASMJIT_REGPARM(N) +#else + #define ASMJIT_CDECL + #define ASMJIT_STDCALL + #define ASMJIT_FASTCALL + #define ASMJIT_REGPARM(N) +#endif + +#if ASMJIT_ARCH_X86 && defined(_WIN32) && defined(_MSC_VER) + #define ASMJIT_VECTORCALL __vectorcall +#elif ASMJIT_ARCH_X86 && defined(_WIN32) + #define ASMJIT_VECTORCALL __attribute__((__vectorcall__)) +#else + #define ASMJIT_VECTORCALL +#endif + + +// Type alignment (not allowed by C++11 'alignas' keyword). +#if defined(__GNUC__) + #define ASMJIT_ALIGN_TYPE(TYPE, N) __attribute__((__aligned__(N))) TYPE +#elif defined(_MSC_VER) + #define ASMJIT_ALIGN_TYPE(TYPE, N) __declspec(align(N)) TYPE +#else + #define ASMJIT_ALIGN_TYPE(TYPE, N) TYPE +#endif + +//! \def ASMJIT_MAY_ALIAS +//! +//! Expands to `__attribute__((__may_alias__))` if supported. +#if defined(__GNUC__) + #define ASMJIT_MAY_ALIAS __attribute__((__may_alias__)) +#else + #define ASMJIT_MAY_ALIAS +#endif + +//! \def ASMJIT_LIKELY(...) +//! +//! Condition is likely to be taken (mostly error handling and edge cases). + +//! \def ASMJIT_UNLIKELY(...) +//! +//! Condition is unlikely to be taken (mostly error handling and edge cases). +#if defined(__GNUC__) + #define ASMJIT_LIKELY(...) __builtin_expect(!!(__VA_ARGS__), 1) + #define ASMJIT_UNLIKELY(...) __builtin_expect(!!(__VA_ARGS__), 0) +#else + #define ASMJIT_LIKELY(...) (__VA_ARGS__) + #define ASMJIT_UNLIKELY(...) (__VA_ARGS__) +#endif + +//! \def ASMJIT_FALLTHROUGH +//! +//! Portable [[fallthrough]] attribute. +#if defined(__clang__) && __cplusplus >= 201103L + #define ASMJIT_FALLTHROUGH [[clang::fallthrough]] +#elif defined(__GNUC__) && __GNUC__ >= 7 + #define ASMJIT_FALLTHROUGH __attribute__((__fallthrough__)) +#else + #define ASMJIT_FALLTHROUGH ((void)0) /* fallthrough */ +#endif + +//! \def ASMJIT_DEPRECATED +//! +//! Marks function, class, struct, enum, or anything else as deprecated. +#if defined(__GNUC__) + #define ASMJIT_DEPRECATED(MESSAGE) __attribute__((__deprecated__(MESSAGE))) + #if defined(__clang__) + #define ASMJIT_DEPRECATED_STRUCT(MESSAGE) __attribute__((__deprecated__(MESSAGE))) + #else + #define ASMJIT_DEPRECATED_STRUCT(MESSAGE) /* not usable if a deprecated function uses it */ + #endif +#elif defined(_MSC_VER) + #define ASMJIT_DEPRECATED(MESSAGE) __declspec(deprecated(MESSAGE)) + #define ASMJIT_DEPRECATED_STRUCT(MESSAGE) /* not usable if a deprecated function uses it */ +#else + #define ASMJIT_DEPRECATED(MESSAGE) + #define ASMJIT_DEPRECATED_STRUCT(MESSAGE) +#endif + +// Utilities. +#define ASMJIT_OFFSET_OF(STRUCT, MEMBER) ((int)(intptr_t)((const char*)&((const STRUCT*)0x100)->MEMBER) - 0x100) +#define ASMJIT_ARRAY_SIZE(X) uint32_t(sizeof(X) / sizeof(X[0])) + +#if ASMJIT_CXX_HAS_ATTRIBUTE(no_sanitize, 0) + #define ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF __attribute__((__no_sanitize__("undefined"))) +#elif ASMJIT_CXX_GNU >= ASMJIT_CXX_MAKE_VER(4, 9) + #define ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF __attribute__((__no_sanitize_undefined__)) +#else + #define ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF +#endif + +// ============================================================================ +// [asmjit::Build - Globals - Begin-Namespace / End-Namespace] +// ============================================================================ + +#if defined(__clang__) + #define ASMJIT_BEGIN_NAMESPACE \ + namespace asmjit { \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wconstant-logical-operand\"") \ + _Pragma("clang diagnostic ignored \"-Wunnamed-type-template-args\"") + #define ASMJIT_END_NAMESPACE \ + _Pragma("clang diagnostic pop") \ + } +#elif defined(__GNUC__) && __GNUC__ == 4 + #define ASMJIT_BEGIN_NAMESPACE \ + namespace asmjit { \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") + #define ASMJIT_END_NAMESPACE \ + _Pragma("GCC diagnostic pop") \ + } +#elif defined(__GNUC__) && __GNUC__ >= 8 + #define ASMJIT_BEGIN_NAMESPACE \ + namespace asmjit { \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wclass-memaccess\"") + #define ASMJIT_END_NAMESPACE \ + _Pragma("GCC diagnostic pop") \ + } +#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) + #define ASMJIT_BEGIN_NAMESPACE \ + namespace asmjit { \ + __pragma(warning(push)) \ + __pragma(warning(disable: 4127)) /* conditional expression is const */ \ + __pragma(warning(disable: 4201)) /* nameless struct/union */ + #define ASMJIT_END_NAMESPACE \ + __pragma(warning(pop)) \ + } +#endif + +#if !defined(ASMJIT_BEGIN_NAMESPACE) && !defined(ASMJIT_END_NAMESPACE) + #define ASMJIT_BEGIN_NAMESPACE namespace asmjit { + #define ASMJIT_END_NAMESPACE } +#endif + +#define ASMJIT_BEGIN_SUB_NAMESPACE(NAMESPACE) \ + ASMJIT_BEGIN_NAMESPACE \ + namespace NAMESPACE { + +#define ASMJIT_END_SUB_NAMESPACE \ + } \ + ASMJIT_END_NAMESPACE + +// ============================================================================ +// [asmjit::Build - Globals - Utilities] +// ============================================================================ + +#define ASMJIT_NONCOPYABLE(...) \ + private: \ + __VA_ARGS__(const __VA_ARGS__& other) = delete; \ + __VA_ARGS__& operator=(const __VA_ARGS__& other) = delete; \ + public: + +#define ASMJIT_NONCONSTRUCTIBLE(...) \ + private: \ + __VA_ARGS__() = delete; \ + __VA_ARGS__(const __VA_ARGS__& other) = delete; \ + __VA_ARGS__& operator=(const __VA_ARGS__& other) = delete; \ + public: + +// ============================================================================ +// [asmjit::Build - Globals - Cleanup] +// ============================================================================ + +// Cleanup definitions that are only used within this header file. +#undef ASMJIT_CXX_GNU +#undef ASMJIT_CXX_MAKE_VER + +#endif // ASMJIT_CORE_API_CONFIG_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/archcommons.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/archcommons.h new file mode 100644 index 0000000..fda2451 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/archcommons.h @@ -0,0 +1,164 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_ARCHCOMMONS_H_INCLUDED +#define ASMJIT_CORE_ARCHCOMMONS_H_INCLUDED + +// This file provides architecture-specific classes that are required in the +// core library. For example Imm operand allows to be created from arm::Shift +// in a const-expr way, so the arm::Shift must be provided. So this header +// file provides everything architecture-specific that is used by the Core API. + +#include "../core/globals.h" + +// ============================================================================ +// [asmjit::arm] +// ============================================================================ + +ASMJIT_BEGIN_SUB_NAMESPACE(arm) + +//! \addtogroup asmjit_arm +//! \{ + +//! Represents ARM immediate shift operation type and value. +class Shift { +public: + //! Operation predicate (ARM) describes either SHIFT or EXTEND operation. + //! + //! \note The constants are AsmJit specific. The first 5 values describe real + //! constants on ARM32 and AArch64 hardware, however, the addition constants + //! that describe extend modes are specific to AsmJit and would be translated + //! to the AArch64 specific constants by the assembler. + enum Op : uint32_t { + //! Shift left logical operation (default). + //! + //! Available to all ARM architectures. + kOpLSL = 0x00u, + + //! Shift right logical operation. + //! + //! Available to all ARM architectures. + kOpLSR = 0x01u, + + //! Shift right arithmetic operation. + //! + //! Available to all ARM architectures. + kOpASR = 0x02u, + + //! Rotate right operation. + //! + //! \note Not available in AArch64 mode. + kOpROR = 0x03u, + + //! Rotate right with carry operation (encoded as `kShiftROR` with zero). + //! + //! \note Not available in AArch64 mode. + kOpRRX = 0x04u, + + //! Shift left by filling low order bits with ones. + kOpMSL = 0x05u, + + //! UXTN extend register operation (AArch64 only). + kOpUXTB = 0x06u, + //! UXTH extend register operation (AArch64 only). + kOpUXTH = 0x07u, + //! UXTW extend register operation (AArch64 only). + kOpUXTW = 0x08u, + //! UXTX extend register operation (AArch64 only). + kOpUXTX = 0x09u, + + //! SXTB extend register operation (AArch64 only). + kOpSXTB = 0x0Au, + //! SXTH extend register operation (AArch64 only). + kOpSXTH = 0x0Bu, + //! SXTW extend register operation (AArch64 only). + kOpSXTW = 0x0Cu, + //! SXTX extend register operation (AArch64 only). + kOpSXTX = 0x0Du + + // NOTE: 0xE and 0xF are used by memory operand to specify POST|PRE offset mode. + }; + + //! Shift operation. + uint32_t _op; + //! Shift Value. + uint32_t _value; + + //! Default constructed Shift is not initialized. + inline Shift() noexcept = default; + + //! Copy constructor (default) + constexpr Shift(const Shift& other) noexcept = default; + + //! Constructs Shift from operation `op` and shift `value`. + constexpr Shift(uint32_t op, uint32_t value) noexcept + : _op(op), + _value(value) {} + + //! Returns the shift operation. + constexpr uint32_t op() const noexcept { return _op; } + //! Returns the shift smount. + constexpr uint32_t value() const noexcept { return _value; } + + //! Sets shift operation to `op`. + inline void setOp(uint32_t op) noexcept { _op = op; } + //! Sets shift amount to `value`. + inline void setValue(uint32_t value) noexcept { _value = value; } +}; + +//! Constructs a `LSL #value` shift (logical shift left). +static constexpr Shift lsl(uint32_t value) noexcept { return Shift(Shift::kOpLSL, value); } +//! Constructs a `LSR #value` shift (logical shift right). +static constexpr Shift lsr(uint32_t value) noexcept { return Shift(Shift::kOpLSR, value); } +//! Constructs a `ASR #value` shift (arithmetic shift right). +static constexpr Shift asr(uint32_t value) noexcept { return Shift(Shift::kOpASR, value); } +//! Constructs a `ROR #value` shift (rotate right). +static constexpr Shift ror(uint32_t value) noexcept { return Shift(Shift::kOpROR, value); } +//! Constructs a `RRX` shift (rotate with carry by 1). +static constexpr Shift rrx() noexcept { return Shift(Shift::kOpRRX, 0); } +//! Constructs a `MSL #value` shift (logical shift left filling ones). +static constexpr Shift msl(uint32_t value) noexcept { return Shift(Shift::kOpMSL, value); } + +//! Constructs a `UXTB #value` extend and shift (unsigned byte extend). +static constexpr Shift uxtb(uint32_t value) noexcept { return Shift(Shift::kOpUXTB, value); } +//! Constructs a `UXTH #value` extend and shift (unsigned hword extend). +static constexpr Shift uxth(uint32_t value) noexcept { return Shift(Shift::kOpUXTH, value); } +//! Constructs a `UXTW #value` extend and shift (unsigned word extend). +static constexpr Shift uxtw(uint32_t value) noexcept { return Shift(Shift::kOpUXTW, value); } +//! Constructs a `UXTX #value` extend and shift (unsigned dword extend). +static constexpr Shift uxtx(uint32_t value) noexcept { return Shift(Shift::kOpUXTX, value); } + +//! Constructs a `SXTB #value` extend and shift (signed byte extend). +static constexpr Shift sxtb(uint32_t value) noexcept { return Shift(Shift::kOpSXTB, value); } +//! Constructs a `SXTH #value` extend and shift (signed hword extend). +static constexpr Shift sxth(uint32_t value) noexcept { return Shift(Shift::kOpSXTH, value); } +//! Constructs a `SXTW #value` extend and shift (signed word extend). +static constexpr Shift sxtw(uint32_t value) noexcept { return Shift(Shift::kOpSXTW, value); } +//! Constructs a `SXTX #value` extend and shift (signed dword extend). +static constexpr Shift sxtx(uint32_t value) noexcept { return Shift(Shift::kOpSXTX, value); } + +//! \} + +ASMJIT_END_SUB_NAMESPACE + +#endif // ASMJIT_CORE_ARCHCOMMONS_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/archtraits.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/archtraits.cpp new file mode 100644 index 0000000..f069354 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/archtraits.cpp @@ -0,0 +1,155 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/archtraits.h" +#include "../core/misc_p.h" + +#ifdef ASMJIT_BUILD_X86 + #include "../x86/x86archtraits_p.h" +#endif + +#ifdef ASMJIT_BUILD_ARM + #include "../arm/armarchtraits_p.h" +#endif + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::ArchTraits] +// ============================================================================ + +static const constexpr ArchTraits noArchTraits = { + 0xFF, // SP. + 0xFF, // FP. + 0xFF, // LR. + 0xFF, // PC. + { 0, 0, 0 }, // Reserved. + 0, // HW stack alignment. + 0, // Min stack offset. + 0, // Max stack offset. + { 0, 0, 0, 0}, // ISA features [Gp, Vec, Other0, Other1]. + { { 0 } }, // RegTypeToSignature. + { 0 }, // RegTypeToTypeId. + { 0 } // TypeIdToRegType. +}; + +ASMJIT_VARAPI const ArchTraits _archTraits[Environment::kArchCount] = { + // No architecture. + noArchTraits, + + // X86/X86 architectures. +#ifdef ASMJIT_BUILD_X86 + x86::x86ArchTraits, + x86::x64ArchTraits, +#else + noArchTraits, + noArchTraits, +#endif + + // RISCV32/RISCV64 architectures. + noArchTraits, + noArchTraits, + + // ARM architecture + noArchTraits, + + // AArch64 architecture. +#ifdef ASMJIT_BUILD_ARM + arm::a64ArchTraits, +#else + noArchTraits, +#endif + + // ARM/Thumb architecture. + noArchTraits, + + // Reserved. + noArchTraits, + + // MIPS32/MIPS64 + noArchTraits, + noArchTraits +}; + +// ============================================================================ +// [asmjit::ArchUtils] +// ============================================================================ + +ASMJIT_FAVOR_SIZE Error ArchUtils::typeIdToRegInfo(uint32_t arch, uint32_t typeId, uint32_t* typeIdOut, RegInfo* regInfoOut) noexcept { + const ArchTraits& archTraits = ArchTraits::byArch(arch); + + // Passed RegType instead of TypeId? + if (typeId <= BaseReg::kTypeMax) + typeId = archTraits.regTypeToTypeId(typeId); + + if (ASMJIT_UNLIKELY(!Type::isValid(typeId))) + return DebugUtils::errored(kErrorInvalidTypeId); + + // First normalize architecture dependent types. + if (Type::isAbstract(typeId)) { + bool is32Bit = Environment::is32Bit(arch); + if (typeId == Type::kIdIntPtr) + typeId = is32Bit ? Type::kIdI32 : Type::kIdI64; + else + typeId = is32Bit ? Type::kIdU32 : Type::kIdU64; + } + + // Type size helps to construct all groups of registers. + // TypeId is invalid if the size is zero. + uint32_t size = Type::sizeOf(typeId); + if (ASMJIT_UNLIKELY(!size)) + return DebugUtils::errored(kErrorInvalidTypeId); + + if (ASMJIT_UNLIKELY(typeId == Type::kIdF80)) + return DebugUtils::errored(kErrorInvalidUseOfF80); + + uint32_t regType = 0; + if (typeId >= Type::_kIdBaseStart && typeId < Type::_kIdVec32Start) { + regType = archTraits._typeIdToRegType[typeId - Type::_kIdBaseStart]; + if (!regType) { + if (typeId == Type::kIdI64 || typeId == Type::kIdU64) + return DebugUtils::errored(kErrorInvalidUseOfGpq); + else + return DebugUtils::errored(kErrorInvalidTypeId); + } + } + else { + if (size <= 8 && archTraits._regInfo[BaseReg::kTypeVec64].isValid()) + regType = BaseReg::kTypeVec64; + else if (size <= 16 && archTraits._regInfo[BaseReg::kTypeVec128].isValid()) + regType = BaseReg::kTypeVec128; + else if (size == 32 && archTraits._regInfo[BaseReg::kTypeVec256].isValid()) + regType = BaseReg::kTypeVec256; + else if (archTraits._regInfo[BaseReg::kTypeVec512].isValid()) + regType = BaseReg::kTypeVec512; + else + return DebugUtils::errored(kErrorInvalidTypeId); + } + + *typeIdOut = typeId; + regInfoOut->reset(archTraits.regTypeToSignature(regType)); + return kErrorOk; +} + +ASMJIT_END_NAMESPACE diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/archtraits.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/archtraits.h new file mode 100644 index 0000000..5af6c7e --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/archtraits.h @@ -0,0 +1,174 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_ARCHTRAITS_H_INCLUDED +#define ASMJIT_CORE_ARCHTRAITS_H_INCLUDED + +#include "../core/environment.h" +#include "../core/operand.h" +#include "../core/type.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_core +//! \{ + +// ============================================================================ +// [asmjit::ArchTraits] +// ============================================================================ + +//! Architecture traits used by Function API and Compiler's register allocator. +struct ArchTraits { + //! ISA features for each register group. + enum IsaFeatures : uint32_t { + //! ISA features a register swap by using a single instruction. + kIsaFeatureSwap = 0x01u, + //! ISA features a push/pop like instruction for this register group. + kIsaFeaturePushPop = 0x02u, + }; + + //! Stack pointer register id. + uint8_t _spRegId; + //! Frame pointer register id. + uint8_t _fpRegId; + //! Link register id. + uint8_t _linkRegId; + //! Instruction pointer (or program counter) register id, if accessible. + uint8_t _ipRegId; + + // Reserved. + uint8_t _reserved[3]; + //! Hardware stack alignment requirement. + uint8_t _hwStackAlignment; + //! Minimum addressable offset on stack guaranteed for all instructions. + uint32_t _minStackOffset; + //! Maximum addressable offset on stack depending on specific instruction. + uint32_t _maxStackOffset; + + //! Flags for each virtual register group (always covers GP and Vec groups). + uint8_t _isaFlags[BaseReg::kGroupVirt]; + + //! Maps register type into a signature, that provides group, size and can + //! be used to construct register operands. + RegInfo _regInfo[BaseReg::kTypeMax + 1]; + //! Maps a register to type-id, see \ref Type::Id. + uint8_t _regTypeToTypeId[BaseReg::kTypeMax + 1]; + //! Maps base TypeId values (from TypeId::_kIdBaseStart) to register types, see \ref Type::Id. + uint8_t _typeIdToRegType[32]; + + //! Resets all members to zeros. + inline void reset() noexcept { memset(this, 0, sizeof(*this)); } + + //! \name Accessors + //! \{ + + //! Returns stack pointer register id. + inline constexpr uint32_t spRegId() const noexcept { return _spRegId; } + //! Returns stack frame register id. + inline constexpr uint32_t fpRegId() const noexcept { return _fpRegId; } + //! Returns link register id, if the architecture provides it. + inline constexpr uint32_t linkRegId() const noexcept { return _linkRegId; } + //! Returns instruction pointer register id, if the architecture provides it. + inline constexpr uint32_t ipRegId() const noexcept { return _ipRegId; } + + //! Returns a hardware stack alignment requirement. + //! + //! \note This is a hardware constraint. Architectures that don't constrain + //! it would return the lowest alignment (1), however, some architectures may + //! constrain the alignment, for example AArch64 requires 16-byte alignment. + inline constexpr uint32_t hwStackAlignment() const noexcept { return _hwStackAlignment; } + + //! Tests whether the architecture provides link register, which is used across + //! function calls. If the link register is not provided then a function call + //! pushes the return address on stack (X86/X64). + inline constexpr bool hasLinkReg() const noexcept { return _linkRegId != BaseReg::kIdBad; } + + //! Returns minimum addressable offset on stack guaranteed for all instructions. + inline constexpr uint32_t minStackOffset() const noexcept { return _minStackOffset; } + //! Returns maximum addressable offset on stack depending on specific instruction. + inline constexpr uint32_t maxStackOffset() const noexcept { return _maxStackOffset; } + + //! Returns ISA flags of the given register `group`. + inline constexpr uint32_t isaFlags(uint32_t group) const noexcept { return _isaFlags[group]; } + //! Tests whether the given register `group` has the given `flag` set. + inline constexpr bool hasIsaFlag(uint32_t group, uint32_t flag) const noexcept { return (_isaFlags[group] & flag) != 0; } + //! Tests whether the ISA provides register swap instruction for the given register `group`. + inline constexpr bool hasSwap(uint32_t group) const noexcept { return hasIsaFlag(group, kIsaFeatureSwap); } + //! Tests whether the ISA provides push/pop instructions for the given register `group`. + inline constexpr bool hasPushPop(uint32_t group) const noexcept { return hasIsaFlag(group, kIsaFeaturePushPop); } + + inline uint32_t hasRegType(uint32_t rType) const noexcept { + return rType <= BaseReg::kTypeMax && _regInfo[rType].signature() != 0; + } + + inline uint32_t regTypeToSignature(uint32_t rType) const noexcept { + ASMJIT_ASSERT(rType <= BaseReg::kTypeMax); + return _regInfo[rType].signature(); + } + + inline uint32_t regTypeToGroup(uint32_t rType) const noexcept { + ASMJIT_ASSERT(rType <= BaseReg::kTypeMax); + return _regInfo[rType].group(); + } + + inline uint32_t regTypeToSize(uint32_t rType) const noexcept { + ASMJIT_ASSERT(rType <= BaseReg::kTypeMax); + return _regInfo[rType].size(); + } + + inline uint32_t regTypeToTypeId(uint32_t rType) const noexcept { + ASMJIT_ASSERT(rType <= BaseReg::kTypeMax); + return _regTypeToTypeId[rType]; + } + + //! \} + + //! \name Statics + //! \{ + + //! Returns a const reference to `ArchTraits` for the given architecture `arch`. + static inline const ArchTraits& byArch(uint32_t arch) noexcept; + + //! \} +}; + +ASMJIT_VARAPI const ArchTraits _archTraits[Environment::kArchCount]; + +inline const ArchTraits& ArchTraits::byArch(uint32_t arch) noexcept { return _archTraits[arch & ~Environment::kArchBigEndianMask]; } + +// ============================================================================ +// [asmjit::ArchUtils] +// ============================================================================ + +//! Architecture utilities. +namespace ArchUtils { + +ASMJIT_API Error typeIdToRegInfo(uint32_t arch, uint32_t typeId, uint32_t* typeIdOut, RegInfo* regInfo) noexcept; + +} // {ArchUtils} + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_ARCHTRAITS_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/assembler.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/assembler.cpp new file mode 100644 index 0000000..c0cbf0f --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/assembler.cpp @@ -0,0 +1,409 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/assembler.h" +#include "../core/codewriter_p.h" +#include "../core/constpool.h" +#include "../core/emitterutils_p.h" +#include "../core/formatter.h" +#include "../core/logger.h" +#include "../core/support.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::BaseAssembler - Construction / Destruction] +// ============================================================================ + +BaseAssembler::BaseAssembler() noexcept + : BaseEmitter(kTypeAssembler) {} + +BaseAssembler::~BaseAssembler() noexcept {} + +// ============================================================================ +// [asmjit::BaseAssembler - Buffer Management] +// ============================================================================ + +Error BaseAssembler::setOffset(size_t offset) { + if (ASMJIT_UNLIKELY(!_code)) + return reportError(DebugUtils::errored(kErrorNotInitialized)); + + size_t size = Support::max(_section->bufferSize(), this->offset()); + if (ASMJIT_UNLIKELY(offset > size)) + return reportError(DebugUtils::errored(kErrorInvalidArgument)); + + _bufferPtr = _bufferData + offset; + return kErrorOk; +} + +// ============================================================================ +// [asmjit::BaseAssembler - Section Management] +// ============================================================================ + +static void BaseAssembler_initSection(BaseAssembler* self, Section* section) noexcept { + uint8_t* p = section->_buffer._data; + + self->_section = section; + self->_bufferData = p; + self->_bufferPtr = p + section->_buffer._size; + self->_bufferEnd = p + section->_buffer._capacity; +} + +Error BaseAssembler::section(Section* section) { + if (ASMJIT_UNLIKELY(!_code)) + return reportError(DebugUtils::errored(kErrorNotInitialized)); + + if (!_code->isSectionValid(section->id()) || _code->_sections[section->id()] != section) + return reportError(DebugUtils::errored(kErrorInvalidSection)); + +#ifndef ASMJIT_NO_LOGGING + if (_logger) + _logger->logf(".section %s {#%u}\n", section->name(), section->id()); +#endif + + BaseAssembler_initSection(this, section); + return kErrorOk; +} + +// ============================================================================ +// [asmjit::BaseAssembler - Label Management] +// ============================================================================ + +Label BaseAssembler::newLabel() { + uint32_t labelId = Globals::kInvalidId; + if (ASMJIT_LIKELY(_code)) { + LabelEntry* le; + Error err = _code->newLabelEntry(&le); + if (ASMJIT_UNLIKELY(err)) + reportError(err); + else + labelId = le->id(); + } + return Label(labelId); +} + +Label BaseAssembler::newNamedLabel(const char* name, size_t nameSize, uint32_t type, uint32_t parentId) { + uint32_t labelId = Globals::kInvalidId; + if (ASMJIT_LIKELY(_code)) { + LabelEntry* le; + Error err = _code->newNamedLabelEntry(&le, name, nameSize, type, parentId); + if (ASMJIT_UNLIKELY(err)) + reportError(err); + else + labelId = le->id(); + } + return Label(labelId); +} + +Error BaseAssembler::bind(const Label& label) { + if (ASMJIT_UNLIKELY(!_code)) + return reportError(DebugUtils::errored(kErrorNotInitialized)); + + Error err = _code->bindLabel(label, _section->id(), offset()); + +#ifndef ASMJIT_NO_LOGGING + if (_logger) + EmitterUtils::logLabelBound(this, label); +#endif + + resetInlineComment(); + if (err) + return reportError(err); + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::BaseAssembler - Embed] +// ============================================================================ + +#ifndef ASMJIT_NO_LOGGING +struct DataSizeByPower { + char str[4]; +}; + +static const DataSizeByPower dataSizeByPowerTable[] = { + { "db" }, + { "dw" }, + { "dd" }, + { "dq" } +}; +#endif + +Error BaseAssembler::embed(const void* data, size_t dataSize) { + if (ASMJIT_UNLIKELY(!_code)) + return reportError(DebugUtils::errored(kErrorNotInitialized)); + + if (dataSize == 0) + return kErrorOk; + + CodeWriter writer(this); + ASMJIT_PROPAGATE(writer.ensureSpace(this, dataSize)); + + writer.emitData(data, dataSize); + +#ifndef ASMJIT_NO_LOGGING + if (_logger) + _logger->logBinary(data, dataSize); +#endif + + writer.done(this); + return kErrorOk; +} + +Error BaseAssembler::embedDataArray(uint32_t typeId, const void* data, size_t itemCcount, size_t repeatCount) { + uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize()); + uint32_t finalTypeId = Type::deabstract(typeId, deabstractDelta); + + if (ASMJIT_UNLIKELY(!Type::isValid(finalTypeId))) + return reportError(DebugUtils::errored(kErrorInvalidArgument)); + + if (itemCcount == 0 || repeatCount == 0) + return kErrorOk; + + uint32_t typeSize = Type::sizeOf(finalTypeId); + Support::FastUInt8 of = 0; + + size_t dataSize = Support::mulOverflow(itemCcount, size_t(typeSize), &of); + size_t totalSize = Support::mulOverflow(dataSize, repeatCount, &of); + + if (ASMJIT_UNLIKELY(of)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + + CodeWriter writer(this); + ASMJIT_PROPAGATE(writer.ensureSpace(this, totalSize)); + +#ifndef ASMJIT_NO_LOGGING + const uint8_t* start = writer.cursor(); +#endif + + for (size_t i = 0; i < repeatCount; i++) { + writer.emitData(data, dataSize); + } + +#ifndef ASMJIT_NO_LOGGING + if (_logger) + _logger->logBinary(start, totalSize); +#endif + + writer.done(this); + return kErrorOk; +} + +Error BaseAssembler::embedConstPool(const Label& label, const ConstPool& pool) { + if (ASMJIT_UNLIKELY(!_code)) + return reportError(DebugUtils::errored(kErrorNotInitialized)); + + if (ASMJIT_UNLIKELY(!isLabelValid(label))) + return reportError(DebugUtils::errored(kErrorInvalidLabel)); + + ASMJIT_PROPAGATE(align(kAlignData, uint32_t(pool.alignment()))); + ASMJIT_PROPAGATE(bind(label)); + + size_t size = pool.size(); + CodeWriter writer(this); + ASMJIT_PROPAGATE(writer.ensureSpace(this, size)); + + pool.fill(writer.cursor()); + +#ifndef ASMJIT_NO_LOGGING + if (_logger) + _logger->logBinary(writer.cursor(), size); +#endif + + writer.advance(size); + writer.done(this); + + return kErrorOk; +} + +Error BaseAssembler::embedLabel(const Label& label, size_t dataSize) { + if (ASMJIT_UNLIKELY(!_code)) + return reportError(DebugUtils::errored(kErrorNotInitialized)); + + ASMJIT_ASSERT(_code != nullptr); + RelocEntry* re; + LabelEntry* le = _code->labelEntry(label); + + if (ASMJIT_UNLIKELY(!le)) + return reportError(DebugUtils::errored(kErrorInvalidLabel)); + + if (dataSize == 0) + dataSize = registerSize(); + + if (ASMJIT_UNLIKELY(!Support::isPowerOf2(dataSize) || dataSize > 8)) + return reportError(DebugUtils::errored(kErrorInvalidOperandSize)); + + CodeWriter writer(this); + ASMJIT_PROPAGATE(writer.ensureSpace(this, dataSize)); + +#ifndef ASMJIT_NO_LOGGING + if (_logger) { + StringTmp<256> sb; + sb.appendFormat("%s ", dataSizeByPowerTable[Support::ctz(dataSize)].str); + Formatter::formatLabel(sb, 0, this, label.id()); + sb.append('\n'); + _logger->log(sb); + } +#endif + + Error err = _code->newRelocEntry(&re, RelocEntry::kTypeRelToAbs); + if (ASMJIT_UNLIKELY(err)) + return reportError(err); + + re->_sourceSectionId = _section->id(); + re->_sourceOffset = offset(); + re->_format.resetToDataValue(uint32_t(dataSize)); + + if (le->isBound()) { + re->_targetSectionId = le->section()->id(); + re->_payload = le->offset(); + } + else { + OffsetFormat of; + of.resetToDataValue(uint32_t(dataSize)); + + LabelLink* link = _code->newLabelLink(le, _section->id(), offset(), 0, of); + if (ASMJIT_UNLIKELY(!link)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + + link->relocId = re->id(); + } + + // Emit dummy DWORD/QWORD depending on the data size. + writer.emitZeros(dataSize); + writer.done(this); + + return kErrorOk; +} + +Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, size_t dataSize) { + if (ASMJIT_UNLIKELY(!_code)) + return reportError(DebugUtils::errored(kErrorNotInitialized)); + + LabelEntry* labelEntry = _code->labelEntry(label); + LabelEntry* baseEntry = _code->labelEntry(base); + + if (ASMJIT_UNLIKELY(!labelEntry || !baseEntry)) + return reportError(DebugUtils::errored(kErrorInvalidLabel)); + + if (dataSize == 0) + dataSize = registerSize(); + + if (ASMJIT_UNLIKELY(!Support::isPowerOf2(dataSize) || dataSize > 8)) + return reportError(DebugUtils::errored(kErrorInvalidOperandSize)); + + CodeWriter writer(this); + ASMJIT_PROPAGATE(writer.ensureSpace(this, dataSize)); + +#ifndef ASMJIT_NO_LOGGING + if (_logger) { + StringTmp<256> sb; + sb.appendFormat(".%s (", dataSizeByPowerTable[Support::ctz(dataSize)].str); + Formatter::formatLabel(sb, 0, this, label.id()); + sb.append(" - "); + Formatter::formatLabel(sb, 0, this, base.id()); + sb.append(")\n"); + _logger->log(sb); + } +#endif + + // If both labels are bound within the same section it means the delta can be calculated now. + if (labelEntry->isBound() && baseEntry->isBound() && labelEntry->section() == baseEntry->section()) { + uint64_t delta = labelEntry->offset() - baseEntry->offset(); + writer.emitValueLE(delta, dataSize); + } + else { + RelocEntry* re; + Error err = _code->newRelocEntry(&re, RelocEntry::kTypeExpression); + if (ASMJIT_UNLIKELY(err)) + return reportError(err); + + Expression* exp = _code->_zone.newT(); + if (ASMJIT_UNLIKELY(!exp)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + + exp->reset(); + exp->opType = Expression::kOpSub; + exp->setValueAsLabel(0, labelEntry); + exp->setValueAsLabel(1, baseEntry); + + re->_format.resetToDataValue(dataSize); + re->_sourceSectionId = _section->id(); + re->_sourceOffset = offset(); + re->_payload = (uint64_t)(uintptr_t)exp; + + writer.emitZeros(dataSize); + } + + writer.done(this); + return kErrorOk; +} + +// ============================================================================ +// [asmjit::BaseAssembler - Comment] +// ============================================================================ + +Error BaseAssembler::comment(const char* data, size_t size) { + if (!hasEmitterFlag(kFlagLogComments)) { + if (!hasEmitterFlag(kFlagAttached)) + return reportError(DebugUtils::errored(kErrorNotInitialized)); + return kErrorOk; + } + +#ifndef ASMJIT_NO_LOGGING + // Logger cannot be NULL if `kFlagLogComments` is set. + ASMJIT_ASSERT(_logger != nullptr); + + _logger->log(data, size); + _logger->log("\n", 1); + return kErrorOk; +#else + DebugUtils::unused(data, size); + return kErrorOk; +#endif +} + +// ============================================================================ +// [asmjit::BaseAssembler - Events] +// ============================================================================ + +Error BaseAssembler::onAttach(CodeHolder* code) noexcept { + ASMJIT_PROPAGATE(Base::onAttach(code)); + + // Attach to the end of the .text section. + BaseAssembler_initSection(this, code->_sections[0]); + + return kErrorOk; +} + +Error BaseAssembler::onDetach(CodeHolder* code) noexcept { + _section = nullptr; + _bufferData = nullptr; + _bufferEnd = nullptr; + _bufferPtr = nullptr; + return Base::onDetach(code); +} + +ASMJIT_END_NAMESPACE diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/assembler.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/assembler.h new file mode 100644 index 0000000..6e38bc5 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/assembler.h @@ -0,0 +1,152 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_ASSEMBLER_H_INCLUDED +#define ASMJIT_CORE_ASSEMBLER_H_INCLUDED + +#include "../core/codeholder.h" +#include "../core/datatypes.h" +#include "../core/emitter.h" +#include "../core/operand.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_assembler +//! \{ + +// ============================================================================ +// [asmjit::BaseAssembler] +// ============================================================================ + +//! Base assembler. +//! +//! This is a base class that provides interface used by architecture specific +//! assembler implementations. Assembler doesn't hold any data, instead it's +//! attached to \ref CodeHolder, which provides all the data that Assembler +//! needs and which can be altered by it. +//! +//! Check out architecture specific assemblers for more details and examples: +//! +//! - \ref x86::Assembler - X86/X64 assembler implementation. +class ASMJIT_VIRTAPI BaseAssembler : public BaseEmitter { +public: + ASMJIT_NONCOPYABLE(BaseAssembler) + typedef BaseEmitter Base; + + //! Current section where the assembling happens. + Section* _section = nullptr; + //! Start of the CodeBuffer of the current section. + uint8_t* _bufferData = nullptr; + //! End (first invalid byte) of the current section. + uint8_t* _bufferEnd = nullptr; + //! Pointer in the CodeBuffer of the current section. + uint8_t* _bufferPtr = nullptr; + + //! \name Construction & Destruction + //! \{ + + //! Creates a new `BaseAssembler` instance. + ASMJIT_API BaseAssembler() noexcept; + //! Destroys the `BaseAssembler` instance. + ASMJIT_API virtual ~BaseAssembler() noexcept; + + //! \} + + //! \name Code-Buffer Management + //! \{ + + //! Returns the capacity of the current CodeBuffer. + inline size_t bufferCapacity() const noexcept { return (size_t)(_bufferEnd - _bufferData); } + //! Returns the number of remaining bytes in the current CodeBuffer. + inline size_t remainingSpace() const noexcept { return (size_t)(_bufferEnd - _bufferPtr); } + + //! Returns the current position in the CodeBuffer. + inline size_t offset() const noexcept { return (size_t)(_bufferPtr - _bufferData); } + + //! Sets the current position in the CodeBuffer to `offset`. + //! + //! \note The `offset` cannot be greater than buffer size even if it's + //! within the buffer's capacity. + ASMJIT_API Error setOffset(size_t offset); + + //! Returns the start of the CodeBuffer in the current section. + inline uint8_t* bufferData() const noexcept { return _bufferData; } + //! Returns the end (first invalid byte) in the current section. + inline uint8_t* bufferEnd() const noexcept { return _bufferEnd; } + //! Returns the current pointer in the CodeBuffer in the current section. + inline uint8_t* bufferPtr() const noexcept { return _bufferPtr; } + + //! \} + + //! \name Section Management + //! \{ + + //! Returns the current section. + inline Section* currentSection() const noexcept { return _section; } + + ASMJIT_API Error section(Section* section) override; + + //! \} + + //! \name Label Management + //! \{ + + ASMJIT_API Label newLabel() override; + ASMJIT_API Label newNamedLabel(const char* name, size_t nameSize = SIZE_MAX, uint32_t type = Label::kTypeGlobal, uint32_t parentId = Globals::kInvalidId) override; + ASMJIT_API Error bind(const Label& label) override; + + //! \} + + //! \name Embed + //! \{ + + ASMJIT_API Error embed(const void* data, size_t dataSize) override; + ASMJIT_API Error embedDataArray(uint32_t typeId, const void* data, size_t itemCcount, size_t repeatCount = 1) override; + ASMJIT_API Error embedConstPool(const Label& label, const ConstPool& pool) override; + + ASMJIT_API Error embedLabel(const Label& label, size_t dataSize = 0) override; + ASMJIT_API Error embedLabelDelta(const Label& label, const Label& base, size_t dataSize = 0) override; + + //! \} + + //! \name Comment + //! \{ + + ASMJIT_API Error comment(const char* data, size_t size = SIZE_MAX) override; + + //! \} + + //! \name Events + //! \{ + + ASMJIT_API Error onAttach(CodeHolder* code) noexcept override; + ASMJIT_API Error onDetach(CodeHolder* code) noexcept override; + + //! \} +}; + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_ASSEMBLER_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/builder.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/builder.cpp new file mode 100644 index 0000000..ad89f1d --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/builder.cpp @@ -0,0 +1,920 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#ifndef ASMJIT_NO_BUILDER + +#include "../core/builder.h" +#include "../core/emitterutils_p.h" +#include "../core/errorhandler.h" +#include "../core/formatter.h" +#include "../core/logger.h" +#include "../core/support.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::PostponedErrorHandler (Internal)] +// ============================================================================ + +//! Postponed error handler that never throws. Used as a temporal error handler +//! to run passes. If error occurs, the caller is notified and will call the +//! real error handler, that can throw. +class PostponedErrorHandler : public ErrorHandler { +public: + void handleError(Error err, const char* message, BaseEmitter* origin) override { + DebugUtils::unused(err, origin); + _message.assign(message); + } + + StringTmp<128> _message; +}; + +// ============================================================================ +// [asmjit::BaseBuilder - Utilities] +// ============================================================================ + +static void BaseBuilder_deletePasses(BaseBuilder* self) noexcept { + for (Pass* pass : self->_passes) + pass->~Pass(); + self->_passes.reset(); +} + +// ============================================================================ +// [asmjit::BaseBuilder - Construction / Destruction] +// ============================================================================ + +BaseBuilder::BaseBuilder() noexcept + : BaseEmitter(kTypeBuilder), + _codeZone(32768 - Zone::kBlockOverhead), + _dataZone(16384 - Zone::kBlockOverhead), + _passZone(65536 - Zone::kBlockOverhead), + _allocator(&_codeZone) {} + +BaseBuilder::~BaseBuilder() noexcept { + BaseBuilder_deletePasses(this); +} + +// ============================================================================ +// [asmjit::BaseBuilder - Node Management] +// ============================================================================ + +Error BaseBuilder::_newInstNode(InstNode** out, uint32_t instId, uint32_t instOptions, uint32_t opCount) { + uint32_t opCapacity = InstNode::capacityOfOpCount(opCount); + ASMJIT_ASSERT(opCapacity >= InstNode::kBaseOpCapacity); + + InstNode* node = _allocator.allocT(InstNode::nodeSizeOfOpCapacity(opCapacity)); + if (ASMJIT_UNLIKELY(!node)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + + *out = new(node) InstNode(this, instId, instOptions, opCount, opCapacity); + return kErrorOk; +} + + +Error BaseBuilder::_newLabelNode(LabelNode** out) { + *out = nullptr; + + ASMJIT_PROPAGATE(_newNodeT(out)); + return registerLabelNode(*out); +} + +Error BaseBuilder::_newAlignNode(AlignNode** out, uint32_t alignMode, uint32_t alignment) { + *out = nullptr; + return _newNodeT(out, alignMode, alignment); +} + +Error BaseBuilder::_newEmbedDataNode(EmbedDataNode** out, uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount) { + *out = nullptr; + + uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize()); + uint32_t finalTypeId = Type::deabstract(typeId, deabstractDelta); + + if (ASMJIT_UNLIKELY(!Type::isValid(finalTypeId))) + return reportError(DebugUtils::errored(kErrorInvalidArgument)); + + uint32_t typeSize = Type::sizeOf(finalTypeId); + Support::FastUInt8 of = 0; + + size_t dataSize = Support::mulOverflow(itemCount, size_t(typeSize), &of); + if (ASMJIT_UNLIKELY(of)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + + EmbedDataNode* node; + ASMJIT_PROPAGATE(_newNodeT(&node)); + + node->_embed._typeId = uint8_t(typeId); + node->_embed._typeSize = uint8_t(typeSize); + node->_itemCount = itemCount; + node->_repeatCount = repeatCount; + + uint8_t* dstData = node->_inlineData; + if (dataSize > EmbedDataNode::kInlineBufferSize) { + dstData = static_cast(_dataZone.alloc(dataSize, 8)); + if (ASMJIT_UNLIKELY(!dstData)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + node->_externalData = dstData; + } + + if (data) + memcpy(dstData, data, dataSize); + + *out = node; + return kErrorOk; +} + +Error BaseBuilder::_newConstPoolNode(ConstPoolNode** out) { + *out = nullptr; + + ASMJIT_PROPAGATE(_newNodeT(out)); + return registerLabelNode(*out); +} + +Error BaseBuilder::_newCommentNode(CommentNode** out, const char* data, size_t size) { + *out = nullptr; + + if (data) { + if (size == SIZE_MAX) + size = strlen(data); + + if (size > 0) { + data = static_cast(_dataZone.dup(data, size, true)); + if (ASMJIT_UNLIKELY(!data)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + } + } + + return _newNodeT(out, data); +} + +BaseNode* BaseBuilder::addNode(BaseNode* node) noexcept { + ASMJIT_ASSERT(node); + ASMJIT_ASSERT(!node->_prev); + ASMJIT_ASSERT(!node->_next); + ASMJIT_ASSERT(!node->isActive()); + + if (!_cursor) { + if (!_firstNode) { + _firstNode = node; + _lastNode = node; + } + else { + node->_next = _firstNode; + _firstNode->_prev = node; + _firstNode = node; + } + } + else { + BaseNode* prev = _cursor; + BaseNode* next = _cursor->next(); + + node->_prev = prev; + node->_next = next; + + prev->_next = node; + if (next) + next->_prev = node; + else + _lastNode = node; + } + + node->addFlags(BaseNode::kFlagIsActive); + if (node->isSection()) + _dirtySectionLinks = true; + + _cursor = node; + return node; +} + +BaseNode* BaseBuilder::addAfter(BaseNode* node, BaseNode* ref) noexcept { + ASMJIT_ASSERT(node); + ASMJIT_ASSERT(ref); + + ASMJIT_ASSERT(!node->_prev); + ASMJIT_ASSERT(!node->_next); + + BaseNode* prev = ref; + BaseNode* next = ref->next(); + + node->_prev = prev; + node->_next = next; + + node->addFlags(BaseNode::kFlagIsActive); + if (node->isSection()) + _dirtySectionLinks = true; + + prev->_next = node; + if (next) + next->_prev = node; + else + _lastNode = node; + + return node; +} + +BaseNode* BaseBuilder::addBefore(BaseNode* node, BaseNode* ref) noexcept { + ASMJIT_ASSERT(node != nullptr); + ASMJIT_ASSERT(!node->_prev); + ASMJIT_ASSERT(!node->_next); + ASMJIT_ASSERT(!node->isActive()); + ASMJIT_ASSERT(ref != nullptr); + ASMJIT_ASSERT(ref->isActive()); + + BaseNode* prev = ref->prev(); + BaseNode* next = ref; + + node->_prev = prev; + node->_next = next; + + node->addFlags(BaseNode::kFlagIsActive); + if (node->isSection()) + _dirtySectionLinks = true; + + next->_prev = node; + if (prev) + prev->_next = node; + else + _firstNode = node; + + return node; +} + +BaseNode* BaseBuilder::removeNode(BaseNode* node) noexcept { + if (!node->isActive()) + return node; + + BaseNode* prev = node->prev(); + BaseNode* next = node->next(); + + if (_firstNode == node) + _firstNode = next; + else + prev->_next = next; + + if (_lastNode == node) + _lastNode = prev; + else + next->_prev = prev; + + node->_prev = nullptr; + node->_next = nullptr; + node->clearFlags(BaseNode::kFlagIsActive); + if (node->isSection()) + _dirtySectionLinks = true; + + if (_cursor == node) + _cursor = prev; + + return node; +} + +void BaseBuilder::removeNodes(BaseNode* first, BaseNode* last) noexcept { + if (first == last) { + removeNode(first); + return; + } + + if (!first->isActive()) + return; + + BaseNode* prev = first->prev(); + BaseNode* next = last->next(); + + if (_firstNode == first) + _firstNode = next; + else + prev->_next = next; + + if (_lastNode == last) + _lastNode = prev; + else + next->_prev = prev; + + BaseNode* node = first; + uint32_t didRemoveSection = false; + + for (;;) { + next = node->next(); + ASMJIT_ASSERT(next != nullptr); + + node->_prev = nullptr; + node->_next = nullptr; + node->clearFlags(BaseNode::kFlagIsActive); + didRemoveSection |= uint32_t(node->isSection()); + + if (_cursor == node) + _cursor = prev; + + if (node == last) + break; + node = next; + } + + if (didRemoveSection) + _dirtySectionLinks = true; +} + +BaseNode* BaseBuilder::setCursor(BaseNode* node) noexcept { + BaseNode* old = _cursor; + _cursor = node; + return old; +} + +// ============================================================================ +// [asmjit::BaseBuilder - Section] +// ============================================================================ + +Error BaseBuilder::sectionNodeOf(SectionNode** out, uint32_t sectionId) { + *out = nullptr; + + if (ASMJIT_UNLIKELY(!_code)) + return DebugUtils::errored(kErrorNotInitialized); + + if (ASMJIT_UNLIKELY(!_code->isSectionValid(sectionId))) + return reportError(DebugUtils::errored(kErrorInvalidSection)); + + if (sectionId >= _sectionNodes.size()) { + Error err = _sectionNodes.reserve(&_allocator, sectionId + 1); + if (ASMJIT_UNLIKELY(err != kErrorOk)) + return reportError(err); + } + + SectionNode* node = nullptr; + if (sectionId < _sectionNodes.size()) + node = _sectionNodes[sectionId]; + + if (!node) { + ASMJIT_PROPAGATE(_newNodeT(&node, sectionId)); + + // We have already reserved enough space, this cannot fail now. + if (sectionId >= _sectionNodes.size()) + _sectionNodes.resize(&_allocator, sectionId + 1); + + _sectionNodes[sectionId] = node; + } + + *out = node; + return kErrorOk; +} + +Error BaseBuilder::section(Section* section) { + SectionNode* node; + ASMJIT_PROPAGATE(sectionNodeOf(&node, section->id())); + + if (!node->isActive()) { + // Insert the section at the end if it was not part of the code. + addAfter(node, lastNode()); + _cursor = node; + } + else { + // This is a bit tricky. We cache section links to make sure that + // switching sections doesn't involve traversal in linked-list unless + // the position of the section has changed. + if (hasDirtySectionLinks()) + updateSectionLinks(); + + if (node->_nextSection) + _cursor = node->_nextSection->_prev; + else + _cursor = _lastNode; + } + + return kErrorOk; +} + +void BaseBuilder::updateSectionLinks() noexcept { + if (!_dirtySectionLinks) + return; + + BaseNode* node_ = _firstNode; + SectionNode* currentSection = nullptr; + + while (node_) { + if (node_->isSection()) { + if (currentSection) + currentSection->_nextSection = node_->as(); + currentSection = node_->as(); + } + node_ = node_->next(); + } + + if (currentSection) + currentSection->_nextSection = nullptr; + + _dirtySectionLinks = false; +} + +// ============================================================================ +// [asmjit::BaseBuilder - Labels] +// ============================================================================ + +Error BaseBuilder::labelNodeOf(LabelNode** out, uint32_t labelId) { + *out = nullptr; + + if (ASMJIT_UNLIKELY(!_code)) + return DebugUtils::errored(kErrorNotInitialized); + + uint32_t index = labelId; + if (ASMJIT_UNLIKELY(index >= _code->labelCount())) + return DebugUtils::errored(kErrorInvalidLabel); + + if (index >= _labelNodes.size()) + ASMJIT_PROPAGATE(_labelNodes.resize(&_allocator, index + 1)); + + LabelNode* node = _labelNodes[index]; + if (!node) { + ASMJIT_PROPAGATE(_newNodeT(&node, labelId)); + _labelNodes[index] = node; + } + + *out = node; + return kErrorOk; +} + +Error BaseBuilder::registerLabelNode(LabelNode* node) { + if (ASMJIT_UNLIKELY(!_code)) + return DebugUtils::errored(kErrorNotInitialized); + + LabelEntry* le; + ASMJIT_PROPAGATE(_code->newLabelEntry(&le)); + uint32_t labelId = le->id(); + + // We just added one label so it must be true. + ASMJIT_ASSERT(_labelNodes.size() < labelId + 1); + ASMJIT_PROPAGATE(_labelNodes.resize(&_allocator, labelId + 1)); + + _labelNodes[labelId] = node; + node->_labelId = labelId; + + return kErrorOk; +} + +static Error BaseBuilder_newLabelInternal(BaseBuilder* self, uint32_t labelId) { + ASMJIT_ASSERT(self->_labelNodes.size() < labelId + 1); + + uint32_t growBy = labelId - self->_labelNodes.size(); + Error err = self->_labelNodes.willGrow(&self->_allocator, growBy); + + if (ASMJIT_UNLIKELY(err)) + return self->reportError(err); + + LabelNode* node; + ASMJIT_PROPAGATE(self->_newNodeT(&node, labelId)); + + self->_labelNodes.resize(&self->_allocator, labelId + 1); + self->_labelNodes[labelId] = node; + node->_labelId = labelId; + return kErrorOk; +} + +Label BaseBuilder::newLabel() { + uint32_t labelId = Globals::kInvalidId; + LabelEntry* le; + + if (_code && + _code->newLabelEntry(&le) == kErrorOk && + BaseBuilder_newLabelInternal(this, le->id()) == kErrorOk) { + labelId = le->id(); + } + + return Label(labelId); +} + +Label BaseBuilder::newNamedLabel(const char* name, size_t nameSize, uint32_t type, uint32_t parentId) { + uint32_t labelId = Globals::kInvalidId; + LabelEntry* le; + + if (_code && + _code->newNamedLabelEntry(&le, name, nameSize, type, parentId) == kErrorOk && + BaseBuilder_newLabelInternal(this, le->id()) == kErrorOk) { + labelId = le->id(); + } + + return Label(labelId); +} + +Error BaseBuilder::bind(const Label& label) { + LabelNode* node; + ASMJIT_PROPAGATE(labelNodeOf(&node, label)); + + addNode(node); + return kErrorOk; +} + +// ============================================================================ +// [asmjit::BaseBuilder - Passes] +// ============================================================================ + +ASMJIT_FAVOR_SIZE Pass* BaseBuilder::passByName(const char* name) const noexcept { + for (Pass* pass : _passes) + if (strcmp(pass->name(), name) == 0) + return pass; + return nullptr; +} + +ASMJIT_FAVOR_SIZE Error BaseBuilder::addPass(Pass* pass) noexcept { + if (ASMJIT_UNLIKELY(!_code)) + return DebugUtils::errored(kErrorNotInitialized); + + if (ASMJIT_UNLIKELY(pass == nullptr)) { + // Since this is directly called by `addPassT()` we treat `null` argument + // as out-of-memory condition. Otherwise it would be API misuse. + return DebugUtils::errored(kErrorOutOfMemory); + } + else if (ASMJIT_UNLIKELY(pass->_cb)) { + // Kinda weird, but okay... + if (pass->_cb == this) + return kErrorOk; + return DebugUtils::errored(kErrorInvalidState); + } + + ASMJIT_PROPAGATE(_passes.append(&_allocator, pass)); + pass->_cb = this; + return kErrorOk; +} + +ASMJIT_FAVOR_SIZE Error BaseBuilder::deletePass(Pass* pass) noexcept { + if (ASMJIT_UNLIKELY(!_code)) + return DebugUtils::errored(kErrorNotInitialized); + + if (ASMJIT_UNLIKELY(pass == nullptr)) + return DebugUtils::errored(kErrorInvalidArgument); + + if (pass->_cb != nullptr) { + if (pass->_cb != this) + return DebugUtils::errored(kErrorInvalidState); + + uint32_t index = _passes.indexOf(pass); + ASMJIT_ASSERT(index != Globals::kNotFound); + + pass->_cb = nullptr; + _passes.removeAt(index); + } + + pass->~Pass(); + return kErrorOk; +} + +Error BaseBuilder::runPasses() { + if (ASMJIT_UNLIKELY(!_code)) + return DebugUtils::errored(kErrorNotInitialized); + + if (_passes.empty()) + return kErrorOk; + + ErrorHandler* prev = errorHandler(); + PostponedErrorHandler postponed; + + Error err = kErrorOk; + setErrorHandler(&postponed); + + for (Pass* pass : _passes) { + _passZone.reset(); + err = pass->run(&_passZone, _logger); + if (err) + break; + } + _passZone.reset(); + setErrorHandler(prev); + + if (ASMJIT_UNLIKELY(err)) + return reportError(err, !postponed._message.empty() ? postponed._message.data() : nullptr); + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::BaseBuilder - Emit] +// ============================================================================ + +Error BaseBuilder::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) { + uint32_t opCount = EmitterUtils::opCountFromEmitArgs(o0, o1, o2, opExt); + uint32_t options = instOptions() | forcedInstOptions(); + + if (options & BaseInst::kOptionReserved) { + if (ASMJIT_UNLIKELY(!_code)) + return DebugUtils::errored(kErrorNotInitialized); + +#ifndef ASMJIT_NO_VALIDATION + // Strict validation. + if (hasValidationOption(kValidationOptionIntermediate)) { + Operand_ opArray[Globals::kMaxOpCount]; + EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt); + + Error err = InstAPI::validate(arch(), BaseInst(instId, options, _extraReg), opArray, opCount); + if (ASMJIT_UNLIKELY(err)) { + resetInstOptions(); + resetExtraReg(); + resetInlineComment(); + return reportError(err); + } + } +#endif + + // Clear options that should never be part of `InstNode`. + options &= ~BaseInst::kOptionReserved; + } + + uint32_t opCapacity = InstNode::capacityOfOpCount(opCount); + ASMJIT_ASSERT(opCapacity >= InstNode::kBaseOpCapacity); + + InstNode* node = _allocator.allocT(InstNode::nodeSizeOfOpCapacity(opCapacity)); + const char* comment = inlineComment(); + + resetInstOptions(); + resetInlineComment(); + + if (ASMJIT_UNLIKELY(!node)) { + resetExtraReg(); + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + } + + node = new(node) InstNode(this, instId, options, opCount, opCapacity); + node->setExtraReg(extraReg()); + node->setOp(0, o0); + node->setOp(1, o1); + node->setOp(2, o2); + for (uint32_t i = 3; i < opCount; i++) + node->setOp(i, opExt[i - 3]); + node->resetOpRange(opCount, opCapacity); + + if (comment) + node->setInlineComment(static_cast(_dataZone.dup(comment, strlen(comment), true))); + + addNode(node); + resetExtraReg(); + return kErrorOk; +} + +// ============================================================================ +// [asmjit::BaseBuilder - Align] +// ============================================================================ + +Error BaseBuilder::align(uint32_t alignMode, uint32_t alignment) { + if (ASMJIT_UNLIKELY(!_code)) + return DebugUtils::errored(kErrorNotInitialized); + + AlignNode* node; + ASMJIT_PROPAGATE(_newAlignNode(&node, alignMode, alignment)); + + addNode(node); + return kErrorOk; +} + +// ============================================================================ +// [asmjit::BaseBuilder - Embed] +// ============================================================================ + +Error BaseBuilder::embed(const void* data, size_t dataSize) { + if (ASMJIT_UNLIKELY(!_code)) + return DebugUtils::errored(kErrorNotInitialized); + + EmbedDataNode* node; + ASMJIT_PROPAGATE(_newEmbedDataNode(&node, Type::kIdU8, data, dataSize)); + + addNode(node); + return kErrorOk; +} + +Error BaseBuilder::embedDataArray(uint32_t typeId, const void* data, size_t itemCount, size_t itemRepeat) { + if (ASMJIT_UNLIKELY(!_code)) + return DebugUtils::errored(kErrorNotInitialized); + + EmbedDataNode* node; + ASMJIT_PROPAGATE(_newEmbedDataNode(&node, typeId, data, itemCount, itemRepeat)); + + addNode(node); + return kErrorOk; +} + +Error BaseBuilder::embedConstPool(const Label& label, const ConstPool& pool) { + if (ASMJIT_UNLIKELY(!_code)) + return DebugUtils::errored(kErrorNotInitialized); + + if (!isLabelValid(label)) + return reportError(DebugUtils::errored(kErrorInvalidLabel)); + + ASMJIT_PROPAGATE(align(kAlignData, uint32_t(pool.alignment()))); + ASMJIT_PROPAGATE(bind(label)); + + EmbedDataNode* node; + ASMJIT_PROPAGATE(_newEmbedDataNode(&node, Type::kIdU8, nullptr, pool.size())); + + pool.fill(node->data()); + addNode(node); + return kErrorOk; +} + +// EmbedLabel / EmbedLabelDelta +// ---------------------------- +// +// If dataSize is zero it means that the size is the same as target register +// width, however, if it's provided we really want to validate whether it's +// within the possible range. + +static inline bool BaseBuilder_checkDataSize(size_t dataSize) noexcept { + return !dataSize || (Support::isPowerOf2(dataSize) && dataSize <= 8); +} + +Error BaseBuilder::embedLabel(const Label& label, size_t dataSize) { + if (ASMJIT_UNLIKELY(!_code)) + return DebugUtils::errored(kErrorNotInitialized); + + if (!BaseBuilder_checkDataSize(dataSize)) + return reportError(DebugUtils::errored(kErrorInvalidArgument)); + + EmbedLabelNode* node; + ASMJIT_PROPAGATE(_newNodeT(&node, label.id(), uint32_t(dataSize))); + + addNode(node); + return kErrorOk; +} + +Error BaseBuilder::embedLabelDelta(const Label& label, const Label& base, size_t dataSize) { + if (ASMJIT_UNLIKELY(!_code)) + return DebugUtils::errored(kErrorNotInitialized); + + if (!BaseBuilder_checkDataSize(dataSize)) + return reportError(DebugUtils::errored(kErrorInvalidArgument)); + + EmbedLabelDeltaNode* node; + ASMJIT_PROPAGATE(_newNodeT(&node, label.id(), base.id(), uint32_t(dataSize))); + + addNode(node); + return kErrorOk; +} + +// ============================================================================ +// [asmjit::BaseBuilder - Comment] +// ============================================================================ + +Error BaseBuilder::comment(const char* data, size_t size) { + if (ASMJIT_UNLIKELY(!_code)) + return DebugUtils::errored(kErrorNotInitialized); + + CommentNode* node; + ASMJIT_PROPAGATE(_newCommentNode(&node, data, size)); + + addNode(node); + return kErrorOk; +} + +// ============================================================================ +// [asmjit::BaseBuilder - Serialize] +// ============================================================================ + +Error BaseBuilder::serializeTo(BaseEmitter* dst) { + Error err = kErrorOk; + BaseNode* node_ = _firstNode; + + Operand_ opArray[Globals::kMaxOpCount]; + + do { + dst->setInlineComment(node_->inlineComment()); + + if (node_->isInst()) { + InstNode* node = node_->as(); + + // NOTE: Inlined to remove one additional call per instruction. + dst->setInstOptions(node->instOptions()); + dst->setExtraReg(node->extraReg()); + + const Operand_* op = node->operands(); + const Operand_* opExt = EmitterUtils::noExt; + + uint32_t opCount = node->opCount(); + if (opCount > 3) { + uint32_t i = 4; + opArray[3] = op[3]; + + while (i < opCount) { + opArray[i].copyFrom(op[i]); + i++; + } + while (i < Globals::kMaxOpCount) { + opArray[i].reset(); + i++; + } + opExt = opArray + 3; + } + + err = dst->_emit(node->id(), op[0], op[1], op[2], opExt); + } + else if (node_->isLabel()) { + if (node_->isConstPool()) { + ConstPoolNode* node = node_->as(); + err = dst->embedConstPool(node->label(), node->constPool()); + } + else { + LabelNode* node = node_->as(); + err = dst->bind(node->label()); + } + } + else if (node_->isAlign()) { + AlignNode* node = node_->as(); + err = dst->align(node->alignMode(), node->alignment()); + } + else if (node_->isEmbedData()) { + EmbedDataNode* node = node_->as(); + err = dst->embedDataArray(node->typeId(), node->data(), node->itemCount(), node->repeatCount()); + } + else if (node_->isEmbedLabel()) { + EmbedLabelNode* node = node_->as(); + err = dst->embedLabel(node->label(), node->dataSize()); + } + else if (node_->isEmbedLabelDelta()) { + EmbedLabelDeltaNode* node = node_->as(); + err = dst->embedLabelDelta(node->label(), node->baseLabel(), node->dataSize()); + } + else if (node_->isSection()) { + SectionNode* node = node_->as(); + err = dst->section(_code->sectionById(node->id())); + } + else if (node_->isComment()) { + CommentNode* node = node_->as(); + err = dst->comment(node->inlineComment()); + } + + if (err) break; + node_ = node_->next(); + } while (node_); + + return err; +} + +// ============================================================================ +// [asmjit::BaseBuilder - Events] +// ============================================================================ + +Error BaseBuilder::onAttach(CodeHolder* code) noexcept { + ASMJIT_PROPAGATE(Base::onAttach(code)); + + SectionNode* initialSection; + Error err = sectionNodeOf(&initialSection, 0); + + if (!err) + err = _passes.willGrow(&_allocator, 8); + + if (ASMJIT_UNLIKELY(err)) { + onDetach(code); + return err; + } + + _cursor = initialSection; + _firstNode = initialSection; + _lastNode = initialSection; + initialSection->setFlags(BaseNode::kFlagIsActive); + + return kErrorOk; +} + +Error BaseBuilder::onDetach(CodeHolder* code) noexcept { + BaseBuilder_deletePasses(this); + _sectionNodes.reset(); + _labelNodes.reset(); + + _allocator.reset(&_codeZone); + _codeZone.reset(); + _dataZone.reset(); + _passZone.reset(); + + _nodeFlags = 0; + + _cursor = nullptr; + _firstNode = nullptr; + _lastNode = nullptr; + + return Base::onDetach(code); +} + +// ============================================================================ +// [asmjit::Pass - Construction / Destruction] +// ============================================================================ + +Pass::Pass(const char* name) noexcept + : _name(name) {} +Pass::~Pass() noexcept {} + +ASMJIT_END_NAMESPACE + +#endif // !ASMJIT_NO_BUILDER diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/builder.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/builder.h new file mode 100644 index 0000000..317bda1 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/builder.h @@ -0,0 +1,1435 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_BUILDER_H_INCLUDED +#define ASMJIT_CORE_BUILDER_H_INCLUDED + +#include "../core/api-config.h" +#ifndef ASMJIT_NO_BUILDER + +#include "../core/assembler.h" +#include "../core/codeholder.h" +#include "../core/constpool.h" +#include "../core/formatter.h" +#include "../core/inst.h" +#include "../core/operand.h" +#include "../core/string.h" +#include "../core/support.h" +#include "../core/type.h" +#include "../core/zone.h" +#include "../core/zonevector.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_builder +//! \{ + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +class BaseBuilder; +class Pass; + +class BaseNode; +class InstNode; +class SectionNode; +class LabelNode; +class AlignNode; +class EmbedDataNode; +class EmbedLabelNode; +class ConstPoolNode; +class CommentNode; +class SentinelNode; +class LabelDeltaNode; + +// Only used by Compiler infrastructure. +class JumpAnnotation; + +// ============================================================================ +// [asmjit::BaseBuilder] +// ============================================================================ + +//! Builder interface. +//! +//! `BaseBuilder` interface was designed to be used as a \ref BaseAssembler +//! replacement in case pre-processing or post-processing of the generated code +//! is required. The code can be modified during or after code generation. Pre +//! or post processing can be done manually or through a \ref Pass object. \ref +//! BaseBuilder stores the emitted code as a double-linked list of nodes, which +//! allows O(1) insertion and removal during processing. +//! +//! Check out architecture specific builders for more details and examples: +//! +//! - \ref x86::Builder - X86/X64 builder implementation. +class ASMJIT_VIRTAPI BaseBuilder : public BaseEmitter { +public: + ASMJIT_NONCOPYABLE(BaseBuilder) + typedef BaseEmitter Base; + + //! Base zone used to allocate nodes and passes. + Zone _codeZone; + //! Data zone used to allocate data and names. + Zone _dataZone; + //! Pass zone, passed to `Pass::run()`. + Zone _passZone; + //! Allocator that uses `_codeZone`. + ZoneAllocator _allocator; + + //! Array of `Pass` objects. + ZoneVector _passes {}; + //! Maps section indexes to `LabelNode` nodes. + ZoneVector _sectionNodes {}; + //! Maps label indexes to `LabelNode` nodes. + ZoneVector _labelNodes {}; + + //! Current node (cursor). + BaseNode* _cursor = nullptr; + //! First node of the current section. + BaseNode* _firstNode = nullptr; + //! Last node of the current section. + BaseNode* _lastNode = nullptr; + + //! Flags assigned to each new node. + uint32_t _nodeFlags = 0; + //! The sections links are dirty (used internally). + bool _dirtySectionLinks = false; + + //! \name Construction & Destruction + //! \{ + + //! Creates a new `BaseBuilder` instance. + ASMJIT_API BaseBuilder() noexcept; + //! Destroys the `BaseBuilder` instance. + ASMJIT_API virtual ~BaseBuilder() noexcept; + + //! \} + + //! \name Node Management + //! \{ + + //! Returns the first node. + inline BaseNode* firstNode() const noexcept { return _firstNode; } + //! Returns the last node. + inline BaseNode* lastNode() const noexcept { return _lastNode; } + + //! Allocates and instantiates a new node of type `T` and returns its instance. + //! If the allocation fails `nullptr` is returned. + //! + //! The template argument `T` must be a type that is extends \ref BaseNode. + //! + //! \remarks The pointer returned (if non-null) is owned by the Builder or + //! Compiler. When the Builder/Compiler is destroyed it destroys all nodes + //! it created so no manual memory management is required. + template + inline Error _newNodeT(T** out, Args&&... args) { + *out = _allocator.newT(this, std::forward(args)...); + if (ASMJIT_UNLIKELY(!*out)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + return kErrorOk; + } + + //! Creates a new \ref InstNode. + ASMJIT_API Error _newInstNode(InstNode** out, uint32_t instId, uint32_t instOptions, uint32_t opCount); + //! Creates a new \ref LabelNode. + ASMJIT_API Error _newLabelNode(LabelNode** out); + //! Creates a new \ref AlignNode. + ASMJIT_API Error _newAlignNode(AlignNode** out, uint32_t alignMode, uint32_t alignment); + //! Creates a new \ref EmbedDataNode. + ASMJIT_API Error _newEmbedDataNode(EmbedDataNode** out, uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount = 1); + //! Creates a new \ref ConstPoolNode. + ASMJIT_API Error _newConstPoolNode(ConstPoolNode** out); + //! Creates a new \ref CommentNode. + ASMJIT_API Error _newCommentNode(CommentNode** out, const char* data, size_t size); + + //! Adds `node` after the current and sets the current node to the given `node`. + ASMJIT_API BaseNode* addNode(BaseNode* node) noexcept; + //! Inserts the given `node` after `ref`. + ASMJIT_API BaseNode* addAfter(BaseNode* node, BaseNode* ref) noexcept; + //! Inserts the given `node` before `ref`. + ASMJIT_API BaseNode* addBefore(BaseNode* node, BaseNode* ref) noexcept; + //! Removes the given `node`. + ASMJIT_API BaseNode* removeNode(BaseNode* node) noexcept; + //! Removes multiple nodes. + ASMJIT_API void removeNodes(BaseNode* first, BaseNode* last) noexcept; + + //! Returns the cursor. + //! + //! When the Builder/Compiler is created it automatically creates a '.text' + //! \ref SectionNode, which will be the initial one. When instructions are + //! added they are always added after the cursor and the cursor is changed + //! to be that newly added node. Use `setCursor()` to change where new nodes + //! are inserted. + inline BaseNode* cursor() const noexcept { + return _cursor; + } + + //! Sets the current node to `node` and return the previous one. + ASMJIT_API BaseNode* setCursor(BaseNode* node) noexcept; + + //! Sets the current node without returning the previous node. + //! + //! Only use this function if you are concerned about performance and want + //! this inlined (for example if you set the cursor in a loop, etc...). + inline void _setCursor(BaseNode* node) noexcept { + _cursor = node; + } + + //! \} + + //! \name Section Management + //! \{ + + //! Returns a vector of SectionNode objects. + //! + //! \note If a section of some id is not associated with the Builder/Compiler + //! it would be null, so always check for nulls if you iterate over the vector. + inline const ZoneVector& sectionNodes() const noexcept { + return _sectionNodes; + } + + //! Tests whether the `SectionNode` of the given `sectionId` was registered. + inline bool hasRegisteredSectionNode(uint32_t sectionId) const noexcept { + return sectionId < _sectionNodes.size() && _sectionNodes[sectionId] != nullptr; + } + + //! Returns or creates a `SectionNode` that matches the given `sectionId`. + //! + //! \remarks This function will either get the existing `SectionNode` or create + //! it in case it wasn't created before. You can check whether a section has a + //! registered `SectionNode` by using `BaseBuilder::hasRegisteredSectionNode()`. + ASMJIT_API Error sectionNodeOf(SectionNode** out, uint32_t sectionId); + + ASMJIT_API Error section(Section* section) override; + + //! Returns whether the section links of active section nodes are dirty. You can + //! update these links by calling `updateSectionLinks()` in such case. + inline bool hasDirtySectionLinks() const noexcept { return _dirtySectionLinks; } + + //! Updates links of all active section nodes. + ASMJIT_API void updateSectionLinks() noexcept; + + //! \} + + //! \name Label Management + //! \{ + + //! Returns a vector of \ref LabelNode nodes. + //! + //! \note If a label of some id is not associated with the Builder/Compiler + //! it would be null, so always check for nulls if you iterate over the vector. + inline const ZoneVector& labelNodes() const noexcept { return _labelNodes; } + + //! Tests whether the `LabelNode` of the given `labelId` was registered. + inline bool hasRegisteredLabelNode(uint32_t labelId) const noexcept { + return labelId < _labelNodes.size() && _labelNodes[labelId] != nullptr; + } + + //! \overload + inline bool hasRegisteredLabelNode(const Label& label) const noexcept { + return hasRegisteredLabelNode(label.id()); + } + + //! Gets or creates a \ref LabelNode that matches the given `labelId`. + //! + //! \remarks This function will either get the existing `LabelNode` or create + //! it in case it wasn't created before. You can check whether a label has a + //! registered `LabelNode` by calling \ref BaseBuilder::hasRegisteredLabelNode(). + ASMJIT_API Error labelNodeOf(LabelNode** out, uint32_t labelId); + + //! \overload + inline Error labelNodeOf(LabelNode** out, const Label& label) { + return labelNodeOf(out, label.id()); + } + + //! Registers this \ref LabelNode (internal). + //! + //! This function is used internally to register a newly created `LabelNode` + //! with this instance of Builder/Compiler. Use \ref labelNodeOf() functions + //! to get back \ref LabelNode from a label or its identifier. + ASMJIT_API Error registerLabelNode(LabelNode* node); + + ASMJIT_API Label newLabel() override; + ASMJIT_API Label newNamedLabel(const char* name, size_t nameSize = SIZE_MAX, uint32_t type = Label::kTypeGlobal, uint32_t parentId = Globals::kInvalidId) override; + ASMJIT_API Error bind(const Label& label) override; + + //! \} + + //! \name Passes + //! \{ + + //! Returns a vector of `Pass` instances that will be executed by `runPasses()`. + inline const ZoneVector& passes() const noexcept { return _passes; } + + //! Allocates and instantiates a new pass of type `T` and returns its instance. + //! If the allocation fails `nullptr` is returned. + //! + //! The template argument `T` must be a type that is extends \ref Pass. + //! + //! \remarks The pointer returned (if non-null) is owned by the Builder or + //! Compiler. When the Builder/Compiler is destroyed it destroys all passes + //! it created so no manual memory management is required. + template + inline T* newPassT() noexcept { return _codeZone.newT(); } + + //! \overload + template + inline T* newPassT(Args&&... args) noexcept { return _codeZone.newT(std::forward(args)...); } + + template + inline Error addPassT() { return addPass(newPassT()); } + + template + inline Error addPassT(Args&&... args) { return addPass(newPassT(std::forward(args)...)); } + + //! Returns `Pass` by name. + //! + //! If the pass having the given `name` doesn't exist `nullptr` is returned. + ASMJIT_API Pass* passByName(const char* name) const noexcept; + //! Adds `pass` to the list of passes. + ASMJIT_API Error addPass(Pass* pass) noexcept; + //! Removes `pass` from the list of passes and delete it. + ASMJIT_API Error deletePass(Pass* pass) noexcept; + + //! Runs all passes in order. + ASMJIT_API Error runPasses(); + + //! \} + + //! \name Emit + //! \{ + + ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) override; + + //! \} + + //! \name Align + //! \{ + + ASMJIT_API Error align(uint32_t alignMode, uint32_t alignment) override; + + //! \} + + //! \name Embed + //! \{ + + ASMJIT_API Error embed(const void* data, size_t dataSize) override; + ASMJIT_API Error embedDataArray(uint32_t typeId, const void* data, size_t count, size_t repeat = 1) override; + ASMJIT_API Error embedConstPool(const Label& label, const ConstPool& pool) override; + + ASMJIT_API Error embedLabel(const Label& label, size_t dataSize = 0) override; + ASMJIT_API Error embedLabelDelta(const Label& label, const Label& base, size_t dataSize = 0) override; + + //! \} + + //! \name Comment + //! \{ + + ASMJIT_API Error comment(const char* data, size_t size = SIZE_MAX) override; + + //! \} + + //! \name Serialization + //! \{ + + //! Serializes everything the given emitter `dst`. + //! + //! Although not explicitly required the emitter will most probably be of + //! Assembler type. The reason is that there is no known use of serializing + //! nodes held by Builder/Compiler into another Builder-like emitter. + ASMJIT_API Error serializeTo(BaseEmitter* dst); + + //! \} + + //! \name Events + //! \{ + + ASMJIT_API Error onAttach(CodeHolder* code) noexcept override; + ASMJIT_API Error onDetach(CodeHolder* code) noexcept override; + + //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use serializeTo() instead, serialize() is now also an instruction.") + inline Error serialize(BaseEmitter* dst) { + return serializeTo(dst); + } + +#ifndef ASMJIT_NO_LOGGING + ASMJIT_DEPRECATED("Use Formatter::formatNodeList(sb, formatFlags, builder)") + inline Error dump(String& sb, uint32_t formatFlags = 0) const noexcept { + return Formatter::formatNodeList(sb, formatFlags, this); + } +#endif // !ASMJIT_NO_LOGGING +#endif // !ASMJIT_NO_DEPRECATED +}; + +// ============================================================================ +// [asmjit::BaseNode] +// ============================================================================ + +//! Base node. +//! +//! Every node represents a building-block used by \ref BaseBuilder. It can +//! be instruction, data, label, comment, directive, or any other high-level +//! representation that can be transformed to the building blocks mentioned. +//! Every class that inherits \ref BaseBuilder can define its own high-level +//! nodes that can be later lowered to basic nodes like instructions. +class BaseNode { +public: + ASMJIT_NONCOPYABLE(BaseNode) + + union { + struct { + //! Previous node. + BaseNode* _prev; + //! Next node. + BaseNode* _next; + }; + //! Links (an alternative view to previous and next nodes). + BaseNode* _links[2]; + }; + + //! Data shared between all types of nodes. + struct AnyData { + //! Node type, see \ref NodeType. + uint8_t _nodeType; + //! Node flags, see \ref Flags. + uint8_t _nodeFlags; + //! Not used by BaseNode. + uint8_t _reserved0; + //! Not used by BaseNode. + uint8_t _reserved1; + }; + + //! Data used by \ref InstNode. + struct InstData { + //! Node type, see \ref NodeType. + uint8_t _nodeType; + //! Node flags, see \ref Flags. + uint8_t _nodeFlags; + //! Instruction operands count (used). + uint8_t _opCount; + //! Instruction operands capacity (allocated). + uint8_t _opCapacity; + }; + + //! Data used by \ref EmbedDataNode. + struct EmbedData { + //! Node type, see \ref NodeType. + uint8_t _nodeType; + //! Node flags, see \ref Flags. + uint8_t _nodeFlags; + //! Type id, see \ref Type::Id. + uint8_t _typeId; + //! Size of `_typeId`. + uint8_t _typeSize; + }; + + //! Data used by \ref SentinelNode. + struct SentinelData { + //! Node type, see \ref NodeType. + uint8_t _nodeType; + //! Node flags, see \ref Flags. + uint8_t _nodeFlags; + //! Sentinel type. + uint8_t _sentinelType; + //! Not used by BaseNode. + uint8_t _reserved1; + }; + + //! Data that can have different meaning dependning on \ref NodeType. + union { + //! Data useful by any node type. + AnyData _any; + //! Data specific to \ref InstNode. + InstData _inst; + //! Data specific to \ref EmbedDataNode. + EmbedData _embed; + //! Data specific to \ref SentinelNode. + SentinelData _sentinel; + }; + + //! Node position in code (should be unique). + uint32_t _position; + + //! Value reserved for AsmJit users never touched by AsmJit itself. + union { + //! User data as 64-bit integer. + uint64_t _userDataU64; + //! User data as pointer. + void* _userDataPtr; + }; + + //! Data used exclusively by the current `Pass`. + void* _passData; + + //! Inline comment/annotation or nullptr if not used. + const char* _inlineComment; + + //! Type of `BaseNode`. + enum NodeType : uint32_t { + //! Invalid node (internal, don't use). + kNodeNone = 0, + + // [BaseBuilder] + + //! Node is \ref InstNode or \ref InstExNode. + kNodeInst = 1, + //! Node is \ref SectionNode. + kNodeSection = 2, + //! Node is \ref LabelNode. + kNodeLabel = 3, + //! Node is \ref AlignNode. + kNodeAlign = 4, + //! Node is \ref EmbedDataNode. + kNodeEmbedData = 5, + //! Node is \ref EmbedLabelNode. + kNodeEmbedLabel = 6, + //! Node is \ref EmbedLabelDeltaNode. + kNodeEmbedLabelDelta = 7, + //! Node is \ref ConstPoolNode. + kNodeConstPool = 8, + //! Node is \ref CommentNode. + kNodeComment = 9, + //! Node is \ref SentinelNode. + kNodeSentinel = 10, + + // [BaseCompiler] + + //! Node is \ref JumpNode (acts as InstNode). + kNodeJump = 15, + //! Node is \ref FuncNode (acts as LabelNode). + kNodeFunc = 16, + //! Node is \ref FuncRetNode (acts as InstNode). + kNodeFuncRet = 17, + //! Node is \ref InvokeNode (acts as InstNode). + kNodeInvoke = 18, + + // [UserDefined] + + //! First id of a user-defined node. + kNodeUser = 32, + +#ifndef ASMJIT_NO_DEPRECATED + kNodeFuncCall = kNodeInvoke +#endif // !ASMJIT_NO_DEPRECATED + }; + + //! Node flags, specify what the node is and/or does. + enum Flags : uint32_t { + //! Node is code that can be executed (instruction, label, align, etc...). + kFlagIsCode = 0x01u, + //! Node is data that cannot be executed (data, const-pool, etc...). + kFlagIsData = 0x02u, + //! Node is informative, can be removed and ignored. + kFlagIsInformative = 0x04u, + //! Node can be safely removed if unreachable. + kFlagIsRemovable = 0x08u, + //! Node does nothing when executed (label, align, explicit nop). + kFlagHasNoEffect = 0x10u, + //! Node is an instruction or acts as it. + kFlagActsAsInst = 0x20u, + //! Node is a label or acts as it. + kFlagActsAsLabel = 0x40u, + //! Node is active (part of the code). + kFlagIsActive = 0x80u + }; + + //! \name Construction & Destruction + //! \{ + + //! Creates a new `BaseNode` - always use `BaseBuilder` to allocate nodes. + ASMJIT_INLINE BaseNode(BaseBuilder* cb, uint32_t type, uint32_t flags = 0) noexcept { + _prev = nullptr; + _next = nullptr; + _any._nodeType = uint8_t(type); + _any._nodeFlags = uint8_t(flags | cb->_nodeFlags); + _any._reserved0 = 0; + _any._reserved1 = 0; + _position = 0; + _userDataU64 = 0; + _passData = nullptr; + _inlineComment = nullptr; + } + + //! \} + + //! \name Accessors + //! \{ + + //! Casts this node to `T*`. + template + inline T* as() noexcept { return static_cast(this); } + //! Casts this node to `const T*`. + template + inline const T* as() const noexcept { return static_cast(this); } + + //! Returns previous node or `nullptr` if this node is either first or not + //! part of Builder/Compiler node-list. + inline BaseNode* prev() const noexcept { return _prev; } + //! Returns next node or `nullptr` if this node is either last or not part + //! of Builder/Compiler node-list. + inline BaseNode* next() const noexcept { return _next; } + + //! Returns the type of the node, see `NodeType`. + inline uint32_t type() const noexcept { return _any._nodeType; } + + //! Sets the type of the node, see `NodeType` (internal). + //! + //! \remarks You should never set a type of a node to anything else than the + //! initial value. This function is only provided for users that use custom + //! nodes and need to change the type either during construction or later. + inline void setType(uint32_t type) noexcept { _any._nodeType = uint8_t(type); } + + //! Tests whether this node is either `InstNode` or extends it. + inline bool isInst() const noexcept { return hasFlag(kFlagActsAsInst); } + //! Tests whether this node is `SectionNode`. + inline bool isSection() const noexcept { return type() == kNodeSection; } + //! Tests whether this node is either `LabelNode` or extends it. + inline bool isLabel() const noexcept { return hasFlag(kFlagActsAsLabel); } + //! Tests whether this node is `AlignNode`. + inline bool isAlign() const noexcept { return type() == kNodeAlign; } + //! Tests whether this node is `EmbedDataNode`. + inline bool isEmbedData() const noexcept { return type() == kNodeEmbedData; } + //! Tests whether this node is `EmbedLabelNode`. + inline bool isEmbedLabel() const noexcept { return type() == kNodeEmbedLabel; } + //! Tests whether this node is `EmbedLabelDeltaNode`. + inline bool isEmbedLabelDelta() const noexcept { return type() == kNodeEmbedLabelDelta; } + //! Tests whether this node is `ConstPoolNode`. + inline bool isConstPool() const noexcept { return type() == kNodeConstPool; } + //! Tests whether this node is `CommentNode`. + inline bool isComment() const noexcept { return type() == kNodeComment; } + //! Tests whether this node is `SentinelNode`. + inline bool isSentinel() const noexcept { return type() == kNodeSentinel; } + + //! Tests whether this node is `FuncNode`. + inline bool isFunc() const noexcept { return type() == kNodeFunc; } + //! Tests whether this node is `FuncRetNode`. + inline bool isFuncRet() const noexcept { return type() == kNodeFuncRet; } + //! Tests whether this node is `InvokeNode`. + inline bool isInvoke() const noexcept { return type() == kNodeInvoke; } + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use isInvoke") + inline bool isFuncCall() const noexcept { return isInvoke(); } +#endif // !ASMJIT_NO_DEPRECATED + + //! Returns the node flags, see \ref Flags. + inline uint32_t flags() const noexcept { return _any._nodeFlags; } + //! Tests whether the node has the given `flag` set. + inline bool hasFlag(uint32_t flag) const noexcept { return (uint32_t(_any._nodeFlags) & flag) != 0; } + //! Replaces node flags with `flags`. + inline void setFlags(uint32_t flags) noexcept { _any._nodeFlags = uint8_t(flags); } + //! Adds the given `flags` to node flags. + inline void addFlags(uint32_t flags) noexcept { _any._nodeFlags = uint8_t(_any._nodeFlags | flags); } + //! Clears the given `flags` from node flags. + inline void clearFlags(uint32_t flags) noexcept { _any._nodeFlags = uint8_t(_any._nodeFlags & (flags ^ 0xFF)); } + + //! Tests whether the node is code that can be executed. + inline bool isCode() const noexcept { return hasFlag(kFlagIsCode); } + //! Tests whether the node is data that cannot be executed. + inline bool isData() const noexcept { return hasFlag(kFlagIsData); } + //! Tests whether the node is informative only (is never encoded like comment, etc...). + inline bool isInformative() const noexcept { return hasFlag(kFlagIsInformative); } + //! Tests whether the node is removable if it's in an unreachable code block. + inline bool isRemovable() const noexcept { return hasFlag(kFlagIsRemovable); } + //! Tests whether the node has no effect when executed (label, .align, nop, ...). + inline bool hasNoEffect() const noexcept { return hasFlag(kFlagHasNoEffect); } + //! Tests whether the node is part of the code. + inline bool isActive() const noexcept { return hasFlag(kFlagIsActive); } + + //! Tests whether the node has a position assigned. + //! + //! \remarks Returns `true` if node position is non-zero. + inline bool hasPosition() const noexcept { return _position != 0; } + //! Returns node position. + inline uint32_t position() const noexcept { return _position; } + //! Sets node position. + //! + //! Node position is a 32-bit unsigned integer that is used by Compiler to + //! track where the node is relatively to the start of the function. It doesn't + //! describe a byte position in a binary, instead it's just a pseudo position + //! used by liveness analysis and other tools around Compiler. + //! + //! If you don't use Compiler then you may use `position()` and `setPosition()` + //! freely for your own purposes if the 32-bit value limit is okay for you. + inline void setPosition(uint32_t position) noexcept { _position = position; } + + //! Returns user data casted to `T*`. + //! + //! User data is decicated to be used only by AsmJit users and not touched + //! by the library. The data has a pointer size so you can either store a + //! pointer or `intptr_t` value through `setUserDataAsIntPtr()`. + template + inline T* userDataAsPtr() const noexcept { return static_cast(_userDataPtr); } + //! Returns user data casted to `int64_t`. + inline int64_t userDataAsInt64() const noexcept { return int64_t(_userDataU64); } + //! Returns user data casted to `uint64_t`. + inline uint64_t userDataAsUInt64() const noexcept { return _userDataU64; } + + //! Sets user data to `data`. + template + inline void setUserDataAsPtr(T* data) noexcept { _userDataPtr = static_cast(data); } + //! Sets used data to the given 64-bit signed `value`. + inline void setUserDataAsInt64(int64_t value) noexcept { _userDataU64 = uint64_t(value); } + //! Sets used data to the given 64-bit unsigned `value`. + inline void setUserDataAsUInt64(uint64_t value) noexcept { _userDataU64 = value; } + + //! Resets user data to zero / nullptr. + inline void resetUserData() noexcept { _userDataU64 = 0; } + + //! Tests whether the node has an associated pass data. + inline bool hasPassData() const noexcept { return _passData != nullptr; } + //! Returns the node pass data - data used during processing & transformations. + template + inline T* passData() const noexcept { return (T*)_passData; } + //! Sets the node pass data to `data`. + template + inline void setPassData(T* data) noexcept { _passData = (void*)data; } + //! Resets the node pass data to nullptr. + inline void resetPassData() noexcept { _passData = nullptr; } + + //! Tests whether the node has an inline comment/annotation. + inline bool hasInlineComment() const noexcept { return _inlineComment != nullptr; } + //! Returns an inline comment/annotation string. + inline const char* inlineComment() const noexcept { return _inlineComment; } + //! Sets an inline comment/annotation string to `s`. + inline void setInlineComment(const char* s) noexcept { _inlineComment = s; } + //! Resets an inline comment/annotation string to nullptr. + inline void resetInlineComment() noexcept { _inlineComment = nullptr; } + + //! \} +}; + +// ============================================================================ +// [asmjit::InstNode] +// ============================================================================ + +//! Instruction node. +//! +//! Wraps an instruction with its options and operands. +class InstNode : public BaseNode { +public: + ASMJIT_NONCOPYABLE(InstNode) + + enum : uint32_t { + //! Count of embedded operands per `InstNode` that are always allocated as + //! a part of the instruction. Minimum embedded operands is 4, but in 32-bit + //! more pointers are smaller and we can embed 5. The rest (up to 6 operands) + //! is always stored in `InstExNode`. + kBaseOpCapacity = uint32_t((128 - sizeof(BaseNode) - sizeof(BaseInst)) / sizeof(Operand_)) + }; + + //! Base instruction data. + BaseInst _baseInst; + //! First 4 or 5 operands (indexed from 0). + Operand_ _opArray[kBaseOpCapacity]; + + //! \name Construction & Destruction + //! \{ + + //! Creates a new `InstNode` instance. + ASMJIT_INLINE InstNode(BaseBuilder* cb, uint32_t instId, uint32_t options, uint32_t opCount, uint32_t opCapacity = kBaseOpCapacity) noexcept + : BaseNode(cb, kNodeInst, kFlagIsCode | kFlagIsRemovable | kFlagActsAsInst), + _baseInst(instId, options) { + _inst._opCapacity = uint8_t(opCapacity); + _inst._opCount = uint8_t(opCount); + } + + //! \cond INTERNAL + //! Reset all built-in operands, including `extraReg`. + inline void _resetOps() noexcept { + _baseInst.resetExtraReg(); + resetOpRange(0, opCapacity()); + } + //! \endcond + + //! \} + + //! \name Accessors + //! \{ + + inline BaseInst& baseInst() noexcept { return _baseInst; } + inline const BaseInst& baseInst() const noexcept { return _baseInst; } + + //! Returns the instruction id, see `BaseInst::Id`. + inline uint32_t id() const noexcept { return _baseInst.id(); } + //! Sets the instruction id to `id`, see `BaseInst::Id`. + inline void setId(uint32_t id) noexcept { _baseInst.setId(id); } + + //! Returns instruction options. + inline uint32_t instOptions() const noexcept { return _baseInst.options(); } + //! Sets instruction options. + inline void setInstOptions(uint32_t options) noexcept { _baseInst.setOptions(options); } + //! Adds instruction options. + inline void addInstOptions(uint32_t options) noexcept { _baseInst.addOptions(options); } + //! Clears instruction options. + inline void clearInstOptions(uint32_t options) noexcept { _baseInst.clearOptions(options); } + + //! Tests whether the node has an extra register operand. + inline bool hasExtraReg() const noexcept { return _baseInst.hasExtraReg(); } + //! Returns extra register operand. + inline RegOnly& extraReg() noexcept { return _baseInst.extraReg(); } + //! \overload + inline const RegOnly& extraReg() const noexcept { return _baseInst.extraReg(); } + //! Sets extra register operand to `reg`. + inline void setExtraReg(const BaseReg& reg) noexcept { _baseInst.setExtraReg(reg); } + //! Sets extra register operand to `reg`. + inline void setExtraReg(const RegOnly& reg) noexcept { _baseInst.setExtraReg(reg); } + //! Resets extra register operand. + inline void resetExtraReg() noexcept { _baseInst.resetExtraReg(); } + + //! Returns operand count. + inline uint32_t opCount() const noexcept { return _inst._opCount; } + //! Returns operand capacity. + inline uint32_t opCapacity() const noexcept { return _inst._opCapacity; } + + //! Sets operand count. + inline void setOpCount(uint32_t opCount) noexcept { _inst._opCount = uint8_t(opCount); } + + //! Returns operands array. + inline Operand* operands() noexcept { return (Operand*)_opArray; } + //! Returns operands array (const). + inline const Operand* operands() const noexcept { return (const Operand*)_opArray; } + + //! Returns operand at the given `index`. + inline Operand& op(uint32_t index) noexcept { + ASMJIT_ASSERT(index < opCapacity()); + return _opArray[index].as(); + } + + //! Returns operand at the given `index` (const). + inline const Operand& op(uint32_t index) const noexcept { + ASMJIT_ASSERT(index < opCapacity()); + return _opArray[index].as(); + } + + //! Sets operand at the given `index` to `op`. + inline void setOp(uint32_t index, const Operand_& op) noexcept { + ASMJIT_ASSERT(index < opCapacity()); + _opArray[index].copyFrom(op); + } + + //! Resets operand at the given `index` to none. + inline void resetOp(uint32_t index) noexcept { + ASMJIT_ASSERT(index < opCapacity()); + _opArray[index].reset(); + } + + //! Resets operands at `[start, end)` range. + inline void resetOpRange(uint32_t start, uint32_t end) noexcept { + for (uint32_t i = start; i < end; i++) + _opArray[i].reset(); + } + + //! \} + + //! \name Utilities + //! \{ + + inline bool hasOpType(uint32_t opType) const noexcept { + for (uint32_t i = 0, count = opCount(); i < count; i++) + if (_opArray[i].opType() == opType) + return true; + return false; + } + + inline bool hasRegOp() const noexcept { return hasOpType(Operand::kOpReg); } + inline bool hasMemOp() const noexcept { return hasOpType(Operand::kOpMem); } + inline bool hasImmOp() const noexcept { return hasOpType(Operand::kOpImm); } + inline bool hasLabelOp() const noexcept { return hasOpType(Operand::kOpLabel); } + + inline uint32_t indexOfOpType(uint32_t opType) const noexcept { + uint32_t i = 0; + uint32_t count = opCount(); + + while (i < count) { + if (_opArray[i].opType() == opType) + break; + i++; + } + + return i; + } + + inline uint32_t indexOfMemOp() const noexcept { return indexOfOpType(Operand::kOpMem); } + inline uint32_t indexOfImmOp() const noexcept { return indexOfOpType(Operand::kOpImm); } + inline uint32_t indexOfLabelOp() const noexcept { return indexOfOpType(Operand::kOpLabel); } + + //! \} + + //! \name Rewriting + //! \{ + + //! \cond INTERNAL + inline uint32_t* _getRewriteArray() noexcept { return &_baseInst._extraReg._id; } + inline const uint32_t* _getRewriteArray() const noexcept { return &_baseInst._extraReg._id; } + + ASMJIT_INLINE uint32_t getRewriteIndex(const uint32_t* id) const noexcept { + const uint32_t* array = _getRewriteArray(); + ASMJIT_ASSERT(array <= id); + + size_t index = (size_t)(id - array); + ASMJIT_ASSERT(index < 32); + + return uint32_t(index); + } + + ASMJIT_INLINE void rewriteIdAtIndex(uint32_t index, uint32_t id) noexcept { + uint32_t* array = _getRewriteArray(); + array[index] = id; + } + //! \endcond + + //! \} + + //! \name Static Functions + //! \{ + + //! \cond INTERNAL + static inline uint32_t capacityOfOpCount(uint32_t opCount) noexcept { + return opCount <= kBaseOpCapacity ? kBaseOpCapacity : Globals::kMaxOpCount; + } + + static inline size_t nodeSizeOfOpCapacity(uint32_t opCapacity) noexcept { + size_t base = sizeof(InstNode) - kBaseOpCapacity * sizeof(Operand); + return base + opCapacity * sizeof(Operand); + } + //! \endcond + + //! \} +}; + +// ============================================================================ +// [asmjit::InstExNode] +// ============================================================================ + +//! Instruction node with maximum number of operands. +//! +//! This node is created automatically by Builder/Compiler in case that the +//! required number of operands exceeds the default capacity of `InstNode`. +class InstExNode : public InstNode { +public: + ASMJIT_NONCOPYABLE(InstExNode) + + //! Continued `_opArray[]` to hold up to `kMaxOpCount` operands. + Operand_ _opArrayEx[Globals::kMaxOpCount - kBaseOpCapacity]; + + //! \name Construction & Destruction + //! \{ + + //! Creates a new `InstExNode` instance. + inline InstExNode(BaseBuilder* cb, uint32_t instId, uint32_t options, uint32_t opCapacity = Globals::kMaxOpCount) noexcept + : InstNode(cb, instId, options, opCapacity) {} + + //! \} +}; + +// ============================================================================ +// [asmjit::SectionNode] +// ============================================================================ + +//! Section node. +class SectionNode : public BaseNode { +public: + ASMJIT_NONCOPYABLE(SectionNode) + + //! Section id. + uint32_t _id; + + //! Next section node that follows this section. + //! + //! This link is only valid when the section is active (is part of the code) + //! and when `Builder::hasDirtySectionLinks()` returns `false`. If you intend + //! to use this field you should always call `Builder::updateSectionLinks()` + //! before you do so. + SectionNode* _nextSection; + + //! \name Construction & Destruction + //! \{ + + //! Creates a new `SectionNode` instance. + inline SectionNode(BaseBuilder* cb, uint32_t id = 0) noexcept + : BaseNode(cb, kNodeSection, kFlagHasNoEffect), + _id(id), + _nextSection(nullptr) {} + + //! \} + + //! \name Accessors + //! \{ + + //! Returns the section id. + inline uint32_t id() const noexcept { return _id; } + + //! \} +}; + +// ============================================================================ +// [asmjit::LabelNode] +// ============================================================================ + +//! Label node. +class LabelNode : public BaseNode { +public: + ASMJIT_NONCOPYABLE(LabelNode) + + //! Label identifier. + uint32_t _labelId; + + //! \name Construction & Destruction + //! \{ + + //! Creates a new `LabelNode` instance. + inline LabelNode(BaseBuilder* cb, uint32_t labelId = 0) noexcept + : BaseNode(cb, kNodeLabel, kFlagHasNoEffect | kFlagActsAsLabel), + _labelId(labelId) {} + + //! \} + + //! \name Accessors + //! \{ + + //! Returns \ref Label representation of the \ref LabelNode. + inline Label label() const noexcept { return Label(_labelId); } + //! Returns the id of the label. + inline uint32_t labelId() const noexcept { return _labelId; } + + //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use labelId() instead") + inline uint32_t id() const noexcept { return labelId(); } +#endif // !ASMJIT_NO_DEPRECATED +}; + +// ============================================================================ +// [asmjit::AlignNode] +// ============================================================================ + +//! Align directive (BaseBuilder). +//! +//! Wraps `.align` directive. +class AlignNode : public BaseNode { +public: + ASMJIT_NONCOPYABLE(AlignNode) + + //! Align mode, see `AlignMode`. + uint32_t _alignMode; + //! Alignment (in bytes). + uint32_t _alignment; + + //! \name Construction & Destruction + //! \{ + + //! Creates a new `AlignNode` instance. + inline AlignNode(BaseBuilder* cb, uint32_t alignMode, uint32_t alignment) noexcept + : BaseNode(cb, kNodeAlign, kFlagIsCode | kFlagHasNoEffect), + _alignMode(alignMode), + _alignment(alignment) {} + + //! \} + + //! \name Accessors + //! \{ + + //! Returns align mode. + inline uint32_t alignMode() const noexcept { return _alignMode; } + //! Sets align mode to `alignMode`. + inline void setAlignMode(uint32_t alignMode) noexcept { _alignMode = alignMode; } + + //! Returns align offset in bytes. + inline uint32_t alignment() const noexcept { return _alignment; } + //! Sets align offset in bytes to `offset`. + inline void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; } + + //! \} +}; + +// ============================================================================ +// [asmjit::EmbedDataNode] +// ============================================================================ + +//! Embed data node. +//! +//! Wraps `.data` directive. The node contains data that will be placed at the +//! node's position in the assembler stream. The data is considered to be RAW; +//! no analysis nor byte-order conversion is performed on RAW data. +class EmbedDataNode : public BaseNode { +public: + ASMJIT_NONCOPYABLE(EmbedDataNode) + + enum : uint32_t { + kInlineBufferSize = 128 - (sizeof(BaseNode) + sizeof(size_t) * 2) + }; + + size_t _itemCount; + size_t _repeatCount; + + union { + uint8_t* _externalData; + uint8_t _inlineData[kInlineBufferSize]; + }; + + //! \name Construction & Destruction + //! \{ + + //! Creates a new `EmbedDataNode` instance. + inline EmbedDataNode(BaseBuilder* cb) noexcept + : BaseNode(cb, kNodeEmbedData, kFlagIsData), + _itemCount(0), + _repeatCount(0) { + _embed._typeId = uint8_t(Type::kIdU8), + _embed._typeSize = uint8_t(1); + memset(_inlineData, 0, kInlineBufferSize); + } + + //! \} + + //! \name Accessors + //! \{ + + //! Returns \ref Type::Id of the data. + inline uint32_t typeId() const noexcept { return _embed._typeId; } + //! Returns the size of a single data element. + inline uint32_t typeSize() const noexcept { return _embed._typeSize; } + + //! Returns a pointer to the data casted to `uint8_t`. + inline uint8_t* data() const noexcept { + return dataSize() <= kInlineBufferSize ? const_cast(_inlineData) : _externalData; + } + + //! Returns a pointer to the data casted to `T`. + template + inline T* dataAs() const noexcept { return reinterpret_cast(data()); } + + //! Returns the number of (typed) items in the array. + inline size_t itemCount() const noexcept { return _itemCount; } + + //! Returns how many times the data is repeated (default 1). + //! + //! Repeated data is useful when defining constants for SIMD, for example. + inline size_t repeatCount() const noexcept { return _repeatCount; } + + //! Returns the size of the data, not considering the number of times it repeats. + //! + //! \note The returned value is the same as `typeSize() * itemCount()`. + inline size_t dataSize() const noexcept { return typeSize() * _itemCount; } + + //! \} +}; + +// ============================================================================ +// [asmjit::EmbedLabelNode] +// ============================================================================ + +//! Label data node. +class EmbedLabelNode : public BaseNode { +public: + ASMJIT_NONCOPYABLE(EmbedLabelNode) + + uint32_t _labelId; + uint32_t _dataSize; + + //! \name Construction & Destruction + //! \{ + + //! Creates a new `EmbedLabelNode` instance. + inline EmbedLabelNode(BaseBuilder* cb, uint32_t labelId = 0, uint32_t dataSize = 0) noexcept + : BaseNode(cb, kNodeEmbedLabel, kFlagIsData), + _labelId(labelId), + _dataSize(dataSize) {} + + //! \} + + //! \name Accessors + //! \{ + + //! Returns the label to embed as \ref Label operand. + inline Label label() const noexcept { return Label(_labelId); } + //! Returns the id of the label. + inline uint32_t labelId() const noexcept { return _labelId; } + + //! Sets the label id from `label` operand. + inline void setLabel(const Label& label) noexcept { setLabelId(label.id()); } + //! Sets the label id (use with caution, improper use can break a lot of things). + inline void setLabelId(uint32_t labelId) noexcept { _labelId = labelId; } + + //! Returns the data size. + inline uint32_t dataSize() const noexcept { return _dataSize; } + //! Sets the data size. + inline void setDataSize(uint32_t dataSize) noexcept { _dataSize = dataSize; } + + //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use labelId() instead") + inline uint32_t id() const noexcept { return labelId(); } +#endif // !ASMJIT_NO_DEPRECATED +}; + +// ============================================================================ +// [asmjit::EmbedLabelDeltaNode] +// ============================================================================ + +//! Label data node. +class EmbedLabelDeltaNode : public BaseNode { +public: + ASMJIT_NONCOPYABLE(EmbedLabelDeltaNode) + + uint32_t _labelId; + uint32_t _baseLabelId; + uint32_t _dataSize; + + //! \name Construction & Destruction + //! \{ + + //! Creates a new `EmbedLabelDeltaNode` instance. + inline EmbedLabelDeltaNode(BaseBuilder* cb, uint32_t labelId = 0, uint32_t baseLabelId = 0, uint32_t dataSize = 0) noexcept + : BaseNode(cb, kNodeEmbedLabelDelta, kFlagIsData), + _labelId(labelId), + _baseLabelId(baseLabelId), + _dataSize(dataSize) {} + + //! \} + + //! \name Accessors + //! \{ + + //! Returns the label as `Label` operand. + inline Label label() const noexcept { return Label(_labelId); } + //! Returns the id of the label. + inline uint32_t labelId() const noexcept { return _labelId; } + + //! Sets the label id from `label` operand. + inline void setLabel(const Label& label) noexcept { setLabelId(label.id()); } + //! Sets the label id. + inline void setLabelId(uint32_t labelId) noexcept { _labelId = labelId; } + + //! Returns the base label as `Label` operand. + inline Label baseLabel() const noexcept { return Label(_baseLabelId); } + //! Returns the id of the base label. + inline uint32_t baseLabelId() const noexcept { return _baseLabelId; } + + //! Sets the base label id from `label` operand. + inline void setBaseLabel(const Label& baseLabel) noexcept { setBaseLabelId(baseLabel.id()); } + //! Sets the base label id. + inline void setBaseLabelId(uint32_t baseLabelId) noexcept { _baseLabelId = baseLabelId; } + + //! Returns the size of the embedded label address. + inline uint32_t dataSize() const noexcept { return _dataSize; } + //! Sets the size of the embedded label address. + inline void setDataSize(uint32_t dataSize) noexcept { _dataSize = dataSize; } + + //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use labelId() instead") + inline uint32_t id() const noexcept { return labelId(); } + + ASMJIT_DEPRECATED("Use setLabelId() instead") + inline void setId(uint32_t id) noexcept { setLabelId(id); } + + ASMJIT_DEPRECATED("Use baseLabelId() instead") + inline uint32_t baseId() const noexcept { return baseLabelId(); } + + ASMJIT_DEPRECATED("Use setBaseLabelId() instead") + inline void setBaseId(uint32_t id) noexcept { setBaseLabelId(id); } +#endif // !ASMJIT_NO_DEPRECATED +}; + +// ============================================================================ +// [asmjit::ConstPoolNode] +// ============================================================================ + +//! A node that wraps `ConstPool`. +class ConstPoolNode : public LabelNode { +public: + ASMJIT_NONCOPYABLE(ConstPoolNode) + + ConstPool _constPool; + + //! \name Construction & Destruction + //! \{ + + //! Creates a new `ConstPoolNode` instance. + inline ConstPoolNode(BaseBuilder* cb, uint32_t id = 0) noexcept + : LabelNode(cb, id), + _constPool(&cb->_codeZone) { + + setType(kNodeConstPool); + addFlags(kFlagIsData); + clearFlags(kFlagIsCode | kFlagHasNoEffect); + } + + //! \} + + //! \name Accessors + //! \{ + + //! Tests whether the constant-pool is empty. + inline bool empty() const noexcept { return _constPool.empty(); } + //! Returns the size of the constant-pool in bytes. + inline size_t size() const noexcept { return _constPool.size(); } + //! Returns minimum alignment. + inline size_t alignment() const noexcept { return _constPool.alignment(); } + + //! Returns the wrapped `ConstPool` instance. + inline ConstPool& constPool() noexcept { return _constPool; } + //! Returns the wrapped `ConstPool` instance (const). + inline const ConstPool& constPool() const noexcept { return _constPool; } + + //! \} + + //! \name Utilities + //! \{ + + //! See `ConstPool::add()`. + inline Error add(const void* data, size_t size, size_t& dstOffset) noexcept { + return _constPool.add(data, size, dstOffset); + } + + //! \} +}; + +// ============================================================================ +// [asmjit::CommentNode] +// ============================================================================ + +//! Comment node. +class CommentNode : public BaseNode { +public: + ASMJIT_NONCOPYABLE(CommentNode) + + //! \name Construction & Destruction + //! \{ + + //! Creates a new `CommentNode` instance. + inline CommentNode(BaseBuilder* cb, const char* comment) noexcept + : BaseNode(cb, kNodeComment, kFlagIsInformative | kFlagHasNoEffect | kFlagIsRemovable) { + _inlineComment = comment; + } + + //! \} +}; + +// ============================================================================ +// [asmjit::SentinelNode] +// ============================================================================ + +//! Sentinel node. +//! +//! Sentinel is a marker that is completely ignored by the code builder. It's +//! used to remember a position in a code as it never gets removed by any pass. +class SentinelNode : public BaseNode { +public: + ASMJIT_NONCOPYABLE(SentinelNode) + + //! Type of the sentinel (purery informative purpose). + enum SentinelType : uint32_t { + //! Type of the sentinel is not known. + kSentinelUnknown = 0u, + //! This is a sentinel used at the end of \ref FuncNode. + kSentinelFuncEnd = 1u + }; + + //! \name Construction & Destruction + //! \{ + + //! Creates a new `SentinelNode` instance. + inline SentinelNode(BaseBuilder* cb, uint32_t sentinelType = kSentinelUnknown) noexcept + : BaseNode(cb, kNodeSentinel, kFlagIsInformative | kFlagHasNoEffect) { + + _sentinel._sentinelType = uint8_t(sentinelType); + } + + //! \} + + //! \name Accessors + //! \{ + + //! Returns the type of the sentinel. + inline uint32_t sentinelType() const noexcept { + return _sentinel._sentinelType; + } + + //! Sets the type of the sentinel. + inline void setSentinelType(uint32_t type) noexcept { + _sentinel._sentinelType = uint8_t(type); + } + + //! \} +}; + +// ============================================================================ +// [asmjit::Pass] +// ============================================================================ + +//! Pass can be used to implement code transformations, analysis, and lowering. +class ASMJIT_VIRTAPI Pass { +public: + ASMJIT_BASE_CLASS(Pass) + ASMJIT_NONCOPYABLE(Pass) + + //! BaseBuilder this pass is assigned to. + BaseBuilder* _cb = nullptr; + //! Name of the pass. + const char* _name = nullptr; + + //! \name Construction & Destruction + //! \{ + + ASMJIT_API Pass(const char* name) noexcept; + ASMJIT_API virtual ~Pass() noexcept; + + //! \} + + //! \name Accessors + //! \{ + + //! Returns \ref BaseBuilder associated with the pass. + inline const BaseBuilder* cb() const noexcept { return _cb; } + //! Returns the name of the pass. + inline const char* name() const noexcept { return _name; } + + //! \} + + //! \name Pass Interface + //! \{ + + //! Processes the code stored in Builder or Compiler. + //! + //! This is the only function that is called by the `BaseBuilder` to process + //! the code. It passes `zone`, which will be reset after the `run()` finishes. + virtual Error run(Zone* zone, Logger* logger) = 0; + + //! \} +}; + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // !ASMJIT_NO_BUILDER +#endif // ASMJIT_CORE_BUILDER_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codebuffer.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codebuffer.h new file mode 100644 index 0000000..76c86b1 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codebuffer.h @@ -0,0 +1,126 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_CODEBUFFER_H_INCLUDED +#define ASMJIT_CORE_CODEBUFFER_H_INCLUDED + +#include "../core/globals.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_core +//! \{ + +// ============================================================================ +// [asmjit::CodeBuffer] +// ============================================================================ + +//! Code or data buffer. +struct CodeBuffer { + //! The content of the buffer (data). + uint8_t* _data; + //! Number of bytes of `data` used. + size_t _size; + //! Buffer capacity (in bytes). + size_t _capacity; + //! Buffer flags. + uint32_t _flags; + + //! Code buffer flags. + enum Flags : uint32_t { + //! Buffer is external (not allocated by asmjit). + kFlagIsExternal = 0x00000001u, + //! Buffer is fixed (cannot be reallocated). + kFlagIsFixed = 0x00000002u + }; + + //! \name Overloaded Operators + //! \{ + + //! Returns a referebce to the byte at the given `index`. + inline uint8_t& operator[](size_t index) noexcept { + ASMJIT_ASSERT(index < _size); + return _data[index]; + } + //! \overload + inline const uint8_t& operator[](size_t index) const noexcept { + ASMJIT_ASSERT(index < _size); + return _data[index]; + } + + //! \} + + //! \name Accessors + //! \{ + + //! Returns code buffer flags, see \ref Flags. + inline uint32_t flags() const noexcept { return _flags; } + //! Tests whether the code buffer has the given `flag` set. + inline bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } + + //! Tests whether this code buffer has a fixed size. + //! + //! Fixed size means that the code buffer is fixed and cannot grow. + inline bool isFixed() const noexcept { return hasFlag(kFlagIsFixed); } + + //! Tests whether the data in this code buffer is external. + //! + //! External data can only be provided by users, it's never used by AsmJit. + inline bool isExternal() const noexcept { return hasFlag(kFlagIsExternal); } + + //! Tests whether the data in this code buffer is allocated (non-null). + inline bool isAllocated() const noexcept { return _data != nullptr; } + + //! Tests whether the code buffer is empty. + inline bool empty() const noexcept { return !_size; } + + //! Returns the size of the data. + inline size_t size() const noexcept { return _size; } + //! Returns the capacity of the data. + inline size_t capacity() const noexcept { return _capacity; } + + //! Returns the pointer to the data the buffer references. + inline uint8_t* data() noexcept { return _data; } + //! \overload + inline const uint8_t* data() const noexcept { return _data; } + + //! \} + + //! \name Iterators + //! \{ + + inline uint8_t* begin() noexcept { return _data; } + inline const uint8_t* begin() const noexcept { return _data; } + + inline uint8_t* end() noexcept { return _data + _size; } + inline const uint8_t* end() const noexcept { return _data + _size; } + + //! \} +}; + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_CODEBUFFER_H_INCLUDED + diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codeholder.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codeholder.cpp new file mode 100644 index 0000000..3c4154e --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codeholder.cpp @@ -0,0 +1,1150 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/assembler.h" +#include "../core/codewriter_p.h" +#include "../core/logger.h" +#include "../core/support.h" + +#include +#include + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [Globals] +// ============================================================================ + +static const char CodeHolder_addrTabName[] = ".addrtab"; + +//! Encode MOD byte. +static inline uint32_t x86EncodeMod(uint32_t m, uint32_t o, uint32_t rm) noexcept { + return (m << 6) | (o << 3) | rm; +} + +// ============================================================================ +// [asmjit::LabelLinkIterator] +// ============================================================================ + +class LabelLinkIterator { +public: + ASMJIT_INLINE LabelLinkIterator(LabelEntry* le) noexcept { reset(le); } + + ASMJIT_INLINE explicit operator bool() const noexcept { return isValid(); } + ASMJIT_INLINE bool isValid() const noexcept { return _link != nullptr; } + + ASMJIT_INLINE LabelLink* link() const noexcept { return _link; } + ASMJIT_INLINE LabelLink* operator->() const noexcept { return _link; } + + ASMJIT_INLINE void reset(LabelEntry* le) noexcept { + _pPrev = &le->_links; + _link = *_pPrev; + } + + ASMJIT_INLINE void next() noexcept { + _pPrev = &_link->next; + _link = *_pPrev; + } + + ASMJIT_INLINE void resolveAndNext(CodeHolder* code) noexcept { + LabelLink* linkToDelete = _link; + + _link = _link->next; + *_pPrev = _link; + + code->_unresolvedLinkCount--; + code->_allocator.release(linkToDelete, sizeof(LabelLink)); + } + + LabelLink** _pPrev; + LabelLink* _link; +}; + +// ============================================================================ +// [asmjit::CodeHolder - Utilities] +// ============================================================================ + +static void CodeHolder_resetInternal(CodeHolder* self, uint32_t resetPolicy) noexcept { + uint32_t i; + const ZoneVector& emitters = self->emitters(); + + i = emitters.size(); + while (i) + self->detach(emitters[--i]); + + // Reset everything into its construction state. + self->_environment.reset(); + self->_baseAddress = Globals::kNoBaseAddress; + self->_logger = nullptr; + self->_errorHandler = nullptr; + + // Reset all sections. + uint32_t numSections = self->_sections.size(); + for (i = 0; i < numSections; i++) { + Section* section = self->_sections[i]; + if (section->_buffer.data() && !section->_buffer.isExternal()) + ::free(section->_buffer._data); + section->_buffer._data = nullptr; + section->_buffer._capacity = 0; + } + + // Reset zone allocator and all containers using it. + ZoneAllocator* allocator = self->allocator(); + + self->_emitters.reset(); + self->_namedLabels.reset(); + self->_relocations.reset(); + self->_labelEntries.reset(); + self->_sections.reset(); + self->_sectionsByOrder.reset(); + + self->_unresolvedLinkCount = 0; + self->_addressTableSection = nullptr; + self->_addressTableEntries.reset(); + + allocator->reset(&self->_zone); + self->_zone.reset(resetPolicy); +} + +static void CodeHolder_onSettingsUpdated(CodeHolder* self) noexcept { + // Notify all attached emitters about a settings update. + for (BaseEmitter* emitter : self->emitters()) { + emitter->onSettingsUpdated(); + } +} + +// ============================================================================ +// [asmjit::CodeHolder - Construction / Destruction] +// ============================================================================ + +CodeHolder::CodeHolder() noexcept + : _environment(), + _baseAddress(Globals::kNoBaseAddress), + _logger(nullptr), + _errorHandler(nullptr), + _zone(16384 - Zone::kBlockOverhead), + _allocator(&_zone), + _unresolvedLinkCount(0), + _addressTableSection(nullptr) {} + +CodeHolder::~CodeHolder() noexcept { + CodeHolder_resetInternal(this, Globals::kResetHard); +} + +// ============================================================================ +// [asmjit::CodeHolder - Init / Reset] +// ============================================================================ + +inline void CodeHolder_setSectionDefaultName( + Section* section, + char c0 = 0, char c1 = 0, char c2 = 0, char c3 = 0, + char c4 = 0, char c5 = 0, char c6 = 0, char c7 = 0) noexcept { + + section->_name.u32[0] = Support::bytepack32_4x8(uint8_t(c0), uint8_t(c1), uint8_t(c2), uint8_t(c3)); + section->_name.u32[1] = Support::bytepack32_4x8(uint8_t(c4), uint8_t(c5), uint8_t(c6), uint8_t(c7)); +} + +Error CodeHolder::init(const Environment& environment, uint64_t baseAddress) noexcept { + // Cannot reinitialize if it's locked or there is one or more emitter attached. + if (isInitialized()) + return DebugUtils::errored(kErrorAlreadyInitialized); + + // If we are just initializing there should be no emitters attached. + ASMJIT_ASSERT(_emitters.empty()); + + // Create a default section and insert it to the `_sections` array. + Error err = _sections.willGrow(&_allocator) | + _sectionsByOrder.willGrow(&_allocator); + if (err == kErrorOk) { + Section* section = _allocator.allocZeroedT
(); + if (ASMJIT_LIKELY(section)) { + section->_flags = Section::kFlagExec | Section::kFlagConst; + CodeHolder_setSectionDefaultName(section, '.', 't', 'e', 'x', 't'); + _sections.appendUnsafe(section); + _sectionsByOrder.appendUnsafe(section); + } + else { + err = DebugUtils::errored(kErrorOutOfMemory); + } + } + + if (ASMJIT_UNLIKELY(err)) { + _zone.reset(); + return err; + } + else { + _environment = environment; + _baseAddress = baseAddress; + return kErrorOk; + } +} + +void CodeHolder::reset(uint32_t resetPolicy) noexcept { + CodeHolder_resetInternal(this, resetPolicy); +} + +// ============================================================================ +// [asmjit::CodeHolder - Attach / Detach] +// ============================================================================ + +Error CodeHolder::attach(BaseEmitter* emitter) noexcept { + // Catch a possible misuse of the API. + if (ASMJIT_UNLIKELY(!emitter)) + return DebugUtils::errored(kErrorInvalidArgument); + + // Invalid emitter, this should not be possible. + uint32_t type = emitter->emitterType(); + if (ASMJIT_UNLIKELY(type == BaseEmitter::kTypeNone || type >= BaseEmitter::kTypeCount)) + return DebugUtils::errored(kErrorInvalidState); + + // This is suspicious, but don't fail if `emitter` is already attached + // to this code holder. This is not error, but it's not recommended. + if (emitter->_code != nullptr) { + if (emitter->_code == this) + return kErrorOk; + return DebugUtils::errored(kErrorInvalidState); + } + + // Reserve the space now as we cannot fail after `onAttach()` succeeded. + ASMJIT_PROPAGATE(_emitters.willGrow(&_allocator, 1)); + ASMJIT_PROPAGATE(emitter->onAttach(this)); + + // Connect CodeHolder <-> BaseEmitter. + ASMJIT_ASSERT(emitter->_code == this); + _emitters.appendUnsafe(emitter); + + return kErrorOk; +} + +Error CodeHolder::detach(BaseEmitter* emitter) noexcept { + if (ASMJIT_UNLIKELY(!emitter)) + return DebugUtils::errored(kErrorInvalidArgument); + + if (ASMJIT_UNLIKELY(emitter->_code != this)) + return DebugUtils::errored(kErrorInvalidState); + + // NOTE: We always detach if we were asked to, if error happens during + // `emitter->onDetach()` we just propagate it, but the BaseEmitter will + // be detached. + Error err = kErrorOk; + if (!emitter->isDestroyed()) + err = emitter->onDetach(this); + + // Disconnect CodeHolder <-> BaseEmitter. + uint32_t index = _emitters.indexOf(emitter); + ASMJIT_ASSERT(index != Globals::kNotFound); + + _emitters.removeAt(index); + emitter->_code = nullptr; + + return err; +} + +// ============================================================================ +// [asmjit::CodeHolder - Logging] +// ============================================================================ + +void CodeHolder::setLogger(Logger* logger) noexcept { +#ifndef ASMJIT_NO_LOGGING + _logger = logger; + CodeHolder_onSettingsUpdated(this); +#else + DebugUtils::unused(logger); +#endif +} + +// ============================================================================ +// [asmjit::CodeHolder - Error Handling] +// ============================================================================ + +void CodeHolder::setErrorHandler(ErrorHandler* errorHandler) noexcept { + _errorHandler = errorHandler; + CodeHolder_onSettingsUpdated(this); +} + +// ============================================================================ +// [asmjit::CodeHolder - Code Buffer] +// ============================================================================ + +static Error CodeHolder_reserveInternal(CodeHolder* self, CodeBuffer* cb, size_t n) noexcept { + uint8_t* oldData = cb->_data; + uint8_t* newData; + + if (oldData && !cb->isExternal()) + newData = static_cast(::realloc(oldData, n)); + else + newData = static_cast(::malloc(n)); + + if (ASMJIT_UNLIKELY(!newData)) + return DebugUtils::errored(kErrorOutOfMemory); + + cb->_data = newData; + cb->_capacity = n; + + // Update pointers used by assemblers, if attached. + for (BaseEmitter* emitter : self->emitters()) { + if (emitter->isAssembler()) { + BaseAssembler* a = static_cast(emitter); + if (&a->_section->_buffer == cb) { + size_t offset = a->offset(); + + a->_bufferData = newData; + a->_bufferEnd = newData + n; + a->_bufferPtr = newData + offset; + } + } + } + + return kErrorOk; +} + +Error CodeHolder::growBuffer(CodeBuffer* cb, size_t n) noexcept { + // The size of the section must be valid. + size_t size = cb->size(); + if (ASMJIT_UNLIKELY(n > std::numeric_limits::max() - size)) + return DebugUtils::errored(kErrorOutOfMemory); + + // We can now check if growing the buffer is really necessary. It's unlikely + // that this function is called while there is still room for `n` bytes. + size_t capacity = cb->capacity(); + size_t required = cb->size() + n; + if (ASMJIT_UNLIKELY(required <= capacity)) + return kErrorOk; + + if (cb->isFixed()) + return DebugUtils::errored(kErrorTooLarge); + + size_t kInitialCapacity = 8096; + if (capacity < kInitialCapacity) + capacity = kInitialCapacity; + else + capacity += Globals::kAllocOverhead; + + do { + size_t old = capacity; + if (capacity < Globals::kGrowThreshold) + capacity *= 2; + else + capacity += Globals::kGrowThreshold; + + // Overflow. + if (ASMJIT_UNLIKELY(old > capacity)) + return DebugUtils::errored(kErrorOutOfMemory); + } while (capacity - Globals::kAllocOverhead < required); + + return CodeHolder_reserveInternal(this, cb, capacity - Globals::kAllocOverhead); +} + +Error CodeHolder::reserveBuffer(CodeBuffer* cb, size_t n) noexcept { + size_t capacity = cb->capacity(); + + if (n <= capacity) + return kErrorOk; + + if (cb->isFixed()) + return DebugUtils::errored(kErrorTooLarge); + + return CodeHolder_reserveInternal(this, cb, n); +} + +// ============================================================================ +// [asmjit::CodeHolder - Sections] +// ============================================================================ + +Error CodeHolder::newSection(Section** sectionOut, const char* name, size_t nameSize, uint32_t flags, uint32_t alignment, int32_t order) noexcept { + *sectionOut = nullptr; + + if (nameSize == SIZE_MAX) + nameSize = strlen(name); + + if (alignment == 0) + alignment = 1; + + if (ASMJIT_UNLIKELY(!Support::isPowerOf2(alignment))) + return DebugUtils::errored(kErrorInvalidArgument); + + if (ASMJIT_UNLIKELY(nameSize > Globals::kMaxSectionNameSize)) + return DebugUtils::errored(kErrorInvalidSectionName); + + uint32_t sectionId = _sections.size(); + if (ASMJIT_UNLIKELY(sectionId == Globals::kInvalidId)) + return DebugUtils::errored(kErrorTooManySections); + + ASMJIT_PROPAGATE(_sections.willGrow(&_allocator)); + ASMJIT_PROPAGATE(_sectionsByOrder.willGrow(&_allocator)); + + Section* section = _allocator.allocZeroedT
(); + if (ASMJIT_UNLIKELY(!section)) + return DebugUtils::errored(kErrorOutOfMemory); + + section->_id = sectionId; + section->_flags = flags; + section->_alignment = alignment; + section->_order = order; + memcpy(section->_name.str, name, nameSize); + + Section** insertPosition = std::lower_bound(_sectionsByOrder.begin(), _sectionsByOrder.end(), section, [](const Section* a, const Section* b) { + return std::make_tuple(a->order(), a->id()) < std::make_tuple(b->order(), b->id()); + }); + + _sections.appendUnsafe(section); + _sectionsByOrder.insertUnsafe((size_t)(insertPosition - _sectionsByOrder.data()), section); + + *sectionOut = section; + return kErrorOk; +} + +Section* CodeHolder::sectionByName(const char* name, size_t nameSize) const noexcept { + if (nameSize == SIZE_MAX) + nameSize = strlen(name); + + // This could be also put in a hash-table similarly like we do with labels, + // however it's questionable as the number of sections should be pretty low + // in general. Create an issue if this becomes a problem. + if (nameSize <= Globals::kMaxSectionNameSize) { + for (Section* section : _sections) + if (memcmp(section->_name.str, name, nameSize) == 0 && section->_name.str[nameSize] == '\0') + return section; + } + + return nullptr; +} + +Section* CodeHolder::ensureAddressTableSection() noexcept { + if (_addressTableSection) + return _addressTableSection; + + newSection(&_addressTableSection, CodeHolder_addrTabName, sizeof(CodeHolder_addrTabName) - 1, 0, _environment.registerSize(), std::numeric_limits::max()); + return _addressTableSection; +} + +Error CodeHolder::addAddressToAddressTable(uint64_t address) noexcept { + AddressTableEntry* entry = _addressTableEntries.get(address); + if (entry) + return kErrorOk; + + Section* section = ensureAddressTableSection(); + if (ASMJIT_UNLIKELY(!section)) + return DebugUtils::errored(kErrorOutOfMemory); + + entry = _zone.newT(address); + if (ASMJIT_UNLIKELY(!entry)) + return DebugUtils::errored(kErrorOutOfMemory); + + _addressTableEntries.insert(entry); + section->_virtualSize += _environment.registerSize(); + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::CodeHolder - Labels / Symbols] +// ============================================================================ + +//! Only used to lookup a label from `_namedLabels`. +class LabelByName { +public: + inline LabelByName(const char* key, size_t keySize, uint32_t hashCode, uint32_t parentId) noexcept + : _key(key), + _keySize(uint32_t(keySize)), + _hashCode(hashCode), + _parentId(parentId) {} + + inline uint32_t hashCode() const noexcept { return _hashCode; } + + inline bool matches(const LabelEntry* entry) const noexcept { + return entry->nameSize() == _keySize && + entry->parentId() == _parentId && + ::memcmp(entry->name(), _key, _keySize) == 0; + } + + const char* _key; + uint32_t _keySize; + uint32_t _hashCode; + uint32_t _parentId; +}; + +// Returns a hash of `name` and fixes `nameSize` if it's `SIZE_MAX`. +static uint32_t CodeHolder_hashNameAndGetSize(const char* name, size_t& nameSize) noexcept { + uint32_t hashCode = 0; + if (nameSize == SIZE_MAX) { + size_t i = 0; + for (;;) { + uint8_t c = uint8_t(name[i]); + if (!c) break; + hashCode = Support::hashRound(hashCode, c); + i++; + } + nameSize = i; + } + else { + for (size_t i = 0; i < nameSize; i++) { + uint8_t c = uint8_t(name[i]); + if (ASMJIT_UNLIKELY(!c)) return DebugUtils::errored(kErrorInvalidLabelName); + hashCode = Support::hashRound(hashCode, c); + } + } + return hashCode; +} + +LabelLink* CodeHolder::newLabelLink(LabelEntry* le, uint32_t sectionId, size_t offset, intptr_t rel, const OffsetFormat& format) noexcept { + LabelLink* link = _allocator.allocT(); + if (ASMJIT_UNLIKELY(!link)) return nullptr; + + link->next = le->_links; + le->_links = link; + + link->sectionId = sectionId; + link->relocId = Globals::kInvalidId; + link->offset = offset; + link->rel = rel; + link->format = format; + + _unresolvedLinkCount++; + return link; +} + +Error CodeHolder::newLabelEntry(LabelEntry** entryOut) noexcept { + *entryOut = nullptr; + + uint32_t labelId = _labelEntries.size(); + if (ASMJIT_UNLIKELY(labelId == Globals::kInvalidId)) + return DebugUtils::errored(kErrorTooManyLabels); + + ASMJIT_PROPAGATE(_labelEntries.willGrow(&_allocator)); + LabelEntry* le = _allocator.allocZeroedT(); + + if (ASMJIT_UNLIKELY(!le)) + return DebugUtils::errored(kErrorOutOfMemory); + + le->_setId(labelId); + le->_parentId = Globals::kInvalidId; + le->_offset = 0; + _labelEntries.appendUnsafe(le); + + *entryOut = le; + return kErrorOk; +} + +Error CodeHolder::newNamedLabelEntry(LabelEntry** entryOut, const char* name, size_t nameSize, uint32_t type, uint32_t parentId) noexcept { + *entryOut = nullptr; + uint32_t hashCode = CodeHolder_hashNameAndGetSize(name, nameSize); + + if (ASMJIT_UNLIKELY(nameSize == 0)) + return DebugUtils::errored(kErrorInvalidLabelName); + + if (ASMJIT_UNLIKELY(nameSize > Globals::kMaxLabelNameSize)) + return DebugUtils::errored(kErrorLabelNameTooLong); + + switch (type) { + case Label::kTypeLocal: + if (ASMJIT_UNLIKELY(parentId >= _labelEntries.size())) + return DebugUtils::errored(kErrorInvalidParentLabel); + + hashCode ^= parentId; + break; + + case Label::kTypeGlobal: + case Label::kTypeExternal: + if (ASMJIT_UNLIKELY(parentId != Globals::kInvalidId)) + return DebugUtils::errored(kErrorNonLocalLabelCannotHaveParent); + break; + + default: + return DebugUtils::errored(kErrorInvalidArgument); + } + + // Don't allow to insert duplicates. Local labels allow duplicates that have + // different id, this is already accomplished by having a different hashes + // between the same label names having different parent labels. + LabelEntry* le = _namedLabels.get(LabelByName(name, nameSize, hashCode, parentId)); + if (ASMJIT_UNLIKELY(le)) + return DebugUtils::errored(kErrorLabelAlreadyDefined); + + Error err = kErrorOk; + uint32_t labelId = _labelEntries.size(); + + if (ASMJIT_UNLIKELY(labelId == Globals::kInvalidId)) + return DebugUtils::errored(kErrorTooManyLabels); + + ASMJIT_PROPAGATE(_labelEntries.willGrow(&_allocator)); + le = _allocator.allocZeroedT(); + + if (ASMJIT_UNLIKELY(!le)) + return DebugUtils::errored(kErrorOutOfMemory); + + le->_hashCode = hashCode; + le->_setId(labelId); + le->_type = uint8_t(type); + le->_parentId = parentId; + le->_offset = 0; + ASMJIT_PROPAGATE(le->_name.setData(&_zone, name, nameSize)); + + _labelEntries.appendUnsafe(le); + _namedLabels.insert(allocator(), le); + + *entryOut = le; + return err; +} + +uint32_t CodeHolder::labelIdByName(const char* name, size_t nameSize, uint32_t parentId) noexcept { + uint32_t hashCode = CodeHolder_hashNameAndGetSize(name, nameSize); + if (ASMJIT_UNLIKELY(!nameSize)) + return 0; + + if (parentId != Globals::kInvalidId) + hashCode ^= parentId; + + LabelEntry* le = _namedLabels.get(LabelByName(name, nameSize, hashCode, parentId)); + return le ? le->id() : uint32_t(Globals::kInvalidId); +} + +ASMJIT_API Error CodeHolder::resolveUnresolvedLinks() noexcept { + if (!hasUnresolvedLinks()) + return kErrorOk; + + Error err = kErrorOk; + for (LabelEntry* le : labelEntries()) { + if (!le->isBound()) + continue; + + LabelLinkIterator link(le); + if (link) { + Support::FastUInt8 of = 0; + Section* toSection = le->section(); + uint64_t toOffset = Support::addOverflow(toSection->offset(), le->offset(), &of); + + do { + uint32_t linkSectionId = link->sectionId; + if (link->relocId == Globals::kInvalidId) { + Section* fromSection = sectionById(linkSectionId); + size_t linkOffset = link->offset; + + CodeBuffer& buf = _sections[linkSectionId]->buffer(); + ASMJIT_ASSERT(linkOffset < buf.size()); + + // Calculate the offset relative to the start of the virtual base. + Support::FastUInt8 localOF = of; + uint64_t fromOffset = Support::addOverflow(fromSection->offset(), linkOffset, &localOF); + int64_t displacement = int64_t(toOffset - fromOffset + uint64_t(int64_t(link->rel))); + + if (!localOF) { + ASMJIT_ASSERT(size_t(linkOffset) < buf.size()); + ASMJIT_ASSERT(buf.size() - size_t(linkOffset) >= link->format.valueSize()); + + // Overwrite a real displacement in the CodeBuffer. + if (CodeWriterUtils::writeOffset(buf._data + linkOffset, displacement, link->format)) { + link.resolveAndNext(this); + continue; + } + } + + err = DebugUtils::errored(kErrorInvalidDisplacement); + // Falls through to `link.next()`. + } + + link.next(); + } while (link); + } + } + + return err; +} + +ASMJIT_API Error CodeHolder::bindLabel(const Label& label, uint32_t toSectionId, uint64_t toOffset) noexcept { + LabelEntry* le = labelEntry(label); + if (ASMJIT_UNLIKELY(!le)) + return DebugUtils::errored(kErrorInvalidLabel); + + if (ASMJIT_UNLIKELY(toSectionId > _sections.size())) + return DebugUtils::errored(kErrorInvalidSection); + + // Label can be bound only once. + if (ASMJIT_UNLIKELY(le->isBound())) + return DebugUtils::errored(kErrorLabelAlreadyBound); + + // Bind the label. + Section* section = _sections[toSectionId]; + le->_section = section; + le->_offset = toOffset; + + Error err = kErrorOk; + CodeBuffer& buf = section->buffer(); + + // Fix all links to this label we have collected so far if they are within + // the same section. We ignore any inter-section links as these have to be + // fixed later. + LabelLinkIterator link(le); + while (link) { + uint32_t linkSectionId = link->sectionId; + size_t linkOffset = link->offset; + + uint32_t relocId = link->relocId; + if (relocId != Globals::kInvalidId) { + // Adjust relocation data only. + RelocEntry* re = _relocations[relocId]; + re->_payload += toOffset; + re->_targetSectionId = toSectionId; + } + else { + if (linkSectionId != toSectionId) { + link.next(); + continue; + } + + ASMJIT_ASSERT(linkOffset < buf.size()); + int64_t displacement = int64_t(toOffset - uint64_t(linkOffset) + uint64_t(int64_t(link->rel))); + + // Size of the value we are going to patch. Only BYTE/DWORD is allowed. + ASMJIT_ASSERT(buf.size() - size_t(linkOffset) >= link->format.regionSize()); + + // Overwrite a real displacement in the CodeBuffer. + if (!CodeWriterUtils::writeOffset(buf._data + linkOffset, displacement, link->format)) { + err = DebugUtils::errored(kErrorInvalidDisplacement); + link.next(); + continue; + } + } + + link.resolveAndNext(this); + } + + return err; +} + +// ============================================================================ +// [asmjit::BaseEmitter - Relocations] +// ============================================================================ + +Error CodeHolder::newRelocEntry(RelocEntry** dst, uint32_t relocType) noexcept { + ASMJIT_PROPAGATE(_relocations.willGrow(&_allocator)); + + uint32_t relocId = _relocations.size(); + if (ASMJIT_UNLIKELY(relocId == Globals::kInvalidId)) + return DebugUtils::errored(kErrorTooManyRelocations); + + RelocEntry* re = _allocator.allocZeroedT(); + if (ASMJIT_UNLIKELY(!re)) + return DebugUtils::errored(kErrorOutOfMemory); + + re->_id = relocId; + re->_relocType = uint8_t(relocType); + re->_sourceSectionId = Globals::kInvalidId; + re->_targetSectionId = Globals::kInvalidId; + _relocations.appendUnsafe(re); + + *dst = re; + return kErrorOk; +} + +// ============================================================================ +// [asmjit::BaseEmitter - Expression Evaluation] +// ============================================================================ + +static Error CodeHolder_evaluateExpression(CodeHolder* self, Expression* exp, uint64_t* out) noexcept { + uint64_t value[2]; + for (size_t i = 0; i < 2; i++) { + uint64_t v; + switch (exp->valueType[i]) { + case Expression::kValueNone: { + v = 0; + break; + } + + case Expression::kValueConstant: { + v = exp->value[i].constant; + break; + } + + case Expression::kValueLabel: { + LabelEntry* le = exp->value[i].label; + if (!le->isBound()) + return DebugUtils::errored(kErrorExpressionLabelNotBound); + v = le->section()->offset() + le->offset(); + break; + } + + case Expression::kValueExpression: { + Expression* nested = exp->value[i].expression; + ASMJIT_PROPAGATE(CodeHolder_evaluateExpression(self, nested, &v)); + break; + } + + default: + return DebugUtils::errored(kErrorInvalidState); + } + + value[i] = v; + } + + uint64_t result; + uint64_t& a = value[0]; + uint64_t& b = value[1]; + + switch (exp->opType) { + case Expression::kOpAdd: + result = a + b; + break; + + case Expression::kOpSub: + result = a - b; + break; + + case Expression::kOpMul: + result = a * b; + break; + + case Expression::kOpSll: + result = (b > 63) ? uint64_t(0) : uint64_t(a << b); + break; + + case Expression::kOpSrl: + result = (b > 63) ? uint64_t(0) : uint64_t(a >> b); + break; + + case Expression::kOpSra: + result = Support::sar(a, Support::min(b, 63)); + break; + + default: + return DebugUtils::errored(kErrorInvalidState); + } + + *out = result; + return kErrorOk; +} + +// ============================================================================ +// [asmjit::BaseEmitter - Utilities] +// ============================================================================ + +Error CodeHolder::flatten() noexcept { + uint64_t offset = 0; + for (Section* section : _sectionsByOrder) { + uint64_t realSize = section->realSize(); + if (realSize) { + uint64_t alignedOffset = Support::alignUp(offset, section->alignment()); + if (ASMJIT_UNLIKELY(alignedOffset < offset)) + return DebugUtils::errored(kErrorTooLarge); + + Support::FastUInt8 of = 0; + offset = Support::addOverflow(alignedOffset, realSize, &of); + + if (ASMJIT_UNLIKELY(of)) + return DebugUtils::errored(kErrorTooLarge); + } + } + + // Now we know that we can assign offsets of all sections properly. + Section* prev = nullptr; + offset = 0; + for (Section* section : _sectionsByOrder) { + uint64_t realSize = section->realSize(); + if (realSize) + offset = Support::alignUp(offset, section->alignment()); + section->_offset = offset; + + // Make sure the previous section extends a bit to cover the alignment. + if (prev) + prev->_virtualSize = offset - prev->_offset; + + prev = section; + offset += realSize; + } + + return kErrorOk; +} + +size_t CodeHolder::codeSize() const noexcept { + Support::FastUInt8 of = 0; + uint64_t offset = 0; + + for (Section* section : _sectionsByOrder) { + uint64_t realSize = section->realSize(); + + if (realSize) { + uint64_t alignedOffset = Support::alignUp(offset, section->alignment()); + ASMJIT_ASSERT(alignedOffset >= offset); + offset = Support::addOverflow(alignedOffset, realSize, &of); + } + } + + if ((sizeof(uint64_t) > sizeof(size_t) && offset > SIZE_MAX) || of) + return SIZE_MAX; + + return size_t(offset); +} + +Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept { + // Base address must be provided. + if (ASMJIT_UNLIKELY(baseAddress == Globals::kNoBaseAddress)) + return DebugUtils::errored(kErrorInvalidArgument); + + _baseAddress = baseAddress; + uint32_t addressSize = _environment.registerSize(); + + Section* addressTableSection = _addressTableSection; + uint32_t addressTableEntryCount = 0; + uint8_t* addressTableEntryData = nullptr; + + if (addressTableSection) { + ASMJIT_PROPAGATE( + reserveBuffer(&addressTableSection->_buffer, size_t(addressTableSection->virtualSize()))); + addressTableEntryData = addressTableSection->_buffer.data(); + } + + // Relocate all recorded locations. + for (const RelocEntry* re : _relocations) { + // Possibly deleted or optimized-out entry. + if (re->relocType() == RelocEntry::kTypeNone) + continue; + + Section* sourceSection = sectionById(re->sourceSectionId()); + Section* targetSection = nullptr; + + if (re->targetSectionId() != Globals::kInvalidId) + targetSection = sectionById(re->targetSectionId()); + + uint64_t value = re->payload(); + uint64_t sectionOffset = sourceSection->offset(); + uint64_t sourceOffset = re->sourceOffset(); + + // Make sure that the `RelocEntry` doesn't go out of bounds. + size_t regionSize = re->format().regionSize(); + if (ASMJIT_UNLIKELY(re->sourceOffset() >= sourceSection->bufferSize() || + sourceSection->bufferSize() - size_t(re->sourceOffset()) < regionSize)) + return DebugUtils::errored(kErrorInvalidRelocEntry); + + uint8_t* buffer = sourceSection->data(); + size_t valueOffset = size_t(re->sourceOffset()) + re->format().valueOffset(); + + switch (re->relocType()) { + case RelocEntry::kTypeExpression: { + Expression* expression = (Expression*)(uintptr_t(value)); + ASMJIT_PROPAGATE(CodeHolder_evaluateExpression(this, expression, &value)); + break; + } + + case RelocEntry::kTypeAbsToAbs: { + break; + } + + case RelocEntry::kTypeRelToAbs: { + // Value is currently a relative offset from the start of its section. + // We have to convert it to an absolute offset (including base address). + if (ASMJIT_UNLIKELY(!targetSection)) + return DebugUtils::errored(kErrorInvalidRelocEntry); + + //value += baseAddress + sectionOffset + sourceOffset + regionSize; + value += baseAddress + targetSection->offset(); + break; + } + + case RelocEntry::kTypeAbsToRel: { + value -= baseAddress + sectionOffset + sourceOffset + regionSize; + if (addressSize > 4 && !Support::isInt32(int64_t(value))) + return DebugUtils::errored(kErrorRelocOffsetOutOfRange); + break; + } + + case RelocEntry::kTypeX64AddressEntry: { + if (re->format().valueSize() != 4 || valueOffset < 2) + return DebugUtils::errored(kErrorInvalidRelocEntry); + + // First try whether a relative 32-bit displacement would work. + value -= baseAddress + sectionOffset + sourceOffset + regionSize; + if (!Support::isInt32(int64_t(value))) { + // Relative 32-bit displacement is not possible, use '.addrtab' section. + AddressTableEntry* atEntry = _addressTableEntries.get(re->payload()); + if (ASMJIT_UNLIKELY(!atEntry)) + return DebugUtils::errored(kErrorInvalidRelocEntry); + + // Cannot be null as we have just matched the `AddressTableEntry`. + ASMJIT_ASSERT(addressTableSection != nullptr); + + if (!atEntry->hasAssignedSlot()) + atEntry->_slot = addressTableEntryCount++; + + size_t atEntryIndex = size_t(atEntry->slot()) * addressSize; + uint64_t addrSrc = sectionOffset + sourceOffset + regionSize; + uint64_t addrDst = addressTableSection->offset() + uint64_t(atEntryIndex); + + value = addrDst - addrSrc; + if (!Support::isInt32(int64_t(value))) + return DebugUtils::errored(kErrorRelocOffsetOutOfRange); + + // Bytes that replace [REX, OPCODE] bytes. + uint32_t byte0 = 0xFF; + uint32_t byte1 = buffer[valueOffset - 1]; + + if (byte1 == 0xE8) { + // Patch CALL/MOD byte to FF /2 (-> 0x15). + byte1 = x86EncodeMod(0, 2, 5); + } + else if (byte1 == 0xE9) { + // Patch JMP/MOD byte to FF /4 (-> 0x25). + byte1 = x86EncodeMod(0, 4, 5); + } + else { + return DebugUtils::errored(kErrorInvalidRelocEntry); + } + + // Patch `jmp/call` instruction. + buffer[valueOffset - 2] = uint8_t(byte0); + buffer[valueOffset - 1] = uint8_t(byte1); + + Support::writeU64uLE(addressTableEntryData + atEntryIndex, re->payload()); + } + break; + } + + default: + return DebugUtils::errored(kErrorInvalidRelocEntry); + } + + switch (re->format().valueSize()) { + case 1: + Support::writeU8(buffer + valueOffset, uint32_t(value & 0xFFu)); + break; + + case 2: + Support::writeU16uLE(buffer + valueOffset, uint32_t(value & 0xFFFFu)); + break; + + case 4: + Support::writeU32uLE(buffer + valueOffset, uint32_t(value & 0xFFFFFFFFu)); + break; + + case 8: + Support::writeU64uLE(buffer + valueOffset, value); + break; + + default: + return DebugUtils::errored(kErrorInvalidRelocEntry); + } + } + + // Fixup the virtual size of the address table if it's the last section. + if (_sectionsByOrder.last() == addressTableSection) { + size_t addressTableSize = addressTableEntryCount * addressSize; + addressTableSection->_buffer._size = addressTableSize; + addressTableSection->_virtualSize = addressTableSize; + } + + return kErrorOk; +} + +Error CodeHolder::copySectionData(void* dst, size_t dstSize, uint32_t sectionId, uint32_t copyOptions) noexcept { + if (ASMJIT_UNLIKELY(!isSectionValid(sectionId))) + return DebugUtils::errored(kErrorInvalidSection); + + Section* section = sectionById(sectionId); + size_t bufferSize = section->bufferSize(); + + if (ASMJIT_UNLIKELY(dstSize < bufferSize)) + return DebugUtils::errored(kErrorInvalidArgument); + + memcpy(dst, section->data(), bufferSize); + + if (bufferSize < dstSize && (copyOptions & kCopyPadSectionBuffer)) { + size_t paddingSize = dstSize - bufferSize; + memset(static_cast(dst) + bufferSize, 0, paddingSize); + } + + return kErrorOk; +} + +Error CodeHolder::copyFlattenedData(void* dst, size_t dstSize, uint32_t copyOptions) noexcept { + size_t end = 0; + for (Section* section : _sectionsByOrder) { + if (section->offset() > dstSize) + return DebugUtils::errored(kErrorInvalidArgument); + + size_t bufferSize = section->bufferSize(); + size_t offset = size_t(section->offset()); + + if (ASMJIT_UNLIKELY(dstSize - offset < bufferSize)) + return DebugUtils::errored(kErrorInvalidArgument); + + uint8_t* dstTarget = static_cast(dst) + offset; + size_t paddingSize = 0; + memcpy(dstTarget, section->data(), bufferSize); + + if ((copyOptions & kCopyPadSectionBuffer) && bufferSize < section->virtualSize()) { + paddingSize = Support::min(dstSize - offset, size_t(section->virtualSize())) - bufferSize; + memset(dstTarget + bufferSize, 0, paddingSize); + } + + end = Support::max(end, offset + bufferSize + paddingSize); + } + + if (end < dstSize && (copyOptions & kCopyPadTargetBuffer)) { + memset(static_cast(dst) + end, 0, dstSize - end); + } + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::CodeHolder - Unit] +// ============================================================================ + +#if defined(ASMJIT_TEST) +UNIT(code_holder) { + CodeHolder code; + + INFO("Verifying CodeHolder::init()"); + Environment env; + env.init(Environment::kArchX86); + + code.init(env); + EXPECT(code.arch() == Environment::kArchX86); + + INFO("Verifying named labels"); + LabelEntry* le; + EXPECT(code.newNamedLabelEntry(&le, "NamedLabel", SIZE_MAX, Label::kTypeGlobal) == kErrorOk); + EXPECT(strcmp(le->name(), "NamedLabel") == 0); + EXPECT(code.labelIdByName("NamedLabel") == le->id()); + + INFO("Verifying section ordering"); + Section* section1; + EXPECT(code.newSection(§ion1, "high-priority", SIZE_MAX, 0, 1, -1) == kErrorOk); + EXPECT(code.sections()[1] == section1); + EXPECT(code.sectionsByOrder()[0] == section1); + + Section* section0; + EXPECT(code.newSection(§ion0, "higher-priority", SIZE_MAX, 0, 1, -2) == kErrorOk); + EXPECT(code.sections()[2] == section0); + EXPECT(code.sectionsByOrder()[0] == section0); + EXPECT(code.sectionsByOrder()[1] == section1); + + Section* section3; + EXPECT(code.newSection(§ion3, "low-priority", SIZE_MAX, 0, 1, 2) == kErrorOk); + EXPECT(code.sections()[3] == section3); + EXPECT(code.sectionsByOrder()[3] == section3); + +} +#endif + +ASMJIT_END_NAMESPACE diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codeholder.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codeholder.h new file mode 100644 index 0000000..06bf3f9 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codeholder.h @@ -0,0 +1,1061 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_CODEHOLDER_H_INCLUDED +#define ASMJIT_CORE_CODEHOLDER_H_INCLUDED + +#include "../core/archtraits.h" +#include "../core/codebuffer.h" +#include "../core/datatypes.h" +#include "../core/errorhandler.h" +#include "../core/operand.h" +#include "../core/string.h" +#include "../core/support.h" +#include "../core/target.h" +#include "../core/zone.h" +#include "../core/zonehash.h" +#include "../core/zonestring.h" +#include "../core/zonetree.h" +#include "../core/zonevector.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_core +//! \{ + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +class BaseEmitter; +class CodeHolder; +class LabelEntry; +class Logger; + +// ============================================================================ +// [asmjit::AlignMode] +// ============================================================================ + +//! Align mode. +enum AlignMode : uint32_t { + //! Align executable code. + kAlignCode = 0, + //! Align non-executable code. + kAlignData = 1, + //! Align by a sequence of zeros. + kAlignZero = 2, + //! Count of alignment modes. + kAlignCount = 3 +}; + +// ============================================================================ +// [asmjit::Expression] +// ============================================================================ + +//! Expression node that can reference constants, labels, and another expressions. +struct Expression { + //! Operation type. + enum OpType : uint8_t { + //! Addition. + kOpAdd = 0, + //! Subtraction. + kOpSub = 1, + //! Multiplication + kOpMul = 2, + //! Logical left shift. + kOpSll = 3, + //! Logical right shift. + kOpSrl = 4, + //! Arithmetic right shift. + kOpSra = 5 + }; + + //! Type of \ref Value. + enum ValueType : uint8_t { + //! No value or invalid. + kValueNone = 0, + //! Value is 64-bit unsigned integer (constant). + kValueConstant = 1, + //! Value is \ref LabelEntry, which references a \ref Label. + kValueLabel = 2, + //! Value is \ref Expression + kValueExpression = 3 + }; + + //! Expression value. + union Value { + //! Constant. + uint64_t constant; + //! Pointer to another expression. + Expression* expression; + //! Poitner to \ref LabelEntry. + LabelEntry* label; + }; + + //! Operation type. + uint8_t opType; + //! Value types of \ref value. + uint8_t valueType[2]; + //! Reserved for future use, should be initialized to zero. + uint8_t reserved[5]; + //! Expression left and right values. + Value value[2]; + + //! Resets the whole expression. + //! + //! Changes both values to \ref kValueNone. + inline void reset() noexcept { memset(this, 0, sizeof(*this)); } + + //! Sets the value type at `index` to \ref kValueConstant and its content to `constant`. + inline void setValueAsConstant(size_t index, uint64_t constant) noexcept { + valueType[index] = kValueConstant; + value[index].constant = constant; + } + + //! Sets the value type at `index` to \ref kValueLabel and its content to `labelEntry`. + inline void setValueAsLabel(size_t index, LabelEntry* labelEntry) noexcept { + valueType[index] = kValueLabel; + value[index].label = labelEntry; + } + + //! Sets the value type at `index` to \ref kValueExpression and its content to `expression`. + inline void setValueAsExpression(size_t index, Expression* expression) noexcept { + valueType[index] = kValueLabel; + value[index].expression = expression; + } +}; + +// ============================================================================ +// [asmjit::Section] +// ============================================================================ + +//! Section entry. +class Section { +public: + //! Section id. + uint32_t _id; + //! Section flags. + uint32_t _flags; + //! Section alignment requirements (0 if no requirements). + uint32_t _alignment; + //! Order (lower value means higher priority). + int32_t _order; + //! Offset of this section from base-address. + uint64_t _offset; + //! Virtual size of the section (zero initialized sections). + uint64_t _virtualSize; + //! Section name (max 35 characters, PE allows max 8). + FixedString _name; + //! Code or data buffer. + CodeBuffer _buffer; + + //! Section flags. + enum Flags : uint32_t { + //! Executable (.text sections). + kFlagExec = 0x00000001u, + //! Read-only (.text and .data sections). + kFlagConst = 0x00000002u, + //! Zero initialized by the loader (BSS). + kFlagZero = 0x00000004u, + //! Info / comment flag. + kFlagInfo = 0x00000008u, + //! Section created implicitly and can be deleted by \ref Target. + kFlagImplicit = 0x80000000u + }; + + //! \name Accessors + //! \{ + + //! Returns the section id. + inline uint32_t id() const noexcept { return _id; } + //! Returns the section name, as a null terminated string. + inline const char* name() const noexcept { return _name.str; } + + //! Returns the section data. + inline uint8_t* data() noexcept { return _buffer.data(); } + //! \overload + inline const uint8_t* data() const noexcept { return _buffer.data(); } + + //! Returns the section flags, see \ref Flags. + inline uint32_t flags() const noexcept { return _flags; } + //! Tests whether the section has the given `flag`. + inline bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } + //! Adds `flags` to the section flags. + inline void addFlags(uint32_t flags) noexcept { _flags |= flags; } + //! Removes `flags` from the section flags. + inline void clearFlags(uint32_t flags) noexcept { _flags &= ~flags; } + + //! Returns the minimum section alignment + inline uint32_t alignment() const noexcept { return _alignment; } + //! Sets the minimum section alignment + inline void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; } + + //! Returns the section order, which has a higher priority than section id. + inline int32_t order() const noexcept { return _order; } + + //! Returns the section offset, relative to base. + inline uint64_t offset() const noexcept { return _offset; } + //! Set the section offset. + inline void setOffset(uint64_t offset) noexcept { _offset = offset; } + + //! Returns the virtual size of the section. + //! + //! Virtual size is initially zero and is never changed by AsmJit. It's normal + //! if virtual size is smaller than size returned by `bufferSize()` as the buffer + //! stores real data emitted by assemblers or appended by users. + //! + //! Use `realSize()` to get the real and final size of this section. + inline uint64_t virtualSize() const noexcept { return _virtualSize; } + //! Sets the virtual size of the section. + inline void setVirtualSize(uint64_t virtualSize) noexcept { _virtualSize = virtualSize; } + + //! Returns the buffer size of the section. + inline size_t bufferSize() const noexcept { return _buffer.size(); } + //! Returns the real size of the section calculated from virtual and buffer sizes. + inline uint64_t realSize() const noexcept { return Support::max(virtualSize(), bufferSize()); } + + //! Returns the `CodeBuffer` used by this section. + inline CodeBuffer& buffer() noexcept { return _buffer; } + //! Returns the `CodeBuffer` used by this section (const). + inline const CodeBuffer& buffer() const noexcept { return _buffer; } + + //! \} +}; + +// ============================================================================ +// [asmjit::OffsetFormat] +// ============================================================================ + +//! Provides information about formatting offsets, absolute addresses, or their +//! parts. Offset format is used by both \ref RelocEntry and \ref LabelLink. +//! +//! The illustration above describes the relation of region size and offset size. +//! Region size is the size of the whole unit whereas offset size is the size of +//! the unit that will be patched. +//! +//! ``` +//! +-> Code buffer | The subject of the relocation (region) | +//! | | (Word-Offset) (Word-Size) | +//! |xxxxxxxxxxxxxxx|................|*PATCHED*|................|xxxxxxxxxxxx-> +//! | | +//! [Word Offset points here]----+ +--- [WordOffset + WordSize] +//! ``` +//! +//! Once the offset word has been located it can be patched like this: +//! +//! ``` +//! |ImmDiscardLSB (discard LSB bits). +//! |.. +//! [0000000000000iiiiiiiiiiiiiiiiiDD] - Offset value (32-bit) +//! [000000000000000iiiiiiiiiiiiiiiii] - Offset value after discard LSB. +//! [00000000000iiiiiiiiiiiiiiiii0000] - Offset value shifted by ImmBitShift. +//! [xxxxxxxxxxxiiiiiiiiiiiiiiiiixxxx] - Patched word (32-bit) +//! |...............| +//! (ImmBitCount) +- ImmBitShift +//! ``` +struct OffsetFormat { + //! Type of the displacement. + uint8_t _type; + //! Encoding flags. + uint8_t _flags; + //! Size of the region (in bytes) containing the offset value, if the offset + //! value is part of an instruction, otherwise it would be the same as + //! `_valueSize`. + uint8_t _regionSize; + //! Size of the offset value, in bytes (1, 2, 4, or 8). + uint8_t _valueSize; + //! Offset of the offset value, in bytes, relative to the start of the region + //! or data. Value offset would be zero if both region size and value size are + //! equal. + uint8_t _valueOffset; + //! Size of the displacement immediate value in bits. + uint8_t _immBitCount; + //! Shift of the displacement immediate value in bits in the target word. + uint8_t _immBitShift; + //! Number of least significant bits to discard before writing the immediate + //! to the destination. All discarded bits must be zero otherwise the value + //! is invalid. + uint8_t _immDiscardLsb; + + //! Type of the displacement. + enum Type : uint8_t { + //! A value having `_immBitCount` bits and shifted by `_immBitShift`. + //! + //! This displacement type is sufficient for both X86/X64 and many other + //! architectures that store displacement as continuous bits within a machine + //! word. + kTypeCommon = 0, + //! AARCH64 ADR format of `[.|immlo:2|.....|immhi:19|.....]`. + kTypeAArch64_ADR, + //! AARCH64 ADRP format of `[.|immlo:2|.....|immhi:19|.....]` (4kB pages). + kTypeAArch64_ADRP, + + //! Count of displacement types. + kTypeCount + }; + + //! Returns the type of the displacement. + inline uint32_t type() const noexcept { return _type; } + + //! Returns flags. + inline uint32_t flags() const noexcept { return _flags; } + + //! Returns the size of the region/instruction where the displacement is encoded. + inline uint32_t regionSize() const noexcept { return _regionSize; } + + //! Returns the the offset of the word relative to the start of the region + //! where the displacement is. + inline uint32_t valueOffset() const noexcept { return _valueOffset; } + + //! Returns the size of the data-type (word) that contains the displacement, in bytes. + inline uint32_t valueSize() const noexcept { return _valueSize; } + //! Returns the count of bits of the displacement value in the data it's stored in. + inline uint32_t immBitCount() const noexcept { return _immBitCount; } + //! Returns the bit-shift of the displacement value in the data it's stored in. + inline uint32_t immBitShift() const noexcept { return _immBitShift; } + //! Returns the number of least significant bits of the displacement value, + //! that must be zero and that are not part of the encoded data. + inline uint32_t immDiscardLsb() const noexcept { return _immDiscardLsb; } + + //! Resets this offset format to a simple data value of `dataSize` bytes. + //! + //! The region will be the same size as data and immediate bits would correspond + //! to `dataSize * 8`. There will be no immediate bit shift or discarded bits. + inline void resetToDataValue(size_t dataSize) noexcept { + ASMJIT_ASSERT(dataSize <= 8u); + + _type = uint8_t(kTypeCommon); + _flags = uint8_t(0); + _regionSize = uint8_t(dataSize); + _valueSize = uint8_t(dataSize); + _valueOffset = uint8_t(0); + _immBitCount = uint8_t(dataSize * 8u); + _immBitShift = uint8_t(0); + _immDiscardLsb = uint8_t(0); + } + + inline void resetToImmValue(uint32_t type, size_t valueSize, uint32_t immBitShift, uint32_t immBitCount, uint32_t immDiscardLsb) noexcept { + ASMJIT_ASSERT(valueSize <= 8u); + ASMJIT_ASSERT(immBitShift < valueSize * 8u); + ASMJIT_ASSERT(immBitCount <= 64u); + ASMJIT_ASSERT(immDiscardLsb <= 64u); + + _type = uint8_t(type); + _flags = uint8_t(0); + _regionSize = uint8_t(valueSize); + _valueSize = uint8_t(valueSize); + _valueOffset = uint8_t(0); + _immBitCount = uint8_t(immBitCount); + _immBitShift = uint8_t(immBitShift); + _immDiscardLsb = uint8_t(immDiscardLsb); + } + + inline void setRegion(size_t regionSize, size_t valueOffset) noexcept { + _regionSize = uint8_t(regionSize); + _valueOffset = uint8_t(valueOffset); + } + + inline void setLeadingAndTrailingSize(size_t leadingSize, size_t trailingSize) noexcept { + _regionSize = uint8_t(leadingSize + trailingSize + _valueSize); + _valueOffset = uint8_t(leadingSize); + } +}; + +// ============================================================================ +// [asmjit::RelocEntry] +// ============================================================================ + +//! Relocation entry. +struct RelocEntry { + //! Relocation id. + uint32_t _id; + //! Type of the relocation. + uint32_t _relocType; + //! Format of the relocated value. + OffsetFormat _format; + //! Source section id. + uint32_t _sourceSectionId; + //! Target section id. + uint32_t _targetSectionId; + //! Source offset (relative to start of the section). + uint64_t _sourceOffset; + //! Payload (target offset, target address, expression, etc). + uint64_t _payload; + + //! Relocation type. + enum RelocType : uint32_t { + //! None/deleted (no relocation). + kTypeNone = 0, + //! Expression evaluation, `_payload` is pointer to `Expression`. + kTypeExpression = 1, + //! Relocate absolute to absolute. + kTypeAbsToAbs = 2, + //! Relocate relative to absolute. + kTypeRelToAbs = 3, + //! Relocate absolute to relative. + kTypeAbsToRel = 4, + //! Relocate absolute to relative or use trampoline. + kTypeX64AddressEntry = 5 + }; + + //! \name Accessors + //! \{ + + inline uint32_t id() const noexcept { return _id; } + + inline uint32_t relocType() const noexcept { return _relocType; } + inline const OffsetFormat& format() const noexcept { return _format; } + + inline uint32_t sourceSectionId() const noexcept { return _sourceSectionId; } + inline uint32_t targetSectionId() const noexcept { return _targetSectionId; } + + inline uint64_t sourceOffset() const noexcept { return _sourceOffset; } + inline uint64_t payload() const noexcept { return _payload; } + + Expression* payloadAsExpression() const noexcept { + return reinterpret_cast(uintptr_t(_payload)); + } + + //! \} +}; + +// ============================================================================ +// [asmjit::LabelLink] +// ============================================================================ + +//! Data structure used to link either unbound labels or cross-section links. +struct LabelLink { + //! Next link (single-linked list). + LabelLink* next; + //! Section id where the label is bound. + uint32_t sectionId; + //! Relocation id or Globals::kInvalidId. + uint32_t relocId; + //! Label offset relative to the start of the section. + size_t offset; + //! Inlined rel8/rel32. + intptr_t rel; + //! Offset format information. + OffsetFormat format; +}; + +// ============================================================================ +// [asmjit::LabelEntry] +// ============================================================================ + +//! Label entry. +//! +//! Contains the following properties: +//! * Label id - This is the only thing that is set to the `Label` operand. +//! * Label name - Optional, used mostly to create executables and libraries. +//! * Label type - Type of the label, default `Label::kTypeAnonymous`. +//! * Label parent id - Derived from many assemblers that allow to define a +//! local label that falls under a global label. This allows to define +//! many labels of the same name that have different parent (global) label. +//! * Offset - offset of the label bound by `Assembler`. +//! * Links - single-linked list that contains locations of code that has +//! to be patched when the label gets bound. Every use of unbound label +//! adds one link to `_links` list. +//! * HVal - Hash value of label's name and optionally parentId. +//! * HashNext - Hash-table implementation detail. +class LabelEntry : public ZoneHashNode { +public: + // Let's round the size of `LabelEntry` to 64 bytes (as `ZoneAllocator` has + // granularity of 32 bytes anyway). This gives `_name` the remaining space, + // which is should be 16 bytes on 64-bit and 28 bytes on 32-bit architectures. + enum : uint32_t { + kStaticNameSize = + 64 - (sizeof(ZoneHashNode) + 8 + sizeof(Section*) + sizeof(size_t) + sizeof(LabelLink*)) + }; + + //! Label type, see `Label::LabelType`. + uint8_t _type; + //! Must be zero. + uint8_t _flags; + //! Reserved. + uint16_t _reserved16; + //! Label parent id or zero. + uint32_t _parentId; + //! Label offset relative to the start of the `_section`. + uint64_t _offset; + //! Section where the label was bound. + Section* _section; + //! Label links. + LabelLink* _links; + //! Label name. + ZoneString _name; + + //! \name Accessors + //! \{ + + // NOTE: Label id is stored in `_customData`, which is provided by ZoneHashNode + // to fill a padding that a C++ compiler targeting 64-bit CPU will add to align + // the structure to 64-bits. + + //! Returns label id. + inline uint32_t id() const noexcept { return _customData; } + //! Sets label id (internal, used only by `CodeHolder`). + inline void _setId(uint32_t id) noexcept { _customData = id; } + + //! Returns label type, see `Label::LabelType`. + inline uint32_t type() const noexcept { return _type; } + //! Returns label flags, returns 0 at the moment. + inline uint32_t flags() const noexcept { return _flags; } + + //! Tests whether the label has a parent label. + inline bool hasParent() const noexcept { return _parentId != Globals::kInvalidId; } + //! Returns label's parent id. + inline uint32_t parentId() const noexcept { return _parentId; } + + //! Returns the section where the label was bound. + //! + //! If the label was not yet bound the return value is `nullptr`. + inline Section* section() const noexcept { return _section; } + + //! Tests whether the label has name. + inline bool hasName() const noexcept { return !_name.empty(); } + + //! Returns the label's name. + //! + //! \note Local labels will return their local name without their parent + //! part, for example ".L1". + inline const char* name() const noexcept { return _name.data(); } + + //! Returns size of label's name. + //! + //! \note Label name is always null terminated, so you can use `strlen()` to + //! get it, however, it's also cached in `LabelEntry` itself, so if you want + //! to know the size the fastest way is to call `LabelEntry::nameSize()`. + inline uint32_t nameSize() const noexcept { return _name.size(); } + + //! Returns links associated with this label. + inline LabelLink* links() const noexcept { return _links; } + + //! Tests whether the label is bound. + inline bool isBound() const noexcept { return _section != nullptr; } + //! Tests whether the label is bound to a the given `sectionId`. + inline bool isBoundTo(Section* section) const noexcept { return _section == section; } + + //! Returns the label offset (only useful if the label is bound). + inline uint64_t offset() const noexcept { return _offset; } + + //! Returns the hash-value of label's name and its parent label (if any). + //! + //! Label hash is calculated as `HASH(Name) ^ ParentId`. The hash function + //! is implemented in `Support::hashString()` and `Support::hashRound()`. + inline uint32_t hashCode() const noexcept { return _hashCode; } + + //! \} +}; + +// ============================================================================ +// [asmjit::AddressTableEntry] +// ============================================================================ + +//! Entry in an address table. +class AddressTableEntry : public ZoneTreeNodeT { +public: + ASMJIT_NONCOPYABLE(AddressTableEntry) + + //! Address. + uint64_t _address; + //! Slot. + uint32_t _slot; + + //! \name Construction & Destruction + //! \{ + + inline explicit AddressTableEntry(uint64_t address) noexcept + : _address(address), + _slot(0xFFFFFFFFu) {} + + //! \} + + //! \name Accessors + //! \{ + + inline uint64_t address() const noexcept { return _address; } + inline uint32_t slot() const noexcept { return _slot; } + + inline bool hasAssignedSlot() const noexcept { return _slot != 0xFFFFFFFFu; } + + inline bool operator<(const AddressTableEntry& other) const noexcept { return _address < other._address; } + inline bool operator>(const AddressTableEntry& other) const noexcept { return _address > other._address; } + + inline bool operator<(uint64_t queryAddress) const noexcept { return _address < queryAddress; } + inline bool operator>(uint64_t queryAddress) const noexcept { return _address > queryAddress; } + + //! \} +}; + +// ============================================================================ +// [asmjit::CodeHolder] +// ============================================================================ + +//! Contains basic information about the target architecture and its options. +//! +//! In addition, it holds assembled code & data (including sections, labels, and +//! relocation information). `CodeHolder` can store both binary and intermediate +//! representation of assembly, which can be generated by \ref BaseAssembler, +//! \ref BaseBuilder, and \ref BaseCompiler +//! +//! \note `CodeHolder` has an ability to attach an \ref ErrorHandler, however, +//! the error handler is not triggered by `CodeHolder` itself, it's instead +//! propagated to all emitters that attach to it. +class CodeHolder { +public: + ASMJIT_NONCOPYABLE(CodeHolder) + + //! Environment information. + Environment _environment; + //! Base address or \ref Globals::kNoBaseAddress. + uint64_t _baseAddress; + + //! Attached `Logger`, used by all consumers. + Logger* _logger; + //! Attached `ErrorHandler`. + ErrorHandler* _errorHandler; + + //! Code zone (used to allocate core structures). + Zone _zone; + //! Zone allocator, used to manage internal containers. + ZoneAllocator _allocator; + + //! Attached emitters. + ZoneVector _emitters; + //! Section entries. + ZoneVector _sections; + //! Section entries sorted by section order and then section id. + ZoneVector _sectionsByOrder; + //! Label entries. + ZoneVector _labelEntries; + //! Relocation entries. + ZoneVector _relocations; + //! Label name -> LabelEntry (only named labels). + ZoneHash _namedLabels; + + //! Count of label links, which are not resolved. + size_t _unresolvedLinkCount; + //! Pointer to an address table section (or null if this section doesn't exist). + Section* _addressTableSection; + //! Address table entries. + ZoneTree _addressTableEntries; + + //! Options that can be used with \ref copySectionData() and \ref copyFlattenedData(). + enum CopyOptions : uint32_t { + //! If virtual size of a section is greater than the size of its \ref CodeBuffer + //! then all bytes between the buffer size and virtual size will be zeroed. + //! If this option is not set then those bytes would be left as is, which + //! means that if the user didn't initialize them they would have a previous + //! content, which may be unwanted. + kCopyPadSectionBuffer = 0x00000001u, + +#ifndef ASMJIT_NO_DEPRECATED + kCopyWithPadding = kCopyPadSectionBuffer, +#endif // !ASMJIT_NO_DEPRECATED + + //! Zeroes the target buffer if the flattened data is less than the destination + //! size. This option works only with \ref copyFlattenedData() as it processes + //! multiple sections. It is ignored by \ref copySectionData(). + kCopyPadTargetBuffer = 0x00000002u + }; + + //! \name Construction & Destruction + //! \{ + + //! Creates an uninitialized CodeHolder (you must init() it before it can be used). + ASMJIT_API CodeHolder() noexcept; + //! Destroys the CodeHolder. + ASMJIT_API ~CodeHolder() noexcept; + + //! Tests whether the `CodeHolder` has been initialized. + //! + //! Emitters can be only attached to initialized `CodeHolder` instances. + inline bool isInitialized() const noexcept { return _environment.isInitialized(); } + + //! Initializes CodeHolder to hold code described by code `info`. + ASMJIT_API Error init(const Environment& environment, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept; + //! Detaches all code-generators attached and resets the `CodeHolder`. + ASMJIT_API void reset(uint32_t resetPolicy = Globals::kResetSoft) noexcept; + + //! \} + + //! \name Attach & Detach + //! \{ + + //! Attaches an emitter to this `CodeHolder`. + ASMJIT_API Error attach(BaseEmitter* emitter) noexcept; + //! Detaches an emitter from this `CodeHolder`. + ASMJIT_API Error detach(BaseEmitter* emitter) noexcept; + + //! \} + + //! \name Allocators + //! \{ + + //! Returns the allocator that the `CodeHolder` uses. + //! + //! \note This should be only used for AsmJit's purposes. Code holder uses + //! arena allocator to allocate everything, so anything allocated through + //! this allocator will be invalidated by \ref CodeHolder::reset() or by + //! CodeHolder's destructor. + inline ZoneAllocator* allocator() const noexcept { return const_cast(&_allocator); } + + //! \} + + //! \name Code & Architecture + //! \{ + + //! Returns the target environment information, see \ref Environment. + inline const Environment& environment() const noexcept { return _environment; } + + //! Returns the target architecture. + inline uint32_t arch() const noexcept { return environment().arch(); } + //! Returns the target sub-architecture. + inline uint32_t subArch() const noexcept { return environment().subArch(); } + + //! Tests whether a static base-address is set. + inline bool hasBaseAddress() const noexcept { return _baseAddress != Globals::kNoBaseAddress; } + //! Returns a static base-address or \ref Globals::kNoBaseAddress, if not set. + inline uint64_t baseAddress() const noexcept { return _baseAddress; } + + //! \} + + //! \name Emitters + //! \{ + + //! Returns a vector of attached emitters. + inline const ZoneVector& emitters() const noexcept { return _emitters; } + + //! \} + + //! \name Logging + //! \{ + + //! Returns the attached logger, see \ref Logger. + inline Logger* logger() const noexcept { return _logger; } + //! Attaches a `logger` to CodeHolder and propagates it to all attached emitters. + ASMJIT_API void setLogger(Logger* logger) noexcept; + //! Resets the logger to none. + inline void resetLogger() noexcept { setLogger(nullptr); } + + //! \name Error Handling + //! \{ + + //! Tests whether the CodeHolder has an attached error handler, see \ref ErrorHandler. + inline bool hasErrorHandler() const noexcept { return _errorHandler != nullptr; } + //! Returns the attached error handler. + inline ErrorHandler* errorHandler() const noexcept { return _errorHandler; } + //! Attach an error handler to this `CodeHolder`. + ASMJIT_API void setErrorHandler(ErrorHandler* errorHandler) noexcept; + //! Resets the error handler to none. + inline void resetErrorHandler() noexcept { setErrorHandler(nullptr); } + + //! \} + + //! \name Code Buffer + //! \{ + + //! Makes sure that at least `n` bytes can be added to CodeHolder's buffer `cb`. + //! + //! \note The buffer `cb` must be managed by `CodeHolder` - otherwise the + //! behavior of the function is undefined. + ASMJIT_API Error growBuffer(CodeBuffer* cb, size_t n) noexcept; + + //! Reserves the size of `cb` to at least `n` bytes. + //! + //! \note The buffer `cb` must be managed by `CodeHolder` - otherwise the + //! behavior of the function is undefined. + ASMJIT_API Error reserveBuffer(CodeBuffer* cb, size_t n) noexcept; + + //! \} + + //! \name Sections + //! \{ + + //! Returns an array of `Section*` records. + inline const ZoneVector& sections() const noexcept { return _sections; } + //! Returns an array of `Section*` records sorted according to section order first, then section id. + inline const ZoneVector& sectionsByOrder() const noexcept { return _sectionsByOrder; } + //! Returns the number of sections. + inline uint32_t sectionCount() const noexcept { return _sections.size(); } + + //! Tests whether the given `sectionId` is valid. + inline bool isSectionValid(uint32_t sectionId) const noexcept { return sectionId < _sections.size(); } + + //! Creates a new section and return its pointer in `sectionOut`. + //! + //! Returns `Error`, does not report a possible error to `ErrorHandler`. + ASMJIT_API Error newSection(Section** sectionOut, const char* name, size_t nameSize = SIZE_MAX, uint32_t flags = 0, uint32_t alignment = 1, int32_t order = 0) noexcept; + + //! Returns a section entry of the given index. + inline Section* sectionById(uint32_t sectionId) const noexcept { return _sections[sectionId]; } + + //! Returns section-id that matches the given `name`. + //! + //! If there is no such section `Section::kInvalidId` is returned. + ASMJIT_API Section* sectionByName(const char* name, size_t nameSize = SIZE_MAX) const noexcept; + + //! Returns '.text' section (section that commonly represents code). + //! + //! \note Text section is always the first section in \ref CodeHolder::sections() array. + inline Section* textSection() const noexcept { return _sections[0]; } + + //! Tests whether '.addrtab' section exists. + inline bool hasAddressTable() const noexcept { return _addressTableSection != nullptr; } + + //! Returns '.addrtab' section. + //! + //! This section is used exclusively by AsmJit to store absolute 64-bit + //! addresses that cannot be encoded in instructions like 'jmp' or 'call'. + //! + //! \note This section is created on demand, the returned pointer can be null. + inline Section* addressTableSection() const noexcept { return _addressTableSection; } + + //! Ensures that '.addrtab' section exists (creates it if it doesn't) and + //! returns it. Can return `nullptr` on out of memory condition. + ASMJIT_API Section* ensureAddressTableSection() noexcept; + + //! Used to add an address to an address table. + //! + //! This implicitly calls `ensureAddressTableSection()` and then creates + //! `AddressTableEntry` that is inserted to `_addressTableEntries`. If the + //! address already exists this operation does nothing as the same addresses + //! use the same slot. + //! + //! This function should be considered internal as it's used by assemblers to + //! insert an absolute address into the address table. Inserting address into + //! address table without creating a particula relocation entry makes no sense. + ASMJIT_API Error addAddressToAddressTable(uint64_t address) noexcept; + + //! \} + + //! \name Labels & Symbols + //! \{ + + //! Returns array of `LabelEntry*` records. + inline const ZoneVector& labelEntries() const noexcept { return _labelEntries; } + + //! Returns number of labels created. + inline uint32_t labelCount() const noexcept { return _labelEntries.size(); } + + //! Tests whether the label having `id` is valid (i.e. created by `newLabelEntry()`). + inline bool isLabelValid(uint32_t labelId) const noexcept { + return labelId < _labelEntries.size(); + } + + //! Tests whether the `label` is valid (i.e. created by `newLabelEntry()`). + inline bool isLabelValid(const Label& label) const noexcept { + return label.id() < _labelEntries.size(); + } + + //! \overload + inline bool isLabelBound(uint32_t labelId) const noexcept { + return isLabelValid(labelId) && _labelEntries[labelId]->isBound(); + } + + //! Tests whether the `label` is already bound. + //! + //! Returns `false` if the `label` is not valid. + inline bool isLabelBound(const Label& label) const noexcept { + return isLabelBound(label.id()); + } + + //! Returns LabelEntry of the given label `id`. + inline LabelEntry* labelEntry(uint32_t labelId) const noexcept { + return isLabelValid(labelId) ? _labelEntries[labelId] : static_cast(nullptr); + } + + //! Returns LabelEntry of the given `label`. + inline LabelEntry* labelEntry(const Label& label) const noexcept { + return labelEntry(label.id()); + } + + //! Returns offset of a `Label` by its `labelId`. + //! + //! The offset returned is relative to the start of the section. Zero offset + //! is returned for unbound labels, which is their initial offset value. + inline uint64_t labelOffset(uint32_t labelId) const noexcept { + ASMJIT_ASSERT(isLabelValid(labelId)); + return _labelEntries[labelId]->offset(); + } + + //! \overload + inline uint64_t labelOffset(const Label& label) const noexcept { + return labelOffset(label.id()); + } + + //! Returns offset of a label by it's `labelId` relative to the base offset. + //! + //! \remarks The offset of the section where the label is bound must be valid + //! in order to use this function, otherwise the value returned will not be + //! reliable. + inline uint64_t labelOffsetFromBase(uint32_t labelId) const noexcept { + ASMJIT_ASSERT(isLabelValid(labelId)); + const LabelEntry* le = _labelEntries[labelId]; + return (le->isBound() ? le->section()->offset() : uint64_t(0)) + le->offset(); + } + + //! \overload + inline uint64_t labelOffsetFromBase(const Label& label) const noexcept { + return labelOffsetFromBase(label.id()); + } + + //! Creates a new anonymous label and return its id in `idOut`. + //! + //! Returns `Error`, does not report error to `ErrorHandler`. + ASMJIT_API Error newLabelEntry(LabelEntry** entryOut) noexcept; + + //! Creates a new named \ref LabelEntry of the given label `type`. + //! + //! \param entryOut Where to store the created \ref LabelEntry. + //! \param name The name of the label. + //! \param nameSize The length of `name` argument, or `SIZE_MAX` if `name` is + //! a null terminated string, which means that the `CodeHolder` will + //! use `strlen()` to determine the length. + //! \param type The type of the label to create, see \ref Label::LabelType. + //! \param parentId Parent id of a local label, otherwise it must be + //! \ref Globals::kInvalidId. + //! + //! \retval Always returns \ref Error, does not report a possible error to + //! the attached \ref ErrorHandler. + //! + //! AsmJit has a support for local labels (\ref Label::kTypeLocal) which + //! require a parent label id (parentId). The names of local labels can + //! conflict with names of other local labels that have a different parent. + ASMJIT_API Error newNamedLabelEntry(LabelEntry** entryOut, const char* name, size_t nameSize, uint32_t type, uint32_t parentId = Globals::kInvalidId) noexcept; + + //! Returns a label by name. + //! + //! If the named label doesn't a default constructed \ref Label is returned, + //! which has its id set to \ref Globals::kInvalidId. + inline Label labelByName(const char* name, size_t nameSize = SIZE_MAX, uint32_t parentId = Globals::kInvalidId) noexcept { + return Label(labelIdByName(name, nameSize, parentId)); + } + + //! Returns a label id by name. + //! + //! If the named label doesn't exist \ref Globals::kInvalidId is returned. + ASMJIT_API uint32_t labelIdByName(const char* name, size_t nameSize = SIZE_MAX, uint32_t parentId = Globals::kInvalidId) noexcept; + + //! Tests whether there are any unresolved label links. + inline bool hasUnresolvedLinks() const noexcept { return _unresolvedLinkCount != 0; } + //! Returns the number of label links, which are unresolved. + inline size_t unresolvedLinkCount() const noexcept { return _unresolvedLinkCount; } + + //! Creates a new label-link used to store information about yet unbound labels. + //! + //! Returns `null` if the allocation failed. + ASMJIT_API LabelLink* newLabelLink(LabelEntry* le, uint32_t sectionId, size_t offset, intptr_t rel, const OffsetFormat& format) noexcept; + + //! Resolves cross-section links (`LabelLink`) associated with each label that + //! was used as a destination in code of a different section. It's only useful + //! to people that use multiple sections as it will do nothing if the code only + //! contains a single section in which cross-section links are not possible. + ASMJIT_API Error resolveUnresolvedLinks() noexcept; + + //! Binds a label to a given `sectionId` and `offset` (relative to start of the section). + //! + //! This function is generally used by `BaseAssembler::bind()` to do the heavy lifting. + ASMJIT_API Error bindLabel(const Label& label, uint32_t sectionId, uint64_t offset) noexcept; + + //! \} + + //! \name Relocations + //! \{ + + //! Tests whether the code contains relocation entries. + inline bool hasRelocEntries() const noexcept { return !_relocations.empty(); } + //! Returns array of `RelocEntry*` records. + inline const ZoneVector& relocEntries() const noexcept { return _relocations; } + + //! Returns a RelocEntry of the given `id`. + inline RelocEntry* relocEntry(uint32_t id) const noexcept { return _relocations[id]; } + + //! Creates a new relocation entry of type `relocType`. + //! + //! Additional fields can be set after the relocation entry was created. + ASMJIT_API Error newRelocEntry(RelocEntry** dst, uint32_t relocType) noexcept; + + //! \} + + //! \name Utilities + //! \{ + + //! Flattens all sections by recalculating their offsets, starting at 0. + //! + //! \note This should never be called more than once. + ASMJIT_API Error flatten() noexcept; + + //! Returns computed the size of code & data of all sections. + //! + //! \note All sections will be iterated over and the code size returned + //! would represent the minimum code size of all combined sections after + //! applying minimum alignment. Code size may decrease after calling + //! `flatten()` and `relocateToBase()`. + ASMJIT_API size_t codeSize() const noexcept; + + //! Relocates the code to the given `baseAddress`. + //! + //! \param baseAddress Absolute base address where the code will be relocated + //! to. Please note that nothing is copied to such base address, it's just an + //! absolute value used by the relocator to resolve all stored relocations. + //! + //! \note This should never be called more than once. + ASMJIT_API Error relocateToBase(uint64_t baseAddress) noexcept; + + //! Copies a single section into `dst`. + ASMJIT_API Error copySectionData(void* dst, size_t dstSize, uint32_t sectionId, uint32_t copyOptions = 0) noexcept; + + //! Copies all sections into `dst`. + //! + //! This should only be used if the data was flattened and there are no gaps + //! between the sections. The `dstSize` is always checked and the copy will + //! never write anything outside the provided buffer. + ASMJIT_API Error copyFlattenedData(void* dst, size_t dstSize, uint32_t copyOptions = 0) noexcept; + + //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use 'CodeHolder::init(const Environment& environment, uint64_t baseAddress)' instead") + inline Error init(const CodeInfo& codeInfo) noexcept { return init(codeInfo._environment, codeInfo._baseAddress); } + + ASMJIT_DEPRECATED("Use nevironment() instead") + inline CodeInfo codeInfo() const noexcept { return CodeInfo(_environment, _baseAddress); } + + ASMJIT_DEPRECATED("Use BaseEmitter::encodingOptions() - this function always returns zero") + inline uint32_t emitterOptions() const noexcept { return 0; } + + ASMJIT_DEPRECATED("Use BaseEmitter::addEncodingOptions() - this function does nothing") + inline void addEmitterOptions(uint32_t options) noexcept { DebugUtils::unused(options); } + + ASMJIT_DEPRECATED("Use BaseEmitter::clearEncodingOptions() - this function does nothing") + inline void clearEmitterOptions(uint32_t options) noexcept { DebugUtils::unused(options); } +#endif // !ASMJIT_NO_DEPRECATED +}; + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_CODEHOLDER_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codewriter.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codewriter.cpp new file mode 100644 index 0000000..6097c0e --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codewriter.cpp @@ -0,0 +1,151 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/codeholder.h" +#include "../core/codewriter_p.h" + +ASMJIT_BEGIN_NAMESPACE + +bool CodeWriterUtils::encodeOffset32(uint32_t* dst, int64_t offset64, const OffsetFormat& format) noexcept { + uint32_t bitCount = format.immBitCount(); + uint32_t bitShift = format.immBitShift(); + uint32_t discardLsb = format.immDiscardLsb(); + + if (!bitCount || bitCount > format.valueSize() * 8u) + return false; + + if (discardLsb) { + ASMJIT_ASSERT(discardLsb <= 32); + if ((offset64 & Support::lsbMask(discardLsb)) != 0) + return false; + offset64 >>= discardLsb; + } + + if (!Support::isInt32(offset64)) + return false; + + int32_t offset32 = int32_t(offset64); + if (!Support::isEncodableOffset32(offset32, bitCount)) + return false; + + switch (format.type()) { + case OffsetFormat::kTypeCommon: { + *dst = (uint32_t(offset32) & Support::lsbMask(bitCount)) << bitShift; + return true; + } + + case OffsetFormat::kTypeAArch64_ADR: + case OffsetFormat::kTypeAArch64_ADRP: { + // Sanity checks. + if (format.valueSize() != 4 || bitCount != 21 || bitShift != 5) + return false; + + uint32_t immLo = uint32_t(offset32) & 0x3u; + uint32_t immHi = uint32_t(offset32 >> 2) & Support::lsbMask(19); + + *dst = (immLo << 29) | (immHi << 5); + return true; + } + + default: + return false; + } +} + +bool CodeWriterUtils::encodeOffset64(uint64_t* dst, int64_t offset64, const OffsetFormat& format) noexcept { + uint32_t bitCount = format.immBitCount(); + uint32_t discardLsb = format.immDiscardLsb(); + + if (!bitCount || bitCount > format.valueSize() * 8u) + return false; + + if (discardLsb) { + ASMJIT_ASSERT(discardLsb <= 32); + if ((offset64 & Support::lsbMask(discardLsb)) != 0) + return false; + offset64 >>= discardLsb; + } + + if (!Support::isEncodableOffset64(offset64, bitCount)) + return false; + + switch (format.type()) { + case OffsetFormat::kTypeCommon: { + *dst = (uint64_t(offset64) & Support::lsbMask(bitCount)) << format.immBitShift(); + return true; + } + + default: + return false; + } +} + +bool CodeWriterUtils::writeOffset(void* dst, int64_t offset64, const OffsetFormat& format) noexcept { + // Offset the destination by ValueOffset so the `dst` points to the + // patched word instead of the beginning of the patched region. + dst = static_cast(dst) + format.valueOffset(); + + switch (format.valueSize()) { + case 1: { + uint32_t mask; + if (!encodeOffset32(&mask, offset64, format)) + return false; + + Support::writeU8(dst, Support::readU8(dst) | mask); + return true; + } + + case 2: { + uint32_t mask; + if (!encodeOffset32(&mask, offset64, format)) + return false; + + Support::writeU16uLE(dst, Support::readU16uLE(dst) | mask); + return true; + } + + case 4: { + uint32_t mask; + if (!encodeOffset32(&mask, offset64, format)) + return false; + + Support::writeU32uLE(dst, Support::readU32uLE(dst) | mask); + return true; + } + + case 8: { + uint64_t mask; + if (!encodeOffset64(&mask, offset64, format)) + return false; + + Support::writeU64uLE(dst, Support::readU64uLE(dst) | mask); + return true; + } + + default: + return false; + } +} + +ASMJIT_END_NAMESPACE diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codewriter_p.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codewriter_p.h new file mode 100644 index 0000000..61c9101 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codewriter_p.h @@ -0,0 +1,208 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_CODEBUFFERWRITER_P_H_INCLUDED +#define ASMJIT_CORE_CODEBUFFERWRITER_P_H_INCLUDED + +#include "../core/assembler.h" +#include "../core/codebuffer.h" +#include "../core/support.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \cond INTERNAL +//! \addtogroup asmjit_assembler +//! \{ + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +struct OffsetFormat; + +// ============================================================================ +// [asmjit::CodeWriter] +// ============================================================================ + +//! Helper that is used to write into a \ref CodeBuffer held by \ref BaseAssembler. +class CodeWriter { +public: + uint8_t* _cursor; + + ASMJIT_INLINE explicit CodeWriter(BaseAssembler* a) noexcept + : _cursor(a->_bufferPtr) {} + + ASMJIT_INLINE Error ensureSpace(BaseAssembler* a, size_t n) noexcept { + size_t remainingSpace = (size_t)(a->_bufferEnd - _cursor); + if (ASMJIT_UNLIKELY(remainingSpace < n)) { + CodeBuffer& buffer = a->_section->_buffer; + Error err = a->_code->growBuffer(&buffer, n); + if (ASMJIT_UNLIKELY(err)) + return a->reportError(err); + _cursor = a->_bufferPtr; + } + return kErrorOk; + } + + ASMJIT_INLINE uint8_t* cursor() const noexcept { return _cursor; } + ASMJIT_INLINE void setCursor(uint8_t* cursor) noexcept { _cursor = cursor; } + ASMJIT_INLINE void advance(size_t n) noexcept { _cursor += n; } + + ASMJIT_INLINE size_t offsetFrom(uint8_t* from) const noexcept { + ASMJIT_ASSERT(_cursor >= from); + return (size_t)(_cursor - from); + } + + template + ASMJIT_INLINE void emit8(T val) noexcept { + typedef typename std::make_unsigned::type U; + _cursor[0] = uint8_t(U(val) & U(0xFF)); + _cursor++; + } + + template + ASMJIT_INLINE void emit8If(T val, Y cond) noexcept { + typedef typename std::make_unsigned::type U; + ASMJIT_ASSERT(size_t(cond) <= 1u); + + _cursor[0] = uint8_t(U(val) & U(0xFF)); + _cursor += size_t(cond); + } + + template + ASMJIT_INLINE void emit16uLE(T val) noexcept { + typedef typename std::make_unsigned::type U; + Support::writeU16uLE(_cursor, uint32_t(U(val) & 0xFFFFu)); + _cursor += 2; + } + + template + ASMJIT_INLINE void emit16uBE(T val) noexcept { + typedef typename std::make_unsigned::type U; + Support::writeU16uBE(_cursor, uint32_t(U(val) & 0xFFFFu)); + _cursor += 2; + } + + template + ASMJIT_INLINE void emit32uLE(T val) noexcept { + typedef typename std::make_unsigned::type U; + Support::writeU32uLE(_cursor, uint32_t(U(val) & 0xFFFFFFFFu)); + _cursor += 4; + } + + template + ASMJIT_INLINE void emit32uBE(T val) noexcept { + typedef typename std::make_unsigned::type U; + Support::writeU32uBE(_cursor, uint32_t(U(val) & 0xFFFFFFFFu)); + _cursor += 4; + } + + ASMJIT_INLINE void emitData(const void* data, size_t size) noexcept { + ASMJIT_ASSERT(size != 0); + memcpy(_cursor, data, size); + _cursor += size; + } + + template + ASMJIT_INLINE void emitValueLE(const T& value, size_t size) noexcept { + typedef typename std::make_unsigned::type U; + ASMJIT_ASSERT(size <= sizeof(T)); + + U v = U(value); + for (uint32_t i = 0; i < size; i++) { + _cursor[i] = uint8_t(v & 0xFFu); + v >>= 8; + } + _cursor += size; + } + + template + ASMJIT_INLINE void emitValueBE(const T& value, size_t size) noexcept { + typedef typename std::make_unsigned::type U; + ASMJIT_ASSERT(size <= sizeof(T)); + + U v = U(value); + for (uint32_t i = 0; i < size; i++) { + _cursor[i] = uint8_t(v >> (sizeof(T) - 8)); + v <<= 8; + } + _cursor += size; + } + + ASMJIT_INLINE void emitZeros(size_t size) noexcept { + ASMJIT_ASSERT(size != 0); + memset(_cursor, 0, size); + _cursor += size; + } + + ASMJIT_INLINE void remove8(uint8_t* where) noexcept { + ASMJIT_ASSERT(where < _cursor); + + uint8_t* p = where; + while (++p != _cursor) + p[-1] = p[0]; + _cursor--; + } + + template + ASMJIT_INLINE void insert8(uint8_t* where, T val) noexcept { + uint8_t* p = _cursor; + + while (p != where) { + p[0] = p[-1]; + p--; + } + + *p = uint8_t(val & 0xFF); + _cursor++; + } + + ASMJIT_INLINE void done(BaseAssembler* a) noexcept { + CodeBuffer& buffer = a->_section->_buffer; + size_t newSize = (size_t)(_cursor - a->_bufferData); + ASMJIT_ASSERT(newSize <= buffer.capacity()); + + a->_bufferPtr = _cursor; + buffer._size = Support::max(buffer._size, newSize); + } +}; + +// ============================================================================ +// [asmjit::CodeWriterUtils] +// ============================================================================ + +namespace CodeWriterUtils { + +bool encodeOffset32(uint32_t* dst, int64_t offset64, const OffsetFormat& format) noexcept; +bool encodeOffset64(uint64_t* dst, int64_t offset64, const OffsetFormat& format) noexcept; + +bool writeOffset(void* dst, int64_t offset64, const OffsetFormat& format) noexcept; + +} // {CodeWriterUtils} + +//! \} +//! \endcond + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_CODEBUFFERWRITER_P_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/compiler.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/compiler.cpp new file mode 100644 index 0000000..4d7baab --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/compiler.cpp @@ -0,0 +1,628 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#ifndef ASMJIT_NO_COMPILER + +#include "../core/assembler.h" +#include "../core/compiler.h" +#include "../core/cpuinfo.h" +#include "../core/logger.h" +#include "../core/rapass_p.h" +#include "../core/rastack_p.h" +#include "../core/support.h" +#include "../core/type.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::GlobalConstPoolPass] +// ============================================================================ + +class GlobalConstPoolPass : public Pass { + typedef Pass Base; + ASMJIT_NONCOPYABLE(GlobalConstPoolPass) + + GlobalConstPoolPass() noexcept : Pass("GlobalConstPoolPass") {} + + Error run(Zone* zone, Logger* logger) override { + DebugUtils::unused(zone, logger); + + // Flush the global constant pool. + BaseCompiler* compiler = static_cast(_cb); + if (compiler->_globalConstPool) { + compiler->addAfter(compiler->_globalConstPool, compiler->lastNode()); + compiler->_globalConstPool = nullptr; + } + + return kErrorOk; + } +}; + +// ============================================================================ +// [asmjit::BaseCompiler - Construction / Destruction] +// ============================================================================ + +BaseCompiler::BaseCompiler() noexcept + : BaseBuilder(), + _func(nullptr), + _vRegZone(4096 - Zone::kBlockOverhead), + _vRegArray(), + _localConstPool(nullptr), + _globalConstPool(nullptr) { + + _emitterType = uint8_t(kTypeCompiler); + _validationFlags = uint8_t(InstAPI::kValidationFlagVirtRegs); +} +BaseCompiler::~BaseCompiler() noexcept {} + +// ============================================================================ +// [asmjit::BaseCompiler - Function Management] +// ============================================================================ + +Error BaseCompiler::_newFuncNode(FuncNode** out, const FuncSignature& signature) { + *out = nullptr; + + // Create FuncNode together with all the required surrounding nodes. + FuncNode* funcNode; + ASMJIT_PROPAGATE(_newNodeT(&funcNode)); + ASMJIT_PROPAGATE(_newLabelNode(&funcNode->_exitNode)); + ASMJIT_PROPAGATE(_newNodeT(&funcNode->_end, SentinelNode::kSentinelFuncEnd)); + + // Initialize the function's detail info. + Error err = funcNode->detail().init(signature, environment()); + if (ASMJIT_UNLIKELY(err)) + return reportError(err); + + // If the Target guarantees greater stack alignment than required by the + // calling convention then override it as we can prevent having to perform + // dynamic stack alignment + uint32_t environmentStackAlignment = _environment.stackAlignment(); + + if (funcNode->_funcDetail._callConv.naturalStackAlignment() < environmentStackAlignment) + funcNode->_funcDetail._callConv.setNaturalStackAlignment(environmentStackAlignment); + + // Initialize the function frame. + err = funcNode->_frame.init(funcNode->_funcDetail); + if (ASMJIT_UNLIKELY(err)) + return reportError(err); + + // Allocate space for function arguments. + funcNode->_args = nullptr; + if (funcNode->argCount() != 0) { + funcNode->_args = _allocator.allocT(funcNode->argCount() * sizeof(FuncNode::ArgPack)); + if (ASMJIT_UNLIKELY(!funcNode->_args)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + memset(funcNode->_args, 0, funcNode->argCount() * sizeof(FuncNode::ArgPack)); + } + + ASMJIT_PROPAGATE(registerLabelNode(funcNode)); + + *out = funcNode; + return kErrorOk; +} + +Error BaseCompiler::_addFuncNode(FuncNode** out, const FuncSignature& signature) { + ASMJIT_PROPAGATE(_newFuncNode(out, signature)); + addFunc(*out); + return kErrorOk; +} + +Error BaseCompiler::_newRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1) { + uint32_t opCount = !o1.isNone() ? 2u : !o0.isNone() ? 1u : 0u; + FuncRetNode* node; + + ASMJIT_PROPAGATE(_newNodeT(&node)); + node->setOpCount(opCount); + node->setOp(0, o0); + node->setOp(1, o1); + node->resetOpRange(2, node->opCapacity()); + + *out = node; + return kErrorOk; +} + +Error BaseCompiler::_addRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1) { + ASMJIT_PROPAGATE(_newRetNode(out, o0, o1)); + addNode(*out); + return kErrorOk; +} + +FuncNode* BaseCompiler::addFunc(FuncNode* func) { + ASMJIT_ASSERT(_func == nullptr); + _func = func; + + addNode(func); // Function node. + BaseNode* prev = cursor(); // {CURSOR}. + addNode(func->exitNode()); // Function exit label. + addNode(func->endNode()); // Function end sentinel. + + _setCursor(prev); + return func; +} + +Error BaseCompiler::endFunc() { + FuncNode* func = _func; + + if (ASMJIT_UNLIKELY(!func)) + return reportError(DebugUtils::errored(kErrorInvalidState)); + + // Add the local constant pool at the end of the function (if exists). + if (_localConstPool) { + setCursor(func->endNode()->prev()); + addNode(_localConstPool); + _localConstPool = nullptr; + } + + // Mark as finished. + _func = nullptr; + + SentinelNode* end = func->endNode(); + setCursor(end); + + return kErrorOk; +} + +Error BaseCompiler::_setArg(size_t argIndex, size_t valueIndex, const BaseReg& r) { + FuncNode* func = _func; + + if (ASMJIT_UNLIKELY(!func)) + return reportError(DebugUtils::errored(kErrorInvalidState)); + + if (ASMJIT_UNLIKELY(!isVirtRegValid(r))) + return reportError(DebugUtils::errored(kErrorInvalidVirtId)); + + VirtReg* vReg = virtRegByReg(r); + func->setArg(argIndex, valueIndex, vReg); + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::BaseCompiler - Function Invocation] +// ============================================================================ + +Error BaseCompiler::_newInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature) { + InvokeNode* node; + ASMJIT_PROPAGATE(_newNodeT(&node, instId, 0u)); + + node->setOpCount(1); + node->setOp(0, o0); + node->resetOpRange(1, node->opCapacity()); + + Error err = node->detail().init(signature, environment()); + if (ASMJIT_UNLIKELY(err)) + return reportError(err); + + // Skip the allocation if there are no arguments. + uint32_t argCount = signature.argCount(); + if (argCount) { + node->_args = static_cast(_allocator.alloc(argCount * sizeof(InvokeNode::OperandPack))); + if (!node->_args) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + memset(node->_args, 0, argCount * sizeof(InvokeNode::OperandPack)); + } + + *out = node; + return kErrorOk; +} + +Error BaseCompiler::_addInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature) { + ASMJIT_PROPAGATE(_newInvokeNode(out, instId, o0, signature)); + addNode(*out); + return kErrorOk; +} + +// ============================================================================ +// [asmjit::BaseCompiler - Virtual Registers] +// ============================================================================ + +static void BaseCompiler_assignGenericName(BaseCompiler* self, VirtReg* vReg) { + uint32_t index = unsigned(Operand::virtIdToIndex(vReg->_id)); + + char buf[64]; + int size = snprintf(buf, ASMJIT_ARRAY_SIZE(buf), "%%%u", unsigned(index)); + + ASMJIT_ASSERT(size > 0 && size < int(ASMJIT_ARRAY_SIZE(buf))); + vReg->_name.setData(&self->_dataZone, buf, unsigned(size)); +} + +Error BaseCompiler::newVirtReg(VirtReg** out, uint32_t typeId, uint32_t signature, const char* name) { + *out = nullptr; + uint32_t index = _vRegArray.size(); + + if (ASMJIT_UNLIKELY(index >= uint32_t(Operand::kVirtIdCount))) + return reportError(DebugUtils::errored(kErrorTooManyVirtRegs)); + + if (ASMJIT_UNLIKELY(_vRegArray.willGrow(&_allocator) != kErrorOk)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + + VirtReg* vReg = _vRegZone.allocZeroedT(); + if (ASMJIT_UNLIKELY(!vReg)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + + uint32_t size = Type::sizeOf(typeId); + uint32_t alignment = Support::min(size, 64); + + vReg = new(vReg) VirtReg(Operand::indexToVirtId(index), signature, size, alignment, typeId); + +#ifndef ASMJIT_NO_LOGGING + if (name && name[0] != '\0') + vReg->_name.setData(&_dataZone, name, SIZE_MAX); + else + BaseCompiler_assignGenericName(this, vReg); +#else + DebugUtils::unused(name); +#endif + + _vRegArray.appendUnsafe(vReg); + *out = vReg; + + return kErrorOk; +} + +Error BaseCompiler::_newReg(BaseReg* out, uint32_t typeId, const char* name) { + RegInfo regInfo; + out->reset(); + + Error err = ArchUtils::typeIdToRegInfo(arch(), typeId, &typeId, ®Info); + if (ASMJIT_UNLIKELY(err)) + return reportError(err); + + VirtReg* vReg; + ASMJIT_PROPAGATE(newVirtReg(&vReg, typeId, regInfo.signature(), name)); + + out->_initReg(regInfo.signature(), vReg->id()); + return kErrorOk; +} + +Error BaseCompiler::_newRegFmt(BaseReg* out, uint32_t typeId, const char* fmt, ...) { + va_list ap; + StringTmp<256> sb; + + va_start(ap, fmt); + sb.appendVFormat(fmt, ap); + va_end(ap); + + return _newReg(out, typeId, sb.data()); +} + +Error BaseCompiler::_newReg(BaseReg* out, const BaseReg& ref, const char* name) { + out->reset(); + + RegInfo regInfo; + uint32_t typeId; + + if (isVirtRegValid(ref)) { + VirtReg* vRef = virtRegByReg(ref); + typeId = vRef->typeId(); + + // NOTE: It's possible to cast one register type to another if it's the + // same register group. However, VirtReg always contains the TypeId that + // was used to create the register. This means that in some cases we may + // end up having different size of `ref` and `vRef`. In such case we + // adjust the TypeId to match the `ref` register type instead of the + // original register type, which should be the expected behavior. + uint32_t typeSize = Type::sizeOf(typeId); + uint32_t refSize = ref.size(); + + if (typeSize != refSize) { + if (Type::isInt(typeId)) { + // GP register - change TypeId to match `ref`, but keep sign of `vRef`. + switch (refSize) { + case 1: typeId = Type::kIdI8 | (typeId & 1); break; + case 2: typeId = Type::kIdI16 | (typeId & 1); break; + case 4: typeId = Type::kIdI32 | (typeId & 1); break; + case 8: typeId = Type::kIdI64 | (typeId & 1); break; + default: typeId = Type::kIdVoid; break; + } + } + else if (Type::isMmx(typeId)) { + // MMX register - always use 64-bit. + typeId = Type::kIdMmx64; + } + else if (Type::isMask(typeId)) { + // Mask register - change TypeId to match `ref` size. + switch (refSize) { + case 1: typeId = Type::kIdMask8; break; + case 2: typeId = Type::kIdMask16; break; + case 4: typeId = Type::kIdMask32; break; + case 8: typeId = Type::kIdMask64; break; + default: typeId = Type::kIdVoid; break; + } + } + else { + // VEC register - change TypeId to match `ref` size, keep vector metadata. + uint32_t elementTypeId = Type::baseOf(typeId); + + switch (refSize) { + case 16: typeId = Type::_kIdVec128Start + (elementTypeId - Type::kIdI8); break; + case 32: typeId = Type::_kIdVec256Start + (elementTypeId - Type::kIdI8); break; + case 64: typeId = Type::_kIdVec512Start + (elementTypeId - Type::kIdI8); break; + default: typeId = Type::kIdVoid; break; + } + } + + if (typeId == Type::kIdVoid) + return reportError(DebugUtils::errored(kErrorInvalidState)); + } + } + else { + typeId = ref.type(); + } + + Error err = ArchUtils::typeIdToRegInfo(arch(), typeId, &typeId, ®Info); + if (ASMJIT_UNLIKELY(err)) + return reportError(err); + + VirtReg* vReg; + ASMJIT_PROPAGATE(newVirtReg(&vReg, typeId, regInfo.signature(), name)); + + out->_initReg(regInfo.signature(), vReg->id()); + return kErrorOk; +} + +Error BaseCompiler::_newRegFmt(BaseReg* out, const BaseReg& ref, const char* fmt, ...) { + va_list ap; + StringTmp<256> sb; + + va_start(ap, fmt); + sb.appendVFormat(fmt, ap); + va_end(ap); + + return _newReg(out, ref, sb.data()); +} + +Error BaseCompiler::_newStack(BaseMem* out, uint32_t size, uint32_t alignment, const char* name) { + out->reset(); + + if (size == 0) + return reportError(DebugUtils::errored(kErrorInvalidArgument)); + + if (alignment == 0) + alignment = 1; + + if (!Support::isPowerOf2(alignment)) + return reportError(DebugUtils::errored(kErrorInvalidArgument)); + + if (alignment > 64) + alignment = 64; + + VirtReg* vReg; + ASMJIT_PROPAGATE(newVirtReg(&vReg, 0, 0, name)); + + vReg->_virtSize = size; + vReg->_isStack = true; + vReg->_alignment = uint8_t(alignment); + + // Set the memory operand to GPD/GPQ and its id to VirtReg. + *out = BaseMem(BaseMem::Decomposed { _gpRegInfo.type(), vReg->id(), BaseReg::kTypeNone, 0, 0, 0, BaseMem::kSignatureMemRegHomeFlag }); + return kErrorOk; +} + +Error BaseCompiler::setStackSize(uint32_t virtId, uint32_t newSize, uint32_t newAlignment) { + if (!isVirtIdValid(virtId)) + return DebugUtils::errored(kErrorInvalidVirtId); + + if (newAlignment && !Support::isPowerOf2(newAlignment)) + return reportError(DebugUtils::errored(kErrorInvalidArgument)); + + if (newAlignment > 64) + newAlignment = 64; + + VirtReg* vReg = virtRegById(virtId); + if (newSize) + vReg->_virtSize = newSize; + + if (newAlignment) + vReg->_alignment = uint8_t(newAlignment); + + // This is required if the RAPass is already running. There is a chance that + // a stack-slot has been already allocated and in that case it has to be + // updated as well, otherwise we would allocate wrong amount of memory. + RAWorkReg* workReg = vReg->_workReg; + if (workReg && workReg->_stackSlot) { + workReg->_stackSlot->_size = vReg->_virtSize; + workReg->_stackSlot->_alignment = vReg->_alignment; + } + + return kErrorOk; +} + +Error BaseCompiler::_newConst(BaseMem* out, uint32_t scope, const void* data, size_t size) { + out->reset(); + ConstPoolNode** pPool; + + if (scope == ConstPool::kScopeLocal) + pPool = &_localConstPool; + else if (scope == ConstPool::kScopeGlobal) + pPool = &_globalConstPool; + else + return reportError(DebugUtils::errored(kErrorInvalidArgument)); + + if (!*pPool) + ASMJIT_PROPAGATE(_newConstPoolNode(pPool)); + + ConstPoolNode* pool = *pPool; + size_t off; + Error err = pool->add(data, size, off); + + if (ASMJIT_UNLIKELY(err)) + return reportError(err); + + *out = BaseMem(BaseMem::Decomposed { + Label::kLabelTag, // Base type. + pool->labelId(), // Base id. + 0, // Index type. + 0, // Index id. + int32_t(off), // Offset. + uint32_t(size), // Size. + 0 // Flags. + }); + + return kErrorOk; +} + +void BaseCompiler::rename(const BaseReg& reg, const char* fmt, ...) { + if (!reg.isVirtReg()) return; + + VirtReg* vReg = virtRegById(reg.id()); + if (!vReg) return; + + if (fmt && fmt[0] != '\0') { + char buf[128]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap); + va_end(ap); + + vReg->_name.setData(&_dataZone, buf, SIZE_MAX); + } + else { + BaseCompiler_assignGenericName(this, vReg); + } +} + +// ============================================================================ +// [asmjit::BaseCompiler - Jump Annotations] +// ============================================================================ + +Error BaseCompiler::newJumpNode(JumpNode** out, uint32_t instId, uint32_t instOptions, const Operand_& o0, JumpAnnotation* annotation) { + JumpNode* node = _allocator.allocT(); + uint32_t opCount = 1; + + *out = node; + if (ASMJIT_UNLIKELY(!node)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + + node = new(node) JumpNode(this, instId, instOptions, opCount, annotation); + node->setOp(0, o0); + node->resetOpRange(opCount, JumpNode::kBaseOpCapacity); + + return kErrorOk; +} + +Error BaseCompiler::emitAnnotatedJump(uint32_t instId, const Operand_& o0, JumpAnnotation* annotation) { + uint32_t options = instOptions() | forcedInstOptions(); + RegOnly extra = extraReg(); + const char* comment = inlineComment(); + + resetInstOptions(); + resetInlineComment(); + resetExtraReg(); + + JumpNode* node; + ASMJIT_PROPAGATE(newJumpNode(&node, instId, options, o0, annotation)); + + node->setExtraReg(extra); + if (comment) + node->setInlineComment(static_cast(_dataZone.dup(comment, strlen(comment), true))); + + addNode(node); + return kErrorOk; +} + +JumpAnnotation* BaseCompiler::newJumpAnnotation() { + if (_jumpAnnotations.grow(&_allocator, 1) != kErrorOk) { + reportError(DebugUtils::errored(kErrorOutOfMemory)); + return nullptr; + } + + uint32_t id = _jumpAnnotations.size(); + JumpAnnotation* jumpAnnotation = _allocator.newT(this, id); + + if (!jumpAnnotation) { + reportError(DebugUtils::errored(kErrorOutOfMemory)); + return nullptr; + } + + _jumpAnnotations.appendUnsafe(jumpAnnotation); + return jumpAnnotation; +} + +// ============================================================================ +// [asmjit::BaseCompiler - Events] +// ============================================================================ + +Error BaseCompiler::onAttach(CodeHolder* code) noexcept { + ASMJIT_PROPAGATE(Base::onAttach(code)); + + const ArchTraits& archTraits = ArchTraits::byArch(code->arch()); + uint32_t nativeRegType = Environment::is32Bit(code->arch()) ? BaseReg::kTypeGp32 : BaseReg::kTypeGp64; + _gpRegInfo.setSignature(archTraits.regTypeToSignature(nativeRegType)); + + Error err = addPassT(); + if (ASMJIT_UNLIKELY(err)) { + onDetach(code); + return err; + } + + return kErrorOk; +} + +Error BaseCompiler::onDetach(CodeHolder* code) noexcept { + _func = nullptr; + _localConstPool = nullptr; + _globalConstPool = nullptr; + + _vRegArray.reset(); + _vRegZone.reset(); + + return Base::onDetach(code); +} + +// ============================================================================ +// [asmjit::FuncPass - Construction / Destruction] +// ============================================================================ + +FuncPass::FuncPass(const char* name) noexcept + : Pass(name) {} + +// ============================================================================ +// [asmjit::FuncPass - Run] +// ============================================================================ + +Error FuncPass::run(Zone* zone, Logger* logger) { + BaseNode* node = cb()->firstNode(); + if (!node) return kErrorOk; + + do { + if (node->type() == BaseNode::kNodeFunc) { + FuncNode* func = node->as(); + node = func->endNode(); + ASMJIT_PROPAGATE(runOnFunction(zone, logger, func)); + } + + // Find a function by skipping all nodes that are not `kNodeFunc`. + do { + node = node->next(); + } while (node && node->type() != BaseNode::kNodeFunc); + } while (node); + + return kErrorOk; +} + +ASMJIT_END_NAMESPACE + +#endif // !ASMJIT_NO_COMPILER diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/compiler.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/compiler.h new file mode 100644 index 0000000..eb2a5aa --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/compiler.h @@ -0,0 +1,763 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_COMPILER_H_INCLUDED +#define ASMJIT_CORE_COMPILER_H_INCLUDED + +#include "../core/api-config.h" +#ifndef ASMJIT_NO_COMPILER + +#include "../core/assembler.h" +#include "../core/builder.h" +#include "../core/constpool.h" +#include "../core/compilerdefs.h" +#include "../core/func.h" +#include "../core/inst.h" +#include "../core/operand.h" +#include "../core/support.h" +#include "../core/zone.h" +#include "../core/zonevector.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +class JumpAnnotation; +class JumpNode; +class FuncNode; +class FuncRetNode; +class InvokeNode; + +//! \addtogroup asmjit_compiler +//! \{ + +// ============================================================================ +// [asmjit::BaseCompiler] +// ============================================================================ + +//! Code emitter that uses virtual registers and performs register allocation. +//! +//! Compiler is a high-level code-generation tool that provides register +//! allocation and automatic handling of function calling conventions. It was +//! primarily designed for merging multiple parts of code into a function +//! without worrying about registers and function calling conventions. +//! +//! BaseCompiler can be used, with a minimum effort, to handle 32-bit and +//! 64-bit code generation within a single code base. +//! +//! BaseCompiler is based on BaseBuilder and contains all the features it +//! provides. It means that the code it stores can be modified (removed, added, +//! injected) and analyzed. When the code is finalized the compiler can emit +//! the code into an Assembler to translate the abstract representation into a +//! machine code. +//! +//! Check out architecture specific compilers for more details and examples: +//! +//! - \ref x86::Compiler - X86/X64 compiler implementation. +class ASMJIT_VIRTAPI BaseCompiler : public BaseBuilder { +public: + ASMJIT_NONCOPYABLE(BaseCompiler) + typedef BaseBuilder Base; + + //! Current function. + FuncNode* _func; + //! Allocates `VirtReg` objects. + Zone _vRegZone; + //! Stores array of `VirtReg` pointers. + ZoneVector _vRegArray; + //! Stores jump annotations. + ZoneVector _jumpAnnotations; + + //! Local constant pool, flushed at the end of each function. + ConstPoolNode* _localConstPool; + //! Global constant pool, flushed by `finalize()`. + ConstPoolNode* _globalConstPool; + + //! \name Construction & Destruction + //! \{ + + //! Creates a new `BaseCompiler` instance. + ASMJIT_API BaseCompiler() noexcept; + //! Destroys the `BaseCompiler` instance. + ASMJIT_API virtual ~BaseCompiler() noexcept; + + //! \} + + //! \name Function Management + //! \{ + + //! Returns the current function. + inline FuncNode* func() const noexcept { return _func; } + + //! Creates a new \ref FuncNode. + ASMJIT_API Error _newFuncNode(FuncNode** out, const FuncSignature& signature); + //! Creates a new \ref FuncNode adds it to the compiler. + ASMJIT_API Error _addFuncNode(FuncNode** out, const FuncSignature& signature); + + //! Creates a new \ref FuncRetNode. + ASMJIT_API Error _newRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1); + //! Creates a new \ref FuncRetNode and adds it to the compiler. + ASMJIT_API Error _addRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1); + + //! Creates a new \ref FuncNode with the given `signature` and returns it. + inline FuncNode* newFunc(const FuncSignature& signature) { + FuncNode* node; + _newFuncNode(&node, signature); + return node; + } + + //! Creates a new \ref FuncNode with the given `signature`, adds it to the + //! compiler by using the \ref addFunc(FuncNode*) overload, and returns it. + inline FuncNode* addFunc(const FuncSignature& signature) { + FuncNode* node; + _addFuncNode(&node, signature); + return node; + } + + //! Adds a function `node` to the instruction stream. + ASMJIT_API FuncNode* addFunc(FuncNode* func); + //! Emits a sentinel that marks the end of the current function. + ASMJIT_API Error endFunc(); + + ASMJIT_API Error _setArg(size_t argIndex, size_t valueIndex, const BaseReg& reg); + + //! Sets a function argument at `argIndex` to `reg`. + inline Error setArg(size_t argIndex, const BaseReg& reg) { return _setArg(argIndex, 0, reg); } + //! Sets a function argument at `argIndex` at `valueIndex` to `reg`. + inline Error setArg(size_t argIndex, size_t valueIndex, const BaseReg& reg) { return _setArg(argIndex, valueIndex, reg); } + + inline FuncRetNode* newRet(const Operand_& o0, const Operand_& o1) { + FuncRetNode* node; + _newRetNode(&node, o0, o1); + return node; + } + + inline FuncRetNode* addRet(const Operand_& o0, const Operand_& o1) { + FuncRetNode* node; + _addRetNode(&node, o0, o1); + return node; + } + + //! \} + + //! \name Function Invocation + //! \{ + + //! Creates a new \ref InvokeNode. + ASMJIT_API Error _newInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature); + //! Creates a new \ref InvokeNode and adds it to Compiler. + ASMJIT_API Error _addInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature); + + //! Creates a new `InvokeNode`. + inline InvokeNode* newCall(uint32_t instId, const Operand_& o0, const FuncSignature& signature) { + InvokeNode* node; + _newInvokeNode(&node, instId, o0, signature); + return node; + } + + //! Adds a new `InvokeNode`. + inline InvokeNode* addCall(uint32_t instId, const Operand_& o0, const FuncSignature& signature) { + InvokeNode* node; + _addInvokeNode(&node, instId, o0, signature); + return node; + } + + //! \} + + //! \name Virtual Registers + //! \{ + + //! Creates a new virtual register representing the given `typeId` and `signature`. + //! + //! \note This function is public, but it's not generally recommended to be used + //! by AsmJit users, use architecture-specific `newReg()` functionality instead + //! or functions like \ref _newReg() and \ref _newRegFmt(). + ASMJIT_API Error newVirtReg(VirtReg** out, uint32_t typeId, uint32_t signature, const char* name); + + //! Creates a new virtual register of the given `typeId` and stores it to `out` operand. + ASMJIT_API Error _newReg(BaseReg* out, uint32_t typeId, const char* name = nullptr); + + //! Creates a new virtual register of the given `typeId` and stores it to `out` operand. + //! + //! \note This version accepts a snprintf() format `fmt` followed by a variadic arguments. + ASMJIT_API Error _newRegFmt(BaseReg* out, uint32_t typeId, const char* fmt, ...); + + //! Creates a new virtual register compatible with the provided reference register `ref`. + ASMJIT_API Error _newReg(BaseReg* out, const BaseReg& ref, const char* name = nullptr); + + //! Creates a new virtual register compatible with the provided reference register `ref`. + //! + //! \note This version accepts a snprintf() format `fmt` followed by a variadic arguments. + ASMJIT_API Error _newRegFmt(BaseReg* out, const BaseReg& ref, const char* fmt, ...); + + //! Tests whether the given `id` is a valid virtual register id. + inline bool isVirtIdValid(uint32_t id) const noexcept { + uint32_t index = Operand::virtIdToIndex(id); + return index < _vRegArray.size(); + } + //! Tests whether the given `reg` is a virtual register having a valid id. + inline bool isVirtRegValid(const BaseReg& reg) const noexcept { + return isVirtIdValid(reg.id()); + } + + //! Returns \ref VirtReg associated with the given `id`. + inline VirtReg* virtRegById(uint32_t id) const noexcept { + ASMJIT_ASSERT(isVirtIdValid(id)); + return _vRegArray[Operand::virtIdToIndex(id)]; + } + + //! Returns \ref VirtReg associated with the given `reg`. + inline VirtReg* virtRegByReg(const BaseReg& reg) const noexcept { return virtRegById(reg.id()); } + + //! Returns \ref VirtReg associated with the given virtual register `index`. + //! + //! \note This is not the same as virtual register id. The conversion between + //! id and its index is implemented by \ref Operand_::virtIdToIndex() and \ref + //! Operand_::indexToVirtId() functions. + inline VirtReg* virtRegByIndex(uint32_t index) const noexcept { return _vRegArray[index]; } + + //! Returns an array of all virtual registers managed by the Compiler. + inline const ZoneVector& virtRegs() const noexcept { return _vRegArray; } + + //! \name Stack + //! \{ + + //! Creates a new stack of the given `size` and `alignment` and stores it to `out`. + //! + //! \note `name` can be used to give the stack a name, for debugging purposes. + ASMJIT_API Error _newStack(BaseMem* out, uint32_t size, uint32_t alignment, const char* name = nullptr); + + //! Updates the stack size of a stack created by `_newStack()` by its `virtId`. + ASMJIT_API Error setStackSize(uint32_t virtId, uint32_t newSize, uint32_t newAlignment = 0); + + //! Updates the stack size of a stack created by `_newStack()`. + inline Error setStackSize(const BaseMem& mem, uint32_t newSize, uint32_t newAlignment = 0) { + return setStackSize(mem.id(), newSize, newAlignment); + } + + //! \} + + //! \name Constants + //! \{ + + //! Creates a new constant of the given `scope` (see \ref ConstPool::Scope). + //! + //! This function adds a constant of the given `size` to the built-in \ref + //! ConstPool and stores the reference to that constant to the `out` operand. + ASMJIT_API Error _newConst(BaseMem* out, uint32_t scope, const void* data, size_t size); + + //! \} + + //! \name Miscellaneous + //! \{ + + //! Rename the given virtual register `reg` to a formatted string `fmt`. + ASMJIT_API void rename(const BaseReg& reg, const char* fmt, ...); + + //! \} + + //! \name Jump Annotations + //! \{ + + inline const ZoneVector& jumpAnnotations() const noexcept { + return _jumpAnnotations; + } + + ASMJIT_API Error newJumpNode(JumpNode** out, uint32_t instId, uint32_t instOptions, const Operand_& o0, JumpAnnotation* annotation); + ASMJIT_API Error emitAnnotatedJump(uint32_t instId, const Operand_& o0, JumpAnnotation* annotation); + + //! Returns a new `JumpAnnotation` instance, which can be used to aggregate + //! possible targets of a jump where the target is not a label, for example + //! to implement jump tables. + ASMJIT_API JumpAnnotation* newJumpAnnotation(); + + //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("alloc() has no effect, it will be removed in the future") + inline void alloc(BaseReg&) {} + ASMJIT_DEPRECATED("spill() has no effect, it will be removed in the future") + inline void spill(BaseReg&) {} +#endif // !ASMJIT_NO_DEPRECATED + + //! \name Events + //! \{ + + ASMJIT_API Error onAttach(CodeHolder* code) noexcept override; + ASMJIT_API Error onDetach(CodeHolder* code) noexcept override; + + //! \} +}; + +// ============================================================================ +// [asmjit::JumpAnnotation] +// ============================================================================ + +//! Jump annotation used to annotate jumps. +//! +//! \ref BaseCompiler allows to emit jumps where the target is either register +//! or memory operand. Such jumps cannot be trivially inspected, so instead of +//! doing heuristics AsmJit allows to annotate such jumps with possible targets. +//! Register allocator then use the annotation to construct control-flow, which +//! is then used by liveness analysis and other tools to prepare ground for +//! register allocation. +class JumpAnnotation { +public: + ASMJIT_NONCOPYABLE(JumpAnnotation) + + //! Compiler that owns this JumpAnnotation. + BaseCompiler* _compiler; + //! Annotation identifier. + uint32_t _annotationId; + //! Vector of label identifiers, see \ref labelIds(). + ZoneVector _labelIds; + + inline JumpAnnotation(BaseCompiler* compiler, uint32_t annotationId) noexcept + : _compiler(compiler), + _annotationId(annotationId) {} + + //! Returns the compiler that owns this JumpAnnotation. + inline BaseCompiler* compiler() const noexcept { return _compiler; } + //! Returns the annotation id. + inline uint32_t annotationId() const noexcept { return _annotationId; } + //! Returns a vector of label identifiers that lists all targets of the jump. + const ZoneVector& labelIds() const noexcept { return _labelIds; } + + //! Tests whether the given `label` is a target of this JumpAnnotation. + inline bool hasLabel(const Label& label) const noexcept { return hasLabelId(label.id()); } + //! Tests whether the given `labelId` is a target of this JumpAnnotation. + inline bool hasLabelId(uint32_t labelId) const noexcept { return _labelIds.contains(labelId); } + + //! Adds the `label` to the list of targets of this JumpAnnotation. + inline Error addLabel(const Label& label) noexcept { return addLabelId(label.id()); } + //! Adds the `labelId` to the list of targets of this JumpAnnotation. + inline Error addLabelId(uint32_t labelId) noexcept { return _labelIds.append(&_compiler->_allocator, labelId); } +}; + +// ============================================================================ +// [asmjit::JumpNode] +// ============================================================================ + +//! Jump instruction with \ref JumpAnnotation. +//! +//! \note This node should be only used to represent jump where the jump target +//! cannot be deduced by examining instruction operands. For example if the jump +//! target is register or memory location. This pattern is often used to perform +//! indirect jumps that use jump table, e.g. to implement `switch{}` statement. +class JumpNode : public InstNode { +public: + ASMJIT_NONCOPYABLE(JumpNode) + + JumpAnnotation* _annotation; + + //! \name Construction & Destruction + //! \{ + + ASMJIT_INLINE JumpNode(BaseCompiler* cc, uint32_t instId, uint32_t options, uint32_t opCount, JumpAnnotation* annotation) noexcept + : InstNode(cc, instId, options, opCount, kBaseOpCapacity), + _annotation(annotation) { + setType(kNodeJump); + } + + //! \} + + //! \name Accessors + //! \{ + + //! Tests whether this JumpNode has associated a \ref JumpAnnotation. + inline bool hasAnnotation() const noexcept { return _annotation != nullptr; } + //! Returns the \ref JumpAnnotation associated with this jump, or `nullptr`. + inline JumpAnnotation* annotation() const noexcept { return _annotation; } + //! Sets the \ref JumpAnnotation associated with this jump to `annotation`. + inline void setAnnotation(JumpAnnotation* annotation) noexcept { _annotation = annotation; } + + //! \} +}; + +// ============================================================================ +// [asmjit::FuncNode] +// ============================================================================ + +//! Function node represents a function used by \ref BaseCompiler. +//! +//! A function is composed of the following: +//! +//! - Function entry, \ref FuncNode acts as a label, so the entry is implicit. +//! To get the entry, simply use \ref FuncNode::label(), which is the same +//! as \ref LabelNode::label(). +//! +//! - Function exit, which is represented by \ref FuncNode::exitNode(). A +//! helper function \ref FuncNode::exitLabel() exists and returns an exit +//! label instead of node. +//! +//! - Function \ref FuncNode::endNode() sentinel. This node marks the end of +//! a function - there should be no code that belongs to the function after +//! this node, but the Compiler doesn't enforce that at the moment. +//! +//! - Function detail, see \ref FuncNode::detail(). +//! +//! - Function frame, see \ref FuncNode::frame(). +//! +//! - Function arguments mapped to virtual registers, see \ref FuncNode::args(). +//! +//! In a node list, the function and its body looks like the following: +//! +//! \code{.unparsed} +//! [...] - Anything before the function. +//! +//! [FuncNode] - Entry point of the function, acts as a label as well. +//! - Prolog inserted by the register allocator. +//! {...} - Function body - user code basically. +//! [ExitLabel] - Exit label +//! - Epilog inserted by the register allocator. +//! - Return inserted by the register allocator. +//! {...} - Can contain data or user code (error handling, special cases, ...). +//! [FuncEnd] - End sentinel +//! +//! [...] - Anything after the function. +//! \endcode +//! +//! When a function is added to the compiler by \ref BaseCompiler::addFunc() it +//! actually inserts 3 nodes (FuncNode, ExitLabel, and FuncEnd) and sets the +//! current cursor to be FuncNode. When \ref BaseCompiler::endFunc() is called +//! the cursor is set to FuncEnd. This guarantees that user can use ExitLabel +//! as a marker after additional code or data can be placed, and it's a common +//! practice. +class FuncNode : public LabelNode { +public: + ASMJIT_NONCOPYABLE(FuncNode) + + //! Arguments pack. + struct ArgPack { + VirtReg* _data[Globals::kMaxValuePack]; + + inline void reset() noexcept { + for (size_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++) + _data[valueIndex] = nullptr; + } + + inline VirtReg*& operator[](size_t valueIndex) noexcept { return _data[valueIndex]; } + inline VirtReg* const& operator[](size_t valueIndex) const noexcept { return _data[valueIndex]; } + }; + + //! Function detail. + FuncDetail _funcDetail; + //! Function frame. + FuncFrame _frame; + //! Function exit label. + LabelNode* _exitNode; + //! Function end (sentinel). + SentinelNode* _end; + + //! Argument packs. + ArgPack* _args; + + //! \name Construction & Destruction + //! \{ + + //! Creates a new `FuncNode` instance. + //! + //! Always use `BaseCompiler::addFunc()` to create `FuncNode`. + ASMJIT_INLINE FuncNode(BaseBuilder* cb) noexcept + : LabelNode(cb), + _funcDetail(), + _frame(), + _exitNode(nullptr), + _end(nullptr), + _args(nullptr) { + setType(kNodeFunc); + } + + //! \} + + //! \{ + //! \name Accessors + + //! Returns function exit `LabelNode`. + inline LabelNode* exitNode() const noexcept { return _exitNode; } + //! Returns function exit label. + inline Label exitLabel() const noexcept { return _exitNode->label(); } + + //! Returns "End of Func" sentinel. + inline SentinelNode* endNode() const noexcept { return _end; } + + //! Returns function declaration. + inline FuncDetail& detail() noexcept { return _funcDetail; } + //! Returns function declaration. + inline const FuncDetail& detail() const noexcept { return _funcDetail; } + + //! Returns function frame. + inline FuncFrame& frame() noexcept { return _frame; } + //! Returns function frame. + inline const FuncFrame& frame() const noexcept { return _frame; } + + //! Tests whether the function has a return value. + inline bool hasRet() const noexcept { return _funcDetail.hasRet(); } + //! Returns arguments count. + inline uint32_t argCount() const noexcept { return _funcDetail.argCount(); } + + //! Returns argument packs. + inline ArgPack* argPacks() const noexcept { return _args; } + + //! Returns argument pack at `argIndex`. + inline ArgPack& argPack(size_t argIndex) const noexcept { + ASMJIT_ASSERT(argIndex < argCount()); + return _args[argIndex]; + } + + //! Sets argument at `argIndex`. + inline void setArg(size_t argIndex, VirtReg* vReg) noexcept { + ASMJIT_ASSERT(argIndex < argCount()); + _args[argIndex][0] = vReg; + } + + //! Sets argument at `argIndex` and `valueIndex`. + inline void setArg(size_t argIndex, size_t valueIndex, VirtReg* vReg) noexcept { + ASMJIT_ASSERT(argIndex < argCount()); + _args[argIndex][valueIndex] = vReg; + } + + //! Resets argument pack at `argIndex`. + inline void resetArg(size_t argIndex) noexcept { + ASMJIT_ASSERT(argIndex < argCount()); + _args[argIndex].reset(); + } + + //! Resets argument pack at `argIndex`. + inline void resetArg(size_t argIndex, size_t valueIndex) noexcept { + ASMJIT_ASSERT(argIndex < argCount()); + _args[argIndex][valueIndex] = nullptr; + } + + //! Returns function attributes. + inline uint32_t attributes() const noexcept { return _frame.attributes(); } + //! Adds `attrs` to the function attributes. + inline void addAttributes(uint32_t attrs) noexcept { _frame.addAttributes(attrs); } + + //! \} +}; + +// ============================================================================ +// [asmjit::FuncRetNode] +// ============================================================================ + +//! Function return, used by \ref BaseCompiler. +class FuncRetNode : public InstNode { +public: + ASMJIT_NONCOPYABLE(FuncRetNode) + + //! \name Construction & Destruction + //! \{ + + //! Creates a new `FuncRetNode` instance. + inline FuncRetNode(BaseBuilder* cb) noexcept : InstNode(cb, BaseInst::kIdAbstract, 0, 0) { + _any._nodeType = kNodeFuncRet; + } + + //! \} +}; + +// ============================================================================ +// [asmjit::InvokeNode] +// ============================================================================ + +//! Function invocation, used by \ref BaseCompiler. +class InvokeNode : public InstNode { +public: + ASMJIT_NONCOPYABLE(InvokeNode) + + //! Operand pack provides multiple operands that can be associated with a + //! single return value of function argument. Sometims this is necessary to + //! express an argument or return value that requires multiple registers, for + //! example 64-bit value in 32-bit mode or passing / returning homogenous data + //! structures. + struct OperandPack { + //! Operands. + Operand_ _data[Globals::kMaxValuePack]; + + //! Reset the pack by resetting all operands in the pack. + inline void reset() noexcept { + for (size_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++) + _data[valueIndex].reset(); + } + + //! Returns an operand at the given `valueIndex`. + inline Operand& operator[](size_t valueIndex) noexcept { + ASMJIT_ASSERT(valueIndex < Globals::kMaxValuePack); + return _data[valueIndex].as(); + } + + //! Returns an operand at the given `valueIndex` (const). + const inline Operand& operator[](size_t valueIndex) const noexcept { + ASMJIT_ASSERT(valueIndex < Globals::kMaxValuePack); + return _data[valueIndex].as(); + } + }; + + //! Function detail. + FuncDetail _funcDetail; + //! Function return value(s). + OperandPack _rets; + //! Function arguments. + OperandPack* _args; + + //! \name Construction & Destruction + //! \{ + + //! Creates a new `InvokeNode` instance. + inline InvokeNode(BaseBuilder* cb, uint32_t instId, uint32_t options) noexcept + : InstNode(cb, instId, options, kBaseOpCapacity), + _funcDetail(), + _args(nullptr) { + setType(kNodeInvoke); + _resetOps(); + _rets.reset(); + addFlags(kFlagIsRemovable); + } + + //! \} + + //! \name Accessors + //! \{ + + //! Sets the function signature. + inline Error init(const FuncSignature& signature, const Environment& environment) noexcept { + return _funcDetail.init(signature, environment); + } + + //! Returns the function detail. + inline FuncDetail& detail() noexcept { return _funcDetail; } + //! Returns the function detail. + inline const FuncDetail& detail() const noexcept { return _funcDetail; } + + //! Returns the target operand. + inline Operand& target() noexcept { return _opArray[0].as(); } + //! \overload + inline const Operand& target() const noexcept { return _opArray[0].as(); } + + //! Returns the number of function return values. + inline bool hasRet() const noexcept { return _funcDetail.hasRet(); } + //! Returns the number of function arguments. + inline uint32_t argCount() const noexcept { return _funcDetail.argCount(); } + + //! Returns operand pack representing function return value(s). + inline OperandPack& retPack() noexcept { return _rets; } + //! Returns operand pack representing function return value(s). + inline const OperandPack& retPack() const noexcept { return _rets; } + + //! Returns the return value at the given `valueIndex`. + inline Operand& ret(size_t valueIndex = 0) noexcept { return _rets[valueIndex]; } + //! \overload + inline const Operand& ret(size_t valueIndex = 0) const noexcept { return _rets[valueIndex]; } + + //! Returns operand pack representing function return value(s). + inline OperandPack& argPack(size_t argIndex) noexcept { + ASMJIT_ASSERT(argIndex < argCount()); + return _args[argIndex]; + } + //! \overload + inline const OperandPack& argPack(size_t argIndex) const noexcept { + ASMJIT_ASSERT(argIndex < argCount()); + return _args[argIndex]; + } + + //! Returns a function argument at the given `argIndex`. + inline Operand& arg(size_t argIndex, size_t valueIndex) noexcept { + ASMJIT_ASSERT(argIndex < argCount()); + return _args[argIndex][valueIndex]; + } + //! \overload + inline const Operand& arg(size_t argIndex, size_t valueIndex) const noexcept { + ASMJIT_ASSERT(argIndex < argCount()); + return _args[argIndex][valueIndex]; + } + + //! Sets the function return value at `i` to `op`. + inline void _setRet(size_t valueIndex, const Operand_& op) noexcept { _rets[valueIndex] = op; } + //! Sets the function argument at `i` to `op`. + inline void _setArg(size_t argIndex, size_t valueIndex, const Operand_& op) noexcept { + ASMJIT_ASSERT(argIndex < argCount()); + _args[argIndex][valueIndex] = op; + } + + //! Sets the function return value at `valueIndex` to `reg`. + inline void setRet(size_t valueIndex, const BaseReg& reg) noexcept { _setRet(valueIndex, reg); } + + //! Sets the first function argument in a value-pack at `argIndex` to `reg`. + inline void setArg(size_t argIndex, const BaseReg& reg) noexcept { _setArg(argIndex, 0, reg); } + //! Sets the first function argument in a value-pack at `argIndex` to `imm`. + inline void setArg(size_t argIndex, const Imm& imm) noexcept { _setArg(argIndex, 0, imm); } + + //! Sets the function argument at `argIndex` and `valueIndex` to `reg`. + inline void setArg(size_t argIndex, size_t valueIndex, const BaseReg& reg) noexcept { _setArg(argIndex, valueIndex, reg); } + //! Sets the function argument at `argIndex` and `valueIndex` to `imm`. + inline void setArg(size_t argIndex, size_t valueIndex, const Imm& imm) noexcept { _setArg(argIndex, valueIndex, imm); } + + //! \} +}; + +// ============================================================================ +// [asmjit::FuncPass] +// ============================================================================ + +//! Function pass extends \ref Pass with \ref FuncPass::runOnFunction(). +class ASMJIT_VIRTAPI FuncPass : public Pass { +public: + ASMJIT_NONCOPYABLE(FuncPass) + typedef Pass Base; + + //! \name Construction & Destruction + //! \{ + + ASMJIT_API FuncPass(const char* name) noexcept; + + //! \} + + //! \name Accessors + //! \{ + + //! Returns the associated `BaseCompiler`. + inline BaseCompiler* cc() const noexcept { return static_cast(_cb); } + + //! \} + + //! \name Run + //! \{ + + //! Calls `runOnFunction()` on each `FuncNode` node found. + ASMJIT_API Error run(Zone* zone, Logger* logger) override; + + //! Called once per `FuncNode`. + virtual Error runOnFunction(Zone* zone, Logger* logger, FuncNode* func) = 0; + + //! \} +}; + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // !ASMJIT_NO_COMPILER +#endif // ASMJIT_CORE_COMPILER_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/compilerdefs.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/compilerdefs.h new file mode 100644 index 0000000..32f0757 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/compilerdefs.h @@ -0,0 +1,170 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_COMPILERDEFS_H_INCLUDED +#define ASMJIT_CORE_COMPILERDEFS_H_INCLUDED + +#include "../core/api-config.h" +#include "../core/operand.h" +#include "../core/zonestring.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +class RAWorkReg; + +//! \addtogroup asmjit_compiler +//! \{ + +// ============================================================================ +// [asmjit::VirtReg] +// ============================================================================ + +//! Virtual register data, managed by \ref BaseCompiler. +class VirtReg { +public: + ASMJIT_NONCOPYABLE(VirtReg) + + //! Virtual register id. + uint32_t _id = 0; + //! Virtual register info (signature). + RegInfo _info = {}; + //! Virtual register size (can be smaller than `regInfo._size`). + uint32_t _virtSize = 0; + //! Virtual register alignment (for spilling). + uint8_t _alignment = 0; + //! Type-id. + uint8_t _typeId = 0; + //! Virtual register weight for alloc/spill decisions. + uint8_t _weight = 1; + //! True if this is a fixed register, never reallocated. + uint8_t _isFixed : 1; + //! True if the virtual register is only used as a stack (never accessed as register). + uint8_t _isStack : 1; + uint8_t _reserved : 6; + + //! Virtual register name (user provided or automatically generated). + ZoneString<16> _name {}; + + // ------------------------------------------------------------------------- + // The following members are used exclusively by RAPass. They are initialized + // when the VirtReg is created to NULL pointers and then changed during RAPass + // execution. RAPass sets them back to NULL before it returns. + // ------------------------------------------------------------------------- + + //! Reference to `RAWorkReg`, used during register allocation. + RAWorkReg* _workReg = nullptr; + + //! \name Construction & Destruction + //! \{ + + inline VirtReg(uint32_t id, uint32_t signature, uint32_t virtSize, uint32_t alignment, uint32_t typeId) noexcept + : _id(id), + _info { signature }, + _virtSize(virtSize), + _alignment(uint8_t(alignment)), + _typeId(uint8_t(typeId)), + _isFixed(false), + _isStack(false), + _reserved(0) {} + + //! \} + + //! \name Accessors + //! \{ + + //! Returns the virtual register id. + inline uint32_t id() const noexcept { return _id; } + + //! Returns the virtual register name. + inline const char* name() const noexcept { return _name.data(); } + //! Returns the size of the virtual register name. + inline uint32_t nameSize() const noexcept { return _name.size(); } + + //! Returns a register information that wraps the register signature. + inline const RegInfo& info() const noexcept { return _info; } + //! Returns a virtual register type (maps to the physical register type as well). + inline uint32_t type() const noexcept { return _info.type(); } + //! Returns a virtual register group (maps to the physical register group as well). + inline uint32_t group() const noexcept { return _info.group(); } + + //! Returns a real size of the register this virtual register maps to. + //! + //! For example if this is a 128-bit SIMD register used for a scalar single + //! precision floating point value then its virtSize would be 4, however, the + //! `regSize` would still say 16 (128-bits), because it's the smallest size + //! of that register type. + inline uint32_t regSize() const noexcept { return _info.size(); } + + //! Returns a register signature of this virtual register. + inline uint32_t signature() const noexcept { return _info.signature(); } + + //! Returns the virtual register size. + //! + //! The virtual register size describes how many bytes the virtual register + //! needs to store its content. It can be smaller than the physical register + //! size, see `regSize()`. + inline uint32_t virtSize() const noexcept { return _virtSize; } + + //! Returns the virtual register alignment. + inline uint32_t alignment() const noexcept { return _alignment; } + + //! Returns the virtual register type id, see `Type::Id`. + inline uint32_t typeId() const noexcept { return _typeId; } + + //! Returns the virtual register weight - the register allocator can use it + //! as explicit hint for alloc/spill decisions. + inline uint32_t weight() const noexcept { return _weight; } + //! Sets the virtual register weight (0 to 255) - the register allocator can + //! use it as explicit hint for alloc/spill decisions and initial bin-packing. + inline void setWeight(uint32_t weight) noexcept { _weight = uint8_t(weight); } + + //! Returns whether the virtual register is always allocated to a fixed + //! physical register (and never reallocated). + //! + //! \note This is only used for special purposes and it's mostly internal. + inline bool isFixed() const noexcept { return bool(_isFixed); } + + //! Returns whether the virtual register is indeed a stack that only uses + //! the virtual register id for making it accessible. + //! + //! \note It's an error if a stack is accessed as a register. + inline bool isStack() const noexcept { return bool(_isStack); } + + inline bool hasWorkReg() const noexcept { return _workReg != nullptr; } + inline RAWorkReg* workReg() const noexcept { return _workReg; } + inline void setWorkReg(RAWorkReg* workReg) noexcept { _workReg = workReg; } + inline void resetWorkReg() noexcept { _workReg = nullptr; } + + //! \} +}; + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_COMPILERDEFS_H_INCLUDED + diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/constpool.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/constpool.cpp new file mode 100644 index 0000000..65c995b --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/constpool.cpp @@ -0,0 +1,375 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/constpool.h" +#include "../core/support.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::ConstPool - Construction / Destruction] +// ============================================================================ + +ConstPool::ConstPool(Zone* zone) noexcept { reset(zone); } +ConstPool::~ConstPool() noexcept {} + +// ============================================================================ +// [asmjit::ConstPool - Reset] +// ============================================================================ + +void ConstPool::reset(Zone* zone) noexcept { + _zone = zone; + + size_t dataSize = 1; + for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_tree); i++) { + _tree[i].reset(); + _tree[i].setDataSize(dataSize); + _gaps[i] = nullptr; + dataSize <<= 1; + } + + _gapPool = nullptr; + _size = 0; + _alignment = 0; +} + +// ============================================================================ +// [asmjit::ConstPool - Ops] +// ============================================================================ + +static ASMJIT_INLINE ConstPool::Gap* ConstPool_allocGap(ConstPool* self) noexcept { + ConstPool::Gap* gap = self->_gapPool; + if (!gap) + return self->_zone->allocT(); + + self->_gapPool = gap->_next; + return gap; +} + +static ASMJIT_INLINE void ConstPool_freeGap(ConstPool* self, ConstPool::Gap* gap) noexcept { + gap->_next = self->_gapPool; + self->_gapPool = gap; +} + +static void ConstPool_addGap(ConstPool* self, size_t offset, size_t size) noexcept { + ASMJIT_ASSERT(size > 0); + + while (size > 0) { + size_t gapIndex; + size_t gapSize; + + if (size >= 16 && Support::isAligned(offset, 16)) { + gapIndex = ConstPool::kIndex16; + gapSize = 16; + } + else if (size >= 8 && Support::isAligned(offset, 8)) { + gapIndex = ConstPool::kIndex8; + gapSize = 8; + } + else if (size >= 4 && Support::isAligned(offset, 4)) { + gapIndex = ConstPool::kIndex4; + gapSize = 4; + } + else if (size >= 2 && Support::isAligned(offset, 2)) { + gapIndex = ConstPool::kIndex2; + gapSize = 2; + } + else { + gapIndex = ConstPool::kIndex1; + gapSize = 1; + } + + // We don't have to check for errors here, if this failed nothing really + // happened (just the gap won't be visible) and it will fail again at + // place where the same check would generate `kErrorOutOfMemory` error. + ConstPool::Gap* gap = ConstPool_allocGap(self); + if (!gap) + return; + + gap->_next = self->_gaps[gapIndex]; + self->_gaps[gapIndex] = gap; + + gap->_offset = offset; + gap->_size = gapSize; + + offset += gapSize; + size -= gapSize; + } +} + +Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) noexcept { + size_t treeIndex; + + if (size == 32) + treeIndex = kIndex32; + else if (size == 16) + treeIndex = kIndex16; + else if (size == 8) + treeIndex = kIndex8; + else if (size == 4) + treeIndex = kIndex4; + else if (size == 2) + treeIndex = kIndex2; + else if (size == 1) + treeIndex = kIndex1; + else + return DebugUtils::errored(kErrorInvalidArgument); + + ConstPool::Node* node = _tree[treeIndex].get(data); + if (node) { + dstOffset = node->_offset; + return kErrorOk; + } + + // Before incrementing the current offset try if there is a gap that can + // be used for the requested data. + size_t offset = ~size_t(0); + size_t gapIndex = treeIndex; + + while (gapIndex != kIndexCount - 1) { + ConstPool::Gap* gap = _gaps[treeIndex]; + + // Check if there is a gap. + if (gap) { + size_t gapOffset = gap->_offset; + size_t gapSize = gap->_size; + + // Destroy the gap for now. + _gaps[treeIndex] = gap->_next; + ConstPool_freeGap(this, gap); + + offset = gapOffset; + ASMJIT_ASSERT(Support::isAligned(offset, size)); + + gapSize -= size; + if (gapSize > 0) + ConstPool_addGap(this, gapOffset, gapSize); + } + + gapIndex++; + } + + if (offset == ~size_t(0)) { + // Get how many bytes have to be skipped so the address is aligned accordingly + // to the 'size'. + size_t diff = Support::alignUpDiff(_size, size); + + if (diff != 0) { + ConstPool_addGap(this, _size, diff); + _size += diff; + } + + offset = _size; + _size += size; + } + + // Add the initial node to the right index. + node = ConstPool::Tree::_newNode(_zone, data, size, offset, false); + if (!node) return DebugUtils::errored(kErrorOutOfMemory); + + _tree[treeIndex].insert(node); + _alignment = Support::max(_alignment, size); + + dstOffset = offset; + + // Now create a bunch of shared constants that are based on the data pattern. + // We stop at size 4, it probably doesn't make sense to split constants down + // to 1 byte. + size_t pCount = 1; + while (size > 4) { + size >>= 1; + pCount <<= 1; + + ASMJIT_ASSERT(treeIndex != 0); + treeIndex--; + + const uint8_t* pData = static_cast(data); + for (size_t i = 0; i < pCount; i++, pData += size) { + node = _tree[treeIndex].get(pData); + if (node) continue; + + node = ConstPool::Tree::_newNode(_zone, pData, size, offset + (i * size), true); + _tree[treeIndex].insert(node); + } + } + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::ConstPool - Reset] +// ============================================================================ + +struct ConstPoolFill { + inline ConstPoolFill(uint8_t* dst, size_t dataSize) noexcept : + _dst(dst), + _dataSize(dataSize) {} + + inline void operator()(const ConstPool::Node* node) noexcept { + if (!node->_shared) + memcpy(_dst + node->_offset, node->data(), _dataSize); + } + + uint8_t* _dst; + size_t _dataSize; +}; + +void ConstPool::fill(void* dst) const noexcept { + // Clears possible gaps, asmjit should never emit garbage to the output. + memset(dst, 0, _size); + + ConstPoolFill filler(static_cast(dst), 1); + for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_tree); i++) { + _tree[i].forEach(filler); + filler._dataSize <<= 1; + } +} + +// ============================================================================ +// [asmjit::ConstPool - Unit] +// ============================================================================ + +#if defined(ASMJIT_TEST) +UNIT(const_pool) { + Zone zone(32384 - Zone::kBlockOverhead); + ConstPool pool(&zone); + + uint32_t i; + uint32_t kCount = BrokenAPI::hasArg("--quick") ? 1000 : 1000000; + + INFO("Adding %u constants to the pool", kCount); + { + size_t prevOffset; + size_t curOffset; + uint64_t c = 0x0101010101010101u; + + EXPECT(pool.add(&c, 8, prevOffset) == kErrorOk); + EXPECT(prevOffset == 0); + + for (i = 1; i < kCount; i++) { + c++; + EXPECT(pool.add(&c, 8, curOffset) == kErrorOk); + EXPECT(prevOffset + 8 == curOffset); + EXPECT(pool.size() == (i + 1) * 8); + prevOffset = curOffset; + } + + EXPECT(pool.alignment() == 8); + } + + INFO("Retrieving %u constants from the pool", kCount); + { + uint64_t c = 0x0101010101010101u; + + for (i = 0; i < kCount; i++) { + size_t offset; + EXPECT(pool.add(&c, 8, offset) == kErrorOk); + EXPECT(offset == i * 8); + c++; + } + } + + INFO("Checking if the constants were split into 4-byte patterns"); + { + uint32_t c = 0x01010101; + for (i = 0; i < kCount; i++) { + size_t offset; + EXPECT(pool.add(&c, 4, offset) == kErrorOk); + EXPECT(offset == i * 8); + c++; + } + } + + INFO("Adding 2 byte constant to misalign the current offset"); + { + uint16_t c = 0xFFFF; + size_t offset; + + EXPECT(pool.add(&c, 2, offset) == kErrorOk); + EXPECT(offset == kCount * 8); + EXPECT(pool.alignment() == 8); + } + + INFO("Adding 8 byte constant to check if pool gets aligned again"); + { + uint64_t c = 0xFFFFFFFFFFFFFFFFu; + size_t offset; + + EXPECT(pool.add(&c, 8, offset) == kErrorOk); + EXPECT(offset == kCount * 8 + 8); + } + + INFO("Adding 2 byte constant to verify the gap is filled"); + { + uint16_t c = 0xFFFE; + size_t offset; + + EXPECT(pool.add(&c, 2, offset) == kErrorOk); + EXPECT(offset == kCount * 8 + 2); + EXPECT(pool.alignment() == 8); + } + + INFO("Checking reset functionality"); + { + pool.reset(&zone); + zone.reset(); + + EXPECT(pool.size() == 0); + EXPECT(pool.alignment() == 0); + } + + INFO("Checking pool alignment when combined constants are added"); + { + uint8_t bytes[32] = { 0 }; + size_t offset; + + pool.add(bytes, 1, offset); + EXPECT(pool.size() == 1); + EXPECT(pool.alignment() == 1); + EXPECT(offset == 0); + + pool.add(bytes, 2, offset); + EXPECT(pool.size() == 4); + EXPECT(pool.alignment() == 2); + EXPECT(offset == 2); + + pool.add(bytes, 4, offset); + EXPECT(pool.size() == 8); + EXPECT(pool.alignment() == 4); + EXPECT(offset == 4); + + pool.add(bytes, 4, offset); + EXPECT(pool.size() == 8); + EXPECT(pool.alignment() == 4); + EXPECT(offset == 4); + + pool.add(bytes, 32, offset); + EXPECT(pool.size() == 64); + EXPECT(pool.alignment() == 32); + EXPECT(offset == 32); + } +} +#endif + +ASMJIT_END_NAMESPACE diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/constpool.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/constpool.h new file mode 100644 index 0000000..d9ac589 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/constpool.h @@ -0,0 +1,262 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_CONSTPOOL_H_INCLUDED +#define ASMJIT_CORE_CONSTPOOL_H_INCLUDED + +#include "../core/support.h" +#include "../core/zone.h" +#include "../core/zonetree.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_utilities +//! \{ + +// ============================================================================ +// [asmjit::ConstPool] +// ============================================================================ + +//! Constant pool. +class ConstPool { +public: + ASMJIT_NONCOPYABLE(ConstPool) + + //! Constant pool scope. + enum Scope : uint32_t { + //! Local constant, always embedded right after the current function. + kScopeLocal = 0, + //! Global constant, embedded at the end of the currently compiled code. + kScopeGlobal = 1 + }; + + //! \cond INTERNAL + + //! Index of a given size in const-pool table. + enum Index : uint32_t { + kIndex1 = 0, + kIndex2 = 1, + kIndex4 = 2, + kIndex8 = 3, + kIndex16 = 4, + kIndex32 = 5, + kIndexCount = 6 + }; + + //! Zone-allocated const-pool gap created by two differently aligned constants. + struct Gap { + //! Pointer to the next gap + Gap* _next; + //! Offset of the gap. + size_t _offset; + //! Remaining bytes of the gap (basically a gap size). + size_t _size; + }; + + //! Zone-allocated const-pool node. + class Node : public ZoneTreeNodeT { + public: + ASMJIT_NONCOPYABLE(Node) + + //! If this constant is shared with another. + uint32_t _shared : 1; + //! Data offset from the beginning of the pool. + uint32_t _offset; + + inline Node(size_t offset, bool shared) noexcept + : ZoneTreeNodeT(), + _shared(shared), + _offset(uint32_t(offset)) {} + + inline void* data() const noexcept { + return static_cast(const_cast(this) + 1); + } + }; + + //! Data comparer used internally. + class Compare { + public: + size_t _dataSize; + + inline Compare(size_t dataSize) noexcept + : _dataSize(dataSize) {} + + inline int operator()(const Node& a, const Node& b) const noexcept { + return ::memcmp(a.data(), b.data(), _dataSize); + } + + inline int operator()(const Node& a, const void* data) const noexcept { + return ::memcmp(a.data(), data, _dataSize); + } + }; + + //! Zone-allocated const-pool tree. + struct Tree { + //! RB tree. + ZoneTree _tree; + //! Size of the tree (number of nodes). + size_t _size; + //! Size of the data. + size_t _dataSize; + + inline explicit Tree(size_t dataSize = 0) noexcept + : _tree(), + _size(0), + _dataSize(dataSize) {} + + inline void reset() noexcept { + _tree.reset(); + _size = 0; + } + + inline bool empty() const noexcept { return _size == 0; } + inline size_t size() const noexcept { return _size; } + + inline void setDataSize(size_t dataSize) noexcept { + ASMJIT_ASSERT(empty()); + _dataSize = dataSize; + } + + inline Node* get(const void* data) noexcept { + Compare cmp(_dataSize); + return _tree.get(data, cmp); + } + + inline void insert(Node* node) noexcept { + Compare cmp(_dataSize); + _tree.insert(node, cmp); + _size++; + } + + template + inline void forEach(Visitor& visitor) const noexcept { + Node* node = _tree.root(); + if (!node) return; + + Node* stack[Globals::kMaxTreeHeight]; + size_t top = 0; + + for (;;) { + Node* left = node->left(); + if (left != nullptr) { + ASMJIT_ASSERT(top != Globals::kMaxTreeHeight); + stack[top++] = node; + + node = left; + continue; + } + + for (;;) { + visitor(node); + node = node->right(); + + if (node != nullptr) + break; + + if (top == 0) + return; + + node = stack[--top]; + } + } + } + + static inline Node* _newNode(Zone* zone, const void* data, size_t size, size_t offset, bool shared) noexcept { + Node* node = zone->allocT(sizeof(Node) + size); + if (ASMJIT_UNLIKELY(!node)) return nullptr; + + node = new(node) Node(offset, shared); + memcpy(node->data(), data, size); + return node; + } + }; + + //! \endcond + + //! Zone allocator. + Zone* _zone; + //! Tree per size. + Tree _tree[kIndexCount]; + //! Gaps per size. + Gap* _gaps[kIndexCount]; + //! Gaps pool + Gap* _gapPool; + + //! Size of the pool (in bytes). + size_t _size; + //! Required pool alignment. + size_t _alignment; + + //! \name Construction & Destruction + //! \{ + + ASMJIT_API ConstPool(Zone* zone) noexcept; + ASMJIT_API ~ConstPool() noexcept; + + ASMJIT_API void reset(Zone* zone) noexcept; + + //! \} + + //! \name Accessors + //! \{ + + //! Tests whether the constant-pool is empty. + inline bool empty() const noexcept { return _size == 0; } + //! Returns the size of the constant-pool in bytes. + inline size_t size() const noexcept { return _size; } + //! Returns minimum alignment. + inline size_t alignment() const noexcept { return _alignment; } + + //! \} + + //! \name Utilities + //! \{ + + //! Adds a constant to the constant pool. + //! + //! The constant must have known size, which is 1, 2, 4, 8, 16 or 32 bytes. + //! The constant is added to the pool only if it doesn't not exist, otherwise + //! cached value is returned. + //! + //! AsmJit is able to subdivide added constants, so for example if you add + //! 8-byte constant 0x1122334455667788 it will create the following slots: + //! + //! 8-byte: 0x1122334455667788 + //! 4-byte: 0x11223344, 0x55667788 + //! + //! The reason is that when combining MMX/SSE/AVX code some patterns are used + //! frequently. However, AsmJit is not able to reallocate a constant that has + //! been already added. For example if you try to add 4-byte constant and then + //! 8-byte constant having the same 4-byte pattern as the previous one, two + //! independent slots will be generated by the pool. + ASMJIT_API Error add(const void* data, size_t size, size_t& dstOffset) noexcept; + + //! Fills the destination with the content of this constant pool. + ASMJIT_API void fill(void* dst) const noexcept; +}; + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_CONSTPOOL_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/cpuinfo.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/cpuinfo.cpp new file mode 100644 index 0000000..edc7d17 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/cpuinfo.cpp @@ -0,0 +1,97 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/cpuinfo.h" + +#if !defined(_WIN32) + #include + #include + #include +#endif + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::CpuInfo - Detect - CPU NumThreads] +// ============================================================================ + +#if defined(_WIN32) +static inline uint32_t detectHWThreadCount() noexcept { + SYSTEM_INFO info; + ::GetSystemInfo(&info); + return info.dwNumberOfProcessors; +} +#elif defined(_SC_NPROCESSORS_ONLN) +static inline uint32_t detectHWThreadCount() noexcept { + long res = ::sysconf(_SC_NPROCESSORS_ONLN); + return res <= 0 ? uint32_t(1) : uint32_t(res); +} +#else +static inline uint32_t detectHWThreadCount() noexcept { + return 1; +} +#endif + +// ============================================================================ +// [asmjit::CpuInfo - Detect - CPU Features] +// ============================================================================ + +#if defined(ASMJIT_BUILD_X86) && ASMJIT_ARCH_X86 +namespace x86 { void detectCpu(CpuInfo& cpu) noexcept; } +#endif + +#if defined(ASMJIT_BUILD_ARM) && ASMJIT_ARCH_ARM +namespace arm { void detectCpu(CpuInfo& cpu) noexcept; } +#endif + +// ============================================================================ +// [asmjit::CpuInfo - Detect - Static Initializer] +// ============================================================================ + +static uint32_t cpuInfoInitialized; +static CpuInfo cpuInfoGlobal(Globals::NoInit); + +const CpuInfo& CpuInfo::host() noexcept { + // This should never cause a problem as the resulting information should + // always be the same. + if (!cpuInfoInitialized) { + CpuInfo cpuInfoLocal; + +#if defined(ASMJIT_BUILD_X86) && ASMJIT_ARCH_X86 + x86::detectCpu(cpuInfoLocal); +#endif + +#if defined(ASMJIT_BUILD_ARM) && ASMJIT_ARCH_ARM + arm::detectCpu(cpuInfoLocal); +#endif + + cpuInfoLocal._hwThreadCount = detectHWThreadCount(); + cpuInfoGlobal = cpuInfoLocal; + cpuInfoInitialized = 1; + } + + return cpuInfoGlobal; +} + +ASMJIT_END_NAMESPACE diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/cpuinfo.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/cpuinfo.h new file mode 100644 index 0000000..83bb8c1 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/cpuinfo.h @@ -0,0 +1,154 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_CPUINFO_H_INCLUDED +#define ASMJIT_CORE_CPUINFO_H_INCLUDED + +#include "../core/archtraits.h" +#include "../core/features.h" +#include "../core/globals.h" +#include "../core/string.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_core +//! \{ + +// ============================================================================ +// [asmjit::CpuInfo] +// ============================================================================ + +//! CPU information. +class CpuInfo { +public: + //! Architecture. + uint8_t _arch; + //! Sub-architecture. + uint8_t _subArch; + //! Reserved for future use. + uint16_t _reserved; + //! CPU family ID. + uint32_t _familyId; + //! CPU model ID. + uint32_t _modelId; + //! CPU brand ID. + uint32_t _brandId; + //! CPU stepping. + uint32_t _stepping; + //! Processor type. + uint32_t _processorType; + //! Maximum number of addressable IDs for logical processors. + uint32_t _maxLogicalProcessors; + //! Cache line size (in bytes). + uint32_t _cacheLineSize; + //! Number of hardware threads. + uint32_t _hwThreadCount; + + //! CPU vendor string. + FixedString<16> _vendor; + //! CPU brand string. + FixedString<64> _brand; + //! CPU features. + BaseFeatures _features; + + //! \name Construction & Destruction + //! \{ + + inline CpuInfo() noexcept { reset(); } + inline CpuInfo(const CpuInfo& other) noexcept = default; + + inline explicit CpuInfo(Globals::NoInit_) noexcept + : _features(Globals::NoInit) {}; + + //! Returns the host CPU information. + ASMJIT_API static const CpuInfo& host() noexcept; + + //! Initializes CpuInfo to the given architecture, see \ref Environment. + inline void initArch(uint32_t arch, uint32_t subArch = 0u) noexcept { + _arch = uint8_t(arch); + _subArch = uint8_t(subArch); + } + + inline void reset() noexcept { memset(this, 0, sizeof(*this)); } + + //! \} + + //! \name Overloaded Operators + //! \{ + + inline CpuInfo& operator=(const CpuInfo& other) noexcept = default; + + //! \} + + //! \name Accessors + //! \{ + + //! Returns the CPU architecture id, see \ref Environment::Arch. + inline uint32_t arch() const noexcept { return _arch; } + //! Returns the CPU architecture sub-id, see \ref Environment::SubArch. + inline uint32_t subArch() const noexcept { return _subArch; } + + //! Returns the CPU family ID. + inline uint32_t familyId() const noexcept { return _familyId; } + //! Returns the CPU model ID. + inline uint32_t modelId() const noexcept { return _modelId; } + //! Returns the CPU brand id. + inline uint32_t brandId() const noexcept { return _brandId; } + //! Returns the CPU stepping. + inline uint32_t stepping() const noexcept { return _stepping; } + //! Returns the processor type. + inline uint32_t processorType() const noexcept { return _processorType; } + //! Returns the number of maximum logical processors. + inline uint32_t maxLogicalProcessors() const noexcept { return _maxLogicalProcessors; } + + //! Returns the size of a cache line flush. + inline uint32_t cacheLineSize() const noexcept { return _cacheLineSize; } + //! Returns number of hardware threads available. + inline uint32_t hwThreadCount() const noexcept { return _hwThreadCount; } + + //! Returns the CPU vendor. + inline const char* vendor() const noexcept { return _vendor.str; } + //! Tests whether the CPU vendor is equal to `s`. + inline bool isVendor(const char* s) const noexcept { return _vendor.eq(s); } + + //! Returns the CPU brand string. + inline const char* brand() const noexcept { return _brand.str; } + + //! Returns all CPU features as `BaseFeatures`, cast to your arch-specific class + //! if needed. + template + inline const T& features() const noexcept { return _features.as(); } + + //! Tests whether the CPU has the given `feature`. + inline bool hasFeature(uint32_t featureId) const noexcept { return _features.has(featureId); } + //! Adds the given CPU `feature` to the list of this CpuInfo features. + inline CpuInfo& addFeature(uint32_t featureId) noexcept { _features.add(featureId); return *this; } + + //! \} +}; + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_CPUINFO_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/datatypes.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/datatypes.h new file mode 100644 index 0000000..2f6cc1e --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/datatypes.h @@ -0,0 +1,1071 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_DATATYPES_H_INCLUDED +#define ASMJIT_CORE_DATATYPES_H_INCLUDED + +#include "../core/globals.h" + +#ifndef ASMJIT_NO_DEPRECATED + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::Data64] +// ============================================================================ + +//! 64-bit data useful for creating SIMD constants. +union ASMJIT_DEPRECATED_STRUCT("Data64 is deprecated and will be removed in the future") Data64 { + //! Array of eight 8-bit signed integers. + int8_t sb[8]; + //! Array of eight 8-bit unsigned integers. + uint8_t ub[8]; + //! Array of four 16-bit signed integers. + int16_t sw[4]; + //! Array of four 16-bit unsigned integers. + uint16_t uw[4]; + //! Array of two 32-bit signed integers. + int32_t sd[2]; + //! Array of two 32-bit unsigned integers. + uint32_t ud[2]; + //! Array of one 64-bit signed integer. + int64_t sq[1]; + //! Array of one 64-bit unsigned integer. + uint64_t uq[1]; + + //! Array of two SP-FP values. + float sf[2]; + //! Array of one DP-FP value. + double df[1]; + + //! \name Construction & Destruction + //! \{ + + //! Sets all eight 8-bit signed integers. + static inline Data64 fromI8(int8_t x0) noexcept { + Data64 self; + self.setI8(x0); + return self; + } + + //! Sets all eight 8-bit unsigned integers. + static inline Data64 fromU8(uint8_t x0) noexcept { + Data64 self; + self.setU8(x0); + return self; + } + + //! Sets all eight 8-bit signed integers. + static inline Data64 fromI8( + int8_t x0, int8_t x1, int8_t x2, int8_t x3, int8_t x4, int8_t x5, int8_t x6, int8_t x7) noexcept { + + Data64 self; + self.setI8(x0, x1, x2, x3, x4, x5, x6, x7); + return self; + } + + //! Sets all eight 8-bit unsigned integers. + static inline Data64 fromU8( + uint8_t x0, uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4, uint8_t x5, uint8_t x6, uint8_t x7) noexcept { + + Data64 self; + self.setU8(x0, x1, x2, x3, x4, x5, x6, x7); + return self; + } + + //! Sets all four 16-bit signed integers. + static inline Data64 fromI16(int16_t x0) noexcept { + Data64 self; + self.setI16(x0); + return self; + } + + //! Sets all four 16-bit unsigned integers. + static inline Data64 fromU16(uint16_t x0) noexcept { + Data64 self; + self.setU16(x0); + return self; + } + + //! Sets all four 16-bit signed integers. + static inline Data64 fromI16(int16_t x0, int16_t x1, int16_t x2, int16_t x3) noexcept { + Data64 self; + self.setI16(x0, x1, x2, x3); + return self; + } + + //! Sets all four 16-bit unsigned integers. + static inline Data64 fromU16(uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3) noexcept { + Data64 self; + self.setU16(x0, x1, x2, x3); + return self; + } + + //! Sets all two 32-bit signed integers. + static inline Data64 fromI32(int32_t x0) noexcept { + Data64 self; + self.setI32(x0); + return self; + } + + //! Sets all two 32-bit unsigned integers. + static inline Data64 fromU32(uint32_t x0) noexcept { + Data64 self; + self.setU32(x0); + return self; + } + + //! Sets all two 32-bit signed integers. + static inline Data64 fromI32(int32_t x0, int32_t x1) noexcept { + Data64 self; + self.setI32(x0, x1); + return self; + } + + //! Sets all two 32-bit unsigned integers. + static inline Data64 fromU32(uint32_t x0, uint32_t x1) noexcept { + Data64 self; + self.setU32(x0, x1); + return self; + } + + //! Sets 64-bit signed integer. + static inline Data64 fromI64(int64_t x0) noexcept { + Data64 self; + self.setI64(x0); + return self; + } + + //! Sets 64-bit unsigned integer. + static inline Data64 fromU64(uint64_t x0) noexcept { + Data64 self; + self.setU64(x0); + return self; + } + + //! Sets all two SP-FP values. + static inline Data64 fromF32(float x0) noexcept { + Data64 self; + self.setF32(x0); + return self; + } + + //! Sets all two SP-FP values. + static inline Data64 fromF32(float x0, float x1) noexcept { + Data64 self; + self.setF32(x0, x1); + return self; + } + + //! Sets all two SP-FP values. + static inline Data64 fromF64(double x0) noexcept { + Data64 self; + self.setF64(x0); + return self; + } + + //! \} + + //! \name Accessors + //! \{ + + //! Sets all eight 8-bit signed integers. + inline void setI8(int8_t x0) noexcept { + setU8(uint8_t(x0)); + } + + //! Sets all eight 8-bit unsigned integers. + inline void setU8(uint8_t x0) noexcept { + if (ASMJIT_ARCH_BITS >= 64) { + uint64_t xq = uint64_t(x0) * 0x0101010101010101u; + uq[0] = xq; + } + else { + uint32_t xd = uint32_t(x0) * 0x01010101u; + ud[0] = xd; + ud[1] = xd; + } + } + + //! Sets all eight 8-bit signed integers. + inline void setI8( + int8_t x0, int8_t x1, int8_t x2, int8_t x3, int8_t x4, int8_t x5, int8_t x6, int8_t x7) noexcept { + + sb[0] = x0; sb[1] = x1; sb[2] = x2; sb[3] = x3; + sb[4] = x4; sb[5] = x5; sb[6] = x6; sb[7] = x7; + } + + //! Sets all eight 8-bit unsigned integers. + inline void setU8( + uint8_t x0, uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4, uint8_t x5, uint8_t x6, uint8_t x7) noexcept { + + ub[0] = x0; ub[1] = x1; ub[2] = x2; ub[3] = x3; + ub[4] = x4; ub[5] = x5; ub[6] = x6; ub[7] = x7; + } + + //! Sets all four 16-bit signed integers. + inline void setI16(int16_t x0) noexcept { + setU16(uint16_t(x0)); + } + + //! Sets all four 16-bit unsigned integers. + inline void setU16(uint16_t x0) noexcept { + if (ASMJIT_ARCH_BITS >= 64) { + uint64_t xq = uint64_t(x0) * 0x0001000100010001u; + uq[0] = xq; + } + else { + uint32_t xd = uint32_t(x0) * 0x00010001u; + ud[0] = xd; + ud[1] = xd; + } + } + + //! Sets all four 16-bit signed integers. + inline void setI16(int16_t x0, int16_t x1, int16_t x2, int16_t x3) noexcept { + sw[0] = x0; sw[1] = x1; sw[2] = x2; sw[3] = x3; + } + + //! Sets all four 16-bit unsigned integers. + inline void setU16(uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3) noexcept { + uw[0] = x0; uw[1] = x1; uw[2] = x2; uw[3] = x3; + } + + //! Sets all two 32-bit signed integers. + inline void setI32(int32_t x0) noexcept { + sd[0] = x0; sd[1] = x0; + } + + //! Sets all two 32-bit unsigned integers. + inline void setU32(uint32_t x0) noexcept { + ud[0] = x0; ud[1] = x0; + } + + //! Sets all two 32-bit signed integers. + inline void setI32(int32_t x0, int32_t x1) noexcept { + sd[0] = x0; sd[1] = x1; + } + + //! Sets all two 32-bit unsigned integers. + inline void setU32(uint32_t x0, uint32_t x1) noexcept { + ud[0] = x0; ud[1] = x1; + } + + //! Sets 64-bit signed integer. + inline void setI64(int64_t x0) noexcept { + sq[0] = x0; + } + + //! Sets 64-bit unsigned integer. + inline void setU64(uint64_t x0) noexcept { + uq[0] = x0; + } + + //! Sets all two SP-FP values. + inline void setF32(float x0) noexcept { + sf[0] = x0; sf[1] = x0; + } + + //! Sets all two SP-FP values. + inline void setF32(float x0, float x1) noexcept { + sf[0] = x0; sf[1] = x1; + } + + //! Sets all two SP-FP values. + inline void setF64(double x0) noexcept { + df[0] = x0; + } +}; + +// ============================================================================ +// [asmjit::Data128] +// ============================================================================ + +//! 128-bit data useful for creating SIMD constants. +union ASMJIT_DEPRECATED_STRUCT("Data128 is deprecated and will be removed in the future") Data128 { + //! Array of sixteen 8-bit signed integers. + int8_t sb[16]; + //! Array of sixteen 8-bit unsigned integers. + uint8_t ub[16]; + //! Array of eight 16-bit signed integers. + int16_t sw[8]; + //! Array of eight 16-bit unsigned integers. + uint16_t uw[8]; + //! Array of four 32-bit signed integers. + int32_t sd[4]; + //! Array of four 32-bit unsigned integers. + uint32_t ud[4]; + //! Array of two 64-bit signed integers. + int64_t sq[2]; + //! Array of two 64-bit unsigned integers. + uint64_t uq[2]; + + //! Array of four 32-bit single precision floating points. + float sf[4]; + //! Array of two 64-bit double precision floating points. + double df[2]; + + //! \name Construction & Destruction + //! \{ + + //! Sets all sixteen 8-bit signed integers. + static inline Data128 fromI8(int8_t x0) noexcept { + Data128 self; + self.setI8(x0); + return self; + } + + //! Sets all sixteen 8-bit unsigned integers. + static inline Data128 fromU8(uint8_t x0) noexcept { + Data128 self; + self.setU8(x0); + return self; + } + + //! Sets all sixteen 8-bit signed integers. + static inline Data128 fromI8( + int8_t x0 , int8_t x1 , int8_t x2 , int8_t x3 , + int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 , + int8_t x8 , int8_t x9 , int8_t x10, int8_t x11, + int8_t x12, int8_t x13, int8_t x14, int8_t x15) noexcept { + + Data128 self; + self.setI8(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15); + return self; + } + + //! Sets all sixteen 8-bit unsigned integers. + static inline Data128 fromU8( + uint8_t x0 , uint8_t x1 , uint8_t x2 , uint8_t x3 , + uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 , + uint8_t x8 , uint8_t x9 , uint8_t x10, uint8_t x11, + uint8_t x12, uint8_t x13, uint8_t x14, uint8_t x15) noexcept { + + Data128 self; + self.setU8(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15); + return self; + } + + //! Sets all eight 16-bit signed integers. + static inline Data128 fromI16(int16_t x0) noexcept { + Data128 self; + self.setI16(x0); + return self; + } + + //! Sets all eight 16-bit unsigned integers. + static inline Data128 fromU16(uint16_t x0) noexcept { + Data128 self; + self.setU16(x0); + return self; + } + + //! Sets all eight 16-bit signed integers. + static inline Data128 fromI16( + int16_t x0, int16_t x1, int16_t x2, int16_t x3, int16_t x4, int16_t x5, int16_t x6, int16_t x7) noexcept { + + Data128 self; + self.setI16(x0, x1, x2, x3, x4, x5, x6, x7); + return self; + } + + //! Sets all eight 16-bit unsigned integers. + static inline Data128 fromU16( + uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3, uint16_t x4, uint16_t x5, uint16_t x6, uint16_t x7) noexcept { + + Data128 self; + self.setU16(x0, x1, x2, x3, x4, x5, x6, x7); + return self; + } + + //! Sets all four 32-bit signed integers. + static inline Data128 fromI32(int32_t x0) noexcept { + Data128 self; + self.setI32(x0); + return self; + } + + //! Sets all four 32-bit unsigned integers. + static inline Data128 fromU32(uint32_t x0) noexcept { + Data128 self; + self.setU32(x0); + return self; + } + + //! Sets all four 32-bit signed integers. + static inline Data128 fromI32(int32_t x0, int32_t x1, int32_t x2, int32_t x3) noexcept { + Data128 self; + self.setI32(x0, x1, x2, x3); + return self; + } + + //! Sets all four 32-bit unsigned integers. + static inline Data128 fromU32(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3) noexcept { + Data128 self; + self.setU32(x0, x1, x2, x3); + return self; + } + + //! Sets all two 64-bit signed integers. + static inline Data128 fromI64(int64_t x0) noexcept { + Data128 self; + self.setI64(x0); + return self; + } + + //! Sets all two 64-bit unsigned integers. + static inline Data128 fromU64(uint64_t x0) noexcept { + Data128 self; + self.setU64(x0); + return self; + } + + //! Sets all two 64-bit signed integers. + static inline Data128 fromI64(int64_t x0, int64_t x1) noexcept { + Data128 self; + self.setI64(x0, x1); + return self; + } + + //! Sets all two 64-bit unsigned integers. + static inline Data128 fromU64(uint64_t x0, uint64_t x1) noexcept { + Data128 self; + self.setU64(x0, x1); + return self; + } + + //! Sets all four SP-FP floats. + static inline Data128 fromF32(float x0) noexcept { + Data128 self; + self.setF32(x0); + return self; + } + + //! Sets all four SP-FP floats. + static inline Data128 fromF32(float x0, float x1, float x2, float x3) noexcept { + Data128 self; + self.setF32(x0, x1, x2, x3); + return self; + } + + //! Sets all two DP-FP floats. + static inline Data128 fromF64(double x0) noexcept { + Data128 self; + self.setF64(x0); + return self; + } + + //! Sets all two DP-FP floats. + static inline Data128 fromF64(double x0, double x1) noexcept { + Data128 self; + self.setF64(x0, x1); + return self; + } + + //! \} + + //! \name Accessors + //! \{ + + //! Sets all sixteen 8-bit signed integers. + inline void setI8(int8_t x0) noexcept { + setU8(uint8_t(x0)); + } + + //! Sets all sixteen 8-bit unsigned integers. + inline void setU8(uint8_t x0) noexcept { + if (ASMJIT_ARCH_BITS >= 64) { + uint64_t xq = uint64_t(x0) * 0x0101010101010101u; + uq[0] = xq; + uq[1] = xq; + } + else { + uint32_t xd = uint32_t(x0) * 0x01010101u; + ud[0] = xd; + ud[1] = xd; + ud[2] = xd; + ud[3] = xd; + } + } + + //! Sets all sixteen 8-bit signed integers. + inline void setI8( + int8_t x0 , int8_t x1 , int8_t x2 , int8_t x3 , + int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 , + int8_t x8 , int8_t x9 , int8_t x10, int8_t x11, + int8_t x12, int8_t x13, int8_t x14, int8_t x15) noexcept { + + sb[0 ] = x0 ; sb[1 ] = x1 ; sb[2 ] = x2 ; sb[3 ] = x3 ; + sb[4 ] = x4 ; sb[5 ] = x5 ; sb[6 ] = x6 ; sb[7 ] = x7 ; + sb[8 ] = x8 ; sb[9 ] = x9 ; sb[10] = x10; sb[11] = x11; + sb[12] = x12; sb[13] = x13; sb[14] = x14; sb[15] = x15; + } + + //! Sets all sixteen 8-bit unsigned integers. + inline void setU8( + uint8_t x0 , uint8_t x1 , uint8_t x2 , uint8_t x3 , + uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 , + uint8_t x8 , uint8_t x9 , uint8_t x10, uint8_t x11, + uint8_t x12, uint8_t x13, uint8_t x14, uint8_t x15) noexcept { + + ub[0 ] = x0 ; ub[1 ] = x1 ; ub[2 ] = x2 ; ub[3 ] = x3 ; + ub[4 ] = x4 ; ub[5 ] = x5 ; ub[6 ] = x6 ; ub[7 ] = x7 ; + ub[8 ] = x8 ; ub[9 ] = x9 ; ub[10] = x10; ub[11] = x11; + ub[12] = x12; ub[13] = x13; ub[14] = x14; ub[15] = x15; + } + + //! Sets all eight 16-bit signed integers. + inline void setI16(int16_t x0) noexcept { + setU16(uint16_t(x0)); + } + + //! Sets all eight 16-bit unsigned integers. + inline void setU16(uint16_t x0) noexcept { + if (ASMJIT_ARCH_BITS >= 64) { + uint64_t xq = uint64_t(x0) * 0x0001000100010001u; + uq[0] = xq; + uq[1] = xq; + } + else { + uint32_t xd = uint32_t(x0) * 0x00010001u; + ud[0] = xd; + ud[1] = xd; + ud[2] = xd; + ud[3] = xd; + } + } + + //! Sets all eight 16-bit signed integers. + inline void setI16( + int16_t x0, int16_t x1, int16_t x2, int16_t x3, int16_t x4, int16_t x5, int16_t x6, int16_t x7) noexcept { + + sw[0] = x0; sw[1] = x1; sw[2] = x2; sw[3] = x3; + sw[4] = x4; sw[5] = x5; sw[6] = x6; sw[7] = x7; + } + + //! Sets all eight 16-bit unsigned integers. + inline void setU16( + uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3, uint16_t x4, uint16_t x5, uint16_t x6, uint16_t x7) noexcept { + + uw[0] = x0; uw[1] = x1; uw[2] = x2; uw[3] = x3; + uw[4] = x4; uw[5] = x5; uw[6] = x6; uw[7] = x7; + } + + //! Sets all four 32-bit signed integers. + inline void setI32(int32_t x0) noexcept { + setU32(uint32_t(x0)); + } + + //! Sets all four 32-bit unsigned integers. + inline void setU32(uint32_t x0) noexcept { + if (ASMJIT_ARCH_BITS >= 64) { + uint64_t t = (uint64_t(x0) << 32) + x0; + uq[0] = t; + uq[1] = t; + } + else { + ud[0] = x0; + ud[1] = x0; + ud[2] = x0; + ud[3] = x0; + } + } + + //! Sets all four 32-bit signed integers. + inline void setI32(int32_t x0, int32_t x1, int32_t x2, int32_t x3) noexcept { + sd[0] = x0; sd[1] = x1; sd[2] = x2; sd[3] = x3; + } + + //! Sets all four 32-bit unsigned integers. + inline void setU32(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3) noexcept { + ud[0] = x0; ud[1] = x1; ud[2] = x2; ud[3] = x3; + } + + //! Sets all two 64-bit signed integers. + inline void setI64(int64_t x0) noexcept { + sq[0] = x0; sq[1] = x0; + } + + //! Sets all two 64-bit unsigned integers. + inline void setU64(uint64_t x0) noexcept { + uq[0] = x0; uq[1] = x0; + } + + //! Sets all two 64-bit signed integers. + inline void setI64(int64_t x0, int64_t x1) noexcept { + sq[0] = x0; sq[1] = x1; + } + + //! Sets all two 64-bit unsigned integers. + inline void setU64(uint64_t x0, uint64_t x1) noexcept { + uq[0] = x0; uq[1] = x1; + } + + //! Sets all four SP-FP floats. + inline void setF32(float x0) noexcept { + sf[0] = x0; sf[1] = x0; sf[2] = x0; sf[3] = x0; + } + + //! Sets all four SP-FP floats. + inline void setF32(float x0, float x1, float x2, float x3) noexcept { + sf[0] = x0; sf[1] = x1; sf[2] = x2; sf[3] = x3; + } + + //! Sets all two DP-FP floats. + inline void setF64(double x0) noexcept { + df[0] = x0; df[1] = x0; + } + + //! Sets all two DP-FP floats. + inline void setF64(double x0, double x1) noexcept { + df[0] = x0; df[1] = x1; + } +}; + +// ============================================================================ +// [asmjit::Data256] +// ============================================================================ + +//! 256-bit data useful for creating SIMD constants. +union ASMJIT_DEPRECATED_STRUCT("Data256 is deprecated and will be removed in the future") Data256 { + //! Array of thirty two 8-bit signed integers. + int8_t sb[32]; + //! Array of thirty two 8-bit unsigned integers. + uint8_t ub[32]; + //! Array of sixteen 16-bit signed integers. + int16_t sw[16]; + //! Array of sixteen 16-bit unsigned integers. + uint16_t uw[16]; + //! Array of eight 32-bit signed integers. + int32_t sd[8]; + //! Array of eight 32-bit unsigned integers. + uint32_t ud[8]; + //! Array of four 64-bit signed integers. + int64_t sq[4]; + //! Array of four 64-bit unsigned integers. + uint64_t uq[4]; + + //! Array of eight 32-bit single precision floating points. + float sf[8]; + //! Array of four 64-bit double precision floating points. + double df[4]; + + //! \name Construction & Destruction + //! \{ + + //! Sets all thirty two 8-bit signed integers. + static inline Data256 fromI8(int8_t x0) noexcept { + Data256 self; + self.setI8(x0); + return self; + } + + //! Sets all thirty two 8-bit unsigned integers. + static inline Data256 fromU8(uint8_t x0) noexcept { + Data256 self; + self.setU8(x0); + return self; + } + + //! Sets all thirty two 8-bit signed integers. + static inline Data256 fromI8( + int8_t x0 , int8_t x1 , int8_t x2 , int8_t x3 , + int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 , + int8_t x8 , int8_t x9 , int8_t x10, int8_t x11, + int8_t x12, int8_t x13, int8_t x14, int8_t x15, + int8_t x16, int8_t x17, int8_t x18, int8_t x19, + int8_t x20, int8_t x21, int8_t x22, int8_t x23, + int8_t x24, int8_t x25, int8_t x26, int8_t x27, + int8_t x28, int8_t x29, int8_t x30, int8_t x31) noexcept { + + Data256 self; + self.setI8( + x0, x1 , x2 , x3 , x4 , x5 , x6 , x7 , x8 , x9 , x10, x11, x12, x13, x14, x15, + x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31); + return self; + } + + //! Sets all thirty two 8-bit unsigned integers. + static inline Data256 fromU8( + uint8_t x0 , uint8_t x1 , uint8_t x2 , uint8_t x3 , + uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 , + uint8_t x8 , uint8_t x9 , uint8_t x10, uint8_t x11, + uint8_t x12, uint8_t x13, uint8_t x14, uint8_t x15, + uint8_t x16, uint8_t x17, uint8_t x18, uint8_t x19, + uint8_t x20, uint8_t x21, uint8_t x22, uint8_t x23, + uint8_t x24, uint8_t x25, uint8_t x26, uint8_t x27, + uint8_t x28, uint8_t x29, uint8_t x30, uint8_t x31) noexcept { + + Data256 self; + self.setU8( + x0, x1 , x2 , x3 , x4 , x5 , x6 , x7 , x8 , x9 , x10, x11, x12, x13, x14, x15, + x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31); + return self; + } + + //! Sets all sixteen 16-bit signed integers. + static inline Data256 fromI16(int16_t x0) noexcept { + Data256 self; + self.setI16(x0); + return self; + } + + //! Sets all sixteen 16-bit unsigned integers. + static inline Data256 fromU16(uint16_t x0) noexcept { + Data256 self; + self.setU16(x0); + return self; + } + + //! Sets all sixteen 16-bit signed integers. + static inline Data256 fromI16( + int16_t x0, int16_t x1, int16_t x2 , int16_t x3 , int16_t x4 , int16_t x5 , int16_t x6 , int16_t x7 , + int16_t x8, int16_t x9, int16_t x10, int16_t x11, int16_t x12, int16_t x13, int16_t x14, int16_t x15) noexcept { + + Data256 self; + self.setI16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15); + return self; + } + + //! Sets all sixteen 16-bit unsigned integers. + static inline Data256 fromU16( + uint16_t x0, uint16_t x1, uint16_t x2 , uint16_t x3 , uint16_t x4 , uint16_t x5 , uint16_t x6 , uint16_t x7 , + uint16_t x8, uint16_t x9, uint16_t x10, uint16_t x11, uint16_t x12, uint16_t x13, uint16_t x14, uint16_t x15) noexcept { + + Data256 self; + self.setU16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15); + return self; + } + + //! Sets all eight 32-bit signed integers. + static inline Data256 fromI32(int32_t x0) noexcept { + Data256 self; + self.setI32(x0); + return self; + } + + //! Sets all eight 32-bit unsigned integers. + static inline Data256 fromU32(uint32_t x0) noexcept { + Data256 self; + self.setU32(x0); + return self; + } + + //! Sets all eight 32-bit signed integers. + static inline Data256 fromI32( + int32_t x0, int32_t x1, int32_t x2, int32_t x3, + int32_t x4, int32_t x5, int32_t x6, int32_t x7) noexcept { + + Data256 self; + self.setI32(x0, x1, x2, x3, x4, x5, x6, x7); + return self; + } + + //! Sets all eight 32-bit unsigned integers. + static inline Data256 fromU32( + uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, + uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7) noexcept { + + Data256 self; + self.setU32(x0, x1, x2, x3, x4, x5, x6, x7); + return self; + } + + //! Sets all four 64-bit signed integers. + static inline Data256 fromI64(int64_t x0) noexcept { + Data256 self; + self.setI64(x0); + return self; + } + + //! Sets all four 64-bit unsigned integers. + static inline Data256 fromU64(uint64_t x0) noexcept { + Data256 self; + self.setU64(x0); + return self; + } + + //! Sets all four 64-bit signed integers. + static inline Data256 fromI64(int64_t x0, int64_t x1, int64_t x2, int64_t x3) noexcept { + Data256 self; + self.setI64(x0, x1, x2, x3); + return self; + } + + //! Sets all four 64-bit unsigned integers. + static inline Data256 fromU64(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3) noexcept { + Data256 self; + self.setU64(x0, x1, x2, x3); + return self; + } + + //! Sets all eight SP-FP floats. + static inline Data256 fromF32(float x0) noexcept { + Data256 self; + self.setF32(x0); + return self; + } + + //! Sets all eight SP-FP floats. + static inline Data256 fromF32( + float x0, float x1, float x2, float x3, + float x4, float x5, float x6, float x7) noexcept { + + Data256 self; + self.setF32(x0, x1, x2, x3, x4, x5, x6, x7); + return self; + } + + //! Sets all four DP-FP floats. + static inline Data256 fromF64(double x0) noexcept { + Data256 self; + self.setF64(x0); + return self; + } + + //! Sets all four DP-FP floats. + static inline Data256 fromF64(double x0, double x1, double x2, double x3) noexcept { + Data256 self; + self.setF64(x0, x1, x2, x3); + return self; + } + + //! \} + + //! \name Accessors + //! \{ + + //! Sets all thirty two 8-bit signed integers. + inline void setI8(int8_t x0) noexcept { + setU8(uint8_t(x0)); + } + + //! Sets all thirty two 8-bit unsigned integers. + inline void setU8(uint8_t x0) noexcept { + if (ASMJIT_ARCH_BITS >= 64) { + uint64_t xq = uint64_t(x0) * 0x0101010101010101u; + uq[0] = xq; + uq[1] = xq; + uq[2] = xq; + uq[3] = xq; + } + else { + uint32_t xd = uint32_t(x0) * 0x01010101u; + ud[0] = xd; + ud[1] = xd; + ud[2] = xd; + ud[3] = xd; + ud[4] = xd; + ud[5] = xd; + ud[6] = xd; + ud[7] = xd; + } + } + + //! Sets all thirty two 8-bit signed integers. + inline void setI8( + int8_t x0 , int8_t x1 , int8_t x2 , int8_t x3 , + int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 , + int8_t x8 , int8_t x9 , int8_t x10, int8_t x11, + int8_t x12, int8_t x13, int8_t x14, int8_t x15, + int8_t x16, int8_t x17, int8_t x18, int8_t x19, + int8_t x20, int8_t x21, int8_t x22, int8_t x23, + int8_t x24, int8_t x25, int8_t x26, int8_t x27, + int8_t x28, int8_t x29, int8_t x30, int8_t x31) noexcept { + + sb[0 ] = x0 ; sb[1 ] = x1 ; sb[2 ] = x2 ; sb[3 ] = x3 ; + sb[4 ] = x4 ; sb[5 ] = x5 ; sb[6 ] = x6 ; sb[7 ] = x7 ; + sb[8 ] = x8 ; sb[9 ] = x9 ; sb[10] = x10; sb[11] = x11; + sb[12] = x12; sb[13] = x13; sb[14] = x14; sb[15] = x15; + sb[16] = x16; sb[17] = x17; sb[18] = x18; sb[19] = x19; + sb[20] = x20; sb[21] = x21; sb[22] = x22; sb[23] = x23; + sb[24] = x24; sb[25] = x25; sb[26] = x26; sb[27] = x27; + sb[28] = x28; sb[29] = x29; sb[30] = x30; sb[31] = x31; + } + + //! Sets all thirty two 8-bit unsigned integers. + inline void setU8( + uint8_t x0 , uint8_t x1 , uint8_t x2 , uint8_t x3 , + uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 , + uint8_t x8 , uint8_t x9 , uint8_t x10, uint8_t x11, + uint8_t x12, uint8_t x13, uint8_t x14, uint8_t x15, + uint8_t x16, uint8_t x17, uint8_t x18, uint8_t x19, + uint8_t x20, uint8_t x21, uint8_t x22, uint8_t x23, + uint8_t x24, uint8_t x25, uint8_t x26, uint8_t x27, + uint8_t x28, uint8_t x29, uint8_t x30, uint8_t x31) noexcept { + + ub[0 ] = x0 ; ub[1 ] = x1 ; ub[2 ] = x2 ; ub[3 ] = x3 ; + ub[4 ] = x4 ; ub[5 ] = x5 ; ub[6 ] = x6 ; ub[7 ] = x7 ; + ub[8 ] = x8 ; ub[9 ] = x9 ; ub[10] = x10; ub[11] = x11; + ub[12] = x12; ub[13] = x13; ub[14] = x14; ub[15] = x15; + ub[16] = x16; ub[17] = x17; ub[18] = x18; ub[19] = x19; + ub[20] = x20; ub[21] = x21; ub[22] = x22; ub[23] = x23; + ub[24] = x24; ub[25] = x25; ub[26] = x26; ub[27] = x27; + ub[28] = x28; ub[29] = x29; ub[30] = x30; ub[31] = x31; + } + + //! Sets all sixteen 16-bit signed integers. + inline void setI16(int16_t x0) noexcept { + setU16(uint16_t(x0)); + } + + //! Sets all eight 16-bit unsigned integers. + inline void setU16(uint16_t x0) noexcept { + if (ASMJIT_ARCH_BITS >= 64) { + uint64_t xq = uint64_t(x0) * 0x0001000100010001u; + uq[0] = xq; + uq[1] = xq; + uq[2] = xq; + uq[3] = xq; + } + else { + uint32_t xd = uint32_t(x0) * 0x00010001u; + ud[0] = xd; + ud[1] = xd; + ud[2] = xd; + ud[3] = xd; + ud[4] = xd; + ud[5] = xd; + ud[6] = xd; + ud[7] = xd; + } + } + + //! Sets all sixteen 16-bit signed integers. + inline void setI16( + int16_t x0, int16_t x1, int16_t x2 , int16_t x3 , int16_t x4 , int16_t x5 , int16_t x6 , int16_t x7, + int16_t x8, int16_t x9, int16_t x10, int16_t x11, int16_t x12, int16_t x13, int16_t x14, int16_t x15) noexcept { + + sw[0 ] = x0 ; sw[1 ] = x1 ; sw[2 ] = x2 ; sw[3 ] = x3 ; + sw[4 ] = x4 ; sw[5 ] = x5 ; sw[6 ] = x6 ; sw[7 ] = x7 ; + sw[8 ] = x8 ; sw[9 ] = x9 ; sw[10] = x10; sw[11] = x11; + sw[12] = x12; sw[13] = x13; sw[14] = x14; sw[15] = x15; + } + + //! Sets all sixteen 16-bit unsigned integers. + inline void setU16( + uint16_t x0, uint16_t x1, uint16_t x2 , uint16_t x3 , uint16_t x4 , uint16_t x5 , uint16_t x6 , uint16_t x7, + uint16_t x8, uint16_t x9, uint16_t x10, uint16_t x11, uint16_t x12, uint16_t x13, uint16_t x14, uint16_t x15) noexcept { + + uw[0 ] = x0 ; uw[1 ] = x1 ; uw[2 ] = x2 ; uw[3 ] = x3 ; + uw[4 ] = x4 ; uw[5 ] = x5 ; uw[6 ] = x6 ; uw[7 ] = x7 ; + uw[8 ] = x8 ; uw[9 ] = x9 ; uw[10] = x10; uw[11] = x11; + uw[12] = x12; uw[13] = x13; uw[14] = x14; uw[15] = x15; + } + + //! Sets all eight 32-bit signed integers. + inline void setI32(int32_t x0) noexcept { + setU32(uint32_t(x0)); + } + + //! Sets all eight 32-bit unsigned integers. + inline void setU32(uint32_t x0) noexcept { + if (ASMJIT_ARCH_BITS >= 64) { + uint64_t xq = (uint64_t(x0) << 32) + x0; + uq[0] = xq; + uq[1] = xq; + uq[2] = xq; + uq[3] = xq; + } + else { + ud[0] = x0; + ud[1] = x0; + ud[2] = x0; + ud[3] = x0; + ud[4] = x0; + ud[5] = x0; + ud[6] = x0; + ud[7] = x0; + } + } + + //! Sets all eight 32-bit signed integers. + inline void setI32( + int32_t x0, int32_t x1, int32_t x2, int32_t x3, + int32_t x4, int32_t x5, int32_t x6, int32_t x7) noexcept { + + sd[0] = x0; sd[1] = x1; sd[2] = x2; sd[3] = x3; + sd[4] = x4; sd[5] = x5; sd[6] = x6; sd[7] = x7; + } + + //! Sets all eight 32-bit unsigned integers. + inline void setU32( + uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, + uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7) noexcept { + + ud[0] = x0; ud[1] = x1; ud[2] = x2; ud[3] = x3; + ud[4] = x4; ud[5] = x5; ud[6] = x6; ud[7] = x7; + } + + //! Sets all four 64-bit signed integers. + inline void setI64(int64_t x0) noexcept { + sq[0] = x0; sq[1] = x0; sq[2] = x0; sq[3] = x0; + } + + //! Sets all four 64-bit unsigned integers. + inline void setU64(uint64_t x0) noexcept { + uq[0] = x0; uq[1] = x0; uq[2] = x0; uq[3] = x0; + } + + //! Sets all four 64-bit signed integers. + inline void setI64(int64_t x0, int64_t x1, int64_t x2, int64_t x3) noexcept { + sq[0] = x0; sq[1] = x1; sq[2] = x2; sq[3] = x3; + } + + //! Sets all four 64-bit unsigned integers. + inline void setU64(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3) noexcept { + uq[0] = x0; uq[1] = x1; uq[2] = x2; uq[3] = x3; + } + + //! Sets all eight SP-FP floats. + inline void setF32(float x0) noexcept { + sf[0] = x0; sf[1] = x0; sf[2] = x0; sf[3] = x0; + sf[4] = x0; sf[5] = x0; sf[6] = x0; sf[7] = x0; + } + + //! Sets all eight SP-FP floats. + inline void setF32( + float x0, float x1, float x2, float x3, + float x4, float x5, float x6, float x7) noexcept { + + sf[0] = x0; sf[1] = x1; sf[2] = x2; sf[3] = x3; + sf[4] = x4; sf[5] = x5; sf[6] = x6; sf[7] = x7; + } + + //! Sets all four DP-FP floats. + inline void setF64(double x0) noexcept { + df[0] = x0; df[1] = x0; df[2] = x0; df[3] = x0; + } + + //! Sets all four DP-FP floats. + inline void setF64(double x0, double x1, double x2, double x3) noexcept { + df[0] = x0; df[1] = x1; df[2] = x2; df[3] = x3; + } + + //! \} +}; + +ASMJIT_END_NAMESPACE + +#endif // !ASMJIT_NO_DEPRECATED +#endif // ASMJIT_CORE_DATATYPES_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emithelper.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emithelper.cpp new file mode 100644 index 0000000..a77211e --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emithelper.cpp @@ -0,0 +1,351 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/archtraits.h" +#include "../core/emithelper_p.h" +#include "../core/formatter.h" +#include "../core/funcargscontext_p.h" +#include "../core/radefs_p.h" + +// Can be used for debugging... +// #define ASMJIT_DUMP_ARGS_ASSIGNMENT + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::BaseEmitHelper - Formatting] +// ============================================================================ + +#ifdef ASMJIT_DUMP_ARGS_ASSIGNMENT +static void dumpFuncValue(String& sb, uint32_t arch, const FuncValue& value) noexcept { + Formatter::formatTypeId(sb, value.typeId()); + sb.append('@'); + + if (value.isIndirect()) + sb.append('['); + + if (value.isReg()) + Formatter::formatRegister(sb, 0, nullptr, arch, value.regType(), value.regId()); + else if (value.isStack()) + sb.appendFormat("[%d]", value.stackOffset()); + else + sb.append(""); + + if (value.isIndirect()) + sb.append(']'); +} + +static void dumpAssignment(String& sb, const FuncArgsContext& ctx) noexcept { + typedef FuncArgsContext::Var Var; + + uint32_t arch = ctx.arch(); + uint32_t varCount = ctx.varCount(); + + for (uint32_t i = 0; i < varCount; i++) { + const Var& var = ctx.var(i); + const FuncValue& dst = var.out; + const FuncValue& cur = var.cur; + + sb.appendFormat("Var%u: ", i); + dumpFuncValue(sb, arch, dst); + sb.append(" <- "); + dumpFuncValue(sb, arch, cur); + + if (var.isDone()) + sb.append(" {Done}"); + + sb.append('\n'); + } +} +#endif + +// ============================================================================ +// [asmjit::BaseEmitHelper - EmitArgsAssignment] +// ============================================================================ + +ASMJIT_FAVOR_SIZE Error BaseEmitHelper::emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args) { + typedef FuncArgsContext::Var Var; + typedef FuncArgsContext::WorkData WorkData; + + enum WorkFlags : uint32_t { + kWorkNone = 0x00, + kWorkDidSome = 0x01, + kWorkPending = 0x02, + kWorkPostponed = 0x04 + }; + + uint32_t arch = frame.arch(); + const ArchTraits& archTraits = ArchTraits::byArch(arch); + + RAConstraints constraints; + FuncArgsContext ctx; + + ASMJIT_PROPAGATE(constraints.init(arch)); + ASMJIT_PROPAGATE(ctx.initWorkData(frame, args, &constraints)); + +#ifdef ASMJIT_DUMP_ARGS_ASSIGNMENT + { + String sb; + dumpAssignment(sb, ctx); + printf("%s\n", sb.data()); + } +#endif + + uint32_t varCount = ctx._varCount; + WorkData* workData = ctx._workData; + + uint32_t saVarId = ctx._saVarId; + BaseReg sp = BaseReg::fromSignatureAndId(_emitter->_gpRegInfo.signature(), archTraits.spRegId()); + BaseReg sa = sp; + + if (frame.hasDynamicAlignment()) { + if (frame.hasPreservedFP()) + sa.setId(archTraits.fpRegId()); + else + sa.setId(saVarId < varCount ? ctx._vars[saVarId].cur.regId() : frame.saRegId()); + } + + // -------------------------------------------------------------------------- + // Register to stack and stack to stack moves must be first as now we have + // the biggest chance of having as many as possible unassigned registers. + // -------------------------------------------------------------------------- + + if (ctx._stackDstMask) { + // Base address of all arguments passed by stack. + BaseMem baseArgPtr(sa, int32_t(frame.saOffset(sa.id()))); + BaseMem baseStackPtr(sp, 0); + + for (uint32_t varId = 0; varId < varCount; varId++) { + Var& var = ctx._vars[varId]; + + if (!var.out.isStack()) + continue; + + FuncValue& cur = var.cur; + FuncValue& out = var.out; + + ASMJIT_ASSERT(cur.isReg() || cur.isStack()); + BaseReg reg; + + BaseMem dstStackPtr = baseStackPtr.cloneAdjusted(out.stackOffset()); + BaseMem srcStackPtr = baseArgPtr.cloneAdjusted(cur.stackOffset()); + + if (cur.isIndirect()) { + if (cur.isStack()) { + // TODO: Indirect stack. + return DebugUtils::errored(kErrorInvalidAssignment); + } + else { + srcStackPtr.setBaseId(cur.regId()); + } + } + + if (cur.isReg() && !cur.isIndirect()) { + WorkData& wd = workData[archTraits.regTypeToGroup(cur.regType())]; + uint32_t rId = cur.regId(); + + reg.setSignatureAndId(archTraits.regTypeToSignature(cur.regType()), rId); + wd.unassign(varId, rId); + } + else { + // Stack to reg move - tricky since we move stack to stack we can decide which + // register to use. In general we follow the rule that IntToInt moves will use + // GP regs with possibility to signature or zero extend, and all other moves will + // either use GP or VEC regs depending on the size of the move. + RegInfo rInfo = getSuitableRegForMemToMemMove(arch, out.typeId(), cur.typeId()); + if (ASMJIT_UNLIKELY(!rInfo.isValid())) + return DebugUtils::errored(kErrorInvalidState); + + WorkData& wd = workData[rInfo.group()]; + uint32_t availableRegs = wd.availableRegs(); + if (ASMJIT_UNLIKELY(!availableRegs)) + return DebugUtils::errored(kErrorInvalidState); + + uint32_t rId = Support::ctz(availableRegs); + reg.setSignatureAndId(rInfo.signature(), rId); + + ASMJIT_PROPAGATE(emitArgMove(reg, out.typeId(), srcStackPtr, cur.typeId())); + } + + if (cur.isIndirect() && cur.isReg()) + workData[BaseReg::kGroupGp].unassign(varId, cur.regId()); + + // Register to stack move. + ASMJIT_PROPAGATE(emitRegMove(dstStackPtr, reg, cur.typeId())); + var.markDone(); + } + } + + // -------------------------------------------------------------------------- + // Shuffle all registers that are currently assigned accordingly to target + // assignment. + // -------------------------------------------------------------------------- + + uint32_t workFlags = kWorkNone; + for (;;) { + for (uint32_t varId = 0; varId < varCount; varId++) { + Var& var = ctx._vars[varId]; + if (var.isDone() || !var.cur.isReg()) + continue; + + FuncValue& cur = var.cur; + FuncValue& out = var.out; + + uint32_t curGroup = archTraits.regTypeToGroup(cur.regType()); + uint32_t outGroup = archTraits.regTypeToGroup(out.regType()); + + uint32_t curId = cur.regId(); + uint32_t outId = out.regId(); + + if (curGroup != outGroup) { + // TODO: Conversion is not supported. + return DebugUtils::errored(kErrorInvalidAssignment); + } + else { + WorkData& wd = workData[outGroup]; + if (!wd.isAssigned(outId)) { +EmitMove: + ASMJIT_PROPAGATE( + emitArgMove( + BaseReg::fromSignatureAndId(archTraits.regTypeToSignature(out.regType()), outId), out.typeId(), + BaseReg::fromSignatureAndId(archTraits.regTypeToSignature(cur.regType()), curId), cur.typeId())); + + wd.reassign(varId, outId, curId); + cur.initReg(out.regType(), outId, out.typeId()); + + if (outId == out.regId()) + var.markDone(); + workFlags |= kWorkDidSome | kWorkPending; + } + else { + uint32_t altId = wd._physToVarId[outId]; + Var& altVar = ctx._vars[altId]; + + if (!altVar.out.isInitialized() || (altVar.out.isReg() && altVar.out.regId() == curId)) { + // Only few architectures provide swap operations, and only for few register groups. + if (archTraits.hasSwap(curGroup)) { + uint32_t highestType = Support::max(cur.regType(), altVar.cur.regType()); + if (Support::isBetween(highestType, BaseReg::kTypeGp8Lo, BaseReg::kTypeGp16)) + highestType = BaseReg::kTypeGp32; + + uint32_t signature = archTraits.regTypeToSignature(highestType); + ASMJIT_PROPAGATE( + emitRegSwap(BaseReg::fromSignatureAndId(signature, outId), + BaseReg::fromSignatureAndId(signature, curId))); + wd.swap(varId, curId, altId, outId); + cur.setRegId(outId); + var.markDone(); + altVar.cur.setRegId(curId); + + if (altVar.out.isInitialized()) + altVar.markDone(); + workFlags |= kWorkDidSome; + } + else { + // If there is a scratch register it can be used to perform the swap. + uint32_t availableRegs = wd.availableRegs(); + if (availableRegs) { + uint32_t inOutRegs = wd.dstRegs(); + if (availableRegs & ~inOutRegs) + availableRegs &= ~inOutRegs; + outId = Support::ctz(availableRegs); + goto EmitMove; + } + else { + workFlags |= kWorkPending; + } + } + } + else { + workFlags |= kWorkPending; + } + } + } + } + + if (!(workFlags & kWorkPending)) + break; + + // If we did nothing twice it means that something is really broken. + if ((workFlags & (kWorkDidSome | kWorkPostponed)) == kWorkPostponed) + return DebugUtils::errored(kErrorInvalidState); + + workFlags = (workFlags & kWorkDidSome) ? kWorkNone : kWorkPostponed; + } + + // -------------------------------------------------------------------------- + // Load arguments passed by stack into registers. This is pretty simple and + // it never requires multiple iterations like the previous phase. + // -------------------------------------------------------------------------- + + if (ctx._hasStackSrc) { + uint32_t iterCount = 1; + if (frame.hasDynamicAlignment() && !frame.hasPreservedFP()) + sa.setId(saVarId < varCount ? ctx._vars[saVarId].cur.regId() : frame.saRegId()); + + // Base address of all arguments passed by stack. + BaseMem baseArgPtr(sa, int32_t(frame.saOffset(sa.id()))); + + for (uint32_t iter = 0; iter < iterCount; iter++) { + for (uint32_t varId = 0; varId < varCount; varId++) { + Var& var = ctx._vars[varId]; + if (var.isDone()) + continue; + + if (var.cur.isStack()) { + ASMJIT_ASSERT(var.out.isReg()); + + uint32_t outId = var.out.regId(); + uint32_t outType = var.out.regType(); + + uint32_t group = archTraits.regTypeToGroup(outType); + WorkData& wd = ctx._workData[group]; + + if (outId == sa.id() && group == BaseReg::kGroupGp) { + // This register will be processed last as we still need `saRegId`. + if (iterCount == 1) { + iterCount++; + continue; + } + wd.unassign(wd._physToVarId[outId], outId); + } + + BaseReg dstReg = BaseReg::fromSignatureAndId(archTraits.regTypeToSignature(outType), outId); + BaseMem srcMem = baseArgPtr.cloneAdjusted(var.cur.stackOffset()); + + ASMJIT_PROPAGATE(emitArgMove( + dstReg, var.out.typeId(), + srcMem, var.cur.typeId())); + + wd.assign(varId, outId); + var.cur.initReg(outType, outId, var.cur.typeId(), FuncValue::kFlagIsDone); + } + } + } + } + + return kErrorOk; +} + +ASMJIT_END_NAMESPACE diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emithelper_p.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emithelper_p.h new file mode 100644 index 0000000..cb8ddf0 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emithelper_p.h @@ -0,0 +1,83 @@ + +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_EMITHELPER_P_H_INCLUDED +#define ASMJIT_CORE_EMITHELPER_P_H_INCLUDED + +#include "../core/emitter.h" +#include "../core/operand.h" +#include "../core/type.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \cond INTERNAL +//! \addtogroup asmjit_core +//! \{ + +// ============================================================================ +// [asmjit::BaseEmitHelper] +// ============================================================================ + +//! Helper class that provides utilities for each supported architecture. +class BaseEmitHelper { +public: + BaseEmitter* _emitter; + + inline explicit BaseEmitHelper(BaseEmitter* emitter = nullptr) noexcept + : _emitter(emitter) {} + + inline BaseEmitter* emitter() const noexcept { return _emitter; } + inline void setEmitter(BaseEmitter* emitter) noexcept { _emitter = emitter; } + + //! Emits a pure move operation between two registers or the same type or + //! between a register and its home slot. This function does not handle + //! register conversion. + virtual Error emitRegMove( + const Operand_& dst_, + const Operand_& src_, uint32_t typeId, const char* comment = nullptr) = 0; + + //! Emits swap between two registers. + virtual Error emitRegSwap( + const BaseReg& a, + const BaseReg& b, const char* comment = nullptr) = 0; + + //! Emits move from a function argument (either register or stack) to a register. + //! + //! This function can handle the necessary conversion from one argument to + //! another, and from one register type to another, if it's possible. Any + //! attempt of conversion that requires third register of a different group + //! (for example conversion from K to MMX on X86/X64) will fail. + virtual Error emitArgMove( + const BaseReg& dst_, uint32_t dstTypeId, + const Operand_& src_, uint32_t srcTypeId, const char* comment = nullptr) = 0; + + Error emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args); +}; + +//! \} +//! \endcond + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_EMITHELPER_P_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emitter.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emitter.cpp new file mode 100644 index 0000000..f684140 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emitter.cpp @@ -0,0 +1,416 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/emitterutils_p.h" +#include "../core/errorhandler.h" +#include "../core/logger.h" +#include "../core/support.h" + +#ifdef ASMJIT_BUILD_X86 + #include "../x86/x86emithelper_p.h" + #include "../x86/x86instdb_p.h" +#endif // ASMJIT_BUILD_X86 + +#ifdef ASMJIT_BUILD_ARM + #include "../arm/a64emithelper_p.h" + #include "../arm/a64instdb.h" +#endif // ASMJIT_BUILD_ARM + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::BaseEmitter - Construction / Destruction] +// ============================================================================ + +BaseEmitter::BaseEmitter(uint32_t emitterType) noexcept + : _emitterType(uint8_t(emitterType)) {} + +BaseEmitter::~BaseEmitter() noexcept { + if (_code) { + _addEmitterFlags(kFlagDestroyed); + _code->detach(this); + } +} + +// ============================================================================ +// [asmjit::BaseEmitter - Finalize] +// ============================================================================ + +Error BaseEmitter::finalize() { + // Does nothing by default, overridden by `BaseBuilder` and `BaseCompiler`. + return kErrorOk; +} + +// ============================================================================ +// [asmjit::BaseEmitter - Internals] +// ============================================================================ + +static constexpr uint32_t kEmitterPreservedFlags = BaseEmitter::kFlagOwnLogger | BaseEmitter::kFlagOwnErrorHandler; + +static ASMJIT_NOINLINE void BaseEmitter_updateForcedOptions(BaseEmitter* self) noexcept { + bool emitComments = false; + bool hasValidationOptions = false; + + if (self->emitterType() == BaseEmitter::kTypeAssembler) { + // Assembler: Don't emit comments if logger is not attached. + emitComments = self->_code != nullptr && self->_logger != nullptr; + hasValidationOptions = self->hasValidationOption(BaseEmitter::kValidationOptionAssembler); + } + else { + // Builder/Compiler: Always emit comments, we cannot assume they won't be used. + emitComments = self->_code != nullptr; + hasValidationOptions = self->hasValidationOption(BaseEmitter::kValidationOptionIntermediate); + } + + if (emitComments) + self->_addEmitterFlags(BaseEmitter::kFlagLogComments); + else + self->_clearEmitterFlags(BaseEmitter::kFlagLogComments); + + // The reserved option tells emitter (Assembler/Builder/Compiler) that there + // may be either a border case (CodeHolder not attached, for example) or that + // logging or validation is required. + if (self->_code == nullptr || self->_logger || hasValidationOptions) + self->_forcedInstOptions |= BaseInst::kOptionReserved; + else + self->_forcedInstOptions &= ~BaseInst::kOptionReserved; +} + +// ============================================================================ +// [asmjit::BaseEmitter - Validation Options] +// ============================================================================ + +void BaseEmitter::addValidationOptions(uint32_t options) noexcept { + _validationOptions = uint8_t(_validationOptions | options); + BaseEmitter_updateForcedOptions(this); +} + +void BaseEmitter::clearValidationOptions(uint32_t options) noexcept { + _validationOptions = uint8_t(_validationOptions | options); + BaseEmitter_updateForcedOptions(this); +} + +// ============================================================================ +// [asmjit::BaseEmitter - Logging] +// ============================================================================ + +void BaseEmitter::setLogger(Logger* logger) noexcept { +#ifndef ASMJIT_NO_LOGGING + if (logger) { + _logger = logger; + _addEmitterFlags(kFlagOwnLogger); + } + else { + _logger = nullptr; + _clearEmitterFlags(kFlagOwnLogger); + if (_code) + _logger = _code->logger(); + } + BaseEmitter_updateForcedOptions(this); +#else + DebugUtils::unused(logger); +#endif +} + +// ============================================================================ +// [asmjit::BaseEmitter - Error Handling] +// ============================================================================ + +void BaseEmitter::setErrorHandler(ErrorHandler* errorHandler) noexcept { + if (errorHandler) { + _errorHandler = errorHandler; + _addEmitterFlags(kFlagOwnErrorHandler); + } + else { + _errorHandler = nullptr; + _clearEmitterFlags(kFlagOwnErrorHandler); + if (_code) + _errorHandler = _code->errorHandler(); + } +} + +Error BaseEmitter::reportError(Error err, const char* message) { + ErrorHandler* eh = _errorHandler; + if (eh) { + if (!message) + message = DebugUtils::errorAsString(err); + eh->handleError(err, message, this); + } + return err; +} + +// ============================================================================ +// [asmjit::BaseEmitter - Labels] +// ============================================================================ + +Label BaseEmitter::labelByName(const char* name, size_t nameSize, uint32_t parentId) noexcept { + return Label(_code ? _code->labelIdByName(name, nameSize, parentId) : uint32_t(Globals::kInvalidId)); +} + +bool BaseEmitter::isLabelValid(uint32_t labelId) const noexcept { + return _code && labelId < _code->labelCount(); +} + +// ============================================================================ +// [asmjit::BaseEmitter - Emit (Low-Level)] +// ============================================================================ + +using EmitterUtils::noExt; + +Error BaseEmitter::_emitI(uint32_t instId) { + return _emit(instId, noExt[0], noExt[1], noExt[2], noExt); +} + +Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0) { + return _emit(instId, o0, noExt[1], noExt[2], noExt); +} + +Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1) { + return _emit(instId, o0, o1, noExt[2], noExt); +} + +Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2) { + return _emit(instId, o0, o1, o2, noExt); +} + +Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) { + Operand_ opExt[3] = { o3 }; + return _emit(instId, o0, o1, o2, opExt); +} + +Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4) { + Operand_ opExt[3] = { o3, o4 }; + return _emit(instId, o0, o1, o2, opExt); +} + +Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) { + Operand_ opExt[3] = { o3, o4, o5 }; + return _emit(instId, o0, o1, o2, opExt); +} + +Error BaseEmitter::_emitOpArray(uint32_t instId, const Operand_* operands, size_t opCount) { + const Operand_* op = operands; + + Operand_ opExt[3]; + + switch (opCount) { + case 0: + return _emit(instId, noExt[0], noExt[1], noExt[2], noExt); + + case 1: + return _emit(instId, op[0], noExt[1], noExt[2], noExt); + + case 2: + return _emit(instId, op[0], op[1], noExt[2], noExt); + + case 3: + return _emit(instId, op[0], op[1], op[2], noExt); + + case 4: + opExt[0] = op[3]; + opExt[1].reset(); + opExt[2].reset(); + return _emit(instId, op[0], op[1], op[2], opExt); + + case 5: + opExt[0] = op[3]; + opExt[1] = op[4]; + opExt[2].reset(); + return _emit(instId, op[0], op[1], op[2], opExt); + + case 6: + return _emit(instId, op[0], op[1], op[2], op + 3); + + default: + return DebugUtils::errored(kErrorInvalidArgument); + } +} + +// ============================================================================ +// [asmjit::BaseEmitter - Emit (High-Level)] +// ============================================================================ + +ASMJIT_FAVOR_SIZE Error BaseEmitter::emitProlog(const FuncFrame& frame) { + if (ASMJIT_UNLIKELY(!_code)) + return DebugUtils::errored(kErrorNotInitialized); + +#ifdef ASMJIT_BUILD_X86 + if (environment().isFamilyX86()) { + x86::EmitHelper emitHelper(this, frame.isAvxEnabled()); + return emitHelper.emitProlog(frame); + } +#endif + +#ifdef ASMJIT_BUILD_ARM + if (environment().isArchAArch64()) { + a64::EmitHelper emitHelper(this); + return emitHelper.emitProlog(frame); + } +#endif + + return DebugUtils::errored(kErrorInvalidArch); +} + +ASMJIT_FAVOR_SIZE Error BaseEmitter::emitEpilog(const FuncFrame& frame) { + if (ASMJIT_UNLIKELY(!_code)) + return DebugUtils::errored(kErrorNotInitialized); + +#ifdef ASMJIT_BUILD_X86 + if (environment().isFamilyX86()) { + x86::EmitHelper emitHelper(this, frame.isAvxEnabled()); + return emitHelper.emitEpilog(frame); + } +#endif + +#ifdef ASMJIT_BUILD_ARM + if (environment().isArchAArch64()) { + a64::EmitHelper emitHelper(this); + return emitHelper.emitEpilog(frame); + } +#endif + + return DebugUtils::errored(kErrorInvalidArch); +} + +ASMJIT_FAVOR_SIZE Error BaseEmitter::emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args) { + if (ASMJIT_UNLIKELY(!_code)) + return DebugUtils::errored(kErrorNotInitialized); + +#ifdef ASMJIT_BUILD_X86 + if (environment().isFamilyX86()) { + x86::EmitHelper emitHelper(this, frame.isAvxEnabled()); + return emitHelper.emitArgsAssignment(frame, args); + } +#endif + +#ifdef ASMJIT_BUILD_ARM + if (environment().isArchAArch64()) { + a64::EmitHelper emitHelper(this); + return emitHelper.emitArgsAssignment(frame, args); + } +#endif + + return DebugUtils::errored(kErrorInvalidArch); +} + +// ============================================================================ +// [asmjit::BaseEmitter - Comment] +// ============================================================================ + +Error BaseEmitter::commentf(const char* fmt, ...) { + if (!hasEmitterFlag(kFlagLogComments)) { + if (!hasEmitterFlag(kFlagAttached)) + return reportError(DebugUtils::errored(kErrorNotInitialized)); + return kErrorOk; + } + +#ifndef ASMJIT_NO_LOGGING + StringTmp<1024> sb; + + va_list ap; + va_start(ap, fmt); + Error err = sb.appendVFormat(fmt, ap); + va_end(ap); + + ASMJIT_PROPAGATE(err); + return comment(sb.data(), sb.size()); +#else + DebugUtils::unused(fmt); + return kErrorOk; +#endif +} + +Error BaseEmitter::commentv(const char* fmt, va_list ap) { + if (!hasEmitterFlag(kFlagLogComments)) { + if (!hasEmitterFlag(kFlagAttached)) + return reportError(DebugUtils::errored(kErrorNotInitialized)); + return kErrorOk; + } + +#ifndef ASMJIT_NO_LOGGING + StringTmp<1024> sb; + Error err = sb.appendVFormat(fmt, ap); + + ASMJIT_PROPAGATE(err); + return comment(sb.data(), sb.size()); +#else + DebugUtils::unused(fmt, ap); + return kErrorOk; +#endif +} + +// ============================================================================ +// [asmjit::BaseEmitter - Events] +// ============================================================================ + +Error BaseEmitter::onAttach(CodeHolder* code) noexcept { + _code = code; + _environment = code->environment(); + _addEmitterFlags(kFlagAttached); + + const ArchTraits& archTraits = ArchTraits::byArch(code->arch()); + uint32_t nativeRegType = Environment::is32Bit(code->arch()) ? BaseReg::kTypeGp32 : BaseReg::kTypeGp64; + _gpRegInfo.setSignature(archTraits._regInfo[nativeRegType].signature()); + + onSettingsUpdated(); + return kErrorOk; +} + +Error BaseEmitter::onDetach(CodeHolder* code) noexcept { + DebugUtils::unused(code); + + if (!hasOwnLogger()) + _logger = nullptr; + + if (!hasOwnErrorHandler()) + _errorHandler = nullptr; + + _clearEmitterFlags(~kEmitterPreservedFlags); + _forcedInstOptions = BaseInst::kOptionReserved; + _privateData = 0; + + _environment.reset(); + _gpRegInfo.reset(); + + _instOptions = 0; + _extraReg.reset(); + _inlineComment = nullptr; + + return kErrorOk; +} + +void BaseEmitter::onSettingsUpdated() noexcept { + // Only called when attached to CodeHolder by CodeHolder. + ASMJIT_ASSERT(_code != nullptr); + + if (!hasOwnLogger()) + _logger = _code->logger(); + + if (!hasOwnErrorHandler()) + _errorHandler = _code->errorHandler(); + + BaseEmitter_updateForcedOptions(this); +} + +ASMJIT_END_NAMESPACE diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emitter.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emitter.h new file mode 100644 index 0000000..fcb9bb5 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emitter.h @@ -0,0 +1,723 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_EMITTER_H_INCLUDED +#define ASMJIT_CORE_EMITTER_H_INCLUDED + +#include "../core/archtraits.h" +#include "../core/codeholder.h" +#include "../core/inst.h" +#include "../core/operand.h" +#include "../core/type.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_core +//! \{ + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +class ConstPool; +class FuncFrame; +class FuncArgsAssignment; + +// ============================================================================ +// [asmjit::BaseEmitter] +// ============================================================================ + +//! Provides a base foundation to emit code - specialized by `Assembler` and +//! `BaseBuilder`. +class ASMJIT_VIRTAPI BaseEmitter { +public: + ASMJIT_BASE_CLASS(BaseEmitter) + + //! See \ref EmitterType. + uint8_t _emitterType = 0; + //! See \ref BaseEmitter::EmitterFlags. + uint8_t _emitterFlags = 0; + //! Validation flags in case validation is used, see \ref InstAPI::ValidationFlags. + //! + //! \note Validation flags are specific to the emitter and they are setup at + //! construction time and then never changed. + uint8_t _validationFlags = 0; + //! Validation options, see \ref ValidationOptions. + uint8_t _validationOptions = 0; + + //! Encoding options, see \ref EncodingOptions. + uint32_t _encodingOptions = 0; + + //! Forced instruction options, combined with \ref _instOptions by \ref emit(). + uint32_t _forcedInstOptions = BaseInst::kOptionReserved; + //! Internal private data used freely by any emitter. + uint32_t _privateData = 0; + + //! CodeHolder the emitter is attached to. + CodeHolder* _code = nullptr; + //! Attached \ref Logger. + Logger* _logger = nullptr; + //! Attached \ref ErrorHandler. + ErrorHandler* _errorHandler = nullptr; + + //! Describes the target environment, matches \ref CodeHolder::environment(). + Environment _environment {}; + //! Native GP register signature and signature related information. + RegInfo _gpRegInfo {}; + + //! Next instruction options (affects the next instruction). + uint32_t _instOptions = 0; + //! Extra register (op-mask {k} on AVX-512) (affects the next instruction). + RegOnly _extraReg {}; + //! Inline comment of the next instruction (affects the next instruction). + const char* _inlineComment = nullptr; + + //! Emitter type. + enum EmitterType : uint32_t { + //! Unknown or uninitialized. + kTypeNone = 0, + //! Emitter inherits from \ref BaseAssembler. + kTypeAssembler = 1, + //! Emitter inherits from \ref BaseBuilder. + kTypeBuilder = 2, + //! Emitter inherits from \ref BaseCompiler. + kTypeCompiler = 3, + + //! Count of emitter types. + kTypeCount = 4 + }; + + //! Emitter flags. + enum EmitterFlags : uint32_t { + //! Emitter is attached to CodeHolder. + kFlagAttached = 0x01u, + //! The emitter must emit comments. + kFlagLogComments = 0x08u, + //! The emitter has its own \ref Logger (not propagated from \ref CodeHolder). + kFlagOwnLogger = 0x10u, + //! The emitter has its own \ref ErrorHandler (not propagated from \ref CodeHolder). + kFlagOwnErrorHandler = 0x20u, + //! The emitter was finalized. + kFlagFinalized = 0x40u, + //! The emitter was destroyed. + kFlagDestroyed = 0x80u + }; + + //! Encoding options. + enum EncodingOptions : uint32_t { + //! Emit instructions that are optimized for size, if possible. + //! + //! Default: false. + //! + //! X86 Specific + //! ------------ + //! + //! When this option is set it the assembler will try to fix instructions + //! if possible into operation equivalent instructions that take less bytes + //! by taking advantage of implicit zero extension. For example instruction + //! like `mov r64, imm` and `and r64, imm` can be translated to `mov r32, imm` + //! and `and r32, imm` when the immediate constant is lesser than `2^31`. + kEncodingOptionOptimizeForSize = 0x00000001u, + + //! Emit optimized code-alignment sequences. + //! + //! Default: false. + //! + //! X86 Specific + //! ------------ + //! + //! Default align sequence used by X86 architecture is one-byte (0x90) + //! opcode that is often shown by disassemblers as NOP. However there are + //! more optimized align sequences for 2-11 bytes that may execute faster + //! on certain CPUs. If this feature is enabled AsmJit will generate + //! specialized sequences for alignment between 2 to 11 bytes. + kEncodingOptionOptimizedAlign = 0x00000002u, + + //! Emit jump-prediction hints. + //! + //! Default: false. + //! + //! X86 Specific + //! ------------ + //! + //! Jump prediction is usually based on the direction of the jump. If the + //! jump is backward it is usually predicted as taken; and if the jump is + //! forward it is usually predicted as not-taken. The reason is that loops + //! generally use backward jumps and conditions usually use forward jumps. + //! However this behavior can be overridden by using instruction prefixes. + //! If this option is enabled these hints will be emitted. + //! + //! This feature is disabled by default, because the only processor that + //! used to take into consideration prediction hints was P4. Newer processors + //! implement heuristics for branch prediction and ignore static hints. This + //! means that this feature can be only used for annotation purposes. + kEncodingOptionPredictedJumps = 0x00000010u + }; + +#ifndef ASMJIT_NO_DEPRECATED + enum EmitterOptions : uint32_t { + kOptionOptimizedForSize = kEncodingOptionOptimizeForSize, + kOptionOptimizedAlign = kEncodingOptionOptimizedAlign, + kOptionPredictedJumps = kEncodingOptionPredictedJumps + }; +#endif + + //! Validation options are used to tell emitters to perform strict validation + //! of instructions passed to \ref emit(). + //! + //! \ref BaseAssembler implementation perform by default only basic checks + //! that are necessary to identify all variations of an instruction so the + //! correct encoding can be selected. This is fine for production-ready code + //! as the assembler doesn't have to perform checks that would slow it down. + //! However, sometimes these checks are beneficial especially when the project + //! that uses AsmJit is in a development phase, in which mistakes happen often. + //! To make the experience of using AsmJit seamless it offers validation + //! features that can be controlled by `ValidationOptions`. + enum ValidationOptions : uint32_t { + //! Perform strict validation in \ref BaseAssembler::emit() implementations. + //! + //! This flag ensures that each instruction is checked before it's encoded + //! into a binary representation. This flag is only relevant for \ref + //! BaseAssembler implementations, but can be set in any other emitter type, + //! in that case if that emitter needs to create an assembler on its own, + //! for the purpose of \ref finalize() it would propagate this flag to such + //! assembler so all instructions passed to it are explicitly validated. + //! + //! Default: false. + kValidationOptionAssembler = 0x00000001u, + + //! Perform strict validation in \ref BaseBuilder::emit() and \ref + //! BaseCompiler::emit() implementations. + //! + //! This flag ensures that each instruction is checked before an \ref + //! InstNode representing the instruction is created by Builder or Compiler. + //! + //! Default: false. + kValidationOptionIntermediate = 0x00000002u + }; + + //! \name Construction & Destruction + //! \{ + + ASMJIT_API explicit BaseEmitter(uint32_t emitterType) noexcept; + ASMJIT_API virtual ~BaseEmitter() noexcept; + + //! \} + + //! \name Cast + //! \{ + + template + inline T* as() noexcept { return reinterpret_cast(this); } + + template + inline const T* as() const noexcept { return reinterpret_cast(this); } + + //! \} + + //! \name Emitter Type & Flags + //! \{ + + //! Returns the type of this emitter, see `EmitterType`. + inline uint32_t emitterType() const noexcept { return _emitterType; } + //! Returns emitter flags , see `Flags`. + inline uint32_t emitterFlags() const noexcept { return _emitterFlags; } + + //! Tests whether the emitter inherits from `BaseAssembler`. + inline bool isAssembler() const noexcept { return _emitterType == kTypeAssembler; } + //! Tests whether the emitter inherits from `BaseBuilder`. + //! + //! \note Both Builder and Compiler emitters would return `true`. + inline bool isBuilder() const noexcept { return _emitterType >= kTypeBuilder; } + //! Tests whether the emitter inherits from `BaseCompiler`. + inline bool isCompiler() const noexcept { return _emitterType == kTypeCompiler; } + + //! Tests whether the emitter has the given `flag` enabled. + inline bool hasEmitterFlag(uint32_t flag) const noexcept { return (_emitterFlags & flag) != 0; } + //! Tests whether the emitter is finalized. + inline bool isFinalized() const noexcept { return hasEmitterFlag(kFlagFinalized); } + //! Tests whether the emitter is destroyed (only used during destruction). + inline bool isDestroyed() const noexcept { return hasEmitterFlag(kFlagDestroyed); } + + inline void _addEmitterFlags(uint32_t flags) noexcept { _emitterFlags = uint8_t(_emitterFlags | flags); } + inline void _clearEmitterFlags(uint32_t flags) noexcept { _emitterFlags = uint8_t(_emitterFlags & ~flags); } + + //! \} + + //! \name Target Information + //! \{ + + //! Returns the CodeHolder this emitter is attached to. + inline CodeHolder* code() const noexcept { return _code; } + + //! Returns the target environment, see \ref Environment. + //! + //! The returned \ref Environment reference matches \ref CodeHolder::environment(). + inline const Environment& environment() const noexcept { return _environment; } + + //! Tests whether the target architecture is 32-bit. + inline bool is32Bit() const noexcept { return environment().is32Bit(); } + //! Tests whether the target architecture is 64-bit. + inline bool is64Bit() const noexcept { return environment().is64Bit(); } + + //! Returns the target architecture type. + inline uint32_t arch() const noexcept { return environment().arch(); } + //! Returns the target architecture sub-type. + inline uint32_t subArch() const noexcept { return environment().subArch(); } + + //! Returns the target architecture's GP register size (4 or 8 bytes). + inline uint32_t registerSize() const noexcept { return environment().registerSize(); } + + //! \} + + //! \name Initialization & Finalization + //! \{ + + //! Tests whether the emitter is initialized (i.e. attached to \ref CodeHolder). + inline bool isInitialized() const noexcept { return _code != nullptr; } + + //! Finalizes this emitter. + //! + //! Materializes the content of the emitter by serializing it to the attached + //! \ref CodeHolder through an architecture specific \ref BaseAssembler. This + //! function won't do anything if the emitter inherits from \ref BaseAssembler + //! as assemblers emit directly to a \ref CodeBuffer held by \ref CodeHolder. + //! However, if this is an emitter that inherits from \ref BaseBuilder or \ref + //! BaseCompiler then these emitters need the materialization phase as they + //! store their content in a representation not visible to \ref CodeHolder. + ASMJIT_API virtual Error finalize(); + + //! \} + + //! \name Logging + //! \{ + + //! Tests whether the emitter has a logger. + inline bool hasLogger() const noexcept { return _logger != nullptr; } + + //! Tests whether the emitter has its own logger. + //! + //! Own logger means that it overrides the possible logger that may be used + //! by \ref CodeHolder this emitter is attached to. + inline bool hasOwnLogger() const noexcept { return hasEmitterFlag(kFlagOwnLogger); } + + //! Returns the logger this emitter uses. + //! + //! The returned logger is either the emitter's own logger or it's logger + //! used by \ref CodeHolder this emitter is attached to. + inline Logger* logger() const noexcept { return _logger; } + + //! Sets or resets the logger of the emitter. + //! + //! If the `logger` argument is non-null then the logger will be considered + //! emitter's own logger, see \ref hasOwnLogger() for more details. If the + //! given `logger` is null then the emitter will automatically use logger + //! that is attached to the \ref CodeHolder this emitter is attached to. + ASMJIT_API void setLogger(Logger* logger) noexcept; + + //! Resets the logger of this emitter. + //! + //! The emitter will bail to using a logger attached to \ref CodeHolder this + //! emitter is attached to, or no logger at all if \ref CodeHolder doesn't + //! have one. + inline void resetLogger() noexcept { return setLogger(nullptr); } + + //! \} + + //! \name Error Handling + //! \{ + + //! Tests whether the emitter has an error handler attached. + inline bool hasErrorHandler() const noexcept { return _errorHandler != nullptr; } + + //! Tests whether the emitter has its own error handler. + //! + //! Own error handler means that it overrides the possible error handler that + //! may be used by \ref CodeHolder this emitter is attached to. + inline bool hasOwnErrorHandler() const noexcept { return hasEmitterFlag(kFlagOwnErrorHandler); } + + //! Returns the error handler this emitter uses. + //! + //! The returned error handler is either the emitter's own error handler or + //! it's error handler used by \ref CodeHolder this emitter is attached to. + inline ErrorHandler* errorHandler() const noexcept { return _errorHandler; } + + //! Sets or resets the error handler of the emitter. + ASMJIT_API void setErrorHandler(ErrorHandler* errorHandler) noexcept; + + //! Resets the error handler. + inline void resetErrorHandler() noexcept { setErrorHandler(nullptr); } + + //! Handles the given error in the following way: + //! 1. If the emitter has \ref ErrorHandler attached, it calls its + //! \ref ErrorHandler::handleError() member function first, and + //! then returns the error. The `handleError()` function may throw. + //! 2. if the emitter doesn't have \ref ErrorHandler, the error is + //! simply returned. + ASMJIT_API Error reportError(Error err, const char* message = nullptr); + + //! \} + + //! \name Encoding Options + //! \{ + + //! Returns encoding options, see \ref EncodingOptions. + inline uint32_t encodingOptions() const noexcept { return _encodingOptions; } + //! Tests whether the encoding `option` is set. + inline bool hasEncodingOption(uint32_t option) const noexcept { return (_encodingOptions & option) != 0; } + + //! Enables the given encoding `options`, see \ref EncodingOptions. + inline void addEncodingOptions(uint32_t options) noexcept { _encodingOptions |= options; } + //! Disables the given encoding `options`, see \ref EncodingOptions. + inline void clearEncodingOptions(uint32_t options) noexcept { _encodingOptions &= ~options; } + + //! \} + + //! \name Validation Options + //! \{ + + //! Returns the emitter's validation options, see \ref ValidationOptions. + inline uint32_t validationOptions() const noexcept { + return _validationOptions; + } + + //! Tests whether the given `option` is present in validation options. + inline bool hasValidationOption(uint32_t option) const noexcept { + return (_validationOptions & option) != 0; + } + + //! Activates the given validation `options`, see \ref ValidationOptions. + //! + //! This function is used to activate explicit validation options that will + //! be then used by all emitter implementations. There are in general two + //! possibilities: + //! + //! - Architecture specific assembler is used. In this case a + //! \ref kValidationOptionAssembler can be used to turn on explicit + //! validation that will be used before an instruction is emitted. + //! This means that internally an extra step will be performed to + //! make sure that the instruction is correct. This is needed, because + //! by default assemblers prefer speed over strictness. + //! + //! This option should be used in debug builds as it's pretty expensive. + //! + //! - Architecture specific builder or compiler is used. In this case + //! the user can turn on \ref kValidationOptionIntermediate option + //! that adds explicit validation step before the Builder or Compiler + //! creates an \ref InstNode to represent an emitted instruction. Error + //! will be returned if the instruction is ill-formed. In addition, + //! also \ref kValidationOptionAssembler can be used, which would not be + //! consumed by Builder / Compiler directly, but it would be propagated + //! to an architecture specific \ref BaseAssembler implementation it + //! creates during \ref BaseEmitter::finalize(). + ASMJIT_API void addValidationOptions(uint32_t options) noexcept; + + //! Deactivates the given validation `options`. + //! + //! See \ref addValidationOptions() and \ref ValidationOptions for more details. + ASMJIT_API void clearValidationOptions(uint32_t options) noexcept; + + //! \} + + //! \name Instruction Options + //! \{ + + //! Returns forced instruction options. + //! + //! Forced instruction options are merged with next instruction options before + //! the instruction is encoded. These options have some bits reserved that are + //! used by error handling, logging, and instruction validation purposes. Other + //! options are globals that affect each instruction. + inline uint32_t forcedInstOptions() const noexcept { return _forcedInstOptions; } + + //! Returns options of the next instruction. + inline uint32_t instOptions() const noexcept { return _instOptions; } + //! Returns options of the next instruction. + inline void setInstOptions(uint32_t options) noexcept { _instOptions = options; } + //! Adds options of the next instruction. + inline void addInstOptions(uint32_t options) noexcept { _instOptions |= options; } + //! Resets options of the next instruction. + inline void resetInstOptions() noexcept { _instOptions = 0; } + + //! Tests whether the extra register operand is valid. + inline bool hasExtraReg() const noexcept { return _extraReg.isReg(); } + //! Returns an extra operand that will be used by the next instruction (architecture specific). + inline const RegOnly& extraReg() const noexcept { return _extraReg; } + //! Sets an extra operand that will be used by the next instruction (architecture specific). + inline void setExtraReg(const BaseReg& reg) noexcept { _extraReg.init(reg); } + //! Sets an extra operand that will be used by the next instruction (architecture specific). + inline void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); } + //! Resets an extra operand that will be used by the next instruction (architecture specific). + inline void resetExtraReg() noexcept { _extraReg.reset(); } + + //! Returns comment/annotation of the next instruction. + inline const char* inlineComment() const noexcept { return _inlineComment; } + //! Sets comment/annotation of the next instruction. + //! + //! \note This string is set back to null by `_emit()`, but until that it has + //! to remain valid as the Emitter is not required to make a copy of it (and + //! it would be slow to do that for each instruction). + inline void setInlineComment(const char* s) noexcept { _inlineComment = s; } + //! Resets the comment/annotation to nullptr. + inline void resetInlineComment() noexcept { _inlineComment = nullptr; } + + //! \} + + //! \name Sections + //! \{ + + virtual Error section(Section* section) = 0; + + //! \} + + //! \name Labels + //! \{ + + //! Creates a new label. + virtual Label newLabel() = 0; + //! Creates a new named label. + virtual Label newNamedLabel(const char* name, size_t nameSize = SIZE_MAX, uint32_t type = Label::kTypeGlobal, uint32_t parentId = Globals::kInvalidId) = 0; + + //! Creates a new external label. + inline Label newExternalLabel(const char* name, size_t nameSize = SIZE_MAX) { + return newNamedLabel(name, nameSize, Label::kTypeExternal); + } + + //! Returns `Label` by `name`. + //! + //! Returns invalid Label in case that the name is invalid or label was not found. + //! + //! \note This function doesn't trigger ErrorHandler in case the name is invalid + //! or no such label exist. You must always check the validity of the `Label` returned. + ASMJIT_API Label labelByName(const char* name, size_t nameSize = SIZE_MAX, uint32_t parentId = Globals::kInvalidId) noexcept; + + //! Binds the `label` to the current position of the current section. + //! + //! \note Attempt to bind the same label multiple times will return an error. + virtual Error bind(const Label& label) = 0; + + //! Tests whether the label `id` is valid (i.e. registered). + ASMJIT_API bool isLabelValid(uint32_t labelId) const noexcept; + //! Tests whether the `label` is valid (i.e. registered). + inline bool isLabelValid(const Label& label) const noexcept { return isLabelValid(label.id()); } + + //! \} + + //! \name Emit + //! \{ + + // NOTE: These `emit()` helpers are designed to address a code-bloat generated + // by C++ compilers to call a function having many arguments. Each parameter to + // `_emit()` requires some code to pass it, which means that if we default to + // 5 arguments in `_emit()` and instId the C++ compiler would have to generate + // a virtual function call having 5 parameters and additional `this` argument, + // which is quite a lot. Since by default most instructions have 2 to 3 operands + // it's better to introduce helpers that pass from 0 to 6 operands that help to + // reduce the size of emit(...) function call. + + //! Emits an instruction (internal). + ASMJIT_API Error _emitI(uint32_t instId); + //! \overload + ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0); + //! \overload + ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1); + //! \overload + ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2); + //! \overload + ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3); + //! \overload + ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4); + //! \overload + ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5); + + //! Emits an instruction `instId` with the given `operands`. + template + ASMJIT_INLINE Error emit(uint32_t instId, Args&&... operands) { + return _emitI(instId, Support::ForwardOp::forward(operands)...); + } + + inline Error emitOpArray(uint32_t instId, const Operand_* operands, size_t opCount) { + return _emitOpArray(instId, operands, opCount); + } + + inline Error emitInst(const BaseInst& inst, const Operand_* operands, size_t opCount) { + setInstOptions(inst.options()); + setExtraReg(inst.extraReg()); + return _emitOpArray(inst.id(), operands, opCount); + } + + //! \cond INTERNAL + //! Emits an instruction - all 6 operands must be defined. + virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* oExt) = 0; + //! Emits instruction having operands stored in array. + ASMJIT_API virtual Error _emitOpArray(uint32_t instId, const Operand_* operands, size_t opCount); + //! \endcond + + //! \} + + //! \name Emit Utilities + //! \{ + + ASMJIT_API Error emitProlog(const FuncFrame& frame); + ASMJIT_API Error emitEpilog(const FuncFrame& frame); + ASMJIT_API Error emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args); + + //! \} + + //! \name Align + //! \{ + + //! Aligns the current CodeBuffer position to the `alignment` specified. + //! + //! The sequence that is used to fill the gap between the aligned location + //! and the current location depends on the align `mode`, see \ref AlignMode. + virtual Error align(uint32_t alignMode, uint32_t alignment) = 0; + + //! \} + + //! \name Embed + //! \{ + + //! Embeds raw data into the \ref CodeBuffer. + virtual Error embed(const void* data, size_t dataSize) = 0; + + //! Embeds a typed data array. + //! + //! This is the most flexible function for embedding data as it allows to: + //! - Assign a `typeId` to the data, so the emitter knows the type of + //! items stored in `data`. Binary data should use \ref Type::kIdU8. + //! - Repeat the given data `repeatCount` times, so the data can be used + //! as a fill pattern for example, or as a pattern used by SIMD instructions. + virtual Error embedDataArray(uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount = 1) = 0; + + //! Embeds int8_t `value` repeated by `repeatCount`. + inline Error embedInt8(int8_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdI8, &value, 1, repeatCount); } + //! Embeds uint8_t `value` repeated by `repeatCount`. + inline Error embedUInt8(uint8_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdU8, &value, 1, repeatCount); } + //! Embeds int16_t `value` repeated by `repeatCount`. + inline Error embedInt16(int16_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdI16, &value, 1, repeatCount); } + //! Embeds uint16_t `value` repeated by `repeatCount`. + inline Error embedUInt16(uint16_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdU16, &value, 1, repeatCount); } + //! Embeds int32_t `value` repeated by `repeatCount`. + inline Error embedInt32(int32_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdI32, &value, 1, repeatCount); } + //! Embeds uint32_t `value` repeated by `repeatCount`. + inline Error embedUInt32(uint32_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdU32, &value, 1, repeatCount); } + //! Embeds int64_t `value` repeated by `repeatCount`. + inline Error embedInt64(int64_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdI64, &value, 1, repeatCount); } + //! Embeds uint64_t `value` repeated by `repeatCount`. + inline Error embedUInt64(uint64_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdU64, &value, 1, repeatCount); } + //! Embeds a floating point `value` repeated by `repeatCount`. + inline Error embedFloat(float value, size_t repeatCount = 1) { return embedDataArray(Type::kIdF32, &value, 1, repeatCount); } + //! Embeds a floating point `value` repeated by `repeatCount`. + inline Error embedDouble(double value, size_t repeatCount = 1) { return embedDataArray(Type::IdOfT::kTypeId, &value, 1, repeatCount); } + + //! Embeds a constant pool at the current offset by performing the following: + //! 1. Aligns by using kAlignData to the minimum `pool` alignment. + //! 2. Binds the ConstPool label so it's bound to an aligned location. + //! 3. Emits ConstPool content. + virtual Error embedConstPool(const Label& label, const ConstPool& pool) = 0; + + //! Embeds an absolute `label` address as data. + //! + //! The `dataSize` is an optional argument that can be used to specify the + //! size of the address data. If it's zero (default) the address size is + //! deduced from the target architecture (either 4 or 8 bytes). + virtual Error embedLabel(const Label& label, size_t dataSize = 0) = 0; + + //! Embeds a delta (distance) between the `label` and `base` calculating it + //! as `label - base`. This function was designed to make it easier to embed + //! lookup tables where each index is a relative distance of two labels. + virtual Error embedLabelDelta(const Label& label, const Label& base, size_t dataSize = 0) = 0; + + //! \} + + //! \name Comment + //! \{ + + //! Emits a comment stored in `data` with an optional `size` parameter. + virtual Error comment(const char* data, size_t size = SIZE_MAX) = 0; + + //! Emits a formatted comment specified by `fmt` and variable number of arguments. + ASMJIT_API Error commentf(const char* fmt, ...); + //! Emits a formatted comment specified by `fmt` and `ap`. + ASMJIT_API Error commentv(const char* fmt, va_list ap); + + //! \} + + //! \name Events + //! \{ + + //! Called after the emitter was attached to `CodeHolder`. + virtual Error onAttach(CodeHolder* code) noexcept = 0; + //! Called after the emitter was detached from `CodeHolder`. + virtual Error onDetach(CodeHolder* code) noexcept = 0; + + //! Called when \ref CodeHolder has updated an important setting, which + //! involves the following: + //! + //! - \ref Logger has been changed (\ref CodeHolder::setLogger() has been + //! called). + //! - \ref ErrorHandler has been changed (\ref CodeHolder::setErrorHandler() + //! has been called). + //! + //! This function ensures that the settings are properly propagated from + //! \ref CodeHolder to the emitter. + //! + //! \note This function is virtual and can be overridden, however, if you + //! do so, always call \ref BaseEmitter::onSettingsUpdated() within your + //! own implementation to ensure that the emitter is in a consisten state. + ASMJIT_API virtual void onSettingsUpdated() noexcept; + + //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use environment() instead") + inline CodeInfo codeInfo() const noexcept { + return CodeInfo(_environment, _code ? _code->baseAddress() : Globals::kNoBaseAddress); + } + + ASMJIT_DEPRECATED("Use arch() instead") + inline uint32_t archId() const noexcept { return arch(); } + + ASMJIT_DEPRECATED("Use registerSize() instead") + inline uint32_t gpSize() const noexcept { return registerSize(); } + + ASMJIT_DEPRECATED("Use encodingOptions() instead") + inline uint32_t emitterOptions() const noexcept { return encodingOptions(); } + + ASMJIT_DEPRECATED("Use addEncodingOptions() instead") + inline void addEmitterOptions(uint32_t options) noexcept { addEncodingOptions(options); } + + ASMJIT_DEPRECATED("Use clearEncodingOptions() instead") + inline void clearEmitterOptions(uint32_t options) noexcept { clearEncodingOptions(options); } + + ASMJIT_DEPRECATED("Use forcedInstOptions() instead") + inline uint32_t globalInstOptions() const noexcept { return forcedInstOptions(); } +#endif // !ASMJIT_NO_DEPRECATED +}; + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_EMITTER_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emitterutils.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emitterutils.cpp new file mode 100644 index 0000000..1115934 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emitterutils.cpp @@ -0,0 +1,150 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/assembler.h" +#include "../core/emitterutils_p.h" +#include "../core/formatter.h" +#include "../core/logger.h" +#include "../core/support.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::EmitterUtils] +// ============================================================================ + +namespace EmitterUtils { + +#ifndef ASMJIT_NO_LOGGING + +Error formatLine(String& sb, const uint8_t* binData, size_t binSize, size_t dispSize, size_t immSize, const char* comment) noexcept { + size_t currentSize = sb.size(); + size_t commentSize = comment ? Support::strLen(comment, Globals::kMaxCommentSize) : 0; + + ASMJIT_ASSERT(binSize >= dispSize); + const size_t kNoBinSize = SIZE_MAX; + + if ((binSize != 0 && binSize != kNoBinSize) || commentSize) { + size_t align = kMaxInstLineSize; + char sep = ';'; + + for (size_t i = (binSize == kNoBinSize); i < 2; i++) { + size_t begin = sb.size(); + ASMJIT_PROPAGATE(sb.padEnd(align)); + + if (sep) { + ASMJIT_PROPAGATE(sb.append(sep)); + ASMJIT_PROPAGATE(sb.append(' ')); + } + + // Append binary data or comment. + if (i == 0) { + ASMJIT_PROPAGATE(sb.appendHex(binData, binSize - dispSize - immSize)); + ASMJIT_PROPAGATE(sb.appendChars('.', dispSize * 2)); + ASMJIT_PROPAGATE(sb.appendHex(binData + binSize - immSize, immSize)); + if (commentSize == 0) break; + } + else { + ASMJIT_PROPAGATE(sb.append(comment, commentSize)); + } + + currentSize += sb.size() - begin; + align += kMaxBinarySize; + sep = '|'; + } + } + + return sb.append('\n'); +} + +void logLabelBound(BaseAssembler* self, const Label& label) noexcept { + Logger* logger = self->logger(); + + StringTmp<512> sb; + size_t binSize = logger->hasFlag(FormatOptions::kFlagMachineCode) ? size_t(0) : SIZE_MAX; + + sb.appendChars(' ', logger->indentation(FormatOptions::kIndentationLabel)); + Formatter::formatLabel(sb, logger->flags(), self, label.id()); + sb.append(':'); + EmitterUtils::formatLine(sb, nullptr, binSize, 0, 0, self->_inlineComment); + logger->log(sb.data(), sb.size()); +} + +void logInstructionEmitted( + BaseAssembler* self, + uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt, + uint32_t relSize, uint32_t immSize, uint8_t* afterCursor) { + + Logger* logger = self->logger(); + ASMJIT_ASSERT(logger != nullptr); + + StringTmp<256> sb; + uint32_t flags = logger->flags(); + + uint8_t* beforeCursor = self->bufferPtr(); + intptr_t emittedSize = (intptr_t)(afterCursor - beforeCursor); + + Operand_ opArray[Globals::kMaxOpCount]; + EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt); + + sb.appendChars(' ', logger->indentation(FormatOptions::kIndentationCode)); + Formatter::formatInstruction(sb, flags, self, self->arch(), BaseInst(instId, options, self->extraReg()), opArray, Globals::kMaxOpCount); + + if ((flags & FormatOptions::kFlagMachineCode) != 0) + EmitterUtils::formatLine(sb, self->bufferPtr(), size_t(emittedSize), relSize, immSize, self->inlineComment()); + else + EmitterUtils::formatLine(sb, nullptr, SIZE_MAX, 0, 0, self->inlineComment()); + logger->log(sb); +} + +Error logInstructionFailed( + BaseAssembler* self, + Error err, + uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) { + + StringTmp<256> sb; + sb.append(DebugUtils::errorAsString(err)); + sb.append(": "); + + Operand_ opArray[Globals::kMaxOpCount]; + EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt); + + Formatter::formatInstruction(sb, 0, self, self->arch(), BaseInst(instId, options, self->extraReg()), opArray, Globals::kMaxOpCount); + + if (self->inlineComment()) { + sb.append(" ; "); + sb.append(self->inlineComment()); + } + + self->resetInstOptions(); + self->resetExtraReg(); + self->resetInlineComment(); + return self->reportError(err, sb.data()); +} + +#endif + +} // {EmitterUtils} + +ASMJIT_END_NAMESPACE diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emitterutils_p.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emitterutils_p.h new file mode 100644 index 0000000..7e222d3 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emitterutils_p.h @@ -0,0 +1,109 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_EMITTERUTILS_P_H_INCLUDED +#define ASMJIT_CORE_EMITTERUTILS_P_H_INCLUDED + +#include "../core/emitter.h" +#include "../core/operand.h" + +ASMJIT_BEGIN_NAMESPACE + +class BaseAssembler; + +//! \cond INTERNAL +//! \addtogroup asmjit_core +//! \{ + +// ============================================================================ +// [asmjit::EmitterUtils] +// ============================================================================ + +namespace EmitterUtils { + +static const Operand_ noExt[3] {}; + +enum kOpIndex { + kOp3 = 0, + kOp4 = 1, + kOp5 = 2 +}; + +static ASMJIT_INLINE uint32_t opCountFromEmitArgs(const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) noexcept { + uint32_t opCount = 0; + + if (opExt[kOp3].isNone()) { + if (!o0.isNone()) opCount = 1; + if (!o1.isNone()) opCount = 2; + if (!o2.isNone()) opCount = 3; + } + else { + opCount = 4; + if (!opExt[kOp4].isNone()) { + opCount = 5 + uint32_t(!opExt[kOp5].isNone()); + } + } + + return opCount; +} + +static ASMJIT_INLINE void opArrayFromEmitArgs(Operand_ dst[Globals::kMaxOpCount], const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) noexcept { + dst[0].copyFrom(o0); + dst[1].copyFrom(o1); + dst[2].copyFrom(o2); + dst[3].copyFrom(opExt[kOp3]); + dst[4].copyFrom(opExt[kOp4]); + dst[5].copyFrom(opExt[kOp5]); +} + +#ifndef ASMJIT_NO_LOGGING +enum : uint32_t { + // Has to be big to be able to hold all metadata compiler can assign to a + // single instruction. + kMaxInstLineSize = 44, + kMaxBinarySize = 26 +}; + +Error formatLine(String& sb, const uint8_t* binData, size_t binSize, size_t dispSize, size_t immSize, const char* comment) noexcept; + +void logLabelBound(BaseAssembler* self, const Label& label) noexcept; + +void logInstructionEmitted( + BaseAssembler* self, + uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt, + uint32_t relSize, uint32_t immSize, uint8_t* afterCursor); + +Error logInstructionFailed( + BaseAssembler* self, + Error err, uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt); +#endif + +} + +//! \} +//! \endcond + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_EMITTERUTILS_P_H_INCLUDED + diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/environment.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/environment.cpp new file mode 100644 index 0000000..3be2b15 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/environment.cpp @@ -0,0 +1,64 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/environment.h" + +ASMJIT_BEGIN_NAMESPACE + +// X86 Target +// ---------- +// +// - 32-bit - Linux, OSX, BSD, and apparently also Haiku guarantee 16-byte +// stack alignment. Other operating systems are assumed to have +// 4-byte alignment by default for safety reasons. +// - 64-bit - stack must be aligned to 16 bytes. +// +// ARM Target +// ---------- +// +// - 32-bit - Stack must be aligned to 8 bytes. +// - 64-bit - Stack must be aligned to 16 bytes (hardware requirement). +uint32_t Environment::stackAlignment() const noexcept { + if (is64Bit()) { + // Assume 16-byte alignment on any 64-bit target. + return 16; + } + else { + // The following platforms use 16-byte alignment in 32-bit mode. + if (isPlatformLinux() || + isPlatformBSD() || + isPlatformApple() || + isPlatformHaiku()) { + return 16u; + } + + if (isFamilyARM()) + return 8; + + // Bail to 4-byte alignment if we don't know. + return 4; + } +} + +ASMJIT_END_NAMESPACE diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/environment.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/environment.h new file mode 100644 index 0000000..79e6f7c --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/environment.h @@ -0,0 +1,612 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_ENVIRONMENT_H_INCLUDED +#define ASMJIT_CORE_ENVIRONMENT_H_INCLUDED + +#include "../core/globals.h" + +#if defined(__APPLE__) + #include +#endif + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_core +//! \{ + +// ============================================================================ +// [asmjit::Environment] +// ============================================================================ + +//! Represents an environment, which is usually related to a \ref Target. +//! +//! Environment has usually an 'arch-subarch-vendor-os-abi' format, which is +//! sometimes called "Triple" (historically it used to be 3 only parts) or +//! "Tuple", which is a convention used by Debian Linux. +//! +//! AsmJit doesn't support all possible combinations or architectures and ABIs, +//! however, it models the environment similarly to other compilers for future +//! extensibility. +class Environment { +public: + //! Architecture type, see \ref Arch. + uint8_t _arch; + //! Sub-architecture type, see \ref SubArch. + uint8_t _subArch; + //! Vendor type, see \ref Vendor. + uint8_t _vendor; + //! Platform type, see \ref Platform. + uint8_t _platform; + //! ABI type, see \ref Abi. + uint8_t _abi; + //! Object format, see \ref Format. + uint8_t _format; + //! Reserved for future use, must be zero. + uint16_t _reserved; + + //! Architecture. + enum Arch : uint32_t { + //! Unknown or uninitialized architecture. + kArchUnknown = 0, + + //! Mask used by 32-bit architectures (odd are 32-bit, even are 64-bit). + kArch32BitMask = 0x01, + //! Mask used by big-endian architectures. + kArchBigEndianMask = 0x80u, + + //! 32-bit X86 architecture. + kArchX86 = 1, + //! 64-bit X86 architecture also known as X86_64 and AMD64. + kArchX64 = 2, + + //! 32-bit RISC-V architecture. + kArchRISCV32 = 3, + //! 64-bit RISC-V architecture. + kArchRISCV64 = 4, + + //! 32-bit ARM architecture (little endian). + kArchARM = 5, + //! 32-bit ARM architecture (big endian). + kArchARM_BE = kArchARM | kArchBigEndianMask, + //! 64-bit ARM architecture in (little endian). + kArchAArch64 = 6, + //! 64-bit ARM architecture in (big endian). + kArchAArch64_BE = kArchAArch64 | kArchBigEndianMask, + //! 32-bit ARM in Thumb mode (little endian). + kArchThumb = 7, + //! 32-bit ARM in Thumb mode (big endian). + kArchThumb_BE = kArchThumb | kArchBigEndianMask, + + // 8 is not used, even numbers are 64-bit architectures. + + //! 32-bit MIPS architecture in (little endian). + kArchMIPS32_LE = 9, + //! 32-bit MIPS architecture in (big endian). + kArchMIPS32_BE = kArchMIPS32_LE | kArchBigEndianMask, + //! 64-bit MIPS architecture in (little endian). + kArchMIPS64_LE = 10, + //! 64-bit MIPS architecture in (big endian). + kArchMIPS64_BE = kArchMIPS64_LE | kArchBigEndianMask, + + //! Count of architectures. + kArchCount = 11 + }; + + //! Sub-architecture. + enum SubArch : uint32_t { + //! Unknown or uninitialized architecture sub-type. + kSubArchUnknown = 0, + + //! Count of sub-architectures. + kSubArchCount + }; + + //! Vendor. + //! + //! \note AsmJit doesn't use vendor information at the moment. It's provided + //! for future use, if required. + enum Vendor : uint32_t { + //! Unknown or uninitialized vendor. + kVendorUnknown = 0, + + //! Count of vendor identifiers. + kVendorCount + }; + + //! Platform / OS. + enum Platform : uint32_t { + //! Unknown or uninitialized platform. + kPlatformUnknown = 0, + + //! Windows OS. + kPlatformWindows, + + //! Other platform, most likely POSIX based. + kPlatformOther, + + //! Linux OS. + kPlatformLinux, + //! GNU/Hurd OS. + kPlatformHurd, + + //! FreeBSD OS. + kPlatformFreeBSD, + //! OpenBSD OS. + kPlatformOpenBSD, + //! NetBSD OS. + kPlatformNetBSD, + //! DragonFly BSD OS. + kPlatformDragonFlyBSD, + + //! Haiku OS. + kPlatformHaiku, + + //! Apple OSX. + kPlatformOSX, + //! Apple iOS. + kPlatformIOS, + //! Apple TVOS. + kPlatformTVOS, + //! Apple WatchOS. + kPlatformWatchOS, + + //! Emscripten platform. + kPlatformEmscripten, + + //! Count of platform identifiers. + kPlatformCount + }; + + //! ABI. + enum Abi : uint32_t { + //! Unknown or uninitialied environment. + kAbiUnknown = 0, + //! Microsoft ABI. + kAbiMSVC, + //! GNU ABI. + kAbiGNU, + //! Android Environment / ABI. + kAbiAndroid, + //! Cygwin ABI. + kAbiCygwin, + + //! Count of known ABI types. + kAbiCount + }; + + //! Object format. + //! + //! \note AsmJit doesn't really use anything except \ref kFormatUnknown and + //! \ref kFormatJIT at the moment. Object file formats are provided for + //! future extensibility and a possibility to generate object files at some + //! point. + enum Format : uint32_t { + //! Unknown or uninitialized object format. + kFormatUnknown = 0, + + //! JIT code generation object, most likely \ref JitRuntime or a custom + //! \ref Target implementation. + kFormatJIT, + + //! Executable and linkable format (ELF). + kFormatELF, + //! Common object file format. + kFormatCOFF, + //! Extended COFF object format. + kFormatXCOFF, + //! Mach object file format. + kFormatMachO, + + //! Count of object format types. + kFormatCount + }; + + //! \name Environment Detection + //! \{ + +#ifdef _DOXYGEN + //! Architecture detected at compile-time (architecture of the host). + static constexpr Arch kArchHost = DETECTED_AT_COMPILE_TIME; + //! Sub-architecture detected at compile-time (sub-architecture of the host). + static constexpr SubArch kSubArchHost = DETECTED_AT_COMPILE_TIME; + //! Vendor detected at compile-time (vendor of the host). + static constexpr Vendor kVendorHost = DETECTED_AT_COMPILE_TIME; + //! Platform detected at compile-time (platform of the host). + static constexpr Platform kPlatformHost = DETECTED_AT_COMPILE_TIME; + //! ABI detected at compile-time (ABI of the host). + static constexpr Abi kAbiHost = DETECTED_AT_COMPILE_TIME; +#else + static constexpr Arch kArchHost = + ASMJIT_ARCH_X86 == 32 ? kArchX86 : + ASMJIT_ARCH_X86 == 64 ? kArchX64 : + + ASMJIT_ARCH_ARM == 32 && ASMJIT_ARCH_LE ? kArchARM : + ASMJIT_ARCH_ARM == 32 && ASMJIT_ARCH_BE ? kArchARM_BE : + ASMJIT_ARCH_ARM == 64 && ASMJIT_ARCH_LE ? kArchAArch64 : + ASMJIT_ARCH_ARM == 64 && ASMJIT_ARCH_BE ? kArchAArch64_BE : + + ASMJIT_ARCH_MIPS == 32 && ASMJIT_ARCH_LE ? kArchMIPS32_LE : + ASMJIT_ARCH_MIPS == 32 && ASMJIT_ARCH_BE ? kArchMIPS32_BE : + ASMJIT_ARCH_MIPS == 64 && ASMJIT_ARCH_LE ? kArchMIPS64_LE : + ASMJIT_ARCH_MIPS == 64 && ASMJIT_ARCH_BE ? kArchMIPS64_BE : + + kArchUnknown; + + static constexpr SubArch kSubArchHost = + kSubArchUnknown; + + static constexpr Vendor kVendorHost = + kVendorUnknown; + + static constexpr Platform kPlatformHost = +#if defined(__EMSCRIPTEN__) + kPlatformEmscripten +#elif defined(_WIN32) + kPlatformWindows +#elif defined(__linux__) + kPlatformLinux +#elif defined(__gnu_hurd__) + kPlatformHurd +#elif defined(__FreeBSD__) + kPlatformFreeBSD +#elif defined(__OpenBSD__) + kPlatformOpenBSD +#elif defined(__NetBSD__) + kPlatformNetBSD +#elif defined(__DragonFly__) + kPlatformDragonFlyBSD +#elif defined(__HAIKU__) + kPlatformHaiku +#elif defined(__APPLE__) && TARGET_OS_OSX + kPlatformOSX +#elif defined(__APPLE__) && TARGET_OS_TV + kPlatformTVOS +#elif defined(__APPLE__) && TARGET_OS_WATCH + kPlatformWatchOS +#elif defined(__APPLE__) && TARGET_OS_IPHONE + kPlatformIOS +#else + kPlatformOther +#endif + ; + + static constexpr Abi kAbiHost = +#if defined(_MSC_VER) + kAbiMSVC +#elif defined(__CYGWIN__) + kAbiCygwin +#elif defined(__MINGW32__) || defined(__GLIBC__) + kAbiGNU +#elif defined(__ANDROID__) + kAbiAndroid +#else + kAbiUnknown +#endif + ; + +#endif + + //! \} + + //! \name Construction / Destruction + //! \{ + + inline Environment() noexcept : + _arch(uint8_t(kArchUnknown)), + _subArch(uint8_t(kSubArchUnknown)), + _vendor(uint8_t(kVendorUnknown)), + _platform(uint8_t(kPlatformUnknown)), + _abi(uint8_t(kAbiUnknown)), + _format(uint8_t(kFormatUnknown)), + _reserved(0) {} + + inline Environment(const Environment& other) noexcept = default; + + inline explicit Environment(uint32_t arch, + uint32_t subArch = kSubArchUnknown, + uint32_t vendor = kVendorUnknown, + uint32_t platform = kPlatformUnknown, + uint32_t abi = kAbiUnknown, + uint32_t format = kFormatUnknown) noexcept { + init(arch, subArch, vendor, platform, abi, format); + } + + //! \} + + //! \name Overloaded Operators + //! \{ + + inline Environment& operator=(const Environment& other) noexcept = default; + + inline bool operator==(const Environment& other) const noexcept { return equals(other); } + inline bool operator!=(const Environment& other) const noexcept { return !equals(other); } + + //! \} + + //! \name Accessors + //! \{ + + //! Tests whether the environment is not set up. + //! + //! Returns true if all members are zero, and thus unknown. + inline bool empty() const noexcept { + // Unfortunately compilers won't optimize fields are checked one by one... + return _packed() == 0; + } + + //! Tests whether the environment is intialized, which means it must have + //! a valid architecture. + inline bool isInitialized() const noexcept { + return _arch != kArchUnknown; + } + + inline uint64_t _packed() const noexcept { + uint64_t x; + memcpy(&x, this, 8); + return x; + } + + //! Resets all members of the environment to zero / unknown. + inline void reset() noexcept { + _arch = uint8_t(kArchUnknown); + _subArch = uint8_t(kSubArchUnknown); + _vendor = uint8_t(kVendorUnknown); + _platform = uint8_t(kPlatformUnknown); + _abi = uint8_t(kAbiUnknown); + _format = uint8_t(kFormatUnknown); + _reserved = 0; + } + + inline bool equals(const Environment& other) const noexcept { + return _packed() == other._packed(); + } + + //! Returns the architecture, see \ref Arch. + inline uint32_t arch() const noexcept { return _arch; } + //! Returns the sub-architecture, see \ref SubArch. + inline uint32_t subArch() const noexcept { return _subArch; } + //! Returns vendor, see \ref Vendor. + inline uint32_t vendor() const noexcept { return _vendor; } + //! Returns target's platform or operating system, see \ref Platform. + inline uint32_t platform() const noexcept { return _platform; } + //! Returns target's ABI, see \ref Abi. + inline uint32_t abi() const noexcept { return _abi; } + //! Returns target's object format, see \ref Format. + inline uint32_t format() const noexcept { return _format; } + + inline void init(uint32_t arch, + uint32_t subArch = kSubArchUnknown, + uint32_t vendor = kVendorUnknown, + uint32_t platform = kPlatformUnknown, + uint32_t abi = kAbiUnknown, + uint32_t format = kFormatUnknown) noexcept { + _arch = uint8_t(arch); + _subArch = uint8_t(subArch); + _vendor = uint8_t(vendor); + _platform = uint8_t(platform); + _abi = uint8_t(abi); + _format = uint8_t(format); + _reserved = 0; + } + + inline bool isArchX86() const noexcept { return _arch == kArchX86; } + inline bool isArchX64() const noexcept { return _arch == kArchX64; } + inline bool isArchRISCV32() const noexcept { return _arch == kArchRISCV32; } + inline bool isArchRISCV64() const noexcept { return _arch == kArchRISCV64; } + inline bool isArchARM() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchARM; } + inline bool isArchThumb() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchThumb; } + inline bool isArchAArch64() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchAArch64; } + inline bool isArchMIPS32() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchMIPS32_LE; } + inline bool isArchMIPS64() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchMIPS64_LE; } + + //! Tests whether the architecture is 32-bit. + inline bool is32Bit() const noexcept { return is32Bit(_arch); } + //! Tests whether the architecture is 64-bit. + inline bool is64Bit() const noexcept { return is64Bit(_arch); } + + //! Tests whether the architecture is little endian. + inline bool isLittleEndian() const noexcept { return isLittleEndian(_arch); } + //! Tests whether the architecture is big endian. + inline bool isBigEndian() const noexcept { return isBigEndian(_arch); } + + //! Tests whether this architecture is of X86 family. + inline bool isFamilyX86() const noexcept { return isFamilyX86(_arch); } + //! Tests whether this architecture family is RISC-V (both 32-bit and 64-bit). + inline bool isFamilyRISCV() const noexcept { return isFamilyRISCV(_arch); } + //! Tests whether this architecture family is ARM, Thumb, or AArch64. + inline bool isFamilyARM() const noexcept { return isFamilyARM(_arch); } + //! Tests whether this architecture family is MISP or MIPS64. + inline bool isFamilyMIPS() const noexcept { return isFamilyMIPS(_arch); } + + //! Tests whether the environment platform is Windows. + inline bool isPlatformWindows() const noexcept { return _platform == kPlatformWindows; } + + //! Tests whether the environment platform is Linux. + inline bool isPlatformLinux() const noexcept { return _platform == kPlatformLinux; } + + //! Tests whether the environment platform is Hurd. + inline bool isPlatformHurd() const noexcept { return _platform == kPlatformHurd; } + + //! Tests whether the environment platform is Haiku. + inline bool isPlatformHaiku() const noexcept { return _platform == kPlatformHaiku; } + + //! Tests whether the environment platform is any BSD. + inline bool isPlatformBSD() const noexcept { + return _platform == kPlatformFreeBSD || + _platform == kPlatformOpenBSD || + _platform == kPlatformNetBSD || + _platform == kPlatformDragonFlyBSD; + } + + //! Tests whether the environment platform is any Apple platform (OSX, iOS, TVOS, WatchOS). + inline bool isPlatformApple() const noexcept { + return _platform == kPlatformOSX || + _platform == kPlatformIOS || + _platform == kPlatformTVOS || + _platform == kPlatformWatchOS; + } + + //! Tests whether the ABI is MSVC. + inline bool isAbiMSVC() const noexcept { return _abi == kAbiMSVC; } + //! Tests whether the ABI is GNU. + inline bool isAbiGNU() const noexcept { return _abi == kAbiGNU; } + + //! Returns a calculated stack alignment for this environment. + ASMJIT_API uint32_t stackAlignment() const noexcept; + + //! Returns a native register size of this architecture. + uint32_t registerSize() const noexcept { return registerSizeFromArch(_arch); } + + //! Sets the architecture to `arch`. + inline void setArch(uint32_t arch) noexcept { _arch = uint8_t(arch); } + //! Sets the sub-architecture to `subArch`. + inline void setSubArch(uint32_t subArch) noexcept { _subArch = uint8_t(subArch); } + //! Sets the vendor to `vendor`. + inline void setVendor(uint32_t vendor) noexcept { _vendor = uint8_t(vendor); } + //! Sets the platform to `platform`. + inline void setPlatform(uint32_t platform) noexcept { _platform = uint8_t(platform); } + //! Sets the ABI to `abi`. + inline void setAbi(uint32_t abi) noexcept { _abi = uint8_t(abi); } + //! Sets the object format to `format`. + inline void setFormat(uint32_t format) noexcept { _format = uint8_t(format); } + + //! \} + + //! \name Static Utilities + //! \{ + + static inline bool isValidArch(uint32_t arch) noexcept { + return (arch & ~kArchBigEndianMask) != 0 && + (arch & ~kArchBigEndianMask) < kArchCount; + } + + //! Tests whether the given architecture `arch` is 32-bit. + static inline bool is32Bit(uint32_t arch) noexcept { + return (arch & kArch32BitMask) == kArch32BitMask; + } + + //! Tests whether the given architecture `arch` is 64-bit. + static inline bool is64Bit(uint32_t arch) noexcept { + return (arch & kArch32BitMask) == 0; + } + + //! Tests whether the given architecture `arch` is little endian. + static inline bool isLittleEndian(uint32_t arch) noexcept { + return (arch & kArchBigEndianMask) == 0; + } + + //! Tests whether the given architecture `arch` is big endian. + static inline bool isBigEndian(uint32_t arch) noexcept { + return (arch & kArchBigEndianMask) == kArchBigEndianMask; + } + + //! Tests whether the given architecture is AArch64. + static inline bool isArchAArch64(uint32_t arch) noexcept { + arch &= ~kArchBigEndianMask; + return arch == kArchAArch64; + } + + //! Tests whether the given architecture family is X86 or X64. + static inline bool isFamilyX86(uint32_t arch) noexcept { + return arch == kArchX86 || + arch == kArchX64; + } + + //! Tests whether the given architecture family is RISC-V (both 32-bit and 64-bit). + static inline bool isFamilyRISCV(uint32_t arch) noexcept { + return arch == kArchRISCV32 || + arch == kArchRISCV64; + } + + //! Tests whether the given architecture family is ARM, Thumb, or AArch64. + static inline bool isFamilyARM(uint32_t arch) noexcept { + arch &= ~kArchBigEndianMask; + return arch == kArchARM || + arch == kArchAArch64 || + arch == kArchThumb; + } + + //! Tests whether the given architecture family is MISP or MIPS64. + static inline bool isFamilyMIPS(uint32_t arch) noexcept { + arch &= ~kArchBigEndianMask; + return arch == kArchMIPS32_LE || + arch == kArchMIPS64_LE; + } + + //! Returns a native general purpose register size from the given architecture. + static uint32_t registerSizeFromArch(uint32_t arch) noexcept { + return is32Bit(arch) ? 4u : 8u; + } + + //! \} +}; + +//! Returns the host environment constructed from preprocessor macros defined +//! by the compiler. +//! +//! The returned environment should precisely match the target host architecture, +//! sub-architecture, platform, and ABI. +static ASMJIT_INLINE Environment hostEnvironment() noexcept { + return Environment(Environment::kArchHost, + Environment::kSubArchHost, + Environment::kVendorHost, + Environment::kPlatformHost, + Environment::kAbiHost, + Environment::kFormatUnknown); +} + +static_assert(sizeof(Environment) == 8, + "Environment must occupy exactly 8 bytes."); + +//! \} + +#ifndef ASMJIT_NO_DEPRECATED +class ASMJIT_DEPRECATED_STRUCT("Use Environment instead") ArchInfo : public Environment { +public: + inline ArchInfo() noexcept : Environment() {} + + inline ArchInfo(const Environment& other) noexcept : Environment(other) {} + inline explicit ArchInfo(uint32_t arch, uint32_t subArch = kSubArchUnknown) noexcept + : Environment(arch, subArch) {} + + enum Id : uint32_t { + kIdNone = Environment::kArchUnknown, + kIdX86 = Environment::kArchX86, + kIdX64 = Environment::kArchX64, + kIdA32 = Environment::kArchARM, + kIdA64 = Environment::kArchAArch64, + kIdHost = Environment::kArchHost + }; + + enum SubType : uint32_t { + kSubIdNone = Environment::kSubArchUnknown + }; + + static inline ArchInfo host() noexcept { return ArchInfo(hostEnvironment()); } +}; +#endif // !ASMJIT_NO_DEPRECATED + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_ENVIRONMENT_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/errorhandler.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/errorhandler.cpp new file mode 100644 index 0000000..8372d75 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/errorhandler.cpp @@ -0,0 +1,37 @@ + +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/errorhandler.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::ErrorHandler] +// ============================================================================ + +ErrorHandler::ErrorHandler() noexcept {} +ErrorHandler::~ErrorHandler() noexcept {} + +ASMJIT_END_NAMESPACE diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/errorhandler.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/errorhandler.h new file mode 100644 index 0000000..2337cd8 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/errorhandler.h @@ -0,0 +1,267 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_ERRORHANDLER_H_INCLUDED +#define ASMJIT_CORE_ERRORHANDLER_H_INCLUDED + +#include "../core/globals.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_error_handling +//! \{ + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +class BaseEmitter; + +// ============================================================================ +// [asmjit::ErrorHandler] +// ============================================================================ + +//! Error handler can be used to override the default behavior of error handling. +//! +//! It's available to all classes that inherit `BaseEmitter`. Override +//! \ref ErrorHandler::handleError() to implement your own error handler. +//! +//! The following use-cases are supported: +//! +//! - Record the error and continue code generation. This is the simplest +//! approach that can be used to at least log possible errors. +//! - Throw an exception. AsmJit doesn't use exceptions and is completely +//! exception-safe, but it's perfectly legal to throw an exception from +//! the error handler. +//! - Use plain old C's `setjmp()` and `longjmp()`. Asmjit always puts Assembler, +//! Builder and Compiler to a consistent state before calling \ref handleError(), +//! so `longjmp()` can be used without issues to cancel the code-generation if +//! an error occurred. This method can be used if exception handling in your +//! project is turned off and you still want some comfort. In most cases it +//! should be safe as AsmJit uses \ref Zone memory and the ownership of memory +//! it allocates always ends with the instance that allocated it. If using this +//! approach please never jump outside the life-time of \ref CodeHolder and +//! \ref BaseEmitter. +//! +//! \ref ErrorHandler can be attached to \ref CodeHolder or \ref BaseEmitter, +//! which has a priority. The example below uses error handler that just prints +//! the error, but lets AsmJit continue: +//! +//! ``` +//! // Error Handling #1 - Logging and returing Error. +//! #include +//! #include +//! +//! using namespace asmjit; +//! +//! // Error handler that just prints the error and lets AsmJit ignore it. +//! class SimpleErrorHandler : public ErrorHandler { +//! public: +//! Error err; +//! +//! inline SimpleErrorHandler() : err(kErrorOk) {} +//! +//! void handleError(Error err, const char* message, BaseEmitter* origin) override { +//! this->err = err; +//! fprintf(stderr, "ERROR: %s\n", message); +//! } +//! }; +//! +//! int main() { +//! JitRuntime rt; +//! SimpleErrorHandler eh; +//! +//! CodeHolder code; +//! code.init(rt.environment()); +//! code.setErrorHandler(&eh); +//! +//! // Try to emit instruction that doesn't exist. +//! x86::Assembler a(&code); +//! a.emit(x86::Inst::kIdMov, x86::xmm0, x86::xmm1); +//! +//! if (eh.err) { +//! // Assembler failed! +//! return 1; +//! } +//! +//! return 0; +//! } +//! ``` +//! +//! If error happens during instruction emitting / encoding the assembler behaves +//! transactionally - the output buffer won't advance if encoding failed, thus +//! either a fully encoded instruction or nothing is emitted. The error handling +//! shown above is useful, but it's still not the best way of dealing with errors +//! in AsmJit. The following example shows how to use exception handling to handle +//! errors in a more C++ way: +//! +//! ``` +//! // Error Handling #2 - Throwing an exception. +//! #include +//! #include +//! #include +//! #include +//! +//! using namespace asmjit; +//! +//! // Error handler that throws a user-defined `AsmJitException`. +//! class AsmJitException : public std::exception { +//! public: +//! Error err; +//! std::string message; +//! +//! AsmJitException(Error err, const char* message) noexcept +//! : err(err), +//! message(message) {} +//! +//! const char* what() const noexcept override { return message.c_str(); } +//! }; +//! +//! class ThrowableErrorHandler : public ErrorHandler { +//! public: +//! // Throw is possible, functions that use ErrorHandler are never 'noexcept'. +//! void handleError(Error err, const char* message, BaseEmitter* origin) override { +//! throw AsmJitException(err, message); +//! } +//! }; +//! +//! int main() { +//! JitRuntime rt; +//! ThrowableErrorHandler eh; +//! +//! CodeHolder code; +//! code.init(rt.environment()); +//! code.setErrorHandler(&eh); +//! +//! x86::Assembler a(&code); +//! +//! // Try to emit instruction that doesn't exist. +//! try { +//! a.emit(x86::Inst::kIdMov, x86::xmm0, x86::xmm1); +//! } +//! catch (const AsmJitException& ex) { +//! printf("EXCEPTION THROWN: %s\n", ex.what()); +//! return 1; +//! } +//! +//! return 0; +//! } +//! ``` +//! +//! If C++ exceptions are not what you like or your project turns off them +//! completely there is still a way of reducing the error handling to a minimum +//! by using a standard setjmp/longjmp approach. AsmJit is exception-safe and +//! cleans up everything before calling the ErrorHandler, so any approach is +//! safe. You can simply jump from the error handler without causing any +//! side-effects or memory leaks. The following example demonstrates how it +//! could be done: +//! +//! ``` +//! // Error Handling #3 - Using setjmp/longjmp if exceptions are not allowed. +//! #include +//! #include +//! #include +//! +//! class LongJmpErrorHandler : public asmjit::ErrorHandler { +//! public: +//! inline LongJmpErrorHandler() : err(asmjit::kErrorOk) {} +//! +//! void handleError(asmjit::Error err, const char* message, asmjit::BaseEmitter* origin) override { +//! this->err = err; +//! longjmp(state, 1); +//! } +//! +//! jmp_buf state; +//! asmjit::Error err; +//! }; +//! +//! int main(int argc, char* argv[]) { +//! using namespace asmjit; +//! +//! JitRuntime rt; +//! LongJmpErrorHandler eh; +//! +//! CodeHolder code; +//! code.init(rt.rt.environment()); +//! code.setErrorHandler(&eh); +//! +//! x86::Assembler a(&code); +//! +//! if (!setjmp(eh.state)) { +//! // Try to emit instruction that doesn't exist. +//! a.emit(x86::Inst::kIdMov, x86::xmm0, x86::xmm1); +//! } +//! else { +//! Error err = eh.err; +//! printf("ASMJIT ERROR: 0x%08X [%s]\n", err, DebugUtils::errorAsString(err)); +//! } +//! +//! return 0; +//! } +//! ``` +class ASMJIT_VIRTAPI ErrorHandler { +public: + ASMJIT_BASE_CLASS(ErrorHandler) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Creates a new `ErrorHandler` instance. + ASMJIT_API ErrorHandler() noexcept; + //! Destroys the `ErrorHandler` instance. + ASMJIT_API virtual ~ErrorHandler() noexcept; + + // -------------------------------------------------------------------------- + // [Handle Error] + // -------------------------------------------------------------------------- + + //! Error handler (must be reimplemented). + //! + //! Error handler is called after an error happened and before it's propagated + //! to the caller. There are multiple ways how the error handler can be used: + //! + //! 1. User-based error handling without throwing exception or using C's + //! `longjmp()`. This is for users that don't use exceptions and want + //! customized error handling. + //! + //! 2. Throwing an exception. AsmJit doesn't use exceptions and is completely + //! exception-safe, but you can throw exception from your error handler if + //! this way is the preferred way of handling errors in your project. + //! + //! 3. Using plain old C's `setjmp()` and `longjmp()`. Asmjit always puts + //! `BaseEmitter` to a consistent state before calling `handleError()` + //! so `longjmp()` can be used without any issues to cancel the code + //! generation if an error occurred. There is no difference between + //! exceptions and `longjmp()` from AsmJit's perspective, however, + //! never jump outside of `CodeHolder` and `BaseEmitter` scope as you + //! would leak memory. + virtual void handleError(Error err, const char* message, BaseEmitter* origin) = 0; +}; + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_ERRORHANDLER_H_INCLUDED + diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/features.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/features.h new file mode 100644 index 0000000..0f2cfe2 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/features.h @@ -0,0 +1,186 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_FEATURES_H_INCLUDED +#define ASMJIT_CORE_FEATURES_H_INCLUDED + +#include "../core/globals.h" +#include "../core/support.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_core +//! \{ + +// ============================================================================ +// [asmjit::BaseFeatures] +// ============================================================================ + +//! Base class that provides information about CPU features. +//! +//! Internally each feature is represented by a single bit in an embedded +//! bit-array, however, feature bits are defined by an architecture specific +//! implementations, like \ref x86::Features. +class BaseFeatures { +public: + typedef Support::BitWord BitWord; + typedef Support::BitVectorIterator Iterator; + + enum : uint32_t { + kMaxFeatures = 256, + kNumBitWords = kMaxFeatures / Support::kBitWordSizeInBits + }; + + BitWord _bits[kNumBitWords]; + + //! \name Construction & Destruction + //! \{ + + inline BaseFeatures() noexcept { reset(); } + inline BaseFeatures(const BaseFeatures& other) noexcept = default; + inline explicit BaseFeatures(Globals::NoInit_) noexcept {} + + inline void reset() noexcept { + for (size_t i = 0; i < kNumBitWords; i++) + _bits[i] = 0; + } + + //! \} + + //! \name Overloaded Operators + //! \{ + + inline BaseFeatures& operator=(const BaseFeatures& other) noexcept = default; + + inline bool operator==(const BaseFeatures& other) noexcept { return eq(other); } + inline bool operator!=(const BaseFeatures& other) noexcept { return !eq(other); } + + //! \} + + //! \name Cast + //! \{ + + //! Casts this base class into a derived type `T`. + template + inline T& as() noexcept { return static_cast(*this); } + + //! Casts this base class into a derived type `T` (const). + template + inline const T& as() const noexcept { return static_cast(*this); } + + //! \} + + //! \name Accessors + //! \{ + + inline bool empty() const noexcept { + for (uint32_t i = 0; i < kNumBitWords; i++) + if (_bits[i]) + return false; + return true; + } + + //! Returns all features as array of bitwords (see \ref Support::BitWord). + inline BitWord* bits() noexcept { return _bits; } + //! Returns all features as array of bitwords (const). + inline const BitWord* bits() const noexcept { return _bits; } + + //! Returns the number of BitWords returned by \ref bits(). + inline size_t bitWordCount() const noexcept { return kNumBitWords; } + + //! Returns \ref Support::BitVectorIterator, that can be used to iterate + //! all features efficiently + inline Iterator iterator() const noexcept { + return Iterator(_bits, kNumBitWords); + } + + //! Tests whether the feature `featureId` is present. + inline bool has(uint32_t featureId) const noexcept { + ASMJIT_ASSERT(featureId < kMaxFeatures); + + uint32_t idx = featureId / Support::kBitWordSizeInBits; + uint32_t bit = featureId % Support::kBitWordSizeInBits; + + return bool((_bits[idx] >> bit) & 0x1); + } + + //! Tests whether all features as defined by `other` are present. + inline bool hasAll(const BaseFeatures& other) const noexcept { + for (uint32_t i = 0; i < kNumBitWords; i++) + if ((_bits[i] & other._bits[i]) != other._bits[i]) + return false; + return true; + } + + //! \} + + //! \name Utilities + //! \{ + + //! Adds the given CPU `featureId` to the list of features. + inline void add(uint32_t featureId) noexcept { + ASMJIT_ASSERT(featureId < kMaxFeatures); + + uint32_t idx = featureId / Support::kBitWordSizeInBits; + uint32_t bit = featureId % Support::kBitWordSizeInBits; + + _bits[idx] |= BitWord(1) << bit; + } + + template + inline void add(uint32_t featureId, Args... otherIds) noexcept { + add(featureId); + add(otherIds...); + } + + //! Removes the given CPU `featureId` from the list of features. + inline void remove(uint32_t featureId) noexcept { + ASMJIT_ASSERT(featureId < kMaxFeatures); + + uint32_t idx = featureId / Support::kBitWordSizeInBits; + uint32_t bit = featureId % Support::kBitWordSizeInBits; + + _bits[idx] &= ~(BitWord(1) << bit); + } + + template + inline void remove(uint32_t featureId, Args... otherIds) noexcept { + remove(featureId); + remove(otherIds...); + } + + inline bool eq(const BaseFeatures& other) const noexcept { + for (size_t i = 0; i < kNumBitWords; i++) + if (_bits[i] != other._bits[i]) + return false; + return true; + } + + //! \} +}; + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_FEATURES_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/formatter.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/formatter.cpp new file mode 100644 index 0000000..89c3228 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/formatter.cpp @@ -0,0 +1,481 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#ifndef ASMJIT_NO_LOGGING + +#include "../core/builder.h" +#include "../core/codeholder.h" +#include "../core/compiler.h" +#include "../core/emitter.h" +#include "../core/formatter.h" +#include "../core/string.h" +#include "../core/support.h" +#include "../core/type.h" + +#ifdef ASMJIT_BUILD_X86 + #include "../x86/x86formatter_p.h" +#endif + +#ifdef ASMJIT_BUILD_ARM + #include "../arm/armformatter_p.h" +#endif + +ASMJIT_BEGIN_NAMESPACE + +#if defined(ASMJIT_NO_COMPILER) +class VirtReg; +#endif + +// ============================================================================ +// [asmjit::Formatter] +// ============================================================================ + +namespace Formatter { + +Error formatTypeId(String& sb, uint32_t typeId) noexcept { + if (typeId == Type::kIdVoid) + return sb.append("void"); + + if (!Type::isValid(typeId)) + return sb.append("unknown"); + + const char* typeName = "unknown"; + uint32_t typeSize = Type::sizeOf(typeId); + + uint32_t baseId = Type::baseOf(typeId); + switch (baseId) { + case Type::kIdIntPtr : typeName = "iptr" ; break; + case Type::kIdUIntPtr: typeName = "uptr" ; break; + case Type::kIdI8 : typeName = "i8" ; break; + case Type::kIdU8 : typeName = "u8" ; break; + case Type::kIdI16 : typeName = "i16" ; break; + case Type::kIdU16 : typeName = "u16" ; break; + case Type::kIdI32 : typeName = "i32" ; break; + case Type::kIdU32 : typeName = "u32" ; break; + case Type::kIdI64 : typeName = "i64" ; break; + case Type::kIdU64 : typeName = "u64" ; break; + case Type::kIdF32 : typeName = "f32" ; break; + case Type::kIdF64 : typeName = "f64" ; break; + case Type::kIdF80 : typeName = "f80" ; break; + case Type::kIdMask8 : typeName = "mask8" ; break; + case Type::kIdMask16 : typeName = "mask16"; break; + case Type::kIdMask32 : typeName = "mask32"; break; + case Type::kIdMask64 : typeName = "mask64"; break; + case Type::kIdMmx32 : typeName = "mmx32" ; break; + case Type::kIdMmx64 : typeName = "mmx64" ; break; + } + + uint32_t baseSize = Type::sizeOf(baseId); + if (typeSize > baseSize) { + uint32_t count = typeSize / baseSize; + return sb.appendFormat("%sx%u", typeName, unsigned(count)); + } + else { + return sb.append(typeName); + } +} + +Error formatFeature( + String& sb, + uint32_t arch, + uint32_t featureId) noexcept { + +#ifdef ASMJIT_BUILD_X86 + if (Environment::isFamilyX86(arch)) + return x86::FormatterInternal::formatFeature(sb, featureId); +#endif + +#ifdef ASMJIT_BUILD_ARM + if (Environment::isFamilyARM(arch)) + return arm::FormatterInternal::formatFeature(sb, featureId); +#endif + + return kErrorInvalidArch; +} + +Error formatLabel( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t labelId) noexcept { + + DebugUtils::unused(formatFlags); + + const LabelEntry* le = emitter->code()->labelEntry(labelId); + if (ASMJIT_UNLIKELY(!le)) + return sb.appendFormat("", labelId); + + if (le->hasName()) { + if (le->hasParent()) { + uint32_t parentId = le->parentId(); + const LabelEntry* pe = emitter->code()->labelEntry(parentId); + + if (ASMJIT_UNLIKELY(!pe)) + ASMJIT_PROPAGATE(sb.appendFormat("", labelId)); + else if (ASMJIT_UNLIKELY(!pe->hasName())) + ASMJIT_PROPAGATE(sb.appendFormat("L%u", parentId)); + else + ASMJIT_PROPAGATE(sb.append(pe->name())); + + ASMJIT_PROPAGATE(sb.append('.')); + } + return sb.append(le->name()); + } + else { + return sb.appendFormat("L%u", labelId); + } +} + +Error formatRegister( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t arch, + uint32_t regType, + uint32_t regId) noexcept { + +#ifdef ASMJIT_BUILD_X86 + if (Environment::isFamilyX86(arch)) + return x86::FormatterInternal::formatRegister(sb, formatFlags, emitter, arch, regType, regId); +#endif + +#ifdef ASMJIT_BUILD_ARM + if (Environment::isFamilyARM(arch)) + return arm::FormatterInternal::formatRegister(sb, formatFlags, emitter, arch, regType, regId); +#endif + + return kErrorInvalidArch; +} + +Error formatOperand( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t arch, + const Operand_& op) noexcept { + +#ifdef ASMJIT_BUILD_X86 + if (Environment::isFamilyX86(arch)) + return x86::FormatterInternal::formatOperand(sb, formatFlags, emitter, arch, op); +#endif + +#ifdef ASMJIT_BUILD_ARM + if (Environment::isFamilyARM(arch)) + return arm::FormatterInternal::formatOperand(sb, formatFlags, emitter, arch, op); +#endif + + return kErrorInvalidArch; +} + +Error formatInstruction( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t arch, + const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept { + +#ifdef ASMJIT_BUILD_X86 + if (Environment::isFamilyX86(arch)) + return x86::FormatterInternal::formatInstruction(sb, formatFlags, emitter, arch, inst, operands, opCount); +#endif + +#ifdef ASMJIT_BUILD_ARM + if (Environment::isFamilyARM(arch)) + return arm::FormatterInternal::formatInstruction(sb, formatFlags, emitter, arch, inst, operands, opCount); +#endif + + return kErrorInvalidArch; +} + +#ifndef ASMJIT_NO_BUILDER + +#ifndef ASMJIT_NO_COMPILER +static Error formatFuncValue(String& sb, uint32_t formatFlags, const BaseEmitter* emitter, FuncValue value) noexcept { + uint32_t typeId = value.typeId(); + ASMJIT_PROPAGATE(formatTypeId(sb, typeId)); + + if (value.isAssigned()) { + ASMJIT_PROPAGATE(sb.append('@')); + + if (value.isIndirect()) + ASMJIT_PROPAGATE(sb.append('[')); + + // NOTE: It should be either reg or stack, but never both. We + // use two IFs on purpose so if the FuncValue is both it would + // show in logs. + if (value.isReg()) { + ASMJIT_PROPAGATE(formatRegister(sb, formatFlags, emitter, emitter->arch(), value.regType(), value.regId())); + } + + if (value.isStack()) { + ASMJIT_PROPAGATE(sb.appendFormat("[%d]", int(value.stackOffset()))); + } + + if (value.isIndirect()) + ASMJIT_PROPAGATE(sb.append(']')); + } + + return kErrorOk; +} + +static Error formatFuncValuePack( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + const FuncValuePack& pack, + VirtReg* const* vRegs) noexcept { + + size_t count = pack.count(); + if (!count) + return sb.append("void"); + + if (count > 1) + sb.append('['); + + for (uint32_t valueIndex = 0; valueIndex < count; valueIndex++) { + const FuncValue& value = pack[valueIndex]; + if (!value) + break; + + if (valueIndex) + ASMJIT_PROPAGATE(sb.append(", ")); + + ASMJIT_PROPAGATE(formatFuncValue(sb, formatFlags, emitter, value)); + + if (vRegs) { + static const char nullRet[] = ""; + ASMJIT_PROPAGATE(sb.appendFormat(" %s", vRegs[valueIndex] ? vRegs[valueIndex]->name() : nullRet)); + } + } + + if (count > 1) + sb.append(']'); + + return kErrorOk; +} + +static Error formatFuncRets( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + const FuncDetail& fd) noexcept { + + return formatFuncValuePack(sb, formatFlags, emitter, fd.retPack(), nullptr); +} + +static Error formatFuncArgs( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + const FuncDetail& fd, + const FuncNode::ArgPack* argPacks) noexcept { + + uint32_t argCount = fd.argCount(); + if (!argCount) + return sb.append("void"); + + for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) { + if (argIndex) + ASMJIT_PROPAGATE(sb.append(", ")); + + ASMJIT_PROPAGATE(formatFuncValuePack(sb, formatFlags, emitter, fd.argPack(argIndex), argPacks[argIndex]._data)); + } + + return kErrorOk; +} +#endif + +Error formatNode( + String& sb, + uint32_t formatFlags, + const BaseBuilder* builder, + const BaseNode* node) noexcept { + + if (node->hasPosition() && (formatFlags & FormatOptions::kFlagPositions) != 0) + ASMJIT_PROPAGATE(sb.appendFormat("<%05u> ", node->position())); + + switch (node->type()) { + case BaseNode::kNodeInst: + case BaseNode::kNodeJump: { + const InstNode* instNode = node->as(); + ASMJIT_PROPAGATE( + formatInstruction(sb, formatFlags, builder, + builder->arch(), + instNode->baseInst(), instNode->operands(), instNode->opCount())); + break; + } + + case BaseNode::kNodeSection: { + const SectionNode* sectionNode = node->as(); + if (builder->_code->isSectionValid(sectionNode->id())) { + const Section* section = builder->_code->sectionById(sectionNode->id()); + ASMJIT_PROPAGATE(sb.appendFormat(".section %s", section->name())); + } + break; + } + + case BaseNode::kNodeLabel: { + const LabelNode* labelNode = node->as(); + ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, labelNode->labelId())); + ASMJIT_PROPAGATE(sb.append(":")); + break; + } + + case BaseNode::kNodeAlign: { + const AlignNode* alignNode = node->as(); + ASMJIT_PROPAGATE( + sb.appendFormat("align %u (%s)", + alignNode->alignment(), + alignNode->alignMode() == kAlignCode ? "code" : "data")); + break; + } + + case BaseNode::kNodeEmbedData: { + const EmbedDataNode* embedNode = node->as(); + ASMJIT_PROPAGATE(sb.append("embed ")); + if (embedNode->repeatCount() != 1) + ASMJIT_PROPAGATE(sb.appendFormat("[repeat=%zu] ", size_t(embedNode->repeatCount()))); + ASMJIT_PROPAGATE(sb.appendFormat("%u bytes", embedNode->dataSize())); + break; + } + + case BaseNode::kNodeEmbedLabel: { + const EmbedLabelNode* embedNode = node->as(); + ASMJIT_PROPAGATE(sb.append(".label ")); + ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, embedNode->labelId())); + break; + } + + case BaseNode::kNodeEmbedLabelDelta: { + const EmbedLabelDeltaNode* embedNode = node->as(); + ASMJIT_PROPAGATE(sb.append(".label (")); + ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, embedNode->labelId())); + ASMJIT_PROPAGATE(sb.append(" - ")); + ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, embedNode->baseLabelId())); + ASMJIT_PROPAGATE(sb.append(")")); + break; + } + + case BaseNode::kNodeComment: { + const CommentNode* commentNode = node->as(); + ASMJIT_PROPAGATE(sb.appendFormat("; %s", commentNode->inlineComment())); + break; + } + + case BaseNode::kNodeSentinel: { + const SentinelNode* sentinelNode = node->as(); + const char* sentinelName = nullptr; + + switch (sentinelNode->sentinelType()) { + case SentinelNode::kSentinelFuncEnd: + sentinelName = "[FuncEnd]"; + break; + + default: + sentinelName = "[Sentinel]"; + break; + } + + ASMJIT_PROPAGATE(sb.append(sentinelName)); + break; + } + +#ifndef ASMJIT_NO_COMPILER + case BaseNode::kNodeFunc: { + const FuncNode* funcNode = node->as(); + + ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, funcNode->labelId())); + ASMJIT_PROPAGATE(sb.append(": ")); + + ASMJIT_PROPAGATE(formatFuncRets(sb, formatFlags, builder, funcNode->detail())); + ASMJIT_PROPAGATE(sb.append(" Func(")); + ASMJIT_PROPAGATE(formatFuncArgs(sb, formatFlags, builder, funcNode->detail(), funcNode->argPacks())); + ASMJIT_PROPAGATE(sb.append(")")); + break; + } + + case BaseNode::kNodeFuncRet: { + const FuncRetNode* retNode = node->as(); + ASMJIT_PROPAGATE(sb.append("[FuncRet]")); + + for (uint32_t i = 0; i < 2; i++) { + const Operand_& op = retNode->_opArray[i]; + if (!op.isNone()) { + ASMJIT_PROPAGATE(sb.append(i == 0 ? " " : ", ")); + ASMJIT_PROPAGATE(formatOperand(sb, formatFlags, builder, builder->arch(), op)); + } + } + break; + } + + case BaseNode::kNodeInvoke: { + const InvokeNode* invokeNode = node->as(); + ASMJIT_PROPAGATE( + formatInstruction(sb, formatFlags, builder, + builder->arch(), + invokeNode->baseInst(), invokeNode->operands(), invokeNode->opCount())); + break; + } +#endif + + default: { + ASMJIT_PROPAGATE(sb.appendFormat("[UserNode:%u]", node->type())); + break; + } + } + + return kErrorOk; +} + + +Error formatNodeList( + String& sb, + uint32_t formatFlags, + const BaseBuilder* builder) noexcept { + + return formatNodeList(sb, formatFlags, builder, builder->firstNode(), nullptr); +} + +Error formatNodeList( + String& sb, + uint32_t formatFlags, + const BaseBuilder* builder, + const BaseNode* begin, + const BaseNode* end) noexcept { + + const BaseNode* node = begin; + while (node != end) { + ASMJIT_PROPAGATE(formatNode(sb, formatFlags, builder, node)); + ASMJIT_PROPAGATE(sb.append('\n')); + node = node->next(); + } + return kErrorOk; +} +#endif + +} // {Formatter} + +ASMJIT_END_NAMESPACE + +#endif diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/formatter.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/formatter.h new file mode 100644 index 0000000..14934ba --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/formatter.h @@ -0,0 +1,256 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_FORMATTER_H_INCLUDED +#define ASMJIT_CORE_FORMATTER_H_INCLUDED + +#include "../core/inst.h" +#include "../core/string.h" + +#ifndef ASMJIT_NO_LOGGING + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_logging +//! \{ + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +class BaseEmitter; +struct Operand_; + +#ifndef ASMJIT_NO_BUILDER +class BaseBuilder; +class BaseNode; +#endif + +#ifndef ASMJIT_NO_COMPILER +class BaseCompiler; +#endif + +// ============================================================================ +// [asmjit::FormatOptions] +// ============================================================================ + +//! Formatting options used by \ref Logger and \ref Formatter. +class FormatOptions { +public: + //! Format flags, see \ref Flags. + uint32_t _flags; + //! Indentation by type, see \ref IndentationType. + uint8_t _indentation[4]; + + //! Flags can enable a logging feature. + enum Flags : uint32_t { + //! No flags. + kNoFlags = 0u, + + //! Show also binary form of each logged instruction (Assembler). + kFlagMachineCode = 0x00000001u, + //! Show a text explanation of some immediate values. + kFlagExplainImms = 0x00000002u, + //! Use hexadecimal notation of immediate values. + kFlagHexImms = 0x00000004u, + //! Use hexadecimal notation of address offsets. + kFlagHexOffsets = 0x00000008u, + //! Show casts between virtual register types (Compiler). + kFlagRegCasts = 0x00000010u, + //! Show positions associated with nodes (Compiler). + kFlagPositions = 0x00000020u, + //! Annotate nodes that are lowered by passes. + kFlagAnnotations = 0x00000040u, + + // TODO: These must go, keep this only for formatting. + //! Show an additional output from passes. + kFlagDebugPasses = 0x00000080u, + //! Show an additional output from RA. + kFlagDebugRA = 0x00000100u + }; + + //! Describes indentation type of code, label, or comment in logger output. + enum IndentationType : uint32_t { + //! Indentation used for instructions and directives. + kIndentationCode = 0u, + //! Indentation used for labels and function nodes. + kIndentationLabel = 1u, + //! Indentation used for comments (not inline comments). + kIndentationComment = 2u, + //! \cond INTERNAL + //! Reserved for future use. + kIndentationReserved = 3u + //! \endcond + }; + + //! \name Construction & Destruction + //! \{ + + //! Creates a default-initialized FormatOptions. + constexpr FormatOptions() noexcept + : _flags(0), + _indentation { 0, 0, 0, 0 } {} + + constexpr FormatOptions(const FormatOptions& other) noexcept = default; + inline FormatOptions& operator=(const FormatOptions& other) noexcept = default; + + //! Resets FormatOptions to its default initialized state. + inline void reset() noexcept { + _flags = 0; + _indentation[0] = 0; + _indentation[1] = 0; + _indentation[2] = 0; + _indentation[3] = 0; + } + + //! \} + + //! \name Accessors + //! \{ + + //! Returns format flags. + constexpr uint32_t flags() const noexcept { return _flags; } + //! Tests whether the given `flag` is set in format flags. + constexpr bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } + //! Resets all format flags to `flags`. + inline void setFlags(uint32_t flags) noexcept { _flags = flags; } + //! Adds `flags` to format flags. + inline void addFlags(uint32_t flags) noexcept { _flags |= flags; } + //! Removes `flags` from format flags. + inline void clearFlags(uint32_t flags) noexcept { _flags &= ~flags; } + + //! Returns indentation for the given `type`, see \ref IndentationType. + constexpr uint8_t indentation(uint32_t type) const noexcept { return _indentation[type]; } + //! Sets indentation for the given `type`, see \ref IndentationType. + inline void setIndentation(uint32_t type, uint32_t n) noexcept { _indentation[type] = uint8_t(n); } + //! Resets indentation for the given `type` to zero. + inline void resetIndentation(uint32_t type) noexcept { _indentation[type] = uint8_t(0); } + + //! \} +}; + +// ============================================================================ +// [asmjit::Formatter] +// ============================================================================ + +//! Provides formatting functionality to format operands, instructions, and nodes. +namespace Formatter { + +//! Appends a formatted `typeId` to the output string `sb`. +ASMJIT_API Error formatTypeId( + String& sb, + uint32_t typeId) noexcept; + +//! Appends a formatted `featureId` to the output string `sb`. +//! +//! See \ref BaseFeatures. +ASMJIT_API Error formatFeature( + String& sb, + uint32_t arch, + uint32_t featureId) noexcept; + +//! Appends a formatted register to the output string `sb`. +//! +//! \note Emitter is optional, but it's required to format virtual registers, +//! which won't be formatted properly if the `emitter` is not provided. +ASMJIT_API Error formatRegister( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t arch, + uint32_t regType, + uint32_t regId) noexcept; + +//! Appends a formatted label to the output string `sb`. +//! +//! \note Emitter is optional, but it's required to format named labels +//! properly, otherwise the formatted as it is an anonymous label. +ASMJIT_API Error formatLabel( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t labelId) noexcept; + +//! Appends a formatted operand to the output string `sb`. +//! +//! \note Emitter is optional, but it's required to format named labels and +//! virtual registers. See \ref formatRegister() and \ref formatLabel() for +//! more details. +ASMJIT_API Error formatOperand( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t arch, + const Operand_& op) noexcept; + +//! Appends a formatted instruction to the output string `sb`. +//! +//! \note Emitter is optional, but it's required to format named labels and +//! virtual registers. See \ref formatRegister() and \ref formatLabel() for +//! more details. +ASMJIT_API Error formatInstruction( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t arch, + const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept; + +#ifndef ASMJIT_NO_BUILDER +//! Appends a formatted node to the output string `sb`. +//! +//! The `node` must belong to the provided `builder`. +ASMJIT_API Error formatNode( + String& sb, + uint32_t formatFlags, + const BaseBuilder* builder, + const BaseNode* node) noexcept; + +//! Appends formatted nodes to the output string `sb`. +//! +//! All nodes that are part of the given `builder` will be appended. +ASMJIT_API Error formatNodeList( + String& sb, + uint32_t formatFlags, + const BaseBuilder* builder) noexcept; + +//! Appends formatted nodes to the output string `sb`. +//! +//! This function works the same as \ref formatNode(), but appends more nodes +//! to the output string, separating each node with a newline '\n' character. +ASMJIT_API Error formatNodeList( + String& sb, + uint32_t formatFlags, + const BaseBuilder* builder, + const BaseNode* begin, + const BaseNode* end) noexcept; +#endif + +} // {Formatter} + +//! \} + +ASMJIT_END_NAMESPACE + +#endif + +#endif // ASMJIT_CORE_FORMATTER_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/func.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/func.cpp new file mode 100644 index 0000000..bb131a0 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/func.cpp @@ -0,0 +1,310 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/archtraits.h" +#include "../core/func.h" +#include "../core/operand.h" +#include "../core/type.h" +#include "../core/funcargscontext_p.h" + +#ifdef ASMJIT_BUILD_X86 + #include "../x86/x86func_p.h" +#endif + +#ifdef ASMJIT_BUILD_ARM + #include "../arm/armfunc_p.h" +#endif + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::CallConv - Init / Reset] +// ============================================================================ + +ASMJIT_FAVOR_SIZE Error CallConv::init(uint32_t ccId, const Environment& environment) noexcept { + reset(); + +#ifdef ASMJIT_BUILD_X86 + if (environment.isFamilyX86()) + return x86::FuncInternal::initCallConv(*this, ccId, environment); +#endif + +#ifdef ASMJIT_BUILD_ARM + if (environment.isFamilyARM()) + return arm::FuncInternal::initCallConv(*this, ccId, environment); +#endif + + return DebugUtils::errored(kErrorInvalidArgument); +} + +// ============================================================================ +// [asmjit::FuncDetail - Init / Reset] +// ============================================================================ + +ASMJIT_FAVOR_SIZE Error FuncDetail::init(const FuncSignature& signature, const Environment& environment) noexcept { + uint32_t ccId = signature.callConv(); + uint32_t argCount = signature.argCount(); + + if (ASMJIT_UNLIKELY(argCount > Globals::kMaxFuncArgs)) + return DebugUtils::errored(kErrorInvalidArgument); + + CallConv& cc = _callConv; + ASMJIT_PROPAGATE(cc.init(ccId, environment)); + + uint32_t registerSize = Environment::registerSizeFromArch(cc.arch()); + uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize); + + const uint8_t* signatureArgs = signature.args(); + for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) { + FuncValuePack& argPack = _args[argIndex]; + argPack[0].initTypeId(Type::deabstract(signatureArgs[argIndex], deabstractDelta)); + } + _argCount = uint8_t(argCount); + _vaIndex = uint8_t(signature.vaIndex()); + + uint32_t ret = signature.ret(); + if (ret != Type::kIdVoid) + _rets[0].initTypeId(Type::deabstract(ret, deabstractDelta)); + +#ifdef ASMJIT_BUILD_X86 + if (environment.isFamilyX86()) + return x86::FuncInternal::initFuncDetail(*this, signature, registerSize); +#endif + +#ifdef ASMJIT_BUILD_ARM + if (environment.isFamilyARM()) + return arm::FuncInternal::initFuncDetail(*this, signature, registerSize); +#endif + + // We should never bubble here as if `cc.init()` succeeded then there has to + // be an implementation for the current architecture. However, stay safe. + return DebugUtils::errored(kErrorInvalidArgument); +} + +// ============================================================================ +// [asmjit::FuncFrame - Init / Finalize] +// ============================================================================ + +ASMJIT_FAVOR_SIZE Error FuncFrame::init(const FuncDetail& func) noexcept { + uint32_t arch = func.callConv().arch(); + if (!Environment::isValidArch(arch)) + return DebugUtils::errored(kErrorInvalidArch); + + const ArchTraits& archTraits = ArchTraits::byArch(arch); + + // Initializing FuncFrame means making a copy of some properties of `func`. + // Properties like `_localStackSize` will be set by the user before the frame + // is finalized. + reset(); + + _arch = uint8_t(arch); + _spRegId = uint8_t(archTraits.spRegId()); + _saRegId = uint8_t(BaseReg::kIdBad); + + uint32_t naturalStackAlignment = func.callConv().naturalStackAlignment(); + uint32_t minDynamicAlignment = Support::max(naturalStackAlignment, 16); + + if (minDynamicAlignment == naturalStackAlignment) + minDynamicAlignment <<= 1; + + _naturalStackAlignment = uint8_t(naturalStackAlignment); + _minDynamicAlignment = uint8_t(minDynamicAlignment); + _redZoneSize = uint8_t(func.redZoneSize()); + _spillZoneSize = uint8_t(func.spillZoneSize()); + _finalStackAlignment = uint8_t(_naturalStackAlignment); + + if (func.hasFlag(CallConv::kFlagCalleePopsStack)) { + _calleeStackCleanup = uint16_t(func.argStackSize()); + } + + // Initial masks of dirty and preserved registers. + for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++) { + _dirtyRegs[group] = func.usedRegs(group); + _preservedRegs[group] = func.preservedRegs(group); + } + + // Exclude stack pointer - this register is never included in saved GP regs. + _preservedRegs[BaseReg::kGroupGp] &= ~Support::bitMask(archTraits.spRegId()); + + // The size and alignment of save/restore area of registers for each significant register group. + memcpy(_saveRestoreRegSize, func.callConv()._saveRestoreRegSize, sizeof(_saveRestoreRegSize)); + memcpy(_saveRestoreAlignment, func.callConv()._saveRestoreAlignment, sizeof(_saveRestoreAlignment)); + + return kErrorOk; +} + +ASMJIT_FAVOR_SIZE Error FuncFrame::finalize() noexcept { + if (!Environment::isValidArch(arch())) + return DebugUtils::errored(kErrorInvalidArch); + + const ArchTraits& archTraits = ArchTraits::byArch(arch()); + + uint32_t registerSize = _saveRestoreRegSize[BaseReg::kGroupGp]; + uint32_t vectorSize = _saveRestoreRegSize[BaseReg::kGroupVec]; + uint32_t returnAddressSize = archTraits.hasLinkReg() ? 0u : registerSize; + + // The final stack alignment must be updated accordingly to call and local stack alignments. + uint32_t stackAlignment = _finalStackAlignment; + ASMJIT_ASSERT(stackAlignment == Support::max(_naturalStackAlignment, + _callStackAlignment, + _localStackAlignment)); + + bool hasFP = hasPreservedFP(); + bool hasDA = hasDynamicAlignment(); + + uint32_t kSp = archTraits.spRegId(); + uint32_t kFp = archTraits.fpRegId(); + uint32_t kLr = archTraits.linkRegId(); + + // Make frame pointer dirty if the function uses it. + if (hasFP) { + _dirtyRegs[BaseReg::kGroupGp] |= Support::bitMask(kFp); + + // Currently required by ARM, if this works differently across architectures + // we would have to generalize most likely in CallConv. + if (kLr != BaseReg::kIdBad) + _dirtyRegs[BaseReg::kGroupGp] |= Support::bitMask(kLr); + } + + // These two are identical if the function doesn't align its stack dynamically. + uint32_t saRegId = _saRegId; + if (saRegId == BaseReg::kIdBad) + saRegId = kSp; + + // Fix stack arguments base-register from SP to FP in case it was not picked + // before and the function performs dynamic stack alignment. + if (hasDA && saRegId == kSp) + saRegId = kFp; + + // Mark as dirty any register but SP if used as SA pointer. + if (saRegId != kSp) + _dirtyRegs[BaseReg::kGroupGp] |= Support::bitMask(saRegId); + + _spRegId = uint8_t(kSp); + _saRegId = uint8_t(saRegId); + + // Setup stack size used to save preserved registers. + uint32_t saveRestoreSizes[2] {}; + for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++) + saveRestoreSizes[size_t(!archTraits.hasPushPop(group))] + += Support::alignUp(Support::popcnt(savedRegs(group)) * saveRestoreRegSize(group), saveRestoreAlignment(group)); + + _pushPopSaveSize = uint16_t(saveRestoreSizes[0]); + _extraRegSaveSize = uint16_t(saveRestoreSizes[1]); + + uint32_t v = 0; // The beginning of the stack frame relative to SP after prolog. + v += callStackSize(); // Count 'callStackSize' <- This is used to call functions. + v = Support::alignUp(v, stackAlignment); // Align to function's stack alignment. + + _localStackOffset = v; // Store 'localStackOffset' <- Function's local stack starts here. + v += localStackSize(); // Count 'localStackSize' <- Function's local stack ends here. + + // If the function's stack must be aligned, calculate the alignment necessary + // to store vector registers, and set `FuncFrame::kAttrAlignedVecSR` to inform + // PEI that it can use instructions that perform aligned stores/loads. + if (stackAlignment >= vectorSize && _extraRegSaveSize) { + addAttributes(FuncFrame::kAttrAlignedVecSR); + v = Support::alignUp(v, vectorSize); // Align 'extraRegSaveOffset'. + } + + _extraRegSaveOffset = v; // Store 'extraRegSaveOffset' <- Non-GP save/restore starts here. + v += _extraRegSaveSize; // Count 'extraRegSaveSize' <- Non-GP save/restore ends here. + + // Calculate if dynamic alignment (DA) slot (stored as offset relative to SP) is required and its offset. + if (hasDA && !hasFP) { + _daOffset = v; // Store 'daOffset' <- DA pointer would be stored here. + v += registerSize; // Count 'daOffset'. + } + else { + _daOffset = FuncFrame::kTagInvalidOffset; + } + + // Link Register + // ------------- + // + // The stack is aligned after the function call as the return address is + // stored in a link register. Some architectures may require to always + // have aligned stack after PUSH/POP operation, which is represented by + // ArchTraits::stackAlignmentConstraint(). + // + // No Link Register (X86/X64) + // -------------------------- + // + // The return address should be stored after GP save/restore regs. It has + // the same size as `registerSize` (basically the native register/pointer + // size). We don't adjust it now as `v` now contains the exact size that the + // function requires to adjust (call frame + stack frame, vec stack size). + // The stack (if we consider this size) is misaligned now, as it's always + // aligned before the function call - when `call()` is executed it pushes + // the current EIP|RIP onto the stack, and misaligns it by 12 or 8 bytes + // (depending on the architecture). So count number of bytes needed to align + // it up to the function's CallFrame (the beginning). + if (v || hasFuncCalls() || !returnAddressSize) + v += Support::alignUpDiff(v + pushPopSaveSize() + returnAddressSize, stackAlignment); + + _pushPopSaveOffset = v; // Store 'pushPopSaveOffset' <- Function's push/pop save/restore starts here. + _stackAdjustment = v; // Store 'stackAdjustment' <- SA used by 'add SP, SA' and 'sub SP, SA'. + v += _pushPopSaveSize; // Count 'pushPopSaveSize' <- Function's push/pop save/restore ends here. + _finalStackSize = v; // Store 'finalStackSize' <- Final stack used by the function. + + if (!archTraits.hasLinkReg()) + v += registerSize; // Count 'ReturnAddress' <- As CALL pushes onto stack. + + // If the function performs dynamic stack alignment then the stack-adjustment must be aligned. + if (hasDA) + _stackAdjustment = Support::alignUp(_stackAdjustment, stackAlignment); + + // Calculate where the function arguments start relative to SP. + _saOffsetFromSP = hasDA ? FuncFrame::kTagInvalidOffset : v; + + // Calculate where the function arguments start relative to FP or user-provided register. + _saOffsetFromSA = hasFP ? returnAddressSize + registerSize // Return address + frame pointer. + : returnAddressSize + _pushPopSaveSize; // Return address + all push/pop regs. + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::FuncArgsAssignment] +// ============================================================================ + +ASMJIT_FAVOR_SIZE Error FuncArgsAssignment::updateFuncFrame(FuncFrame& frame) const noexcept { + uint32_t arch = frame.arch(); + const FuncDetail* func = funcDetail(); + + if (!func) + return DebugUtils::errored(kErrorInvalidState); + + RAConstraints constraints; + ASMJIT_PROPAGATE(constraints.init(arch)); + + FuncArgsContext ctx; + ASMJIT_PROPAGATE(ctx.initWorkData(frame, *this, &constraints)); + ASMJIT_PROPAGATE(ctx.markDstRegsDirty(frame)); + ASMJIT_PROPAGATE(ctx.markScratchRegs(frame)); + ASMJIT_PROPAGATE(ctx.markStackArgsReg(frame)); + return kErrorOk; +} + +ASMJIT_END_NAMESPACE diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/func.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/func.h new file mode 100644 index 0000000..6cfd044 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/func.h @@ -0,0 +1,1426 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_FUNC_H_INCLUDED +#define ASMJIT_CORE_FUNC_H_INCLUDED + +#include "../core/archtraits.h" +#include "../core/environment.h" +#include "../core/operand.h" +#include "../core/type.h" +#include "../core/support.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_function +//! \{ + +// ============================================================================ +// [asmjit::CallConv] +// ============================================================================ + +//! Function calling convention. +//! +//! Function calling convention is a scheme that defines how function parameters +//! are passed and how function returns its result. AsmJit defines a variety of +//! architecture and OS specific calling conventions and also provides a compile +//! time detection to make the code-generation easier. +struct CallConv { + //! Calling convention id, see \ref Id. + uint8_t _id; + //! Architecture identifier, see \ref Environment::Arch. + uint8_t _arch; + //! Register assignment strategy, see \ref Strategy. + uint8_t _strategy; + + //! Red zone size (AMD64 == 128 bytes). + uint8_t _redZoneSize; + //! Spill zone size (WIN-X64 == 32 bytes). + uint8_t _spillZoneSize; + //! Natural stack alignment as defined by OS/ABI. + uint8_t _naturalStackAlignment; + + //! Flags. + uint16_t _flags; + + //! Size to save/restore per register group. + uint8_t _saveRestoreRegSize[BaseReg::kGroupVirt]; + //! Alignment of save/restore groups. + uint8_t _saveRestoreAlignment[BaseReg::kGroupVirt]; + + //! Mask of all passed registers, per group. + uint32_t _passedRegs[BaseReg::kGroupVirt]; + //! Mask of all preserved registers, per group. + uint32_t _preservedRegs[BaseReg::kGroupVirt]; + + //! Internal limits of AsmJit's CallConv. + enum Limits : uint32_t { + //! Maximum number of register arguments per register group. + //! + //! \note This is not really AsmJit's limitatation, it's just the number + //! that makes sense considering all common calling conventions. Usually + //! even conventions that use registers to pass function arguments are + //! limited to 8 and less arguments passed via registers per group. + kMaxRegArgsPerGroup = 16 + }; + + //! Passed registers' order. + union RegOrder { + //! Passed registers, ordered. + uint8_t id[kMaxRegArgsPerGroup]; + //! Packed IDs in `uint32_t` array. + uint32_t packed[(kMaxRegArgsPerGroup + 3) / 4]; + }; + + //! Passed registers' order, per register group. + RegOrder _passedOrder[BaseReg::kGroupVirt]; + + //! Calling convention id. + //! + //! Calling conventions can be divided into the following groups: + //! + //! - Universal - calling conventions are applicable to any target. They + //! will be converted to a target dependent calling convention at runtime + //! by \ref init(). The purpose of these conventions is to make using + //! functions less target dependent and closer to how they are declared + //! in C and C++. + //! + //! - Target specific - calling conventions that are used by a particular + //! architecture and ABI. For example Windows 64-bit calling convention + //! and AMD64 SystemV calling convention. + enum Id : uint32_t { + //! None or invalid (can't be used). + kIdNone = 0, + + // ------------------------------------------------------------------------ + // [Universal Calling Conventions] + // ------------------------------------------------------------------------ + + //! Standard function call or explicit `__cdecl` where it can be specified. + //! + //! This is a universal calling convention, which is used to initialize + //! specific calling connventions based on architecture, platform, and its ABI. + kIdCDecl = 1, + + //! `__stdcall` on targets that support this calling convention (X86). + //! + //! \note This calling convention is only supported on 32-bit X86. If used + //! on environment that doesn't support this calling convention it will be + //! replaced by \ref kIdCDecl. + kIdStdCall = 2, + + //! `__fastcall` on targets that support this calling convention (X86). + //! + //! \note This calling convention is only supported on 32-bit X86. If used + //! on environment that doesn't support this calling convention it will be + //! replaced by \ref kIdCDecl. + kIdFastCall = 3, + + //! `__vectorcall` on targets that support this calling convention (X86/X64). + //! + //! \note This calling convention is only supported on 32-bit and 64-bit + //! X86 architecture on Windows platform. If used on environment that doesn't + //! support this calling it will be replaced by \ref kIdCDecl. + kIdVectorCall = 4, + + //! `__thiscall` on targets that support this calling convention (X86). + //! + //! \note This calling convention is only supported on 32-bit X86 Windows + //! platform. If used on environment that doesn't support this calling + //! convention it will be replaced by \ref kIdCDecl. + kIdThisCall = 5, + + //! `__attribute__((regparm(1)))` convention (GCC and Clang). + kIdRegParm1 = 6, + //! `__attribute__((regparm(2)))` convention (GCC and Clang). + kIdRegParm2 = 7, + //! `__attribute__((regparm(3)))` convention (GCC and Clang). + kIdRegParm3 = 8, + + //! Soft-float calling convention (ARM). + //! + //! Floating point arguments are passed via general purpose registers. + kIdSoftFloat = 9, + + //! Hard-float calling convention (ARM). + //! + //! Floating point arguments are passed via SIMD registers. + kIdHardFloat = 10, + + //! AsmJit specific calling convention designed for calling functions + //! inside a multimedia code that don't use many registers internally, + //! but are long enough to be called and not inlined. These functions are + //! usually used to calculate trigonometric functions, logarithms, etc... + kIdLightCall2 = 16, + kIdLightCall3 = 17, + kIdLightCall4 = 18, + + // ------------------------------------------------------------------------ + // [ABI-Specific Calling Conventions] + // ------------------------------------------------------------------------ + + //! X64 System-V calling convention. + kIdX64SystemV = 32, + //! X64 Windows calling convention. + kIdX64Windows = 33, + + // ------------------------------------------------------------------------ + // [Host] + // ------------------------------------------------------------------------ + + //! Host calling convention detected at compile-time. + kIdHost = +#if ASMJIT_ARCH_ARM == 32 && defined(__SOFTFP__) + kIdSoftFloat +#elif ASMJIT_ARCH_ARM == 32 && !defined(__SOFTFP__) + kIdHardFloat +#else + kIdCDecl +#endif + +#ifndef ASMJIT_NO_DEPRECATE + , kIdHostCDecl = kIdCDecl + , kIdHostStdCall = kIdStdCall + , kIdHostFastCall = kIdFastCall + , kIdHostLightCall2 = kIdLightCall2 + , kIdHostLightCall3 = kIdLightCall3 + , kIdHostLightCall4 = kIdLightCall4 +#endif // !ASMJIT_NO_DEPRECATE + }; + + //! Strategy used to assign registers to function arguments. + //! + //! This is AsmJit specific. It basically describes how AsmJit should convert + //! the function arguments defined by `FuncSignature` into register IDs and + //! stack offsets. The default strategy `kStrategyDefault` assigns registers + //! and then stack whereas `kStrategyWin64` strategy does register shadowing + //! as defined by WIN64 calling convention - it applies to 64-bit calling + //! conventions only. + enum Strategy : uint32_t { + //! Default register assignment strategy. + kStrategyDefault = 0, + //! Windows 64-bit ABI register assignment strategy. + kStrategyX64Windows = 1, + //! Windows 64-bit __vectorcall register assignment strategy. + kStrategyX64VectorCall = 2, + + //! Number of assignment strategies. + kStrategyCount = 3 + }; + + //! Calling convention flags. + enum Flags : uint32_t { + //! Callee is responsible for cleaning up the stack. + kFlagCalleePopsStack = 0x0001u, + //! Pass vector arguments indirectly (as a pointer). + kFlagIndirectVecArgs = 0x0002u, + //! Pass F32 and F64 arguments via VEC128 register. + kFlagPassFloatsByVec = 0x0004u, + //! Pass MMX and vector arguments via stack if the function has variable arguments. + kFlagPassVecByStackIfVA = 0x0008u, + //! MMX registers are passed and returned via GP registers. + kFlagPassMmxByGp = 0x0010u, + //! MMX registers are passed and returned via XMM registers. + kFlagPassMmxByXmm = 0x0020u, + //! Calling convention can be used with variable arguments. + kFlagVarArgCompatible = 0x0080u + }; + + //! \name Construction & Destruction + //! \{ + + //! Initializes this calling convention to the given `ccId` based on the + //! `environment`. + //! + //! See \ref Id and \ref Environment for more details. + ASMJIT_API Error init(uint32_t ccId, const Environment& environment) noexcept; + + //! Resets this CallConv struct into a defined state. + //! + //! It's recommended to reset the \ref CallConv struct in case you would + //! like create a custom calling convention as it prevents from using an + //! uninitialized data (CallConv doesn't have a constructor that would + //! initialize it, it's just a struct). + inline void reset() noexcept { + memset(this, 0, sizeof(*this)); + memset(_passedOrder, 0xFF, sizeof(_passedOrder)); + } + + //! \} + + //! \name Accessors + //! \{ + + //! Returns the calling convention id, see `Id`. + inline uint32_t id() const noexcept { return _id; } + //! Sets the calling convention id, see `Id`. + inline void setId(uint32_t id) noexcept { _id = uint8_t(id); } + + //! Returns the calling function architecture id. + inline uint32_t arch() const noexcept { return _arch; } + //! Sets the calling function architecture id. + inline void setArch(uint32_t arch) noexcept { _arch = uint8_t(arch); } + + //! Returns the strategy used to assign registers to arguments, see `Strategy`. + inline uint32_t strategy() const noexcept { return _strategy; } + //! Sets the strategy used to assign registers to arguments, see `Strategy`. + inline void setStrategy(uint32_t strategy) noexcept { _strategy = uint8_t(strategy); } + + //! Tests whether the calling convention has the given `flag` set. + inline bool hasFlag(uint32_t flag) const noexcept { return (uint32_t(_flags) & flag) != 0; } + //! Returns the calling convention flags, see `Flags`. + inline uint32_t flags() const noexcept { return _flags; } + //! Adds the calling convention flags, see `Flags`. + inline void setFlags(uint32_t flag) noexcept { _flags = uint16_t(flag); }; + //! Adds the calling convention flags, see `Flags`. + inline void addFlags(uint32_t flags) noexcept { _flags = uint16_t(_flags | flags); }; + + //! Tests whether this calling convention specifies 'RedZone'. + inline bool hasRedZone() const noexcept { return _redZoneSize != 0; } + //! Tests whether this calling convention specifies 'SpillZone'. + inline bool hasSpillZone() const noexcept { return _spillZoneSize != 0; } + + //! Returns size of 'RedZone'. + inline uint32_t redZoneSize() const noexcept { return _redZoneSize; } + //! Returns size of 'SpillZone'. + inline uint32_t spillZoneSize() const noexcept { return _spillZoneSize; } + + //! Sets size of 'RedZone'. + inline void setRedZoneSize(uint32_t size) noexcept { _redZoneSize = uint8_t(size); } + //! Sets size of 'SpillZone'. + inline void setSpillZoneSize(uint32_t size) noexcept { _spillZoneSize = uint8_t(size); } + + //! Returns a natural stack alignment. + inline uint32_t naturalStackAlignment() const noexcept { return _naturalStackAlignment; } + //! Sets a natural stack alignment. + //! + //! This function can be used to override the default stack alignment in case + //! that you know that it's alignment is different. For example it allows to + //! implement custom calling conventions that guarantee higher stack alignment. + inline void setNaturalStackAlignment(uint32_t value) noexcept { _naturalStackAlignment = uint8_t(value); } + + //! Returns the size of a register (or its part) to be saved and restored of the given `group`. + inline uint32_t saveRestoreRegSize(uint32_t group) const noexcept { return _saveRestoreRegSize[group]; } + //! Sets the size of a vector register (or its part) to be saved and restored. + inline void setSaveRestoreRegSize(uint32_t group, uint32_t size) noexcept { _saveRestoreRegSize[group] = uint8_t(size); } + + //! Returns the alignment of a save-restore area of the given `group`. + inline uint32_t saveRestoreAlignment(uint32_t group) const noexcept { return _saveRestoreAlignment[group]; } + //! Sets the alignment of a save-restore area of the given `group`. + inline void setSaveRestoreAlignment(uint32_t group, uint32_t alignment) noexcept { _saveRestoreAlignment[group] = uint8_t(alignment); } + + //! Returns the order of passed registers of the given `group`, see \ref BaseReg::RegGroup. + inline const uint8_t* passedOrder(uint32_t group) const noexcept { + ASMJIT_ASSERT(group < BaseReg::kGroupVirt); + return _passedOrder[group].id; + } + + //! Returns the mask of passed registers of the given `group`, see \ref BaseReg::RegGroup. + inline uint32_t passedRegs(uint32_t group) const noexcept { + ASMJIT_ASSERT(group < BaseReg::kGroupVirt); + return _passedRegs[group]; + } + + inline void _setPassedPacked(uint32_t group, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3) noexcept { + ASMJIT_ASSERT(group < BaseReg::kGroupVirt); + + _passedOrder[group].packed[0] = p0; + _passedOrder[group].packed[1] = p1; + _passedOrder[group].packed[2] = p2; + _passedOrder[group].packed[3] = p3; + } + + //! Resets the order and mask of passed registers. + inline void setPassedToNone(uint32_t group) noexcept { + ASMJIT_ASSERT(group < BaseReg::kGroupVirt); + + _setPassedPacked(group, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu); + _passedRegs[group] = 0u; + } + + //! Sets the order and mask of passed registers. + inline void setPassedOrder(uint32_t group, uint32_t a0, uint32_t a1 = 0xFF, uint32_t a2 = 0xFF, uint32_t a3 = 0xFF, uint32_t a4 = 0xFF, uint32_t a5 = 0xFF, uint32_t a6 = 0xFF, uint32_t a7 = 0xFF) noexcept { + ASMJIT_ASSERT(group < BaseReg::kGroupVirt); + + // NOTE: This should always be called with all arguments known at compile time, + // so even if it looks scary it should be translated into few instructions. + _setPassedPacked(group, Support::bytepack32_4x8(a0, a1, a2, a3), + Support::bytepack32_4x8(a4, a5, a6, a7), + 0xFFFFFFFFu, + 0xFFFFFFFFu); + + _passedRegs[group] = (a0 != 0xFF ? 1u << a0 : 0u) | + (a1 != 0xFF ? 1u << a1 : 0u) | + (a2 != 0xFF ? 1u << a2 : 0u) | + (a3 != 0xFF ? 1u << a3 : 0u) | + (a4 != 0xFF ? 1u << a4 : 0u) | + (a5 != 0xFF ? 1u << a5 : 0u) | + (a6 != 0xFF ? 1u << a6 : 0u) | + (a7 != 0xFF ? 1u << a7 : 0u) ; + } + + //! Returns preserved register mask of the given `group`, see \ref BaseReg::RegGroup. + inline uint32_t preservedRegs(uint32_t group) const noexcept { + ASMJIT_ASSERT(group < BaseReg::kGroupVirt); + return _preservedRegs[group]; + } + + //! Sets preserved register mask of the given `group`, see \ref BaseReg::RegGroup. + inline void setPreservedRegs(uint32_t group, uint32_t regs) noexcept { + ASMJIT_ASSERT(group < BaseReg::kGroupVirt); + _preservedRegs[group] = regs; + } + + //! \} +}; + +// ============================================================================ +// [asmjit::FuncSignature] +// ============================================================================ + +//! Function signature. +//! +//! Contains information about function return type, count of arguments and +//! their TypeIds. Function signature is a low level structure which doesn't +//! contain platform specific or calling convention specific information. +struct FuncSignature { + //! Calling convention id. + uint8_t _callConv; + //! Count of arguments. + uint8_t _argCount; + //! Index of a first VA or `kNoVarArgs`. + uint8_t _vaIndex; + //! Return value TypeId. + uint8_t _ret; + //! Function arguments TypeIds. + const uint8_t* _args; + + enum : uint8_t { + //! Doesn't have variable number of arguments (`...`). + kNoVarArgs = 0xFF + }; + + //! \name Initializtion & Reset + //! \{ + + //! Initializes the function signature. + inline void init(uint32_t ccId, uint32_t vaIndex, uint32_t ret, const uint8_t* args, uint32_t argCount) noexcept { + ASMJIT_ASSERT(ccId <= 0xFF); + ASMJIT_ASSERT(argCount <= 0xFF); + + _callConv = uint8_t(ccId); + _argCount = uint8_t(argCount); + _vaIndex = uint8_t(vaIndex); + _ret = uint8_t(ret); + _args = args; + } + + inline void reset() noexcept { memset(this, 0, sizeof(*this)); } + + //! \} + + //! \name Accessors + //! \{ + + //! Returns the calling convention. + inline uint32_t callConv() const noexcept { return _callConv; } + //! Sets the calling convention to `ccId`; + inline void setCallConv(uint32_t ccId) noexcept { _callConv = uint8_t(ccId); } + + //! Tests whether the function has variable number of arguments (...). + inline bool hasVarArgs() const noexcept { return _vaIndex != kNoVarArgs; } + //! Returns the variable arguments (...) index, `kNoVarArgs` if none. + inline uint32_t vaIndex() const noexcept { return _vaIndex; } + //! Sets the variable arguments (...) index to `index`. + inline void setVaIndex(uint32_t index) noexcept { _vaIndex = uint8_t(index); } + //! Resets the variable arguments index (making it a non-va function). + inline void resetVaIndex() noexcept { _vaIndex = kNoVarArgs; } + + //! Returns the number of function arguments. + inline uint32_t argCount() const noexcept { return _argCount; } + + inline bool hasRet() const noexcept { return _ret != Type::kIdVoid; } + //! Returns the return value type. + inline uint32_t ret() const noexcept { return _ret; } + + //! Returns the type of the argument at index `i`. + inline uint32_t arg(uint32_t i) const noexcept { + ASMJIT_ASSERT(i < _argCount); + return _args[i]; + } + //! Returns the array of function arguments' types. + inline const uint8_t* args() const noexcept { return _args; } + + //! \} +}; + +// ============================================================================ +// [asmjit::FuncSignatureT] +// ============================================================================ + +template +class FuncSignatureT : public FuncSignature { +public: + inline FuncSignatureT(uint32_t ccId = CallConv::kIdHost, uint32_t vaIndex = kNoVarArgs) noexcept { + static const uint8_t ret_args[] = { (uint8_t(Type::IdOfT::kTypeId))... }; + init(ccId, vaIndex, ret_args[0], ret_args + 1, uint32_t(ASMJIT_ARRAY_SIZE(ret_args) - 1)); + } +}; + +// ============================================================================ +// [asmjit::FuncSignatureBuilder] +// ============================================================================ + +//! Function signature builder. +class FuncSignatureBuilder : public FuncSignature { +public: + uint8_t _builderArgList[Globals::kMaxFuncArgs]; + + //! \name Initializtion & Reset + //! \{ + + inline FuncSignatureBuilder(uint32_t ccId = CallConv::kIdHost, uint32_t vaIndex = kNoVarArgs) noexcept { + init(ccId, vaIndex, Type::kIdVoid, _builderArgList, 0); + } + + //! \} + + //! \name Accessors + //! \{ + + //! Sets the return type to `retType`. + inline void setRet(uint32_t retType) noexcept { _ret = uint8_t(retType); } + //! Sets the return type based on `T`. + template + inline void setRetT() noexcept { setRet(Type::IdOfT::kTypeId); } + + //! Sets the argument at index `index` to `argType`. + inline void setArg(uint32_t index, uint32_t argType) noexcept { + ASMJIT_ASSERT(index < _argCount); + _builderArgList[index] = uint8_t(argType); + } + //! Sets the argument at index `i` to the type based on `T`. + template + inline void setArgT(uint32_t index) noexcept { setArg(index, Type::IdOfT::kTypeId); } + + //! Appends an argument of `type` to the function prototype. + inline void addArg(uint32_t type) noexcept { + ASMJIT_ASSERT(_argCount < Globals::kMaxFuncArgs); + _builderArgList[_argCount++] = uint8_t(type); + } + //! Appends an argument of type based on `T` to the function prototype. + template + inline void addArgT() noexcept { addArg(Type::IdOfT::kTypeId); } + + //! \} +}; + +// ============================================================================ +// [asmjit::FuncValue] +// ============================================================================ + +//! Argument or return value (or its part) as defined by `FuncSignature`, but +//! with register or stack address (and other metadata) assigned. +struct FuncValue { + uint32_t _data; + + enum Parts : uint32_t { + kTypeIdShift = 0, //!< TypeId shift. + kTypeIdMask = 0x000000FFu, //!< TypeId mask. + + kFlagIsReg = 0x00000100u, //!< Passed by register. + kFlagIsStack = 0x00000200u, //!< Passed by stack. + kFlagIsIndirect = 0x00000400u, //!< Passed indirectly by reference (internally a pointer). + kFlagIsDone = 0x00000800u, //!< Used internally by arguments allocator. + + kStackOffsetShift = 12, //!< Stack offset shift. + kStackOffsetMask = 0xFFFFF000u, //!< Stack offset mask (must occupy MSB bits). + + kRegIdShift = 16, //!< RegId shift. + kRegIdMask = 0x00FF0000u, //!< RegId mask. + + kRegTypeShift = 24, //!< RegType shift. + kRegTypeMask = 0xFF000000u //!< RegType mask. + }; + + //! \name Initializtion & Reset + //! \{ + + // These initialize the whole `FuncValue` to either register or stack. Useful + // when you know all of these properties and wanna just set it up. + + //! Initializes the `typeId` of this `FuncValue`. + inline void initTypeId(uint32_t typeId) noexcept { + _data = typeId << kTypeIdShift; + } + + inline void initReg(uint32_t regType, uint32_t regId, uint32_t typeId, uint32_t flags = 0) noexcept { + _data = (regType << kRegTypeShift) | (regId << kRegIdShift) | (typeId << kTypeIdShift) | kFlagIsReg | flags; + } + + inline void initStack(int32_t offset, uint32_t typeId) noexcept { + _data = (uint32_t(offset) << kStackOffsetShift) | (typeId << kTypeIdShift) | kFlagIsStack; + } + + //! Resets the value to its unassigned state. + inline void reset() noexcept { _data = 0; } + + //! \} + + //! \name Assign + //! \{ + + // These initialize only part of `FuncValue`, useful when building `FuncValue` + // incrementally. The caller should first init the type-id by caliing `initTypeId` + // and then continue building either register or stack. + + inline void assignRegData(uint32_t regType, uint32_t regId) noexcept { + ASMJIT_ASSERT((_data & (kRegTypeMask | kRegIdMask)) == 0); + _data |= (regType << kRegTypeShift) | (regId << kRegIdShift) | kFlagIsReg; + } + + inline void assignStackOffset(int32_t offset) noexcept { + ASMJIT_ASSERT((_data & kStackOffsetMask) == 0); + _data |= (uint32_t(offset) << kStackOffsetShift) | kFlagIsStack; + } + + //! \} + + //! \name Accessors + //! \{ + + inline explicit operator bool() const noexcept { return _data != 0; } + + inline void _replaceValue(uint32_t mask, uint32_t value) noexcept { _data = (_data & ~mask) | value; } + + //! Tests whether the `FuncValue` has a flag `flag` set. + inline bool hasFlag(uint32_t flag) const noexcept { return (_data & flag) != 0; } + //! Adds `flags` to `FuncValue`. + inline void addFlags(uint32_t flags) noexcept { _data |= flags; } + //! Clears `flags` of `FuncValue`. + inline void clearFlags(uint32_t flags) noexcept { _data &= ~flags; } + + //! Tests whether the value is initialized (i.e. contains a valid data). + inline bool isInitialized() const noexcept { return _data != 0; } + //! Tests whether the argument is passed by register. + inline bool isReg() const noexcept { return hasFlag(kFlagIsReg); } + //! Tests whether the argument is passed by stack. + inline bool isStack() const noexcept { return hasFlag(kFlagIsStack); } + //! Tests whether the argument is passed by register. + inline bool isAssigned() const noexcept { return hasFlag(kFlagIsReg | kFlagIsStack); } + //! Tests whether the argument is passed through a pointer (used by WIN64 to pass XMM|YMM|ZMM). + inline bool isIndirect() const noexcept { return hasFlag(kFlagIsIndirect); } + + //! Tests whether the argument was already processed (used internally). + inline bool isDone() const noexcept { return hasFlag(kFlagIsDone); } + + //! Returns a register type of the register used to pass function argument or return value. + inline uint32_t regType() const noexcept { return (_data & kRegTypeMask) >> kRegTypeShift; } + //! Sets a register type of the register used to pass function argument or return value. + inline void setRegType(uint32_t regType) noexcept { _replaceValue(kRegTypeMask, regType << kRegTypeShift); } + + //! Returns a physical id of the register used to pass function argument or return value. + inline uint32_t regId() const noexcept { return (_data & kRegIdMask) >> kRegIdShift; } + //! Sets a physical id of the register used to pass function argument or return value. + inline void setRegId(uint32_t regId) noexcept { _replaceValue(kRegIdMask, regId << kRegIdShift); } + + //! Returns a stack offset of this argument. + inline int32_t stackOffset() const noexcept { return int32_t(_data & kStackOffsetMask) >> kStackOffsetShift; } + //! Sets a stack offset of this argument. + inline void setStackOffset(int32_t offset) noexcept { _replaceValue(kStackOffsetMask, uint32_t(offset) << kStackOffsetShift); } + + //! Tests whether the argument or return value has associated `Type::Id`. + inline bool hasTypeId() const noexcept { return (_data & kTypeIdMask) != 0; } + //! Returns a TypeId of this argument or return value. + inline uint32_t typeId() const noexcept { return (_data & kTypeIdMask) >> kTypeIdShift; } + //! Sets a TypeId of this argument or return value. + inline void setTypeId(uint32_t typeId) noexcept { _replaceValue(kTypeIdMask, typeId << kTypeIdShift); } + + //! \} +}; + +// ============================================================================ +// [asmjit::FuncValuePack] +// ============================================================================ + +//! Contains multiple `FuncValue` instances in an array so functions that use +//! multiple registers for arguments or return values can represent all inputs +//! and outputs. +struct FuncValuePack { +public: + //! Values data. + FuncValue _values[Globals::kMaxValuePack]; + + inline void reset() noexcept { + for (size_t i = 0; i < Globals::kMaxValuePack; i++) + _values[i].reset(); + } + + //! Calculates how many values are in the pack, checking for non-values + //! from the end. + inline uint32_t count() const noexcept { + uint32_t n = Globals::kMaxValuePack; + while (n && !_values[n - 1]) + n--; + return n; + } + + inline FuncValue* values() noexcept { return _values; } + inline const FuncValue* values() const noexcept { return _values; } + + inline void resetValue(size_t index) noexcept { + ASMJIT_ASSERT(index < Globals::kMaxValuePack); + _values[index].reset(); + } + + inline bool hasValue(size_t index) noexcept { + ASMJIT_ASSERT(index < Globals::kMaxValuePack); + return _values[index].isInitialized(); + } + + inline void assignReg(size_t index, const BaseReg& reg, uint32_t typeId = Type::kIdVoid) noexcept { + ASMJIT_ASSERT(index < Globals::kMaxValuePack); + ASMJIT_ASSERT(reg.isPhysReg()); + _values[index].initReg(reg.type(), reg.id(), typeId); + } + + inline void assignReg(size_t index, uint32_t regType, uint32_t regId, uint32_t typeId = Type::kIdVoid) noexcept { + ASMJIT_ASSERT(index < Globals::kMaxValuePack); + _values[index].initReg(regType, regId, typeId); + } + + inline void assignStack(size_t index, int32_t offset, uint32_t typeId = Type::kIdVoid) noexcept { + ASMJIT_ASSERT(index < Globals::kMaxValuePack); + _values[index].initStack(offset, typeId); + } + + inline FuncValue& operator[](size_t index) { + ASMJIT_ASSERT(index < Globals::kMaxValuePack); + return _values[index]; + } + + inline const FuncValue& operator[](size_t index) const { + ASMJIT_ASSERT(index < Globals::kMaxValuePack); + return _values[index]; + } +}; + +// ============================================================================ +// [asmjit::FuncDetail] +// ============================================================================ + +//! Function detail - CallConv and expanded FuncSignature. +//! +//! Function detail is architecture and OS dependent representation of a function. +//! It contains calling convention and expanded function signature so all +//! arguments have assigned either register type & id or stack address. +class FuncDetail { +public: + //! Calling convention. + CallConv _callConv; + //! Number of function arguments. + uint8_t _argCount; + //! Variable arguments index of `kNoVarArgs`. + uint8_t _vaIndex; + //! Reserved for future use. + uint16_t _reserved; + //! Registers that contains arguments. + uint32_t _usedRegs[BaseReg::kGroupVirt]; + //! Size of arguments passed by stack. + uint32_t _argStackSize; + //! Function return value(s). + FuncValuePack _rets; + //! Function arguments. + FuncValuePack _args[Globals::kMaxFuncArgs]; + + enum : uint8_t { + //! Doesn't have variable number of arguments (`...`). + kNoVarArgs = 0xFF + }; + + //! \name Construction & Destruction + //! \{ + + inline FuncDetail() noexcept { reset(); } + inline FuncDetail(const FuncDetail& other) noexcept = default; + + //! Initializes this `FuncDetail` to the given signature. + ASMJIT_API Error init(const FuncSignature& signature, const Environment& environment) noexcept; + inline void reset() noexcept { memset(this, 0, sizeof(*this)); } + + //! \} + + //! \name Accessors + //! \{ + + //! Returns the function's calling convention, see `CallConv`. + inline const CallConv& callConv() const noexcept { return _callConv; } + + //! Returns the associated calling convention flags, see `CallConv::Flags`. + inline uint32_t flags() const noexcept { return _callConv.flags(); } + //! Checks whether a CallConv `flag` is set, see `CallConv::Flags`. + inline bool hasFlag(uint32_t ccFlag) const noexcept { return _callConv.hasFlag(ccFlag); } + + //! Tests whether the function has a return value. + inline bool hasRet() const noexcept { return bool(_rets[0]); } + //! Returns the number of function arguments. + inline uint32_t argCount() const noexcept { return _argCount; } + + //! Returns function return values. + inline FuncValuePack& retPack() noexcept { return _rets; } + //! Returns function return values. + inline const FuncValuePack& retPack() const noexcept { return _rets; } + + //! Returns a function return value associated with the given `valueIndex`. + inline FuncValue& ret(size_t valueIndex = 0) noexcept { return _rets[valueIndex]; } + //! Returns a function return value associated with the given `valueIndex` (const). + inline const FuncValue& ret(size_t valueIndex = 0) const noexcept { return _rets[valueIndex]; } + + //! Returns function argument packs array. + inline FuncValuePack* argPacks() noexcept { return _args; } + //! Returns function argument packs array (const). + inline const FuncValuePack* argPacks() const noexcept { return _args; } + + //! Returns function argument pack at the given `argIndex`. + inline FuncValuePack& argPack(size_t argIndex) noexcept { + ASMJIT_ASSERT(argIndex < Globals::kMaxFuncArgs); + return _args[argIndex]; + } + + //! Returns function argument pack at the given `argIndex` (const). + inline const FuncValuePack& argPack(size_t argIndex) const noexcept { + ASMJIT_ASSERT(argIndex < Globals::kMaxFuncArgs); + return _args[argIndex]; + } + + //! Returns an argument at `valueIndex` from the argument pack at the given `argIndex`. + inline FuncValue& arg(size_t argIndex, size_t valueIndex = 0) noexcept { + ASMJIT_ASSERT(argIndex < Globals::kMaxFuncArgs); + return _args[argIndex][valueIndex]; + } + + //! Returns an argument at `valueIndex` from the argument pack at the given `argIndex` (const). + inline const FuncValue& arg(size_t argIndex, size_t valueIndex = 0) const noexcept { + ASMJIT_ASSERT(argIndex < Globals::kMaxFuncArgs); + return _args[argIndex][valueIndex]; + } + + //! Resets an argument at the given `argIndex`. + //! + //! If the argument is a parameter pack (has multiple values) all values are reset. + inline void resetArg(size_t argIndex) noexcept { + ASMJIT_ASSERT(argIndex < Globals::kMaxFuncArgs); + _args[argIndex].reset(); + } + + //! Tests whether the function has variable arguments. + inline bool hasVarArgs() const noexcept { return _vaIndex != kNoVarArgs; } + //! Returns an index of a first variable argument. + inline uint32_t vaIndex() const noexcept { return _vaIndex; } + + //! Tests whether the function passes one or more argument by stack. + inline bool hasStackArgs() const noexcept { return _argStackSize != 0; } + //! Returns stack size needed for function arguments passed on the stack. + inline uint32_t argStackSize() const noexcept { return _argStackSize; } + + //! Returns red zone size. + inline uint32_t redZoneSize() const noexcept { return _callConv.redZoneSize(); } + //! Returns spill zone size. + inline uint32_t spillZoneSize() const noexcept { return _callConv.spillZoneSize(); } + //! Returns natural stack alignment. + inline uint32_t naturalStackAlignment() const noexcept { return _callConv.naturalStackAlignment(); } + + //! Returns a mask of all passed registers of the given register `group`. + inline uint32_t passedRegs(uint32_t group) const noexcept { return _callConv.passedRegs(group); } + //! Returns a mask of all preserved registers of the given register `group`. + inline uint32_t preservedRegs(uint32_t group) const noexcept { return _callConv.preservedRegs(group); } + + //! Returns a mask of all used registers of the given register `group`. + inline uint32_t usedRegs(uint32_t group) const noexcept { + ASMJIT_ASSERT(group < BaseReg::kGroupVirt); + return _usedRegs[group]; + } + + //! Adds `regs` to the mask of used registers of the given register `group`. + inline void addUsedRegs(uint32_t group, uint32_t regs) noexcept { + ASMJIT_ASSERT(group < BaseReg::kGroupVirt); + _usedRegs[group] |= regs; + } + + //! \} +}; + +// ============================================================================ +// [asmjit::FuncFrame] +// ============================================================================ + +//! Function frame. +//! +//! Function frame is used directly by prolog and epilog insertion (PEI) utils. +//! It provides information necessary to insert a proper and ABI comforming +//! prolog and epilog. Function frame calculation is based on `CallConv` and +//! other function attributes. +//! +//! Function Frame Structure +//! ------------------------ +//! +//! Various properties can contribute to the size and structure of the function +//! frame. The function frame in most cases won't use all of the properties +//! illustrated (for example Spill Zone and Red Zone are never used together). +//! +//! ``` +//! +-----------------------------+ +//! | Arguments Passed by Stack | +//! +-----------------------------+ +//! | Spill Zone | +//! +-----------------------------+ <- Stack offset (args) starts from here. +//! | Return Address, if Pushed | +//! +-----------------------------+ <- Stack pointer (SP) upon entry. +//! | Save/Restore Stack. | +//! +-----------------------------+-----------------------------+ +//! | Local Stack | | +//! +-----------------------------+ Final Stack | +//! | Call Stack | | +//! +-----------------------------+-----------------------------+ <- SP after prolog. +//! | Red Zone | +//! +-----------------------------+ +//! ``` +class FuncFrame { +public: + enum Tag : uint32_t { + //! Tag used to inform that some offset is invalid. + kTagInvalidOffset = 0xFFFFFFFFu + }; + + //! Attributes are designed in a way that all are initially false, and user + //! or FuncFrame finalizer adds them when necessary. + enum Attributes : uint32_t { + //! Function has variable number of arguments. + kAttrHasVarArgs = 0x00000001u, + //! Preserve frame pointer (don't omit FP). + kAttrHasPreservedFP = 0x00000010u, + //! Function calls other functions (is not leaf). + kAttrHasFuncCalls = 0x00000020u, + + //! Use AVX instead of SSE for all operations (X86). + kAttrX86AvxEnabled = 0x00010000u, + //! Emit VZEROUPPER instruction in epilog (X86). + kAttrX86AvxCleanup = 0x00020000u, + //! Emit EMMS instruction in epilog (X86). + kAttrX86MmxCleanup = 0x00040000u, + + //! Function has aligned save/restore of vector registers. + kAttrAlignedVecSR = 0x40000000u, + //! FuncFrame is finalized and can be used by PEI. + kAttrIsFinalized = 0x80000000u + }; + + //! Function attributes. + uint32_t _attributes; + + //! Architecture, see \ref Environment::Arch. + uint8_t _arch; + //! SP register ID (to access call stack and local stack). + uint8_t _spRegId; + //! SA register ID (to access stack arguments). + uint8_t _saRegId; + + //! Red zone size (copied from CallConv). + uint8_t _redZoneSize; + //! Spill zone size (copied from CallConv). + uint8_t _spillZoneSize; + //! Natural stack alignment (copied from CallConv). + uint8_t _naturalStackAlignment; + //! Minimum stack alignment to turn on dynamic alignment. + uint8_t _minDynamicAlignment; + + //! Call stack alignment. + uint8_t _callStackAlignment; + //! Local stack alignment. + uint8_t _localStackAlignment; + //! Final stack alignment. + uint8_t _finalStackAlignment; + + //! Adjustment of the stack before returning (X86-STDCALL). + uint16_t _calleeStackCleanup; + + //! Call stack size. + uint32_t _callStackSize; + //! Local stack size. + uint32_t _localStackSize; + //! Final stack size (sum of call stack and local stack). + uint32_t _finalStackSize; + + //! Local stack offset (non-zero only if call stack is used). + uint32_t _localStackOffset; + //! Offset relative to SP that contains previous SP (before alignment). + uint32_t _daOffset; + //! Offset of the first stack argument relative to SP. + uint32_t _saOffsetFromSP; + //! Offset of the first stack argument relative to SA (_saRegId or FP). + uint32_t _saOffsetFromSA; + + //! Local stack adjustment in prolog/epilog. + uint32_t _stackAdjustment; + + //! Registers that are dirty. + uint32_t _dirtyRegs[BaseReg::kGroupVirt]; + //! Registers that must be preserved (copied from CallConv). + uint32_t _preservedRegs[BaseReg::kGroupVirt]; + //! Size to save/restore per register group. + uint8_t _saveRestoreRegSize[BaseReg::kGroupVirt]; + //! Alignment of save/restore area per register group. + uint8_t _saveRestoreAlignment[BaseReg::kGroupVirt]; + + //! Stack size required to save registers with push/pop. + uint16_t _pushPopSaveSize; + //! Stack size required to save extra registers that cannot use push/pop. + uint16_t _extraRegSaveSize; + //! Offset where registers saved/restored via push/pop are stored + uint32_t _pushPopSaveOffset; + //! Offset where extra ragisters that cannot use push/pop are stored. + uint32_t _extraRegSaveOffset; + + //! \name Construction & Destruction + //! \{ + + inline FuncFrame() noexcept { reset(); } + inline FuncFrame(const FuncFrame& other) noexcept = default; + + ASMJIT_API Error init(const FuncDetail& func) noexcept; + + inline void reset() noexcept { + memset(this, 0, sizeof(FuncFrame)); + _spRegId = BaseReg::kIdBad; + _saRegId = BaseReg::kIdBad; + _daOffset = kTagInvalidOffset; + } + + //! \} + + //! \name Accessors + //! \{ + + //! Returns the target architecture of the function frame. + inline uint32_t arch() const noexcept { return _arch; } + + //! Returns function frame attributes, see `Attributes`. + inline uint32_t attributes() const noexcept { return _attributes; } + //! Checks whether the FuncFame contains an attribute `attr`. + inline bool hasAttribute(uint32_t attr) const noexcept { return (_attributes & attr) != 0; } + //! Adds attributes `attrs` to the FuncFrame. + inline void addAttributes(uint32_t attrs) noexcept { _attributes |= attrs; } + //! Clears attributes `attrs` from the FrameFrame. + inline void clearAttributes(uint32_t attrs) noexcept { _attributes &= ~attrs; } + + //! Tests whether the function has variable number of arguments. + inline bool hasVarArgs() const noexcept { return hasAttribute(kAttrHasVarArgs); } + //! Sets the variable arguments flag. + inline void setVarArgs() noexcept { addAttributes(kAttrHasVarArgs); } + //! Resets variable arguments flag. + inline void resetVarArgs() noexcept { clearAttributes(kAttrHasVarArgs); } + + //! Tests whether the function preserves frame pointer (EBP|ESP on X86). + inline bool hasPreservedFP() const noexcept { return hasAttribute(kAttrHasPreservedFP); } + //! Enables preserved frame pointer. + inline void setPreservedFP() noexcept { addAttributes(kAttrHasPreservedFP); } + //! Disables preserved frame pointer. + inline void resetPreservedFP() noexcept { clearAttributes(kAttrHasPreservedFP); } + + //! Tests whether the function calls other functions. + inline bool hasFuncCalls() const noexcept { return hasAttribute(kAttrHasFuncCalls); } + //! Sets `kFlagHasCalls` to true. + inline void setFuncCalls() noexcept { addAttributes(kAttrHasFuncCalls); } + //! Sets `kFlagHasCalls` to false. + inline void resetFuncCalls() noexcept { clearAttributes(kAttrHasFuncCalls); } + + //! Tests whether the function contains AVX cleanup - 'vzeroupper' instruction in epilog. + inline bool hasAvxCleanup() const noexcept { return hasAttribute(kAttrX86AvxCleanup); } + //! Enables AVX cleanup. + inline void setAvxCleanup() noexcept { addAttributes(kAttrX86AvxCleanup); } + //! Disables AVX cleanup. + inline void resetAvxCleanup() noexcept { clearAttributes(kAttrX86AvxCleanup); } + + //! Tests whether the function contains AVX cleanup - 'vzeroupper' instruction in epilog. + inline bool isAvxEnabled() const noexcept { return hasAttribute(kAttrX86AvxEnabled); } + //! Enables AVX cleanup. + inline void setAvxEnabled() noexcept { addAttributes(kAttrX86AvxEnabled); } + //! Disables AVX cleanup. + inline void resetAvxEnabled() noexcept { clearAttributes(kAttrX86AvxEnabled); } + + //! Tests whether the function contains MMX cleanup - 'emms' instruction in epilog. + inline bool hasMmxCleanup() const noexcept { return hasAttribute(kAttrX86MmxCleanup); } + //! Enables MMX cleanup. + inline void setMmxCleanup() noexcept { addAttributes(kAttrX86MmxCleanup); } + //! Disables MMX cleanup. + inline void resetMmxCleanup() noexcept { clearAttributes(kAttrX86MmxCleanup); } + + //! Tests whether the function uses call stack. + inline bool hasCallStack() const noexcept { return _callStackSize != 0; } + //! Tests whether the function uses local stack. + inline bool hasLocalStack() const noexcept { return _localStackSize != 0; } + //! Tests whether vector registers can be saved and restored by using aligned reads and writes. + inline bool hasAlignedVecSR() const noexcept { return hasAttribute(kAttrAlignedVecSR); } + //! Tests whether the function has to align stack dynamically. + inline bool hasDynamicAlignment() const noexcept { return _finalStackAlignment >= _minDynamicAlignment; } + + //! Tests whether the calling convention specifies 'RedZone'. + inline bool hasRedZone() const noexcept { return _redZoneSize != 0; } + //! Tests whether the calling convention specifies 'SpillZone'. + inline bool hasSpillZone() const noexcept { return _spillZoneSize != 0; } + + //! Returns the size of 'RedZone'. + inline uint32_t redZoneSize() const noexcept { return _redZoneSize; } + //! Returns the size of 'SpillZone'. + inline uint32_t spillZoneSize() const noexcept { return _spillZoneSize; } + //! Returns natural stack alignment (guaranteed stack alignment upon entry). + inline uint32_t naturalStackAlignment() const noexcept { return _naturalStackAlignment; } + //! Returns natural stack alignment (guaranteed stack alignment upon entry). + inline uint32_t minDynamicAlignment() const noexcept { return _minDynamicAlignment; } + + //! Tests whether the callee must adjust SP before returning (X86-STDCALL only) + inline bool hasCalleeStackCleanup() const noexcept { return _calleeStackCleanup != 0; } + //! Returns home many bytes of the stack the the callee must adjust before returning (X86-STDCALL only) + inline uint32_t calleeStackCleanup() const noexcept { return _calleeStackCleanup; } + + //! Returns call stack alignment. + inline uint32_t callStackAlignment() const noexcept { return _callStackAlignment; } + //! Returns local stack alignment. + inline uint32_t localStackAlignment() const noexcept { return _localStackAlignment; } + //! Returns final stack alignment (the maximum value of call, local, and natural stack alignments). + inline uint32_t finalStackAlignment() const noexcept { return _finalStackAlignment; } + + //! Sets call stack alignment. + //! + //! \note This also updates the final stack alignment. + inline void setCallStackAlignment(uint32_t alignment) noexcept { + _callStackAlignment = uint8_t(alignment); + _finalStackAlignment = Support::max(_naturalStackAlignment, _callStackAlignment, _localStackAlignment); + } + + //! Sets local stack alignment. + //! + //! \note This also updates the final stack alignment. + inline void setLocalStackAlignment(uint32_t value) noexcept { + _localStackAlignment = uint8_t(value); + _finalStackAlignment = Support::max(_naturalStackAlignment, _callStackAlignment, _localStackAlignment); + } + + //! Combines call stack alignment with `alignment`, updating it to the greater value. + //! + //! \note This also updates the final stack alignment. + inline void updateCallStackAlignment(uint32_t alignment) noexcept { + _callStackAlignment = uint8_t(Support::max(_callStackAlignment, alignment)); + _finalStackAlignment = Support::max(_finalStackAlignment, _callStackAlignment); + } + + //! Combines local stack alignment with `alignment`, updating it to the greater value. + //! + //! \note This also updates the final stack alignment. + inline void updateLocalStackAlignment(uint32_t alignment) noexcept { + _localStackAlignment = uint8_t(Support::max(_localStackAlignment, alignment)); + _finalStackAlignment = Support::max(_finalStackAlignment, _localStackAlignment); + } + + //! Returns call stack size. + inline uint32_t callStackSize() const noexcept { return _callStackSize; } + //! Returns local stack size. + inline uint32_t localStackSize() const noexcept { return _localStackSize; } + + //! Sets call stack size. + inline void setCallStackSize(uint32_t size) noexcept { _callStackSize = size; } + //! Sets local stack size. + inline void setLocalStackSize(uint32_t size) noexcept { _localStackSize = size; } + + //! Combines call stack size with `size`, updating it to the greater value. + inline void updateCallStackSize(uint32_t size) noexcept { _callStackSize = Support::max(_callStackSize, size); } + //! Combines local stack size with `size`, updating it to the greater value. + inline void updateLocalStackSize(uint32_t size) noexcept { _localStackSize = Support::max(_localStackSize, size); } + + //! Returns final stack size (only valid after the FuncFrame is finalized). + inline uint32_t finalStackSize() const noexcept { return _finalStackSize; } + + //! Returns an offset to access the local stack (non-zero only if call stack is used). + inline uint32_t localStackOffset() const noexcept { return _localStackOffset; } + + //! Tests whether the function prolog/epilog requires a memory slot for storing unaligned SP. + inline bool hasDAOffset() const noexcept { return _daOffset != kTagInvalidOffset; } + //! Returns a memory offset used to store DA (dynamic alignment) slot (relative to SP). + inline uint32_t daOffset() const noexcept { return _daOffset; } + + inline uint32_t saOffset(uint32_t regId) const noexcept { + return regId == _spRegId ? saOffsetFromSP() + : saOffsetFromSA(); + } + + inline uint32_t saOffsetFromSP() const noexcept { return _saOffsetFromSP; } + inline uint32_t saOffsetFromSA() const noexcept { return _saOffsetFromSA; } + + //! Returns mask of registers of the given register `group` that are modified + //! by the function. The engine would then calculate which registers must be + //! saved & restored by the function by using the data provided by the calling + //! convention. + inline uint32_t dirtyRegs(uint32_t group) const noexcept { + ASMJIT_ASSERT(group < BaseReg::kGroupVirt); + return _dirtyRegs[group]; + } + + //! Sets which registers (as a mask) are modified by the function. + //! + //! \remarks Please note that this will completely overwrite the existing + //! register mask, use `addDirtyRegs()` to modify the existing register + //! mask. + inline void setDirtyRegs(uint32_t group, uint32_t regs) noexcept { + ASMJIT_ASSERT(group < BaseReg::kGroupVirt); + _dirtyRegs[group] = regs; + } + + //! Adds which registers (as a mask) are modified by the function. + inline void addDirtyRegs(uint32_t group, uint32_t regs) noexcept { + ASMJIT_ASSERT(group < BaseReg::kGroupVirt); + _dirtyRegs[group] |= regs; + } + + //! \overload + inline void addDirtyRegs(const BaseReg& reg) noexcept { + ASMJIT_ASSERT(reg.id() < Globals::kMaxPhysRegs); + addDirtyRegs(reg.group(), Support::bitMask(reg.id())); + } + + //! \overload + template + ASMJIT_INLINE void addDirtyRegs(const BaseReg& reg, Args&&... args) noexcept { + addDirtyRegs(reg); + addDirtyRegs(std::forward(args)...); + } + + inline void setAllDirty() noexcept { + for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_dirtyRegs); i++) + _dirtyRegs[i] = 0xFFFFFFFFu; + } + + inline void setAllDirty(uint32_t group) noexcept { + ASMJIT_ASSERT(group < BaseReg::kGroupVirt); + _dirtyRegs[group] = 0xFFFFFFFFu; + } + + //! Returns a calculated mask of registers of the given `group` that will be + //! saved and restored in the function's prolog and epilog, respectively. The + //! register mask is calculated from both `dirtyRegs` (provided by user) and + //! `preservedMask` (provided by the calling convention). + inline uint32_t savedRegs(uint32_t group) const noexcept { + ASMJIT_ASSERT(group < BaseReg::kGroupVirt); + return _dirtyRegs[group] & _preservedRegs[group]; + } + + //! Returns the mask of preserved registers of the given register `group`. + //! + //! Preserved registers are those that must survive the function call + //! unmodified. The function can only modify preserved registers it they + //! are saved and restored in funciton's prolog and epilog, respectively. + inline uint32_t preservedRegs(uint32_t group) const noexcept { + ASMJIT_ASSERT(group < BaseReg::kGroupVirt); + return _preservedRegs[group]; + } + + inline uint32_t saveRestoreRegSize(uint32_t group) const noexcept { + ASMJIT_ASSERT(group < BaseReg::kGroupVirt); + return _saveRestoreRegSize[group]; + } + + inline uint32_t saveRestoreAlignment(uint32_t group) const noexcept { + ASMJIT_ASSERT(group < BaseReg::kGroupVirt); + return _saveRestoreAlignment[group]; + } + + inline bool hasSARegId() const noexcept { return _saRegId != BaseReg::kIdBad; } + inline uint32_t saRegId() const noexcept { return _saRegId; } + inline void setSARegId(uint32_t regId) { _saRegId = uint8_t(regId); } + inline void resetSARegId() { setSARegId(BaseReg::kIdBad); } + + //! Returns stack size required to save/restore registers via push/pop. + inline uint32_t pushPopSaveSize() const noexcept { return _pushPopSaveSize; } + //! Returns an offset to the stack where registers are saved via push/pop. + inline uint32_t pushPopSaveOffset() const noexcept { return _pushPopSaveOffset; } + + //! Returns stack size required to save/restore extra registers that don't + //! use push/pop/ + //! + //! \note On X86 this covers all registers except GP registers, on other + //! architectures it can be always zero (for example AArch64 saves all + //! registers via push/pop like instructions, so this would be zero). + inline uint32_t extraRegSaveSize() const noexcept { return _extraRegSaveSize; } + //! Returns an offset to the stack where extra registers are saved. + inline uint32_t extraRegSaveOffset() const noexcept { return _extraRegSaveOffset; } + + //! Tests whether the functions contains stack adjustment. + inline bool hasStackAdjustment() const noexcept { return _stackAdjustment != 0; } + //! Returns function's stack adjustment used in function's prolog and epilog. + //! + //! If the returned value is zero it means that the stack is not adjusted. + //! This can mean both that the stack is not used and/or the stack is only + //! adjusted by instructions that pust/pop registers into/from stack. + inline uint32_t stackAdjustment() const noexcept { return _stackAdjustment; } + + //! \} + + //! \name Finaliztion + //! \{ + + ASMJIT_API Error finalize() noexcept; + + //! \} +}; + +// ============================================================================ +// [asmjit::FuncArgsAssignment] +// ============================================================================ + +//! A helper class that can be used to assign a physical register for each +//! function argument. Use with `BaseEmitter::emitArgsAssignment()`. +class FuncArgsAssignment { +public: + //! Function detail. + const FuncDetail* _funcDetail; + //! Register that can be used to access arguments passed by stack. + uint8_t _saRegId; + //! Reserved for future use. + uint8_t _reserved[3]; + //! Mapping of each function argument. + FuncValuePack _argPacks[Globals::kMaxFuncArgs]; + + //! \name Construction & Destruction + //! \{ + + inline explicit FuncArgsAssignment(const FuncDetail* fd = nullptr) noexcept { reset(fd); } + + inline FuncArgsAssignment(const FuncArgsAssignment& other) noexcept { + memcpy(this, &other, sizeof(*this)); + } + + inline void reset(const FuncDetail* fd = nullptr) noexcept { + _funcDetail = fd; + _saRegId = uint8_t(BaseReg::kIdBad); + memset(_reserved, 0, sizeof(_reserved)); + memset(_argPacks, 0, sizeof(_argPacks)); + } + + //! \} + + //! \name Accessors + //! \{ + + inline const FuncDetail* funcDetail() const noexcept { return _funcDetail; } + inline void setFuncDetail(const FuncDetail* fd) noexcept { _funcDetail = fd; } + + inline bool hasSARegId() const noexcept { return _saRegId != BaseReg::kIdBad; } + inline uint32_t saRegId() const noexcept { return _saRegId; } + inline void setSARegId(uint32_t regId) { _saRegId = uint8_t(regId); } + inline void resetSARegId() { _saRegId = uint8_t(BaseReg::kIdBad); } + + inline FuncValue& arg(size_t argIndex, size_t valueIndex) noexcept { + ASMJIT_ASSERT(argIndex < ASMJIT_ARRAY_SIZE(_argPacks)); + return _argPacks[argIndex][valueIndex]; + } + inline const FuncValue& arg(size_t argIndex, size_t valueIndex) const noexcept { + ASMJIT_ASSERT(argIndex < ASMJIT_ARRAY_SIZE(_argPacks)); + return _argPacks[argIndex][valueIndex]; + } + + inline bool isAssigned(size_t argIndex, size_t valueIndex) const noexcept { + ASMJIT_ASSERT(argIndex < ASMJIT_ARRAY_SIZE(_argPacks)); + return _argPacks[argIndex][valueIndex].isAssigned(); + } + + inline void assignReg(size_t argIndex, const BaseReg& reg, uint32_t typeId = Type::kIdVoid) noexcept { + ASMJIT_ASSERT(argIndex < ASMJIT_ARRAY_SIZE(_argPacks)); + ASMJIT_ASSERT(reg.isPhysReg()); + _argPacks[argIndex][0].initReg(reg.type(), reg.id(), typeId); + } + + inline void assignReg(size_t argIndex, uint32_t regType, uint32_t regId, uint32_t typeId = Type::kIdVoid) noexcept { + ASMJIT_ASSERT(argIndex < ASMJIT_ARRAY_SIZE(_argPacks)); + _argPacks[argIndex][0].initReg(regType, regId, typeId); + } + + inline void assignStack(size_t argIndex, int32_t offset, uint32_t typeId = Type::kIdVoid) noexcept { + ASMJIT_ASSERT(argIndex < ASMJIT_ARRAY_SIZE(_argPacks)); + _argPacks[argIndex][0].initStack(offset, typeId); + } + + inline void assignRegInPack(size_t argIndex, size_t valueIndex, const BaseReg& reg, uint32_t typeId = Type::kIdVoid) noexcept { + ASMJIT_ASSERT(argIndex < ASMJIT_ARRAY_SIZE(_argPacks)); + ASMJIT_ASSERT(reg.isPhysReg()); + _argPacks[argIndex][valueIndex].initReg(reg.type(), reg.id(), typeId); + } + + inline void assignRegInPack(size_t argIndex, size_t valueIndex, uint32_t regType, uint32_t regId, uint32_t typeId = Type::kIdVoid) noexcept { + ASMJIT_ASSERT(argIndex < ASMJIT_ARRAY_SIZE(_argPacks)); + _argPacks[argIndex][valueIndex].initReg(regType, regId, typeId); + } + + inline void assignStackInPack(size_t argIndex, size_t valueIndex, int32_t offset, uint32_t typeId = Type::kIdVoid) noexcept { + ASMJIT_ASSERT(argIndex < ASMJIT_ARRAY_SIZE(_argPacks)); + _argPacks[argIndex][valueIndex].initStack(offset, typeId); + } + + // NOTE: All `assignAll()` methods are shortcuts to assign all arguments at + // once, however, since registers are passed all at once these initializers + // don't provide any way to pass TypeId and/or to keep any argument between + // the arguments passed unassigned. + inline void _assignAllInternal(size_t argIndex, const BaseReg& reg) noexcept { + assignReg(argIndex, reg); + } + + template + inline void _assignAllInternal(size_t argIndex, const BaseReg& reg, Args&&... args) noexcept { + assignReg(argIndex, reg); + _assignAllInternal(argIndex + 1, std::forward(args)...); + } + + template + inline void assignAll(Args&&... args) noexcept { + _assignAllInternal(0, std::forward(args)...); + } + + //! \} + + //! \name Utilities + //! \{ + + //! Update `FuncFrame` based on function's arguments assignment. + //! + //! \note You MUST call this in orher to use `BaseEmitter::emitArgsAssignment()`, + //! otherwise the FuncFrame would not contain the information necessary to + //! assign all arguments into the registers and/or stack specified. + ASMJIT_API Error updateFuncFrame(FuncFrame& frame) const noexcept; + + //! \} +}; + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_FUNC_H_INCLUDED + diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/funcargscontext.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/funcargscontext.cpp new file mode 100644 index 0000000..331e205 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/funcargscontext.cpp @@ -0,0 +1,315 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/funcargscontext_p.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \cond INTERNAL +//! \addtogroup asmjit_core +//! \{ + +FuncArgsContext::FuncArgsContext() noexcept { + for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++) + _workData[group].reset(); +} + +ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, const FuncArgsAssignment& args, const RAConstraints* constraints) noexcept { + // The code has to be updated if this changes. + ASMJIT_ASSERT(BaseReg::kGroupVirt == 4); + + uint32_t i; + + uint32_t arch = frame.arch(); + const FuncDetail& func = *args.funcDetail(); + + _archTraits = &ArchTraits::byArch(arch); + _constraints = constraints; + _arch = uint8_t(arch); + + // Initialize `_archRegs`. + for (i = 0; i < BaseReg::kGroupVirt; i++) + _workData[i]._archRegs = _constraints->availableRegs(i); + + if (frame.hasPreservedFP()) + _workData[BaseReg::kGroupGp]._archRegs &= ~Support::bitMask(archTraits().fpRegId()); + + // Extract information from all function arguments/assignments and build Var[] array. + uint32_t varId = 0; + for (uint32_t argIndex = 0; argIndex < Globals::kMaxFuncArgs; argIndex++) { + for (uint32_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++) { + const FuncValue& dst_ = args.arg(argIndex, valueIndex); + if (!dst_.isAssigned()) + continue; + + const FuncValue& src_ = func.arg(argIndex, valueIndex); + if (ASMJIT_UNLIKELY(!src_.isAssigned())) + return DebugUtils::errored(kErrorInvalidState); + + Var& var = _vars[varId]; + var.init(src_, dst_); + + FuncValue& src = var.cur; + FuncValue& dst = var.out; + + uint32_t dstGroup = 0xFFFFFFFFu; + uint32_t dstId = BaseReg::kIdBad; + WorkData* dstWd = nullptr; + + // Not supported. + if (src.isIndirect()) + return DebugUtils::errored(kErrorInvalidAssignment); + + if (dst.isReg()) { + uint32_t dstType = dst.regType(); + if (ASMJIT_UNLIKELY(!archTraits().hasRegType(dstType))) + return DebugUtils::errored(kErrorInvalidRegType); + + // Copy TypeId from source if the destination doesn't have it. The RA + // used by BaseCompiler would never leave TypeId undefined, but users + // of FuncAPI can just assign phys regs without specifying the type. + if (!dst.hasTypeId()) + dst.setTypeId(archTraits().regTypeToTypeId(dst.regType())); + + dstGroup = archTraits().regTypeToGroup(dstType); + if (ASMJIT_UNLIKELY(dstGroup >= BaseReg::kGroupVirt)) + return DebugUtils::errored(kErrorInvalidRegGroup); + + dstWd = &_workData[dstGroup]; + dstId = dst.regId(); + if (ASMJIT_UNLIKELY(dstId >= 32 || !Support::bitTest(dstWd->archRegs(), dstId))) + return DebugUtils::errored(kErrorInvalidPhysId); + + if (ASMJIT_UNLIKELY(Support::bitTest(dstWd->dstRegs(), dstId))) + return DebugUtils::errored(kErrorOverlappedRegs); + + dstWd->_dstRegs |= Support::bitMask(dstId); + dstWd->_dstShuf |= Support::bitMask(dstId); + dstWd->_usedRegs |= Support::bitMask(dstId); + } + else { + if (!dst.hasTypeId()) + dst.setTypeId(src.typeId()); + + RegInfo regInfo = getSuitableRegForMemToMemMove(arch, dst.typeId(), src.typeId()); + if (ASMJIT_UNLIKELY(!regInfo.isValid())) + return DebugUtils::errored(kErrorInvalidState); + _stackDstMask = uint8_t(_stackDstMask | Support::bitMask(regInfo.group())); + } + + if (src.isReg()) { + uint32_t srcId = src.regId(); + uint32_t srcGroup = archTraits().regTypeToGroup(src.regType()); + + if (dstGroup == srcGroup) { + dstWd->assign(varId, srcId); + + // The best case, register is allocated where it is expected to be. + if (dstId == srcId) + var.markDone(); + } + else { + if (ASMJIT_UNLIKELY(srcGroup >= BaseReg::kGroupVirt)) + return DebugUtils::errored(kErrorInvalidState); + + WorkData& srcData = _workData[srcGroup]; + srcData.assign(varId, srcId); + } + } + else { + if (dstWd) + dstWd->_numStackArgs++; + _hasStackSrc = true; + } + + varId++; + } + } + + // Initialize WorkData::workRegs. + for (i = 0; i < BaseReg::kGroupVirt; i++) { + _workData[i]._workRegs = (_workData[i].archRegs() & (frame.dirtyRegs(i) | ~frame.preservedRegs(i))) | _workData[i].dstRegs() | _workData[i].assignedRegs(); + } + + // Create a variable that represents `SARegId` if necessary. + bool saRegRequired = _hasStackSrc && frame.hasDynamicAlignment() && !frame.hasPreservedFP(); + + WorkData& gpRegs = _workData[BaseReg::kGroupGp]; + uint32_t saCurRegId = frame.saRegId(); + uint32_t saOutRegId = args.saRegId(); + + if (saCurRegId != BaseReg::kIdBad) { + // Check if the provided `SARegId` doesn't collide with input registers. + if (ASMJIT_UNLIKELY(gpRegs.isAssigned(saCurRegId))) + return DebugUtils::errored(kErrorOverlappedRegs); + } + + if (saOutRegId != BaseReg::kIdBad) { + // Check if the provided `SARegId` doesn't collide with argument assignments. + if (ASMJIT_UNLIKELY(Support::bitTest(gpRegs.dstRegs(), saOutRegId))) + return DebugUtils::errored(kErrorOverlappedRegs); + saRegRequired = true; + } + + if (saRegRequired) { + uint32_t ptrTypeId = Environment::is32Bit(arch) ? Type::kIdU32 : Type::kIdU64; + uint32_t ptrRegType = Environment::is32Bit(arch) ? BaseReg::kTypeGp32 : BaseReg::kTypeGp64; + + _saVarId = uint8_t(varId); + _hasPreservedFP = frame.hasPreservedFP(); + + Var& var = _vars[varId]; + var.reset(); + + if (saCurRegId == BaseReg::kIdBad) { + if (saOutRegId != BaseReg::kIdBad && !gpRegs.isAssigned(saOutRegId)) { + saCurRegId = saOutRegId; + } + else { + uint32_t availableRegs = gpRegs.availableRegs(); + if (!availableRegs) + availableRegs = gpRegs.archRegs() & ~gpRegs.workRegs(); + + if (ASMJIT_UNLIKELY(!availableRegs)) + return DebugUtils::errored(kErrorNoMorePhysRegs); + + saCurRegId = Support::ctz(availableRegs); + } + } + + var.cur.initReg(ptrRegType, saCurRegId, ptrTypeId); + gpRegs.assign(varId, saCurRegId); + gpRegs._workRegs |= Support::bitMask(saCurRegId); + + if (saOutRegId != BaseReg::kIdBad) { + var.out.initReg(ptrRegType, saOutRegId, ptrTypeId); + gpRegs._dstRegs |= Support::bitMask(saOutRegId); + gpRegs._workRegs |= Support::bitMask(saOutRegId); + } + else { + var.markDone(); + } + + varId++; + } + + _varCount = varId; + + // Detect register swaps. + for (varId = 0; varId < _varCount; varId++) { + Var& var = _vars[varId]; + if (var.cur.isReg() && var.out.isReg()) { + uint32_t srcId = var.cur.regId(); + uint32_t dstId = var.out.regId(); + + uint32_t group = archTraits().regTypeToGroup(var.cur.regType()); + if (group != archTraits().regTypeToGroup(var.out.regType())) + continue; + + WorkData& wd = _workData[group]; + if (wd.isAssigned(dstId)) { + Var& other = _vars[wd._physToVarId[dstId]]; + if (archTraits().regTypeToGroup(other.out.regType()) == group && other.out.regId() == srcId) { + wd._numSwaps++; + _regSwapsMask = uint8_t(_regSwapsMask | Support::bitMask(group)); + } + } + } + } + + return kErrorOk; +} + +ASMJIT_FAVOR_SIZE Error FuncArgsContext::markDstRegsDirty(FuncFrame& frame) noexcept { + for (uint32_t i = 0; i < BaseReg::kGroupVirt; i++) { + WorkData& wd = _workData[i]; + uint32_t regs = wd.usedRegs() | wd._dstShuf; + + wd._workRegs |= regs; + frame.addDirtyRegs(i, regs); + } + + return kErrorOk; +} + +ASMJIT_FAVOR_SIZE Error FuncArgsContext::markScratchRegs(FuncFrame& frame) noexcept { + uint32_t groupMask = 0; + + // Handle stack to stack moves. + groupMask |= _stackDstMask; + + // Handle register swaps. + groupMask |= _regSwapsMask & ~Support::bitMask(BaseReg::kGroupGp); + + if (!groupMask) + return kErrorOk; + + // Selects one dirty register per affected group that can be used as a scratch register. + for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++) { + if (Support::bitTest(groupMask, group)) { + WorkData& wd = _workData[group]; + + // Initially, pick some clobbered or dirty register. + uint32_t workRegs = wd.workRegs(); + uint32_t regs = workRegs & ~(wd.usedRegs() | wd._dstShuf); + + // If that didn't work out pick some register which is not in 'used'. + if (!regs) + regs = workRegs & ~wd.usedRegs(); + + // If that didn't work out pick any other register that is allocable. + // This last resort case will, however, result in marking one more + // register dirty. + if (!regs) + regs = wd.archRegs() & ~workRegs; + + // If that didn't work out we will have to use XORs instead of MOVs. + if (!regs) + continue; + + uint32_t regMask = Support::blsi(regs); + wd._workRegs |= regMask; + frame.addDirtyRegs(group, regMask); + } + } + + return kErrorOk; +} + +ASMJIT_FAVOR_SIZE Error FuncArgsContext::markStackArgsReg(FuncFrame& frame) noexcept { + if (_saVarId != kVarIdNone) { + const Var& var = _vars[_saVarId]; + frame.setSARegId(var.cur.regId()); + } + else if (frame.hasPreservedFP()) { + frame.setSARegId(archTraits().fpRegId()); + } + + return kErrorOk; +} + +//! \} +//! \endcond + +ASMJIT_END_NAMESPACE diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/funcargscontext_p.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/funcargscontext_p.h new file mode 100644 index 0000000..6c4ea6a --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/funcargscontext_p.h @@ -0,0 +1,224 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_FUNCARGSCONTEXT_P_H_INCLUDED +#define ASMJIT_CORE_FUNCARGSCONTEXT_P_H_INCLUDED + +#include "../core/archtraits.h" +#include "../core/environment.h" +#include "../core/func.h" +#include "../core/operand.h" +#include "../core/radefs_p.h" +#include "../core/support.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \cond INTERNAL +//! \addtogroup asmjit_core +//! \{ + +// ============================================================================ +// [TODO: Place somewhere else] +// ============================================================================ + +static inline RegInfo getSuitableRegForMemToMemMove(uint32_t arch, uint32_t dstTypeId, uint32_t srcTypeId) noexcept { + const ArchTraits& archTraits = ArchTraits::byArch(arch); + + uint32_t dstSize = Type::sizeOf(dstTypeId); + uint32_t srcSize = Type::sizeOf(srcTypeId); + uint32_t maxSize = Support::max(dstSize, srcSize); + uint32_t regSize = Environment::registerSizeFromArch(arch); + + uint32_t signature = 0; + if (maxSize <= regSize || (Type::isInt(dstTypeId) && Type::isInt(srcTypeId))) + signature = maxSize <= 4 ? archTraits.regTypeToSignature(BaseReg::kTypeGp32) + : archTraits.regTypeToSignature(BaseReg::kTypeGp64); + else if (maxSize <= 8 && archTraits.hasRegType(BaseReg::kTypeVec64)) + signature = archTraits.regTypeToSignature(BaseReg::kTypeVec64); + else if (maxSize <= 16 && archTraits.hasRegType(BaseReg::kTypeVec128)) + signature = archTraits.regTypeToSignature(BaseReg::kTypeVec128); + else if (maxSize <= 32 && archTraits.hasRegType(BaseReg::kTypeVec256)) + signature = archTraits.regTypeToSignature(BaseReg::kTypeVec256); + else if (maxSize <= 64 && archTraits.hasRegType(BaseReg::kTypeVec512)) + signature = archTraits.regTypeToSignature(BaseReg::kTypeVec512); + + return RegInfo { signature }; +} + +// ============================================================================ +// [asmjit::FuncArgsContext] +// ============================================================================ + +class FuncArgsContext { +public: + enum VarId : uint32_t { + kVarIdNone = 0xFF + }; + + //! Contains information about a single argument or SA register that may need shuffling. + struct Var { + FuncValue cur; + FuncValue out; + + inline void init(const FuncValue& cur_, const FuncValue& out_) noexcept { + cur = cur_; + out = out_; + } + + //! Reset the value to its unassigned state. + inline void reset() noexcept { + cur.reset(); + out.reset(); + } + + inline bool isDone() const noexcept { return cur.isDone(); } + inline void markDone() noexcept { cur.addFlags(FuncValue::kFlagIsDone); } + }; + + struct WorkData { + //! All allocable registers provided by the architecture. + uint32_t _archRegs; + //! All registers that can be used by the shuffler. + uint32_t _workRegs; + //! Registers used by the shuffler (all). + uint32_t _usedRegs; + //! Assigned registers. + uint32_t _assignedRegs; + //! Destination registers assigned to arguments or SA. + uint32_t _dstRegs; + //! Destination registers that require shuffling. + uint32_t _dstShuf; + //! Number of register swaps. + uint8_t _numSwaps; + //! Number of stack loads. + uint8_t _numStackArgs; + //! Reserved (only used as padding). + uint8_t _reserved[6]; + //! Physical ID to variable ID mapping. + uint8_t _physToVarId[32]; + + inline void reset() noexcept { + _archRegs = 0; + _workRegs = 0; + _usedRegs = 0; + _assignedRegs = 0; + _dstRegs = 0; + _dstShuf = 0; + _numSwaps = 0; + _numStackArgs = 0; + memset(_reserved, 0, sizeof(_reserved)); + memset(_physToVarId, kVarIdNone, 32); + } + + inline bool isAssigned(uint32_t regId) const noexcept { + ASMJIT_ASSERT(regId < 32); + return Support::bitTest(_assignedRegs, regId); + } + + inline void assign(uint32_t varId, uint32_t regId) noexcept { + ASMJIT_ASSERT(!isAssigned(regId)); + ASMJIT_ASSERT(_physToVarId[regId] == kVarIdNone); + + _physToVarId[regId] = uint8_t(varId); + _assignedRegs ^= Support::bitMask(regId); + } + + inline void reassign(uint32_t varId, uint32_t newId, uint32_t oldId) noexcept { + ASMJIT_ASSERT( isAssigned(oldId)); + ASMJIT_ASSERT(!isAssigned(newId)); + ASMJIT_ASSERT(_physToVarId[oldId] == varId); + ASMJIT_ASSERT(_physToVarId[newId] == kVarIdNone); + + _physToVarId[oldId] = uint8_t(kVarIdNone); + _physToVarId[newId] = uint8_t(varId); + _assignedRegs ^= Support::bitMask(newId) ^ Support::bitMask(oldId); + } + + inline void swap(uint32_t aVarId, uint32_t aRegId, uint32_t bVarId, uint32_t bRegId) noexcept { + ASMJIT_ASSERT(isAssigned(aRegId)); + ASMJIT_ASSERT(isAssigned(bRegId)); + ASMJIT_ASSERT(_physToVarId[aRegId] == aVarId); + ASMJIT_ASSERT(_physToVarId[bRegId] == bVarId); + + _physToVarId[aRegId] = uint8_t(bVarId); + _physToVarId[bRegId] = uint8_t(aVarId); + } + + inline void unassign(uint32_t varId, uint32_t regId) noexcept { + ASMJIT_ASSERT(isAssigned(regId)); + ASMJIT_ASSERT(_physToVarId[regId] == varId); + + DebugUtils::unused(varId); + _physToVarId[regId] = uint8_t(kVarIdNone); + _assignedRegs ^= Support::bitMask(regId); + } + + inline uint32_t archRegs() const noexcept { return _archRegs; } + inline uint32_t workRegs() const noexcept { return _workRegs; } + inline uint32_t usedRegs() const noexcept { return _usedRegs; } + inline uint32_t assignedRegs() const noexcept { return _assignedRegs; } + inline uint32_t dstRegs() const noexcept { return _dstRegs; } + inline uint32_t availableRegs() const noexcept { return _workRegs & ~_assignedRegs; } + }; + + //! Architecture traits. + const ArchTraits* _archTraits = nullptr; + const RAConstraints* _constraints = nullptr; + //! Architecture identifier. + uint8_t _arch = 0; + //! Has arguments passed via stack (SRC). + bool _hasStackSrc = false; + //! Has preserved frame-pointer (FP). + bool _hasPreservedFP = false; + //! Has arguments assigned to stack (DST). + uint8_t _stackDstMask = 0; + //! Register swap groups (bit-mask). + uint8_t _regSwapsMask = 0; + uint8_t _saVarId = kVarIdNone; + uint32_t _varCount = 0; + WorkData _workData[BaseReg::kGroupVirt]; + Var _vars[Globals::kMaxFuncArgs * Globals::kMaxValuePack + 1]; + + FuncArgsContext() noexcept; + + inline const ArchTraits& archTraits() const noexcept { return *_archTraits; } + inline uint32_t arch() const noexcept { return _arch; } + + inline uint32_t varCount() const noexcept { return _varCount; } + inline size_t indexOf(const Var* var) const noexcept { return (size_t)(var - _vars); } + + inline Var& var(size_t varId) noexcept { return _vars[varId]; } + inline const Var& var(size_t varId) const noexcept { return _vars[varId]; } + + Error initWorkData(const FuncFrame& frame, const FuncArgsAssignment& args, const RAConstraints* constraints) noexcept; + Error markScratchRegs(FuncFrame& frame) noexcept; + Error markDstRegsDirty(FuncFrame& frame) noexcept; + Error markStackArgsReg(FuncFrame& frame) noexcept; +}; + +//! \} +//! \endcond + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_FUNCARGSCONTEXT_P_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/globals.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/globals.cpp new file mode 100644 index 0000000..dc5083b --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/globals.cpp @@ -0,0 +1,146 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/globals.h" +#include "../core/support.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::DebugUtils] +// ============================================================================ + +ASMJIT_FAVOR_SIZE const char* DebugUtils::errorAsString(Error err) noexcept { +#ifndef ASMJIT_NO_TEXT + // @EnumStringBegin{"enum": "ErrorCode", "output": "sError", "strip": "kError"}@ + static const char sErrorString[] = + "Ok\0" + "OutOfMemory\0" + "InvalidArgument\0" + "InvalidState\0" + "InvalidArch\0" + "NotInitialized\0" + "AlreadyInitialized\0" + "FeatureNotEnabled\0" + "TooManyHandles\0" + "TooLarge\0" + "NoCodeGenerated\0" + "InvalidDirective\0" + "InvalidLabel\0" + "TooManyLabels\0" + "LabelAlreadyBound\0" + "LabelAlreadyDefined\0" + "LabelNameTooLong\0" + "InvalidLabelName\0" + "InvalidParentLabel\0" + "NonLocalLabelCannotHaveParent\0" + "InvalidSection\0" + "TooManySections\0" + "InvalidSectionName\0" + "TooManyRelocations\0" + "InvalidRelocEntry\0" + "RelocOffsetOutOfRange\0" + "InvalidAssignment\0" + "InvalidInstruction\0" + "InvalidRegType\0" + "InvalidRegGroup\0" + "InvalidPhysId\0" + "InvalidVirtId\0" + "InvalidElementIndex\0" + "InvalidPrefixCombination\0" + "InvalidLockPrefix\0" + "InvalidXAcquirePrefix\0" + "InvalidXReleasePrefix\0" + "InvalidRepPrefix\0" + "InvalidRexPrefix\0" + "InvalidExtraReg\0" + "InvalidKMaskUse\0" + "InvalidKZeroUse\0" + "InvalidBroadcast\0" + "InvalidEROrSAE\0" + "InvalidAddress\0" + "InvalidAddressIndex\0" + "InvalidAddressScale\0" + "InvalidAddress64Bit\0" + "InvalidAddress64BitZeroExtension\0" + "InvalidDisplacement\0" + "InvalidSegment\0" + "InvalidImmediate\0" + "InvalidOperandSize\0" + "AmbiguousOperandSize\0" + "OperandSizeMismatch\0" + "InvalidOption\0" + "OptionAlreadyDefined\0" + "InvalidTypeId\0" + "InvalidUseOfGpbHi\0" + "InvalidUseOfGpq\0" + "InvalidUseOfF80\0" + "NotConsecutiveRegs\0" + "IllegalVirtReg\0" + "TooManyVirtRegs\0" + "NoMorePhysRegs\0" + "OverlappedRegs\0" + "OverlappingStackRegWithRegArg\0" + "ExpressionLabelNotBound\0" + "ExpressionOverflow\0" + "FailedToOpenAnonymousMemory\0" + "\0"; + + static const uint16_t sErrorIndex[] = { + 0, 3, 15, 31, 44, 56, 71, 90, 108, 123, 132, 148, 165, 178, 192, 210, 230, + 247, 264, 283, 313, 328, 344, 363, 382, 400, 422, 440, 459, 474, 490, 504, + 518, 538, 563, 581, 603, 625, 642, 659, 675, 691, 707, 724, 739, 754, 774, + 794, 814, 847, 867, 882, 899, 918, 939, 959, 973, 994, 1008, 1026, 1042, + 1058, 1077, 1092, 1108, 1123, 1138, 1168, 1192, 1211, 1239 + }; + // @EnumStringEnd@ + + return sErrorString + sErrorIndex[Support::min(err, kErrorCount)]; +#else + DebugUtils::unused(err); + static const char noMessage[] = ""; + return noMessage; +#endif +} + +ASMJIT_FAVOR_SIZE void DebugUtils::debugOutput(const char* str) noexcept { +#if defined(_WIN32) + ::OutputDebugStringA(str); +#else + ::fputs(str, stderr); +#endif +} + +ASMJIT_FAVOR_SIZE void DebugUtils::assertionFailed(const char* file, int line, const char* msg) noexcept { + char str[1024]; + + snprintf(str, 1024, + "[asmjit] Assertion failed at %s (line %d):\n" + "[asmjit] %s\n", file, line, msg); + + debugOutput(str); + ::abort(); +} + +ASMJIT_END_NAMESPACE diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/globals.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/globals.h new file mode 100644 index 0000000..3b7bfc9 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/globals.h @@ -0,0 +1,462 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_GLOBALS_H_INCLUDED +#define ASMJIT_CORE_GLOBALS_H_INCLUDED + +#include "../core/api-config.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::Support] +// ============================================================================ + +//! \cond INTERNAL +//! \addtogroup asmjit_utilities +//! \{ +namespace Support { + //! Cast designed to cast between function and void* pointers. + template + static inline Dst ptr_cast_impl(Src p) noexcept { return (Dst)p; } +} // {Support} + +#if defined(ASMJIT_NO_STDCXX) +namespace Support { + ASMJIT_INLINE void* operatorNew(size_t n) noexcept { return malloc(n); } + ASMJIT_INLINE void operatorDelete(void* p) noexcept { if (p) free(p); } +} // {Support} + +#define ASMJIT_BASE_CLASS(TYPE) \ + ASMJIT_INLINE void* operator new(size_t n) noexcept { \ + return Support::operatorNew(n); \ + } \ + \ + ASMJIT_INLINE void operator delete(void* p) noexcept { \ + Support::operatorDelete(p); \ + } \ + \ + ASMJIT_INLINE void* operator new(size_t, void* p) noexcept { return p; } \ + ASMJIT_INLINE void operator delete(void*, void*) noexcept {} +#else +#define ASMJIT_BASE_CLASS(TYPE) +#endif + +//! \} +//! \endcond + +// ============================================================================ +// [asmjit::Globals] +// ============================================================================ + +//! \addtogroup asmjit_core +//! \{ + +//! Contains typedefs, constants, and variables used globally by AsmJit. +namespace Globals { + +// ============================================================================ +// [asmjit::Globals::] +// ============================================================================ + +//! Host memory allocator overhead. +static constexpr uint32_t kAllocOverhead = uint32_t(sizeof(intptr_t) * 4); + +//! Host memory allocator alignment. +static constexpr uint32_t kAllocAlignment = 8; + +//! Aggressive growing strategy threshold. +static constexpr uint32_t kGrowThreshold = 1024 * 1024 * 16; + +//! Maximum depth of RB-Tree is: +//! +//! `2 * log2(n + 1)` +//! +//! Size of RB node is at least two pointers (without data), +//! so a theoretical architecture limit would be: +//! +//! `2 * log2(addressableMemorySize / sizeof(Node) + 1)` +//! +//! Which yields 30 on 32-bit arch and 61 on 64-bit arch. +//! The final value was adjusted by +1 for safety reasons. +static constexpr uint32_t kMaxTreeHeight = (ASMJIT_ARCH_BITS == 32 ? 30 : 61) + 1; + +//! Maximum number of operands per a single instruction. +static constexpr uint32_t kMaxOpCount = 6; + +//! Maximum arguments of a function supported by the Compiler / Function API. +static constexpr uint32_t kMaxFuncArgs = 16; + +//! The number of values that can be assigned to a single function argument or +//! return value. +static constexpr uint32_t kMaxValuePack = 4; + +//! Maximum number of physical registers AsmJit can use per register group. +static constexpr uint32_t kMaxPhysRegs = 32; + +//! Maximum alignment. +static constexpr uint32_t kMaxAlignment = 64; + +//! Maximum label or symbol size in bytes. +static constexpr uint32_t kMaxLabelNameSize = 2048; + +//! Maximum section name size. +static constexpr uint32_t kMaxSectionNameSize = 35; + +//! Maximum size of comment. +static constexpr uint32_t kMaxCommentSize = 1024; + +//! Invalid identifier. +static constexpr uint32_t kInvalidId = 0xFFFFFFFFu; + +//! Returned by `indexOf()` and similar when working with containers that use 32-bit index/size. +static constexpr uint32_t kNotFound = 0xFFFFFFFFu; + +//! Invalid base address. +static constexpr uint64_t kNoBaseAddress = ~uint64_t(0); + +// ============================================================================ +// [asmjit::Globals::ResetPolicy] +// ============================================================================ + +//! Reset policy used by most `reset()` functions. +enum ResetPolicy : uint32_t { + //! Soft reset, doesn't deallocate memory (default). + kResetSoft = 0, + //! Hard reset, releases all memory used, if any. + kResetHard = 1 +}; + +// ============================================================================ +// [asmjit::Globals::Link] +// ============================================================================ + +enum Link : uint32_t { + kLinkLeft = 0, + kLinkRight = 1, + + kLinkPrev = 0, + kLinkNext = 1, + + kLinkFirst = 0, + kLinkLast = 1, + + kLinkCount = 2 +}; + +struct Init_ {}; +struct NoInit_ {}; + +static const constexpr Init_ Init {}; +static const constexpr NoInit_ NoInit {}; + +} // {Globals} + +// ============================================================================ +// [asmjit::ByteOrder] +// ============================================================================ + +//! Byte order. +namespace ByteOrder { + enum : uint32_t { + kLE = 0, + kBE = 1, + kNative = ASMJIT_ARCH_LE ? kLE : kBE, + kSwapped = ASMJIT_ARCH_LE ? kBE : kLE + }; +} + +// ============================================================================ +// [asmjit::ptr_as_func / func_as_ptr] +// ============================================================================ + +template +static inline Func ptr_as_func(void* func) noexcept { return Support::ptr_cast_impl(func); } + +template +static inline void* func_as_ptr(Func func) noexcept { return Support::ptr_cast_impl(func); } + +//! \} + +// ============================================================================ +// [asmjit::Error] +// ============================================================================ + +//! \addtogroup asmjit_error_handling +//! \{ + +//! AsmJit error type (uint32_t). +typedef uint32_t Error; + +//! AsmJit error codes. +enum ErrorCode : uint32_t { + // @EnumValuesBegin{"enum": "ErrorCode"}@ + + //! No error (success). + kErrorOk = 0, + + //! Out of memory. + kErrorOutOfMemory, + + //! Invalid argument. + kErrorInvalidArgument, + + //! Invalid state. + //! + //! If this error is returned it means that either you are doing something + //! wrong or AsmJit caught itself by doing something wrong. This error should + //! never be ignored. + kErrorInvalidState, + + //! Invalid or incompatible architecture. + kErrorInvalidArch, + + //! The object is not initialized. + kErrorNotInitialized, + //! The object is already initialized. + kErrorAlreadyInitialized, + + //! Built-in feature was disabled at compile time and it's not available. + kErrorFeatureNotEnabled, + + //! Too many handles (Windows) or file descriptors (Unix/Posix). + kErrorTooManyHandles, + //! Code generated is larger than allowed. + kErrorTooLarge, + + //! No code generated. + //! + //! Returned by runtime if the \ref CodeHolder contains no code. + kErrorNoCodeGenerated, + + //! Invalid directive. + kErrorInvalidDirective, + //! Attempt to use uninitialized label. + kErrorInvalidLabel, + //! Label index overflow - a single \ref BaseAssembler instance can hold + //! almost 2^32 (4 billion) labels. If there is an attempt to create more + //! labels then this error is returned. + kErrorTooManyLabels, + //! Label is already bound. + kErrorLabelAlreadyBound, + //! Label is already defined (named labels). + kErrorLabelAlreadyDefined, + //! Label name is too long. + kErrorLabelNameTooLong, + //! Label must always be local if it's anonymous (without a name). + kErrorInvalidLabelName, + //! Parent id passed to \ref CodeHolder::newNamedLabelEntry() was invalid. + kErrorInvalidParentLabel, + //! Parent id specified for a non-local (global) label. + kErrorNonLocalLabelCannotHaveParent, + + //! Invalid section. + kErrorInvalidSection, + //! Too many sections (section index overflow). + kErrorTooManySections, + //! Invalid section name (most probably too long). + kErrorInvalidSectionName, + + //! Relocation index overflow (too many relocations). + kErrorTooManyRelocations, + //! Invalid relocation entry. + kErrorInvalidRelocEntry, + //! Reloc entry contains address that is out of range (unencodable). + kErrorRelocOffsetOutOfRange, + + //! Invalid assignment to a register, function argument, or function return value. + kErrorInvalidAssignment, + //! Invalid instruction. + kErrorInvalidInstruction, + //! Invalid register type. + kErrorInvalidRegType, + //! Invalid register group. + kErrorInvalidRegGroup, + //! Invalid physical register id. + kErrorInvalidPhysId, + //! Invalid virtual register id. + kErrorInvalidVirtId, + //! Invalid element index (ARM). + kErrorInvalidElementIndex, + //! Invalid prefix combination (X86|X64). + kErrorInvalidPrefixCombination, + //! Invalid LOCK prefix (X86|X64). + kErrorInvalidLockPrefix, + //! Invalid XACQUIRE prefix (X86|X64). + kErrorInvalidXAcquirePrefix, + //! Invalid XRELEASE prefix (X86|X64). + kErrorInvalidXReleasePrefix, + //! Invalid REP prefix (X86|X64). + kErrorInvalidRepPrefix, + //! Invalid REX prefix (X86|X64). + kErrorInvalidRexPrefix, + //! Invalid {...} register (X86|X64). + kErrorInvalidExtraReg, + //! Invalid {k} use (not supported by the instruction) (X86|X64). + kErrorInvalidKMaskUse, + //! Invalid {k}{z} use (not supported by the instruction) (X86|X64). + kErrorInvalidKZeroUse, + //! Invalid broadcast - Currently only related to invalid use of AVX-512 {1tox} (X86|X64). + kErrorInvalidBroadcast, + //! Invalid 'embedded-rounding' {er} or 'suppress-all-exceptions' {sae} (AVX-512) (X86|X64). + kErrorInvalidEROrSAE, + //! Invalid address used (not encodable). + kErrorInvalidAddress, + //! Invalid index register used in memory address (not encodable). + kErrorInvalidAddressIndex, + //! Invalid address scale (not encodable). + kErrorInvalidAddressScale, + //! Invalid use of 64-bit address. + kErrorInvalidAddress64Bit, + //! Invalid use of 64-bit address that require 32-bit zero-extension (X64). + kErrorInvalidAddress64BitZeroExtension, + //! Invalid displacement (not encodable). + kErrorInvalidDisplacement, + //! Invalid segment (X86). + kErrorInvalidSegment, + + //! Invalid immediate (out of bounds on X86 and invalid pattern on ARM). + kErrorInvalidImmediate, + + //! Invalid operand size. + kErrorInvalidOperandSize, + //! Ambiguous operand size (memory has zero size while it's required to determine the operation type. + kErrorAmbiguousOperandSize, + //! Mismatching operand size (size of multiple operands doesn't match the operation size). + kErrorOperandSizeMismatch, + + //! Invalid option. + kErrorInvalidOption, + //! Option already defined. + kErrorOptionAlreadyDefined, + + //! Invalid TypeId. + kErrorInvalidTypeId, + //! Invalid use of a 8-bit GPB-HIGH register. + kErrorInvalidUseOfGpbHi, + //! Invalid use of a 64-bit GPQ register in 32-bit mode. + kErrorInvalidUseOfGpq, + //! Invalid use of an 80-bit float (\ref Type::kIdF80). + kErrorInvalidUseOfF80, + //! Some registers in the instruction muse be consecutive (some ARM and AVX512 + //! neural-net instructions). + kErrorNotConsecutiveRegs, + + //! Illegal virtual register - reported by instruction validation. + kErrorIllegalVirtReg, + //! AsmJit cannot create more virtual registers. + kErrorTooManyVirtRegs, + + //! AsmJit requires a physical register, but no one is available. + kErrorNoMorePhysRegs, + //! A variable has been assigned more than once to a function argument (BaseCompiler). + kErrorOverlappedRegs, + //! Invalid register to hold stack arguments offset. + kErrorOverlappingStackRegWithRegArg, + + //! Unbound label cannot be evaluated by expression. + kErrorExpressionLabelNotBound, + //! Arithmetic overflow during expression evaluation. + kErrorExpressionOverflow, + + //! Failed to open anonymous memory handle or file descriptor. + kErrorFailedToOpenAnonymousMemory, + + // @EnumValuesEnd@ + + //! Count of AsmJit error codes. + kErrorCount +}; + +// ============================================================================ +// [asmjit::DebugUtils] +// ============================================================================ + +//! Debugging utilities. +namespace DebugUtils { + +//! \cond INTERNAL +//! Used to silence warnings about unused arguments or variables. +template +static ASMJIT_INLINE void unused(Args&&...) noexcept {} +//! \endcond + +//! Returns the error `err` passed. +//! +//! Provided for debugging purposes. Putting a breakpoint inside `errored` can +//! help with tracing the origin of any error reported / returned by AsmJit. +static constexpr Error errored(Error err) noexcept { return err; } + +//! Returns a printable version of `asmjit::Error` code. +ASMJIT_API const char* errorAsString(Error err) noexcept; + +//! Called to output debugging message(s). +ASMJIT_API void debugOutput(const char* str) noexcept; + +//! Called on assertion failure. +//! +//! \param file Source file name where it happened. +//! \param line Line in the source file. +//! \param msg Message to display. +//! +//! If you have problems with assertion failures a breakpoint can be put +//! at \ref assertionFailed() function (asmjit/core/globals.cpp). A call stack +//! will be available when such assertion failure is triggered. AsmJit always +//! returns errors on failures, assertions are a last resort and usually mean +//! unrecoverable state due to out of range array access or totally invalid +//! arguments like nullptr where a valid pointer should be provided, etc... +ASMJIT_API void ASMJIT_NORETURN assertionFailed(const char* file, int line, const char* msg) noexcept; + +} // {DebugUtils} + +//! \def ASMJIT_ASSERT(...) +//! +//! AsmJit's own assert macro used in AsmJit code-base. +#if defined(ASMJIT_BUILD_DEBUG) +#define ASMJIT_ASSERT(...) \ + do { \ + if (ASMJIT_LIKELY(__VA_ARGS__)) \ + break; \ + ::asmjit::DebugUtils::assertionFailed(__FILE__, __LINE__, #__VA_ARGS__); \ + } while (0) +#else +#define ASMJIT_ASSERT(...) ((void)0) +#endif + +//! \def ASMJIT_PROPAGATE(...) +//! +//! Propagates a possible `Error` produced by `...` to the caller by returning +//! the error immediately. Used by AsmJit internally, but kept public for users +//! that want to use the same technique to propagate errors to the caller. +#define ASMJIT_PROPAGATE(...) \ + do { \ + ::asmjit::Error _err = __VA_ARGS__; \ + if (ASMJIT_UNLIKELY(_err)) \ + return _err; \ + } while (0) + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_GLOBALS_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/inst.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/inst.cpp new file mode 100644 index 0000000..a79fe83 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/inst.cpp @@ -0,0 +1,139 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#ifdef ASMJIT_BUILD_X86 + +#include "../core/archtraits.h" +#include "../core/inst.h" + +#ifdef ASMJIT_BUILD_X86 + #include "../x86/x86instapi_p.h" +#endif + +#ifdef ASMJIT_BUILD_ARM + #include "../arm/a64instapi_p.h" +#endif + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::InstAPI - Text] +// ============================================================================ + +#ifndef ASMJIT_NO_TEXT +Error InstAPI::instIdToString(uint32_t arch, uint32_t instId, String& output) noexcept { +#ifdef ASMJIT_BUILD_X86 + if (Environment::isFamilyX86(arch)) + return x86::InstInternal::instIdToString(arch, instId, output); +#endif + +#ifdef ASMJIT_BUILD_ARM + if (Environment::isArchAArch64(arch)) + return a64::InstInternal::instIdToString(arch, instId, output); +#endif + + return DebugUtils::errored(kErrorInvalidArch); +} + +uint32_t InstAPI::stringToInstId(uint32_t arch, const char* s, size_t len) noexcept { +#ifdef ASMJIT_BUILD_X86 + if (Environment::isFamilyX86(arch)) + return x86::InstInternal::stringToInstId(arch, s, len); +#endif + +#ifdef ASMJIT_BUILD_ARM + if (Environment::isArchAArch64(arch)) + return a64::InstInternal::stringToInstId(arch, s, len); +#endif + + return 0; +} +#endif // !ASMJIT_NO_TEXT + +// ============================================================================ +// [asmjit::InstAPI - Validate] +// ============================================================================ + +#ifndef ASMJIT_NO_VALIDATION +Error InstAPI::validate(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, uint32_t validationFlags) noexcept { +#ifdef ASMJIT_BUILD_X86 + if (Environment::isFamilyX86(arch)) + return x86::InstInternal::validate(arch, inst, operands, opCount, validationFlags); +#endif + +#ifdef ASMJIT_BUILD_ARM + if (Environment::isArchAArch64(arch)) + return a64::InstInternal::validate(arch, inst, operands, opCount, validationFlags); +#endif + + return DebugUtils::errored(kErrorInvalidArch); +} +#endif // !ASMJIT_NO_VALIDATION + +// ============================================================================ +// [asmjit::InstAPI - QueryRWInfo] +// ============================================================================ + +#ifndef ASMJIT_NO_INTROSPECTION +Error InstAPI::queryRWInfo(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept { + if (ASMJIT_UNLIKELY(opCount > Globals::kMaxOpCount)) + return DebugUtils::errored(kErrorInvalidArgument); + +#ifdef ASMJIT_BUILD_X86 + if (Environment::isFamilyX86(arch)) + return x86::InstInternal::queryRWInfo(arch, inst, operands, opCount, out); +#endif + +#ifdef ASMJIT_BUILD_ARM + if (Environment::isArchAArch64(arch)) + return a64::InstInternal::queryRWInfo(arch, inst, operands, opCount, out); +#endif + + return DebugUtils::errored(kErrorInvalidArch); +} +#endif // !ASMJIT_NO_INTROSPECTION + +// ============================================================================ +// [asmjit::InstAPI - QueryFeatures] +// ============================================================================ + +#ifndef ASMJIT_NO_INTROSPECTION +Error InstAPI::queryFeatures(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, BaseFeatures* out) noexcept { +#ifdef ASMJIT_BUILD_X86 + if (Environment::isFamilyX86(arch)) + return x86::InstInternal::queryFeatures(arch, inst, operands, opCount, out); +#endif + +#ifdef ASMJIT_BUILD_ARM + if (Environment::isArchAArch64(arch)) + return a64::InstInternal::queryFeatures(arch, inst, operands, opCount, out); +#endif + + return DebugUtils::errored(kErrorInvalidArch); +} +#endif // !ASMJIT_NO_INTROSPECTION + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_BUILD_X86 diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/inst.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/inst.h new file mode 100644 index 0000000..bc3708d --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/inst.h @@ -0,0 +1,559 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_INST_H_INCLUDED +#define ASMJIT_CORE_INST_H_INCLUDED + +#include "../core/cpuinfo.h" +#include "../core/operand.h" +#include "../core/string.h" +#include "../core/support.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_instruction_db +//! \{ + +// ============================================================================ +// [asmjit::BaseInst] +// ============================================================================ + +//! Instruction id, options, and extraReg in a single structure. This structure +//! exists mainly to simplify analysis and validation API that requires `BaseInst` +//! and `Operand[]` array. +class BaseInst { +public: + //! Instruction id, see \ref BaseInst::Id or {arch-specific}::Inst::Id. + uint32_t _id; + //! Instruction options, see \ref BaseInst::Options or {arch-specific}::Inst::Options. + uint32_t _options; + //! Extra register used by instruction (either REP register or AVX-512 selector). + RegOnly _extraReg; + + enum Id : uint32_t { + //! Invalid or uninitialized instruction id. + kIdNone = 0x00000000u, + //! Abstract instruction (BaseBuilder and BaseCompiler). + kIdAbstract = 0x80000000u + }; + + enum Options : uint32_t { + //! Used internally by emitters for handling errors and rare cases. + kOptionReserved = 0x00000001u, + + //! Prevents following a jump during compilation (BaseCompiler). + kOptionUnfollow = 0x00000002u, + + //! Overwrite the destination operand(s) (BaseCompiler). + //! + //! Hint that is important for register liveness analysis. It tells the + //! compiler that the destination operand will be overwritten now or by + //! adjacent instructions. BaseCompiler knows when a register is completely + //! overwritten by a single instruction, for example you don't have to + //! mark "movaps" or "pxor x, x", however, if a pair of instructions is + //! used and the first of them doesn't completely overwrite the content + //! of the destination, BaseCompiler fails to mark that register as dead. + //! + //! X86 Specific + //! ------------ + //! + //! - All instructions that always overwrite at least the size of the + //! register the virtual-register uses , for example "mov", "movq", + //! "movaps" don't need the overwrite option to be used - conversion, + //! shuffle, and other miscellaneous instructions included. + //! + //! - All instructions that clear the destination register if all operands + //! are the same, for example "xor x, x", "pcmpeqb x x", etc... + //! + //! - Consecutive instructions that partially overwrite the variable until + //! there is no old content require `BaseCompiler::overwrite()` to be used. + //! Some examples (not always the best use cases thought): + //! + //! - `movlps xmm0, ?` followed by `movhps xmm0, ?` and vice versa + //! - `movlpd xmm0, ?` followed by `movhpd xmm0, ?` and vice versa + //! - `mov al, ?` followed by `and ax, 0xFF` + //! - `mov al, ?` followed by `mov ah, al` + //! - `pinsrq xmm0, ?, 0` followed by `pinsrq xmm0, ?, 1` + //! + //! - If allocated variable is used temporarily for scalar operations. For + //! example if you allocate a full vector like `x86::Compiler::newXmm()` + //! and then use that vector for scalar operations you should use + //! `overwrite()` directive: + //! + //! - `sqrtss x, y` - only LO element of `x` is changed, if you don't + //! use HI elements, use `compiler.overwrite().sqrtss(x, y)`. + kOptionOverwrite = 0x00000004u, + + //! Emit short-form of the instruction. + kOptionShortForm = 0x00000010u, + //! Emit long-form of the instruction. + kOptionLongForm = 0x00000020u, + + //! Conditional jump is likely to be taken. + kOptionTaken = 0x00000040u, + //! Conditional jump is unlikely to be taken. + kOptionNotTaken = 0x00000080u + }; + + //! Control type. + enum ControlType : uint32_t { + //! No control type (doesn't jump). + kControlNone = 0u, + //! Unconditional jump. + kControlJump = 1u, + //! Conditional jump (branch). + kControlBranch = 2u, + //! Function call. + kControlCall = 3u, + //! Function return. + kControlReturn = 4u + }; + + //! \name Construction & Destruction + //! \{ + + //! Creates a new BaseInst instance with `id` and `options` set. + //! + //! Default values of `id` and `options` are zero, which means none instruciton. + //! Such instruction is guaranteed to never exist for any architecture supported + //! by AsmJit. + inline explicit BaseInst(uint32_t id = 0, uint32_t options = 0) noexcept + : _id(id), + _options(options), + _extraReg() {} + + inline BaseInst(uint32_t id, uint32_t options, const RegOnly& extraReg) noexcept + : _id(id), + _options(options), + _extraReg(extraReg) {} + + inline BaseInst(uint32_t id, uint32_t options, const BaseReg& extraReg) noexcept + : _id(id), + _options(options), + _extraReg { extraReg.signature(), extraReg.id() } {} + + //! \} + + //! \name Instruction ID + //! \{ + + //! Returns the instruction id. + inline uint32_t id() const noexcept { return _id; } + //! Sets the instruction id to the given `id`. + inline void setId(uint32_t id) noexcept { _id = id; } + //! Resets the instruction id to zero, see \ref kIdNone. + inline void resetId() noexcept { _id = 0; } + + //! \} + + //! \name Instruction Options + //! \{ + + inline uint32_t options() const noexcept { return _options; } + inline bool hasOption(uint32_t option) const noexcept { return (_options & option) != 0; } + inline void setOptions(uint32_t options) noexcept { _options = options; } + inline void addOptions(uint32_t options) noexcept { _options |= options; } + inline void clearOptions(uint32_t options) noexcept { _options &= ~options; } + inline void resetOptions() noexcept { _options = 0; } + + //! \} + + //! \name Extra Register + //! \{ + + inline bool hasExtraReg() const noexcept { return _extraReg.isReg(); } + inline RegOnly& extraReg() noexcept { return _extraReg; } + inline const RegOnly& extraReg() const noexcept { return _extraReg; } + inline void setExtraReg(const BaseReg& reg) noexcept { _extraReg.init(reg); } + inline void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); } + inline void resetExtraReg() noexcept { _extraReg.reset(); } + + //! \} +}; + +// ============================================================================ +// [asmjit::OpRWInfo] +// ============================================================================ + +//! Read/Write information related to a single operand, used by \ref InstRWInfo. +struct OpRWInfo { + //! Read/Write flags, see \ref OpRWInfo::Flags. + uint32_t _opFlags; + //! Physical register index, if required. + uint8_t _physId; + //! Size of a possible memory operand that can replace a register operand. + uint8_t _rmSize; + //! Reserved for future use. + uint8_t _reserved[2]; + //! Read bit-mask where each bit represents one byte read from Reg/Mem. + uint64_t _readByteMask; + //! Write bit-mask where each bit represents one byte written to Reg/Mem. + uint64_t _writeByteMask; + //! Zero/Sign extend bit-mask where each bit represents one byte written to Reg/Mem. + uint64_t _extendByteMask; + + //! Flags describe how the operand is accessed and some additional information. + enum Flags : uint32_t { + //! Operand is read. + kRead = 0x00000001u, + + //! Operand is written. + kWrite = 0x00000002u, + + //! Operand is both read and written. + kRW = 0x00000003u, + + //! Register operand can be replaced by a memory operand. + kRegMem = 0x00000004u, + + //! The `extendByteMask()` represents a zero extension. + kZExt = 0x00000010u, + + //! Register operand must use \ref physId(). + kRegPhysId = 0x00000100u, + //! Base register of a memory operand must use \ref physId(). + kMemPhysId = 0x00000200u, + + //! This memory operand is only used to encode registers and doesn't access memory. + //! + //! X86 Specific + //! ------------ + //! + //! Instructions that use such feature include BNDLDX, BNDSTX, and LEA. + kMemFake = 0x000000400u, + + //! Base register of the memory operand will be read. + kMemBaseRead = 0x00001000u, + //! Base register of the memory operand will be written. + kMemBaseWrite = 0x00002000u, + //! Base register of the memory operand will be read & written. + kMemBaseRW = 0x00003000u, + + //! Index register of the memory operand will be read. + kMemIndexRead = 0x00004000u, + //! Index register of the memory operand will be written. + kMemIndexWrite = 0x00008000u, + //! Index register of the memory operand will be read & written. + kMemIndexRW = 0x0000C000u, + + //! Base register of the memory operand will be modified before the operation. + kMemBasePreModify = 0x00010000u, + //! Base register of the memory operand will be modified after the operation. + kMemBasePostModify = 0x00020000u + }; + + // Don't remove these asserts. Read/Write flags are used extensively + // by Compiler and they must always be compatible with constants below. + static_assert(kRead == 0x1, "OpRWInfo::kRead flag must be 0x1"); + static_assert(kWrite == 0x2, "OpRWInfo::kWrite flag must be 0x2"); + static_assert(kRegMem == 0x4, "OpRWInfo::kRegMem flag must be 0x4"); + + //! \name Reset + //! \{ + + //! Resets this operand information to all zeros. + inline void reset() noexcept { memset(this, 0, sizeof(*this)); } + + //! Resets this operand info (resets all members) and set common information + //! to the given `opFlags`, `regSize`, and possibly `physId`. + inline void reset(uint32_t opFlags, uint32_t regSize, uint32_t physId = BaseReg::kIdBad) noexcept { + _opFlags = opFlags; + _physId = uint8_t(physId); + _rmSize = uint8_t((opFlags & kRegMem) ? regSize : uint32_t(0)); + _resetReserved(); + + uint64_t mask = Support::lsbMask(regSize); + _readByteMask = opFlags & kRead ? mask : uint64_t(0); + _writeByteMask = opFlags & kWrite ? mask : uint64_t(0); + _extendByteMask = 0; + } + + inline void _resetReserved() noexcept { + memset(_reserved, 0, sizeof(_reserved)); + } + + //! \} + + //! \name Operand Flags + //! \{ + + //! Returns operand flags, see \ref Flags. + inline uint32_t opFlags() const noexcept { return _opFlags; } + //! Tests whether operand flags contain the given `flag`. + inline bool hasOpFlag(uint32_t flag) const noexcept { return (_opFlags & flag) != 0; } + + //! Adds the given `flags` to operand flags. + inline void addOpFlags(uint32_t flags) noexcept { _opFlags |= flags; } + //! Removes the given `flags` from operand flags. + inline void clearOpFlags(uint32_t flags) noexcept { _opFlags &= ~flags; } + + //! Tests whether this operand is read from. + inline bool isRead() const noexcept { return hasOpFlag(kRead); } + //! Tests whether this operand is written to. + inline bool isWrite() const noexcept { return hasOpFlag(kWrite); } + //! Tests whether this operand is both read and write. + inline bool isReadWrite() const noexcept { return (_opFlags & kRW) == kRW; } + //! Tests whether this operand is read only. + inline bool isReadOnly() const noexcept { return (_opFlags & kRW) == kRead; } + //! Tests whether this operand is write only. + inline bool isWriteOnly() const noexcept { return (_opFlags & kRW) == kWrite; } + + //! Tests whether this operand is Reg/Mem + //! + //! Reg/Mem operands can use either register or memory. + inline bool isRm() const noexcept { return hasOpFlag(kRegMem); } + + //! Tests whether the operand will be zero extended. + inline bool isZExt() const noexcept { return hasOpFlag(kZExt); } + + //! \} + + //! \name Memory Flags + //! \{ + + //! Tests whether this is a fake memory operand, which is only used, because + //! of encoding. Fake memory operands do not access any memory, they are only + //! used to encode registers. + inline bool isMemFake() const noexcept { return hasOpFlag(kMemFake); } + + //! Tests whether the instruction's memory BASE register is used. + inline bool isMemBaseUsed() const noexcept { return (_opFlags & kMemBaseRW) != 0; } + //! Tests whether the instruction reads from its BASE registers. + inline bool isMemBaseRead() const noexcept { return hasOpFlag(kMemBaseRead); } + //! Tests whether the instruction writes to its BASE registers. + inline bool isMemBaseWrite() const noexcept { return hasOpFlag(kMemBaseWrite); } + //! Tests whether the instruction reads and writes from/to its BASE registers. + inline bool isMemBaseReadWrite() const noexcept { return (_opFlags & kMemBaseRW) == kMemBaseRW; } + //! Tests whether the instruction only reads from its BASE registers. + inline bool isMemBaseReadOnly() const noexcept { return (_opFlags & kMemBaseRW) == kMemBaseRead; } + //! Tests whether the instruction only writes to its BASE registers. + inline bool isMemBaseWriteOnly() const noexcept { return (_opFlags & kMemBaseRW) == kMemBaseWrite; } + + //! Tests whether the instruction modifies the BASE register before it uses + //! it to calculate the target address. + inline bool isMemBasePreModify() const noexcept { return hasOpFlag(kMemBasePreModify); } + //! Tests whether the instruction modifies the BASE register after it uses + //! it to calculate the target address. + inline bool isMemBasePostModify() const noexcept { return hasOpFlag(kMemBasePostModify); } + + //! Tests whether the instruction's memory INDEX register is used. + inline bool isMemIndexUsed() const noexcept { return (_opFlags & kMemIndexRW) != 0; } + //! Tests whether the instruction reads the INDEX registers. + inline bool isMemIndexRead() const noexcept { return hasOpFlag(kMemIndexRead); } + //! Tests whether the instruction writes to its INDEX registers. + inline bool isMemIndexWrite() const noexcept { return hasOpFlag(kMemIndexWrite); } + //! Tests whether the instruction reads and writes from/to its INDEX registers. + inline bool isMemIndexReadWrite() const noexcept { return (_opFlags & kMemIndexRW) == kMemIndexRW; } + //! Tests whether the instruction only reads from its INDEX registers. + inline bool isMemIndexReadOnly() const noexcept { return (_opFlags & kMemIndexRW) == kMemIndexRead; } + //! Tests whether the instruction only writes to its INDEX registers. + inline bool isMemIndexWriteOnly() const noexcept { return (_opFlags & kMemIndexRW) == kMemIndexWrite; } + + //! \} + + //! \name Physical Register ID + //! \{ + + //! Returns a physical id of the register that is fixed for this operand. + //! + //! Returns \ref BaseReg::kIdBad if any register can be used. + inline uint32_t physId() const noexcept { return _physId; } + //! Tests whether \ref physId() would return a valid physical register id. + inline bool hasPhysId() const noexcept { return _physId != BaseReg::kIdBad; } + //! Sets physical register id, which would be fixed for this operand. + inline void setPhysId(uint32_t physId) noexcept { _physId = uint8_t(physId); } + + //! \} + + //! \name Reg/Mem Information + //! \{ + + //! Returns Reg/Mem size of the operand. + inline uint32_t rmSize() const noexcept { return _rmSize; } + //! Sets Reg/Mem size of the operand. + inline void setRmSize(uint32_t rmSize) noexcept { _rmSize = uint8_t(rmSize); } + + //! \} + + //! \name Read & Write Masks + //! \{ + + //! Returns read mask. + inline uint64_t readByteMask() const noexcept { return _readByteMask; } + //! Returns write mask. + inline uint64_t writeByteMask() const noexcept { return _writeByteMask; } + //! Returns extend mask. + inline uint64_t extendByteMask() const noexcept { return _extendByteMask; } + + //! Sets read mask. + inline void setReadByteMask(uint64_t mask) noexcept { _readByteMask = mask; } + //! Sets write mask. + inline void setWriteByteMask(uint64_t mask) noexcept { _writeByteMask = mask; } + //! Sets externd mask. + inline void setExtendByteMask(uint64_t mask) noexcept { _extendByteMask = mask; } + + //! \} +}; + +// ============================================================================ +// [asmjit::InstRWInfo] +// ============================================================================ + +//! Read/Write information of an instruction. +struct InstRWInfo { + //! Instruction flags (there are no flags at the moment, this field is reserved). + uint32_t _instFlags; + //! Mask of CPU flags read. + uint32_t _readFlags; + //! Mask of CPU flags written. + uint32_t _writeFlags; + //! Count of operands. + uint8_t _opCount; + //! CPU feature required for replacing register operand with memory operand. + uint8_t _rmFeature; + //! Reserved for future use. + uint8_t _reserved[18]; + //! Read/Write onfo of extra register (rep{} or kz{}). + OpRWInfo _extraReg; + //! Read/Write info of instruction operands. + OpRWInfo _operands[Globals::kMaxOpCount]; + + //! \name Commons + //! \{ + + //! Resets this RW information to all zeros. + inline void reset() noexcept { memset(this, 0, sizeof(*this)); } + + //! \} + + //! \name Instruction Flags + //! + //! \{ + + inline uint32_t instFlags() const noexcept { return _instFlags; } + inline bool hasInstFlag(uint32_t flag) const noexcept { return (_instFlags & flag) != 0; } + + //! } + + //! \name CPU Flags Read/Write Information + //! \{ + + //! Returns read flags of the instruction. + inline uint32_t readFlags() const noexcept { return _readFlags; } + //! Returns write flags of the instruction. + inline uint32_t writeFlags() const noexcept { return _writeFlags; } + + //! \} + + //! \name Reg/Mem Information + //! \{ + + //! Returns the CPU feature required to replace a register operand with memory + //! operand. If the returned feature is zero (none) then this instruction + //! either doesn't provide memory operand combination or there is no extra + //! CPU feature required. + //! + //! X86 Specific + //! ------------ + //! + //! Some AVX+ instructions may require extra features for replacing registers + //! with memory operands, for example VPSLLDQ instruction only supports + //! 'reg/reg/imm' combination on AVX/AVX2 capable CPUs and requires AVX-512 for + //! 'reg/mem/imm' combination. + inline uint32_t rmFeature() const noexcept { return _rmFeature; } + + //! \} + + //! \name Operand Read/Write Information + //! \{ + + //! Returns RW information of extra register operand (extraReg). + inline const OpRWInfo& extraReg() const noexcept { return _extraReg; } + + //! Returns RW information of all instruction's operands. + inline const OpRWInfo* operands() const noexcept { return _operands; } + + //! Returns RW information of the operand at the given `index`. + inline const OpRWInfo& operand(size_t index) const noexcept { + ASMJIT_ASSERT(index < Globals::kMaxOpCount); + return _operands[index]; + } + + //! Returns the number of operands this instruction has. + inline uint32_t opCount() const noexcept { return _opCount; } + + //! \} +}; + +// ============================================================================ +// [asmjit::InstAPI] +// ============================================================================ + +//! Instruction API. +namespace InstAPI { + +//! Validation flags that can be used with \ref InstAPI::validate(). +enum ValidationFlags : uint32_t { + //! Allow virtual registers in the instruction. + kValidationFlagVirtRegs = 0x01u +}; + +#ifndef ASMJIT_NO_TEXT +//! Appends the name of the instruction specified by `instId` and `instOptions` +//! into the `output` string. +//! +//! \note Instruction options would only affect instruction prefix & suffix, +//! other options would be ignored. If `instOptions` is zero then only raw +//! instruction name (without any additional text) will be appended. +ASMJIT_API Error instIdToString(uint32_t arch, uint32_t instId, String& output) noexcept; + +//! Parses an instruction name in the given string `s`. Length is specified +//! by `len` argument, which can be `SIZE_MAX` if `s` is known to be null +//! terminated. +//! +//! Returns the parsed instruction id or \ref BaseInst::kIdNone if no such +//! instruction exists. +ASMJIT_API uint32_t stringToInstId(uint32_t arch, const char* s, size_t len) noexcept; +#endif // !ASMJIT_NO_TEXT + +#ifndef ASMJIT_NO_VALIDATION +//! Validates the given instruction considering the validation `flags`, see +//! \ref ValidationFlags. +ASMJIT_API Error validate(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, uint32_t validationFlags = 0) noexcept; +#endif // !ASMJIT_NO_VALIDATION + +#ifndef ASMJIT_NO_INTROSPECTION +//! Gets Read/Write information of the given instruction. +ASMJIT_API Error queryRWInfo(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept; + +//! Gets CPU features required by the given instruction. +ASMJIT_API Error queryFeatures(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, BaseFeatures* out) noexcept; +#endif // !ASMJIT_NO_INTROSPECTION + +} // {InstAPI} + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_INST_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/jitallocator.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/jitallocator.cpp new file mode 100644 index 0000000..b576e21 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/jitallocator.cpp @@ -0,0 +1,1246 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#ifndef ASMJIT_NO_JIT + +#include "../core/archtraits.h" +#include "../core/jitallocator.h" +#include "../core/osutils_p.h" +#include "../core/support.h" +#include "../core/virtmem.h" +#include "../core/zone.h" +#include "../core/zonelist.h" +#include "../core/zonetree.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::JitAllocator - Constants] +// ============================================================================ + +enum JitAllocatorConstants : uint32_t { + //! Number of pools to use when `JitAllocator::kOptionUseMultiplePools` is set. + //! + //! Each pool increases granularity twice to make memory management more + //! efficient. Ideal number of pools appears to be 3 to 4 as it distributes + //! small and large functions properly. + kJitAllocatorMultiPoolCount = 3, + + //! Minimum granularity (and the default granularity for pool #0). + kJitAllocatorBaseGranularity = 64, + + //! Maximum block size (32MB). + kJitAllocatorMaxBlockSize = 1024 * 1024 * 32 +}; + +static inline uint32_t JitAllocator_defaultFillPattern() noexcept { + // X86 and X86_64 - 4x 'int3' instruction. + if (ASMJIT_ARCH_X86) + return 0xCCCCCCCCu; + + // Unknown... + return 0u; +} + +// ============================================================================ +// [asmjit::BitVectorRangeIterator] +// ============================================================================ + +template +class BitVectorRangeIterator { +public: + const T* _ptr; + size_t _idx; + size_t _end; + T _bitWord; + + enum : uint32_t { kBitWordSize = Support::bitSizeOf() }; + enum : T { kXorMask = B == 0 ? Support::allOnes() : T(0) }; + + ASMJIT_INLINE BitVectorRangeIterator(const T* data, size_t numBitWords) noexcept { + init(data, numBitWords); + } + + ASMJIT_INLINE BitVectorRangeIterator(const T* data, size_t numBitWords, size_t start, size_t end) noexcept { + init(data, numBitWords, start, end); + } + + ASMJIT_INLINE void init(const T* data, size_t numBitWords) noexcept { + init(data, numBitWords, 0, numBitWords * kBitWordSize); + } + + ASMJIT_INLINE void init(const T* data, size_t numBitWords, size_t start, size_t end) noexcept { + ASMJIT_ASSERT(numBitWords >= (end + kBitWordSize - 1) / kBitWordSize); + DebugUtils::unused(numBitWords); + + size_t idx = Support::alignDown(start, kBitWordSize); + const T* ptr = data + (idx / kBitWordSize); + + T bitWord = 0; + if (idx < end) + bitWord = (*ptr ^ kXorMask) & (Support::allOnes() << (start % kBitWordSize)); + + _ptr = ptr; + _idx = idx; + _end = end; + _bitWord = bitWord; + } + + ASMJIT_INLINE bool nextRange(size_t* rangeStart, size_t* rangeEnd, size_t rangeHint = std::numeric_limits::max()) noexcept { + // Skip all empty BitWords. + while (_bitWord == 0) { + _idx += kBitWordSize; + if (_idx >= _end) + return false; + _bitWord = (*++_ptr) ^ kXorMask; + } + + size_t i = Support::ctz(_bitWord); + + *rangeStart = _idx + i; + _bitWord = ~(_bitWord ^ ~(Support::allOnes() << i)); + + if (_bitWord == 0) { + *rangeEnd = Support::min(_idx + kBitWordSize, _end); + while (*rangeEnd - *rangeStart < rangeHint) { + _idx += kBitWordSize; + if (_idx >= _end) + break; + + _bitWord = (*++_ptr) ^ kXorMask; + if (_bitWord != Support::allOnes()) { + size_t j = Support::ctz(~_bitWord); + *rangeEnd = Support::min(_idx + j, _end); + _bitWord = _bitWord ^ ~(Support::allOnes() << j); + break; + } + + *rangeEnd = Support::min(_idx + kBitWordSize, _end); + _bitWord = 0; + continue; + } + + return true; + } + else { + size_t j = Support::ctz(_bitWord); + *rangeEnd = Support::min(_idx + j, _end); + + _bitWord = ~(_bitWord ^ ~(Support::allOnes() << j)); + return true; + } + } +}; + +// ============================================================================ +// [asmjit::JitAllocator - Pool] +// ============================================================================ + +class JitAllocatorBlock; + +class JitAllocatorPool { +public: + ASMJIT_NONCOPYABLE(JitAllocatorPool) + + inline JitAllocatorPool(uint32_t granularity) noexcept + : blocks(), + cursor(nullptr), + blockCount(0), + granularity(uint16_t(granularity)), + granularityLog2(uint8_t(Support::ctz(granularity))), + emptyBlockCount(0), + totalAreaSize(0), + totalAreaUsed(0), + totalOverheadBytes(0) {} + + inline void reset() noexcept { + blocks.reset(); + cursor = nullptr; + blockCount = 0; + totalAreaSize = 0; + totalAreaUsed = 0; + totalOverheadBytes = 0; + } + + inline size_t byteSizeFromAreaSize(uint32_t areaSize) const noexcept { return size_t(areaSize) * granularity; } + inline uint32_t areaSizeFromByteSize(size_t size) const noexcept { return uint32_t((size + granularity - 1) >> granularityLog2); } + + inline size_t bitWordCountFromAreaSize(uint32_t areaSize) const noexcept { + using namespace Support; + return alignUp(areaSize, kBitWordSizeInBits) / kBitWordSizeInBits; + } + + //! Double linked list of blocks. + ZoneList blocks; + //! Where to start looking first. + JitAllocatorBlock* cursor; + + //! Count of blocks. + uint32_t blockCount; + //! Allocation granularity. + uint16_t granularity; + //! Log2(granularity). + uint8_t granularityLog2; + //! Count of empty blocks (either 0 or 1 as we won't keep more blocks empty). + uint8_t emptyBlockCount; + + //! Number of bits reserved across all blocks. + size_t totalAreaSize; + //! Number of bits used across all blocks. + size_t totalAreaUsed; + //! Overhead of all blocks (in bytes). + size_t totalOverheadBytes; +}; + +// ============================================================================ +// [asmjit::JitAllocator - Block] +// ============================================================================ + +class JitAllocatorBlock : public ZoneTreeNodeT, + public ZoneListNode { +public: + ASMJIT_NONCOPYABLE(JitAllocatorBlock) + + enum Flags : uint32_t { + //! Block is empty. + kFlagEmpty = 0x00000001u, + //! Block is dirty (largestUnusedArea, searchStart, searchEnd). + kFlagDirty = 0x00000002u, + //! Block is dual-mapped. + kFlagDualMapped = 0x00000004u + }; + + //! Link to the pool that owns this block. + JitAllocatorPool* _pool; + //! Virtual memory mapping - either single mapping (both pointers equal) or + //! dual mapping, where one pointer is Read+Execute and the second Read+Write. + VirtMem::DualMapping _mapping; + //! Virtual memory size (block size) [bytes]. + size_t _blockSize; + + //! Block flags. + uint32_t _flags; + //! Size of the whole block area (bit-vector size). + uint32_t _areaSize; + //! Used area (number of bits in bit-vector used). + uint32_t _areaUsed; + //! The largest unused continuous area in the bit-vector (or `areaSize` to initiate rescan). + uint32_t _largestUnusedArea; + //! Start of a search range (for unused bits). + uint32_t _searchStart; + //! End of a search range (for unused bits). + uint32_t _searchEnd; + + //! Used bit-vector (0 = unused, 1 = used). + Support::BitWord* _usedBitVector; + //! Stop bit-vector (0 = don't care, 1 = stop). + Support::BitWord* _stopBitVector; + + inline JitAllocatorBlock( + JitAllocatorPool* pool, + VirtMem::DualMapping mapping, + size_t blockSize, + uint32_t blockFlags, + Support::BitWord* usedBitVector, + Support::BitWord* stopBitVector, + uint32_t areaSize) noexcept + : ZoneTreeNodeT(), + _pool(pool), + _mapping(mapping), + _blockSize(blockSize), + _flags(blockFlags), + _areaSize(areaSize), + _areaUsed(0), + _largestUnusedArea(areaSize), + _searchStart(0), + _searchEnd(areaSize), + _usedBitVector(usedBitVector), + _stopBitVector(stopBitVector) {} + + inline JitAllocatorPool* pool() const noexcept { return _pool; } + + inline uint8_t* roPtr() const noexcept { return static_cast(_mapping.ro); } + inline uint8_t* rwPtr() const noexcept { return static_cast(_mapping.rw); } + + inline bool hasFlag(uint32_t f) const noexcept { return (_flags & f) != 0; } + inline void addFlags(uint32_t f) noexcept { _flags |= f; } + inline void clearFlags(uint32_t f) noexcept { _flags &= ~f; } + + inline bool isDirty() const noexcept { return hasFlag(kFlagDirty); } + inline void makeDirty() noexcept { addFlags(kFlagDirty); } + + inline size_t blockSize() const noexcept { return _blockSize; } + + inline uint32_t areaSize() const noexcept { return _areaSize; } + inline uint32_t areaUsed() const noexcept { return _areaUsed; } + inline uint32_t areaAvailable() const noexcept { return _areaSize - _areaUsed; } + inline uint32_t largestUnusedArea() const noexcept { return _largestUnusedArea; } + + inline void decreaseUsedArea(uint32_t value) noexcept { + _areaUsed -= value; + _pool->totalAreaUsed -= value; + } + + inline void markAllocatedArea(uint32_t allocatedAreaStart, uint32_t allocatedAreaEnd) noexcept { + uint32_t allocatedAreaSize = allocatedAreaEnd - allocatedAreaStart; + + // Mark the newly allocated space as occupied and also the sentinel. + Support::bitVectorFill(_usedBitVector, allocatedAreaStart, allocatedAreaSize); + Support::bitVectorSetBit(_stopBitVector, allocatedAreaEnd - 1, true); + + // Update search region and statistics. + _pool->totalAreaUsed += allocatedAreaSize; + _areaUsed += allocatedAreaSize; + + if (areaAvailable() == 0) { + _searchStart = _areaSize; + _searchEnd = 0; + _largestUnusedArea = 0; + clearFlags(kFlagDirty); + } + else { + if (_searchStart == allocatedAreaStart) + _searchStart = allocatedAreaEnd; + if (_searchEnd == allocatedAreaEnd) + _searchEnd = allocatedAreaStart; + addFlags(kFlagDirty); + } + } + + inline void markReleasedArea(uint32_t releasedAreaStart, uint32_t releasedAreaEnd) noexcept { + uint32_t releasedAreaSize = releasedAreaEnd - releasedAreaStart; + + // Update the search region and statistics. + _pool->totalAreaUsed -= releasedAreaSize; + _areaUsed -= releasedAreaSize; + _searchStart = Support::min(_searchStart, releasedAreaStart); + _searchEnd = Support::max(_searchEnd, releasedAreaEnd); + + // Unmark occupied bits and also the sentinel. + Support::bitVectorClear(_usedBitVector, releasedAreaStart, releasedAreaSize); + Support::bitVectorSetBit(_stopBitVector, releasedAreaEnd - 1, false); + + if (areaUsed() == 0) { + _searchStart = 0; + _searchEnd = _areaSize; + _largestUnusedArea = _areaSize; + addFlags(kFlagEmpty); + clearFlags(kFlagDirty); + } + else { + addFlags(kFlagDirty); + } + } + + inline void markShrunkArea(uint32_t shrunkAreaStart, uint32_t shrunkAreaEnd) noexcept { + uint32_t shrunkAreaSize = shrunkAreaEnd - shrunkAreaStart; + + // Shrunk area cannot start at zero as it would mean that we have shrunk the first + // block to zero bytes, which is not allowed as such block must be released instead. + ASMJIT_ASSERT(shrunkAreaStart != 0); + ASMJIT_ASSERT(shrunkAreaSize != 0); + + // Update the search region and statistics. + _pool->totalAreaUsed -= shrunkAreaSize; + _areaUsed -= shrunkAreaSize; + _searchStart = Support::min(_searchStart, shrunkAreaStart); + _searchEnd = Support::max(_searchEnd, shrunkAreaEnd); + + // Unmark the released space and move the sentinel. + Support::bitVectorClear(_usedBitVector, shrunkAreaStart, shrunkAreaSize); + Support::bitVectorSetBit(_stopBitVector, shrunkAreaEnd - 1, false); + Support::bitVectorSetBit(_stopBitVector, shrunkAreaStart - 1, true); + + addFlags(kFlagDirty); + } + + // RBTree default CMP uses '<' and '>' operators. + inline bool operator<(const JitAllocatorBlock& other) const noexcept { return roPtr() < other.roPtr(); } + inline bool operator>(const JitAllocatorBlock& other) const noexcept { return roPtr() > other.roPtr(); } + + // Special implementation for querying blocks by `key`, which must be in `[BlockPtr, BlockPtr + BlockSize)` range. + inline bool operator<(const uint8_t* key) const noexcept { return roPtr() + _blockSize <= key; } + inline bool operator>(const uint8_t* key) const noexcept { return roPtr() > key; } +}; + +// ============================================================================ +// [asmjit::JitAllocator - PrivateImpl] +// ============================================================================ + +class JitAllocatorPrivateImpl : public JitAllocator::Impl { +public: + inline JitAllocatorPrivateImpl(JitAllocatorPool* pools, size_t poolCount) noexcept + : JitAllocator::Impl {}, + pools(pools), + poolCount(poolCount) {} + inline ~JitAllocatorPrivateImpl() noexcept {} + + //! Lock for thread safety. + mutable Lock lock; + //! System page size (also a minimum block size). + uint32_t pageSize; + + //! Blocks from all pools in RBTree. + ZoneTree tree; + //! Allocator pools. + JitAllocatorPool* pools; + //! Number of allocator pools. + size_t poolCount; +}; + +static const JitAllocator::Impl JitAllocatorImpl_none {}; +static const JitAllocator::CreateParams JitAllocatorParams_none {}; + +// ============================================================================ +// [asmjit::JitAllocator - Utilities] +// ============================================================================ + +static inline JitAllocatorPrivateImpl* JitAllocatorImpl_new(const JitAllocator::CreateParams* params) noexcept { + VirtMem::Info vmInfo = VirtMem::info(); + + if (!params) + params = &JitAllocatorParams_none; + + uint32_t options = params->options; + uint32_t blockSize = params->blockSize; + uint32_t granularity = params->granularity; + uint32_t fillPattern = params->fillPattern; + + // Setup pool count to [1..3]. + size_t poolCount = 1; + if (options & JitAllocator::kOptionUseMultiplePools) + poolCount = kJitAllocatorMultiPoolCount;; + + // Setup block size [64kB..256MB]. + if (blockSize < 64 * 1024 || blockSize > 256 * 1024 * 1024 || !Support::isPowerOf2(blockSize)) + blockSize = vmInfo.pageGranularity; + + // Setup granularity [64..256]. + if (granularity < 64 || granularity > 256 || !Support::isPowerOf2(granularity)) + granularity = kJitAllocatorBaseGranularity; + + // Setup fill-pattern. + if (!(options & JitAllocator::kOptionCustomFillPattern)) + fillPattern = JitAllocator_defaultFillPattern(); + + size_t size = sizeof(JitAllocatorPrivateImpl) + sizeof(JitAllocatorPool) * poolCount; + void* p = ::malloc(size); + if (ASMJIT_UNLIKELY(!p)) + return nullptr; + + JitAllocatorPool* pools = reinterpret_cast((uint8_t*)p + sizeof(JitAllocatorPrivateImpl)); + JitAllocatorPrivateImpl* impl = new(p) JitAllocatorPrivateImpl(pools, poolCount); + + impl->options = options; + impl->blockSize = blockSize; + impl->granularity = granularity; + impl->fillPattern = fillPattern; + impl->pageSize = vmInfo.pageSize; + + for (size_t poolId = 0; poolId < poolCount; poolId++) + new(&pools[poolId]) JitAllocatorPool(granularity << poolId); + + return impl; +} + +static inline void JitAllocatorImpl_destroy(JitAllocatorPrivateImpl* impl) noexcept { + impl->~JitAllocatorPrivateImpl(); + ::free(impl); +} + +static inline size_t JitAllocatorImpl_sizeToPoolId(const JitAllocatorPrivateImpl* impl, size_t size) noexcept { + size_t poolId = impl->poolCount - 1; + size_t granularity = size_t(impl->granularity) << poolId; + + while (poolId) { + if (Support::alignUp(size, granularity) == size) + break; + poolId--; + granularity >>= 1; + } + + return poolId; +} + +static inline size_t JitAllocatorImpl_bitVectorSizeToByteSize(uint32_t areaSize) noexcept { + using Support::kBitWordSizeInBits; + return ((areaSize + kBitWordSizeInBits - 1u) / kBitWordSizeInBits) * sizeof(Support::BitWord); +} + +static inline size_t JitAllocatorImpl_calculateIdealBlockSize(JitAllocatorPrivateImpl* impl, JitAllocatorPool* pool, size_t allocationSize) noexcept { + JitAllocatorBlock* last = pool->blocks.last(); + size_t blockSize = last ? last->blockSize() : size_t(impl->blockSize); + + if (blockSize < kJitAllocatorMaxBlockSize) + blockSize *= 2u; + + if (allocationSize > blockSize) { + blockSize = Support::alignUp(allocationSize, impl->blockSize); + if (ASMJIT_UNLIKELY(blockSize < allocationSize)) + return 0; // Overflown. + } + + return blockSize; +} + +ASMJIT_FAVOR_SPEED static void JitAllocatorImpl_fillPattern(void* mem, uint32_t pattern, size_t sizeInBytes) noexcept { + size_t n = sizeInBytes / 4u; + uint32_t* p = static_cast(mem); + + for (size_t i = 0; i < n; i++) + p[i] = pattern; +} + +// Allocate a new `JitAllocatorBlock` for the given `blockSize`. +// +// NOTE: The block doesn't have `kFlagEmpty` flag set, because the new block +// is only allocated when it's actually needed, so it would be cleared anyway. +static JitAllocatorBlock* JitAllocatorImpl_newBlock(JitAllocatorPrivateImpl* impl, JitAllocatorPool* pool, size_t blockSize) noexcept { + using Support::BitWord; + using Support::kBitWordSizeInBits; + + uint32_t areaSize = uint32_t((blockSize + pool->granularity - 1) >> pool->granularityLog2); + uint32_t numBitWords = (areaSize + kBitWordSizeInBits - 1u) / kBitWordSizeInBits; + + JitAllocatorBlock* block = static_cast(::malloc(sizeof(JitAllocatorBlock))); + BitWord* bitWords = nullptr; + VirtMem::DualMapping virtMem {}; + Error err = kErrorOutOfMemory; + + if (block != nullptr) + bitWords = static_cast(::malloc(size_t(numBitWords) * 2 * sizeof(BitWord))); + + uint32_t blockFlags = 0; + if (bitWords != nullptr) { + if (impl->options & JitAllocator::kOptionUseDualMapping) { + err = VirtMem::allocDualMapping(&virtMem, blockSize, VirtMem::kAccessRWX); + blockFlags |= JitAllocatorBlock::kFlagDualMapped; + } + else { + err = VirtMem::alloc(&virtMem.ro, blockSize, VirtMem::kAccessRWX); + virtMem.rw = virtMem.ro; + } + } + + // Out of memory. + if (ASMJIT_UNLIKELY(!block || !bitWords || err != kErrorOk)) { + if (bitWords) ::free(bitWords); + if (block) ::free(block); + return nullptr; + } + + // Fill the memory if the secure mode is enabled. + if (impl->options & JitAllocator::kOptionFillUnusedMemory) + JitAllocatorImpl_fillPattern(virtMem.rw, impl->fillPattern, blockSize); + + memset(bitWords, 0, size_t(numBitWords) * 2 * sizeof(BitWord)); + return new(block) JitAllocatorBlock(pool, virtMem, blockSize, blockFlags, bitWords, bitWords + numBitWords, areaSize); +} + +static void JitAllocatorImpl_deleteBlock(JitAllocatorPrivateImpl* impl, JitAllocatorBlock* block) noexcept { + DebugUtils::unused(impl); + + if (block->hasFlag(JitAllocatorBlock::kFlagDualMapped)) + VirtMem::releaseDualMapping(&block->_mapping, block->blockSize()); + else + VirtMem::release(block->roPtr(), block->blockSize()); + + ::free(block->_usedBitVector); + ::free(block); +} + +static void JitAllocatorImpl_insertBlock(JitAllocatorPrivateImpl* impl, JitAllocatorBlock* block) noexcept { + JitAllocatorPool* pool = block->pool(); + + if (!pool->cursor) + pool->cursor = block; + + // Add to RBTree and List. + impl->tree.insert(block); + pool->blocks.append(block); + + // Update statistics. + pool->blockCount++; + pool->totalAreaSize += block->areaSize(); + pool->totalOverheadBytes += sizeof(JitAllocatorBlock) + JitAllocatorImpl_bitVectorSizeToByteSize(block->areaSize()) * 2u; +} + +static void JitAllocatorImpl_removeBlock(JitAllocatorPrivateImpl* impl, JitAllocatorBlock* block) noexcept { + JitAllocatorPool* pool = block->pool(); + + // Remove from RBTree and List. + if (pool->cursor == block) + pool->cursor = block->hasPrev() ? block->prev() : block->next(); + + impl->tree.remove(block); + pool->blocks.unlink(block); + + // Update statistics. + pool->blockCount--; + pool->totalAreaSize -= block->areaSize(); + pool->totalOverheadBytes -= sizeof(JitAllocatorBlock) + JitAllocatorImpl_bitVectorSizeToByteSize(block->areaSize()) * 2u; +} + +static void JitAllocatorImpl_wipeOutBlock(JitAllocatorPrivateImpl* impl, JitAllocatorBlock* block) noexcept { + JitAllocatorPool* pool = block->pool(); + + if (block->hasFlag(JitAllocatorBlock::kFlagEmpty)) + return; + + uint32_t areaSize = block->areaSize(); + uint32_t granularity = pool->granularity; + size_t numBitWords = pool->bitWordCountFromAreaSize(areaSize); + + if (impl->options & JitAllocator::kOptionFillUnusedMemory) { + uint8_t* rwPtr = block->rwPtr(); + for (size_t i = 0; i < numBitWords; i++) { + Support::BitWordIterator it(block->_usedBitVector[i]); + while (it.hasNext()) { + size_t index = it.next(); + JitAllocatorImpl_fillPattern(rwPtr + index * granularity , impl->fillPattern, granularity); + } + rwPtr += Support::bitSizeOf() * granularity; + } + } + + memset(block->_usedBitVector, 0, size_t(numBitWords) * sizeof(Support::BitWord)); + memset(block->_stopBitVector, 0, size_t(numBitWords) * sizeof(Support::BitWord)); + + block->_areaUsed = 0; + block->_largestUnusedArea = areaSize; + block->_searchStart = 0; + block->_searchEnd = areaSize; + block->addFlags(JitAllocatorBlock::kFlagEmpty); + block->clearFlags(JitAllocatorBlock::kFlagDirty); +} + +// ============================================================================ +// [asmjit::JitAllocator - Construction / Destruction] +// ============================================================================ + +JitAllocator::JitAllocator(const CreateParams* params) noexcept { + _impl = JitAllocatorImpl_new(params); + if (ASMJIT_UNLIKELY(!_impl)) + _impl = const_cast(&JitAllocatorImpl_none); +} + +JitAllocator::~JitAllocator() noexcept { + if (_impl == &JitAllocatorImpl_none) + return; + + reset(Globals::kResetHard); + JitAllocatorImpl_destroy(static_cast(_impl)); +} + +// ============================================================================ +// [asmjit::JitAllocator - Reset] +// ============================================================================ + +void JitAllocator::reset(uint32_t resetPolicy) noexcept { + if (_impl == &JitAllocatorImpl_none) + return; + + JitAllocatorPrivateImpl* impl = static_cast(_impl); + impl->tree.reset(); + size_t poolCount = impl->poolCount; + + for (size_t poolId = 0; poolId < poolCount; poolId++) { + JitAllocatorPool& pool = impl->pools[poolId]; + JitAllocatorBlock* block = pool.blocks.first(); + + JitAllocatorBlock* blockToKeep = nullptr; + if (resetPolicy != Globals::kResetHard && !(impl->options & kOptionImmediateRelease)) { + blockToKeep = block; + block = block->next(); + } + + while (block) { + JitAllocatorBlock* next = block->next(); + JitAllocatorImpl_deleteBlock(impl, block); + block = next; + } + + pool.reset(); + + if (blockToKeep) { + blockToKeep->_listNodes[0] = nullptr; + blockToKeep->_listNodes[1] = nullptr; + JitAllocatorImpl_wipeOutBlock(impl, blockToKeep); + JitAllocatorImpl_insertBlock(impl, blockToKeep); + pool.emptyBlockCount = 1; + } + } +} + +// ============================================================================ +// [asmjit::JitAllocator - Statistics] +// ============================================================================ + +JitAllocator::Statistics JitAllocator::statistics() const noexcept { + Statistics statistics; + statistics.reset(); + + if (ASMJIT_LIKELY(_impl != &JitAllocatorImpl_none)) { + JitAllocatorPrivateImpl* impl = static_cast(_impl); + LockGuard guard(impl->lock); + + size_t poolCount = impl->poolCount; + for (size_t poolId = 0; poolId < poolCount; poolId++) { + const JitAllocatorPool& pool = impl->pools[poolId]; + statistics._blockCount += size_t(pool.blockCount); + statistics._reservedSize += size_t(pool.totalAreaSize) * pool.granularity; + statistics._usedSize += size_t(pool.totalAreaUsed) * pool.granularity; + statistics._overheadSize += size_t(pool.totalOverheadBytes); + } + } + + return statistics; +} + +// ============================================================================ +// [asmjit::JitAllocator - Alloc / Release] +// ============================================================================ + +Error JitAllocator::alloc(void** roPtrOut, void** rwPtrOut, size_t size) noexcept { + if (ASMJIT_UNLIKELY(_impl == &JitAllocatorImpl_none)) + return DebugUtils::errored(kErrorNotInitialized); + + JitAllocatorPrivateImpl* impl = static_cast(_impl); + constexpr uint32_t kNoIndex = std::numeric_limits::max(); + + *roPtrOut = nullptr; + *rwPtrOut = nullptr; + + // Align to the minimum granularity by default. + size = Support::alignUp(size, impl->granularity); + if (ASMJIT_UNLIKELY(size == 0)) + return DebugUtils::errored(kErrorInvalidArgument); + + if (ASMJIT_UNLIKELY(size > std::numeric_limits::max() / 2)) + return DebugUtils::errored(kErrorTooLarge); + + LockGuard guard(impl->lock); + JitAllocatorPool* pool = &impl->pools[JitAllocatorImpl_sizeToPoolId(impl, size)]; + + uint32_t areaIndex = kNoIndex; + uint32_t areaSize = uint32_t(pool->areaSizeFromByteSize(size)); + + // Try to find the requested memory area in existing blocks. + JitAllocatorBlock* block = pool->blocks.first(); + if (block) { + JitAllocatorBlock* initial = block; + do { + JitAllocatorBlock* next = block->hasNext() ? block->next() : pool->blocks.first(); + if (block->areaAvailable() >= areaSize) { + if (block->isDirty() || block->largestUnusedArea() >= areaSize) { + BitVectorRangeIterator it(block->_usedBitVector, pool->bitWordCountFromAreaSize(block->areaSize()), block->_searchStart, block->_searchEnd); + + size_t rangeStart = 0; + size_t rangeEnd = block->areaSize(); + + size_t searchStart = SIZE_MAX; + size_t largestArea = 0; + + while (it.nextRange(&rangeStart, &rangeEnd, areaSize)) { + size_t rangeSize = rangeEnd - rangeStart; + if (rangeSize >= areaSize) { + areaIndex = uint32_t(rangeStart); + break; + } + + searchStart = Support::min(searchStart, rangeStart); + largestArea = Support::max(largestArea, rangeSize); + } + + if (areaIndex != kNoIndex) + break; + + if (searchStart != SIZE_MAX) { + // Because we have iterated over the entire block, we can now mark the + // largest unused area that can be used to cache the next traversal. + size_t searchEnd = rangeEnd; + + block->_searchStart = uint32_t(searchStart); + block->_searchEnd = uint32_t(searchEnd); + block->_largestUnusedArea = uint32_t(largestArea); + block->clearFlags(JitAllocatorBlock::kFlagDirty); + } + } + } + + block = next; + } while (block != initial); + } + + // Allocate a new block if there is no region of a required width. + if (areaIndex == kNoIndex) { + size_t blockSize = JitAllocatorImpl_calculateIdealBlockSize(impl, pool, size); + if (ASMJIT_UNLIKELY(!blockSize)) + return DebugUtils::errored(kErrorOutOfMemory); + + block = JitAllocatorImpl_newBlock(impl, pool, blockSize); + areaIndex = 0; + + if (ASMJIT_UNLIKELY(!block)) + return DebugUtils::errored(kErrorOutOfMemory); + + JitAllocatorImpl_insertBlock(impl, block); + block->_searchStart = areaSize; + block->_largestUnusedArea = block->areaSize() - areaSize; + } + else if (block->hasFlag(JitAllocatorBlock::kFlagEmpty)) { + pool->emptyBlockCount--; + block->clearFlags(JitAllocatorBlock::kFlagEmpty); + } + + // Update statistics. + block->markAllocatedArea(areaIndex, areaIndex + areaSize); + + // Return a pointer to the allocated memory. + size_t offset = pool->byteSizeFromAreaSize(areaIndex); + ASMJIT_ASSERT(offset <= block->blockSize() - size); + + *roPtrOut = block->roPtr() + offset; + *rwPtrOut = block->rwPtr() + offset; + return kErrorOk; +} + +Error JitAllocator::release(void* roPtr) noexcept { + if (ASMJIT_UNLIKELY(_impl == &JitAllocatorImpl_none)) + return DebugUtils::errored(kErrorNotInitialized); + + if (ASMJIT_UNLIKELY(!roPtr)) + return DebugUtils::errored(kErrorInvalidArgument); + + JitAllocatorPrivateImpl* impl = static_cast(_impl); + LockGuard guard(impl->lock); + + JitAllocatorBlock* block = impl->tree.get(static_cast(roPtr)); + if (ASMJIT_UNLIKELY(!block)) + return DebugUtils::errored(kErrorInvalidState); + + // Offset relative to the start of the block. + JitAllocatorPool* pool = block->pool(); + size_t offset = (size_t)((uint8_t*)roPtr - block->roPtr()); + + // The first bit representing the allocated area and its size. + uint32_t areaIndex = uint32_t(offset >> pool->granularityLog2); + uint32_t areaEnd = uint32_t(Support::bitVectorIndexOf(block->_stopBitVector, areaIndex, true)) + 1; + uint32_t areaSize = areaEnd - areaIndex; + + block->markReleasedArea(areaIndex, areaEnd); + + // Fill the released memory if the secure mode is enabled. + if (impl->options & kOptionFillUnusedMemory) + JitAllocatorImpl_fillPattern(block->rwPtr() + areaIndex * pool->granularity, impl->fillPattern, areaSize * pool->granularity); + + // Release the whole block if it became empty. + if (block->areaUsed() == 0) { + if (pool->emptyBlockCount || (impl->options & kOptionImmediateRelease)) { + JitAllocatorImpl_removeBlock(impl, block); + JitAllocatorImpl_deleteBlock(impl, block); + } + else { + pool->emptyBlockCount++; + } + } + + return kErrorOk; +} + +Error JitAllocator::shrink(void* roPtr, size_t newSize) noexcept { + if (ASMJIT_UNLIKELY(_impl == &JitAllocatorImpl_none)) + return DebugUtils::errored(kErrorNotInitialized); + + if (ASMJIT_UNLIKELY(!roPtr)) + return DebugUtils::errored(kErrorInvalidArgument); + + if (ASMJIT_UNLIKELY(newSize == 0)) + return release(roPtr); + + JitAllocatorPrivateImpl* impl = static_cast(_impl); + LockGuard guard(impl->lock); + JitAllocatorBlock* block = impl->tree.get(static_cast(roPtr)); + + if (ASMJIT_UNLIKELY(!block)) + return DebugUtils::errored(kErrorInvalidArgument); + + // Offset relative to the start of the block. + JitAllocatorPool* pool = block->pool(); + size_t offset = (size_t)((uint8_t*)roPtr - block->roPtr()); + + // The first bit representing the allocated area and its size. + uint32_t areaStart = uint32_t(offset >> pool->granularityLog2); + uint32_t areaEnd = uint32_t(Support::bitVectorIndexOf(block->_stopBitVector, areaStart, true)) + 1; + + uint32_t areaPrevSize = areaEnd - areaStart; + uint32_t areaShrunkSize = pool->areaSizeFromByteSize(newSize); + + if (ASMJIT_UNLIKELY(areaShrunkSize > areaPrevSize)) + return DebugUtils::errored(kErrorInvalidState); + + uint32_t areaDiff = areaPrevSize - areaShrunkSize; + if (areaDiff) { + block->markShrunkArea(areaStart + areaShrunkSize, areaEnd); + + // Fill released memory if the secure mode is enabled. + if (impl->options & kOptionFillUnusedMemory) + JitAllocatorImpl_fillPattern(block->rwPtr() + (areaStart + areaShrunkSize) * pool->granularity, fillPattern(), areaDiff * pool->granularity); + } + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::JitAllocator - Unit] +// ============================================================================ + +#if defined(ASMJIT_TEST) +// A pseudo random number generator based on a paper by Sebastiano Vigna: +// http://vigna.di.unimi.it/ftp/papers/xorshiftplus.pdf +class Random { +public: + // Constants suggested as `23/18/5`. + enum Steps : uint32_t { + kStep1_SHL = 23, + kStep2_SHR = 18, + kStep3_SHR = 5 + }; + + inline explicit Random(uint64_t seed = 0) noexcept { reset(seed); } + inline Random(const Random& other) noexcept = default; + + inline void reset(uint64_t seed = 0) noexcept { + // The number is arbitrary, it means nothing. + constexpr uint64_t kZeroSeed = 0x1F0A2BE71D163FA0u; + + // Generate the state data by using splitmix64. + for (uint32_t i = 0; i < 2; i++) { + seed += 0x9E3779B97F4A7C15u; + uint64_t x = seed; + x = (x ^ (x >> 30)) * 0xBF58476D1CE4E5B9u; + x = (x ^ (x >> 27)) * 0x94D049BB133111EBu; + x = (x ^ (x >> 31)); + _state[i] = x != 0 ? x : kZeroSeed; + } + } + + inline uint32_t nextUInt32() noexcept { + return uint32_t(nextUInt64() >> 32); + } + + inline uint64_t nextUInt64() noexcept { + uint64_t x = _state[0]; + uint64_t y = _state[1]; + + x ^= x << kStep1_SHL; + y ^= y >> kStep3_SHR; + x ^= x >> kStep2_SHR; + x ^= y; + + _state[0] = y; + _state[1] = x; + return x + y; + } + + uint64_t _state[2]; +}; + +// Helper class to verify that JitAllocator doesn't return addresses that overlap. +class JitAllocatorWrapper { +public: + // Address to a memory region of a given size. + class Range { + public: + inline Range(uint8_t* addr, size_t size) noexcept + : addr(addr), + size(size) {} + uint8_t* addr; + size_t size; + }; + + // Based on JitAllocator::Block, serves our purpose well... + class Record : public ZoneTreeNodeT, + public Range { + public: + inline Record(uint8_t* addr, size_t size) + : ZoneTreeNodeT(), + Range(addr, size) {} + + inline bool operator<(const Record& other) const noexcept { return addr < other.addr; } + inline bool operator>(const Record& other) const noexcept { return addr > other.addr; } + + inline bool operator<(const uint8_t* key) const noexcept { return addr + size <= key; } + inline bool operator>(const uint8_t* key) const noexcept { return addr > key; } + }; + + Zone _zone; + ZoneAllocator _heap; + ZoneTree _records; + JitAllocator _allocator; + + explicit JitAllocatorWrapper(const JitAllocator::CreateParams* params) noexcept + : _zone(1024 * 1024), + _heap(&_zone), + _allocator(params) {} + + void _insert(void* p_, size_t size) noexcept { + uint8_t* p = static_cast(p_); + uint8_t* pEnd = p + size - 1; + + Record* record; + + record = _records.get(p); + if (record) + EXPECT(record == nullptr, "Address [%p:%p] collides with a newly allocated [%p:%p]\n", record->addr, record->addr + record->size, p, p + size); + + record = _records.get(pEnd); + if (record) + EXPECT(record == nullptr, "Address [%p:%p] collides with a newly allocated [%p:%p]\n", record->addr, record->addr + record->size, p, p + size); + + record = _heap.newT(p, size); + EXPECT(record != nullptr, "Out of memory, cannot allocate 'Record'"); + + _records.insert(record); + } + + void _remove(void* p) noexcept { + Record* record = _records.get(static_cast(p)); + EXPECT(record != nullptr, "Address [%p] doesn't exist\n", p); + + _records.remove(record); + _heap.release(record, sizeof(Record)); + } + + void* alloc(size_t size) noexcept { + void* roPtr; + void* rwPtr; + + Error err = _allocator.alloc(&roPtr, &rwPtr, size); + EXPECT(err == kErrorOk, "JitAllocator failed to allocate %zu bytes\n", size); + + _insert(roPtr, size); + return roPtr; + } + + void release(void* p) noexcept { + _remove(p); + EXPECT(_allocator.release(p) == kErrorOk, "JitAllocator failed to release '%p'\n", p); + } + + void shrink(void* p, size_t newSize) noexcept { + Record* record = _records.get(static_cast(p)); + EXPECT(record != nullptr, "Address [%p] doesn't exist\n", p); + + if (!newSize) + return release(p); + + Error err = _allocator.shrink(p, newSize); + EXPECT(err == kErrorOk, "JitAllocator failed to shrink %p to %zu bytes\n", p, newSize); + + record->size = newSize; + } +}; + +static void JitAllocatorTest_shuffle(void** ptrArray, size_t count, Random& prng) noexcept { + for (size_t i = 0; i < count; ++i) + std::swap(ptrArray[i], ptrArray[size_t(prng.nextUInt32() % count)]); +} + +static void JitAllocatorTest_usage(JitAllocator& allocator) noexcept { + JitAllocator::Statistics stats = allocator.statistics(); + INFO(" Block Count : %9llu [Blocks]" , (unsigned long long)(stats.blockCount())); + INFO(" Reserved (VirtMem): %9llu [Bytes]" , (unsigned long long)(stats.reservedSize())); + INFO(" Used (VirtMem): %9llu [Bytes] (%.1f%%)", (unsigned long long)(stats.usedSize()), stats.usedSizeAsPercent()); + INFO(" Overhead (HeapMem): %9llu [Bytes] (%.1f%%)", (unsigned long long)(stats.overheadSize()), stats.overheadSizeAsPercent()); +} + +template +static void BitVectorRangeIterator_testRandom(Random& rnd, size_t count) noexcept { + for (size_t i = 0; i < count; i++) { + T in[kPatternSize]; + T out[kPatternSize]; + + for (size_t j = 0; j < kPatternSize; j++) { + in[j] = T(uint64_t(rnd.nextUInt32() & 0xFFu) * 0x0101010101010101); + out[j] = Bit == 0 ? Support::allOnes() : T(0); + } + + { + BitVectorRangeIterator it(in, kPatternSize); + size_t rangeStart, rangeEnd; + while (it.nextRange(&rangeStart, &rangeEnd)) { + if (Bit) + Support::bitVectorFill(out, rangeStart, rangeEnd - rangeStart); + else + Support::bitVectorClear(out, rangeStart, rangeEnd - rangeStart); + } + } + + for (size_t j = 0; j < kPatternSize; j++) { + EXPECT(in[j] == out[j], "Invalid pattern detected at [%zu] (%llX != %llX", j, (unsigned long long)in[j], (unsigned long long)out[j]); + } + } +} + +UNIT(jit_allocator) { + size_t kCount = BrokenAPI::hasArg("--quick") ? 1000 : 100000; + + struct TestParams { + const char* name; + uint32_t options; + uint32_t blockSize; + uint32_t granularity; + }; + + static TestParams testParams[] = { + { "Default", 0, 0, 0 }, + { "16MB blocks", 0, 16 * 1024 * 1024, 0 }, + { "256B granularity", 0, 0, 256 }, + { "kOptionUseDualMapping", JitAllocator::kOptionUseDualMapping, 0, 0 }, + { "kOptionUseMultiplePools", JitAllocator::kOptionUseMultiplePools, 0, 0 }, + { "kOptionFillUnusedMemory", JitAllocator::kOptionFillUnusedMemory, 0, 0 }, + { "kOptionImmediateRelease", JitAllocator::kOptionImmediateRelease, 0, 0 }, + { "kOptionUseDualMapping | kOptionFillUnusedMemory", JitAllocator::kOptionUseDualMapping | JitAllocator::kOptionFillUnusedMemory, 0, 0 } + }; + + INFO("BitVectorRangeIterator"); + { + Random rnd; + BitVectorRangeIterator_testRandom(rnd, kCount); + } + + INFO("BitVectorRangeIterator"); + { + Random rnd; + BitVectorRangeIterator_testRandom(rnd, kCount); + } + + for (uint32_t testId = 0; testId < ASMJIT_ARRAY_SIZE(testParams); testId++) { + INFO("JitAllocator(%s)", testParams[testId].name); + + JitAllocator::CreateParams params {}; + params.options = testParams[testId].options; + params.blockSize = testParams[testId].blockSize; + params.granularity = testParams[testId].granularity; + + size_t fixedBlockSize = 256; + + JitAllocatorWrapper wrapper(¶ms); + Random prng(100); + + size_t i; + + INFO(" Memory alloc/release test - %d allocations", kCount); + + void** ptrArray = (void**)::malloc(sizeof(void*) * size_t(kCount)); + EXPECT(ptrArray != nullptr, + "Couldn't allocate '%u' bytes for pointer-array", unsigned(sizeof(void*) * size_t(kCount))); + + // Random blocks tests... + INFO(" Allocating random blocks..."); + for (i = 0; i < kCount; i++) + ptrArray[i] = wrapper.alloc((prng.nextUInt32() % 1024) + 8); + JitAllocatorTest_usage(wrapper._allocator); + + INFO(" Releasing all allocated blocks from the beginning..."); + for (i = 0; i < kCount; i++) + wrapper.release(ptrArray[i]); + JitAllocatorTest_usage(wrapper._allocator); + + INFO(" Allocating random blocks again...", kCount); + for (i = 0; i < kCount; i++) + ptrArray[i] = wrapper.alloc((prng.nextUInt32() % 1024) + 8); + JitAllocatorTest_usage(wrapper._allocator); + + INFO(" Shuffling allocated blocks..."); + JitAllocatorTest_shuffle(ptrArray, unsigned(kCount), prng); + + INFO(" Releasing 50%% of allocated blocks..."); + for (i = 0; i < kCount / 2; i++) + wrapper.release(ptrArray[i]); + JitAllocatorTest_usage(wrapper._allocator); + + INFO(" Allocating 50%% more blocks again..."); + for (i = 0; i < kCount / 2; i++) + ptrArray[i] = wrapper.alloc((prng.nextUInt32() % 1024) + 8); + JitAllocatorTest_usage(wrapper._allocator); + + INFO(" Releasing all allocated blocks from the end..."); + for (i = 0; i < kCount; i++) + wrapper.release(ptrArray[kCount - i - 1]); + JitAllocatorTest_usage(wrapper._allocator); + + // Fixed blocks tests... + INFO(" Allocating %zuB blocks...", fixedBlockSize); + for (i = 0; i < kCount / 2; i++) + ptrArray[i] = wrapper.alloc(fixedBlockSize); + JitAllocatorTest_usage(wrapper._allocator); + + INFO(" Shrinking each %zuB block to 1 byte", fixedBlockSize); + for (i = 0; i < kCount / 2; i++) + wrapper.shrink(ptrArray[i], 1); + JitAllocatorTest_usage(wrapper._allocator); + + INFO(" Allocating more 64B blocks...", 64); + for (i = kCount / 2; i < kCount; i++) + ptrArray[i] = wrapper.alloc(64); + JitAllocatorTest_usage(wrapper._allocator); + + INFO(" Releasing all blocks from the beginning..."); + for (i = 0; i < kCount; i++) + wrapper.release(ptrArray[i]); + JitAllocatorTest_usage(wrapper._allocator); + + INFO(" Allocating %zuB blocks...", fixedBlockSize); + for (i = 0; i < kCount; i++) + ptrArray[i] = wrapper.alloc(fixedBlockSize); + JitAllocatorTest_usage(wrapper._allocator); + + INFO(" Shuffling allocated blocks..."); + JitAllocatorTest_shuffle(ptrArray, unsigned(kCount), prng); + + INFO(" Releasing 50%% of allocated blocks..."); + for (i = 0; i < kCount / 2; i++) + wrapper.release(ptrArray[i]); + JitAllocatorTest_usage(wrapper._allocator); + + INFO(" Allocating 50%% more %zuB blocks again...", fixedBlockSize); + for (i = 0; i < kCount / 2; i++) + ptrArray[i] = wrapper.alloc(fixedBlockSize); + JitAllocatorTest_usage(wrapper._allocator); + + INFO(" Releasing all allocated blocks from the end..."); + for (i = 0; i < kCount; i++) + wrapper.release(ptrArray[kCount - i - 1]); + JitAllocatorTest_usage(wrapper._allocator); + + ::free(ptrArray); + } +} +#endif + +ASMJIT_END_NAMESPACE + +#endif diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/jitallocator.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/jitallocator.h new file mode 100644 index 0000000..c9eea2a --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/jitallocator.h @@ -0,0 +1,278 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_JITALLOCATOR_H_INCLUDED +#define ASMJIT_CORE_JITALLOCATOR_H_INCLUDED + +#include "../core/api-config.h" +#ifndef ASMJIT_NO_JIT + +#include "../core/globals.h" +#include "../core/virtmem.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_virtual_memory +//! \{ + +// ============================================================================ +// [asmjit::JitAllocator] +// ============================================================================ + +//! A simple implementation of memory manager that uses `asmjit::VirtMem` +//! functions to manage virtual memory for JIT compiled code. +//! +//! Implementation notes: +//! +//! - Granularity of allocated blocks is different than granularity for a typical +//! C malloc. In addition, the allocator can use several memory pools having a +//! different granularity to minimize the maintenance overhead. Multiple pools +//! feature requires `kFlagUseMultiplePools` flag to be set. +//! +//! - The allocator doesn't store any information in executable memory, instead, +//! the implementation uses two bit-vectors to manage allocated memory of each +//! allocator-block. The first bit-vector called 'used' is used to track used +//! memory (where each bit represents memory size defined by granularity) and +//! the second bit vector called 'stop' is used as a sentinel to mark where +//! the allocated area ends. +//! +//! - Internally, the allocator also uses RB tree to keep track of all blocks +//! across all pools. Each inserted block is added to the tree so it can be +//! matched fast during `release()` and `shrink()`. +class JitAllocator { +public: + ASMJIT_NONCOPYABLE(JitAllocator) + + struct Impl { + //! Allocator options, see \ref JitAllocator::Options. + uint32_t options; + //! Base block size (0 if the allocator is not initialized). + uint32_t blockSize; + //! Base granularity (0 if the allocator is not initialized). + uint32_t granularity; + //! A pattern that is used to fill unused memory if secure mode is enabled. + uint32_t fillPattern; + }; + + //! Allocator implementation (private). + Impl* _impl; + + enum Options : uint32_t { + //! Enables the use of an anonymous memory-mapped memory that is mapped into + //! two buffers having a different pointer. The first buffer has read and + //! execute permissions and the second buffer has read+write permissions. + //! + //! See \ref VirtMem::allocDualMapping() for more details about this feature. + kOptionUseDualMapping = 0x00000001u, + + //! Enables the use of multiple pools with increasing granularity instead of + //! a single pool. This flag would enable 3 internal pools in total having + //! 64, 128, and 256 bytes granularity. + //! + //! This feature is only recommended for users that generate a lot of code + //! and would like to minimize the overhead of `JitAllocator` itself by + //! having blocks of different allocation granularities. Using this feature + //! only for few allocations won't pay off as the allocator may need to + //! create more blocks initially before it can take the advantage of + //! variable block granularity. + kOptionUseMultiplePools = 0x00000002u, + + //! Always fill reserved memory by a fill-pattern. + //! + //! Causes a new block to be cleared by the fill pattern and freshly + //! released memory to be cleared before making it ready for another use. + kOptionFillUnusedMemory = 0x00000004u, + + //! When this flag is set the allocator would immediately release unused + //! blocks during `release()` or `reset()`. When this flag is not set the + //! allocator would keep one empty block in each pool to prevent excessive + //! virtual memory allocations and deallocations in border cases, which + //! involve constantly allocating and deallocating a single block caused + //! by repetitive calling `alloc()` and `release()` when the allocator has + //! either no blocks or have all blocks fully occupied. + kOptionImmediateRelease = 0x00000008u, + + //! Use a custom fill pattern, must be combined with `kFlagFillUnusedMemory`. + kOptionCustomFillPattern = 0x10000000u + }; + + //! \name Construction & Destruction + //! \{ + + //! Parameters that can be passed to `JitAllocator` constructor. + //! + //! Use it like this: + //! + //! ``` + //! // Zero initialize (zero means the default value) and change what you need. + //! JitAllocator::CreateParams params {}; + //! params.blockSize = 1024 * 1024; + //! + //! // Create the allocator. + //! JitAllocator allocator(¶ms); + //! ``` + struct CreateParams { + //! Allocator options, see \ref JitAllocator::Options. + //! + //! No options are used by default. + uint32_t options; + + //! Base size of a single block in bytes (default 64kB). + //! + //! \remarks Block size must be equal or greater to page size and must be + //! power of 2. If the input is not valid then the default block size will + //! be used instead. + uint32_t blockSize; + + //! Base granularity (and also natural alignment) of allocations in bytes + //! (default 64). + //! + //! Since the `JitAllocator` uses bit-arrays to mark used memory the + //! granularity also specifies how many bytes correspond to a single bit in + //! such bit-array. Higher granularity means more waste of virtual memory + //! (as it increases the natural alignment), but smaller bit-arrays as less + //! bits would be required per a single block. + uint32_t granularity; + + //! Patter to use to fill unused memory. + //! + //! Only used if \ref kOptionCustomFillPattern is set. + uint32_t fillPattern; + + // Reset the content of `CreateParams`. + inline void reset() noexcept { memset(this, 0, sizeof(*this)); } + }; + + //! Creates a `JitAllocator` instance. + explicit ASMJIT_API JitAllocator(const CreateParams* params = nullptr) noexcept; + //! Destroys the `JitAllocator` instance and release all blocks held. + ASMJIT_API ~JitAllocator() noexcept; + + inline bool isInitialized() const noexcept { return _impl->blockSize == 0; } + + //! Free all allocated memory - makes all pointers returned by `alloc()` invalid. + //! + //! \remarks This function is not thread-safe as it's designed to be used when + //! nobody else is using allocator. The reason is that there is no point of + //1 calling `reset()` when the allocator is still in use. + ASMJIT_API void reset(uint32_t resetPolicy = Globals::kResetSoft) noexcept; + + //! \} + + //! \name Accessors + //! \{ + + //! Returns allocator options, see `Flags`. + inline uint32_t options() const noexcept { return _impl->options; } + //! Tests whether the allocator has the given `option` set. + inline bool hasOption(uint32_t option) const noexcept { return (_impl->options & option) != 0; } + + //! Returns a base block size (a minimum size of block that the allocator would allocate). + inline uint32_t blockSize() const noexcept { return _impl->blockSize; } + //! Returns granularity of the allocator. + inline uint32_t granularity() const noexcept { return _impl->granularity; } + //! Returns pattern that is used to fill unused memory if `kFlagUseFillPattern` is set. + inline uint32_t fillPattern() const noexcept { return _impl->fillPattern; } + + //! \} + + //! \name Alloc & Release + //! \{ + + //! Allocate `size` bytes of virtual memory. + //! + //! \remarks This function is thread-safe. + ASMJIT_API Error alloc(void** roPtrOut, void** rwPtrOut, size_t size) noexcept; + + //! Release a memory returned by `alloc()`. + //! + //! \remarks This function is thread-safe. + ASMJIT_API Error release(void* roPtr) noexcept; + + //! Free extra memory allocated with `p` by restricting it to `newSize` size. + //! + //! \remarks This function is thread-safe. + ASMJIT_API Error shrink(void* roPtr, size_t newSize) noexcept; + + //! \} + + //! \name Statistics + //! \{ + + //! Statistics about `JitAllocator`. + struct Statistics { + //! Number of blocks `JitAllocator` maintains. + size_t _blockCount; + //! How many bytes are currently used / allocated. + size_t _usedSize; + //! How many bytes are currently reserved by the allocator. + size_t _reservedSize; + //! Allocation overhead (in bytes) required to maintain all blocks. + size_t _overheadSize; + + inline void reset() noexcept { + _blockCount = 0; + _usedSize = 0; + _reservedSize = 0; + _overheadSize = 0; + } + + //! Returns count of blocks managed by `JitAllocator` at the moment. + inline size_t blockCount() const noexcept { return _blockCount; } + + //! Returns how many bytes are currently used. + inline size_t usedSize() const noexcept { return _usedSize; } + //! Returns the number of bytes unused by the allocator at the moment. + inline size_t unusedSize() const noexcept { return _reservedSize - _usedSize; } + //! Returns the total number of bytes bytes reserved by the allocator (sum of sizes of all blocks). + inline size_t reservedSize() const noexcept { return _reservedSize; } + //! Returns the number of bytes the allocator needs to manage the allocated memory. + inline size_t overheadSize() const noexcept { return _overheadSize; } + + inline double usedSizeAsPercent() const noexcept { + return (double(usedSize()) / (double(reservedSize()) + 1e-16)) * 100.0; + } + + inline double unusedSizeAsPercent() const noexcept { + return (double(unusedSize()) / (double(reservedSize()) + 1e-16)) * 100.0; + } + + inline double overheadSizeAsPercent() const noexcept { + return (double(overheadSize()) / (double(reservedSize()) + 1e-16)) * 100.0; + } + }; + + //! Returns JIT allocator statistics. + //! + //! \remarks This function is thread-safe. + ASMJIT_API Statistics statistics() const noexcept; + + //! \} +}; + +//! \} + +ASMJIT_END_NAMESPACE + +#endif +#endif diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/jitruntime.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/jitruntime.cpp new file mode 100644 index 0000000..a2b46d7 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/jitruntime.cpp @@ -0,0 +1,128 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#ifndef ASMJIT_NO_JIT + +#include "../core/cpuinfo.h" +#include "../core/jitruntime.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::JitRuntime - Utilities] +// ============================================================================ + +// Only useful on non-x86 architectures. +static inline void JitRuntime_flushInstructionCache(const void* p, size_t size) noexcept { +#if ASMJIT_ARCH_X86 + DebugUtils::unused(p, size); +#else +# if defined(_WIN32) + // Windows has a built-in support in `kernel32.dll`. + ::FlushInstructionCache(::GetCurrentProcess(), p, size); +# elif defined(__GNUC__) + char* start = static_cast(const_cast(p)); + char* end = start + size; + __builtin___clear_cache(start, end); +# else + DebugUtils::unused(p, size); +# endif +#endif +} + +// ============================================================================ +// [asmjit::JitRuntime - Construction / Destruction] +// ============================================================================ + +JitRuntime::JitRuntime(const JitAllocator::CreateParams* params) noexcept + : _allocator(params) { + _environment = hostEnvironment(); + _environment.setFormat(Environment::kFormatJIT); +} + +JitRuntime::~JitRuntime() noexcept {} + +// ============================================================================ +// [asmjit::JitRuntime - Interface] +// ============================================================================ + +Error JitRuntime::_add(void** dst, CodeHolder* code) noexcept { + *dst = nullptr; + + ASMJIT_PROPAGATE(code->flatten()); + ASMJIT_PROPAGATE(code->resolveUnresolvedLinks()); + + size_t estimatedCodeSize = code->codeSize(); + if (ASMJIT_UNLIKELY(estimatedCodeSize == 0)) + return DebugUtils::errored(kErrorNoCodeGenerated); + + uint8_t* ro; + uint8_t* rw; + ASMJIT_PROPAGATE(_allocator.alloc((void**)&ro, (void**)&rw, estimatedCodeSize)); + + // Relocate the code. + Error err = code->relocateToBase(uintptr_t((void*)ro)); + if (ASMJIT_UNLIKELY(err)) { + _allocator.release(ro); + return err; + } + + // Recalculate the final code size and shrink the memory we allocated for it + // in case that some relocations didn't require records in an address table. + size_t codeSize = code->codeSize(); + + for (Section* section : code->_sections) { + size_t offset = size_t(section->offset()); + size_t bufferSize = size_t(section->bufferSize()); + size_t virtualSize = size_t(section->virtualSize()); + + ASMJIT_ASSERT(offset + bufferSize <= codeSize); + memcpy(rw + offset, section->data(), bufferSize); + + if (virtualSize > bufferSize) { + ASMJIT_ASSERT(offset + virtualSize <= codeSize); + memset(rw + offset + bufferSize, 0, virtualSize - bufferSize); + } + } + + if (codeSize < estimatedCodeSize) + _allocator.shrink(ro, codeSize); + + flush(ro, codeSize); + *dst = ro; + + return kErrorOk; +} + +Error JitRuntime::_release(void* p) noexcept { + return _allocator.release(p); +} + +void JitRuntime::flush(const void* p, size_t size) noexcept { + JitRuntime_flushInstructionCache(p, size); +} + +ASMJIT_END_NAMESPACE + +#endif diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/jitruntime.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/jitruntime.h new file mode 100644 index 0000000..91880e6 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/jitruntime.h @@ -0,0 +1,126 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_JITRUNTIME_H_INCLUDED +#define ASMJIT_CORE_JITRUNTIME_H_INCLUDED + +#include "../core/api-config.h" +#ifndef ASMJIT_NO_JIT + +#include "../core/codeholder.h" +#include "../core/jitallocator.h" +#include "../core/target.h" + +ASMJIT_BEGIN_NAMESPACE + +class CodeHolder; + +//! \addtogroup asmjit_virtual_memory +//! \{ + +// ============================================================================ +// [asmjit::JitRuntime] +// ============================================================================ + +//! JIT execution runtime is a special `Target` that is designed to store and +//! execute the generated code. +class ASMJIT_VIRTAPI JitRuntime : public Target { +public: + ASMJIT_NONCOPYABLE(JitRuntime) + + //! Virtual memory allocator. + JitAllocator _allocator; + + //! \name Construction & Destruction + //! \{ + + //! Creates a `JitRuntime` instance. + explicit ASMJIT_API JitRuntime(const JitAllocator::CreateParams* params = nullptr) noexcept; + //! Destroys the `JitRuntime` instance. + ASMJIT_API virtual ~JitRuntime() noexcept; + + inline void reset(uint32_t resetPolicy = Globals::kResetSoft) noexcept { + _allocator.reset(resetPolicy); + } + + //! \} + + //! \name Accessors + //! \{ + + //! Returns the associated `JitAllocator`. + inline JitAllocator* allocator() const noexcept { return const_cast(&_allocator); } + + //! \} + + //! \name Utilities + //! \{ + + // NOTE: To allow passing function pointers to `add()` and `release()` the + // virtual methods are prefixed with `_` and called from templates instead. + + //! Allocates memory needed for a code stored in the `CodeHolder` and relocates + //! the code to the pointer allocated. + //! + //! The beginning of the memory allocated for the function is returned in `dst`. + //! If failed `Error` code is returned and `dst` is explicitly set to `nullptr` + //! (this means that you don't have to set it to null before calling `add()`). + template + inline Error add(Func* dst, CodeHolder* code) noexcept { + return _add(Support::ptr_cast_impl(dst), code); + } + + //! Releases `p` which was obtained by calling `add()`. + template + inline Error release(Func p) noexcept { + return _release(Support::ptr_cast_impl(p)); + } + + //! Type-unsafe version of `add()`. + ASMJIT_API virtual Error _add(void** dst, CodeHolder* code) noexcept; + + //! Type-unsafe version of `release()`. + ASMJIT_API virtual Error _release(void* p) noexcept; + + //! Flushes an instruction cache. + //! + //! This member function is called after the code has been copied to the + //! destination buffer. It is only useful for JIT code generation as it + //! causes a flush of the processor's cache. + //! + //! Flushing is basically a NOP under X86, but is needed by architectures + //! that do not have a transparent instruction cache like ARM. + //! + //! This function can also be overridden to improve compatibility with tools + //! such as Valgrind, however, it's not an official part of AsmJit. + ASMJIT_API virtual void flush(const void* p, size_t size) noexcept; + + //! \} +}; + +//! \} + +ASMJIT_END_NAMESPACE + +#endif +#endif diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/logger.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/logger.cpp new file mode 100644 index 0000000..22e0b9a --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/logger.cpp @@ -0,0 +1,124 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#ifndef ASMJIT_NO_LOGGING + +#include "../core/logger.h" +#include "../core/string.h" +#include "../core/support.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::Logger - Construction / Destruction] +// ============================================================================ + +Logger::Logger() noexcept + : _options() {} +Logger::~Logger() noexcept {} + +// ============================================================================ +// [asmjit::Logger - Logging] +// ============================================================================ + +Error Logger::logf(const char* fmt, ...) noexcept { + Error err; + va_list ap; + + va_start(ap, fmt); + err = logv(fmt, ap); + va_end(ap); + + return err; +} + +Error Logger::logv(const char* fmt, va_list ap) noexcept { + StringTmp<2048> sb; + ASMJIT_PROPAGATE(sb.appendVFormat(fmt, ap)); + return log(sb); +} + +Error Logger::logBinary(const void* data, size_t size) noexcept { + static const char prefix[] = "db "; + + StringTmp<256> sb; + sb.append(prefix, ASMJIT_ARRAY_SIZE(prefix) - 1); + + size_t i = size; + const uint8_t* s = static_cast(data); + + while (i) { + uint32_t n = uint32_t(Support::min(i, 16)); + sb.truncate(ASMJIT_ARRAY_SIZE(prefix) - 1); + sb.appendHex(s, n); + sb.append('\n'); + ASMJIT_PROPAGATE(log(sb)); + s += n; + i -= n; + } + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::FileLogger - Construction / Destruction] +// ============================================================================ + +FileLogger::FileLogger(FILE* file) noexcept + : _file(file) {} +FileLogger::~FileLogger() noexcept {} + +// ============================================================================ +// [asmjit::FileLogger - Logging] +// ============================================================================ + +Error FileLogger::_log(const char* data, size_t size) noexcept { + if (!_file) + return kErrorOk; + + if (size == SIZE_MAX) + size = strlen(data); + + fwrite(data, 1, size, _file); + return kErrorOk; +} + +// ============================================================================ +// [asmjit::StringLogger - Construction / Destruction] +// ============================================================================ + +StringLogger::StringLogger() noexcept {} +StringLogger::~StringLogger() noexcept {} + +// ============================================================================ +// [asmjit::StringLogger - Logging] +// ============================================================================ + +Error StringLogger::_log(const char* data, size_t size) noexcept { + return _content.append(data, size); +} + +ASMJIT_END_NAMESPACE + +#endif diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/logger.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/logger.h new file mode 100644 index 0000000..2840869 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/logger.h @@ -0,0 +1,228 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_LOGGING_H_INCLUDED +#define ASMJIT_CORE_LOGGING_H_INCLUDED + +#include "../core/inst.h" +#include "../core/string.h" +#include "../core/formatter.h" + +#ifndef ASMJIT_NO_LOGGING + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_logging +//! \{ + +// ============================================================================ +// [asmjit::Logger] +// ============================================================================ + +//! Logging interface. +//! +//! This class can be inherited and reimplemented to fit into your own logging +//! needs. When reimplementing a logger use \ref Logger::_log() method to log +//! customize the output. +//! +//! There are two `Logger` implementations offered by AsmJit: +//! - \ref FileLogger - logs into a `FILE*`. +//! - \ref StringLogger - concatenates all logs into a \ref String. +class ASMJIT_VIRTAPI Logger { +public: + ASMJIT_BASE_CLASS(Logger) + ASMJIT_NONCOPYABLE(Logger) + + //! Format options. + FormatOptions _options; + + //! \name Construction & Destruction + //! \{ + + //! Creates a `Logger` instance. + ASMJIT_API Logger() noexcept; + //! Destroys the `Logger` instance. + ASMJIT_API virtual ~Logger() noexcept; + + //! \} + + //! \name Format Options + //! \{ + + //! Returns \ref FormatOptions of this logger. + inline FormatOptions& options() noexcept { return _options; } + //! \overload + inline const FormatOptions& options() const noexcept { return _options; } + + //! Returns formatting flags, see \ref FormatOptions::Flags. + inline uint32_t flags() const noexcept { return _options.flags(); } + //! Tests whether the logger has the given `flag` enabled. + inline bool hasFlag(uint32_t flag) const noexcept { return _options.hasFlag(flag); } + //! Sets formatting flags to `flags`, see \ref FormatOptions::Flags. + inline void setFlags(uint32_t flags) noexcept { _options.setFlags(flags); } + //! Enables the given formatting `flags`, see \ref FormatOptions::Flags. + inline void addFlags(uint32_t flags) noexcept { _options.addFlags(flags); } + //! Disables the given formatting `flags`, see \ref FormatOptions::Flags. + inline void clearFlags(uint32_t flags) noexcept { _options.clearFlags(flags); } + + //! Returns indentation of `type`, see \ref FormatOptions::IndentationType. + inline uint32_t indentation(uint32_t type) const noexcept { return _options.indentation(type); } + //! Sets indentation of the given indentation `type` to `n` spaces, see \ref + //! FormatOptions::IndentationType. + inline void setIndentation(uint32_t type, uint32_t n) noexcept { _options.setIndentation(type, n); } + //! Resets indentation of the given indentation `type` to 0 spaces. + inline void resetIndentation(uint32_t type) noexcept { _options.resetIndentation(type); } + + //! \} + + //! \name Logging Interface + //! \{ + + //! Logs `str` - must be reimplemented. + //! + //! The function can accept either a null terminated string if `size` is + //! `SIZE_MAX` or a non-null terminated string of the given `size`. The + //! function cannot assume that the data is null terminated and must handle + //! non-null terminated inputs. + virtual Error _log(const char* data, size_t size) noexcept = 0; + + //! Logs string `str`, which is either null terminated or having size `size`. + inline Error log(const char* data, size_t size = SIZE_MAX) noexcept { return _log(data, size); } + //! Logs content of a string `str`. + inline Error log(const String& str) noexcept { return _log(str.data(), str.size()); } + + //! Formats the message by using `snprintf()` and then passes the formatted + //! string to \ref _log(). + ASMJIT_API Error logf(const char* fmt, ...) noexcept; + + //! Formats the message by using `vsnprintf()` and then passes the formatted + //! string to \ref _log(). + ASMJIT_API Error logv(const char* fmt, va_list ap) noexcept; + + //! Logs binary `data` of the given `size`. + ASMJIT_API Error logBinary(const void* data, size_t size) noexcept; + + //! \} +}; + +// ============================================================================ +// [asmjit::FileLogger] +// ============================================================================ + +//! Logger that can log to a `FILE*`. +class ASMJIT_VIRTAPI FileLogger : public Logger { +public: + ASMJIT_NONCOPYABLE(FileLogger) + + FILE* _file; + + //! \name Construction & Destruction + //! \{ + + //! Creates a new `FileLogger` that logs to `FILE*`. + ASMJIT_API FileLogger(FILE* file = nullptr) noexcept; + //! Destroys the `FileLogger`. + ASMJIT_API virtual ~FileLogger() noexcept; + + //! \} + + //! \name Accessors + //! \{ + + //! Returns the logging output stream or null if the logger has no output + //! stream. + inline FILE* file() const noexcept { return _file; } + + //! Sets the logging output stream to `stream` or null. + //! + //! \note If the `file` is null the logging will be disabled. When a logger + //! is attached to `CodeHolder` or any emitter the logging API will always + //! be called regardless of the output file. This means that if you really + //! want to disable logging at emitter level you must not attach a logger + //! to it. + inline void setFile(FILE* file) noexcept { _file = file; } + + //! \} + + ASMJIT_API Error _log(const char* data, size_t size = SIZE_MAX) noexcept override; +}; + +// ============================================================================ +// [asmjit::StringLogger] +// ============================================================================ + +//! Logger that stores everything in an internal string buffer. +class ASMJIT_VIRTAPI StringLogger : public Logger { +public: + ASMJIT_NONCOPYABLE(StringLogger) + + //! Logger data as string. + String _content; + + //! \name Construction & Destruction + //! \{ + + //! Create new `StringLogger`. + ASMJIT_API StringLogger() noexcept; + //! Destroys the `StringLogger`. + ASMJIT_API virtual ~StringLogger() noexcept; + + //! \} + + //! \name Logger Data Accessors + //! \{ + + //! Returns the content of the logger as \ref String. + //! + //! It can be moved, if desired. + inline String& content() noexcept { return _content; } + //! \overload + inline const String& content() const noexcept { return _content; } + + //! Returns aggregated logger data as `char*` pointer. + //! + //! The pointer is owned by `StringLogger`, it can't be modified or freed. + inline const char* data() const noexcept { return _content.data(); } + //! Returns size of the data returned by `data()`. + inline size_t dataSize() const noexcept { return _content.size(); } + + //! \} + + //! \name Logger Data Manipulation + //! \{ + + //! Clears the accumulated logger data. + inline void clear() noexcept { _content.clear(); } + + //! \} + + ASMJIT_API Error _log(const char* data, size_t size = SIZE_MAX) noexcept override; +}; + +//! \} + +ASMJIT_END_NAMESPACE + +#endif + +#endif // ASMJIT_CORE_LOGGER_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/misc_p.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/misc_p.h new file mode 100644 index 0000000..225ba6a --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/misc_p.h @@ -0,0 +1,51 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_MISC_P_H_INCLUDED +#define ASMJIT_CORE_MISC_P_H_INCLUDED + +#include "../core/api-config.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \cond INTERNAL +//! \addtogroup asmjit_utilities +//! \{ + +#define ASMJIT_LOOKUP_TABLE_4(T, I) T((I)), T((I+1)), T((I+2)), T((I+3)) +#define ASMJIT_LOOKUP_TABLE_8(T, I) ASMJIT_LOOKUP_TABLE_4(T, I), ASMJIT_LOOKUP_TABLE_4(T, I + 4) +#define ASMJIT_LOOKUP_TABLE_16(T, I) ASMJIT_LOOKUP_TABLE_8(T, I), ASMJIT_LOOKUP_TABLE_8(T, I + 8) +#define ASMJIT_LOOKUP_TABLE_32(T, I) ASMJIT_LOOKUP_TABLE_16(T, I), ASMJIT_LOOKUP_TABLE_16(T, I + 16) +#define ASMJIT_LOOKUP_TABLE_40(T, I) ASMJIT_LOOKUP_TABLE_16(T, I), ASMJIT_LOOKUP_TABLE_16(T, I + 16), ASMJIT_LOOKUP_TABLE_8(T, I + 32) +#define ASMJIT_LOOKUP_TABLE_64(T, I) ASMJIT_LOOKUP_TABLE_32(T, I), ASMJIT_LOOKUP_TABLE_32(T, I + 32) +#define ASMJIT_LOOKUP_TABLE_128(T, I) ASMJIT_LOOKUP_TABLE_64(T, I), ASMJIT_LOOKUP_TABLE_64(T, I + 64) +#define ASMJIT_LOOKUP_TABLE_256(T, I) ASMJIT_LOOKUP_TABLE_128(T, I), ASMJIT_LOOKUP_TABLE_128(T, I + 128) +#define ASMJIT_LOOKUP_TABLE_512(T, I) ASMJIT_LOOKUP_TABLE_256(T, I), ASMJIT_LOOKUP_TABLE_256(T, I + 256) +#define ASMJIT_LOOKUP_TABLE_1024(T, I) ASMJIT_LOOKUP_TABLE_512(T, I), ASMJIT_LOOKUP_TABLE_512(T, I + 512) + +//! \} +//! \endcond + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_MISC_P_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/operand.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/operand.cpp new file mode 100644 index 0000000..cd5931f --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/operand.cpp @@ -0,0 +1,143 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/operand.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::Operand - Unit] +// ============================================================================ + +#if defined(ASMJIT_TEST) +UNIT(operand) { + INFO("Checking operand sizes"); + EXPECT(sizeof(Operand) == 16); + EXPECT(sizeof(BaseReg) == 16); + EXPECT(sizeof(BaseMem) == 16); + EXPECT(sizeof(Imm) == 16); + EXPECT(sizeof(Label) == 16); + + INFO("Checking basic functionality of Operand"); + Operand a, b; + Operand dummy; + + EXPECT(a.isNone() == true); + EXPECT(a.isReg() == false); + EXPECT(a.isMem() == false); + EXPECT(a.isImm() == false); + EXPECT(a.isLabel() == false); + EXPECT(a == b); + EXPECT(a._data[0] == 0); + EXPECT(a._data[1] == 0); + + INFO("Checking basic functionality of Label"); + Label label; + EXPECT(label.isValid() == false); + EXPECT(label.id() == Globals::kInvalidId); + + INFO("Checking basic functionality of BaseReg"); + EXPECT(BaseReg().isReg() == true); + EXPECT(BaseReg().isValid() == false); + EXPECT(BaseReg()._data[0] == 0); + EXPECT(BaseReg()._data[1] == 0); + EXPECT(dummy.as().isValid() == false); + + // Create some register (not specific to any architecture). + uint32_t rSig = Operand::kOpReg | (1 << Operand::kSignatureRegTypeShift ) | + (2 << Operand::kSignatureRegGroupShift) | + (8 << Operand::kSignatureSizeShift ) ; + BaseReg r1 = BaseReg::fromSignatureAndId(rSig, 5); + + EXPECT(r1.isValid() == true); + EXPECT(r1.isReg() == true); + EXPECT(r1.isReg(1) == true); + EXPECT(r1.isPhysReg() == true); + EXPECT(r1.isVirtReg() == false); + EXPECT(r1.signature() == rSig); + EXPECT(r1.type() == 1); + EXPECT(r1.group() == 2); + EXPECT(r1.size() == 8); + EXPECT(r1.id() == 5); + EXPECT(r1.isReg(1, 5) == true); // RegType and Id. + EXPECT(r1._data[0] == 0); + EXPECT(r1._data[1] == 0); + + // The same type of register having different id. + BaseReg r2(r1, 6); + EXPECT(r2.isValid() == true); + EXPECT(r2.isReg() == true); + EXPECT(r2.isReg(1) == true); + EXPECT(r2.isPhysReg() == true); + EXPECT(r2.isVirtReg() == false); + EXPECT(r2.signature() == rSig); + EXPECT(r2.type() == r1.type()); + EXPECT(r2.group() == r1.group()); + EXPECT(r2.size() == r1.size()); + EXPECT(r2.id() == 6); + EXPECT(r2.isReg(1, 6) == true); + + r1.reset(); + EXPECT(!r1.isReg()); + EXPECT(!r1.isValid()); + + INFO("Checking basic functionality of BaseMem"); + BaseMem m; + EXPECT(m.isMem()); + EXPECT(m == BaseMem()); + EXPECT(m.hasBase() == false); + EXPECT(m.hasIndex() == false); + EXPECT(m.hasOffset() == false); + EXPECT(m.isOffset64Bit() == true); + EXPECT(m.offset() == 0); + + m.setOffset(-1); + EXPECT(m.offsetLo32() == -1); + EXPECT(m.offset() == -1); + + int64_t x = int64_t(0xFF00FF0000000001u); + int32_t xHi = int32_t(0xFF00FF00u); + + m.setOffset(x); + EXPECT(m.offset() == x); + EXPECT(m.offsetLo32() == 1); + EXPECT(m.offsetHi32() == xHi); + + INFO("Checking basic functionality of Imm"); + Imm immValue(-42); + EXPECT(immValue.type() == Imm::kTypeInteger); + EXPECT(Imm(-1).value() == -1); + EXPECT(imm(-1).value() == -1); + EXPECT(immValue.value() == -42); + EXPECT(imm(0xFFFFFFFF).value() == int64_t(0xFFFFFFFF)); + + Imm immDouble(0.4); + EXPECT(immDouble.type() == Imm::kTypeDouble); + EXPECT(immDouble.valueAs() == 0.4); + EXPECT(immDouble == imm(0.4)); + +} +#endif + +ASMJIT_END_NAMESPACE diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/operand.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/operand.h new file mode 100644 index 0000000..05e4c0f --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/operand.h @@ -0,0 +1,1530 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_OPERAND_H_INCLUDED +#define ASMJIT_CORE_OPERAND_H_INCLUDED + +#include "../core/archcommons.h" +#include "../core/support.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [Macros] +// ============================================================================ + +//! Adds a template specialization for `REG_TYPE` into the local `RegTraits`. +#define ASMJIT_DEFINE_REG_TRAITS(REG, REG_TYPE, GROUP, SIZE, COUNT, TYPE_ID) \ +template<> \ +struct RegTraits { \ + typedef REG RegT; \ + \ + static constexpr uint32_t kValid = 1; \ + static constexpr uint32_t kCount = COUNT; \ + static constexpr uint32_t kTypeId = TYPE_ID; \ + \ + static constexpr uint32_t kType = REG_TYPE; \ + static constexpr uint32_t kGroup = GROUP; \ + static constexpr uint32_t kSize = SIZE; \ + \ + static constexpr uint32_t kSignature = \ + (Operand::kOpReg << Operand::kSignatureOpTypeShift ) | \ + (kType << Operand::kSignatureRegTypeShift ) | \ + (kGroup << Operand::kSignatureRegGroupShift) | \ + (kSize << Operand::kSignatureSizeShift ) ; \ +} + +//! Adds constructors and member functions to a class that implements abstract +//! register. Abstract register is register that doesn't have type or signature +//! yet, it's a base class like `x86::Reg` or `arm::Reg`. +#define ASMJIT_DEFINE_ABSTRACT_REG(REG, BASE) \ +public: \ + /*! Default constructor that only setups basics. */ \ + constexpr REG() noexcept \ + : BASE(SignatureAndId(kSignature, kIdBad)) {} \ + \ + /*! Makes a copy of the `other` register operand. */ \ + constexpr REG(const REG& other) noexcept \ + : BASE(other) {} \ + \ + /*! Makes a copy of the `other` register having id set to `rId` */ \ + constexpr REG(const BaseReg& other, uint32_t rId) noexcept \ + : BASE(other, rId) {} \ + \ + /*! Creates a register based on `signature` and `rId`. */ \ + constexpr explicit REG(const SignatureAndId& sid) noexcept \ + : BASE(sid) {} \ + \ + /*! Creates a completely uninitialized REG register operand (garbage). */ \ + inline explicit REG(Globals::NoInit_) noexcept \ + : BASE(Globals::NoInit) {} \ + \ + /*! Creates a new register from register type and id. */ \ + static inline REG fromTypeAndId(uint32_t rType, uint32_t rId) noexcept { \ + return REG(SignatureAndId(signatureOf(rType), rId)); \ + } \ + \ + /*! Creates a new register from register signature and id. */ \ + static inline REG fromSignatureAndId(uint32_t rSgn, uint32_t rId) noexcept {\ + return REG(SignatureAndId(rSgn, rId)); \ + } \ + \ + /*! Clones the register operand. */ \ + constexpr REG clone() const noexcept { return REG(*this); } \ + \ + inline REG& operator=(const REG& other) noexcept = default; + +//! Adds constructors and member functions to a class that implements final +//! register. Final registers MUST HAVE a valid signature. +#define ASMJIT_DEFINE_FINAL_REG(REG, BASE, TRAITS) \ +public: \ + static constexpr uint32_t kThisType = TRAITS::kType; \ + static constexpr uint32_t kThisGroup = TRAITS::kGroup; \ + static constexpr uint32_t kThisSize = TRAITS::kSize; \ + static constexpr uint32_t kSignature = TRAITS::kSignature; \ + \ + ASMJIT_DEFINE_ABSTRACT_REG(REG, BASE) \ + \ + /*! Creates a register operand having its id set to `rId`. */ \ + constexpr explicit REG(uint32_t rId) noexcept \ + : BASE(SignatureAndId(kSignature, rId)) {} + +//! \addtogroup asmjit_assembler +//! \{ + +// ============================================================================ +// [asmjit::Operand_] +// ============================================================================ + +//! Constructor-less `Operand`. +//! +//! Contains no initialization code and can be used safely to define an array +//! of operands that won't be initialized. This is an `Operand` compatible +//! data structure designed to be statically initialized, static const, or to +//! be used by the user to define an array of operands without having them +//! default initialized. +//! +//! The key difference between `Operand` and `Operand_`: +//! +//! ``` +//! Operand_ xArray[10]; // Not initialized, contains garbage. +//! Operand yArray[10]; // All operands initialized to none. +//! ``` +struct Operand_ { + //! Operand's signature that provides operand type and additional information. + uint32_t _signature; + //! Either base id as used by memory operand or any id as used by others. + uint32_t _baseId; + + //! Data specific to the operand type. + //! + //! The reason we don't use union is that we have `constexpr` constructors that + //! construct operands and other `constexpr` functions that return wither another + //! Operand or something else. These cannot generally work with unions so we also + //! cannot use `union` if we want to be standard compliant. + uint32_t _data[2]; + + //! Indexes to `_data` array. + enum DataIndex : uint32_t { + kDataMemIndexId = 0, + kDataMemOffsetLo = 1, + + kDataImmValueLo = ASMJIT_ARCH_LE ? 0 : 1, + kDataImmValueHi = ASMJIT_ARCH_LE ? 1 : 0 + }; + + //! Operand types that can be encoded in `Operand`. + enum OpType : uint32_t { + //! Not an operand or not initialized. + kOpNone = 0, + //! Operand is a register. + kOpReg = 1, + //! Operand is a memory. + kOpMem = 2, + //! Operand is an immediate value. + kOpImm = 3, + //! Operand is a label. + kOpLabel = 4 + }; + static_assert(kOpMem == kOpReg + 1, "asmjit::Operand requires `kOpMem` to be `kOpReg+1`."); + + //! Label tag. + enum LabelTag { + //! Label tag is used as a sub-type, forming a unique signature across all + //! operand types as 0x1 is never associated with any register type. This + //! means that a memory operand's BASE register can be constructed from + //! virtually any operand (register vs. label) by just assigning its type + //! (register type or label-tag) and operand id. + kLabelTag = 0x1 + }; + + // \cond INTERNAL + enum SignatureBits : uint32_t { + // Operand type (3 least significant bits). + // |........|........|........|.....XXX| + kSignatureOpTypeShift = 0, + kSignatureOpTypeMask = 0x07u << kSignatureOpTypeShift, + + // Register type (5 bits). + // |........|........|........|XXXXX...| + kSignatureRegTypeShift = 3, + kSignatureRegTypeMask = 0x1Fu << kSignatureRegTypeShift, + + // Register group (4 bits). + // |........|........|....XXXX|........| + kSignatureRegGroupShift = 8, + kSignatureRegGroupMask = 0x0Fu << kSignatureRegGroupShift, + + // Memory base type (5 bits). + // |........|........|........|XXXXX...| + kSignatureMemBaseTypeShift = 3, + kSignatureMemBaseTypeMask = 0x1Fu << kSignatureMemBaseTypeShift, + + // Memory index type (5 bits). + // |........|........|...XXXXX|........| + kSignatureMemIndexTypeShift = 8, + kSignatureMemIndexTypeMask = 0x1Fu << kSignatureMemIndexTypeShift, + + // Memory base+index combined (10 bits). + // |........|........|...XXXXX|XXXXX...| + kSignatureMemBaseIndexShift = 3, + kSignatureMemBaseIndexMask = 0x3FFu << kSignatureMemBaseIndexShift, + + // This memory operand represents a home-slot or stack (Compiler) (1 bit). + // |........|........|..X.....|........| + kSignatureMemRegHomeShift = 13, + kSignatureMemRegHomeFlag = 0x01u << kSignatureMemRegHomeShift, + + // Immediate type (1 bit). + // |........|........|........|....X...| + kSignatureImmTypeShift = 4, + kSignatureImmTypeMask = 0x01u << kSignatureImmTypeShift, + + // Predicate used by either registers or immediate values (4 bits). + // |........|XXXX....|........|........| + kSignaturePredicateShift = 20, + kSignaturePredicateMask = 0x0Fu << kSignaturePredicateShift, + + // Operand size (8 most significant bits). + // |XXXXXXXX|........|........|........| + kSignatureSizeShift = 24, + kSignatureSizeMask = 0xFFu << kSignatureSizeShift + }; + //! \endcond + + //! Constants useful for VirtId <-> Index translation. + enum VirtIdConstants : uint32_t { + //! Minimum valid packed-id. + kVirtIdMin = 256, + //! Maximum valid packed-id, excludes Globals::kInvalidId. + kVirtIdMax = Globals::kInvalidId - 1, + //! Count of valid packed-ids. + kVirtIdCount = uint32_t(kVirtIdMax - kVirtIdMin + 1) + }; + + //! Tests whether the given `id` is a valid virtual register id. Since AsmJit + //! supports both physical and virtual registers it must be able to distinguish + //! between these two. The idea is that physical registers are always limited + //! in size, so virtual identifiers start from `kVirtIdMin` and end at `kVirtIdMax`. + static ASMJIT_INLINE bool isVirtId(uint32_t id) noexcept { return id - kVirtIdMin < uint32_t(kVirtIdCount); } + //! Converts a real-id into a packed-id that can be stored in Operand. + static ASMJIT_INLINE uint32_t indexToVirtId(uint32_t id) noexcept { return id + kVirtIdMin; } + //! Converts a packed-id back to real-id. + static ASMJIT_INLINE uint32_t virtIdToIndex(uint32_t id) noexcept { return id - kVirtIdMin; } + + //! \name Construction & Destruction + //! \{ + + //! \cond INTERNAL + //! Initializes a `BaseReg` operand from `signature` and register `id`. + inline void _initReg(uint32_t signature, uint32_t id) noexcept { + _signature = signature; + _baseId = id; + _data[0] = 0; + _data[1] = 0; + } + //! \endcond + + //! Initializes the operand from `other` operand (used by operator overloads). + inline void copyFrom(const Operand_& other) noexcept { memcpy(this, &other, sizeof(Operand_)); } + + //! Resets the `Operand` to none. + //! + //! None operand is defined the following way: + //! - Its signature is zero (kOpNone, and the rest zero as well). + //! - Its id is `0`. + //! - The reserved8_4 field is set to `0`. + //! - The reserved12_4 field is set to zero. + //! + //! In other words, reset operands have all members set to zero. Reset operand + //! must match the Operand state right after its construction. Alternatively, + //! if you have an array of operands, you can simply use `memset()`. + //! + //! ``` + //! using namespace asmjit; + //! + //! Operand a; + //! Operand b; + //! assert(a == b); + //! + //! b = x86::eax; + //! assert(a != b); + //! + //! b.reset(); + //! assert(a == b); + //! + //! memset(&b, 0, sizeof(Operand)); + //! assert(a == b); + //! ``` + inline void reset() noexcept { + _signature = 0; + _baseId = 0; + _data[0] = 0; + _data[1] = 0; + } + + //! \} + + //! \name Operator Overloads + //! \{ + + //! Tests whether this operand is the same as `other`. + constexpr bool operator==(const Operand_& other) const noexcept { return equals(other); } + //! Tests whether this operand is not the same as `other`. + constexpr bool operator!=(const Operand_& other) const noexcept { return !equals(other); } + + //! \} + + //! \name Cast + //! \{ + + //! Casts this operand to `T` type. + template + inline T& as() noexcept { return static_cast(*this); } + + //! Casts this operand to `T` type (const). + template + inline const T& as() const noexcept { return static_cast(*this); } + + //! \} + + //! \name Accessors + //! \{ + + //! Tests whether the operand's signature matches the given signature `sign`. + constexpr bool hasSignature(uint32_t signature) const noexcept { return _signature == signature; } + //! Tests whether the operand's signature matches the signature of the `other` operand. + constexpr bool hasSignature(const Operand_& other) const noexcept { return _signature == other.signature(); } + + //! Returns operand signature as unsigned 32-bit integer. + //! + //! Signature is first 4 bytes of the operand data. It's used mostly for + //! operand checking as it's much faster to check 4 bytes at once than having + //! to check these bytes individually. + constexpr uint32_t signature() const noexcept { return _signature; } + + //! Sets the operand signature, see `signature()`. + //! + //! \note Improper use of `setSignature()` can lead to hard-to-debug errors. + inline void setSignature(uint32_t signature) noexcept { _signature = signature; } + + //! \cond INTERNAL + template + constexpr bool _hasSignaturePart() const noexcept { + return (_signature & mask) != 0; + } + + template + constexpr bool _hasSignaturePart(uint32_t signature) const noexcept { + return (_signature & mask) == signature; + } + + template + constexpr uint32_t _getSignaturePart() const noexcept { + return (_signature >> Support::constCtz(mask)) & (mask >> Support::constCtz(mask)); + } + + template + inline void _setSignaturePart(uint32_t value) noexcept { + ASMJIT_ASSERT((value & ~(mask >> Support::constCtz(mask))) == 0); + _signature = (_signature & ~mask) | (value << Support::constCtz(mask)); + } + //! \endcond + + //! Returns the type of the operand, see `OpType`. + constexpr uint32_t opType() const noexcept { return _getSignaturePart(); } + //! Tests whether the operand is none (`kOpNone`). + constexpr bool isNone() const noexcept { return _signature == 0; } + //! Tests whether the operand is a register (`kOpReg`). + constexpr bool isReg() const noexcept { return opType() == kOpReg; } + //! Tests whether the operand is a memory location (`kOpMem`). + constexpr bool isMem() const noexcept { return opType() == kOpMem; } + //! Tests whether the operand is an immediate (`kOpImm`). + constexpr bool isImm() const noexcept { return opType() == kOpImm; } + //! Tests whether the operand is a label (`kOpLabel`). + constexpr bool isLabel() const noexcept { return opType() == kOpLabel; } + + //! Tests whether the operand is a physical register. + constexpr bool isPhysReg() const noexcept { return isReg() && _baseId < 0xFFu; } + //! Tests whether the operand is a virtual register. + constexpr bool isVirtReg() const noexcept { return isReg() && _baseId > 0xFFu; } + + //! Tests whether the operand specifies a size (i.e. the size is not zero). + constexpr bool hasSize() const noexcept { return _hasSignaturePart(); } + //! Tests whether the size of the operand matches `size`. + constexpr bool hasSize(uint32_t s) const noexcept { return size() == s; } + + //! Returns the size of the operand in bytes. + //! + //! The value returned depends on the operand type: + //! * None - Should always return zero size. + //! * Reg - Should always return the size of the register. If the register + //! size depends on architecture (like `x86::CReg` and `x86::DReg`) + //! the size returned should be the greatest possible (so it should + //! return 64-bit size in such case). + //! * Mem - Size is optional and will be in most cases zero. + //! * Imm - Should always return zero size. + //! * Label - Should always return zero size. + constexpr uint32_t size() const noexcept { return _getSignaturePart(); } + + //! Returns the operand id. + //! + //! The value returned should be interpreted accordingly to the operand type: + //! * None - Should be `0`. + //! * Reg - Physical or virtual register id. + //! * Mem - Multiple meanings - BASE address (register or label id), or + //! high value of a 64-bit absolute address. + //! * Imm - Should be `0`. + //! * Label - Label id if it was created by using `newLabel()` or + //! `Globals::kInvalidId` if the label is invalid or not + //! initialized. + constexpr uint32_t id() const noexcept { return _baseId; } + + //! Tests whether the operand is 100% equal to `other` operand. + //! + //! \note This basically performs a binary comparison, if aby bit is + //! different the operands are not equal. + constexpr bool equals(const Operand_& other) const noexcept { + return (_signature == other._signature) & + (_baseId == other._baseId ) & + (_data[0] == other._data[0] ) & + (_data[1] == other._data[1] ) ; + } + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use equals() instead") + constexpr bool isEqual(const Operand_& other) const noexcept { return equals(other); } +#endif //!ASMJIT_NO_DEPRECATED + + //! Tests whether the operand is a register matching `rType`. + constexpr bool isReg(uint32_t rType) const noexcept { + return (_signature & (kSignatureOpTypeMask | kSignatureRegTypeMask)) == + ((kOpReg << kSignatureOpTypeShift) | (rType << kSignatureRegTypeShift)); + } + + //! Tests whether the operand is register and of `rType` and `rId`. + constexpr bool isReg(uint32_t rType, uint32_t rId) const noexcept { + return isReg(rType) && id() == rId; + } + + //! Tests whether the operand is a register or memory. + constexpr bool isRegOrMem() const noexcept { + return Support::isBetween(opType(), kOpReg, kOpMem); + } + + //! \} +}; + +// ============================================================================ +// [asmjit::Operand] +// ============================================================================ + +//! Operand can contain register, memory location, immediate, or label. +class Operand : public Operand_ { +public: + //! \name Construction & Destruction + //! \{ + + //! Creates `kOpNone` operand having all members initialized to zero. + constexpr Operand() noexcept + : Operand_{ kOpNone, 0u, { 0u, 0u }} {} + + //! Creates a cloned `other` operand. + constexpr Operand(const Operand& other) noexcept = default; + + //! Creates a cloned `other` operand. + constexpr explicit Operand(const Operand_& other) + : Operand_(other) {} + + //! Creates an operand initialized to raw `[u0, u1, u2, u3]` values. + constexpr Operand(Globals::Init_, uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3) noexcept + : Operand_{ u0, u1, { u2, u3 }} {} + + //! Creates an uninitialized operand (dangerous). + inline explicit Operand(Globals::NoInit_) noexcept {} + + //! \} + + //! \name Operator Overloads + //! \{ + + inline Operand& operator=(const Operand& other) noexcept = default; + inline Operand& operator=(const Operand_& other) noexcept { return operator=(static_cast(other)); } + + //! \} + + //! \name Utilities + //! \{ + + //! Clones this operand and returns its copy. + constexpr Operand clone() const noexcept { return Operand(*this); } + + //! \} +}; + +static_assert(sizeof(Operand) == 16, "asmjit::Operand must be exactly 16 bytes long"); + +// ============================================================================ +// [asmjit::Label] +// ============================================================================ + +//! Label (jump target or data location). +//! +//! Label represents a location in code typically used as a jump target, but +//! may be also a reference to some data or a static variable. Label has to be +//! explicitly created by BaseEmitter. +//! +//! Example of using labels: +//! +//! ``` +//! // Create some emitter (for example x86::Assembler). +//! x86::Assembler a; +//! +//! // Create Label instance. +//! Label L1 = a.newLabel(); +//! +//! // ... your code ... +//! +//! // Using label. +//! a.jump(L1); +//! +//! // ... your code ... +//! +//! // Bind label to the current position, see `BaseEmitter::bind()`. +//! a.bind(L1); +//! ``` +class Label : public Operand { +public: + //! Type of the Label. + enum LabelType : uint32_t { + //! Anonymous (unnamed) label. + kTypeAnonymous = 0, + //! Local label (always has parentId). + kTypeLocal = 1, + //! Global label (never has parentId). + kTypeGlobal = 2, + //! External label (references an external symbol). + kTypeExternal = 3, + //! Number of label types. + kTypeCount = 4 + }; + + //! \name Construction & Destruction + //! \{ + + //! Creates a label operand without ID (you must set the ID to make it valid). + constexpr Label() noexcept + : Operand(Globals::Init, kOpLabel, Globals::kInvalidId, 0, 0) {} + + //! Creates a cloned label operand of `other`. + constexpr Label(const Label& other) noexcept + : Operand(other) {} + + //! Creates a label operand of the given `id`. + constexpr explicit Label(uint32_t id) noexcept + : Operand(Globals::Init, kOpLabel, id, 0, 0) {} + + inline explicit Label(Globals::NoInit_) noexcept + : Operand(Globals::NoInit) {} + + //! Resets the label, will reset all properties and set its ID to `Globals::kInvalidId`. + inline void reset() noexcept { + _signature = kOpLabel; + _baseId = Globals::kInvalidId; + _data[0] = 0; + _data[1] = 0; + } + + //! \} + + //! \name Overloaded Operators + //! \{ + + inline Label& operator=(const Label& other) noexcept = default; + + //! \} + + //! \name Accessors + //! \{ + + //! Tests whether the label was created by CodeHolder and/or an attached emitter. + constexpr bool isValid() const noexcept { return _baseId != Globals::kInvalidId; } + //! Sets the label `id`. + inline void setId(uint32_t id) noexcept { _baseId = id; } + + //! \} +}; + +// ============================================================================ +// [asmjit::BaseRegTraits] +// ============================================================================ + +//! \cond INTERNAL +//! Default register traits. +struct BaseRegTraits { + //! RegType is not valid by default. + static constexpr uint32_t kValid = 0; + //! Count of registers (0 if none). + static constexpr uint32_t kCount = 0; + //! Everything is void by default. + static constexpr uint32_t kTypeId = 0; + + //! Zero type by default. + static constexpr uint32_t kType = 0; + //! Zero group by default. + static constexpr uint32_t kGroup = 0; + //! No size by default. + static constexpr uint32_t kSize = 0; + + //! Empty signature by default (not even having operand type set to register). + static constexpr uint32_t kSignature = 0; +}; +//! \endcond + +// ============================================================================ +// [asmjit::BaseReg] +// ============================================================================ + +//! Structure that allows to extract a register information based on the signature. +//! +//! This information is compatible with operand's signature (32-bit integer) +//! and `RegInfo` just provides easy way to access it. +struct RegInfo { + inline void reset(uint32_t signature = 0) noexcept { _signature = signature; } + inline void setSignature(uint32_t signature) noexcept { _signature = signature; } + + template + constexpr uint32_t _getSignaturePart() const noexcept { + return (_signature >> Support::constCtz(mask)) & (mask >> Support::constCtz(mask)); + } + + constexpr bool isValid() const noexcept { return _signature != 0; } + constexpr uint32_t signature() const noexcept { return _signature; } + constexpr uint32_t opType() const noexcept { return _getSignaturePart(); } + constexpr uint32_t group() const noexcept { return _getSignaturePart(); } + constexpr uint32_t type() const noexcept { return _getSignaturePart(); } + constexpr uint32_t size() const noexcept { return _getSignaturePart(); } + + uint32_t _signature; +}; + +//! Physical or virtual register operand. +class BaseReg : public Operand { +public: + static constexpr uint32_t kBaseSignature = + kSignatureOpTypeMask | + kSignatureRegTypeMask | + kSignatureRegGroupMask | + kSignatureSizeMask ; + + //! Architecture neutral register types. + //! + //! These must be reused by any platform that contains that types. All GP + //! and VEC registers are also allowed by design to be part of a BASE|INDEX + //! of a memory operand. + enum RegType : uint32_t { + //! No register - unused, invalid, multiple meanings. + kTypeNone = 0, + + // (1 is used as a LabelTag) + + //! 8-bit low general purpose register (X86). + kTypeGp8Lo = 2, + //! 8-bit high general purpose register (X86). + kTypeGp8Hi = 3, + //! 16-bit general purpose register (X86). + kTypeGp16 = 4, + //! 32-bit general purpose register (X86|ARM). + kTypeGp32 = 5, + //! 64-bit general purpose register (X86|ARM). + kTypeGp64 = 6, + //! 8-bit view of a vector register (ARM). + kTypeVec8 = 7, + //! 16-bit view of a vector register (ARM). + kTypeVec16 = 8, + //! 32-bit view of a vector register (ARM). + kTypeVec32 = 9, + //! 64-bit view of a vector register (ARM). + kTypeVec64 = 10, + //! 128-bit view of a vector register (X86|ARM). + kTypeVec128 = 11, + //! 256-bit view of a vector register (X86). + kTypeVec256 = 12, + //! 512-bit view of a vector register (X86). + kTypeVec512 = 13, + //! 1024-bit view of a vector register (future). + kTypeVec1024 = 14, + //! Other0 register, should match `kOther0` group. + kTypeOther0 = 15, + //! Other1 register, should match `kOther1` group. + kTypeOther1 = 16, + //! Universal id of IP/PC register (if separate). + kTypeIP = 17, + //! Start of platform dependent register types. + kTypeCustom = 18, + //! Maximum possible register type value. + kTypeMax = 31 + }; + + //! Register group (architecture neutral), and some limits. + enum RegGroup : uint32_t { + //! General purpose register group compatible with all backends. + kGroupGp = 0, + //! Vector register group compatible with all backends. + kGroupVec = 1, + //! Group that is architecture dependent. + kGroupOther0 = 2, + //! Group that is architecture dependent. + kGroupOther1 = 3, + //! Count of register groups used by physical and virtual registers. + kGroupVirt = 4, + //! Count of register groups used by physical registers only. + kGroupCount = 16 + }; + + enum Id : uint32_t { + //! None or any register (mostly internal). + kIdBad = 0xFFu + }; + + //! A helper used by constructors. + struct SignatureAndId { + uint32_t _signature; + uint32_t _id; + + inline SignatureAndId() noexcept = default; + constexpr SignatureAndId(const SignatureAndId& other) noexcept = default; + + constexpr explicit SignatureAndId(uint32_t signature, uint32_t id) noexcept + : _signature(signature), + _id(id) {} + + constexpr uint32_t signature() const noexcept { return _signature; } + constexpr uint32_t id() const noexcept { return _id; } + }; + + static constexpr uint32_t kSignature = kOpReg; + + //! \name Construction & Destruction + //! \{ + + //! Creates a dummy register operand. + constexpr BaseReg() noexcept + : Operand(Globals::Init, kSignature, kIdBad, 0, 0) {} + + //! Creates a new register operand which is the same as `other` . + constexpr BaseReg(const BaseReg& other) noexcept + : Operand(other) {} + + //! Creates a new register operand compatible with `other`, but with a different `rId`. + constexpr BaseReg(const BaseReg& other, uint32_t rId) noexcept + : Operand(Globals::Init, other._signature, rId, 0, 0) {} + + //! Creates a register initialized to `signature` and `rId`. + constexpr explicit BaseReg(const SignatureAndId& sid) noexcept + : Operand(Globals::Init, sid._signature, sid._id, 0, 0) {} + + inline explicit BaseReg(Globals::NoInit_) noexcept + : Operand(Globals::NoInit) {} + + /*! Creates a new register from register signature `rSgn` and id. */ + static inline BaseReg fromSignatureAndId(uint32_t rSgn, uint32_t rId) noexcept { + return BaseReg(SignatureAndId(rSgn, rId)); + } + + //! \} + + //! \name Overloaded Operators + //! \{ + + inline BaseReg& operator=(const BaseReg& other) noexcept = default; + + //! \} + + //! \name Accessors + //! \{ + + //! Returns base signature of the register associated with each register type. + //! + //! Base signature only contains the operand type, register type, register + //! group, and register size. It doesn't contain element type, predicate, or + //! other architecture-specific data. Base signature is a signature that is + //! provided by architecture-specific `RegTraits`, like \ref x86::RegTraits. + constexpr uint32_t baseSignature() const noexcept { + return _signature & (kBaseSignature); + } + + //! Tests whether the operand's base signature matches the given signature `sign`. + constexpr bool hasBaseSignature(uint32_t signature) const noexcept { return baseSignature() == signature; } + //! Tests whether the operand's base signature matches the base signature of the `other` operand. + constexpr bool hasBaseSignature(const BaseReg& other) const noexcept { return baseSignature() == other.baseSignature(); } + + //! Tests whether this register is the same as `other`. + //! + //! This is just an optimization. Registers by default only use the first + //! 8 bytes of Operand data, so this method takes advantage of this knowledge + //! and only compares these 8 bytes. If both operands were created correctly + //! both \ref equals() and \ref isSame() should give the same answer, however, + //! if any of these two contains garbage or other metadata in the upper 8 + //! bytes then \ref isSame() may return `true` in cases in which \ref equals() + //! returns false. + constexpr bool isSame(const BaseReg& other) const noexcept { + return (_signature == other._signature) & (_baseId == other._baseId); + } + + //! Tests whether the register is valid (either virtual or physical). + constexpr bool isValid() const noexcept { return (_signature != 0) & (_baseId != kIdBad); } + + //! Tests whether this is a physical register. + constexpr bool isPhysReg() const noexcept { return _baseId < kIdBad; } + //! Tests whether this is a virtual register. + constexpr bool isVirtReg() const noexcept { return _baseId > kIdBad; } + + //! Tests whether the register type matches `type` - same as `isReg(type)`, provided for convenience. + constexpr bool isType(uint32_t type) const noexcept { return (_signature & kSignatureRegTypeMask) == (type << kSignatureRegTypeShift); } + //! Tests whether the register group matches `group`. + constexpr bool isGroup(uint32_t group) const noexcept { return (_signature & kSignatureRegGroupMask) == (group << kSignatureRegGroupShift); } + + //! Tests whether the register is a general purpose register (any size). + constexpr bool isGp() const noexcept { return isGroup(kGroupGp); } + //! Tests whether the register is a vector register. + constexpr bool isVec() const noexcept { return isGroup(kGroupVec); } + + using Operand_::isReg; + + //! Same as `isType()`, provided for convenience. + constexpr bool isReg(uint32_t rType) const noexcept { return isType(rType); } + //! Tests whether the register type matches `type` and register id matches `rId`. + constexpr bool isReg(uint32_t rType, uint32_t rId) const noexcept { return isType(rType) && id() == rId; } + + //! Returns the type of the register. + constexpr uint32_t type() const noexcept { return _getSignaturePart(); } + //! Returns the register group. + constexpr uint32_t group() const noexcept { return _getSignaturePart(); } + + //! Returns operation predicate of the register (ARM/AArch64). + //! + //! The meaning depends on architecture, for example on ARM hardware this + //! describes \ref arm::Predicate::ShiftOp of the register. + constexpr uint32_t predicate() const noexcept { return _getSignaturePart(); } + + //! Sets operation predicate of the register to `predicate` (ARM/AArch64). + //! + //! The meaning depends on architecture, for example on ARM hardware this + //! describes \ref arm::Predicate::ShiftOp of the register. + inline void setPredicate(uint32_t predicate) noexcept { _setSignaturePart(predicate); } + + //! Resets shift operation type of the register to the default value (ARM/AArch64). + inline void resetPredicate() noexcept { _setSignaturePart(0); } + + //! Clones the register operand. + constexpr BaseReg clone() const noexcept { return BaseReg(*this); } + + //! Casts this register to `RegT` by also changing its signature. + //! + //! \note Improper use of `cloneAs()` can lead to hard-to-debug errors. + template + constexpr RegT cloneAs() const noexcept { return RegT(RegT::kSignature, id()); } + + //! Casts this register to `other` by also changing its signature. + //! + //! \note Improper use of `cloneAs()` can lead to hard-to-debug errors. + template + constexpr RegT cloneAs(const RegT& other) const noexcept { return RegT(SignatureAndId(other.signature(), id())); } + + //! Sets the register id to `rId`. + inline void setId(uint32_t rId) noexcept { _baseId = rId; } + + //! Sets a 32-bit operand signature based on traits of `RegT`. + template + inline void setSignatureT() noexcept { _signature = RegT::kSignature; } + + //! Sets the register `signature` and `rId`. + inline void setSignatureAndId(uint32_t signature, uint32_t rId) noexcept { + _signature = signature; + _baseId = rId; + } + + //! \} + + //! \name Static Functions + //! \{ + + //! Tests whether the `op` operand is a general purpose register. + static inline bool isGp(const Operand_& op) noexcept { + // Check operand type and register group. Not interested in register type and size. + const uint32_t kSgn = (kOpReg << kSignatureOpTypeShift ) | + (kGroupGp << kSignatureRegGroupShift) ; + return (op.signature() & (kSignatureOpTypeMask | kSignatureRegGroupMask)) == kSgn; + } + + //! Tests whether the `op` operand is a vector register. + static inline bool isVec(const Operand_& op) noexcept { + // Check operand type and register group. Not interested in register type and size. + const uint32_t kSgn = (kOpReg << kSignatureOpTypeShift ) | + (kGroupVec << kSignatureRegGroupShift) ; + return (op.signature() & (kSignatureOpTypeMask | kSignatureRegGroupMask)) == kSgn; + } + + //! Tests whether the `op` is a general purpose register of the given `rId`. + static inline bool isGp(const Operand_& op, uint32_t rId) noexcept { return isGp(op) & (op.id() == rId); } + //! Tests whether the `op` is a vector register of the given `rId`. + static inline bool isVec(const Operand_& op, uint32_t rId) noexcept { return isVec(op) & (op.id() == rId); } + + //! \} +}; + +// ============================================================================ +// [asmjit::RegOnly] +// ============================================================================ + +//! RegOnly is 8-byte version of `BaseReg` that allows to store either register +//! or nothing. +//! +//! This class was designed to decrease the space consumed by each extra "operand" +//! in `BaseEmitter` and `InstNode` classes. +struct RegOnly { + //! Type of the operand, either `kOpNone` or `kOpReg`. + uint32_t _signature; + //! Physical or virtual register id. + uint32_t _id; + + //! \name Construction & Destruction + //! \{ + + //! Initializes the `RegOnly` instance to hold register `signature` and `id`. + inline void init(uint32_t signature, uint32_t id) noexcept { + _signature = signature; + _id = id; + } + + inline void init(const BaseReg& reg) noexcept { init(reg.signature(), reg.id()); } + inline void init(const RegOnly& reg) noexcept { init(reg.signature(), reg.id()); } + + //! Resets the `RegOnly` members to zeros (none). + inline void reset() noexcept { init(0, 0); } + + //! \} + + //! \name Accessors + //! \{ + + //! Tests whether this ExtraReg is none (same as calling `Operand_::isNone()`). + constexpr bool isNone() const noexcept { return _signature == 0; } + //! Tests whether the register is valid (either virtual or physical). + constexpr bool isReg() const noexcept { return _signature != 0; } + + //! Tests whether this is a physical register. + constexpr bool isPhysReg() const noexcept { return _id < BaseReg::kIdBad; } + //! Tests whether this is a virtual register (used by `BaseCompiler`). + constexpr bool isVirtReg() const noexcept { return _id > BaseReg::kIdBad; } + + //! Returns the register signature or 0 if no register is assigned. + constexpr uint32_t signature() const noexcept { return _signature; } + //! Returns the register id. + //! + //! \note Always check whether the register is assigned before using the + //! returned identifier as non-assigned `RegOnly` instance would return + //! zero id, which is still a valid register id. + constexpr uint32_t id() const noexcept { return _id; } + + //! Sets the register id. + inline void setId(uint32_t id) noexcept { _id = id; } + + //! \cond INTERNAL + //! + //! Extracts information from operand's signature. + template + constexpr uint32_t _getSignaturePart() const noexcept { + return (_signature >> Support::constCtz(mask)) & (mask >> Support::constCtz(mask)); + } + //! \endcond + + //! Returns the type of the register. + constexpr uint32_t type() const noexcept { return _getSignaturePart(); } + //! Returns the register group. + constexpr uint32_t group() const noexcept { return _getSignaturePart(); } + + //! \} + + //! \name Utilities + //! \{ + + //! Converts this ExtraReg to a real `RegT` operand. + template + constexpr RegT toReg() const noexcept { return RegT(BaseReg::SignatureAndId(_signature, _id)); } + + //! \} +}; + +// ============================================================================ +// [asmjit::BaseMem] +// ============================================================================ + +//! Base class for all memory operands. +//! +//! \note It's tricky to pack all possible cases that define a memory operand +//! into just 16 bytes. The `BaseMem` splits data into the following parts: +//! +//! - BASE - Base register or label - requires 36 bits total. 4 bits are used +//! to encode the type of the BASE operand (label vs. register type) and the +//! remaining 32 bits define the BASE id, which can be a physical or virtual +//! register index. If BASE type is zero, which is never used as a register +//! type and label doesn't use it as well then BASE field contains a high +//! DWORD of a possible 64-bit absolute address, which is possible on X64. +//! +//! - INDEX - Index register (or theoretically Label, which doesn't make sense). +//! Encoding is similar to BASE - it also requires 36 bits and splits the +//! encoding to INDEX type (4 bits defining the register type) and id (32-bits). +//! +//! - OFFSET - A relative offset of the address. Basically if BASE is specified +//! the relative displacement adjusts BASE and an optional INDEX. if BASE is +//! not specified then the OFFSET should be considered as ABSOLUTE address (at +//! least on X86). In that case its low 32 bits are stored in DISPLACEMENT +//! field and the remaining high 32 bits are stored in BASE. +//! +//! - OTHER - There is rest 8 bits that can be used for whatever purpose. For +//! example \ref x86::Mem operand uses these bits to store segment override +//! prefix and index shift (or scale). +class BaseMem : public Operand { +public: + //! \cond INTERNAL + //! Used internally to construct `BaseMem` operand from decomposed data. + struct Decomposed { + uint32_t baseType; + uint32_t baseId; + uint32_t indexType; + uint32_t indexId; + int32_t offset; + uint32_t size; + uint32_t flags; + }; + //! \endcond + + //! \name Construction & Destruction + //! \{ + + //! Creates a default `BaseMem` operand, that points to [0]. + constexpr BaseMem() noexcept + : Operand(Globals::Init, kOpMem, 0, 0, 0) {} + + //! Creates a `BaseMem` operand that is a clone of `other`. + constexpr BaseMem(const BaseMem& other) noexcept + : Operand(other) {} + + //! Creates a `BaseMem` operand from `baseReg` and `offset`. + //! + //! \note This is an architecture independent constructor that can be used to + //! create an architecture independent memory operand to be used in portable + //! code that can handle multiple architectures. + constexpr explicit BaseMem(const BaseReg& baseReg, int32_t offset = 0) noexcept + : Operand(Globals::Init, + kOpMem | (baseReg.type() << kSignatureMemBaseTypeShift), + baseReg.id(), + 0, + uint32_t(offset)) {} + + //! \cond INTERNAL + + //! Creates a `BaseMem` operand from 4 integers as used by `Operand_` struct. + constexpr BaseMem(Globals::Init_, uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3) noexcept + : Operand(Globals::Init, u0, u1, u2, u3) {} + + constexpr BaseMem(const Decomposed& d) noexcept + : Operand(Globals::Init, + kOpMem | (d.baseType << kSignatureMemBaseTypeShift ) + | (d.indexType << kSignatureMemIndexTypeShift) + | (d.size << kSignatureSizeShift ) + | d.flags, + d.baseId, + d.indexId, + uint32_t(d.offset)) {} + + //! \endcond + + //! Creates a completely uninitialized `BaseMem` operand. + inline explicit BaseMem(Globals::NoInit_) noexcept + : Operand(Globals::NoInit) {} + + //! Resets the memory operand - after the reset the memory points to [0]. + inline void reset() noexcept { + _signature = kOpMem; + _baseId = 0; + _data[0] = 0; + _data[1] = 0; + } + + //! \} + + //! \name Overloaded Operators + //! \{ + + inline BaseMem& operator=(const BaseMem& other) noexcept { copyFrom(other); return *this; } + + //! \} + + //! \name Accessors + //! \{ + + //! Clones the memory operand. + constexpr BaseMem clone() const noexcept { return BaseMem(*this); } + + //! Creates a new copy of this memory operand adjusted by `off`. + inline BaseMem cloneAdjusted(int64_t off) const noexcept { + BaseMem result(*this); + result.addOffset(off); + return result; + } + + //! Tests whether this memory operand is a register home (only used by \ref asmjit_compiler) + constexpr bool isRegHome() const noexcept { return _hasSignaturePart(); } + //! Mark this memory operand as register home (only used by \ref asmjit_compiler). + inline void setRegHome() noexcept { _signature |= kSignatureMemRegHomeFlag; } + //! Marks this operand to not be a register home (only used by \ref asmjit_compiler). + inline void clearRegHome() noexcept { _signature &= ~kSignatureMemRegHomeFlag; } + + //! Tests whether the memory operand has a BASE register or label specified. + constexpr bool hasBase() const noexcept { return (_signature & kSignatureMemBaseTypeMask) != 0; } + //! Tests whether the memory operand has an INDEX register specified. + constexpr bool hasIndex() const noexcept { return (_signature & kSignatureMemIndexTypeMask) != 0; } + //! Tests whether the memory operand has BASE or INDEX register. + constexpr bool hasBaseOrIndex() const noexcept { return (_signature & kSignatureMemBaseIndexMask) != 0; } + //! Tests whether the memory operand has BASE and INDEX register. + constexpr bool hasBaseAndIndex() const noexcept { return (_signature & kSignatureMemBaseTypeMask) != 0 && (_signature & kSignatureMemIndexTypeMask) != 0; } + + //! Tests whether the BASE operand is a register (registers start after `kLabelTag`). + constexpr bool hasBaseReg() const noexcept { return (_signature & kSignatureMemBaseTypeMask) > (Label::kLabelTag << kSignatureMemBaseTypeShift); } + //! Tests whether the BASE operand is a label. + constexpr bool hasBaseLabel() const noexcept { return (_signature & kSignatureMemBaseTypeMask) == (Label::kLabelTag << kSignatureMemBaseTypeShift); } + //! Tests whether the INDEX operand is a register (registers start after `kLabelTag`). + constexpr bool hasIndexReg() const noexcept { return (_signature & kSignatureMemIndexTypeMask) > (Label::kLabelTag << kSignatureMemIndexTypeShift); } + + //! Returns the type of the BASE register (0 if this memory operand doesn't + //! use the BASE register). + //! + //! \note If the returned type is one (a value never associated to a register + //! type) the BASE is not register, but it's a label. One equals to `kLabelTag`. + //! You should always check `hasBaseLabel()` before using `baseId()` result. + constexpr uint32_t baseType() const noexcept { return _getSignaturePart(); } + + //! Returns the type of an INDEX register (0 if this memory operand doesn't + //! use the INDEX register). + constexpr uint32_t indexType() const noexcept { return _getSignaturePart(); } + + //! This is used internally for BASE+INDEX validation. + constexpr uint32_t baseAndIndexTypes() const noexcept { return _getSignaturePart(); } + + //! Returns both BASE (4:0 bits) and INDEX (9:5 bits) types combined into a + //! single value. + //! + //! \remarks Returns id of the BASE register or label (if the BASE was + //! specified as label). + constexpr uint32_t baseId() const noexcept { return _baseId; } + + //! Returns the id of the INDEX register. + constexpr uint32_t indexId() const noexcept { return _data[kDataMemIndexId]; } + + //! Sets the id of the BASE register (without modifying its type). + inline void setBaseId(uint32_t rId) noexcept { _baseId = rId; } + //! Sets the id of the INDEX register (without modifying its type). + inline void setIndexId(uint32_t rId) noexcept { _data[kDataMemIndexId] = rId; } + + //! Sets the base register to type and id of the given `base` operand. + inline void setBase(const BaseReg& base) noexcept { return _setBase(base.type(), base.id()); } + //! Sets the index register to type and id of the given `index` operand. + inline void setIndex(const BaseReg& index) noexcept { return _setIndex(index.type(), index.id()); } + + //! \cond INTERNAL + inline void _setBase(uint32_t rType, uint32_t rId) noexcept { + _setSignaturePart(rType); + _baseId = rId; + } + + inline void _setIndex(uint32_t rType, uint32_t rId) noexcept { + _setSignaturePart(rType); + _data[kDataMemIndexId] = rId; + } + //! \endcond + + //! Resets the memory operand's BASE register or label. + inline void resetBase() noexcept { _setBase(0, 0); } + //! Resets the memory operand's INDEX register. + inline void resetIndex() noexcept { _setIndex(0, 0); } + + //! Sets the memory operand size (in bytes). + inline void setSize(uint32_t size) noexcept { _setSignaturePart(size); } + + //! Tests whether the memory operand has a 64-bit offset or absolute address. + //! + //! If this is true then `hasBase()` must always report false. + constexpr bool isOffset64Bit() const noexcept { return baseType() == 0; } + + //! Tests whether the memory operand has a non-zero offset or absolute address. + constexpr bool hasOffset() const noexcept { + return (_data[kDataMemOffsetLo] | uint32_t(_baseId & Support::bitMaskFromBool(isOffset64Bit()))) != 0; + } + + //! Returns either relative offset or absolute address as 64-bit integer. + constexpr int64_t offset() const noexcept { + return isOffset64Bit() ? int64_t(uint64_t(_data[kDataMemOffsetLo]) | (uint64_t(_baseId) << 32)) + : int64_t(int32_t(_data[kDataMemOffsetLo])); // Sign extend 32-bit offset. + } + + //! Returns a 32-bit low part of a 64-bit offset or absolute address. + constexpr int32_t offsetLo32() const noexcept { return int32_t(_data[kDataMemOffsetLo]); } + //! Returns a 32-but high part of a 64-bit offset or absolute address. + //! + //! \note This function is UNSAFE and returns garbage if `isOffset64Bit()` + //! returns false. Never use it blindly without checking it first. + constexpr int32_t offsetHi32() const noexcept { return int32_t(_baseId); } + + //! Sets a 64-bit offset or an absolute address to `offset`. + //! + //! \note This functions attempts to set both high and low parts of a 64-bit + //! offset, however, if the operand has a BASE register it will store only the + //! low 32 bits of the offset / address as there is no way to store both BASE + //! and 64-bit offset, and there is currently no architecture that has such + //! capability targeted by AsmJit. + inline void setOffset(int64_t offset) noexcept { + uint32_t lo = uint32_t(uint64_t(offset) & 0xFFFFFFFFu); + uint32_t hi = uint32_t(uint64_t(offset) >> 32); + uint32_t hiMsk = Support::bitMaskFromBool(isOffset64Bit()); + + _data[kDataMemOffsetLo] = lo; + _baseId = (hi & hiMsk) | (_baseId & ~hiMsk); + } + //! Sets a low 32-bit offset to `offset` (don't use without knowing how BaseMem works). + inline void setOffsetLo32(int32_t offset) noexcept { _data[kDataMemOffsetLo] = uint32_t(offset); } + + //! Adjusts the offset by `offset`. + //! + //! \note This is a fast function that doesn't use the HI 32-bits of a + //! 64-bit offset. Use it only if you know that there is a BASE register + //! and the offset is only 32 bits anyway. + + //! Adjusts the memory operand offset by a `offset`. + inline void addOffset(int64_t offset) noexcept { + if (isOffset64Bit()) { + int64_t result = offset + int64_t(uint64_t(_data[kDataMemOffsetLo]) | (uint64_t(_baseId) << 32)); + _data[kDataMemOffsetLo] = uint32_t(uint64_t(result) & 0xFFFFFFFFu); + _baseId = uint32_t(uint64_t(result) >> 32); + } + else { + _data[kDataMemOffsetLo] += uint32_t(uint64_t(offset) & 0xFFFFFFFFu); + } + } + + //! Adds `offset` to a low 32-bit offset part (don't use without knowing how + //! BaseMem works). + inline void addOffsetLo32(int32_t offset) noexcept { _data[kDataMemOffsetLo] += uint32_t(offset); } + + //! Resets the memory offset to zero. + inline void resetOffset() noexcept { setOffset(0); } + + //! Resets the lo part of the memory offset to zero (don't use without knowing + //! how BaseMem works). + inline void resetOffsetLo32() noexcept { setOffsetLo32(0); } + + //! \} +}; + +// ============================================================================ +// [asmjit::Imm] +// ============================================================================ + +//! Immediate operand. +//! +//! Immediate operand is usually part of instruction itself. It's inlined after +//! or before the instruction opcode. Immediates can be only signed or unsigned +//! integers. +//! +//! To create an immediate operand use `asmjit::imm()` helper, which can be used +//! with any type, not just the default 64-bit int. +class Imm : public Operand { +public: + //! Type of the immediate. + enum Type : uint32_t { + //! Immediate is integer. + kTypeInteger = 0, + //! Immediate is a floating point stored as double-precision. + kTypeDouble = 1 + }; + + //! \name Construction & Destruction + //! \{ + + //! Creates a new immediate value (initial value is 0). + inline constexpr Imm() noexcept + : Operand(Globals::Init, kOpImm, 0, 0, 0) {} + + //! Creates a new immediate value from `other`. + inline constexpr Imm(const Imm& other) noexcept + : Operand(other) {} + + //! Creates a new immediate value from ARM/AArch64 specific `shift`. + inline constexpr Imm(const arm::Shift& shift) noexcept + : Operand(Globals::Init, kOpImm | (shift.op() << kSignaturePredicateShift), + 0, + Support::unpackU32At0(shift.value()), + Support::unpackU32At1(shift.value())) {} + + //! Creates a new signed immediate value, assigning the value to `val` and + //! an architecture-specific predicate to `predicate`. + //! + //! \note Predicate is currently only used by ARM architectures. + template + inline constexpr Imm(const T& val, const uint32_t predicate = 0) noexcept + : Operand(Globals::Init, kOpImm | (predicate << kSignaturePredicateShift), + 0, + Support::unpackU32At0(int64_t(val)), + Support::unpackU32At1(int64_t(val))) {} + + inline Imm(const float& val, const uint32_t predicate = 0) noexcept + : Operand(Globals::Init, kOpImm | (predicate << kSignaturePredicateShift), 0, 0, 0) { setValue(val); } + + inline Imm(const double& val, const uint32_t predicate = 0) noexcept + : Operand(Globals::Init, kOpImm | (predicate << kSignaturePredicateShift), 0, 0, 0) { setValue(val); } + + inline explicit Imm(Globals::NoInit_) noexcept + : Operand(Globals::NoInit) {} + + //! \} + + //! \name Overloaded Operators + //! \{ + + //! Assigns the value of the `other` operand to this immediate. + inline Imm& operator=(const Imm& other) noexcept { copyFrom(other); return *this; } + + //! \} + + //! \name Accessors + //! \{ + + //! Returns immediate type, see \ref Type. + constexpr uint32_t type() const noexcept { return _getSignaturePart(); } + //! Sets the immediate type to `type`, see \ref Type. + inline void setType(uint32_t type) noexcept { _setSignaturePart(type); } + //! Resets immediate type to `kTypeInteger`. + inline void resetType() noexcept { setType(kTypeInteger); } + + //! Returns operation predicate of the immediate. + //! + //! The meaning depends on architecture, for example on ARM hardware this + //! describes \ref arm::Predicate::ShiftOp of the immediate. + constexpr uint32_t predicate() const noexcept { return _getSignaturePart(); } + + //! Sets operation predicate of the immediate to `predicate`. + //! + //! The meaning depends on architecture, for example on ARM hardware this + //! describes \ref arm::Predicate::ShiftOp of the immediate. + inline void setPredicate(uint32_t predicate) noexcept { _setSignaturePart(predicate); } + + //! Resets the shift operation type of the immediate to the default value (no operation). + inline void resetPredicate() noexcept { _setSignaturePart(0); } + + //! Returns the immediate value as `int64_t`, which is the internal format Imm uses. + constexpr int64_t value() const noexcept { + return int64_t((uint64_t(_data[kDataImmValueHi]) << 32) | _data[kDataImmValueLo]); + } + + //! Tests whether this immediate value is integer of any size. + constexpr uint32_t isInteger() const noexcept { return type() == kTypeInteger; } + //! Tests whether this immediate value is a double precision floating point value. + constexpr uint32_t isDouble() const noexcept { return type() == kTypeDouble; } + + //! Tests whether the immediate can be casted to 8-bit signed integer. + constexpr bool isInt8() const noexcept { return type() == kTypeInteger && Support::isInt8(value()); } + //! Tests whether the immediate can be casted to 8-bit unsigned integer. + constexpr bool isUInt8() const noexcept { return type() == kTypeInteger && Support::isUInt8(value()); } + //! Tests whether the immediate can be casted to 16-bit signed integer. + constexpr bool isInt16() const noexcept { return type() == kTypeInteger && Support::isInt16(value()); } + //! Tests whether the immediate can be casted to 16-bit unsigned integer. + constexpr bool isUInt16() const noexcept { return type() == kTypeInteger && Support::isUInt16(value()); } + //! Tests whether the immediate can be casted to 32-bit signed integer. + constexpr bool isInt32() const noexcept { return type() == kTypeInteger && Support::isInt32(value()); } + //! Tests whether the immediate can be casted to 32-bit unsigned integer. + constexpr bool isUInt32() const noexcept { return type() == kTypeInteger && _data[kDataImmValueHi] == 0; } + + //! Returns the immediate value casted to `T`. + //! + //! The value is masked before it's casted to `T` so the returned value is + //! simply the representation of `T` considering the original value's lowest + //! bits. + template + inline T valueAs() const noexcept { return Support::immediateToT(value()); } + + //! Returns low 32-bit signed integer. + constexpr int32_t int32Lo() const noexcept { return int32_t(_data[kDataImmValueLo]); } + //! Returns high 32-bit signed integer. + constexpr int32_t int32Hi() const noexcept { return int32_t(_data[kDataImmValueHi]); } + //! Returns low 32-bit signed integer. + constexpr uint32_t uint32Lo() const noexcept { return _data[kDataImmValueLo]; } + //! Returns high 32-bit signed integer. + constexpr uint32_t uint32Hi() const noexcept { return _data[kDataImmValueHi]; } + + //! Sets immediate value to `val`, the value is casted to a signed 64-bit integer. + template + inline void setValue(const T& val) noexcept { + _setValueInternal(Support::immediateFromT(val), std::is_floating_point::value ? kTypeDouble : kTypeInteger); + } + + inline void _setValueInternal(int64_t val, uint32_t type) noexcept { + setType(type); + _data[kDataImmValueHi] = uint32_t(uint64_t(val) >> 32); + _data[kDataImmValueLo] = uint32_t(uint64_t(val) & 0xFFFFFFFFu); + } + + //! \} + + //! \name Utilities + //! \{ + + //! Clones the immediate operand. + constexpr Imm clone() const noexcept { return Imm(*this); } + + inline void signExtend8Bits() noexcept { setValue(int64_t(valueAs())); } + inline void signExtend16Bits() noexcept { setValue(int64_t(valueAs())); } + inline void signExtend32Bits() noexcept { setValue(int64_t(valueAs())); } + + inline void zeroExtend8Bits() noexcept { setValue(valueAs()); } + inline void zeroExtend16Bits() noexcept { setValue(valueAs()); } + inline void zeroExtend32Bits() noexcept { _data[kDataImmValueHi] = 0u; } + + //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use valueAs() instead") + inline int8_t i8() const noexcept { return valueAs(); } + + ASMJIT_DEPRECATED("Use valueAs() instead") + inline uint8_t u8() const noexcept { return valueAs(); } + + ASMJIT_DEPRECATED("Use valueAs() instead") + inline int16_t i16() const noexcept { return valueAs(); } + + ASMJIT_DEPRECATED("Use valueAs() instead") + inline uint16_t u16() const noexcept { return valueAs(); } + + ASMJIT_DEPRECATED("Use valueAs() instead") + inline int32_t i32() const noexcept { return valueAs(); } + + ASMJIT_DEPRECATED("Use valueAs() instead") + inline uint32_t u32() const noexcept { return valueAs(); } + + ASMJIT_DEPRECATED("Use value() instead") + inline int64_t i64() const noexcept { return value(); } + + ASMJIT_DEPRECATED("Use valueAs() instead") + inline uint64_t u64() const noexcept { return valueAs(); } + + ASMJIT_DEPRECATED("Use valueAs() instead") + inline intptr_t iptr() const noexcept { return valueAs(); } + + ASMJIT_DEPRECATED("Use valueAs() instead") + inline uintptr_t uptr() const noexcept { return valueAs(); } + + ASMJIT_DEPRECATED("Use int32Lo() instead") + inline int32_t i32Lo() const noexcept { return int32Lo(); } + + ASMJIT_DEPRECATED("Use uint32Lo() instead") + inline uint32_t u32Lo() const noexcept { return uint32Lo(); } + + ASMJIT_DEPRECATED("Use int32Hi() instead") + inline int32_t i32Hi() const noexcept { return int32Hi(); } + + ASMJIT_DEPRECATED("Use uint32Hi() instead") + inline uint32_t u32Hi() const noexcept { return uint32Hi(); } +#endif // !ASMJIT_NO_DEPRECATED +}; + +//! Creates a new immediate operand. +//! +//! Using `imm(x)` is much nicer than using `Imm(x)` as this is a template +//! which can accept any integer including pointers and function pointers. +template +static constexpr Imm imm(const T& val) noexcept { return Imm(val); } + +//! \} + +// ============================================================================ +// [asmjit::Globals::none] +// ============================================================================ + +namespace Globals { + //! \ingroup asmjit_assembler + //! + //! A default-constructed operand of `Operand_::kOpNone` type. + static constexpr const Operand none; +} + +// ============================================================================ +// [asmjit::Support::ForwardOp] +// ============================================================================ + +//! \cond INTERNAL +namespace Support { + +template +struct ForwardOpImpl { + static ASMJIT_INLINE const T& forward(const T& value) noexcept { return value; } +}; + +template +struct ForwardOpImpl { + static ASMJIT_INLINE Imm forward(const T& value) noexcept { return Imm(value); } +}; + +//! Either forwards operand T or returns a new operand for T if T is a type +//! convertible to operand. At the moment this is only used to convert integers +//! to \ref Imm operands. +template +struct ForwardOp : public ForwardOpImpl::type>::value> {}; + +} + +//! \endcond + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_OPERAND_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/osutils.cpp b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/osutils.cpp new file mode 100644 index 0000000..e2f34ef --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/osutils.cpp @@ -0,0 +1,106 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/osutils.h" +#include "../core/support.h" + +#if defined(_WIN32) + #include +#elif defined(__APPLE__) + #include +#else + #include + #include +#endif + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::OSUtils - GetTickCount] +// ============================================================================ + +uint32_t OSUtils::getTickCount() noexcept { +#if defined(_WIN32) + enum HiResStatus : uint32_t { + kHiResUnknown = 0, + kHiResAvailable = 1, + kHiResNotAvailable = 2 + }; + + static std::atomic _hiResStatus(kHiResUnknown); + static volatile double _hiResFreq(0); + + uint32_t status = _hiResStatus.load(); + LARGE_INTEGER now, qpf; + + if (status != kHiResNotAvailable && ::QueryPerformanceCounter(&now)) { + double freq = _hiResFreq; + if (status == kHiResUnknown) { + // Detects the availability of high resolution counter. + if (::QueryPerformanceFrequency(&qpf)) { + freq = double(qpf.QuadPart) / 1000.0; + _hiResFreq = freq; + _hiResStatus.compare_exchange_strong(status, kHiResAvailable); + status = kHiResAvailable; + } + else { + // High resolution not available. + _hiResStatus.compare_exchange_strong(status, kHiResNotAvailable); + } + } + + if (status == kHiResAvailable) + return uint32_t(uint64_t(int64_t(double(now.QuadPart) / freq)) & 0xFFFFFFFFu); + } + + // Bail to `GetTickCount()` if we cannot use high resolution. + return ::GetTickCount(); +#elif defined(__APPLE__) + // See Apple's QA1398. + static mach_timebase_info_data_t _machTime; + + uint32_t denom = _machTime.denom; + if (ASMJIT_UNLIKELY(!denom)) { + if (mach_timebase_info(&_machTime) != KERN_SUCCESS || !(denom = _machTime.denom)) + return 0; + } + + // `mach_absolute_time()` returns nanoseconds, we want milliseconds. + uint64_t t = mach_absolute_time() / 1000000u; + t = (t * _machTime.numer) / _machTime.denom; + return uint32_t(t & 0xFFFFFFFFu); +#elif defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0 + struct timespec ts; + if (ASMJIT_UNLIKELY(clock_gettime(CLOCK_MONOTONIC, &ts) != 0)) + return 0; + + uint64_t t = (uint64_t(ts.tv_sec ) * 1000u) + (uint64_t(ts.tv_nsec) / 1000000u); + return uint32_t(t & 0xFFFFFFFFu); +#else + #pragma message("asmjit::OSUtils::getTickCount() doesn't have implementation for the target OS.") + return 0; +#endif +} + +ASMJIT_END_NAMESPACE diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/osutils.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/osutils.h new file mode 100644 index 0000000..a469129 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/osutils.h @@ -0,0 +1,87 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_OSUTILS_H_INCLUDED +#define ASMJIT_CORE_OSUTILS_H_INCLUDED + +#include "../core/globals.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_utilities +//! \{ + +// ============================================================================ +// [asmjit::OSUtils] +// ============================================================================ + +//! Operating system utilities. +namespace OSUtils { + //! Gets the current CPU tick count, used for benchmarking (1ms resolution). + ASMJIT_API uint32_t getTickCount() noexcept; +}; + +// ============================================================================ +// [asmjit::Lock] +// ============================================================================ + +//! \cond INTERNAL + +//! Lock. +//! +//! Lock is internal, it cannot be used outside of AsmJit, however, its internal +//! layout is exposed as it's used by some other classes, which are public. +class Lock { +public: + ASMJIT_NONCOPYABLE(Lock) + +#if defined(_WIN32) +#pragma pack(push, 8) + struct ASMJIT_MAY_ALIAS Handle { + void* DebugInfo; + long LockCount; + long RecursionCount; + void* OwningThread; + void* LockSemaphore; + unsigned long* SpinCount; + }; + Handle _handle; +#pragma pack(pop) +#elif !defined(__EMSCRIPTEN__) + typedef pthread_mutex_t Handle; + Handle _handle; +#endif + + inline Lock() noexcept; + inline ~Lock() noexcept; + + inline void lock() noexcept; + inline void unlock() noexcept; +}; +//! \endcond + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_OSUTILS_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/osutils_p.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/osutils_p.h new file mode 100644 index 0000000..31db308 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/osutils_p.h @@ -0,0 +1,94 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_OSUTILS_P_H_INCLUDED +#define ASMJIT_CORE_OSUTILS_P_H_INCLUDED + +#include "../core/osutils.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \cond INTERNAL +//! \addtogroup asmjit_utilities +//! \{ + +// ============================================================================ +// [asmjit::Lock] +// ============================================================================ + +#if defined(_WIN32) + +// Windows implementation. +static_assert(sizeof(Lock::Handle) == sizeof(CRITICAL_SECTION), "asmjit::Lock::Handle layout must match CRITICAL_SECTION"); +static_assert(alignof(Lock::Handle) == alignof(CRITICAL_SECTION), "asmjit::Lock::Handle alignment must match CRITICAL_SECTION"); + +inline Lock::Lock() noexcept { InitializeCriticalSection(reinterpret_cast(&_handle)); } +inline Lock::~Lock() noexcept { DeleteCriticalSection(reinterpret_cast(&_handle)); } +inline void Lock::lock() noexcept { EnterCriticalSection(reinterpret_cast(&_handle)); } +inline void Lock::unlock() noexcept { LeaveCriticalSection(reinterpret_cast(&_handle)); } + +#elif !defined(__EMSCRIPTEN__) + +// PThread implementation. +#ifdef PTHREAD_MUTEX_INITIALIZER +inline Lock::Lock() noexcept : _handle(PTHREAD_MUTEX_INITIALIZER) {} +#else +inline Lock::Lock() noexcept { pthread_mutex_init(&_handle, nullptr); } +#endif +inline Lock::~Lock() noexcept { pthread_mutex_destroy(&_handle); } +inline void Lock::lock() noexcept { pthread_mutex_lock(&_handle); } +inline void Lock::unlock() noexcept { pthread_mutex_unlock(&_handle); } + +#else + +// Dummy implementation - Emscripten or other unsupported platform. +inline Lock::Lock() noexcept {} +inline Lock::~Lock() noexcept {} +inline void Lock::lock() noexcept {} +inline void Lock::unlock() noexcept {} + +#endif + +// ============================================================================ +// [asmjit::LockGuard] +// ============================================================================ + +//! Scoped lock. +class LockGuard { +public: + ASMJIT_NONCOPYABLE(LockGuard) + + Lock& _target; + + inline LockGuard(Lock& target) noexcept + : _target(target) { _target.lock(); } + inline ~LockGuard() noexcept { _target.unlock(); } +}; + +//! \} +//! \endcond + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_OSUTILS_P_H_INCLUDED + diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/raassignment_p.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/raassignment_p.h new file mode 100644 index 0000000..bcdf1a9 --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/raassignment_p.h @@ -0,0 +1,408 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_RAASSIGNMENT_P_H_INCLUDED +#define ASMJIT_CORE_RAASSIGNMENT_P_H_INCLUDED + +#include "../core/api-config.h" +#ifndef ASMJIT_NO_COMPILER + +#include "../core/radefs_p.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \cond INTERNAL +//! \addtogroup asmjit_ra +//! \{ + +// ============================================================================ +// [asmjit::RAAssignment] +// ============================================================================ + +class RAAssignment { + ASMJIT_NONCOPYABLE(RAAssignment) + +public: + enum Ids : uint32_t { + kPhysNone = 0xFF, + kWorkNone = RAWorkReg::kIdNone + }; + + enum DirtyBit : uint32_t { + kClean = 0, + kDirty = 1 + }; + + struct Layout { + //! Index of architecture registers per group. + RARegIndex physIndex; + //! Count of architecture registers per group. + RARegCount physCount; + //! Count of physical registers of all groups. + uint32_t physTotal; + //! Count of work registers. + uint32_t workCount; + //! WorkRegs data (vector). + const RAWorkRegs* workRegs; + + inline void reset() noexcept { + physIndex.reset(); + physCount.reset(); + physTotal = 0; + workCount = 0; + workRegs = nullptr; + } + }; + + struct PhysToWorkMap { + //! Assigned registers (each bit represents one physical reg). + RARegMask assigned; + //! Dirty registers (spill slot out of sync or no spill slot). + RARegMask dirty; + //! PhysReg to WorkReg mapping. + uint32_t workIds[1 /* ... */]; + + static inline size_t sizeOf(size_t count) noexcept { + return sizeof(PhysToWorkMap) - sizeof(uint32_t) + count * sizeof(uint32_t); + } + + inline void reset(size_t count) noexcept { + assigned.reset(); + dirty.reset(); + + for (size_t i = 0; i < count; i++) + workIds[i] = kWorkNone; + } + + inline void copyFrom(const PhysToWorkMap* other, size_t count) noexcept { + size_t size = sizeOf(count); + memcpy(this, other, size); + } + }; + + struct WorkToPhysMap { + //! WorkReg to PhysReg mapping + uint8_t physIds[1 /* ... */]; + + static inline size_t sizeOf(size_t count) noexcept { + return size_t(count) * sizeof(uint8_t); + } + + inline void reset(size_t count) noexcept { + for (size_t i = 0; i < count; i++) + physIds[i] = kPhysNone; + } + + inline void copyFrom(const WorkToPhysMap* other, size_t count) noexcept { + size_t size = sizeOf(count); + if (ASMJIT_LIKELY(size)) + memcpy(this, other, size); + } + }; + + //! Physical registers layout. + Layout _layout; + //! WorkReg to PhysReg mapping. + WorkToPhysMap* _workToPhysMap; + //! PhysReg to WorkReg mapping and assigned/dirty bits. + PhysToWorkMap* _physToWorkMap; + //! Optimization to translate PhysRegs to WorkRegs faster. + uint32_t* _physToWorkIds[BaseReg::kGroupVirt]; + + //! \name Construction & Destruction + //! \{ + + inline RAAssignment() noexcept { + _layout.reset(); + resetMaps(); + } + + inline void initLayout(const RARegCount& physCount, const RAWorkRegs& workRegs) noexcept { + // Layout must be initialized before data. + ASMJIT_ASSERT(_physToWorkMap == nullptr); + ASMJIT_ASSERT(_workToPhysMap == nullptr); + + _layout.physIndex.buildIndexes(physCount); + _layout.physCount = physCount; + _layout.physTotal = uint32_t(_layout.physIndex[BaseReg::kGroupVirt - 1]) + + uint32_t(_layout.physCount[BaseReg::kGroupVirt - 1]) ; + _layout.workCount = workRegs.size(); + _layout.workRegs = &workRegs; + } + + inline void initMaps(PhysToWorkMap* physToWorkMap, WorkToPhysMap* workToPhysMap) noexcept { + _physToWorkMap = physToWorkMap; + _workToPhysMap = workToPhysMap; + for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++) + _physToWorkIds[group] = physToWorkMap->workIds + _layout.physIndex.get(group); + } + + inline void resetMaps() noexcept { + _physToWorkMap = nullptr; + _workToPhysMap = nullptr; + for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++) + _physToWorkIds[group] = nullptr; + } + + //! \} + + //! \name Accessors + //! \{ + + inline PhysToWorkMap* physToWorkMap() const noexcept { return _physToWorkMap; } + inline WorkToPhysMap* workToPhysMap() const noexcept { return _workToPhysMap; } + + inline RARegMask& assigned() noexcept { return _physToWorkMap->assigned; } + inline const RARegMask& assigned() const noexcept { return _physToWorkMap->assigned; } + inline uint32_t assigned(uint32_t group) const noexcept { return _physToWorkMap->assigned[group]; } + + inline RARegMask& dirty() noexcept { return _physToWorkMap->dirty; } + inline const RARegMask& dirty() const noexcept { return _physToWorkMap->dirty; } + inline uint32_t dirty(uint32_t group) const noexcept { return _physToWorkMap->dirty[group]; } + + inline uint32_t workToPhysId(uint32_t group, uint32_t workId) const noexcept { + DebugUtils::unused(group); + ASMJIT_ASSERT(workId != kWorkNone); + ASMJIT_ASSERT(workId < _layout.workCount); + return _workToPhysMap->physIds[workId]; + } + + inline uint32_t physToWorkId(uint32_t group, uint32_t physId) const noexcept { + ASMJIT_ASSERT(physId < Globals::kMaxPhysRegs); + return _physToWorkIds[group][physId]; + } + + inline bool isPhysAssigned(uint32_t group, uint32_t physId) const noexcept { + ASMJIT_ASSERT(physId < Globals::kMaxPhysRegs); + return Support::bitTest(_physToWorkMap->assigned[group], physId); + } + + inline bool isPhysDirty(uint32_t group, uint32_t physId) const noexcept { + ASMJIT_ASSERT(physId < Globals::kMaxPhysRegs); + return Support::bitTest(_physToWorkMap->dirty[group], physId); + } + + //! \} + + //! \name Assignment + //! \{ + + // These are low-level allocation helpers that are used to update the current + // mappings between physical and virt/work registers and also to update masks + // that represent allocated and dirty registers. These functions don't emit + // any code; they are only used to update and keep all mappings in sync. + + //! Assign [VirtReg/WorkReg] to a physical register. + ASMJIT_INLINE void assign(uint32_t group, uint32_t workId, uint32_t physId, uint32_t dirty) noexcept { + ASMJIT_ASSERT(workToPhysId(group, workId) == kPhysNone); + ASMJIT_ASSERT(physToWorkId(group, physId) == kWorkNone); + ASMJIT_ASSERT(!isPhysAssigned(group, physId)); + ASMJIT_ASSERT(!isPhysDirty(group, physId)); + + _workToPhysMap->physIds[workId] = uint8_t(physId); + _physToWorkIds[group][physId] = workId; + + uint32_t regMask = Support::bitMask(physId); + _physToWorkMap->assigned[group] |= regMask; + _physToWorkMap->dirty[group] |= regMask & Support::bitMaskFromBool(dirty); + + verify(); + } + + //! Reassign [VirtReg/WorkReg] to `dstPhysId` from `srcPhysId`. + ASMJIT_INLINE void reassign(uint32_t group, uint32_t workId, uint32_t dstPhysId, uint32_t srcPhysId) noexcept { + ASMJIT_ASSERT(dstPhysId != srcPhysId); + ASMJIT_ASSERT(workToPhysId(group, workId) == srcPhysId); + ASMJIT_ASSERT(physToWorkId(group, srcPhysId) == workId); + ASMJIT_ASSERT(isPhysAssigned(group, srcPhysId) == true); + ASMJIT_ASSERT(isPhysAssigned(group, dstPhysId) == false); + + _workToPhysMap->physIds[workId] = uint8_t(dstPhysId); + _physToWorkIds[group][srcPhysId] = kWorkNone; + _physToWorkIds[group][dstPhysId] = workId; + + uint32_t srcMask = Support::bitMask(srcPhysId); + uint32_t dstMask = Support::bitMask(dstPhysId); + + uint32_t dirty = (_physToWorkMap->dirty[group] & srcMask) != 0; + uint32_t regMask = dstMask | srcMask; + + _physToWorkMap->assigned[group] ^= regMask; + _physToWorkMap->dirty[group] ^= regMask & Support::bitMaskFromBool(dirty); + + verify(); + } + + ASMJIT_INLINE void swap(uint32_t group, uint32_t aWorkId, uint32_t aPhysId, uint32_t bWorkId, uint32_t bPhysId) noexcept { + ASMJIT_ASSERT(aPhysId != bPhysId); + ASMJIT_ASSERT(workToPhysId(group, aWorkId) == aPhysId); + ASMJIT_ASSERT(workToPhysId(group, bWorkId) == bPhysId); + ASMJIT_ASSERT(physToWorkId(group, aPhysId) == aWorkId); + ASMJIT_ASSERT(physToWorkId(group, bPhysId) == bWorkId); + ASMJIT_ASSERT(isPhysAssigned(group, aPhysId)); + ASMJIT_ASSERT(isPhysAssigned(group, bPhysId)); + + _workToPhysMap->physIds[aWorkId] = uint8_t(bPhysId); + _workToPhysMap->physIds[bWorkId] = uint8_t(aPhysId); + _physToWorkIds[group][aPhysId] = bWorkId; + _physToWorkIds[group][bPhysId] = aWorkId; + + uint32_t aMask = Support::bitMask(aPhysId); + uint32_t bMask = Support::bitMask(bPhysId); + + uint32_t flipMask = Support::bitMaskFromBool( + ((_physToWorkMap->dirty[group] & aMask) != 0) ^ + ((_physToWorkMap->dirty[group] & bMask) != 0)); + + uint32_t regMask = aMask | bMask; + _physToWorkMap->dirty[group] ^= regMask & flipMask; + + verify(); + } + + //! Unassign [VirtReg/WorkReg] from a physical register. + ASMJIT_INLINE void unassign(uint32_t group, uint32_t workId, uint32_t physId) noexcept { + ASMJIT_ASSERT(physId < Globals::kMaxPhysRegs); + ASMJIT_ASSERT(workToPhysId(group, workId) == physId); + ASMJIT_ASSERT(physToWorkId(group, physId) == workId); + ASMJIT_ASSERT(isPhysAssigned(group, physId)); + + _workToPhysMap->physIds[workId] = kPhysNone; + _physToWorkIds[group][physId] = kWorkNone; + + uint32_t regMask = Support::bitMask(physId); + _physToWorkMap->assigned[group] &= ~regMask; + _physToWorkMap->dirty[group] &= ~regMask; + + verify(); + } + + inline void makeClean(uint32_t group, uint32_t workId, uint32_t physId) noexcept { + DebugUtils::unused(workId); + uint32_t regMask = Support::bitMask(physId); + _physToWorkMap->dirty[group] &= ~regMask; + } + + inline void makeDirty(uint32_t group, uint32_t workId, uint32_t physId) noexcept { + DebugUtils::unused(workId); + uint32_t regMask = Support::bitMask(physId); + _physToWorkMap->dirty[group] |= regMask; + } + + //! \} + + //! \name Utilities + //! \{ + + inline void swap(RAAssignment& other) noexcept { + std::swap(_workToPhysMap, other._workToPhysMap); + std::swap(_physToWorkMap, other._physToWorkMap); + + for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++) + std::swap(_physToWorkIds[group], other._physToWorkIds[group]); + } + + inline void copyFrom(const PhysToWorkMap* physToWorkMap, const WorkToPhysMap* workToPhysMap) noexcept { + memcpy(_physToWorkMap, physToWorkMap, PhysToWorkMap::sizeOf(_layout.physTotal)); + memcpy(_workToPhysMap, workToPhysMap, WorkToPhysMap::sizeOf(_layout.workCount)); + } + + inline void copyFrom(const RAAssignment& other) noexcept { + copyFrom(other.physToWorkMap(), other.workToPhysMap()); + } + + // Not really useful outside of debugging. + bool equals(const RAAssignment& other) const noexcept { + // Layout should always match. + if (_layout.physIndex != other._layout.physIndex || + _layout.physCount != other._layout.physCount || + _layout.physTotal != other._layout.physTotal || + _layout.workCount != other._layout.workCount || + _layout.workRegs != other._layout.workRegs) + return false; + + uint32_t physTotal = _layout.physTotal; + uint32_t workCount = _layout.workCount; + + for (uint32_t physId = 0; physId < physTotal; physId++) { + uint32_t thisWorkId = _physToWorkMap->workIds[physId]; + uint32_t otherWorkId = other._physToWorkMap->workIds[physId]; + if (thisWorkId != otherWorkId) + return false; + } + + for (uint32_t workId = 0; workId < workCount; workId++) { + uint32_t thisPhysId = _workToPhysMap->physIds[workId]; + uint32_t otherPhysId = other._workToPhysMap->physIds[workId]; + if (thisPhysId != otherPhysId) + return false; + } + + if (_physToWorkMap->assigned != other._physToWorkMap->assigned || + _physToWorkMap->dirty != other._physToWorkMap->dirty ) + return false; + + return true; + } + +#if defined(ASMJIT_BUILD_DEBUG) + ASMJIT_NOINLINE void verify() noexcept { + // Verify WorkToPhysMap. + { + for (uint32_t workId = 0; workId < _layout.workCount; workId++) { + uint32_t physId = _workToPhysMap->physIds[workId]; + if (physId != kPhysNone) { + const RAWorkReg* workReg = _layout.workRegs->at(workId); + uint32_t group = workReg->group(); + ASMJIT_ASSERT(_physToWorkIds[group][physId] == workId); + } + } + } + + // Verify PhysToWorkMap. + { + for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++) { + uint32_t physCount = _layout.physCount[group]; + for (uint32_t physId = 0; physId < physCount; physId++) { + uint32_t workId = _physToWorkIds[group][physId]; + if (workId != kWorkNone) { + ASMJIT_ASSERT(_workToPhysMap->physIds[workId] == physId); + } + } + } + } + } +#else + inline void verify() noexcept {} +#endif + + //! \} +}; + +//! \} +//! \endcond + +ASMJIT_END_NAMESPACE + +#endif // !ASMJIT_NO_COMPILER +#endif // ASMJIT_CORE_RAASSIGNMENT_P_H_INCLUDED diff --git a/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/rabuilders_p.h b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/rabuilders_p.h new file mode 100644 index 0000000..290839f --- /dev/null +++ b/Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/rabuilders_p.h @@ -0,0 +1,636 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_RABUILDERS_P_H_INCLUDED +#define ASMJIT_CORE_RABUILDERS_P_H_INCLUDED + +#include "../core/api-config.h" +#ifndef ASMJIT_NO_COMPILER + +#include "../core/formatter.h" +#include "../core/rapass_p.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \cond INTERNAL +//! \addtogroup asmjit_ra +//! \{ + +// ============================================================================ +// [asmjit::RACFGBuilderT] +// ============================================================================ + +template +class RACFGBuilderT { +public: + BaseRAPass* _pass = nullptr; + BaseCompiler* _cc = nullptr; + RABlock* _curBlock = nullptr; + RABlock* _retBlock = nullptr; + FuncNode* _funcNode = nullptr; + RARegsStats _blockRegStats {}; + uint32_t _exitLabelId = Globals::kInvalidId; + ZoneVector _sharedAssignmentsMap {}; + + // Only used by logging, it's fine to be here to prevent more #ifdefs... + bool _hasCode = false; + RABlock* _lastLoggedBlock = nullptr; + +#ifndef ASMJIT_NO_LOGGING + Logger* _logger = nullptr; + uint32_t _logFlags = FormatOptions::kFlagPositions; + StringTmp<512> _sb; +#endif + + static constexpr uint32_t kRootIndentation = 2; + static constexpr uint32_t kCodeIndentation = 4; + + // NOTE: This is a bit hacky. There are some nodes which are processed twice + // (see `onBeforeInvoke()` and `onBeforeRet()`) as they can insert some nodes + // around them. Since we don't have any flags to mark these we just use their + // position that is [at that time] unassigned. + static constexpr uint32_t kNodePositionDidOnBefore = 0xFFFFFFFFu; + + inline RACFGBuilderT(BaseRAPass* pass) noexcept + : _pass(pass), + _cc(pass->cc()) { +#ifndef ASMJIT_NO_LOGGING + _logger = _pass->debugLogger(); + if (_logger) + _logFlags |= _logger->flags(); +#endif + } + + inline BaseCompiler* cc() const noexcept { return _cc; } + + // -------------------------------------------------------------------------- + // [Run] + // -------------------------------------------------------------------------- + + //! Called per function by an architecture-specific CFG builder. + Error run() noexcept { + log("[RAPass::BuildCFG]\n"); + ASMJIT_PROPAGATE(prepare()); + + logNode(_funcNode, kRootIndentation); + logBlock(_curBlock, kRootIndentation); + + RABlock* entryBlock = _curBlock; + BaseNode* node = _funcNode->next(); + if (ASMJIT_UNLIKELY(!node)) + return DebugUtils::errored(kErrorInvalidState); + + _curBlock->setFirst(_funcNode); + _curBlock->setLast(_funcNode); + + RAInstBuilder ib; + ZoneVector blocksWithUnknownJumps; + + for (;;) { + BaseNode* next = node->next(); + ASMJIT_ASSERT(node->position() == 0 || node->position() == kNodePositionDidOnBefore); + + if (node->isInst()) { + // Instruction | Jump | Invoke | Return + // ------------------------------------ + + // Handle `InstNode`, `InvokeNode`, and `FuncRetNode`. All of them + // share the same interface that provides operands that have read/write + // semantics. + if (ASMJIT_UNLIKELY(!_curBlock)) { + // Unreachable code has to be removed, we cannot allocate registers + // in such code as we cannot do proper liveness analysis in such case. + removeNode(node); + node = next; + continue; + } + + _hasCode = true; + + if (node->isInvoke() || node->isFuncRet()) { + if (node->position() != kNodePositionDidOnBefore) { + // Call and Reg are complicated as they may insert some surrounding + // code around them. The simplest approach is to get the previous + // node, call the `onBefore()` handlers and then check whether + // anything changed and restart if so. By restart we mean that the + // current `node` would go back to the first possible inserted node + // by `onBeforeInvoke()` or `onBeforeRet()`. + BaseNode* prev = node->prev(); + + if (node->type() == BaseNode::kNodeInvoke) + ASMJIT_PROPAGATE(static_cast(this)->onBeforeInvoke(node->as())); + else + ASMJIT_PROPAGATE(static_cast(this)->onBeforeRet(node->as())); + + if (prev != node->prev()) { + // If this was the first node in the block and something was + // inserted before it then we have to update the first block. + if (_curBlock->first() == node) + _curBlock->setFirst(prev->next()); + + node->setPosition(kNodePositionDidOnBefore); + node = prev->next(); + + // `onBeforeInvoke()` and `onBeforeRet()` can only insert instructions. + ASMJIT_ASSERT(node->isInst()); + } + + // Necessary if something was inserted after `node`, but nothing before. + next = node->next(); + } + else { + // Change the position back to its original value. + node->setPosition(0); + } + } + + InstNode* inst = node->as(); + logNode(inst, kCodeIndentation); + + uint32_t controlType = BaseInst::kControlNone; + ib.reset(); + ASMJIT_PROPAGATE(static_cast(this)->onInst(inst, controlType, ib)); + + if (node->isInvoke()) { + ASMJIT_PROPAGATE(static_cast(this)->onInvoke(inst->as(), ib)); + } + + if (node->isFuncRet()) { + ASMJIT_PROPAGATE(static_cast(this)->onRet(inst->as(), ib)); + controlType = BaseInst::kControlReturn; + } + + if (controlType == BaseInst::kControlJump) { + uint32_t fixedRegCount = 0; + for (RATiedReg& tiedReg : ib) { + RAWorkReg* workReg = _pass->workRegById(tiedReg.workId()); + if (workReg->group() == BaseReg::kGroupGp) { + uint32_t useId = tiedReg.useId(); + if (useId == BaseReg::kIdBad) { + useId = _pass->_scratchRegIndexes[fixedRegCount++]; + tiedReg.setUseId(useId); + } + _curBlock->addExitScratchGpRegs(Support::bitMask(useId)); + } + } + } + + ASMJIT_PROPAGATE(_pass->assignRAInst(inst, _curBlock, ib)); + _blockRegStats.combineWith(ib._stats); + + if (controlType != BaseInst::kControlNone) { + // Support for conditional and unconditional jumps. + if (controlType == BaseInst::kControlJump || controlType == BaseInst::kControlBranch) { + _curBlock->setLast(node); + _curBlock->addFlags(RABlock::kFlagHasTerminator); + _curBlock->makeConstructed(_blockRegStats); + + if (!(inst->instOptions() & BaseInst::kOptionUnfollow)) { + // Jmp/Jcc/Call/Loop/etc... + uint32_t opCount = inst->opCount(); + const Operand* opArray = inst->operands(); + + // Cannot jump anywhere without operands. + if (ASMJIT_UNLIKELY(!opCount)) + return DebugUtils::errored(kErrorInvalidState); + + if (opArray[opCount - 1].isLabel()) { + // Labels are easy for constructing the control flow. + LabelNode* labelNode; + ASMJIT_PROPAGATE(cc()->labelNodeOf(&labelNode, opArray[opCount - 1].as