提交 5068031f 编写于 作者: K khz_pc

Blackbone分支Branch_bd30dd1的源码

上级 cff95bda
###############################################################################
# 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
#OS junk files
[Tt]humbs.db
*.DS_Store
#Visual Studio files
*.[Oo]bj
*.user
*.aps
*.pch
*.vspscc
*.vssscc
*_i.c
*_p.c
*.ncb
*.suo
*.tlb
*.tlh
*.bak
*.[Cc]ache
*.ilk
*.log
*.tlog
*.pdb
*.cer
*.lib
*.sbr
*.sdf
*.opensdf
*.unsuccessfulbuild
*.lastbuildstate
ipch/
obj/
cmake/
[Bb]in
[Dd]ebug*/
[Rr]elease*/
Ankh.NoLoad
#MonoDevelop
*.pidb
*.userprefs
#Tooling
_ReSharper*/
*.resharper
[Tt]est[Rr]esult*
*.sass-cache
#Project files
[Bb]uild/
obj/
#Subversion files
.svn
# Office Temp Files
~$*
#NuGet
packages/
#ncrunch
*ncrunch*
*crunch*.local.xml
# visual studio database projects
*.dbmdl
#Test files
*.testsettings
#Generated libraries
*.dll
*.bin
*.sys
#and files
GeneratedFiles*/
*.ggpk
*.idb
*.opendb
*.db
*.sqlite
/.vs
*.db-shm
*.db-wal
*.json

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.15
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlackBone", "src\BlackBone\BlackBone.vcxproj", "{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Samples", "src\Samples\Samples.vcxproj", "{D31B07B5-C75F-4382-B07F-D95922764BD7}"
ProjectSection(ProjectDependencies) = postProject
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB} = {A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlackBoneTest", "src\BlackBoneTest\BlackBoneTest.vcxproj", "{15F6F215-4A5E-4B57-B0A0-90B067111285}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug(DLL)|Win32 = Debug(DLL)|Win32
Debug(DLL)|x64 = Debug(DLL)|x64
Debug(XP)|Win32 = Debug(XP)|Win32
Debug(XP)|x64 = Debug(XP)|x64
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release(DLL)|Win32 = Release(DLL)|Win32
Release(DLL)|x64 = Release(DLL)|x64
Release(XP)|Win32 = Release(XP)|Win32
Release(XP)|x64 = Release(XP)|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Debug(DLL)|Win32.ActiveCfg = Debug(DLL)|Win32
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Debug(DLL)|Win32.Build.0 = Debug(DLL)|Win32
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Debug(DLL)|x64.ActiveCfg = Debug(DLL)|x64
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Debug(DLL)|x64.Build.0 = Debug(DLL)|x64
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Debug(XP)|Win32.ActiveCfg = Debug(XP)|Win32
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Debug(XP)|Win32.Build.0 = Debug(XP)|Win32
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Debug(XP)|x64.ActiveCfg = Debug(XP)|x64
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Debug(XP)|x64.Build.0 = Debug(XP)|x64
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Debug|Win32.ActiveCfg = Debug|Win32
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Debug|Win32.Build.0 = Debug|Win32
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Debug|x64.ActiveCfg = Debug|x64
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Debug|x64.Build.0 = Debug|x64
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Release(DLL)|Win32.ActiveCfg = Release(DLL)|Win32
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Release(DLL)|Win32.Build.0 = Release(DLL)|Win32
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Release(DLL)|x64.ActiveCfg = Release(DLL)|x64
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Release(DLL)|x64.Build.0 = Release(DLL)|x64
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Release(XP)|Win32.ActiveCfg = Release(XP)|Win32
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Release(XP)|Win32.Build.0 = Release(XP)|Win32
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Release(XP)|x64.ActiveCfg = Release(XP)|x64
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Release(XP)|x64.Build.0 = Release(XP)|x64
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Release|Win32.ActiveCfg = Release|Win32
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Release|Win32.Build.0 = Release|Win32
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Release|x64.ActiveCfg = Release|x64
{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Release|x64.Build.0 = Release|x64
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Debug(DLL)|Win32.ActiveCfg = Debug(DLL)|Win32
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Debug(DLL)|Win32.Build.0 = Debug(DLL)|Win32
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Debug(DLL)|x64.ActiveCfg = Debug(DLL)|x64
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Debug(DLL)|x64.Build.0 = Debug(DLL)|x64
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Debug(XP)|Win32.ActiveCfg = Debug(XP)|Win32
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Debug(XP)|Win32.Build.0 = Debug(XP)|Win32
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Debug(XP)|x64.ActiveCfg = Debug(XP)|x64
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Debug(XP)|x64.Build.0 = Debug(XP)|x64
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Debug|Win32.ActiveCfg = Debug|Win32
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Debug|Win32.Build.0 = Debug|Win32
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Debug|Win32.Deploy.0 = Debug|Win32
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Debug|x64.ActiveCfg = Debug|x64
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Debug|x64.Build.0 = Debug|x64
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Debug|x64.Deploy.0 = Debug|x64
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Release(DLL)|Win32.ActiveCfg = Release(DLL)|Win32
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Release(DLL)|Win32.Build.0 = Release(DLL)|Win32
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Release(DLL)|Win32.Deploy.0 = Release(DLL)|Win32
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Release(DLL)|x64.ActiveCfg = Release(DLL)|x64
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Release(DLL)|x64.Build.0 = Release(DLL)|x64
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Release(XP)|Win32.ActiveCfg = Release(XP)|Win32
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Release(XP)|Win32.Build.0 = Release(XP)|Win32
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Release(XP)|x64.ActiveCfg = Release(XP)|x64
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Release(XP)|x64.Build.0 = Release(XP)|x64
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Release|Win32.ActiveCfg = Release|Win32
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Release|Win32.Build.0 = Release|Win32
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Release|Win32.Deploy.0 = Release|Win32
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Release|x64.ActiveCfg = Release|x64
{D31B07B5-C75F-4382-B07F-D95922764BD7}.Release|x64.Build.0 = Release|x64
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Debug(DLL)|Win32.ActiveCfg = Debug(DLL)|Win32
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Debug(DLL)|Win32.Build.0 = Debug(DLL)|Win32
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Debug(DLL)|x64.ActiveCfg = Debug(DLL)|x64
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Debug(DLL)|x64.Build.0 = Debug(DLL)|x64
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Debug(XP)|Win32.ActiveCfg = Debug|Win32
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Debug(XP)|Win32.Build.0 = Debug|Win32
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Debug(XP)|x64.ActiveCfg = Debug|x64
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Debug(XP)|x64.Build.0 = Debug|x64
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Debug|Win32.ActiveCfg = Debug|Win32
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Debug|Win32.Build.0 = Debug|Win32
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Debug|x64.ActiveCfg = Debug|x64
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Debug|x64.Build.0 = Debug|x64
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Release(DLL)|Win32.ActiveCfg = Release(DLL)|Win32
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Release(DLL)|Win32.Build.0 = Release(DLL)|Win32
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Release(DLL)|x64.ActiveCfg = Release(DLL)|x64
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Release(DLL)|x64.Build.0 = Release(DLL)|x64
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Release(XP)|Win32.ActiveCfg = Release|Win32
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Release(XP)|Win32.Build.0 = Release|Win32
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Release(XP)|x64.ActiveCfg = Release|x64
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Release(XP)|x64.Build.0 = Release|x64
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Release|Win32.ActiveCfg = Release|Win32
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Release|Win32.Build.0 = Release|Win32
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Release|x64.ActiveCfg = Release|x64
{15F6F215-4A5E-4B57-B0A0-90B067111285}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FA23DB8B-7FAB-4586-936D-4ADB4CD8B90E}
EndGlobalSection
EndGlobal
The MIT License (MIT)
Copyright (c) 2015 DarthTon
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# Blackbone
### Windows memory hacking library
## Features
- **x86 and x64 support**
**Process interaction**
- Manage PEB32/PEB64
- Manage process through WOW64 barrier
**Process Memory**
- Allocate and free virtual memory
- Change memory protection
- Read/Write virtual memory
**Process modules**
- Enumerate all (32/64 bit) modules loaded. Enumerate modules using Loader list/Section objects/PE headers methods.
- Get exported function address
- Get the main module
- Unlink module from loader lists
- Inject and eject modules (including pure IL images)
- Inject 64bit modules into WOW64 processes
- Manually map native PE images
**Threads**
- Enumerate threads
- Create and terminate threads. Support for cross-session thread creation.
- Get thread exit code
- Get main thread
- Manage TEB32/TEB64
- Join threads
- Suspend and resume threads
- Set/Remove hardware breakpoints
**Pattern search**
- Search for arbitrary pattern in local or remote process
**Remote code execution**
- Execute functions in remote process
- Assemble own code and execute it remotely
- Support for cdecl/stdcall/thiscall/fastcall conventions
- Support for arguments passed by value, pointer or reference, including structures
- FPU types are supported
- Execute code in new thread or any existing one
**Remote hooking**
- Hook functions in remote process using int3 or hardware breakpoints
- Hook functions upon return
**Manual map features**
- x86 and x64 image support
- Mapping into any arbitrary unprotected process
- Section mapping with proper memory protection flags
- Image relocations (only 2 types supported. I haven't seen a single PE image with some other relocation types)
- Imports and Delayed imports are resolved
- Bound import is resolved as a side effect, I think
- Module exports
- Loading of forwarded export images
- Api schema name redirection
- SxS redirection and isolation
- Activation context support
- Dll path resolving similar to native load order
- TLS callbacks. Only for one thread and only with PROCESS_ATTACH/PROCESS_DETACH reasons.
- Static TLS
- Exception handling support (SEH and C++)
- Adding module to some native loader structures(for basic module api support: GetModuleHandle, GetProcAdress, etc.)
- Security cookie initialization
- C++/CLI images are supported
- Image unloading
- Increase reference counter for import libraries in case of manual import mapping
- Cyclic dependencies are handled properly
**Driver features**
- Allocate/free/protect user memory
- Read/write user and kernel memory
- Disable permanent DEP for WOW64 processes
- Change process protection flag
- Change handle access rights
- Remap process memory
- Hiding allocated user-mode memory
- User-mode dll injection and manual mapping
- Manual mapping of drivers
## Requirements
- Visual Studio 2017 15.7 or higher
- Windows SDK 10.0.17134 or higher
- WDK 10.0.17134 or higher (driver only)
- VC++ 2017 Libs for Spectre (x86 and x64)
- Visual C++ ATL (x86/x64) with Spectre Mitigations
## License
Blackbone is licensed under the MIT License. Dependencies are under their respective licenses.
[![Build status](https://ci.appveyor.com/api/projects/status/h3tr97727ngr7jko?svg=true)](https://ci.appveyor.com/project/DarthTon/blackbone)
[![Build status](https://ci.appveyor.com/api/projects/status/5lu9aw84t00ibkdo?svg=true)](https://ci.appveyor.com/project/DarthTon/blackbone-q21rd)
\ No newline at end of file
version: 1.0.{build}
branches:
only:
- master
- testing
image: Visual Studio 2017
clone_folder: c:\projects\blackbone
platform:
- Win32
- x64
configuration:
- Debug
- Debug(DLL)
- Release
- Release(DLL)
build:
parallel: true
project: BlackBone.sln
build_script:
MSBuild.exe BlackBone.sln /p:CI=true /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
test_script:
- ps: vstest.console /logger:Appveyor "build/$env:PLATFORM/$env:CONFIGURATION/BlackboneTest.dll"
skip_commits:
message: /Driver/
\ No newline at end of file
version: 1.0.{build}
branches:
only:
- master
image: Visual Studio 2015
clone_folder: c:\projects\blackboneDrv
platform:
- x64
configuration:
- Win10Debug
- Win10Release
- Win8.1 Debug
- Win8.1 Release
- Win8 Debug
- Win8 Release
- Win7 Debug
- Win7 Release
build:
parallel: true
project: src/BlackBoneDrv/BlackBoneDrv.sln
only_commits:
message: /Driver/
\ No newline at end of file
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
#if !defined(_ASMJIT_BUILD_H)
#include "build.h"
#endif // !_ASMJIT_BUILD_H
// ============================================================================
// [MSVC]
// ============================================================================
#if defined(_MSC_VER)
// Disable some warnings we know about
# 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'
// Rename symbols.
# if !defined(vsnprintf)
# define ASMJIT_DEFINED_VSNPRINTF
# define vsnprintf _vsnprintf
# endif // !vsnprintf
# if !defined(snprintf)
# define ASMJIT_DEFINED_SNPRINTF
# define snprintf _snprintf
# endif // !snprintf
#endif // _MSC_VER
// ============================================================================
// [GNUC]
// ============================================================================
#if defined(__GNUC__) && !defined(__clang__)
# if __GNUC__ >= 4 && !defined(__MINGW32__)
# pragma GCC visibility push(hidden)
# endif // __GNUC__ >= 4
#endif // __GNUC__
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// ============================================================================
// [MSVC]
// ============================================================================
#if defined(_MSC_VER)
// Pop disabled warnings by ApiBegin.h
# pragma warning(pop)
// Rename symbols back.
# if defined(ASMJIT_DEFINED_VSNPRINTF)
# undef ASMJIT_DEFINED_VSNPRINTF
# undef vsnprintf
# endif // ASMJIT_DEFINED_VSNPRINTF
# if defined(ASMJIT_DEFINED_SNPRINTF)
# undef ASMJIT_DEFINED_SNPRINTF
# undef snprintf
# endif // ASMJIT_DEFINED_SNPRINTF
#endif // _MSC_VER
// ============================================================================
// [GNUC]
// ============================================================================
#if defined(__GNUC__) && !defined(__clang__)
# if __GNUC__ >= 4 && !defined(__MINGW32__)
# pragma GCC visibility pop
# endif // __GNUC__ >= 4
#endif // __GNUC__
// [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++.
//!
//! AsmJit is a complete JIT and remote assembler for C++ language. It can
//! generate native code for x86 and x64 architectures having support for
//! a full instruction set, from legacy MMX to the newest AVX2. It has a
//! type-safe API that allows C++ compiler to do a semantic checks at
//! compile-time even before the assembled code is generated or run.
//!
//! AsmJit is not a virtual machine (VM). It doesn't have functionality to
//! implement VM out of the box; however, it can be be used as a JIT backend
//! for your own VM. The usage of AsmJit is not limited at all; it's suitable
//! for multimedia, VM backends or remote code generation.
//!
//! @section AsmJit_Concepts Code Generation Concepts
//!
//! AsmJit has two completely different code generation concepts. The difference
//! is in how the code is generated. The first concept, also referred as the low
//! level concept, is called 'Assembler' and it's the same as writing RAW
//! assembly by using physical registers directly. In this case AsmJit does only
//! instruction encoding, verification and relocation.
//!
//! The second concept, also referred as the high level concept, is called
//! 'Compiler'. Compiler lets you use virtually unlimited number of registers
//! (called variables) significantly simplifying the code generation process.
//! Compiler allocates these virtual registers to physical registers after the
//! code generation is done. This requires some extra effort - Compiler has to
//! generate information for each node (instruction, function declaration,
//! function call) in the code, perform a variable liveness analysis and
//! translate the code having variables into code having only registers.
//!
//! In addition, Compiler understands functions and function calling conventions.
//! It has been designed in a way that the code generated is always a function
//! having prototype like in a programming language. By having a function
//! prototype the Compiler is able to insert prolog and epilog to a function
//! being generated and it is able to call a function inside a generated one.
//!
//! There is no conclusion on which concept is better. Assembler brings full
//! control on how the code is generated, while Compiler makes the generation
//! more portable.
//!
//! @section AsmJit_Main_CodeGeneration Code Generation
//!
//! - \ref asmjit_base_general "Assembler core" - Operands, intrinsics and low-level assembler.
//! - \ref asmjit_compiler "Compiler" - High level code generation.
//! - \ref asmjit_cpuinfo "Cpu Information" - Get information about host processor.
//! - \ref asmjit_logging "Logging" - Logging and error handling.
//! - \ref AsmJit_MemoryManagement "Memory Management" - Virtual memory management.
//!
//! @section AsmJit_Main_HomePage AsmJit Homepage
//!
//! - https://github.com/kobalicek/asmjit
// ============================================================================
// [asmjit_base]
// ============================================================================
//! \defgroup asmjit_base AsmJit
//!
//! \brief AsmJit.
// ============================================================================
// [asmjit_base_general]
// ============================================================================
//! \defgroup asmjit_base_general AsmJit General API
//! \ingroup asmjit_base
//!
//! \brief AsmJit general API.
//!
//! Contains all `asmjit` classes and helper functions that are architecture
//! independent or abstract. Abstract classes are implemented by the backend,
//! for example `Assembler` is implemented by `X86Assembler`.
//!
//! - See `Assembler` for low level code generation documentation.
//! - See `Compiler` for high level code generation documentation.
//! - See `Operand` for operand's overview.
//!
//! Logging and Error Handling
//! --------------------------
//!
//! AsmJit contains robust interface that can be used to log the generated code
//! and to handle possible errors. Base logging interface is defined in `Logger`
//! class that is abstract and can be overridden. AsmJit contains two loggers
//! that can be used out of the box - `FileLogger` that logs into a pure C
//! `FILE*` stream and `StringLogger` that just concatenates all log messages
//! by using a `StringBuilder` class.
//!
//! The following snippet shows how to setup a logger that logs to `stderr`:
//!
//! ~~~
//! // `FileLogger` instance.
//! FileLogger logger(stderr);
//!
//! // `Compiler` or any other `CodeGen` interface.
//! host::Compiler c;
//!
//! // use `setLogger` to replace the `CodeGen` logger.
//! c.setLogger(&logger);
//! ~~~
//!
//! \sa \ref Logger, \ref FileLogger, \ref StringLogger.
// ============================================================================
// [asmjit_base_compiler]
// ============================================================================
//! \defgroup asmjit_base_compiler AsmJit Compiler
//! \ingroup asmjit_base
//!
//! \brief AsmJit code-tree used by Compiler.
//!
//! AsmJit intermediate code-tree is a double-linked list that is made of nodes
//! that represent assembler instructions, directives, labels and high-level
//! constructs compiler is using to represent functions and function calls. The
//! node list can only be used together with \ref Compiler.
//!
//! TODO
// ============================================================================
// [asmjit_base_util]
// ============================================================================
//! \defgroup asmjit_base_util AsmJit Utilities
//! \ingroup asmjit_base
//!
//! \brief AsmJit utility classes.
//!
//! AsmJit contains numerous utility classes that are needed by the library
//! itself. The most useful ones have been made public and are now exported.
//!
//! POD Containers
//! --------------
//!
//! POD containers are used by AsmJit to manage its own data structures. The
//! following classes can be used by AsmJit consumers:
//!
//! - \ref PodVector - Simple growing array-like container for POD data.
//! - \ref StringBuilder - Simple string builder that can append string
//! and integers.
//!
//! Zone Memory Allocator
//! ---------------------
//!
//! Zone memory allocator is an incremental memory allocator that can be used
//! to allocate data of short life-time. It has much better performance
//! characteristics than all other allocators, because the only thing it can do
//! is to increment a pointer and return its previous address. See \ref Zone
//! for more details.
//!
//! CPU Ticks
//! ---------
//!
//! CPU Ticks is a simple helper that can be used to do basic benchmarks. See
//! \ref CpuTicks class for more details.
//!
//! Integer Utilities
//! -----------------
//!
//! Integer utilities are all implemented by a static class \ref IntUtil.
//! There are utilities for bit manipulation and bit counting, utilities to get
//! an integer minimum / maximum and various other helpers required to perform
//! alignment checks and binary casting from float to integer and vica versa.
//!
//! Vector Utilities
//! ----------------
//!
//! SIMD code generation often requires to embed constants after each function
//! or a block of functions generated. AsmJit contains classes `Vec64`,
//! `Vec128` and `Vec256` that can be used to prepare data useful when
//! generating SIMD code.
//!
//! X86/X64 code generator contains member functions `dmm`, `dxmm` and `dymm`
//! which can be used to embed 64-bit, 128-bit and 256-bit data structures into
//! machine code (both assembler and compiler are supported).
//!
//! \note Compiler contains a constant pool, which should be used instead of
//! embedding constants manually after the function body.
// ============================================================================
// [asmjit_x86]
// ============================================================================
//! \defgroup asmjit_x86 X86/X64
//!
//! \brief X86/X64 module
// ============================================================================
// [asmjit_x86_general]
// ============================================================================
//! \defgroup asmjit_x86_general X86/X64 General API
//! \ingroup asmjit_x86
//!
//! \brief X86/X64 general API.
//!
//! X86/X64 Registers
//! -----------------
//!
//! There are static objects that represents X86 and X64 registers. They can
//! be used directly (like `eax`, `mm`, `xmm`, ...) or created through
//! these functions:
//!
//! - `asmjit::gpb_lo()` - Get Gpb-lo register.
//! - `asmjit::gpb_hi()` - Get Gpb-hi register.
//! - `asmjit::gpw()` - Get Gpw register.
//! - `asmjit::gpd()` - Get Gpd register.
//! - `asmjit::gpq()` - Get Gpq Gp register.
//! - `asmjit::gpz()` - Get Gpd/Gpq register.
//! - `asmjit::fp()` - Get Fp register.
//! - `asmjit::mm()` - Get Mm register.
//! - `asmjit::xmm()` - Get Xmm register.
//! - `asmjit::ymm()` - Get Ymm register.
//!
//! X86/X64 Addressing
//! ------------------
//!
//! X86 and x64 architectures contains several addressing modes and most ones
//! are possible with AsmJit library. Memory represents are represented by
//! `BaseMem` class. These functions are used to make operands that represents
//! memory addresses:
//!
//! - `asmjit::ptr()` - Address size not specified.
//! - `asmjit::byte_ptr()` - 1 byte.
//! - `asmjit::word_ptr()` - 2 bytes (Gpw size).
//! - `asmjit::dword_ptr()` - 4 bytes (Gpd size).
//! - `asmjit::qword_ptr()` - 8 bytes (Gpq/Mm size).
//! - `asmjit::tword_ptr()` - 10 bytes (FPU).
//! - `asmjit::oword_ptr()` - 16 bytes (Xmm size).
//! - `asmjit::yword_ptr()` - 32 bytes (Ymm size).
//! - `asmjit::zword_ptr()` - 64 bytes (Zmm size).
//!
//! Most useful function to make pointer should be `asmjit::ptr()`. It creates
//! pointer to the target with unspecified size. Unspecified size works in all
//! intrinsics where are used registers (this means that size is specified by
//! register operand or by instruction itself). For example `asmjit::ptr()`
//! can't be used with `Assembler::inc()` instruction. In this case size must
//! be specified and it's also reason to make difference between pointer sizes.
//!
//! Supported are simple address forms `[base + displacement]` and complex
//! address forms `[base + index * scale + displacement]`.
//!
//! X86/X64 Immediates
//! ------------------
//!
//! Immediate values are constants thats passed directly after instruction
//! opcode. To create such value use `imm()` or `imm_u()` methods to create
//! signed or unsigned immediate value.
//!
//! X86/X64 CPU Information
//! -----------------------
//!
//! The CPUID instruction can be used to get an exhaustive information about
//! the host X86/X64 processor. AsmJit contains utilities that can get the most
//! important information related to the features supported by the CPU and the
//! host operating system, in addition to host processor name and number of
//! cores. Class `X86CpuInfo` extends `CpuInfo` and provides functionality
//! specific to X86 and X64.
//!
//! By default AsmJit queries the CPU information after the library is loaded
//! and the queried information is reused by all instances of `JitRuntime`.
//! The global instance of `X86CpuInfo` can't be changed, because it will affect
//! the code generation of all `Runtime`s. If there is a need to have a
//! specific CPU information which contains modified features or processor
//! vendor it's possible by creating a new instance of `X86CpuInfo` and setting
//! up its members. `X86CpuUtil::detect` can be used to detect CPU features into
//! an existing `X86CpuInfo` instance - it may become handly if only one property
//! has to be turned on/off.
//!
//! If the high-level interface `X86CpuInfo` offers is not enough there is also
//! `X86CpuUtil::callCpuId` helper that can be used to call CPUID instruction
//! with a given parameters and to consume the output.
//!
//! Cpu detection is important when generating a JIT code that may or may not
//! use certain CPU features. For example there used to be a SSE/SSE2 detection
//! in the past and today there is often AVX/AVX2 detection.
//!
//! The example below shows how to detect SSE2:
//!
//! ~~~
//! using namespace asmjit;
//!
//! // Get `X86CpuInfo` global instance.
//! const X86CpuInfo* cpuInfo = X86CpuInfo::getHost();
//!
//! if (cpuInfo->hasFeature(kX86CpuFeatureSSE2)) {
//! // Processor has SSE2.
//! }
//! else if (cpuInfo->hasFeature(kX86CpuFeatureMMX)) {
//! // Processor doesn't have SSE2, but has MMX.
//! }
//! else {
//! // Processor is archaic; it's a wonder AsmJit works here!
//! }
//! ~~~
//!
//! The next example shows how to call `CPUID` directly:
//!
//! ~~~
//! using namespace asmjit;
//!
//! // Call cpuid, first two arguments are passed in Eax/Ecx.
//! X86CpuId out;
//! X86CpuUtil::callCpuId(0, 0, &out);
//!
//! // If Eax argument is 0, Ebx, Ecx and Edx registers are filled with a cpu vendor.
//! char cpuVendor[13];
//! ::memcpy(cpuVendor, &out.ebx, 4);
//! ::memcpy(cpuVendor + 4, &out.edx, 4);
//! ::memcpy(cpuVendor + 8, &out.ecx, 4);
//! vendor[12] = '\0';
//!
//! // Print a CPU vendor retrieved from CPUID.
//! ::printf("%s", cpuVendor);
//! ~~~
// ============================================================================
// [asmjit_x86_compiler]
// ============================================================================
//! \defgroup asmjit_x86_compiler X86/X64 Code-Tree
//! \ingroup asmjit_x86
//!
//! \brief X86/X64 code-tree and helpers.
// ============================================================================
// [asmjit_x86_inst]
// ============================================================================
//! \defgroup asmjit_x86_inst X86/X64 Instructions
//! \ingroup asmjit_x86
//!
//! \brief X86/X64 low-level instruction definitions.
// ============================================================================
// [asmjit_x86_util]
// ============================================================================
//! \defgroup asmjit_x86_util X86/X64 Utilities
//! \ingroup asmjit_x86
//!
//! \brief X86/X64 utility classes.
// ============================================================================
// [asmjit_contrib]
// ============================================================================
//! \defgroup asmjit_contrib Contributions
//!
//! \brief Contributions.
// [Dependencies - Base]
#include "base.h"
// [Dependencies - X86/X64]
#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)
#include "x86.h"
#endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64
// [Dependencies - Host]
#include "host.h"
// [Guard]
#endif // _ASMJIT_ASMJIT_H
// [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
// [Include]
#if defined(ASMJIT_CONFIG_FILE)
# include ASMJIT_CONFIG_FILE
#else
# include "./config.h"
#endif // ASMJIT_CONFIG_FILE
// Turn off deprecation warnings when compiling AsmJit.
#if defined(ASMJIT_EXPORTS) && defined(_MSC_VER)
# if !defined(_CRT_SECURE_NO_DEPRECATE)
# define _CRT_SECURE_NO_DEPRECATE
# endif // !_CRT_SECURE_NO_DEPRECATE
# if !defined(_CRT_SECURE_NO_WARNINGS)
# define _CRT_SECURE_NO_WARNINGS
# endif // !_CRT_SECURE_NO_WARNINGS
#endif // ASMJIT_EXPORTS
// [Dependencies - C]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// [Dependencies - C++]
#include <new>
// ============================================================================
// [asmjit::build - Sanity]
// ============================================================================
#if defined(ASMJIT_DISABLE_NAMES) && !defined(ASMJIT_DISABLE_LOGGER)
# error "ASMJIT_DISABLE_NAMES requires ASMJIT_DISABLE_LOGGER to be defined."
#endif // ASMJIT_DISABLE_NAMES && !ASMJIT_DISABLE_LOGGER
// ============================================================================
// [asmjit::build - OS]
// ============================================================================
#if defined(_WINDOWS) || defined(__WINDOWS__) || defined(_WIN32) || defined(_WIN64)
# define ASMJIT_OS_WINDOWS
#elif defined(__linux) || defined(__linux__)
# define ASMJIT_OS_POSIX
# define ASMJIT_OS_LINUX
#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
# define ASMJIT_OS_POSIX
# define ASMJIT_OS_BSD
#elif defined(__APPLE__)
# define ASMJIT_OS_POSIX
# define ASMJIT_OS_MAC
#else
# warning "AsmJit - Unable to detect host operating system, using ASMJIT_OS_POSIX"
# define ASMJIT_OS_POSIX
#endif
// ============================================================================
// [asmjit::build - Arch]
// ============================================================================
#if defined(_M_X64 ) || \
defined(_M_AMD64 ) || \
defined(_WIN64 ) || \
defined(__amd64__ ) || \
defined(__LP64 ) || \
defined(__x86_64__)
# define ASMJIT_HOST_X64
# define ASMJIT_HOST_LE
# define ASMJIT_HOST_UNALIGNED_16
# define ASMJIT_HOST_UNALIGNED_32
# define ASMJIT_HOST_UNALIGNED_64
#elif \
defined(_M_IX86 ) || \
defined(__INTEL__) || \
defined(__i386__ )
# define ASMJIT_HOST_X86
# define ASMJIT_HOST_LE
# define ASMJIT_HOST_UNALIGNED_16
# define ASMJIT_HOST_UNALIGNED_32
# define ASMJIT_HOST_UNALIGNED_64
#elif \
defined(_ARM ) || \
defined(_M_ARM_FP ) || \
defined(__ARM_NEON__ ) || \
defined(__arm ) || \
defined(__arm__ ) || \
defined(__TARGET_ARCH_ARM ) || \
defined(__TARGET_ARCH_THUMB) || \
defined(__thumb__ )
# define ASMJIT_HOST_ARM
# define ASMJIT_HOST_LE
#else
# warning "AsmJit - Unable to detect host architecture"
#endif
// ============================================================================
// [asmjit::build - Build]
// ============================================================================
// Build host architecture if no architecture is selected.
#if !defined(ASMJIT_BUILD_HOST) && \
!defined(ASMJIT_BUILD_X86) && \
!defined(ASMJIT_BUILD_X64)
# define ASMJIT_BUILD_HOST
#endif
// Autodetect host architecture if enabled.
#if defined(ASMJIT_BUILD_HOST)
# if defined(ASMJIT_HOST_X86) && !defined(ASMJIT_BUILD_X86)
# define ASMJIT_BUILD_X86
# endif // ASMJIT_HOST_X86 && !ASMJIT_BUILD_X86
# if defined(ASMJIT_HOST_X64) && !defined(ASMJIT_BUILD_X64)
# define ASMJIT_BUILD_X64
# endif // ASMJIT_HOST_X64 && !ASMJIT_BUILD_X64
#endif // ASMJIT_BUILD_HOST
// ============================================================================
// [asmjit::build - Decorators]
// ============================================================================
#if defined(ASMJIT_EMBED) && !defined(ASMJIT_STATIC)
# define ASMJIT_STATIC
#endif // ASMJIT_EMBED && !ASMJIT_STATIC
#if defined(ASMJIT_STATIC)
# define ASMJIT_API
#elif defined(ASMJIT_OS_WINDOWS)
# if (defined(__GNUC__) || defined(__clang__)) && !defined(__MINGW32__)
# if defined(ASMJIT_EXPORTS)
# define ASMJIT_API __attribute__((dllexport))
# else
# define ASMJIT_API __attribute__((dllimport))
# endif // ASMJIT_EXPORTS
# else
# if defined(ASMJIT_EXPORTS)
# define ASMJIT_API __declspec(dllexport)
# else
# define ASMJIT_API __declspec(dllimport)
# endif
# endif
#elif defined(__GNUC__) && (__GNUC__ >= 4)
# define ASMJIT_API __attribute__((visibility("default")))
#endif
#if !defined(ASMJIT_API)
# define ASMJIT_API
#endif // ASMJIT_API
// This is basically a workaround. When using MSVC and marking class as DLL
// export everything is exported, which is unwanted since there are many
// inlines which mimic instructions. MSVC automatically exports typeinfo and
// vtable if at least one symbol of that 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 marked as "visibility(default)".
#if !defined(ASMJIT_OS_WINDOWS) && (defined(__GNUC__) || defined (__clang__))
# define ASMJIT_VCLASS ASMJIT_API
#else
# define ASMJIT_VCLASS
#endif
#if !defined(ASMJIT_VAR)
# define ASMJIT_VAR extern ASMJIT_API
#endif // !ASMJIT_VAR
#if defined(_MSC_VER)
# define ASMJIT_INLINE __forceinline
#elif defined(__clang__)
# define ASMJIT_INLINE inline __attribute__((always_inline)) __attribute__((visibility("hidden")))
#elif defined(__GNUC__)
# define ASMJIT_INLINE inline __attribute__((always_inline))
#else
# define ASMJIT_INLINE inline
#endif
#if defined(ASMJIT_HOST_X86)
# if defined(__GNUC__) || defined(__clang__)
# define ASMJIT_REGPARM_1 __attribute__((regparm(1)))
# define ASMJIT_REGPARM_2 __attribute__((regparm(2)))
# define ASMJIT_REGPARM_3 __attribute__((regparm(3)))
# define ASMJIT_FASTCALL __attribute__((fastcall))
# define ASMJIT_STDCALL __attribute__((stdcall))
# define ASMJIT_CDECL __attribute__((cdecl))
# else
# define ASMJIT_FASTCALL __fastcall
# define ASMJIT_STDCALL __stdcall
# define ASMJIT_CDECL __cdecl
# endif
#else
# define ASMJIT_FASTCALL
# define ASMJIT_STDCALL
# define ASMJIT_CDECL
#endif // ASMJIT_HOST_X86
// ============================================================================
// [asmjit::build - Enum]
// ============================================================================
#if defined(_MSC_VER)
# define ASMJIT_ENUM(_Name_) enum _Name_ : uint32_t
#else
# define ASMJIT_ENUM(_Name_) enum _Name_
#endif
// ============================================================================
// [asmjit::build - Memory Management]
// ============================================================================
#if !defined(ASMJIT_ALLOC) && !defined(ASMJIT_REALLOC) && !defined(ASMJIT_FREE)
# define ASMJIT_ALLOC(_Size_) ::malloc(_Size_)
# define ASMJIT_REALLOC(_Ptr_, _Size_) ::realloc(_Ptr_, _Size_)
# define ASMJIT_FREE(_Ptr_) ::free(_Ptr_)
#else
# if !defined(ASMJIT_ALLOC) || !defined(ASMJIT_REALLOC) || !defined(ASMJIT_FREE)
# error "AsmJit - You must redefine ASMJIT_ALLOC, ASMJIT_REALLOC and ASMJIT_FREE."
# endif
#endif // !ASMJIT_ALLOC && !ASMJIT_REALLOC && !ASMJIT_FREE
// ============================================================================
// [asmjit::build - _ASMJIT_HOST_INDEX]
// ============================================================================
#if defined(ASMJIT_HOST_LE)
# define _ASMJIT_HOST_INDEX(_Total_, _Index_) (_Index_)
#else
# define _ASMJIT_HOST_INDEX(_Total_, _Index_) ((_Total_) - 1 - (_Index_))
#endif
// ============================================================================
// [asmjit::build - BLEND_OFFSET_OF]
// ============================================================================
//! Cross-platform solution to get offset of `_Field_` in `_Struct_`.
#define ASMJIT_OFFSET_OF(_Struct_, _Field_) \
static_cast<int>((intptr_t) ((const uint8_t*) &((const _Struct_*)0x1)->_Field_) - 1)
// ============================================================================
// [asmjit::build - ASMJIT_ARRAY_SIZE]
// ============================================================================
#define ASMJIT_ARRAY_SIZE(_Array_) \
(sizeof(_Array_) / sizeof(*_Array_))
// ============================================================================
// [asmjit::build - ASMJIT_DEBUG / ASMJIT_TRACE]
// ============================================================================
// If ASMJIT_DEBUG and ASMJIT_RELEASE is not defined ASMJIT_DEBUG will be
// detected using the compiler specific macros. This enables to set the build
// type using IDE.
#if !defined(ASMJIT_DEBUG) && !defined(ASMJIT_RELEASE)
# if defined(_DEBUG)
# define ASMJIT_DEBUG
# endif // _DEBUG
#endif // !ASMJIT_DEBUG && !ASMJIT_RELEASE
// ASMJIT_TRACE is only used by sources and private headers. It's safe to make
// it unavailable outside of AsmJit.
#if defined(ASMJIT_EXPORTS)
namespace asmjit { static inline int disabledTrace(...) { return 0; } }
# if defined(ASMJIT_TRACE)
# define ASMJIT_TSEC(_Section_) _Section_
# define ASMJIT_TLOG ::printf(__VA_ARGS__)
# else
# define ASMJIT_TSEC(_Section_) do {} while(0)
# define ASMJIT_TLOG 0 && ::asmjit::disabledTrace
# endif // ASMJIT_TRACE
#endif // ASMJIT_EXPORTS
// ============================================================================
// [asmjit::build - ASMJIT_UNUSED]
// ============================================================================
#if !defined(ASMJIT_UNUSED)
# define ASMJIT_UNUSED(_Var_) ((void)_Var_)
#endif // ASMJIT_UNUSED
// ============================================================================
// [asmjit::build - ASMJIT_NOP]
// ============================================================================
#if !defined(ASMJIT_NOP)
# define ASMJIT_NOP() ((void)0)
#endif // ASMJIT_NOP
// ============================================================================
// [asmjit::build - ASMJIT_NO_COPY]
// ============================================================================
#define ASMJIT_NO_COPY(_Type_) \
private: \
ASMJIT_INLINE _Type_(const _Type_& other); \
ASMJIT_INLINE _Type_& operator=(const _Type_& other); \
public:
// ============================================================================
// [asmjit::build - StdInt]
// ============================================================================
#if defined(__MINGW32__)
# include <sys/types.h>
#endif // __MINGW32__
#if defined(_MSC_VER) && (_MSC_VER < 1600)
# if !defined(ASMJIT_SUPRESS_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 signed __int8 int8_t;
typedef signed __int16 int16_t;
typedef signed __int32 int32_t;
typedef signed __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
# endif // _MSC_VER
# endif // ASMJIT_SUPRESS_STD_TYPES
#else
# include <stdint.h>
# include <limits.h>
#endif
#if defined(_MSC_VER)
# define ASMJIT_INT64_C(_Num_) _Num_##i64
# define ASMJIT_UINT64_C(_Num_) _Num_##ui64
#else
# define ASMJIT_INT64_C(_Num_) _Num_##LL
# define ASMJIT_UINT64_C(_Num_) _Num_##ULL
#endif
// ============================================================================
// [asmjit::build - Windows]
// ============================================================================
#if defined(ASMJIT_OS_WINDOWS) && !defined(ASMJIT_SUPRESS_WINDOWS_H)
# if !defined(WIN32_LEAN_AND_MEAN)
# define WIN32_LEAN_AND_MEAN
# define ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN
# endif // !WIN32_LEAN_AND_MEAN
# if !defined(NOMINMAX)
# define NOMINMAX
# define ASMJIT_UNDEF_NOMINMAX
# endif // !NOMINMAX
# include <windows.h>
# 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 // ASMJIT_OS_WINDOWS && !ASMJIT_SUPRESS_WINDOWS_H
// ============================================================================
// [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
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_CONFIG_H
#define _ASMJIT_CONFIG_H
// This file can be used to modify built-in features of AsmJit. AsmJit is by
// default compiled only for host processor to enable JIT compilation. Both
// Assembler and Compiler code generators are compiled by default.
//
// ASMJIT_BUILD_... flags can be defined to build additional backends that can
// be used for remote code generation.
//
// ASMJIT_DISABLE_... 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 Compiler).
#ifdef _DEBUG
#define ASMJIT_DEBUG // Define to enable debug-mode.
#else
#define ASMJIT_RELEASE // Define to enable release-mode.
#endif
// ============================================================================
// [AsmJit - Build-Type]
// ============================================================================
#ifdef BLACKBONE_STATIC
#define ASMJIT_STATIC
#elif BLACKBONE_EXPORTS
#define ASMJIT_EXPORTS
#endif
// #define ASMJIT_EMBED // Asmjit is embedded (implies ASMJIT_STATIC).
// #define ASMJIT_STATIC // Define to enable static-library build.
// ============================================================================
// [AsmJit - Build-Mode]
// ============================================================================
// #define ASMJIT_DEBUG // Define to enable debug-mode.
// #define ASMJIT_RELEASE // Define to enable release-mode.
// #define ASMJIT_TRACE // Define to enable tracing.
// ============================================================================
// [AsmJit - Features]
// ============================================================================
// If none of these is defined AsmJit will select host architecture by default.
#define ASMJIT_BUILD_X86 // Define to enable x86 instruction set (32-bit).
#define ASMJIT_BUILD_X64 // Define to enable x64 instruction set (64-bit).
// #define ASMJIT_BUILD_HOST // Define to enable host instruction set.
// AsmJit features are enabled by default.
#define ASMJIT_DISABLE_COMPILER // Disable Compiler (completely).
#define ASMJIT_DISABLE_LOGGER // Disable Logger (completely).
#define ASMJIT_DISABLE_NAMES // Disable everything that uses strings
// (instruction names, error names, ...).
// [Guard]
#endif // _ASMJIT_CONFIG_H
AsmJit - Complete x86/x64 JIT and Remote Assembler for C++
Copyright (c) 2008-2014, Petr Kobalicek <kobalicek.petr@gmail.com>
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.
此差异已折叠。
// [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 - AsmJit]
#include "build.h"
#include "base/assembler.h"
#include "base/codegen.h"
#include "base/compiler.h"
#include "base/constpool.h"
#include "base/containers.h"
#include "base/cpuinfo.h"
#include "base/cputicks.h"
#include "base/error.h"
#include "base/globals.h"
#include "base/intutil.h"
#include "base/lock.h"
#include "base/logger.h"
#include "base/operand.h"
#include "base/runtime.h"
#include "base/string.h"
#include "base/vectypes.h"
#include "base/vmem.h"
#include "base/zone.h"
// [Guard]
#endif // _ASMJIT_BASE_H
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/assembler.h"
#include "../base/intutil.h"
#include "../base/vmem.h"
// [Dependenceis - C]
#include <stdarg.h>
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::Assembler - Construction / Destruction]
// ============================================================================
Assembler::Assembler(Runtime* runtime) :
CodeGen(runtime),
_buffer(NULL),
_end(NULL),
_cursor(NULL),
_trampolineSize(0),
_comment(NULL),
_unusedLinks(NULL) {}
Assembler::~Assembler() {
reset(true);
}
// ============================================================================
// [asmjit::Assembler - Clear / Reset]
// ============================================================================
void Assembler::reset(bool releaseMemory) {
// CodeGen members.
_baseAddress = kNoBaseAddress;
_instOptions = 0;
_error = kErrorOk;
_baseZone.reset(releaseMemory);
// Assembler members.
if (releaseMemory && _buffer != NULL) {
ASMJIT_FREE(_buffer);
_buffer = NULL;
_end = NULL;
}
_cursor = _buffer;
_trampolineSize = 0;
_comment = NULL;
_unusedLinks = NULL;
_labelList.reset(releaseMemory);
_relocList.reset(releaseMemory);
}
// ============================================================================
// [asmjit::Assembler - Buffer]
// ============================================================================
Error Assembler::_grow(size_t n) {
size_t capacity = getCapacity();
size_t after = getOffset() + n;
// Overflow.
if (n > IntUtil::maxUInt<uintptr_t>() - capacity)
return setError(kErrorNoHeapMemory);
// Grow is called when allocation is needed, so it shouldn't happen, but on
// the other hand it is simple to catch and it's not an error.
if (after <= capacity)
return kErrorOk;
if (capacity < kMemAllocOverhead)
capacity = kMemAllocOverhead;
else
capacity += kMemAllocOverhead;
do {
size_t oldCapacity = capacity;
if (capacity < kMemAllocGrowMax)
capacity *= 2;
else
capacity += kMemAllocGrowMax;
// Overflow.
if (oldCapacity > capacity)
return setError(kErrorNoHeapMemory);
} while (capacity - kMemAllocOverhead < after);
capacity -= kMemAllocOverhead;
return _reserve(capacity);
}
Error Assembler::_reserve(size_t n) {
size_t capacity = getCapacity();
if (n <= capacity)
return kErrorOk;
uint8_t* newBuffer;
if (_buffer == NULL)
newBuffer = static_cast<uint8_t*>(ASMJIT_ALLOC(n));
else
newBuffer = static_cast<uint8_t*>(ASMJIT_REALLOC(_buffer, n));
if (newBuffer == NULL)
return setError(kErrorNoHeapMemory);
size_t offset = getOffset();
_buffer = newBuffer;
_end = _buffer + n;
_cursor = newBuffer + offset;
return kErrorOk;
}
// ============================================================================
// [asmjit::Assembler - Label]
// ============================================================================
Error Assembler::_registerIndexedLabels(size_t index) {
size_t i = _labelList.getLength();
if (index < i)
return kErrorOk;
if (_labelList._grow(index - i) != kErrorOk)
return setError(kErrorNoHeapMemory);
LabelData data;
data.offset = -1;
data.links = NULL;
do {
_labelList.append(data);
} while (++i < index);
return kErrorOk;
}
Error Assembler::_newLabel(Label* dst) {
dst->_label.op = kOperandTypeLabel;
dst->_label.size = 0;
dst->_label.id = OperandUtil::makeLabelId(static_cast<uint32_t>(_labelList.getLength()));
LabelData data;
data.offset = -1;
data.links = NULL;
if (_labelList.append(data) != kErrorOk)
goto _NoMemory;
return kErrorOk;
_NoMemory:
dst->_label.id = kInvalidValue;
return setError(kErrorNoHeapMemory);
}
LabelLink* Assembler::_newLabelLink() {
LabelLink* link = _unusedLinks;
if (link) {
_unusedLinks = link->prev;
}
else {
link = _baseZone.allocT<LabelLink>();
if (link == NULL)
return NULL;
}
link->prev = NULL;
link->offset = 0;
link->displacement = 0;
link->relocId = -1;
return link;
}
Error Assembler::bind(const Label& label) {
// Get label data based on label id.
uint32_t index = label.getId();
LabelData* data = getLabelData(index);
// Label can be bound only once.
if (data->offset != -1)
return setError(kErrorLabelAlreadyBound);
#if !defined(ASMJIT_DISABLE_LOGGER)
if (_logger)
_logger->logFormat(kLoggerStyleLabel, "L%u:\n", index);
#endif // !ASMJIT_DISABLE_LOGGER
Error error = kErrorOk;
size_t pos = getOffset();
LabelLink* link = data->links;
LabelLink* prev = NULL;
while (link) {
intptr_t offset = link->offset;
if (link->relocId != -1) {
// Handle RelocData - We have to update RelocData information instead of
// patching the displacement in LabelData.
_relocList[link->relocId].data += static_cast<Ptr>(pos);
}
else {
// Not using relocId, this means that we are overwriting a real
// displacement in the binary stream.
int32_t patchedValue = static_cast<int32_t>(
static_cast<intptr_t>(pos) - offset + link->displacement);
// Size of the value we are going to patch. Only BYTE/DWORD is allowed.
uint32_t size = getByteAt(offset);
ASMJIT_ASSERT(size == 1 || size == 4);
if (size == 4) {
setInt32At(offset, patchedValue);
}
else {
ASMJIT_ASSERT(size == 1);
if (IntUtil::isInt8(patchedValue))
setByteAt(offset, static_cast<uint8_t>(patchedValue & 0xFF));
else
error = kErrorIllegalDisplacement;
}
}
prev = link->prev;
link = prev;
}
// Chain unused links.
link = data->links;
if (link) {
if (prev == NULL)
prev = link;
prev->prev = _unusedLinks;
_unusedLinks = link;
}
// Set as bound (offset is zero or greater and no links).
data->offset = pos;
data->links = NULL;
if (error != kErrorOk)
return setError(error);
return error;
}
// ============================================================================
// [asmjit::Assembler - Embed]
// ============================================================================
Error Assembler::embed(const void* data, uint32_t size) {
if (getRemainingSpace() < size) {
Error error = _grow(size);
if (error != kErrorOk)
return setError(error);
}
uint8_t* cursor = getCursor();
::memcpy(cursor, data, size);
setCursor(cursor + size);
#if !defined(ASMJIT_DISABLE_LOGGER)
if (_logger)
_logger->logBinary(kLoggerStyleData, data, size);
#endif // !ASMJIT_DISABLE_LOGGER
return kErrorOk;
}
// ============================================================================
// [asmjit::Assembler - Reloc]
// ============================================================================
size_t Assembler::relocCode(void* dst, Ptr baseAddress) const {
if (baseAddress == kNoBaseAddress)
baseAddress = hasBaseAddress() ? getBaseAddress() : static_cast<Ptr>((uintptr_t)dst);
else if (getBaseAddress() != baseAddress)
return 0;
return _relocCode(dst, baseAddress);
}
// ============================================================================
// [asmjit::Assembler - Make]
// ============================================================================
void* Assembler::make() {
// Do nothing on error condition or if no instruction has been emitted.
if (_error != kErrorOk || getCodeSize() == 0)
return NULL;
void* p;
Error error = _runtime->add(&p, this);
if (error != kErrorOk)
setError(error);
return p;
}
// ============================================================================
// [asmjit::Assembler - Emit (Helpers)]
// ============================================================================
#define NA noOperand
Error Assembler::emit(uint32_t code) {
return _emit(code, NA, NA, NA, NA);
}
Error Assembler::emit(uint32_t code, const Operand& o0) {
return _emit(code, o0, NA, NA, NA);
}
Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1) {
return _emit(code, o0, o1, NA, NA);
}
Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2) {
return _emit(code, o0, o1, o2, NA);
}
Error Assembler::emit(uint32_t code, int o0) {
Imm imm(o0);
return _emit(code, imm, NA, NA, NA);
}
Error Assembler::emit(uint32_t code, uint64_t o0) {
Imm imm(o0);
return _emit(code, imm, NA, NA, NA);
}
Error Assembler::emit(uint32_t code, const Operand& o0, int o1) {
Imm imm(o1);
return _emit(code, o0, imm, NA, NA);
}
Error Assembler::emit(uint32_t code, const Operand& o0, uint64_t o1) {
Imm imm(o1);
return _emit(code, o0, imm, NA, NA);
}
Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, int o2) {
Imm imm(o2);
return _emit(code, o0, o1, imm, NA);
}
Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, uint64_t o2) {
Imm imm(o2);
return _emit(code, o0, o1, imm, NA);
}
Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int o3) {
Imm imm(o3);
return _emit(code, o0, o1, o2, imm);
}
Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, uint64_t o3) {
Imm imm(o3);
return _emit(code, o0, o1, o2, imm);
}
#undef NA
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [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 - AsmJit]
#include "../base/codegen.h"
#include "../base/containers.h"
#include "../base/error.h"
#include "../base/logger.h"
#include "../base/operand.h"
#include "../base/runtime.h"
#include "../base/zone.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::kInstId]
// ============================================================================
//! Instruction codes (stub).
ASMJIT_ENUM(kInstId) {
//! No instruction.
kInstIdNone = 0
};
// ============================================================================
// [asmjit::kInstOptions]
// ============================================================================
//! Instruction options (stub).
ASMJIT_ENUM(kInstOptions) {
//! No instruction options.
kInstOptionNone = 0x00000000,
//! Emit short form of the instruction.
//!
//! X86/X64:
//!
//! Short form is mostly related to jmp and jcc instructions, but can be used
//! by other instructions supporting 8-bit or 32-bit immediates. This option
//! can be dangerous if the short jmp/jcc is required, but not encodable due
//! to large displacement, in such case an error happens and the whole
//! assembler/compiler stream is unusable.
kInstOptionShortForm = 0x00000001,
//! Emit long form of the instruction.
//!
//! X86/X64:
//!
//! Long form is mosrlt related to jmp and jcc instructions, but like the
//! `kInstOptionShortForm` option it can be used by other instructions
//! supporting both 8-bit and 32-bit immediates.
kInstOptionLongForm = 0x00000002,
//! Condition is likely to be taken.
kInstOptionTaken = 0x00000004,
//! Condition is unlikely to be taken.
kInstOptionNotTaken = 0x00000008
};
// ============================================================================
// [asmjit::LabelLink]
// ============================================================================
//! \internal
//!
//! Data structure used to link linked-labels.
struct LabelLink {
//! Previous link.
LabelLink* prev;
//! Offset.
intptr_t offset;
//! Inlined displacement.
intptr_t displacement;
//! RelocId if link must be absolute when relocated.
intptr_t relocId;
};
// ============================================================================
// [asmjit::LabelData]
// ============================================================================
//! \internal
//!
//! Label data.
struct LabelData {
//! Label offset.
intptr_t offset;
//! Label links chain.
LabelLink* links;
};
// ============================================================================
// [asmjit::RelocData]
// ============================================================================
//! \internal
//!
//! Code relocation data (relative vs absolute addresses).
//!
//! X86/X64:
//!
//! X86 architecture uses 32-bit absolute addressing model by memory operands,
//! but 64-bit mode uses relative addressing model (RIP + displacement). In
//! code we are always using relative addressing model for referencing labels
//! and embedded data. In 32-bit mode we must patch all references to absolute
//! address before we can call generated function.
struct RelocData {
//! Type of relocation.
uint32_t type;
//! Size of relocation (4 or 8 bytes).
uint32_t size;
//! Offset from code begin address.
Ptr from;
//! Relative displacement from code begin address (not to `offset`) or
//! absolute address.
Ptr data;
};
// ============================================================================
// [asmjit::Assembler]
// ============================================================================
//! Base assembler.
//!
//! This class implements the base interface to an assembler. The architecture
//! specific API is implemented by backends.
//!
//! \sa Compiler.
struct ASMJIT_VCLASS Assembler : public CodeGen {
ASMJIT_NO_COPY(Assembler)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `Assembler` instance.
ASMJIT_API Assembler(Runtime* runtime);
//! Destroy the `Assembler` instance.
ASMJIT_API virtual ~Assembler();
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
//! Reset the assembler.
//!
//! If `releaseMemory` is true all buffers will be released to the system.
ASMJIT_API void reset(bool releaseMemory = false);
// --------------------------------------------------------------------------
// [Buffer]
// --------------------------------------------------------------------------
//! Get capacity of the code buffer.
ASMJIT_INLINE size_t getCapacity() const {
return (size_t)(_end - _buffer);
}
//! Get the number of remaining bytes (space between cursor and the end of
//! the buffer).
ASMJIT_INLINE size_t getRemainingSpace() const {
return (size_t)(_end - _cursor);
}
//! Get buffer.
ASMJIT_INLINE uint8_t* getBuffer() const {
return _buffer;
}
//! Get the end of the buffer (points to the first byte that is outside).
ASMJIT_INLINE uint8_t* getEnd() const {
return _end;
}
//! Get the current position in the buffer.
ASMJIT_INLINE uint8_t* getCursor() const {
return _cursor;
}
//! Set the current position in the buffer.
ASMJIT_INLINE void setCursor(uint8_t* cursor) {
ASMJIT_ASSERT(cursor >= _buffer && cursor <= _end);
_cursor = cursor;
}
//! Get the current offset in the buffer.
ASMJIT_INLINE size_t getOffset() const {
return (size_t)(_cursor - _buffer);
}
//! Set the current offset in the buffer to `offset` and get the previous
//! offset value.
ASMJIT_INLINE size_t setOffset(size_t offset) {
ASMJIT_ASSERT(offset < getCapacity());
size_t oldOffset = (size_t)(_cursor - _buffer);
_cursor = _buffer + offset;
return oldOffset;
}
//! Grow the internal buffer.
//!
//! The internal buffer will grow at least by `n` bytes so `n` bytes can be
//! added to it. If `n` is zero or `getOffset() + n` is not greater than the
//! current capacity of the buffer this function does nothing.
ASMJIT_API Error _grow(size_t n);
//! Reserve the internal buffer to at least `n` bytes.
ASMJIT_API Error _reserve(size_t n);
//! Get BYTE at position `pos`.
ASMJIT_INLINE uint8_t getByteAt(size_t pos) const {
ASMJIT_ASSERT(pos + 1 <= (size_t)(_end - _buffer));
return *reinterpret_cast<const uint8_t*>(_buffer + pos);
}
//! Get WORD at position `pos`.
ASMJIT_INLINE uint16_t getWordAt(size_t pos) const {
ASMJIT_ASSERT(pos + 2 <= (size_t)(_end - _buffer));
return *reinterpret_cast<const uint16_t*>(_buffer + pos);
}
//! Get DWORD at position `pos`.
ASMJIT_INLINE uint32_t getDWordAt(size_t pos) const {
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
return *reinterpret_cast<const uint32_t*>(_buffer + pos);
}
//! Get QWORD at position `pos`.
ASMJIT_INLINE uint64_t getQWordAt(size_t pos) const {
ASMJIT_ASSERT(pos + 8 <= (size_t)(_end - _buffer));
return *reinterpret_cast<const uint64_t*>(_buffer + pos);
}
//! Get int32_t at position `pos`.
ASMJIT_INLINE int32_t getInt32At(size_t pos) const {
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
return *reinterpret_cast<const int32_t*>(_buffer + pos);
}
//! Get uint32_t at position `pos`.
ASMJIT_INLINE uint32_t getUInt32At(size_t pos) const {
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
return *reinterpret_cast<const uint32_t*>(_buffer + pos);
}
//! Set BYTE at position `pos`.
ASMJIT_INLINE void setByteAt(size_t pos, uint8_t x) {
ASMJIT_ASSERT(pos + 1 <= (size_t)(_end - _buffer));
*reinterpret_cast<uint8_t*>(_buffer + pos) = x;
}
//! Set WORD at position `pos`.
ASMJIT_INLINE void setWordAt(size_t pos, uint16_t x) {
ASMJIT_ASSERT(pos + 2 <= (size_t)(_end - _buffer));
*reinterpret_cast<uint16_t*>(_buffer + pos) = x;
}
//! Set DWORD at position `pos`.
ASMJIT_INLINE void setDWordAt(size_t pos, uint32_t x) {
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
*reinterpret_cast<uint32_t*>(_buffer + pos) = x;
}
//! Set QWORD at position `pos`.
ASMJIT_INLINE void setQWordAt(size_t pos, uint64_t x) {
ASMJIT_ASSERT(pos + 8 <= (size_t)(_end - _buffer));
*reinterpret_cast<uint64_t*>(_buffer + pos) = x;
}
//! Set int32_t at position `pos`.
ASMJIT_INLINE void setInt32At(size_t pos, int32_t x) {
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
*reinterpret_cast<int32_t*>(_buffer + pos) = x;
}
//! Set uint32_t at position `pos`.
ASMJIT_INLINE void setUInt32At(size_t pos, uint32_t x) {
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
*reinterpret_cast<uint32_t*>(_buffer + pos) = x;
}
// --------------------------------------------------------------------------
// [GetCodeSize]
// --------------------------------------------------------------------------
//! Get current offset in buffer, same as `getOffset() + getTramplineSize()`.
ASMJIT_INLINE size_t getCodeSize() const {
return getOffset() + getTrampolineSize();
}
// --------------------------------------------------------------------------
// [GetTrampolineSize]
// --------------------------------------------------------------------------
//! Get size of all possible trampolines.
//!
//! Trampolines are needed to successfuly 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 getTrampolineSize() const {
return _trampolineSize;
}
// --------------------------------------------------------------------------
// [Label]
// --------------------------------------------------------------------------
//! Get number of labels created.
ASMJIT_INLINE size_t getLabelsCount() const {
return _labelList.getLength();
}
//! Get whether the `label` is valid (created by the assembler).
ASMJIT_INLINE bool isLabelValid(const Label& label) const {
return isLabelValid(label.getId());
}
//! \overload
ASMJIT_INLINE bool isLabelValid(uint32_t id) const {
return static_cast<size_t>(id) < _labelList.getLength();
}
//! Get whether the `label` is bound.
//!
//! \note It's an error to pass label that is not valid. Check the validity
//! of the label by using `isLabelValid()` method before the bound check if
//! you are not sure about its validity, otherwise you may hit an assertion
//! failure in debug mode, and undefined behavior in release mode.
ASMJIT_INLINE bool isLabelBound(const Label& label) const {
return isLabelBound(label.getId());
}
//! \overload
ASMJIT_INLINE bool isLabelBound(uint32_t id) const {
ASMJIT_ASSERT(isLabelValid(id));
return _labelList[id].offset != -1;
}
//! Get `label` offset or -1 if the label is not yet bound.
ASMJIT_INLINE intptr_t getLabelOffset(const Label& label) const {
return getLabelOffset(label.getId());
}
//! \overload
ASMJIT_INLINE intptr_t getLabelOffset(uint32_t id) const {
ASMJIT_ASSERT(isLabelValid(id));
return _labelList[id].offset;
}
//! Get `LabelData` by `label`.
ASMJIT_INLINE LabelData* getLabelData(const Label& label) const {
return getLabelData(label.getId());
}
//! \overload
ASMJIT_INLINE LabelData* getLabelData(uint32_t id) const {
ASMJIT_ASSERT(isLabelValid(id));
return const_cast<LabelData*>(&_labelList[id]);
}
//! \internal
//!
//! Register labels for other code generator, i.e. `Compiler`.
ASMJIT_API Error _registerIndexedLabels(size_t index);
//! \internal
//!
//! Create and initialize a new `Label`.
ASMJIT_API Error _newLabel(Label* dst);
//! \internal
//!
//! New LabelLink instance.
ASMJIT_API LabelLink* _newLabelLink();
//! Create and return a new `Label`.
ASMJIT_INLINE Label newLabel() {
Label result(NoInit);
_newLabel(&result);
return result;
}
//! Bind label to the current offset.
//!
//! \note Label can be bound only once!
ASMJIT_API virtual Error bind(const Label& label);
// --------------------------------------------------------------------------
// [Embed]
// --------------------------------------------------------------------------
//! Embed data into the code buffer.
ASMJIT_API virtual Error embed(const void* data, uint32_t size);
// --------------------------------------------------------------------------
// [Align]
// --------------------------------------------------------------------------
//! Align target buffer to `m` bytes.
//!
//! Typical usage of this is to align labels at start of the inner loops.
//!
//! Inserts `nop()` instructions or CPU optimized NOPs.
virtual Error align(uint32_t mode, uint32_t offset) = 0;
// --------------------------------------------------------------------------
// [Reloc]
// --------------------------------------------------------------------------
//! Relocate the code to `baseAddress` and copy 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 base Base address used for relocation. The `JitRuntime` always
//! sets the `base` address to be the same as `dst`, but other runtimes, for
//! example `StaticRuntime`, do not have to follow this rule.
//!
//! \retval The number bytes actually used. If the code generator 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 allocated first time.
//!
//! A given buffer will be overwritten, to get the number of bytes required,
//! use `getCodeSize()`.
ASMJIT_API size_t relocCode(void* dst, Ptr baseAddress = kNoBaseAddress) const;
//! \internal
//!
//! Reloc code.
virtual size_t _relocCode(void* dst, Ptr baseAddress) const = 0;
// --------------------------------------------------------------------------
// [Make]
// --------------------------------------------------------------------------
ASMJIT_API virtual void* make();
// --------------------------------------------------------------------------
// [Emit]
// --------------------------------------------------------------------------
//! Emit an instruction.
ASMJIT_API Error emit(uint32_t code);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2);
//! \overload
ASMJIT_INLINE Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3) {
return _emit(code, o0, o1, o2, o3);
}
//! Emit an instruction with integer immediate operand.
ASMJIT_API Error emit(uint32_t code, int o0);
//! \overload
ASMJIT_API Error emit(uint32_t code, uint64_t o0);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, int o1);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, uint64_t o1);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, int o2);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, uint64_t o2);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int o3);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, uint64_t o3);
//! Emit an instruction (virtual).
virtual Error _emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3) = 0;
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Buffer where the code is emitted (either live or temporary).
//!
//! This is actually the base pointer of the buffer, to get the current
//! position (cursor) look at the `_cursor` member.
uint8_t* _buffer;
//! The end of the buffer (points to the first invalid byte).
//!
//! The end of the buffer is calculated as <code>_buffer + size</code>.
uint8_t* _end;
//! The current position in code `_buffer`.
uint8_t* _cursor;
//! Size of possible trampolines.
uint32_t _trampolineSize;
//! Inline comment that will be logged by the next instruction and set to NULL.
const char* _comment;
//! Unused `LabelLink` structures pool.
LabelLink* _unusedLinks;
//! LabelData list.
PodVector<LabelData> _labelList;
//! RelocData list.
PodVector<RelocData> _relocList;
};
//! \}
// ============================================================================
// [Defined-Later]
// ============================================================================
ASMJIT_INLINE Label::Label(Assembler& a) : Operand(NoInit) {
a._newLabel(this);
}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_ASSEMBLER_H
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/codegen.h"
#include "../base/intutil.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::CodeGen - Construction / Destruction]
// ============================================================================
CodeGen::CodeGen(Runtime* runtime) :
_runtime(runtime),
_logger(NULL),
_errorHandler(NULL),
_baseAddress(runtime->getBaseAddress()),
_arch(kArchNone),
_regSize(0),
_reserved(0),
_features(IntUtil::mask(kCodeGenOptimizedAlign)),
_instOptions(0),
_error(kErrorOk),
_baseZone(16384 - kZoneOverhead) {}
CodeGen::~CodeGen() {
if (_errorHandler != NULL)
_errorHandler->release();
}
// ============================================================================
// [asmjit::CodeGen - Logging]
// ============================================================================
#if !defined(ASMJIT_DISABLE_LOGGER)
Error CodeGen::setLogger(Logger* logger) {
_logger = logger;
return kErrorOk;
}
#endif // !ASMJIT_DISABLE_LOGGER
// ============================================================================
// [asmjit::CodeGen - Error]
// ============================================================================
Error CodeGen::setError(Error error, const char* message) {
if (error == kErrorOk) {
_error = kErrorOk;
return kErrorOk;
}
if (message == NULL) {
#if !defined(ASMJIT_DISABLE_NAMES)
message = ErrorUtil::asString(error);
#else
static const char noMessage[] = "";
message = noMessage;
#endif // ASMJIT_DISABLE_NAMES
}
// Error handler is called before logger so logging can be skipped if error
// has been handled.
ErrorHandler* handler = _errorHandler;
ASMJIT_TLOG("[ERROR] %s %s\n", message, !handler ? "(Possibly unhandled?)" : "");
if (handler != NULL && handler->handleError(error, message))
return error;
#if !defined(ASMJIT_DISABLE_LOGGER)
Logger* logger = _logger;
if (logger != NULL) {
logger->logFormat(kLoggerStyleComment,
"*** ERROR: %s (%u).\n", message, static_cast<unsigned int>(error));
}
#endif // !ASMJIT_DISABLE_LOGGER
// The handler->handleError() function may throw an exception or longjmp()
// to terminate the execution of setError(). This is the reason why we have
// delayed changing the _error member until now.
_error = error;
return error;
}
Error CodeGen::setErrorHandler(ErrorHandler* handler) {
ErrorHandler* oldHandler = _errorHandler;
if (oldHandler != NULL)
oldHandler->release();
if (handler != NULL)
handler = handler->addRef();
_errorHandler = handler;
return kErrorOk;
}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CODEGEN_H
#define _ASMJIT_BASE_CODEGEN_H
// [Dependencies - AsmJit]
#include "../base/error.h"
#include "../base/logger.h"
#include "../base/runtime.h"
#include "../base/zone.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::kCodeGen]
// ============================================================================
//! Features of \ref CodeGen.
ASMJIT_ENUM(kCodeGen) {
//! Emit optimized code-alignment sequences (`Assembler` and `Compiler`).
//!
//! Default `true`.
//!
//! X86/X64
//! -------
//!
//! Default align sequence used by X86/X64 architecture is one-byte 0x90
//! opcode that is mostly 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 1 to 11 bytes. Also when `X86Compiler` is used,
//! it can add REX prefixes into the code to make some instructions greater
//! so no alignment sequence is needed.
kCodeGenOptimizedAlign = 0,
//! Emit jump-prediction hints (`Assembler` and `Compiler`).
//!
//! Default `false`.
//!
//! X86/X64
//! -------
//!
//! 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.
kCodeGenPredictedJumps = 1,
//! Schedule instructions so they can be executed faster (`Compiler` only).
//!
//! Default `false` - has to be explicitly enabled as the scheduler needs
//! some time to run.
//!
//! X86/X64
//! -------
//!
//! If scheduling is enabled AsmJit will try to reorder instructions to
//! minimize dependency chain. Scheduler always runs after the registers are
//! allocated so it doesn't change count of register allocs/spills.
//!
//! This feature is highly experimental and untested.
kCodeGenEnableScheduler = 2
};
// ============================================================================
// [asmjit::kAlignMode]
// ============================================================================
//! Code aligning mode.
ASMJIT_ENUM(kAlignMode) {
//! Align by emitting a sequence that can be executed (code).
kAlignCode = 0,
//! Align by emitting sequence that shouldn't be executed (data).
kAlignData = 1
};
// ============================================================================
// [asmjit::kRelocMode]
// ============================================================================
//! Relocation mode.
ASMJIT_ENUM(kRelocMode) {
//! Relocate an absolute address to an absolute address.
kRelocAbsToAbs = 0,
//! Relocate a relative address to an absolute address.
kRelocRelToAbs = 1,
//! Relocate an absolute address to a relative address.
kRelocAbsToRel = 2,
//! Relocate an absolute address to a relative address or use trampoline.
kRelocTrampoline = 3
};
// ============================================================================
// [asmjit::CodeGen]
// ============================================================================
//! Abstract class defining basics of \ref Assembler and \ref Compiler.
struct ASMJIT_VCLASS CodeGen {
ASMJIT_NO_COPY(CodeGen)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CodeGen` instance.
ASMJIT_API CodeGen(Runtime* runtime);
//! Destroy the `CodeGen` instance.
ASMJIT_API virtual ~CodeGen();
// --------------------------------------------------------------------------
// [Runtime]
// --------------------------------------------------------------------------
//! Get runtime.
ASMJIT_INLINE Runtime* getRuntime() const {
return _runtime;
}
// --------------------------------------------------------------------------
// [Logger]
// --------------------------------------------------------------------------
#if !defined(ASMJIT_DISABLE_LOGGER)
//! Get whether the code generator has a logger.
ASMJIT_INLINE bool hasLogger() const {
return _logger != NULL;
}
//! Get logger.
ASMJIT_INLINE Logger* getLogger() const {
return _logger;
}
//! Set logger to `logger`.
ASMJIT_API Error setLogger(Logger* logger);
#endif // !ASMJIT_DISABLE_LOGGER
// --------------------------------------------------------------------------
// [Arch]
// --------------------------------------------------------------------------
//! Get target architecture.
ASMJIT_INLINE uint32_t getArch() const {
return _arch;
}
//! Get default register size (4 or 8 bytes).
ASMJIT_INLINE uint32_t getRegSize() const {
return _regSize;
}
// --------------------------------------------------------------------------
// [BaseAddress]
// --------------------------------------------------------------------------
//! Get whether the code-generator has a base address.
//!
//! \sa \ref getBaseAddress()
ASMJIT_INLINE bool hasBaseAddress() const {
return _baseAddress != kNoBaseAddress;
}
//! Get the base address.
ASMJIT_INLINE Ptr getBaseAddress() const {
return _baseAddress;
}
//! Set the base address to `baseAddress`.
ASMJIT_INLINE void setBaseAddress(Ptr baseAddress) {
_baseAddress = baseAddress;
}
//! Reset the base address.
ASMJIT_INLINE void resetBaseAddress() {
setBaseAddress(kNoBaseAddress);
}
// --------------------------------------------------------------------------
// [LastError / ErrorHandler]
// --------------------------------------------------------------------------
//! Get last error code.
ASMJIT_INLINE Error getError() const {
return _error;
}
//! Set last error code and propagate it through the error handler.
ASMJIT_API Error setError(Error error, const char* message = NULL);
//! Clear the last error code.
ASMJIT_INLINE void resetError() {
_error = kErrorOk;
}
//! Get error handler.
ASMJIT_INLINE ErrorHandler* getErrorHandler() const {
return _errorHandler;
}
//! Set error handler.
ASMJIT_API Error setErrorHandler(ErrorHandler* handler);
//! Clear error handler.
ASMJIT_INLINE Error resetErrorHandler() {
return setErrorHandler(NULL);
}
// --------------------------------------------------------------------------
// [Code-Generation Features]
// --------------------------------------------------------------------------
//! Get code-generator `feature`.
ASMJIT_INLINE bool hasFeature(uint32_t feature) const {
ASMJIT_ASSERT(feature < 32);
return (_features & (1 << feature)) != 0;
}
//! Set code-generator `feature` to `value`.
ASMJIT_INLINE void setFeature(uint32_t feature, bool value) {
ASMJIT_ASSERT(feature < 32);
feature = static_cast<uint32_t>(value) << feature;
_features = (_features & ~feature) | feature;
}
//! Get code-generator features.
ASMJIT_INLINE uint32_t getFeatures() const {
return _features;
}
//! Set code-generator features.
ASMJIT_INLINE void setFeatures(uint32_t features) {
_features = features;
}
// --------------------------------------------------------------------------
// [Instruction Options]
// --------------------------------------------------------------------------
//! Get options of the next instruction.
ASMJIT_INLINE uint32_t getInstOptions() const {
return _instOptions;
}
//! Get options of the next instruction and reset them.
ASMJIT_INLINE uint32_t getInstOptionsAndReset() {
uint32_t instOptions = _instOptions;
_instOptions = 0;
return instOptions;
};
//! Set options of the next instruction.
ASMJIT_INLINE void setInstOptions(uint32_t instOptions) {
_instOptions = instOptions;
}
// --------------------------------------------------------------------------
// [Make]
// --------------------------------------------------------------------------
//! Make is a convenience method to make and relocate the current code and
//! add it to the associated `Runtime`.
//!
//! What is needed is only to cast the returned pointer to your function type
//! and then use it. If there was an error during `make()` `NULL` is returned
//! and the last error code can be obtained by calling `getError()`.
virtual void* make() = 0;
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Target runtime.
Runtime* _runtime;
#if !defined(ASMJIT_DISABLE_LOGGER)
//! Logger.
Logger* _logger;
#else
//! \internal
//!
//! Makes libraries built with or without logging support binary compatible.
void* _logger;
#endif // ASMJIT_DISABLE_LOGGER
//! Error handler, called by \ref setError().
ErrorHandler* _errorHandler;
//! Base address (-1 if unknown/not used).
Ptr _baseAddress;
//! Target architecture ID.
uint8_t _arch;
//! Target architecture GP register size in bytes (4 or 8).
uint8_t _regSize;
//! \internal
uint16_t _reserved;
//! Code-Generation features, used by \ref hasFeature() and \ref setFeature().
uint32_t _features;
//! Options affecting the next instruction.
uint32_t _instOptions;
//! Last error code.
uint32_t _error;
//! Base zone.
Zone _baseZone;
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_CODEGEN_H
// [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 "../build.h"
#if !defined(ASMJIT_DISABLE_COMPILER)
// [Dependencies - AsmJit]
#include "../base/assembler.h"
#include "../base/compiler.h"
#include "../base/context_p.h"
#include "../base/cpuinfo.h"
#include "../base/intutil.h"
#include "../base/logger.h"
// [Dependencies - C]
#include <stdarg.h>
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// ============================================================================
// [Constants]
// ============================================================================
static const char noName[1] = { '\0' };
enum { kBaseCompilerDefaultLookAhead = 64 };
// ============================================================================
// [asmjit::Compiler - Construction / Destruction]
// ============================================================================
Compiler::Compiler(Runtime* runtime) :
CodeGen(runtime),
_assembler(NULL),
_nodeFlowId(0),
_nodeFlags(0),
_maxLookAhead(kBaseCompilerDefaultLookAhead),
_targetVarMapping(NULL),
_firstNode(NULL),
_lastNode(NULL),
_cursor(NULL),
_func(NULL),
_varZone(4096 - kZoneOverhead),
_stringZone(4096 - kZoneOverhead),
_localConstZone(4096 - kZoneOverhead),
_localConstPool(&_localConstZone),
_globalConstPool(&_baseZone) {}
Compiler::~Compiler() {
reset(true);
if (_assembler != NULL)
delete _assembler;
}
// ============================================================================
// [asmjit::Compiler - Clear / Reset]
// ============================================================================
void Compiler::reset(bool releaseMemory) {
// CodeGen members.
_baseAddress = kNoBaseAddress;
_instOptions = 0;
_error = kErrorOk;
_baseZone.reset(releaseMemory);
// Compiler members.
_nodeFlowId = 0;
_nodeFlags = 0;
if (_assembler != NULL)
_assembler->reset(releaseMemory);
_firstNode = NULL;
_lastNode = NULL;
_cursor = NULL;
_func = NULL;
_localConstPool.reset();
_globalConstPool.reset();
_localConstPoolLabel.reset();
_globalConstPoolLabel.reset();
_varZone.reset(releaseMemory);
_stringZone.reset(releaseMemory);
_localConstZone.reset(releaseMemory);
_targetList.reset(releaseMemory);
_varList.reset(releaseMemory);
}
// ============================================================================
// [asmjit::Compiler - Node Management]
// ============================================================================
Node* Compiler::setCursor(Node* node) {
Node* old = _cursor;
_cursor = node;
return old;
}
Node* Compiler::addNode(Node* node) {
ASMJIT_ASSERT(node != NULL);
ASMJIT_ASSERT(node->_prev == NULL);
ASMJIT_ASSERT(node->_next == NULL);
if (_cursor == NULL) {
if (_firstNode == NULL) {
_firstNode = node;
_lastNode = node;
}
else {
node->_next = _firstNode;
_firstNode->_prev = node;
_firstNode = node;
}
}
else {
Node* prev = _cursor;
Node* next = _cursor->_next;
node->_prev = prev;
node->_next = next;
prev->_next = node;
if (next)
next->_prev = node;
else
_lastNode = node;
}
_cursor = node;
return node;
}
Node* Compiler::addNodeBefore(Node* node, Node* ref) {
ASMJIT_ASSERT(node != NULL);
ASMJIT_ASSERT(node->_prev == NULL);
ASMJIT_ASSERT(node->_next == NULL);
ASMJIT_ASSERT(ref != NULL);
Node* prev = ref->_prev;
Node* next = ref;
node->_prev = prev;
node->_next = next;
next->_prev = node;
if (prev)
prev->_next = node;
else
_firstNode = node;
return node;
}
Node* Compiler::addNodeAfter(Node* node, Node* ref) {
ASMJIT_ASSERT(node != NULL);
ASMJIT_ASSERT(node->_prev == NULL);
ASMJIT_ASSERT(node->_next == NULL);
ASMJIT_ASSERT(ref != NULL);
Node* prev = ref;
Node* next = ref->_next;
node->_prev = prev;
node->_next = next;
prev->_next = node;
if (next)
next->_prev = node;
else
_lastNode = node;
return node;
}
static ASMJIT_INLINE void BaseCompiler_nodeRemoved(Compiler* self, Node* node_) {
if (node_->isJmpOrJcc()) {
JumpNode* node = static_cast<JumpNode*>(node_);
TargetNode* target = node->getTarget();
// Disconnect.
JumpNode** pPrev = &target->_from;
for (;;) {
ASMJIT_ASSERT(*pPrev != NULL);
JumpNode* current = *pPrev;
if (current == NULL)
break;
if (current == node) {
*pPrev = node->_jumpNext;
break;
}
pPrev = &current->_jumpNext;
}
target->subNumRefs();
}
}
Node* Compiler::removeNode(Node* node) {
Node* prev = node->_prev;
Node* next = node->_next;
if (_firstNode == node)
_firstNode = next;
else
prev->_next = next;
if (_lastNode == node)
_lastNode = prev;
else
next->_prev = prev;
node->_prev = NULL;
node->_next = NULL;
if (_cursor == node)
_cursor = prev;
BaseCompiler_nodeRemoved(this, node);
return node;
}
void Compiler::removeNodes(Node* first, Node* last) {
if (first == last) {
removeNode(first);
return;
}
Node* prev = first->_prev;
Node* next = last->_next;
if (_firstNode == first)
_firstNode = next;
else
prev->_next = next;
if (_lastNode == last)
_lastNode = prev;
else
next->_prev = prev;
Node* node = first;
for (;;) {
Node* next = node->getNext();
ASMJIT_ASSERT(next != NULL);
node->_prev = NULL;
node->_next = NULL;
if (_cursor == node)
_cursor = prev;
BaseCompiler_nodeRemoved(this, node);
if (node == last)
break;
node = next;
}
}
// ============================================================================
// [asmjit::Compiler - Align]
// ============================================================================
AlignNode* Compiler::newAlign(uint32_t mode, uint32_t offset) {
AlignNode* node = newNode<AlignNode>(mode, offset);
if (node == NULL)
goto _NoMemory;
return node;
_NoMemory:
setError(kErrorNoHeapMemory);
return NULL;
}
AlignNode* Compiler::addAlign(uint32_t mode, uint32_t offset) {
AlignNode* node = newAlign(mode, offset);
if (node == NULL)
return NULL;
return static_cast<AlignNode*>(addNode(node));
}
// ============================================================================
// [asmjit::Compiler - Target]
// ============================================================================
TargetNode* Compiler::newTarget() {
TargetNode* node = newNode<TargetNode>(
OperandUtil::makeLabelId(static_cast<uint32_t>(_targetList.getLength())));
if (node == NULL || _targetList.append(node) != kErrorOk)
goto _NoMemory;
return node;
_NoMemory:
setError(kErrorNoHeapMemory);
return NULL;
}
TargetNode* Compiler::addTarget() {
TargetNode* node = newTarget();
if (node == NULL)
return NULL;
return static_cast<TargetNode*>(addNode(node));
}
// ============================================================================
// [asmjit::Compiler - Label]
// ============================================================================
Error Compiler::_newLabel(Label* dst) {
dst->_init_packed_op_sz_b0_b1_id(kOperandTypeLabel, 0, 0, 0, kInvalidValue);
dst->_init_packed_d2_d3(0, 0);
TargetNode* node = newTarget();
if (node == NULL)
goto _NoMemory;
dst->_label.id = node->getLabelId();
return kErrorOk;
_NoMemory:
return setError(kErrorNoHeapMemory);
}
Error Compiler::bind(const Label& label) {
uint32_t index = label.getId();
ASMJIT_ASSERT(index < _targetList.getLength());
addNode(_targetList[index]);
return kErrorOk;
}
// ============================================================================
// [asmjit::Compiler - Embed]
// ============================================================================
EmbedNode* Compiler::newEmbed(const void* data, uint32_t size) {
EmbedNode* node;
if (size > EmbedNode::kInlineBufferSize) {
void* clonedData = _stringZone.alloc(size);
if (clonedData == NULL)
goto _NoMemory;
if (data != NULL)
::memcpy(clonedData, data, size);
data = clonedData;
}
node = newNode<EmbedNode>(const_cast<void*>(data), size);
if (node == NULL)
goto _NoMemory;
return node;
_NoMemory:
setError(kErrorNoHeapMemory);
return NULL;
}
EmbedNode* Compiler::addEmbed(const void* data, uint32_t size) {
EmbedNode* node = newEmbed(data, size);
if (node == NULL)
return node;
return static_cast<EmbedNode*>(addNode(node));
}
// ============================================================================
// [asmjit::Compiler - Comment]
// ============================================================================
CommentNode* Compiler::newComment(const char* str) {
CommentNode* node;
if (str != NULL && str[0]) {
str = _stringZone.sdup(str);
if (str == NULL)
goto _NoMemory;
}
node = newNode<CommentNode>(str);
if (node == NULL)
goto _NoMemory;
return node;
_NoMemory:
setError(kErrorNoHeapMemory);
return NULL;
}
CommentNode* Compiler::addComment(const char* str) {
CommentNode* node = newComment(str);
if (node == NULL)
return NULL;
return static_cast<CommentNode*>(addNode(node));
}
CommentNode* Compiler::comment(const char* fmt, ...) {
char buf[256];
char* p = buf;
if (fmt) {
*p++ = ';';
*p++ = ' ';
va_list ap;
va_start(ap, fmt);
p += vsnprintf(p, 254, fmt, ap);
va_end(ap);
}
p[0] = '\n';
p[1] = '\0';
return addComment(fmt);
}
// ============================================================================
// [asmjit::Compiler - Hint]
// ============================================================================
HintNode* Compiler::newHint(Var& var, uint32_t hint, uint32_t value) {
if (var.getId() == kInvalidValue)
return NULL;
VarData* vd = getVd(var);
HintNode* node = newNode<HintNode>(vd, hint, value);
if (node == NULL)
goto _NoMemory;
return node;
_NoMemory:
setError(kErrorNoHeapMemory);
return NULL;
}
HintNode* Compiler::addHint(Var& var, uint32_t hint, uint32_t value) {
if (var.getId() == kInvalidValue)
return NULL;
HintNode* node = newHint(var, hint, value);
if (node == NULL)
return NULL;
return static_cast<HintNode*>(addNode(node));
}
// ============================================================================
// [asmjit::Compiler - Vars]
// ============================================================================
VarData* Compiler::_newVd(uint32_t type, uint32_t size, uint32_t c, const char* name) {
VarData* vd = reinterpret_cast<VarData*>(_varZone.alloc(sizeof(VarData)));
if (vd == NULL)
goto _NoMemory;
vd->_name = noName;
vd->_id = OperandUtil::makeVarId(static_cast<uint32_t>(_varList.getLength()));
vd->_contextId = kInvalidValue;
if (name != NULL && name[0] != '\0') {
vd->_name = _stringZone.sdup(name);
}
vd->_type = static_cast<uint8_t>(type);
vd->_class = static_cast<uint8_t>(c);
vd->_flags = 0;
vd->_priority = 10;
vd->_state = kVarStateUnused;
vd->_regIndex = kInvalidReg;
vd->_isStack = false;
vd->_isMemArg = false;
vd->_isCalculated = false;
vd->_saveOnUnuse = false;
vd->_modified = false;
vd->_reserved0 = 0;
vd->_alignment = static_cast<uint8_t>(IntUtil::iMin<uint32_t>(size, 64));
vd->_size = size;
vd->_homeMask = 0;
vd->_memOffset = 0;
vd->_memCell = NULL;
vd->rReadCount = 0;
vd->rWriteCount = 0;
vd->mReadCount = 0;
vd->mWriteCount = 0;
vd->_va = NULL;
if (_varList.append(vd) != kErrorOk)
goto _NoMemory;
return vd;
_NoMemory:
setError(kErrorNoHeapMemory);
return NULL;
}
void Compiler::alloc(Var& var) {
addHint(var, kVarHintAlloc, kInvalidValue);
}
void Compiler::alloc(Var& var, uint32_t regIndex) {
addHint(var, kVarHintAlloc, regIndex);
}
void Compiler::alloc(Var& var, const Reg& reg) {
addHint(var, kVarHintAlloc, reg.getRegIndex());
}
void Compiler::save(Var& var) {
addHint(var, kVarHintSave, kInvalidValue);
}
void Compiler::spill(Var& var) {
addHint(var, kVarHintSpill, kInvalidValue);
}
void Compiler::unuse(Var& var) {
addHint(var, kVarHintUnuse, kInvalidValue);
}
uint32_t Compiler::getPriority(Var& var) const {
if (var.getId() == kInvalidValue)
return kInvalidValue;
VarData* vd = getVdById(var.getId());
return vd->getPriority();
}
void Compiler::setPriority(Var& var, uint32_t priority) {
if (var.getId() == kInvalidValue)
return;
if (priority > 255)
priority = 255;
VarData* vd = getVdById(var.getId());
vd->_priority = static_cast<uint8_t>(priority);
}
bool Compiler::getSaveOnUnuse(Var& var) const {
if (var.getId() == kInvalidValue)
return false;
VarData* vd = getVdById(var.getId());
return static_cast<bool>(vd->_saveOnUnuse);
}
void Compiler::setSaveOnUnuse(Var& var, bool value) {
if (var.getId() == kInvalidValue)
return;
VarData* vd = getVdById(var.getId());
vd->_saveOnUnuse = value;
}
void Compiler::rename(Var& var, const char* name) {
if (var.getId() == kInvalidValue)
return;
VarData* vd = getVdById(var.getId());
vd->_name = noName;
if (name != NULL && name[0] != '\0') {
vd->_name = _stringZone.sdup(name);
}
}
// ============================================================================
// [asmjit::Compiler - Assembler]
// ============================================================================
Assembler* Compiler::getAssembler() {
Assembler* a = _assembler;
if (a != NULL) {
a->reset(false);
}
else {
a = _newAssembler();
_assembler = a;
}
#if !defined(ASMJIT_DISABLE_LOGGER)
Logger* logger = _logger;
if (logger != NULL)
a->setLogger(logger);
#endif // !ASMJIT_DISABLE_LOGGER
a->setBaseAddress(_baseAddress);
a->setFeatures(_features);
return a;
}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_COMPILER
此差异已折叠。
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/constpool.h"
#include "../base/intutil.h"
// [Api-Begin]
#include "../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::ConstPoolTree - Ops]
// ============================================================================
//! \internal
//!
//! Remove left horizontal links.
static ASMJIT_INLINE ConstPoolNode* ConstPoolTree_skewNode(ConstPoolNode* node) {
ConstPoolNode* link = node->_link[0];
uint32_t level = node->_level;
if (level != 0 && link != NULL && 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 ConstPoolNode* ConstPoolTree_splitNode(ConstPoolNode* node) {
ConstPoolNode* link = node->_link[1];
uint32_t level = node->_level;
if (level != 0 && link != NULL && link->_link[1] != NULL && link->_link[1]->_level == level) {
node->_link[1] = link->_link[0];
link->_link[0] = node;
node = link;
node->_level++;
}
return node;
}
ConstPoolNode* ConstPoolTree::get(const void* data) {
ConstPoolNode* node = _root;
size_t dataSize = _dataSize;
while (node != NULL) {
int c = ::memcmp(node->getData(), data, dataSize);
if (c == 0)
return node;
node = node->_link[c < 0];
}
return NULL;
}
void ConstPoolTree::put(ConstPoolNode* newNode) {
size_t dataSize = _dataSize;
_length++;
if (_root == NULL) {
_root = newNode;
return;
}
ConstPoolNode* node = _root;
ConstPoolNode* 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;
ConstPoolNode* link = node->_link[dir];
if (link == NULL)
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) {
_zone = zone;
size_t dataSize = 1;
for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_tree); i++) {
_tree[i].setDataSize(dataSize);
_gaps[i] = NULL;
dataSize <<= 1;
}
_gapPool = NULL;
_size = 0;
_alignment = 0;
}
ConstPool::~ConstPool() {}
// ============================================================================
// [asmjit::ConstPool - Reset]
// ============================================================================
void ConstPool::reset() {
for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_tree); i++) {
_tree[i].reset();
_gaps[i] = NULL;
}
_gapPool = NULL;
_size = 0;
_alignment = 0;
}
// ============================================================================
// [asmjit::ConstPool - Ops]
// ============================================================================
static ASMJIT_INLINE ConstPoolGap* ConstPool_allocGap(ConstPool* self) {
ConstPoolGap* gap = self->_gapPool;
if (gap == NULL)
return self->_zone->allocT<ConstPoolGap>();
self->_gapPool = gap->_next;
return gap;
}
static ASMJIT_INLINE void ConstPool_freeGap(ConstPool* self, ConstPoolGap* gap) {
gap->_next = self->_gapPool;
self->_gapPool = gap;
}
static void ConstPool_addGap(ConstPool* self, size_t offset, size_t length) {
ASMJIT_ASSERT(length > 0);
while (length > 0) {
size_t gapIndex;
size_t gapLength;
if (length >= 16 && IntUtil::isAligned<size_t>(offset, 16)) {
gapIndex = ConstPool::kIndex16;
gapLength = 16;
}
else if (length >= 8 && IntUtil::isAligned<size_t>(offset, 8)) {
gapIndex = ConstPool::kIndex8;
gapLength = 8;
}
else if (length >= 4 && IntUtil::isAligned<size_t>(offset, 4)) {
gapIndex = ConstPool::kIndex4;
gapLength = 4;
}
else if (length >= 2 && IntUtil::isAligned<size_t>(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.
ConstPoolGap* gap = ConstPool_allocGap(self);
if (gap == NULL)
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) {
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 kErrorInvalidArgument;
ConstPoolNode* node = _tree[treeIndex].get(data);
if (node != NULL) {
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<size_t>(0);
size_t gapIndex = treeIndex;
while (gapIndex != kIndexCount - 1) {
ConstPoolGap* gap = _gaps[treeIndex];
// Check if there is a gap.
if (gap != NULL) {
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(IntUtil::isAligned<size_t>(offset, size));
gapLength -= size;
if (gapLength > 0)
ConstPool_addGap(this, gapOffset, gapLength);
}
gapIndex++;
}
if (offset == ~static_cast<size_t>(0)) {
// Get how many bytes have to be skipped so the address is aligned accordingly
// to the 'size'.
size_t deltaTo = IntUtil::deltaTo<size_t>(_size, size);
if (deltaTo != 0) {
ConstPool_addGap(this, _size, deltaTo);
_size += deltaTo;
}
offset = _size;
_size += size;
}
// Add the initial node to the right index.
node = ConstPoolTree::_newNode(_zone, data, size, offset, false);
if (node == NULL)
return kErrorNoHeapMemory;
_tree[treeIndex].put(node);
_alignment = IntUtil::iMax<size_t>(_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<const uint8_t*>(data);
for (size_t i = 0; i < pCount; i++, pData += size) {
node = _tree[treeIndex].get(pData);
if (node != NULL)
continue;
node = ConstPoolTree::_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) :
_dst(dst),
_dataSize(dataSize) {}
ASMJIT_INLINE void visit(const ConstPoolNode* node) {
if (!node->_shared)
::memcpy(_dst + node->_offset, node->getData(), _dataSize);
}
uint8_t* _dst;
size_t _dataSize;
};
void ConstPool::fill(void* dst) {
// Clears possible gaps, asmjit should never emit garbage to the output.
::memset(dst, 0, _size);
ConstPoolFill filler(static_cast<uint8_t*>(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 - 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();
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 "../apiend.h"
// [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 - AsmJit]
#include "../base/error.h"
#include "../base/zone.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::ConstPoolNode]
// ============================================================================
//! \internal
//!
//! Zone-allocated constant-pool node.
struct ConstPoolNode {
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
ASMJIT_INLINE void* getData() const {
return static_cast<void*>(const_cast<ConstPoolNode*>(this) + 1);
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Left/Right nodes.
ConstPoolNode* _link[2];
//! Horizontal level for balance.
uint32_t _level : 31;
//! Whether this constant is shared with another.
uint32_t _shared : 1;
//! Data offset from the beginning of the pool.
uint32_t _offset;
};
// ============================================================================
// [asmjit::ConstPoolTree]
// ============================================================================
//! \internal
//!
//! Zone-allocated constant-pool tree.
struct ConstPoolTree {
enum {
//! Maximum tree height == log2(1 << 64).
kHeightLimit = 64
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE ConstPoolTree(size_t dataSize = 0) :
_root(NULL),
_length(0),
_dataSize(dataSize) {}
ASMJIT_INLINE ~ConstPoolTree() {}
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
ASMJIT_INLINE void reset() {
_root = NULL;
_length = 0;
}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool isEmpty() const {
return _length == 0;
}
ASMJIT_INLINE size_t getLength() const {
return _length;
}
ASMJIT_INLINE void setDataSize(size_t dataSize) {
ASMJIT_ASSERT(isEmpty());
_dataSize = dataSize;
}
// --------------------------------------------------------------------------
// [Ops]
// --------------------------------------------------------------------------
ASMJIT_API ConstPoolNode* get(const void* data);
ASMJIT_API void put(ConstPoolNode* node);
// --------------------------------------------------------------------------
// [Iterate]
// --------------------------------------------------------------------------
template<typename Visitor>
ASMJIT_INLINE void iterate(Visitor& visitor) const {
ConstPoolNode* node = const_cast<ConstPoolNode*>(_root);
ConstPoolNode* link;
ConstPoolNode* stack[kHeightLimit];
if (node == NULL)
return;
size_t top = 0;
for (;;) {
link = node->_link[0];
if (link != NULL) {
ASMJIT_ASSERT(top != kHeightLimit);
stack[top++] = node;
node = link;
continue;
}
_Visit:
visitor.visit(node);
link = node->_link[1];
if (link != NULL) {
node = link;
continue;
}
if (top == 0)
break;
node = stack[--top];
goto _Visit;
}
}
// --------------------------------------------------------------------------
// [Helpers]
// --------------------------------------------------------------------------
static ASMJIT_INLINE ConstPoolNode* _newNode(Zone* zone, const void* data, size_t size, size_t offset, bool shared) {
ConstPoolNode* node = zone->allocT<ConstPoolNode>(sizeof(ConstPoolNode) + size);
if (node == NULL)
return NULL;
node->_link[0] = NULL;
node->_link[1] = NULL;
node->_level = 1;
node->_shared = shared;
node->_offset = static_cast<uint32_t>(offset);
::memcpy(node->getData(), data, size);
return node;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Root of the tree
ConstPoolNode* _root;
//! Length of the tree (count of nodes).
size_t _length;
//! Size of the data.
size_t _dataSize;
};
// ============================================================================
// [asmjit::ConstPoolGap]
// ============================================================================
//! \internal
//!
//! Zone-allocated constant-pool gap.
struct ConstPoolGap {
//! Link to the next gap
ConstPoolGap* _next;
//! Offset of the gap.
size_t _offset;
//! Remaining bytes of the gap (basically a gap size).
size_t _length;
};
// ============================================================================
// [asmjit::ConstPool]
// ============================================================================
//! Constant pool.
struct ConstPool {
ASMJIT_NO_COPY(ConstPool)
enum {
kIndex1 = 0,
kIndex2 = 1,
kIndex4 = 2,
kIndex8 = 3,
kIndex16 = 4,
kIndex32 = 5,
kIndexCount = 6
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_API ConstPool(Zone* zone);
ASMJIT_API ~ConstPool();
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
ASMJIT_API void reset();
// --------------------------------------------------------------------------
// [Ops]
// --------------------------------------------------------------------------
//! Get whether the constant-pool is empty.
ASMJIT_INLINE bool isEmpty() const {
return _size == 0;
}
//! Get the size of the constant-pool in bytes.
ASMJIT_INLINE size_t getSize() const {
return _size;
}
//! Get minimum alignment.
ASMJIT_INLINE size_t getAlignment() const {
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);
// --------------------------------------------------------------------------
// [Fill]
// --------------------------------------------------------------------------
//! Fill the destination with the constants from the pool.
ASMJIT_API void fill(void* dst);
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Zone allocator.
Zone* _zone;
//! Tree per size.
ConstPoolTree _tree[kIndexCount];
//! Gaps per size.
ConstPoolGap* _gaps[kIndexCount];
//! Gaps pool
ConstPoolGap* _gapPool;
//! Size of the pool (in bytes).
size_t _size;
//! Alignemnt.
size_t _alignment;
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_CONSTPOOL_H
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/containers.h"
#include "../base/intutil.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::PodVectorBase - NullData]
// ============================================================================
const PodVectorData PodVectorBase::_nullData = { 0, 0 };
// ============================================================================
// [asmjit::PodVectorBase - Reset]
// ============================================================================
//! Clear vector data and free internal buffer.
void PodVectorBase::reset(bool releaseMemory) {
PodVectorData* d = _d;
if (d == &_nullData)
return;
if (releaseMemory) {
ASMJIT_FREE(d);
_d = const_cast<PodVectorData*>(&_nullData);
return;
}
d->length = 0;
}
// ============================================================================
// [asmjit::PodVectorBase - Helpers]
// ============================================================================
Error PodVectorBase::_grow(size_t n, size_t sizeOfT) {
PodVectorData* d = _d;
size_t threshold = kMemAllocGrowMax / sizeOfT;
size_t capacity = d->capacity;
size_t after = d->length;
if (IntUtil::maxUInt<size_t>() - n < after)
return kErrorNoHeapMemory;
after += n;
if (capacity >= after)
return kErrorOk;
// PodVector is used as a linear array for some data structures used by
// AsmJit code generation. The purpose of this agressive growing schema
// is to minimize memory reallocations, because AsmJit code generation
// classes live short life and will be freed or reused soon.
if (capacity < 32)
capacity = 32;
else if (capacity < 128)
capacity = 128;
else if (capacity < 512)
capacity = 512;
while (capacity < after) {
if (capacity < threshold)
capacity *= 2;
else
capacity += threshold;
}
return _reserve(capacity, sizeOfT);
}
Error PodVectorBase::_reserve(size_t n, size_t sizeOfT) {
PodVectorData* d = _d;
if (d->capacity >= n)
return kErrorOk;
size_t nBytes = sizeof(PodVectorData) + n * sizeOfT;
if (nBytes < n)
return kErrorNoHeapMemory;
if (d == &_nullData) {
d = static_cast<PodVectorData*>(ASMJIT_ALLOC(nBytes));
if (d == NULL)
return kErrorNoHeapMemory;
d->length = 0;
}
else {
d = static_cast<PodVectorData*>(ASMJIT_REALLOC(d, nBytes));
if (d == NULL)
return kErrorNoHeapMemory;
}
d->capacity = n;
_d = d;
return kErrorOk;
}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
此差异已折叠。
此差异已折叠。
此差异已折叠。
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/cpuinfo.h"
#if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
#include "../x86/x86cpuinfo.h"
#else
// ?
#endif // ASMJIT_HOST || ASMJIT_HOST_X64
// [Dependencies - Posix]
#if defined(ASMJIT_OS_POSIX)
# include <errno.h>
# include <sys/statvfs.h>
# include <sys/utsname.h>
# include <unistd.h>
#endif // ASMJIT_OS_POSIX
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::CpuInfo - DetectHwThreadsCount]
// ============================================================================
uint32_t CpuInfo::detectHwThreadsCount() {
#if defined(ASMJIT_OS_WINDOWS)
SYSTEM_INFO info;
::GetSystemInfo(&info);
return info.dwNumberOfProcessors;
#elif defined(ASMJIT_OS_POSIX) && defined(_SC_NPROCESSORS_ONLN)
// It seems that sysconf returns the number of "logical" processors on both
// mac and linux. So we get the number of "online logical" processors.
long res = ::sysconf(_SC_NPROCESSORS_ONLN);
if (res == -1) return 1;
return static_cast<uint32_t>(res);
#else
return 1;
#endif
}
// ============================================================================
// [asmjit::CpuInfo - GetHost]
// ============================================================================
#if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
struct AutoX86CpuInfo : public X86CpuInfo {
ASMJIT_INLINE AutoX86CpuInfo() : X86CpuInfo() {
X86CpuUtil::detect(this);
}
};
#else
#error "AsmJit - Unsupported CPU."
#endif // ASMJIT_HOST || ASMJIT_HOST_X64
const CpuInfo* CpuInfo::getHost() {
#if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
static AutoX86CpuInfo cpuInfo;
#else
#error "AsmJit - Unsupported CPU."
#endif // ASMJIT_HOST || ASMJIT_HOST_X64
return &cpuInfo;
}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/globals.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::Assert]
// ============================================================================
void assertionFailed(const char* exp, const char* file, int line) {
::fprintf(stderr, "Assertion failed: %s\n, file %s, line %d\n", exp, file, line);
::abort();
}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
# rewolf-wow64ext
WOW64Ext is a helper library for x86 programs that runs under WOW64 layer on x64 versions of Microsoft Windows operating systems. It enables x86 applications to read, write and enumerate memory of a native x64 applications. There is also possibility to call any x64 function from 64-bits version of NTDLL through a special function called X64Call(). As a bonus, wow64ext.h contains definitions of some structures that might be useful for programs that want to access PEB, TEB, TIB etc.
cl /Zi /D "UNICODE" ../bin/wow64ext.lib main.cpp
B// Microsoft Visual C++ generated resource script.
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册