From 207a08c2cf201252145825e37336e84eabd4b779 Mon Sep 17 00:00:00 2001 From: _xeroxz Date: Sun, 7 Mar 2021 22:11:17 -0800 Subject: [PATCH] added examples --- Examples/DemoDll/DemoDll.vcxproj | 109 + Examples/DemoDll/DemoDll.vcxproj.filters | 22 + .../DemoDll/DemoDll.vcxproj.user | 0 {DemoDrv => Examples/DemoDll}/Theodosius.h | 0 Examples/DemoDll/main.cpp | 28 + {DemoDrv => Examples/DemoDrv}/DemoDrv.vcxproj | 2 +- .../DemoDrv}/DemoDrv.vcxproj.filters | 0 Examples/DemoDrv/DemoDrv.vcxproj.user | 4 + {DemoDrv => Examples/DemoDrv}/DriverEntry.cpp | 0 Examples/DemoDrv/Theodosius.h | 3 + {DemoDrv => Examples/DemoDrv}/Types.h | 0 Examples/Theodosius-Examples.sln | 43 + .../Theodosius-MSREXEC.vcxproj | 278 + .../Theodosius-MSREXEC.vcxproj.filters | 589 + .../Theodosius-MSREXEC.vcxproj.user | 13 + .../Theodosius-MSREXEC/Zycore.lib | Bin 0 -> 262406 bytes .../Theodosius-MSREXEC/Zycore/API/Memory.h | 134 + .../Theodosius-MSREXEC/Zycore/API/Process.h | 67 + .../Zycore/API/Synchronization.h | 133 + .../Theodosius-MSREXEC/Zycore/API/Terminal.h | 163 + .../Theodosius-MSREXEC/Zycore/API/Thread.h | 244 + .../Theodosius-MSREXEC/Zycore/Allocator.h | 143 + .../Theodosius-MSREXEC/Zycore/ArgParse.h | 173 + .../Theodosius-MSREXEC/Zycore/Bitset.h | 484 + .../Theodosius-MSREXEC/Zycore/Comparison.h | 316 + .../Theodosius-MSREXEC/Zycore/Defines.h | 443 + .../Theodosius-MSREXEC/Zycore/Format.h | 286 + .../Theodosius-MSREXEC/Zycore/LibC.h | 511 + .../Theodosius-MSREXEC/Zycore/List.h | 574 + .../Theodosius-MSREXEC/Zycore/Object.h | 84 + .../Theodosius-MSREXEC/Zycore/Status.h | 287 + .../Theodosius-MSREXEC/Zycore/String.h | 1012 + .../Theodosius-MSREXEC/Zycore/Types.h | 195 + .../Theodosius-MSREXEC/Zycore/Vector.h | 723 + .../Theodosius-MSREXEC/Zycore/Zycore.h | 111 + .../Theodosius-MSREXEC/ZycoreExportConfig.h | 42 + .../Theodosius-MSREXEC/Zydis.lib | Bin 0 -> 1344336 bytes .../Theodosius-MSREXEC/Zydis/Decoder.h | 237 + .../Theodosius-MSREXEC/Zydis/DecoderTypes.h | 1528 ++ .../Theodosius-MSREXEC/Zydis/Formatter.h | 1179 + .../Zydis/FormatterBuffer.h | 306 + .../Zydis/Generated/EnumISAExt.h | 98 + .../Zydis/Generated/EnumISASet.h | 184 + .../Zydis/Generated/EnumInstructionCategory.h | 117 + .../Zydis/Generated/EnumMnemonic.h | 1643 ++ .../Zydis/Generated/EnumRegister.h | 301 + .../Zydis/Internal/DecoderData.h | 331 + .../Zydis/Internal/FormatterATT.h | 178 + .../Zydis/Internal/FormatterBase.h | 318 + .../Zydis/Internal/FormatterIntel.h | 267 + .../Zydis/Internal/SharedData.h | 974 + .../Zydis/Internal/String.h | 464 + .../Theodosius-MSREXEC/Zydis/MetaInfo.h | 88 + .../Theodosius-MSREXEC/Zydis/Mnemonic.h | 88 + .../Theodosius-MSREXEC/Zydis/Register.h | 293 + .../Theodosius-MSREXEC/Zydis/SharedTypes.h | 480 + .../Theodosius-MSREXEC/Zydis/ShortString.h | 90 + .../Theodosius-MSREXEC/Zydis/Status.h | 159 + .../Theodosius-MSREXEC/Zydis/Utils.h | 275 + .../Theodosius-MSREXEC/Zydis/Zydis.h | 169 + .../Theodosius-MSREXEC/ZydisExportConfig.h | 42 + .../Theodosius-MSREXEC/asmjit.natvis | 201 + .../asmjit/asmjit-scope-begin.h | 35 + .../asmjit/asmjit-scope-end.h | 27 + .../Theodosius-MSREXEC/asmjit/asmjit.h | 37 + .../Theodosius-MSREXEC/asmjit/core.h | 2063 ++ .../asmjit/core/api-build_p.h | 77 + .../asmjit/core/api-config.h | 552 + .../asmjit/core/archcommons.h | 164 + .../asmjit/core/archtraits.cpp | 155 + .../asmjit/core/archtraits.h | 174 + .../asmjit/core/assembler.cpp | 409 + .../asmjit/core/assembler.h | 152 + .../asmjit/core/builder.cpp | 920 + .../Theodosius-MSREXEC/asmjit/core/builder.h | 1435 + .../asmjit/core/codebuffer.h | 126 + .../asmjit/core/codeholder.cpp | 1150 + .../asmjit/core/codeholder.h | 1061 + .../asmjit/core/codewriter.cpp | 151 + .../asmjit/core/codewriter_p.h | 208 + .../asmjit/core/compiler.cpp | 628 + .../Theodosius-MSREXEC/asmjit/core/compiler.h | 763 + .../asmjit/core/compilerdefs.h | 170 + .../asmjit/core/constpool.cpp | 375 + .../asmjit/core/constpool.h | 262 + .../asmjit/core/cpuinfo.cpp | 97 + .../Theodosius-MSREXEC/asmjit/core/cpuinfo.h | 154 + .../asmjit/core/datatypes.h | 1071 + .../asmjit/core/emithelper.cpp | 351 + .../asmjit/core/emithelper_p.h | 83 + .../asmjit/core/emitter.cpp | 416 + .../Theodosius-MSREXEC/asmjit/core/emitter.h | 723 + .../asmjit/core/emitterutils.cpp | 150 + .../asmjit/core/emitterutils_p.h | 109 + .../asmjit/core/environment.cpp | 64 + .../asmjit/core/environment.h | 612 + .../asmjit/core/errorhandler.cpp | 37 + .../asmjit/core/errorhandler.h | 267 + .../Theodosius-MSREXEC/asmjit/core/features.h | 186 + .../asmjit/core/formatter.cpp | 481 + .../asmjit/core/formatter.h | 256 + .../Theodosius-MSREXEC/asmjit/core/func.cpp | 310 + .../Theodosius-MSREXEC/asmjit/core/func.h | 1426 + .../asmjit/core/funcargscontext.cpp | 315 + .../asmjit/core/funcargscontext_p.h | 224 + .../asmjit/core/globals.cpp | 146 + .../Theodosius-MSREXEC/asmjit/core/globals.h | 462 + .../Theodosius-MSREXEC/asmjit/core/inst.cpp | 139 + .../Theodosius-MSREXEC/asmjit/core/inst.h | 559 + .../asmjit/core/jitallocator.cpp | 1246 + .../asmjit/core/jitallocator.h | 278 + .../asmjit/core/jitruntime.cpp | 128 + .../asmjit/core/jitruntime.h | 126 + .../Theodosius-MSREXEC/asmjit/core/logger.cpp | 124 + .../Theodosius-MSREXEC/asmjit/core/logger.h | 228 + .../Theodosius-MSREXEC/asmjit/core/misc_p.h | 51 + .../asmjit/core/operand.cpp | 143 + .../Theodosius-MSREXEC/asmjit/core/operand.h | 1530 ++ .../asmjit/core/osutils.cpp | 106 + .../Theodosius-MSREXEC/asmjit/core/osutils.h | 87 + .../asmjit/core/osutils_p.h | 94 + .../asmjit/core/raassignment_p.h | 408 + .../asmjit/core/rabuilders_p.h | 636 + .../Theodosius-MSREXEC/asmjit/core/radefs_p.h | 1077 + .../asmjit/core/ralocal.cpp | 1046 + .../asmjit/core/ralocal_p.h | 282 + .../Theodosius-MSREXEC/asmjit/core/rapass.cpp | 1984 ++ .../Theodosius-MSREXEC/asmjit/core/rapass_p.h | 1175 + .../asmjit/core/rastack.cpp | 206 + .../asmjit/core/rastack_p.h | 187 + .../Theodosius-MSREXEC/asmjit/core/string.cpp | 551 + .../Theodosius-MSREXEC/asmjit/core/string.h | 400 + .../asmjit/core/support.cpp | 507 + .../Theodosius-MSREXEC/asmjit/core/support.h | 1573 ++ .../Theodosius-MSREXEC/asmjit/core/target.cpp | 37 + .../Theodosius-MSREXEC/asmjit/core/target.h | 175 + .../Theodosius-MSREXEC/asmjit/core/type.cpp | 92 + .../Theodosius-MSREXEC/asmjit/core/type.h | 375 + .../asmjit/core/virtmem.cpp | 640 + .../Theodosius-MSREXEC/asmjit/core/virtmem.h | 165 + .../Theodosius-MSREXEC/asmjit/core/zone.cpp | 382 + .../Theodosius-MSREXEC/asmjit/core/zone.h | 649 + .../asmjit/core/zonehash.cpp | 331 + .../Theodosius-MSREXEC/asmjit/core/zonehash.h | 218 + .../asmjit/core/zonelist.cpp | 182 + .../Theodosius-MSREXEC/asmjit/core/zonelist.h | 205 + .../asmjit/core/zonestack.cpp | 197 + .../asmjit/core/zonestack.h | 234 + .../asmjit/core/zonestring.h | 137 + .../asmjit/core/zonetree.cpp | 118 + .../Theodosius-MSREXEC/asmjit/core/zonetree.h | 385 + .../asmjit/core/zonevector.cpp | 377 + .../asmjit/core/zonevector.h | 714 + .../Theodosius-MSREXEC/asmjit/x86.h | 119 + .../asmjit/x86/x86archtraits_p.h | 150 + .../asmjit/x86/x86assembler.cpp | 5147 ++++ .../asmjit/x86/x86assembler.h | 743 + .../asmjit/x86/x86builder.cpp | 68 + .../asmjit/x86/x86builder.h | 387 + .../asmjit/x86/x86compiler.cpp | 77 + .../asmjit/x86/x86compiler.h | 721 + .../asmjit/x86/x86emithelper.cpp | 603 + .../asmjit/x86/x86emithelper_p.h | 78 + .../asmjit/x86/x86emitter.h | 4164 +++ .../asmjit/x86/x86features.cpp | 452 + .../asmjit/x86/x86features.h | 318 + .../asmjit/x86/x86formatter.cpp | 934 + .../asmjit/x86/x86formatter_p.h | 80 + .../Theodosius-MSREXEC/asmjit/x86/x86func.cpp | 531 + .../Theodosius-MSREXEC/asmjit/x86/x86func_p.h | 55 + .../asmjit/x86/x86globals.h | 2172 ++ .../asmjit/x86/x86instapi.cpp | 1675 ++ .../asmjit/x86/x86instapi_p.h | 59 + .../asmjit/x86/x86instdb.cpp | 4217 +++ .../Theodosius-MSREXEC/asmjit/x86/x86instdb.h | 474 + .../asmjit/x86/x86instdb_p.h | 342 + .../asmjit/x86/x86opcode_p.h | 482 + .../asmjit/x86/x86operand.cpp | 248 + .../asmjit/x86/x86operand.h | 1136 + .../asmjit/x86/x86rapass.cpp | 1286 + .../asmjit/x86/x86rapass_p.h | 118 + .../Theodosius-MSREXEC/ia32.hpp | 21527 ++++++++++++++++ .../Theodosius-MSREXEC/linker/linker.cpp | 301 + .../Theodosius-MSREXEC/linker/linker.hpp | 76 + .../Theodosius-MSREXEC}/loadup.hpp | 0 .../Theodosius-MSREXEC}/main.cpp | 23 +- .../Theodosius-MSREXEC}/msrexec.cpp | 0 .../Theodosius-MSREXEC}/msrexec.hpp | 0 .../obfuscation/obfuscation.cpp | 179 + .../obfuscation/obfuscation.hpp | 59 + .../Theodosius-MSREXEC}/raw_driver.hpp | 0 .../Theodosius-MSREXEC}/syscall_handler.asm | 0 .../Theodosius-MSREXEC}/syscall_handler.h | 0 .../Theodosius-MSREXEC/theo.cpp | 2 +- .../Theodosius-MSREXEC/theo.h | 0 .../Theodosius-MSREXEC/utils.hpp | 428 + .../Theodosius-MSREXEC}/vdm.hpp | 0 .../Theodosius-VDM/Theodosius-VDM.vcxproj | 273 + .../Theodosius-VDM.vcxproj.filters | 584 + .../Theodosius-VDM.vcxproj.user | 13 + .../Theodosius-VDM/Zycore.lib | Bin 0 -> 262406 bytes .../Theodosius-VDM/Zycore/API/Memory.h | 134 + .../Theodosius-VDM/Zycore/API/Process.h | 67 + .../Zycore/API/Synchronization.h | 133 + .../Theodosius-VDM/Zycore/API/Terminal.h | 163 + .../Theodosius-VDM/Zycore/API/Thread.h | 244 + .../Theodosius-VDM/Zycore/Allocator.h | 143 + .../Theodosius-VDM/Zycore/ArgParse.h | 173 + .../Theodosius-VDM/Zycore/Bitset.h | 484 + .../Theodosius-VDM/Zycore/Comparison.h | 316 + .../Theodosius-VDM/Zycore/Defines.h | 443 + .../Theodosius-VDM/Zycore/Format.h | 286 + .../Theodosius-VDM/Zycore/LibC.h | 511 + .../Theodosius-VDM/Zycore/List.h | 574 + .../Theodosius-VDM/Zycore/Object.h | 84 + .../Theodosius-VDM/Zycore/Status.h | 287 + .../Theodosius-VDM/Zycore/String.h | 1012 + .../Theodosius-VDM/Zycore/Types.h | 195 + .../Theodosius-VDM/Zycore/Vector.h | 723 + .../Theodosius-VDM/Zycore/Zycore.h | 111 + .../Theodosius-VDM/ZycoreExportConfig.h | 42 + .../Theodosius-VDM/Zydis.lib | Bin 0 -> 1344336 bytes .../Theodosius-VDM/Zydis/Decoder.h | 237 + .../Theodosius-VDM/Zydis/DecoderTypes.h | 1528 ++ .../Theodosius-VDM/Zydis/Formatter.h | 1179 + .../Theodosius-VDM/Zydis/FormatterBuffer.h | 306 + .../Zydis/Generated/EnumISAExt.h | 98 + .../Zydis/Generated/EnumISASet.h | 184 + .../Zydis/Generated/EnumInstructionCategory.h | 117 + .../Zydis/Generated/EnumMnemonic.h | 1643 ++ .../Zydis/Generated/EnumRegister.h | 301 + .../Zydis/Internal/DecoderData.h | 331 + .../Zydis/Internal/FormatterATT.h | 178 + .../Zydis/Internal/FormatterBase.h | 318 + .../Zydis/Internal/FormatterIntel.h | 267 + .../Zydis/Internal/SharedData.h | 974 + .../Theodosius-VDM/Zydis/Internal/String.h | 464 + .../Theodosius-VDM/Zydis/MetaInfo.h | 88 + .../Theodosius-VDM/Zydis/Mnemonic.h | 88 + .../Theodosius-VDM/Zydis/Register.h | 293 + .../Theodosius-VDM/Zydis/SharedTypes.h | 480 + .../Theodosius-VDM/Zydis/ShortString.h | 90 + .../Theodosius-VDM/Zydis/Status.h | 159 + .../Theodosius-VDM/Zydis/Utils.h | 275 + .../Theodosius-VDM/Zydis/Zydis.h | 169 + .../Theodosius-VDM/ZydisExportConfig.h | 42 + .../Theodosius-VDM/asmjit.natvis | 201 + .../asmjit/asmjit-scope-begin.h | 35 + .../Theodosius-VDM/asmjit/asmjit-scope-end.h | 27 + .../Theodosius-VDM/asmjit/asmjit.h | 37 + .../Theodosius-VDM/asmjit/core.h | 2063 ++ .../Theodosius-VDM/asmjit/core/api-build_p.h | 77 + .../Theodosius-VDM/asmjit/core/api-config.h | 552 + .../Theodosius-VDM/asmjit/core/archcommons.h | 164 + .../Theodosius-VDM/asmjit/core/archtraits.cpp | 155 + .../Theodosius-VDM/asmjit/core/archtraits.h | 174 + .../Theodosius-VDM/asmjit/core/assembler.cpp | 409 + .../Theodosius-VDM/asmjit/core/assembler.h | 152 + .../Theodosius-VDM/asmjit/core/builder.cpp | 920 + .../Theodosius-VDM/asmjit/core/builder.h | 1435 + .../Theodosius-VDM/asmjit/core/codebuffer.h | 126 + .../Theodosius-VDM/asmjit/core/codeholder.cpp | 1150 + .../Theodosius-VDM/asmjit/core/codeholder.h | 1061 + .../Theodosius-VDM/asmjit/core/codewriter.cpp | 151 + .../Theodosius-VDM/asmjit/core/codewriter_p.h | 208 + .../Theodosius-VDM/asmjit/core/compiler.cpp | 628 + .../Theodosius-VDM/asmjit/core/compiler.h | 763 + .../Theodosius-VDM/asmjit/core/compilerdefs.h | 170 + .../Theodosius-VDM/asmjit/core/constpool.cpp | 375 + .../Theodosius-VDM/asmjit/core/constpool.h | 262 + .../Theodosius-VDM/asmjit/core/cpuinfo.cpp | 97 + .../Theodosius-VDM/asmjit/core/cpuinfo.h | 154 + .../Theodosius-VDM/asmjit/core/datatypes.h | 1071 + .../Theodosius-VDM/asmjit/core/emithelper.cpp | 351 + .../Theodosius-VDM/asmjit/core/emithelper_p.h | 83 + .../Theodosius-VDM/asmjit/core/emitter.cpp | 416 + .../Theodosius-VDM/asmjit/core/emitter.h | 723 + .../asmjit/core/emitterutils.cpp | 150 + .../asmjit/core/emitterutils_p.h | 109 + .../asmjit/core/environment.cpp | 64 + .../Theodosius-VDM/asmjit/core/environment.h | 612 + .../asmjit/core/errorhandler.cpp | 37 + .../Theodosius-VDM/asmjit/core/errorhandler.h | 267 + .../Theodosius-VDM/asmjit/core/features.h | 186 + .../Theodosius-VDM/asmjit/core/formatter.cpp | 481 + .../Theodosius-VDM/asmjit/core/formatter.h | 256 + .../Theodosius-VDM/asmjit/core/func.cpp | 310 + .../Theodosius-VDM/asmjit/core/func.h | 1426 + .../asmjit/core/funcargscontext.cpp | 315 + .../asmjit/core/funcargscontext_p.h | 224 + .../Theodosius-VDM/asmjit/core/globals.cpp | 146 + .../Theodosius-VDM/asmjit/core/globals.h | 462 + .../Theodosius-VDM/asmjit/core/inst.cpp | 139 + .../Theodosius-VDM/asmjit/core/inst.h | 559 + .../asmjit/core/jitallocator.cpp | 1246 + .../Theodosius-VDM/asmjit/core/jitallocator.h | 278 + .../Theodosius-VDM/asmjit/core/jitruntime.cpp | 128 + .../Theodosius-VDM/asmjit/core/jitruntime.h | 126 + .../Theodosius-VDM/asmjit/core/logger.cpp | 124 + .../Theodosius-VDM/asmjit/core/logger.h | 228 + .../Theodosius-VDM/asmjit/core/misc_p.h | 51 + .../Theodosius-VDM/asmjit/core/operand.cpp | 143 + .../Theodosius-VDM/asmjit/core/operand.h | 1530 ++ .../Theodosius-VDM/asmjit/core/osutils.cpp | 106 + .../Theodosius-VDM/asmjit/core/osutils.h | 87 + .../Theodosius-VDM/asmjit/core/osutils_p.h | 94 + .../asmjit/core/raassignment_p.h | 408 + .../Theodosius-VDM/asmjit/core/rabuilders_p.h | 636 + .../Theodosius-VDM/asmjit/core/radefs_p.h | 1077 + .../Theodosius-VDM/asmjit/core/ralocal.cpp | 1046 + .../Theodosius-VDM/asmjit/core/ralocal_p.h | 282 + .../Theodosius-VDM/asmjit/core/rapass.cpp | 1984 ++ .../Theodosius-VDM/asmjit/core/rapass_p.h | 1175 + .../Theodosius-VDM/asmjit/core/rastack.cpp | 206 + .../Theodosius-VDM/asmjit/core/rastack_p.h | 187 + .../Theodosius-VDM/asmjit/core/string.cpp | 551 + .../Theodosius-VDM/asmjit/core/string.h | 400 + .../Theodosius-VDM/asmjit/core/support.cpp | 507 + .../Theodosius-VDM/asmjit/core/support.h | 1573 ++ .../Theodosius-VDM/asmjit/core/target.cpp | 37 + .../Theodosius-VDM/asmjit/core/target.h | 175 + .../Theodosius-VDM/asmjit/core/type.cpp | 92 + .../Theodosius-VDM/asmjit/core/type.h | 375 + .../Theodosius-VDM/asmjit/core/virtmem.cpp | 640 + .../Theodosius-VDM/asmjit/core/virtmem.h | 165 + .../Theodosius-VDM/asmjit/core/zone.cpp | 382 + .../Theodosius-VDM/asmjit/core/zone.h | 649 + .../Theodosius-VDM/asmjit/core/zonehash.cpp | 331 + .../Theodosius-VDM/asmjit/core/zonehash.h | 218 + .../Theodosius-VDM/asmjit/core/zonelist.cpp | 182 + .../Theodosius-VDM/asmjit/core/zonelist.h | 205 + .../Theodosius-VDM/asmjit/core/zonestack.cpp | 197 + .../Theodosius-VDM/asmjit/core/zonestack.h | 234 + .../Theodosius-VDM/asmjit/core/zonestring.h | 137 + .../Theodosius-VDM/asmjit/core/zonetree.cpp | 118 + .../Theodosius-VDM/asmjit/core/zonetree.h | 385 + .../Theodosius-VDM/asmjit/core/zonevector.cpp | 377 + .../Theodosius-VDM/asmjit/core/zonevector.h | 714 + .../Theodosius-VDM/asmjit/x86.h | 119 + .../asmjit/x86/x86archtraits_p.h | 150 + .../asmjit/x86/x86assembler.cpp | 5147 ++++ .../Theodosius-VDM/asmjit/x86/x86assembler.h | 743 + .../Theodosius-VDM/asmjit/x86/x86builder.cpp | 68 + .../Theodosius-VDM/asmjit/x86/x86builder.h | 387 + .../Theodosius-VDM/asmjit/x86/x86compiler.cpp | 77 + .../Theodosius-VDM/asmjit/x86/x86compiler.h | 721 + .../asmjit/x86/x86emithelper.cpp | 603 + .../asmjit/x86/x86emithelper_p.h | 78 + .../Theodosius-VDM/asmjit/x86/x86emitter.h | 4164 +++ .../Theodosius-VDM/asmjit/x86/x86features.cpp | 452 + .../Theodosius-VDM/asmjit/x86/x86features.h | 318 + .../asmjit/x86/x86formatter.cpp | 934 + .../asmjit/x86/x86formatter_p.h | 80 + .../Theodosius-VDM/asmjit/x86/x86func.cpp | 531 + .../Theodosius-VDM/asmjit/x86/x86func_p.h | 55 + .../Theodosius-VDM/asmjit/x86/x86globals.h | 2172 ++ .../Theodosius-VDM/asmjit/x86/x86instapi.cpp | 1675 ++ .../Theodosius-VDM/asmjit/x86/x86instapi_p.h | 59 + .../Theodosius-VDM/asmjit/x86/x86instdb.cpp | 4217 +++ .../Theodosius-VDM/asmjit/x86/x86instdb.h | 474 + .../Theodosius-VDM/asmjit/x86/x86instdb_p.h | 342 + .../Theodosius-VDM/asmjit/x86/x86opcode_p.h | 482 + .../Theodosius-VDM/asmjit/x86/x86operand.cpp | 248 + .../Theodosius-VDM/asmjit/x86/x86operand.h | 1136 + .../Theodosius-VDM/asmjit/x86/x86rapass.cpp | 1286 + .../Theodosius-VDM/asmjit/x86/x86rapass_p.h | 118 + .../Theodosius-Kernel/Theodosius-VDM/ia32.hpp | 21527 ++++++++++++++++ .../Theodosius-VDM/linker/linker.cpp | 301 + .../Theodosius-VDM/linker/linker.hpp | 76 + .../Theodosius-VDM/loadup.hpp | 262 + .../Theodosius-Kernel/Theodosius-VDM/main.cpp | 216 + .../obfuscation/obfuscation.cpp | 179 + .../obfuscation/obfuscation.hpp | 59 + .../Theodosius-Kernel/Theodosius-VDM/theo.cpp | 376 + .../Theodosius-Kernel/Theodosius-VDM/theo.h | 47 + .../Theodosius-VDM/utils.hpp | 491 + .../Theodosius-VDM/vdm/raw_driver.hpp | 2242 ++ .../Theodosius-VDM/vdm/vdm.hpp | 139 + .../Theodosius-VDM/vdm_ctx/vdm_ctx.cpp | 103 + .../Theodosius-VDM/vdm_ctx/vdm_ctx.hpp | 71 + .../Theodosius-Usermode.vcxproj | 268 + .../Theodosius-Usermode.vcxproj.filters | 566 + .../Theodosius-Usermode.vcxproj.user | 13 + Examples/Theodosius-Usermode/Zycore.lib | Bin 0 -> 262406 bytes .../Theodosius-Usermode/Zycore/API/Memory.h | 134 + .../Theodosius-Usermode/Zycore/API/Process.h | 67 + .../Zycore/API/Synchronization.h | 133 + .../Theodosius-Usermode/Zycore/API/Terminal.h | 163 + .../Theodosius-Usermode/Zycore/API/Thread.h | 244 + .../Theodosius-Usermode/Zycore/Allocator.h | 143 + .../Theodosius-Usermode/Zycore/ArgParse.h | 173 + Examples/Theodosius-Usermode/Zycore/Bitset.h | 484 + .../Theodosius-Usermode/Zycore/Comparison.h | 316 + Examples/Theodosius-Usermode/Zycore/Defines.h | 443 + Examples/Theodosius-Usermode/Zycore/Format.h | 286 + Examples/Theodosius-Usermode/Zycore/LibC.h | 511 + Examples/Theodosius-Usermode/Zycore/List.h | 574 + Examples/Theodosius-Usermode/Zycore/Object.h | 84 + Examples/Theodosius-Usermode/Zycore/Status.h | 287 + Examples/Theodosius-Usermode/Zycore/String.h | 1012 + Examples/Theodosius-Usermode/Zycore/Types.h | 195 + Examples/Theodosius-Usermode/Zycore/Vector.h | 723 + Examples/Theodosius-Usermode/Zycore/Zycore.h | 111 + .../Theodosius-Usermode/ZycoreExportConfig.h | 42 + Examples/Theodosius-Usermode/Zydis.lib | Bin 0 -> 1344336 bytes Examples/Theodosius-Usermode/Zydis/Decoder.h | 237 + .../Theodosius-Usermode/Zydis/DecoderTypes.h | 1528 ++ .../Theodosius-Usermode/Zydis/Formatter.h | 1179 + .../Zydis/FormatterBuffer.h | 306 + .../Zydis/Generated/EnumISAExt.h | 98 + .../Zydis/Generated/EnumISASet.h | 184 + .../Zydis/Generated/EnumInstructionCategory.h | 117 + .../Zydis/Generated/EnumMnemonic.h | 1643 ++ .../Zydis/Generated/EnumRegister.h | 301 + .../Zydis/Internal/DecoderData.h | 331 + .../Zydis/Internal/FormatterATT.h | 178 + .../Zydis/Internal/FormatterBase.h | 318 + .../Zydis/Internal/FormatterIntel.h | 267 + .../Zydis/Internal/SharedData.h | 974 + .../Zydis/Internal/String.h | 464 + Examples/Theodosius-Usermode/Zydis/MetaInfo.h | 88 + Examples/Theodosius-Usermode/Zydis/Mnemonic.h | 88 + Examples/Theodosius-Usermode/Zydis/Register.h | 293 + .../Theodosius-Usermode/Zydis/SharedTypes.h | 480 + .../Theodosius-Usermode/Zydis/ShortString.h | 90 + Examples/Theodosius-Usermode/Zydis/Status.h | 159 + Examples/Theodosius-Usermode/Zydis/Utils.h | 275 + Examples/Theodosius-Usermode/Zydis/Zydis.h | 169 + .../Theodosius-Usermode/ZydisExportConfig.h | 42 + Examples/Theodosius-Usermode/asmjit.natvis | 201 + .../asmjit/asmjit-scope-begin.h | 35 + .../asmjit/asmjit-scope-end.h | 27 + Examples/Theodosius-Usermode/asmjit/asmjit.h | 37 + Examples/Theodosius-Usermode/asmjit/core.h | 2063 ++ .../asmjit/core/api-build_p.h | 77 + .../asmjit/core/api-config.h | 552 + .../asmjit/core/archcommons.h | 164 + .../asmjit/core/archtraits.cpp | 155 + .../asmjit/core/archtraits.h | 174 + .../asmjit/core/assembler.cpp | 409 + .../asmjit/core/assembler.h | 152 + .../asmjit/core/builder.cpp | 920 + .../Theodosius-Usermode/asmjit/core/builder.h | 1435 + .../asmjit/core/codebuffer.h | 126 + .../asmjit/core/codeholder.cpp | 1150 + .../asmjit/core/codeholder.h | 1061 + .../asmjit/core/codewriter.cpp | 151 + .../asmjit/core/codewriter_p.h | 208 + .../asmjit/core/compiler.cpp | 628 + .../asmjit/core/compiler.h | 763 + .../asmjit/core/compilerdefs.h | 170 + .../asmjit/core/constpool.cpp | 375 + .../asmjit/core/constpool.h | 262 + .../asmjit/core/cpuinfo.cpp | 97 + .../Theodosius-Usermode/asmjit/core/cpuinfo.h | 154 + .../asmjit/core/datatypes.h | 1071 + .../asmjit/core/emithelper.cpp | 351 + .../asmjit/core/emithelper_p.h | 83 + .../asmjit/core/emitter.cpp | 416 + .../Theodosius-Usermode/asmjit/core/emitter.h | 723 + .../asmjit/core/emitterutils.cpp | 150 + .../asmjit/core/emitterutils_p.h | 109 + .../asmjit/core/environment.cpp | 64 + .../asmjit/core/environment.h | 612 + .../asmjit/core/errorhandler.cpp | 37 + .../asmjit/core/errorhandler.h | 267 + .../asmjit/core/features.h | 186 + .../asmjit/core/formatter.cpp | 481 + .../asmjit/core/formatter.h | 256 + .../Theodosius-Usermode/asmjit/core/func.cpp | 310 + .../Theodosius-Usermode/asmjit/core/func.h | 1426 + .../asmjit/core/funcargscontext.cpp | 315 + .../asmjit/core/funcargscontext_p.h | 224 + .../asmjit/core/globals.cpp | 146 + .../Theodosius-Usermode/asmjit/core/globals.h | 462 + .../Theodosius-Usermode/asmjit/core/inst.cpp | 139 + .../Theodosius-Usermode/asmjit/core/inst.h | 559 + .../asmjit/core/jitallocator.cpp | 1246 + .../asmjit/core/jitallocator.h | 278 + .../asmjit/core/jitruntime.cpp | 128 + .../asmjit/core/jitruntime.h | 126 + .../asmjit/core/logger.cpp | 124 + .../Theodosius-Usermode/asmjit/core/logger.h | 228 + .../Theodosius-Usermode/asmjit/core/misc_p.h | 51 + .../asmjit/core/operand.cpp | 143 + .../Theodosius-Usermode/asmjit/core/operand.h | 1530 ++ .../asmjit/core/osutils.cpp | 106 + .../Theodosius-Usermode/asmjit/core/osutils.h | 87 + .../asmjit/core/osutils_p.h | 94 + .../asmjit/core/raassignment_p.h | 408 + .../asmjit/core/rabuilders_p.h | 636 + .../asmjit/core/radefs_p.h | 1077 + .../asmjit/core/ralocal.cpp | 1046 + .../asmjit/core/ralocal_p.h | 282 + .../asmjit/core/rapass.cpp | 1984 ++ .../asmjit/core/rapass_p.h | 1175 + .../asmjit/core/rastack.cpp | 206 + .../asmjit/core/rastack_p.h | 187 + .../asmjit/core/string.cpp | 551 + .../Theodosius-Usermode/asmjit/core/string.h | 400 + .../asmjit/core/support.cpp | 507 + .../Theodosius-Usermode/asmjit/core/support.h | 1573 ++ .../asmjit/core/target.cpp | 37 + .../Theodosius-Usermode/asmjit/core/target.h | 175 + .../Theodosius-Usermode/asmjit/core/type.cpp | 92 + .../Theodosius-Usermode/asmjit/core/type.h | 375 + .../asmjit/core/virtmem.cpp | 640 + .../Theodosius-Usermode/asmjit/core/virtmem.h | 165 + .../Theodosius-Usermode/asmjit/core/zone.cpp | 382 + .../Theodosius-Usermode/asmjit/core/zone.h | 649 + .../asmjit/core/zonehash.cpp | 331 + .../asmjit/core/zonehash.h | 218 + .../asmjit/core/zonelist.cpp | 182 + .../asmjit/core/zonelist.h | 205 + .../asmjit/core/zonestack.cpp | 197 + .../asmjit/core/zonestack.h | 234 + .../asmjit/core/zonestring.h | 137 + .../asmjit/core/zonetree.cpp | 118 + .../asmjit/core/zonetree.h | 385 + .../asmjit/core/zonevector.cpp | 377 + .../asmjit/core/zonevector.h | 714 + Examples/Theodosius-Usermode/asmjit/x86.h | 119 + .../asmjit/x86/x86archtraits_p.h | 150 + .../asmjit/x86/x86assembler.cpp | 5147 ++++ .../asmjit/x86/x86assembler.h | 743 + .../asmjit/x86/x86builder.cpp | 68 + .../asmjit/x86/x86builder.h | 387 + .../asmjit/x86/x86compiler.cpp | 77 + .../asmjit/x86/x86compiler.h | 721 + .../asmjit/x86/x86emithelper.cpp | 603 + .../asmjit/x86/x86emithelper_p.h | 78 + .../asmjit/x86/x86emitter.h | 4164 +++ .../asmjit/x86/x86features.cpp | 452 + .../asmjit/x86/x86features.h | 318 + .../asmjit/x86/x86formatter.cpp | 934 + .../asmjit/x86/x86formatter_p.h | 80 + .../asmjit/x86/x86func.cpp | 531 + .../asmjit/x86/x86func_p.h | 55 + .../asmjit/x86/x86globals.h | 2172 ++ .../asmjit/x86/x86instapi.cpp | 1675 ++ .../asmjit/x86/x86instapi_p.h | 59 + .../asmjit/x86/x86instdb.cpp | 4217 +++ .../asmjit/x86/x86instdb.h | 474 + .../asmjit/x86/x86instdb_p.h | 342 + .../asmjit/x86/x86opcode_p.h | 482 + .../asmjit/x86/x86operand.cpp | 248 + .../asmjit/x86/x86operand.h | 1136 + .../asmjit/x86/x86rapass.cpp | 1286 + .../asmjit/x86/x86rapass_p.h | 118 + Examples/Theodosius-Usermode/ia32.hpp | 21527 ++++++++++++++++ .../Theodosius-Usermode/linker/linker.cpp | 301 + .../Theodosius-Usermode/linker/linker.hpp | 76 + Examples/Theodosius-Usermode/main.cpp | 162 + .../obfuscation/obfuscation.cpp | 179 + .../obfuscation/obfuscation.hpp | 59 + Examples/Theodosius-Usermode/theo.cpp | 376 + Examples/Theodosius-Usermode/theo.h | 47 + Examples/Theodosius-Usermode/utils.hpp | 423 + Theodosius.sln | 18 +- Theodosius/Theodosius.vcxproj | 23 +- Theodosius/Theodosius.vcxproj.filters | 38 +- Theodosius/Theodosius.vcxproj.user | 6 +- Theodosius/theo.cpp | 376 + Theodosius/theo.h | 47 + 564 files changed, 322543 insertions(+), 74 deletions(-) create mode 100644 Examples/DemoDll/DemoDll.vcxproj create mode 100644 Examples/DemoDll/DemoDll.vcxproj.filters rename DemoDrv/DemoDrv.vcxproj.user => Examples/DemoDll/DemoDll.vcxproj.user (100%) rename {DemoDrv => Examples/DemoDll}/Theodosius.h (100%) create mode 100644 Examples/DemoDll/main.cpp rename {DemoDrv => Examples/DemoDrv}/DemoDrv.vcxproj (98%) rename {DemoDrv => Examples/DemoDrv}/DemoDrv.vcxproj.filters (100%) create mode 100644 Examples/DemoDrv/DemoDrv.vcxproj.user rename {DemoDrv => Examples/DemoDrv}/DriverEntry.cpp (100%) create mode 100644 Examples/DemoDrv/Theodosius.h rename {DemoDrv => Examples/DemoDrv}/Types.h (100%) create mode 100644 Examples/Theodosius-Examples.sln create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Theodosius-MSREXEC.vcxproj create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Theodosius-MSREXEC.vcxproj.filters create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Theodosius-MSREXEC.vcxproj.user create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore.lib create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Memory.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Process.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Synchronization.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Terminal.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/API/Thread.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Allocator.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/ArgParse.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Bitset.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Comparison.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Defines.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Format.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/LibC.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/List.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Object.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Status.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/String.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Types.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Vector.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zycore/Zycore.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/ZycoreExportConfig.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis.lib create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Decoder.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/DecoderTypes.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Formatter.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/FormatterBuffer.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumISAExt.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumISASet.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumInstructionCategory.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumMnemonic.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Generated/EnumRegister.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/DecoderData.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/FormatterATT.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/FormatterBase.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/FormatterIntel.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/SharedData.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Internal/String.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/MetaInfo.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Mnemonic.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Register.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/SharedTypes.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/ShortString.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Status.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Utils.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/Zydis/Zydis.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/ZydisExportConfig.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit.natvis create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/asmjit-scope-begin.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/asmjit-scope-end.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/asmjit.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/api-build_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/api-config.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/archcommons.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/archtraits.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/archtraits.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/assembler.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/assembler.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/builder.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/builder.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codebuffer.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codeholder.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codeholder.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codewriter.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/codewriter_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/compiler.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/compiler.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/compilerdefs.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/constpool.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/constpool.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/cpuinfo.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/cpuinfo.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/datatypes.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emithelper.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emithelper_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emitter.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emitter.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emitterutils.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/emitterutils_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/environment.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/environment.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/errorhandler.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/errorhandler.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/features.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/formatter.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/formatter.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/func.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/func.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/funcargscontext.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/funcargscontext_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/globals.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/globals.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/inst.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/inst.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/jitallocator.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/jitallocator.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/jitruntime.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/jitruntime.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/logger.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/logger.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/misc_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/operand.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/operand.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/osutils.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/osutils.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/osutils_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/raassignment_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/rabuilders_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/radefs_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/ralocal.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/ralocal_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/rapass.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/rapass_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/rastack.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/rastack_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/string.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/string.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/support.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/support.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/target.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/target.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/type.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/type.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/virtmem.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/virtmem.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/zone.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/zone.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/zonehash.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/zonehash.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/zonelist.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/zonelist.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/zonestack.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/zonestack.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/zonestring.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/zonetree.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/zonetree.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/zonevector.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/core/zonevector.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86archtraits_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86assembler.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86assembler.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86builder.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86builder.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86compiler.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86compiler.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86emithelper.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86emithelper_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86emitter.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86features.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86features.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86formatter.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86formatter_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86func.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86func_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86globals.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86instapi.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86instapi_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86instdb.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86instdb.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86instdb_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86opcode_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86operand.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86operand.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86rapass.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/asmjit/x86/x86rapass_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/ia32.hpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/linker/linker.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/linker/linker.hpp rename {Theodosius => Examples/Theodosius-Kernel/Theodosius-MSREXEC}/loadup.hpp (100%) rename {Theodosius => Examples/Theodosius-Kernel/Theodosius-MSREXEC}/main.cpp (93%) rename {Theodosius => Examples/Theodosius-Kernel/Theodosius-MSREXEC}/msrexec.cpp (100%) rename {Theodosius => Examples/Theodosius-Kernel/Theodosius-MSREXEC}/msrexec.hpp (100%) create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/obfuscation/obfuscation.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/obfuscation/obfuscation.hpp rename {Theodosius => Examples/Theodosius-Kernel/Theodosius-MSREXEC}/raw_driver.hpp (100%) rename {Theodosius => Examples/Theodosius-Kernel/Theodosius-MSREXEC}/syscall_handler.asm (100%) rename {Theodosius => Examples/Theodosius-Kernel/Theodosius-MSREXEC}/syscall_handler.h (100%) rename Theodosius/hmdm_ctx.cpp => Examples/Theodosius-Kernel/Theodosius-MSREXEC/theo.cpp (99%) rename Theodosius/hmdm_ctx.h => Examples/Theodosius-Kernel/Theodosius-MSREXEC/theo.h (100%) create mode 100644 Examples/Theodosius-Kernel/Theodosius-MSREXEC/utils.hpp rename {Theodosius => Examples/Theodosius-Kernel/Theodosius-MSREXEC}/vdm.hpp (100%) create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Theodosius-VDM.vcxproj create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Theodosius-VDM.vcxproj.filters create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Theodosius-VDM.vcxproj.user create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore.lib create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore/API/Memory.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore/API/Process.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore/API/Synchronization.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore/API/Terminal.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore/API/Thread.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore/Allocator.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore/ArgParse.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore/Bitset.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore/Comparison.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore/Defines.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore/Format.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore/LibC.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore/List.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore/Object.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore/Status.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore/String.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore/Types.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore/Vector.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zycore/Zycore.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/ZycoreExportConfig.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis.lib create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/Decoder.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/DecoderTypes.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/Formatter.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/FormatterBuffer.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/Generated/EnumISAExt.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/Generated/EnumISASet.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/Generated/EnumInstructionCategory.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/Generated/EnumMnemonic.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/Generated/EnumRegister.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/Internal/DecoderData.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/Internal/FormatterATT.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/Internal/FormatterBase.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/Internal/FormatterIntel.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/Internal/SharedData.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/Internal/String.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/MetaInfo.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/Mnemonic.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/Register.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/SharedTypes.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/ShortString.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/Status.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/Utils.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/Zydis/Zydis.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/ZydisExportConfig.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit.natvis create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/asmjit-scope-begin.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/asmjit-scope-end.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/asmjit.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/api-build_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/api-config.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/archcommons.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/archtraits.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/archtraits.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/assembler.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/assembler.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/builder.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/builder.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/codebuffer.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/codeholder.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/codeholder.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/codewriter.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/codewriter_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/compiler.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/compiler.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/compilerdefs.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/constpool.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/constpool.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/cpuinfo.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/cpuinfo.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/datatypes.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/emithelper.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/emithelper_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/emitter.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/emitter.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/emitterutils.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/emitterutils_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/environment.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/environment.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/errorhandler.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/errorhandler.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/features.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/formatter.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/formatter.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/func.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/func.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/funcargscontext.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/funcargscontext_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/globals.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/globals.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/inst.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/inst.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/jitallocator.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/jitallocator.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/jitruntime.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/jitruntime.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/logger.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/logger.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/misc_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/operand.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/operand.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/osutils.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/osutils.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/osutils_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/raassignment_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/rabuilders_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/radefs_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/ralocal.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/ralocal_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/rapass.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/rapass_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/rastack.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/rastack_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/string.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/string.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/support.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/support.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/target.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/target.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/type.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/type.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/virtmem.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/virtmem.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/zone.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/zone.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/zonehash.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/zonehash.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/zonelist.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/zonelist.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/zonestack.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/zonestack.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/zonestring.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/zonetree.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/zonetree.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/zonevector.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/core/zonevector.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86archtraits_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86assembler.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86assembler.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86builder.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86builder.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86compiler.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86compiler.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86emithelper.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86emithelper_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86emitter.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86features.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86features.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86formatter.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86formatter_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86func.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86func_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86globals.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86instapi.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86instapi_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86instdb.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86instdb.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86instdb_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86opcode_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86operand.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86operand.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86rapass.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/asmjit/x86/x86rapass_p.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/ia32.hpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/linker/linker.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/linker/linker.hpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/loadup.hpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/main.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/obfuscation/obfuscation.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/obfuscation/obfuscation.hpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/theo.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/theo.h create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/utils.hpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/vdm/raw_driver.hpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/vdm/vdm.hpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/vdm_ctx/vdm_ctx.cpp create mode 100644 Examples/Theodosius-Kernel/Theodosius-VDM/vdm_ctx/vdm_ctx.hpp create mode 100644 Examples/Theodosius-Usermode/Theodosius-Usermode.vcxproj create mode 100644 Examples/Theodosius-Usermode/Theodosius-Usermode.vcxproj.filters create mode 100644 Examples/Theodosius-Usermode/Theodosius-Usermode.vcxproj.user create mode 100644 Examples/Theodosius-Usermode/Zycore.lib create mode 100644 Examples/Theodosius-Usermode/Zycore/API/Memory.h create mode 100644 Examples/Theodosius-Usermode/Zycore/API/Process.h create mode 100644 Examples/Theodosius-Usermode/Zycore/API/Synchronization.h create mode 100644 Examples/Theodosius-Usermode/Zycore/API/Terminal.h create mode 100644 Examples/Theodosius-Usermode/Zycore/API/Thread.h create mode 100644 Examples/Theodosius-Usermode/Zycore/Allocator.h create mode 100644 Examples/Theodosius-Usermode/Zycore/ArgParse.h create mode 100644 Examples/Theodosius-Usermode/Zycore/Bitset.h create mode 100644 Examples/Theodosius-Usermode/Zycore/Comparison.h create mode 100644 Examples/Theodosius-Usermode/Zycore/Defines.h create mode 100644 Examples/Theodosius-Usermode/Zycore/Format.h create mode 100644 Examples/Theodosius-Usermode/Zycore/LibC.h create mode 100644 Examples/Theodosius-Usermode/Zycore/List.h create mode 100644 Examples/Theodosius-Usermode/Zycore/Object.h create mode 100644 Examples/Theodosius-Usermode/Zycore/Status.h create mode 100644 Examples/Theodosius-Usermode/Zycore/String.h create mode 100644 Examples/Theodosius-Usermode/Zycore/Types.h create mode 100644 Examples/Theodosius-Usermode/Zycore/Vector.h create mode 100644 Examples/Theodosius-Usermode/Zycore/Zycore.h create mode 100644 Examples/Theodosius-Usermode/ZycoreExportConfig.h create mode 100644 Examples/Theodosius-Usermode/Zydis.lib create mode 100644 Examples/Theodosius-Usermode/Zydis/Decoder.h create mode 100644 Examples/Theodosius-Usermode/Zydis/DecoderTypes.h create mode 100644 Examples/Theodosius-Usermode/Zydis/Formatter.h create mode 100644 Examples/Theodosius-Usermode/Zydis/FormatterBuffer.h create mode 100644 Examples/Theodosius-Usermode/Zydis/Generated/EnumISAExt.h create mode 100644 Examples/Theodosius-Usermode/Zydis/Generated/EnumISASet.h create mode 100644 Examples/Theodosius-Usermode/Zydis/Generated/EnumInstructionCategory.h create mode 100644 Examples/Theodosius-Usermode/Zydis/Generated/EnumMnemonic.h create mode 100644 Examples/Theodosius-Usermode/Zydis/Generated/EnumRegister.h create mode 100644 Examples/Theodosius-Usermode/Zydis/Internal/DecoderData.h create mode 100644 Examples/Theodosius-Usermode/Zydis/Internal/FormatterATT.h create mode 100644 Examples/Theodosius-Usermode/Zydis/Internal/FormatterBase.h create mode 100644 Examples/Theodosius-Usermode/Zydis/Internal/FormatterIntel.h create mode 100644 Examples/Theodosius-Usermode/Zydis/Internal/SharedData.h create mode 100644 Examples/Theodosius-Usermode/Zydis/Internal/String.h create mode 100644 Examples/Theodosius-Usermode/Zydis/MetaInfo.h create mode 100644 Examples/Theodosius-Usermode/Zydis/Mnemonic.h create mode 100644 Examples/Theodosius-Usermode/Zydis/Register.h create mode 100644 Examples/Theodosius-Usermode/Zydis/SharedTypes.h create mode 100644 Examples/Theodosius-Usermode/Zydis/ShortString.h create mode 100644 Examples/Theodosius-Usermode/Zydis/Status.h create mode 100644 Examples/Theodosius-Usermode/Zydis/Utils.h create mode 100644 Examples/Theodosius-Usermode/Zydis/Zydis.h create mode 100644 Examples/Theodosius-Usermode/ZydisExportConfig.h create mode 100644 Examples/Theodosius-Usermode/asmjit.natvis create mode 100644 Examples/Theodosius-Usermode/asmjit/asmjit-scope-begin.h create mode 100644 Examples/Theodosius-Usermode/asmjit/asmjit-scope-end.h create mode 100644 Examples/Theodosius-Usermode/asmjit/asmjit.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/api-build_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/api-config.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/archcommons.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/archtraits.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/archtraits.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/assembler.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/assembler.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/builder.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/builder.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/codebuffer.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/codeholder.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/codeholder.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/codewriter.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/codewriter_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/compiler.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/compiler.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/compilerdefs.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/constpool.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/constpool.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/cpuinfo.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/cpuinfo.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/datatypes.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/emithelper.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/emithelper_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/emitter.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/emitter.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/emitterutils.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/emitterutils_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/environment.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/environment.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/errorhandler.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/errorhandler.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/features.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/formatter.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/formatter.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/func.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/func.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/funcargscontext.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/funcargscontext_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/globals.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/globals.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/inst.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/inst.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/jitallocator.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/jitallocator.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/jitruntime.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/jitruntime.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/logger.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/logger.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/misc_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/operand.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/operand.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/osutils.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/osutils.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/osutils_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/raassignment_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/rabuilders_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/radefs_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/ralocal.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/ralocal_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/rapass.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/rapass_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/rastack.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/rastack_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/string.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/string.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/support.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/support.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/target.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/target.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/type.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/type.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/virtmem.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/virtmem.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/zone.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/zone.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/zonehash.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/zonehash.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/zonelist.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/zonelist.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/zonestack.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/zonestack.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/zonestring.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/zonetree.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/zonetree.h create mode 100644 Examples/Theodosius-Usermode/asmjit/core/zonevector.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/core/zonevector.h create mode 100644 Examples/Theodosius-Usermode/asmjit/x86.h create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86archtraits_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86assembler.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86assembler.h create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86builder.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86builder.h create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86compiler.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86compiler.h create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86emithelper.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86emithelper_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86emitter.h create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86features.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86features.h create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86formatter.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86formatter_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86func.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86func_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86globals.h create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86instapi.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86instapi_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86instdb.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86instdb.h create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86instdb_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86opcode_p.h create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86operand.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86operand.h create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86rapass.cpp create mode 100644 Examples/Theodosius-Usermode/asmjit/x86/x86rapass_p.h create mode 100644 Examples/Theodosius-Usermode/ia32.hpp create mode 100644 Examples/Theodosius-Usermode/linker/linker.cpp create mode 100644 Examples/Theodosius-Usermode/linker/linker.hpp create mode 100644 Examples/Theodosius-Usermode/main.cpp create mode 100644 Examples/Theodosius-Usermode/obfuscation/obfuscation.cpp create mode 100644 Examples/Theodosius-Usermode/obfuscation/obfuscation.hpp create mode 100644 Examples/Theodosius-Usermode/theo.cpp create mode 100644 Examples/Theodosius-Usermode/theo.h create mode 100644 Examples/Theodosius-Usermode/utils.hpp create mode 100644 Theodosius/theo.cpp create mode 100644 Theodosius/theo.h 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 0000000000000000000000000000000000000000..b36a9382ce0ab14f7b109449de8363d3b054a564 GIT binary patch literal 262406 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

ewBL3^ayLVTs7 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..42ca9b6ea787481fc0ea05c1b07649f5c936e96b GIT binary patch literal 1344336 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�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
(); + 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

P~gONzY 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�yK{GGk7O`r-k=>M~<)0#=t9^AfPSxMi1v&0=+N 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 z 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 +#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