You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2064 lines
91 KiB
2064 lines
91 KiB
4 years ago
|
// AsmJit - Machine code generation for C++
|
||
|
//
|
||
|
// * Official AsmJit Home Page: https://asmjit.com
|
||
|
// * Official Github Repository: https://github.com/asmjit/asmjit
|
||
|
//
|
||
|
// Copyright (c) 2008-2020 The AsmJit Authors
|
||
|
//
|
||
|
// This software is provided 'as-is', without any express or implied
|
||
|
// warranty. In no event will the authors be held liable for any damages
|
||
|
// arising from the use of this software.
|
||
|
//
|
||
|
// Permission is granted to anyone to use this software for any purpose,
|
||
|
// including commercial applications, and to alter it and redistribute it
|
||
|
// freely, subject to the following restrictions:
|
||
|
//
|
||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||
|
// claim that you wrote the original software. If you use this software
|
||
|
// in a product, an acknowledgment in the product documentation would be
|
||
|
// appreciated but is not required.
|
||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||
|
// misrepresented as being the original software.
|
||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||
|
|
||
|
#ifndef ASMJIT_CORE_H_INCLUDED
|
||
|
#define ASMJIT_CORE_H_INCLUDED
|
||
|
|
||
|
//! Root namespace used by AsmJit.
|
||
|
namespace asmjit {
|
||
|
|
||
|
// ============================================================================
|
||
|
// [Documentation - mainpage]
|
||
|
// ============================================================================
|
||
|
|
||
|
//! \mainpage API Reference
|
||
|
//!
|
||
|
//! AsmJit C++ API reference documentation generated by Doxygen.
|
||
|
//!
|
||
|
//! AsmJit library uses one global namespace called \ref asmjit, which provides
|
||
|
//! the whole functionality. Core functionality is within \ref asmjit namespace
|
||
|
//! and architecture specific functionality is always in its own namespace. For
|
||
|
//! example \ref asmjit::x86 provides both 32-bit and 64-bit X86 code generation.
|
||
|
//!
|
||
|
//! \section main_groups Documentation Groups
|
||
|
//!
|
||
|
//! AsmJit documentation is structured into groups. Groups can be followed in
|
||
|
//! order to learn AsmJit, but knowledge from multiple groups is required to
|
||
|
//! use AsmJit properly:
|
||
|
//!
|
||
|
//! $$DOCS_GROUP_OVERVIEW$$
|
||
|
//!
|
||
|
//! \note It's important to understand that in order to learn AsmJit all groups
|
||
|
//! are important. Some groups can be omitted if a particular tool is out of
|
||
|
//! interest - for example \ref asmjit_assembler users don't need to know about
|
||
|
//! \ref asmjit_builder, but it's not the opposite. \ref asmjit_builder users
|
||
|
//! must know about \ref asmjit_assembler as it also uses operands, labels, and
|
||
|
//! other concepts. Similarly \ref asmjit_compiler users must know how both \ref
|
||
|
//! asmjit_assembler and \ref asmjit_builder tools work.
|
||
|
//!
|
||
|
//! \section where_to_start Where To Start
|
||
|
//!
|
||
|
//! AsmJit \ref asmjit_core provides the following two classes that are essential
|
||
|
//! from the code generation perspective:
|
||
|
//!
|
||
|
//! - \ref CodeHolder provides functionality
|
||
|
//! to temporarily hold the generated code. It stores all the necessary
|
||
|
//! information about the code - code buffers, sections, labels, symbols,
|
||
|
//! and information about relocations.
|
||
|
//!
|
||
|
//! - \ref BaseEmitter provides interface used
|
||
|
//! by emitter implementations. The interface provides basic building blocks
|
||
|
//! that are then implemented by \ref BaseAssembler, \ref BaseBuilder, and
|
||
|
//! \ref BaseCompiler.
|
||
|
//!
|
||
|
//! Code emitters:
|
||
|
//!
|
||
|
//! - \ref asmjit_assembler - provides direct machine code generation.
|
||
|
//!
|
||
|
//! - \ref asmjit_builder - provides intermediate code generation that can
|
||
|
//! be processed before it's serialized to \ref BaseAssembler.
|
||
|
//!
|
||
|
//! - \ref asmjit_compiler - provides high-level code generation with built-in
|
||
|
//! register allocation.
|
||
|
//!
|
||
|
//! - \ref FuncNode - provides insight into how function looks from the Compiler
|
||
|
//! perspective and how it's stored in a node-list.
|
||
|
//!
|
||
|
//! \section main_recommendations Recommendations
|
||
|
//!
|
||
|
//! The following steps are recommended for all AsmJit users:
|
||
|
//!
|
||
|
//! - Make sure that you use \ref Logger, see \ref asmjit_logging.
|
||
|
//!
|
||
|
//! - Make sure that you use \ref ErrorHandler, see \ref asmjit_error_handling.
|
||
|
//!
|
||
|
//! - Instruction validation in your debug builds can reveal problems too.
|
||
|
//! AsmJit provides validation at instruction level, that can be enabled
|
||
|
//! by \ref BaseEmitter::addValidationOptions().
|
||
|
//!
|
||
|
//! See \ref BaseEmitter::ValidationOptions for more details.
|
||
|
//!
|
||
|
//! - Make sure you put a breakpoint into \ref DebugUtils::errored() function
|
||
|
//! if you have a problem with AsmJit returning errors during instruction
|
||
|
//! encoding or register allocation. Having an active breakpoint there can
|
||
|
//! help to reveal the origin of the error, to inspect variables and other
|
||
|
//! conditions that caused to it.
|
||
|
//!
|
||
|
//! The reason for using \ref Logger and \ref ErrorHandler is that they provide
|
||
|
//! a very useful information about what's happening inside emitters. In many
|
||
|
//! cases the information provided by these two is crucial to quickly fix issues
|
||
|
//! that happen during development (for example wrong instruction, address, or
|
||
|
//! register used). In addition, output from \ref Logger is always necessary
|
||
|
//! when filling bug reports. In other words, using logging and proper error
|
||
|
//! handling can save a lot of time during the development.
|
||
|
//!
|
||
|
//! \section main_other Other Pages
|
||
|
//!
|
||
|
//! - <a href="annotated.html">Class List</a> - List of classes sorted alphabetically
|
||
|
//! - <a href="namespaceasmjit.html">AsmJit Namespace</a> - List of symbols provided by `asmjit` namespace
|
||
|
|
||
|
// ============================================================================
|
||
|
// [Documentation - asmjit_build]
|
||
|
// ============================================================================
|
||
|
|
||
|
//! \defgroup asmjit_build Build Instructions
|
||
|
//! \brief Build instructions, supported environments, and feature selection.
|
||
|
//!
|
||
|
//! ### Overview
|
||
|
//!
|
||
|
//! AsmJit is designed to be easy embeddable in any project. However, it depends
|
||
|
//! on some compile-time definitions that can be used to enable or disable
|
||
|
//! features to decrease the resulting binary size. A typical way of building
|
||
|
//! AsmJit is to use [cmake](https://www.cmake.org), but it's also possible to
|
||
|
//! just include AsmJit source code in your project and to just build it. The
|
||
|
//! easiest way to include AsmJit in your project is to just include **src**
|
||
|
//! directory in your project and to define \ref ASMJIT_STATIC. AsmJit can be
|
||
|
//! just updated from time to time without any changes to this integration
|
||
|
//! process. Do not embed AsmJit's `test` files in such case as these are used
|
||
|
//! exclusively for testing.
|
||
|
//!
|
||
|
//! ### Supported C++ Compilers
|
||
|
//!
|
||
|
//! - Requirements:
|
||
|
//!
|
||
|
//! - AsmJit won't build without C++11 enabled. If you use older GCC or Clang
|
||
|
//! you would have to enable at least C++11 standard through compiler flags.
|
||
|
//!
|
||
|
//! - Tested:
|
||
|
//!
|
||
|
//! - **Clang** - Tested by Travis-CI - Clang 3.9+ (with C++11 enabled) is
|
||
|
//! officially supported (older Clang versions having C++11 support are
|
||
|
//! probably fine, but are not regularly tested).
|
||
|
//!
|
||
|
//! - **GNU** - Tested by Travis-CI - GCC 4.8+ (with C++11 enabled) is
|
||
|
//! officially supported.
|
||
|
//!
|
||
|
//! - **MINGW** - Tested by Travis-CI - Use the latest version, if possible.
|
||
|
//!
|
||
|
//! - **MSVC** - Tested by Travis-CI - VS2017+ is officially supported, VS2015
|
||
|
//! is reported to work.
|
||
|
//!
|
||
|
//! - Untested:
|
||
|
//!
|
||
|
//! - **Intel** - No maintainers and no CI environment to regularly test
|
||
|
//! this compiler.
|
||
|
//!
|
||
|
//! - **Other** C++ compilers would require basic support in
|
||
|
//! [core/api-config.h](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/api-config.h).
|
||
|
//!
|
||
|
//! ### Supported Operating Systems and Platforms
|
||
|
//!
|
||
|
//! - Tested:
|
||
|
//!
|
||
|
//! - **Linux** - Tested by Travis-CI (any distribution is generally supported).
|
||
|
//!
|
||
|
//! - **OSX** - Tested by Travis-CI (any version is supported).
|
||
|
//!
|
||
|
//! - **Windows** - Tested by Travis-CI - (Windows 7+ is officially supported).
|
||
|
//!
|
||
|
//! - **Emscripten** - Works if compiled with \ref ASMJIT_NO_JIT. AsmJit
|
||
|
//! cannot generate WASM code, but can be used to generate X86/X64 code
|
||
|
//! within a browser, for example.
|
||
|
//!
|
||
|
//! - Untested:
|
||
|
//!
|
||
|
//! - **BSDs** - No maintainers, no CI environment to regularly test BSDs,
|
||
|
//! but they should work out of box.
|
||
|
//!
|
||
|
//! - **Haiku** - Not regularly tested, but reported to work.
|
||
|
//!
|
||
|
//! - **Other** operating systems would require some testing and support in
|
||
|
//! the following files:
|
||
|
//! - [core/api-config.h](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/api-config.h)
|
||
|
//! - [core/osutils.cpp](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/osutils.cpp)
|
||
|
//! - [core/virtmem.cpp](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/virtmem.cpp)
|
||
|
//!
|
||
|
//! ### Supported Backends / Architectures
|
||
|
//!
|
||
|
//! - **X86** - Both 32-bit and 64-bit backends tested by Travis-CI.
|
||
|
//! - **ARM** - Work-in-progress (not public at the moment).
|
||
|
//!
|
||
|
//! ### Static Builds and Embedding
|
||
|
//!
|
||
|
//! These definitions can be used to enable static library build. Embed is used
|
||
|
//! when AsmJit's source code is embedded directly in another project, implies
|
||
|
//! static build as well.
|
||
|
//!
|
||
|
//! - \ref ASMJIT_EMBED - Asmjit is embedded, implies \ref ASMJIT_STATIC.
|
||
|
//! - \ref ASMJIT_STATIC - Enable static-library build.
|
||
|
//!
|
||
|
//! \note Projects that use AsmJit statically must define \ref ASMJIT_STATIC in
|
||
|
//! all compilation units that use AsmJit, otherwise AsmJit would use dynamic
|
||
|
//! library imports in \ref ASMJIT_API decorator. The recommendation is to
|
||
|
//! define this macro across the whole project that uses AsmJit this way.
|
||
|
//!
|
||
|
//! ### Build Configuration
|
||
|
//!
|
||
|
//! These definitions control whether asserts are active or not. By default
|
||
|
//! AsmJit would autodetect build configuration from existing pre-processor
|
||
|
//! definitions, but this behavior can be overridden, for example to enable
|
||
|
//! debug asserts in release configuration.
|
||
|
//!
|
||
|
//! - \ref ASMJIT_BUILD_DEBUG - Overrides build configuration to debug,
|
||
|
//! asserts will be enabled in this case.
|
||
|
//! - \ref ASMJIT_BUILD_RELEASE - Overrides build configuration to release,
|
||
|
//! asserts will be disabled in this case.
|
||
|
//!
|
||
|
//! \note There is usually no need to override the build configuration. AsmJit
|
||
|
//! detects the build configuration by checking whether `NDEBUG` is defined and
|
||
|
//! automatically defines \ref ASMJIT_BUILD_RELEASE if configuration overrides
|
||
|
//! were not used. We only recommend using build configuration overrides in
|
||
|
//! special situations, like using AsmJit in release configuration with asserts
|
||
|
//! enabled for whatever reason.
|
||
|
//!
|
||
|
//! ### AsmJit Backends
|
||
|
//!
|
||
|
//! AsmJit currently supports only X86/X64 backend, but the plan is to add more
|
||
|
//! backends in the future. By default AsmJit builds only the host backend, which
|
||
|
//! is autodetected at compile-time, but this can be overridden.
|
||
|
//!
|
||
|
//! - \ref ASMJIT_BUILD_X86 - Always build X86 backend (X86 and X86_64).
|
||
|
//! - \ref ASMJIT_BUILD_ARM - Always build ARM backend (ARM and AArch64).
|
||
|
//! - \ref ASMJIT_BUILD_HOST - Always build the host backend.
|
||
|
//!
|
||
|
//! ### Features Selection
|
||
|
//!
|
||
|
//! AsmJit builds by defaults all supported features, which includes all emitters,
|
||
|
//! logging, instruction validation and introspection, and JIT memory allocation.
|
||
|
//! Features can be disabled at compile time by using `ASMJIT_NO_...` definitions.
|
||
|
//!
|
||
|
//! - \ref ASMJIT_NO_DEPRECATED - Disables deprecated API at compile time
|
||
|
//! so it won't be available and the compilation will fail if there is
|
||
|
//! attempt to use such API. This includes deprecated classes, namespaces,
|
||
|
//! enumerations, and functions.
|
||
|
//!
|
||
|
//! - \ref ASMJIT_NO_FOREIGN - Disables the support for foreign architectures.
|
||
|
//! If defined, it would internally set \ref ASMJIT_BUILD_HOST to true.
|
||
|
//!
|
||
|
//! - \ref ASMJIT_NO_BUILDER - Disables \ref asmjit_builder functionality
|
||
|
//! completely. This implies \ref ASMJIT_NO_COMPILER as \ref asmjit_compiler
|
||
|
//! cannot be used without \ref asmjit_builder.
|
||
|
//!
|
||
|
//! - \ref ASMJIT_NO_COMPILER - Disables \ref asmjit_compiler functionality
|
||
|
//! completely.
|
||
|
//!
|
||
|
//! - \ref ASMJIT_NO_JIT - Disables JIT memory management and \ref JitRuntime.
|
||
|
//!
|
||
|
//! - \ref ASMJIT_NO_LOGGING - Disables \ref Logger and \ref Formatter.
|
||
|
//!
|
||
|
//! - \ref ASMJIT_NO_TEXT - Disables everything that contains string
|
||
|
//! representation of AsmJit constants, should be used together with
|
||
|
//! \ref ASMJIT_NO_LOGGING as logging doesn't make sense without the
|
||
|
//! ability to quiry instruction names, register names, etc...
|
||
|
//!
|
||
|
//! - \ref ASMJIT_NO_VALIDATION - Disables validation API.
|
||
|
//!
|
||
|
//! - \ref ASMJIT_NO_INTROSPECTION - Disables instruction introspection API,
|
||
|
//! must be used together with \ref ASMJIT_NO_COMPILER as \ref asmjit_compiler
|
||
|
//! requires introspection for its liveness analysis and register allocation.
|
||
|
//!
|
||
|
//! \note It's not recommended to disable features if you plan to build AsmJit
|
||
|
//! as a shared library that will be used by multiple projects that you don't
|
||
|
//! control how AsmJit was built (for example AsmJit in a Linux distribution).
|
||
|
//! The possibility to disable certain features exists mainly for customized
|
||
|
//! AsmJit builds.
|
||
|
|
||
|
// ============================================================================
|
||
|
// [Documentation - asmjit_breaking_changes]
|
||
|
// ============================================================================
|
||
|
|
||
|
//! \defgroup asmjit_breaking_changes Breaking Changes
|
||
|
//! \brief Documentation of breaking changes
|
||
|
//!
|
||
|
//! ### Overview
|
||
|
//!
|
||
|
//! AsmJit is a live project that is being actively developed. Deprecating the
|
||
|
//! existing API in favor of a new one is preferred, but it's not always
|
||
|
//! possible if the changes are significant. AsmJit authors prefer to do
|
||
|
//! accumulated breaking changes at once instead of breaking the API often.
|
||
|
//! This page documents deprecated and removed APIs and should serve as a how-to
|
||
|
//! guide for people that want to port existing code to work with the newest AsmJit.
|
||
|
//!
|
||
|
//! ### Tips
|
||
|
//!
|
||
|
//! Useful tips before you start:
|
||
|
//!
|
||
|
//! - Visit our [Public Gitter Channel](https://gitter.im/asmjit/asmjit) if
|
||
|
//! you need a quick help.
|
||
|
//!
|
||
|
//! - Build AsmJit with `ASMJIT_NO_DEPRECATED` macro defined to make sure that
|
||
|
//! you are not using deprecated functionality at all. Deprecated functions
|
||
|
//! are decorated with `ASMJIT_DEPRECATED()` macro, but sometimes it's not
|
||
|
//! possible to decorate everything like classes, which are used by deprecated
|
||
|
//! functions as well, because some compilers would warn about that. If your
|
||
|
//! project compiles fine with `ASMJIT_NO_DEPRECATED` it's not using anything,
|
||
|
//! which was deprecated.
|
||
|
//!
|
||
|
//! ### Changes committed at 2020-05-30
|
||
|
//!
|
||
|
//! AsmJit has been cleaned up significantly, many todo items have been fixed
|
||
|
//! and many functions and classes have been redesigned, some in an incompatible
|
||
|
//! way.
|
||
|
//!
|
||
|
//! Core changes:
|
||
|
//!
|
||
|
//! - \ref Imm operand has now only \ref Imm::value() and \ref Imm::valueAs()
|
||
|
//! functions that return its value content, and \ref Imm::setValue() function
|
||
|
//! that sets the content. Functions like `setI8()`, `setU8()` were deprecated.
|
||
|
//!
|
||
|
//! Old functions were deprecated, but code using them should still compile.
|
||
|
//!
|
||
|
//! - `ArchInfo` has been replaced with \ref Environment. Environment provides
|
||
|
//! more details about the architecture, but drops some properties that
|
||
|
//! were used by arch info - `gpSize(`) and `gpCount()`. `gpSize()` can
|
||
|
//! be replaced with `registerSize()` getter, which returns a native register
|
||
|
//! size of the architecture the environment uses. However, `gpCount()` was
|
||
|
//! removed - at the moment \ref ArchRegs can be used to access such properties.
|
||
|
//!
|
||
|
//! Some other functions were renamed, like `ArchInfo::isX86Family()` is
|
||
|
//! now \ref Environment::isFamilyX86(), etc. The reason for changing the
|
||
|
//! order was support for more propertries and all the accessors now
|
||
|
//! start with the type of the property, like \ref Environment::isPlatformWindows().
|
||
|
//!
|
||
|
//! This function causes many other classes to provide `environment()` getter
|
||
|
//! instead of `archInfo()` getter. In addition, AsmJit now uses `arch()` to
|
||
|
//! get an architecture instead of `archId()`. `ArchInfo::kIdXXX` was renamed
|
||
|
//! to `Environment::kArchXXX`.
|
||
|
//!
|
||
|
//! Some functions were deprecated, some removed...
|
||
|
//!
|
||
|
//! - `CodeInfo` has been removed in favor of \ref Environment. If you used
|
||
|
//! `CodeInfo` to set architecture and base address, this is now possible
|
||
|
//! with \ref Environment and setting base address explicitly by \ref
|
||
|
//! CodeHolder::init() - the first argument is \ref Environment, and the
|
||
|
//! second argument is base address, which defaults to \ref
|
||
|
//! Globals::kNoBaseAddress.
|
||
|
//!
|
||
|
//! CodeInfo class was deprecated, but the code using it should still
|
||
|
//! compile with warnings.
|
||
|
//!
|
||
|
//! - \ref CallConv has been updated to offer a more unified way of representing
|
||
|
//! calling conventions - many calling conventions were abstracted to follow
|
||
|
//! standard naming like \ref CallConv::kIdCDecl or \ref CallConv::kIdStdCall.
|
||
|
//!
|
||
|
//! This change means that other APIs like \ref FuncDetail::init() now
|
||
|
//! require both, calling convention and target \ref Environment.
|
||
|
//!
|
||
|
//! - `Logging` namespace has been renamed to \ref Formatter, which now
|
||
|
//! provides general functionality for formatting in AsmJit.
|
||
|
//!
|
||
|
//! Logging namespace should still work, but its use is deprecated.
|
||
|
//! Unfortunately this will be without deprecation warnings, so please
|
||
|
//! make sure you don't use it.
|
||
|
//!
|
||
|
//! - `Data64`, `Data128`, and `Data256` structs were deprecated and should
|
||
|
//! no longer be used. There is no replacement, AsmJit users should simply
|
||
|
//! create their own structures if they need them or use the new repeated
|
||
|
//! embed API in emitters, see \ref BaseEmitter::embedDataArray().
|
||
|
//!
|
||
|
//! Emitter changes:
|
||
|
//!
|
||
|
//! - \ref BaseEmitter::emit() function signature has been changed to accept
|
||
|
//! 3 operands by reference and the rest 3 operands as a continuous array.
|
||
|
//! This change is purely cosmetic and shouldn't affect users as emit()
|
||
|
//! has many overloads that dispatch to the right function.
|
||
|
//!
|
||
|
//! - \ref x86::Emitter (Assembler, Builder, Compiler) deprecates embed
|
||
|
//! utilities like `dint8()`, `duint8()`, `duint16()`, `dxmm()`, etc...
|
||
|
//! in favor of a new and more powerful \ref BaseEmitter::embedDataArray().
|
||
|
//! This function also allows emitting repeated values and/or patterns,
|
||
|
//! which is used by helpers \ref BaseEmitter::embedUInt8(), and others...
|
||
|
//!
|
||
|
//! - Validation is now available through \ref BaseEmitter::ValidationOptions,
|
||
|
//! which can be enabled/disabled through \ref BaseEmitter::addValidationOptions()
|
||
|
//! and \ref BaseEmitter::clearValidationOptions(), respectively. Validation
|
||
|
//! options now separate between encoding and Builder/Compiler so it's possible
|
||
|
//! to choose the granularity required.
|
||
|
//!
|
||
|
//! Builder changes:
|
||
|
//!
|
||
|
//! - Internal functions for creating nodes were redesigned. They now accept
|
||
|
//! a pointer to the node created as a first parameter. These changes should
|
||
|
//! not affect AsmJit users as these functions were used internally.
|
||
|
//!
|
||
|
//! Compiler changes:
|
||
|
//!
|
||
|
//! - `FuncCallNode` has been renamed to \ref InvokeNode. Additionally, function
|
||
|
//! calls should now use \ref x86::Compiler::invoke() instead of `call()`.
|
||
|
//! The reason behind this is to remove the confusion between a `call`
|
||
|
//! instruction and AsmJit's `call()` intrinsic, which is now `invoke()`.
|
||
|
//!
|
||
|
//! - Creating new nodes also changed. Now the preferred way of invoking a
|
||
|
//! function is to call \ref x86::Compiler::invoke() where the first
|
||
|
//! argument is `InvokeNode**`. The function now returns an error and would
|
||
|
//! call \ref ErrorHandler in case of a failure. Error handling was
|
||
|
//! unspecified in the past - the function was marked noexcept, but called
|
||
|
//! error handler, which could throw.
|
||
|
//!
|
||
|
//! The reason behind this change is to make the API consistent with other
|
||
|
//! changes and to also make it possible to inspect the possible error. In
|
||
|
//! the previous API it returned a new node or `nullptr` in case of error,
|
||
|
//! which the user couldn't inspect unless there was an attached \ref
|
||
|
//! ErrorHandler.
|
||
|
//!
|
||
|
//! Samples:
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/x86.h>
|
||
|
//! using namespace asmjit;
|
||
|
//!
|
||
|
//! // The basic setup of JitRuntime and CodeHolder changed, use environment()
|
||
|
//! // instead of codeInfo().
|
||
|
//! void basicSetup() {
|
||
|
//! JitRuntime rt;
|
||
|
//! CodeHolder code(rt.environment());
|
||
|
//! }
|
||
|
//!
|
||
|
//! // Calling a function (Compiler) changed - use invoke() instead of call().
|
||
|
//! void functionInvocation(x86::Compiler& cc) {
|
||
|
//! InvokeNode* invokeNode;
|
||
|
//! cc.invoke(&invokeNode, targetOperand, FuncSignatureT<...>(...));
|
||
|
//! }
|
||
|
//! ```
|
||
|
|
||
|
// ============================================================================
|
||
|
// [Documentation - asmjit_core]
|
||
|
// ============================================================================
|
||
|
|
||
|
//! \defgroup asmjit_core Core
|
||
|
//! \brief Globals, code storage, and emitter interface.
|
||
|
//!
|
||
|
//! ### Overview
|
||
|
//!
|
||
|
//! AsmJit library uses \ref CodeHolder to hold code during code generation and
|
||
|
//! emitters inheriting from \ref BaseEmitter to emit code. CodeHolder uses
|
||
|
//! containers to manage its data:
|
||
|
//!
|
||
|
//! - \ref Section - stores information about a code or data section.
|
||
|
//! - \ref CodeBuffer - stores actual code or data, part of \ref Section.
|
||
|
//! - \ref LabelEntry - stores information about a label - its name, offset,
|
||
|
//! section where it belongs to, and other bits.
|
||
|
//! - \ref LabelLink - stores information about yet unbound label, which was
|
||
|
//! already used by the assembler.
|
||
|
//! - \ref RelocEntry - stores information about a relocation.
|
||
|
//! - \ref AddressTableEntry - stores information about an address, which was
|
||
|
//! used in a jump or call. Such address may need relocation.
|
||
|
//!
|
||
|
//! To generate code you would need to instantiate at least the following classes:
|
||
|
//!
|
||
|
//! - \ref CodeHolder - to hold code during code generation.
|
||
|
//! - \ref BaseEmitter - to emit code into \ref CodeHolder.
|
||
|
//! - \ref Target (optional) - most likely \ref JitRuntime to keep the generated
|
||
|
//! code in executable memory. \ref Target can be customized by inheriting from
|
||
|
//! it.
|
||
|
//!
|
||
|
//! There are also other core classes that are important:
|
||
|
//!
|
||
|
//! - \ref Environment - describes where the code will run. Environment brings
|
||
|
//! the concept of target triples or tuples into AsmJit, which means that users
|
||
|
//! can specify target architecture, platform, and ABI.
|
||
|
//! - \ref Type - encapsulates lightweight type functionality that can be used
|
||
|
//! to describe primitive and vector types. Types are used by higher level
|
||
|
//! utilities, for example by \ref asmjit_function and \ref asmjit_compiler.
|
||
|
//! - \ref CpuInfo - encapsulates CPU information - stores both CPU information
|
||
|
//! and features described by \ref BaseFeatures.
|
||
|
//!
|
||
|
//! AsmJit also provides global constants:
|
||
|
//!
|
||
|
//! - \ref Globals - namespace that provides global constants.
|
||
|
//! - \ref ByteOrder - byte-order constants and functionality.
|
||
|
//!
|
||
|
//! \note CodeHolder examples use \ref x86::Assembler as abstract interfaces cannot
|
||
|
//! be used to generate code.
|
||
|
//!
|
||
|
//! ### CodeHolder & Emitters
|
||
|
//!
|
||
|
//! The example below shows how the mentioned classes interact to generate X86 code:
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/x86.h>
|
||
|
//! #include <stdio.h>
|
||
|
//!
|
||
|
//! using namespace asmjit;
|
||
|
//!
|
||
|
//! // Signature of the generated function.
|
||
|
//! typedef int (*Func)(void);
|
||
|
//!
|
||
|
//! int main() {
|
||
|
//! JitRuntime rt; // Runtime specialized for JIT code execution.
|
||
|
//!
|
||
|
//! CodeHolder code; // Holds code and relocation information.
|
||
|
//! code.init(rt.environment()); // Initialize code to match the JIT environment.
|
||
|
//!
|
||
|
//! x86::Assembler a(&code); // Create and attach x86::Assembler to code.
|
||
|
//! a.mov(x86::eax, 1); // Move one to eax register.
|
||
|
//! a.ret(); // Return from function.
|
||
|
//! // ===== x86::Assembler is no longer needed from here and can be destroyed =====
|
||
|
//!
|
||
|
//! Func fn; // Holds address to the generated function.
|
||
|
//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime.
|
||
|
//! if (err) return 1; // Handle a possible error returned by AsmJit.
|
||
|
//! // ===== CodeHolder is no longer needed from here and can be destroyed =====
|
||
|
//!
|
||
|
//! int result = fn(); // Execute the generated code.
|
||
|
//! printf("%d\n", result); // Print the resulting "1".
|
||
|
//!
|
||
|
//! // All classes use RAII, all resources will be released before `main()` returns,
|
||
|
//! // the generated function can be, however, released explicitly if you intend to
|
||
|
//! // reuse or keep the runtime alive, which you should in a production-ready code.
|
||
|
//! rt.release(fn);
|
||
|
//!
|
||
|
//! return 0;
|
||
|
//! }
|
||
|
//! ```
|
||
|
//!
|
||
|
//! The example above used \ref x86::Assembler as an emitter. AsmJit provides the
|
||
|
//! following emitters that offer various levels of abstraction:
|
||
|
//!
|
||
|
//! - \ref asmjit_assembler - Low-level emitter that emits directly to \ref CodeBuffer.
|
||
|
//! - \ref asmjit_builder - Low-level emitter that emits to a \ref BaseNode list.
|
||
|
//! - \ref asmjit_compiler - High-level emitter that provides register allocation.
|
||
|
//!
|
||
|
//! ### Targets and JitRuntime
|
||
|
//!
|
||
|
//! AsmJit's \ref Target is an interface that provides basic target abstraction.
|
||
|
//! At the moment AsmJit provides only one implementation called \ref JitRuntime,
|
||
|
//! which as the name suggests provides JIT code target and execution runtime.
|
||
|
//! \ref JitRuntime provides all the necessary stuff to implement a simple JIT
|
||
|
//! compiler with basic memory management. It only provides \ref JitRuntime::add()
|
||
|
//! and \ref JitRuntime::release() functions that are used to either add code
|
||
|
//! to the runtime or release it. \ref JitRuntime doesn't do any decisions on
|
||
|
//! when the code should be released, the decision is up to the developer.
|
||
|
//!
|
||
|
//! See more at \ref asmjit_virtual_memory group.
|
||
|
//!
|
||
|
//! ### More About Environment
|
||
|
//!
|
||
|
//! In the previous example the \ref Environment is retrieved from \ref JitRuntime.
|
||
|
//! It's logical as \ref JitRuntime always returns an \ref Environment that is
|
||
|
//! compatible with the host. For example if your application runs in 64-bit mode
|
||
|
//! the \ref Environment returned will use \ref Environment::kArchX64 architecture
|
||
|
//! in contrast to \ref Environment::kArchX86, which will be used in 32-bit mode on
|
||
|
//! any X86 platform.
|
||
|
//!
|
||
|
//! AsmJit allows to setup the \ref Environment manually and to select a different
|
||
|
//! architecture and ABI when necessary. So let's do something else this time, let's
|
||
|
//! always generate a 32-bit code and print its binary representation. To do that, we
|
||
|
//! can create our own \ref Environment and initialize it to \ref Environment::kArchX86.
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/x86.h>
|
||
|
//! #include <stdio.h>
|
||
|
//!
|
||
|
//! using namespace asmjit;
|
||
|
//!
|
||
|
//! int main(int argc, char* argv[]) {
|
||
|
//! using namespace asmjit::x86;
|
||
|
//!
|
||
|
//! // Create a custom environment initialized to 32-bit X86 architecture.
|
||
|
//! Environment env;
|
||
|
//! env.setArch(Environment::kArchX86);
|
||
|
//!
|
||
|
//! CodeHolder code; // Create a CodeHolder.
|
||
|
//! code.init(env); // Initialize CodeHolder with custom environment.
|
||
|
//!
|
||
|
//! // Generate a 32-bit function that sums 4 floats and looks like:
|
||
|
//! // void func(float* dst, const float* a, const float* b)
|
||
|
//! x86::Assembler a(&code); // Create and attach x86::Assembler to `code`.
|
||
|
//!
|
||
|
//! a.mov(eax, dword_ptr(esp, 4)); // Load the destination pointer.
|
||
|
//! a.mov(ecx, dword_ptr(esp, 8)); // Load the first source pointer.
|
||
|
//! a.mov(edx, dword_ptr(esp, 12)); // Load the second source pointer.
|
||
|
//!
|
||
|
//! a.movups(xmm0, ptr(ecx)); // Load 4 floats from [ecx] to XMM0.
|
||
|
//! a.movups(xmm1, ptr(edx)); // Load 4 floats from [edx] to XMM1.
|
||
|
//! a.addps(xmm0, xmm1); // Add 4 floats in XMM1 to XMM0.
|
||
|
//! a.movups(ptr(eax), xmm0); // Store the result to [eax].
|
||
|
//! a.ret(); // Return from function.
|
||
|
//!
|
||
|
//! // We have no Runtime this time, it's on us what we do with the code.
|
||
|
//! // CodeHolder stores code in Section, which provides some basic properties
|
||
|
//! // and CodeBuffer structure. We are interested in section's CodeBuffer.
|
||
|
//! //
|
||
|
//! // NOTE: The first section is always '.text', it can be retrieved by
|
||
|
//! // code.sectionById(0) or simply by code.textSection().
|
||
|
//! CodeBuffer& buffer = code.textSection()->buffer();
|
||
|
//!
|
||
|
//! // Print the machine-code generated or do something else with it...
|
||
|
//! // 8B4424048B4C24048B5424040F28010F58010F2900C3
|
||
|
//! for (size_t i = 0; i < buffer.length; i++)
|
||
|
//! printf("%02X", buffer.data[i]);
|
||
|
//!
|
||
|
//! return 0;
|
||
|
//! }
|
||
|
//! ```
|
||
|
//!
|
||
|
//! ### Explicit Code Relocation
|
||
|
//!
|
||
|
//! In addition to \ref Environment, \ref CodeHolder can be configured to
|
||
|
//! specify a base-address (or a virtual base-address in a linker terminology),
|
||
|
//! which could be static (useful when you know the location where the target's
|
||
|
//! machine code will be) or dynamic. AsmJit assumes dynamic base-address by
|
||
|
//! default and relocates the code held by \ref CodeHolder to a user provided
|
||
|
//! address on-demand. To be able to relocate to a user provided address it needs
|
||
|
//! to store some information about relocations, which is represented by \ref
|
||
|
//! RelocEntry. Relocation entries are only required if you call external functions
|
||
|
//! from the generated code that cannot be encoded by using a 32-bit displacement
|
||
|
//! (64-bit displacements are not provided by aby supported architecture).
|
||
|
//!
|
||
|
//! There is also a concept called \ref LabelLink - label link is a lightweight
|
||
|
//! data structure that doesn't have any identifier and is stored in \ref LabelEntry
|
||
|
//! as a single-linked list. Label link represents either unbound yet used label
|
||
|
//! and cross-sections links (only relevant to code that uses multiple sections).
|
||
|
//! Since crossing sections is something that cannot be resolved immediately these
|
||
|
//! links persist until offsets of these sections are assigned and until
|
||
|
//! \ref CodeHolder::resolveUnresolvedLinks() is called. It's an error if you end
|
||
|
//! up with code that has unresolved label links after flattening. You can verify
|
||
|
//! it by calling \ref CodeHolder::hasUnresolvedLinks(), which inspects the value
|
||
|
//! returned by \ref CodeHolder::unresolvedLinkCount().
|
||
|
//!
|
||
|
//! AsmJit can flatten code that uses multiple sections by assigning each section
|
||
|
//! an incrementing offset that respects its alignment. Use \ref CodeHolder::flatten()
|
||
|
//! to do that. After the sections are flattened their offsets and virtual-sizes
|
||
|
//! are adjusted to respect each section's buffer size and alignment. The \ref
|
||
|
//! CodeHolder::resolveUnresolvedLinks() function must be called before relocating
|
||
|
//! the code held by \ref CodeHolder. You can also flatten your code manually by
|
||
|
//! iterating over all sections and calculating their offsets (relative to base)
|
||
|
//! by your own algorithm. In that case \ref CodeHolder::flatten() should not be
|
||
|
//! called, however, \ref CodeHolder::resolveUnresolvedLinks() should be.
|
||
|
//!
|
||
|
//! The example below shows how to use a built-in virtual memory allocator
|
||
|
//! \ref JitAllocator instead of using \ref JitRuntime (just in case you want
|
||
|
//! to use your own memory management) and how to relocate the generated code
|
||
|
//! into your own memory block - you can use your own virtual memory allocator
|
||
|
//! if you prefer that, but that's OS specific and not covered by the documentation.
|
||
|
//!
|
||
|
//! The following code is similar to the previous one, but implements a function
|
||
|
//! working in both 32-bit and 64-bit environments:
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/x86.h>
|
||
|
//! #include <stdio.h>
|
||
|
//!
|
||
|
//! using namespace asmjit;
|
||
|
//!
|
||
|
//! typedef void (*SumIntsFunc)(int* dst, const int* a, const int* b);
|
||
|
//!
|
||
|
//! int main() {
|
||
|
//! // Create a custom environment that matches the current host environment.
|
||
|
//! Environment env = hostEnvironment();
|
||
|
//!
|
||
|
//! CodeHolder code; // Create a CodeHolder.
|
||
|
//! code.init(env); // Initialize CodeHolder with environment.
|
||
|
//!
|
||
|
//! x86::Assembler a(&code); // Create and attach x86::Assembler to `code`.
|
||
|
//!
|
||
|
//! // Signature: 'void func(int* dst, const int* a, const int* b)'.
|
||
|
//! x86::Gp dst;
|
||
|
//! x86::Gp src_a;
|
||
|
//! x86::Gp src_b;
|
||
|
//!
|
||
|
//! // Handle the difference between 32-bit and 64-bit calling conventions
|
||
|
//! // (arguments passed through stack vs. arguments passed by registers).
|
||
|
//! if (env.is32Bit()) {
|
||
|
//! dst = x86::eax;
|
||
|
//! src_a = x86::ecx;
|
||
|
//! src_b = x86::edx;
|
||
|
//! a.mov(dst , x86::dword_ptr(x86::esp, 4));
|
||
|
//! a.mov(src_a, x86::dword_ptr(x86::esp, 8));
|
||
|
//! a.mov(src_b, x86::dword_ptr(x86::esp, 12));
|
||
|
//! }
|
||
|
//! else {
|
||
|
//! if (env.isPlatformWindows()) {
|
||
|
//! dst = x86::rcx; // First argument (destination pointer).
|
||
|
//! src_a = x86::rdx; // Second argument (source 'a' pointer).
|
||
|
//! src_b = x86::r8; // Third argument (source 'b' pointer).
|
||
|
//! }
|
||
|
//! else {
|
||
|
//! dst = x86::rdi; // First argument (destination pointer).
|
||
|
//! src_a = x86::rsi; // Second argument (source 'a' pointer).
|
||
|
//! src_b = x86::rdx; // Third argument (source 'b' pointer).
|
||
|
//! }
|
||
|
//! }
|
||
|
//!
|
||
|
//! a.movdqu(x86::xmm0, x86::ptr(src_a)); // Load 4 ints from [src_a] to XMM0.
|
||
|
//! a.movdqu(x86::xmm1, x86::ptr(src_b)); // Load 4 ints from [src_b] to XMM1.
|
||
|
//! a.paddd(x86::xmm0, x86::xmm1); // Add 4 ints in XMM1 to XMM0.
|
||
|
//! a.movdqu(x86::ptr(dst), x86::xmm0); // Store the result to [dst].
|
||
|
//! a.ret(); // Return from function.
|
||
|
//!
|
||
|
//! // Even when we didn't use multiple sections AsmJit could insert one section
|
||
|
//! // called '.addrtab' (address table section), which would be filled by data
|
||
|
//! // required by relocations (absolute jumps and calls). You can omit this code
|
||
|
//! // if you are 100% sure your code doesn't contain multiple sections and
|
||
|
//! // such relocations. You can use `CodeHolder::hasAddressTable()` to verify
|
||
|
//! // whether the address table section does exist.
|
||
|
//! code.flatten();
|
||
|
//! code.resolveUnresolvedLinks();
|
||
|
//!
|
||
|
//! // After the code was generated it can be relocated manually to any memory
|
||
|
//! // location, however, we need to know it's size before we perform memory
|
||
|
//! // allocation. `CodeHolder::codeSize()` returns the worst estimated code
|
||
|
//! // size in case that relocations are not possible without trampolines (in
|
||
|
//! // that case some extra code at the end of the current code buffer is
|
||
|
//! // generated during relocation).
|
||
|
//! size_t estimatedSize = code.codeSize();
|
||
|
//!
|
||
|
//! // Instead of rolling up our own memory allocator we can use the one AsmJit
|
||
|
//! // provides. It's decoupled so you don't need to use `JitRuntime` for that.
|
||
|
//! JitAllocator allocator;
|
||
|
//!
|
||
|
//! // Allocate an executable virtual memory and handle a possible failure.
|
||
|
//! void* p = allocator.alloc(estimatedSize);
|
||
|
//! if (!p)
|
||
|
//! return 0;
|
||
|
//!
|
||
|
//! // Now relocate the code to the address provided by the memory allocator.
|
||
|
//! // Please note that this DOESN'T COPY anything to `p`. This function will
|
||
|
//! // store the address in CodeHolder and use relocation entries to patch the
|
||
|
//! // existing code in all sections to respect the base address provided.
|
||
|
//! code.relocateToBase((uint64_t)p);
|
||
|
//!
|
||
|
//! // This is purely optional. There are cases in which the relocation can omit
|
||
|
//! // unneeded data, which would shrink the size of address table. If that
|
||
|
//! // happened the codeSize returned after relocateToBase() would be smaller
|
||
|
//! // than the originally `estimatedSize`.
|
||
|
//! size_t codeSize = code.codeSize();
|
||
|
//!
|
||
|
//! // This will copy code from all sections to `p`. Iterating over all sections
|
||
|
//! // and calling `memcpy()` would work as well, however, this function supports
|
||
|
//! // additional options that can be used to also zero pad sections' virtual
|
||
|
//! // size, etc.
|
||
|
//! //
|
||
|
//! // With some additional features, copyFlattenData() does roughly this:
|
||
|
//! // for (Section* section : code.sections())
|
||
|
//! // memcpy((uint8_t*)p + section->offset(),
|
||
|
//! // section->data(),
|
||
|
//! // section->bufferSize());
|
||
|
//! code.copyFlattenedData(p, codeSize, CodeHolder::kCopyPadSectionBuffer);
|
||
|
//!
|
||
|
//! // Execute the generated function.
|
||
|
//! int inA[4] = { 4, 3, 2, 1 };
|
||
|
//! int inB[4] = { 1, 5, 2, 8 };
|
||
|
//! int out[4];
|
||
|
//!
|
||
|
//! // This code uses AsmJit's ptr_as_func<> to cast between void* and SumIntsFunc.
|
||
|
//! ptr_as_func<SumIntsFunc>(p)(out, inA, inB);
|
||
|
//!
|
||
|
//! // Prints {5 8 4 9}
|
||
|
//! printf("{%d %d %d %d}\n", out[0], out[1], out[2], out[3]);
|
||
|
//!
|
||
|
//! // Release 'p' is it's no longer needed. It will be destroyed with 'vm'
|
||
|
//! // instance anyway, but it's a good practice to release it explicitly
|
||
|
//! // when you know that the function will not be needed anymore.
|
||
|
//! allocator.release(p);
|
||
|
//!
|
||
|
//! return 0;
|
||
|
//! }
|
||
|
//! ```
|
||
|
//!
|
||
|
//! If you know the base-address in advance (before the code generation) it can
|
||
|
//! be passed as a second argument to \ref CodeHolder::init(). In that case the
|
||
|
//! Assembler will know the absolute position of each instruction and would be
|
||
|
//! able to use it during instruction encoding to prevent relocations where
|
||
|
//! possible. The following example shows how to configure the base address:
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/x86.h>
|
||
|
//! #include <stdio.h>
|
||
|
//!
|
||
|
//! void initializeCodeHolder(CodeHolder& code) {
|
||
|
//! Environment env = hostEnvironment();
|
||
|
//! uint64_t baseAddress = uint64_t(0x1234);
|
||
|
//!
|
||
|
//! // initialize CodeHolder with environment and custom base address.
|
||
|
//! code.init(env, baseAddress);
|
||
|
//! }
|
||
|
//! ```
|
||
|
//!
|
||
|
//! ### Label Offsets and Links
|
||
|
//!
|
||
|
//! When a label that is not yet bound is used by the Assembler, it creates a
|
||
|
//! \ref LabelLink, which is then added to a \ref LabelEntry. These links are
|
||
|
//! also created if a label is used in a different section than in which it
|
||
|
//! was bound. Let's examine some functions that can be used to check whether
|
||
|
//! there are any unresolved links.
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/core.h>
|
||
|
//! #include <stdio.h>
|
||
|
//!
|
||
|
//! void labelLinksExample(CodeHolder& code, const Label& label) {
|
||
|
//! // Tests whether the `label` is bound.
|
||
|
//! bool isBound = code.isLabelBound(label);
|
||
|
//! printf("Label %u is %s\n", label.id(), isBound ? "bound" : "not bound");
|
||
|
//!
|
||
|
//! // Returns true if the code contains either referenced, but unbound
|
||
|
//! // labels, or cross-section label links that are not resolved yet.
|
||
|
//! bool hasUnresolved = code.hasUnresolvedLinks(); // Boolean answer.
|
||
|
//! size_t nUnresolved = code.unresolvedLinkCount(); // Count of unresolved links.
|
||
|
//!
|
||
|
//! printf("Number of unresolved links: %zu\n", nUnresolved);
|
||
|
//! }
|
||
|
//! ```
|
||
|
//!
|
||
|
//! There is no function that would return the number of unbound labels as this
|
||
|
//! is completely unimportant from CodeHolder's perspective. If a label is not
|
||
|
//! used then it doesn't matter whether it's bound or not, only actually used
|
||
|
//! labels matter. After a Label is bound it's possible to query its offset
|
||
|
//! offset relative to the start of the section where it was bound:
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/core.h>
|
||
|
//! #include <stdio.h>
|
||
|
//!
|
||
|
//! void labelOffsetExample(CodeHolder& code, const Label& label) {
|
||
|
//! // Label offset is known after it's bound. The offset provided is relative
|
||
|
//! // to the start of the section, see below for alternative. If the given
|
||
|
//! // label is not bound the offset returned will be zero. It's recommended
|
||
|
//! // to always check whether the label is bound before using its offset.
|
||
|
//! uint64_t sectionOffset = code.labelOffset(label);
|
||
|
//! printf("Label offset relative to section: %llu\n", (unsigned long long)sectionOffset);
|
||
|
//!
|
||
|
//! // If you use multiple sections and want the offset relative to the base.
|
||
|
//! // NOTE: This function expects that the section has already an offset and
|
||
|
//! // the label-link was resolved (if this is not true you will still get an
|
||
|
//! // offset relative to the start of the section).
|
||
|
//! uint64_t baseOffset = code.labelOffsetFromBase(label);
|
||
|
//! printf("Label offset relative to base: %llu\n", (unsigned long long)baseOffset);
|
||
|
//! }
|
||
|
//! ```
|
||
|
//!
|
||
|
//! ### Sections
|
||
|
//!
|
||
|
//! AsmJit allows to create multiple sections within the same \ref CodeHolder.
|
||
|
//! A test-case [asmjit_test_x86_sections.cpp](https://github.com/asmjit/asmjit/blob/master/test/asmjit_test_x86_sections.cpp)
|
||
|
//! can be used as a reference point although the following example should
|
||
|
//! also provide a useful insight:
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/x86.h>
|
||
|
//! #include <stdio.h>
|
||
|
//!
|
||
|
//! void sectionsExample(CodeHolder& code) {
|
||
|
//! // Text section is always provided as the first section.
|
||
|
//! Section* text = code.textSection(); // or code.sectionById(0);
|
||
|
//!
|
||
|
//! // To create another section use CodeHolder::newSection().
|
||
|
//! Section* data;
|
||
|
//! Error err = code.newSection(&data,
|
||
|
//! ".data", // Section name
|
||
|
//! SIZE_MAX, // Name length if the name is not null terminated (or SIZE_MAX).
|
||
|
//! 0, // Section flags, see Section::Flags.
|
||
|
//! 8, // Section alignment, must be power of 2.
|
||
|
//! 0); // Section order value (optional, default 0).
|
||
|
//!
|
||
|
//! // When you switch sections in Assembler, Builder, or Compiler the cursor
|
||
|
//! // will always move to the end of that section. When you create an Assembler
|
||
|
//! // the cursor would be placed at the end of the first (.text) section, which
|
||
|
//! // is initially empty.
|
||
|
//! x86::Assembler a(&code);
|
||
|
//! Label L_Data = a.newLabel();
|
||
|
//!
|
||
|
//! a.mov(x86::eax, x86::ebx); // Emits in .text section.
|
||
|
//!
|
||
|
//! a.section(data); // Switches to the end of .data section.
|
||
|
//! a.bind(L_Data); // Binds label in this .data section
|
||
|
//! a.db(0x01); // Emits byte in .data section.
|
||
|
//!
|
||
|
//! a.section(text); // Switches to the end of .text section.
|
||
|
//! a.add(x86::ebx, x86::eax); // Emits in .text section.
|
||
|
//!
|
||
|
//! // References a label in .text section, which was bound in .data section.
|
||
|
//! // This would create a LabelLink even when the L_Data is already bound,
|
||
|
//! // because the reference crosses sections. See below...
|
||
|
//! a.lea(x86::rsi, x86::ptr(L_Data));
|
||
|
//! }
|
||
|
//! ```
|
||
|
//!
|
||
|
//! The last line in the example above shows that a LabelLink would be created
|
||
|
//! even for bound labels that cross sections. In this case a referenced label
|
||
|
//! was bound in another section, which means that the link couldn't be resolved
|
||
|
//! at that moment. If your code uses sections, but you wish AsmJit to flatten
|
||
|
//! these sections (you don't plan to flatten them manually) then there is an
|
||
|
//! API for that.
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/x86.h>
|
||
|
//! #include <stdio.h>
|
||
|
//!
|
||
|
//! // ... (continuing the previous example) ...
|
||
|
//! void sectionsExampleContinued(CodeHolder& code) {
|
||
|
//! // Suppose we have some code that contains multiple sections and
|
||
|
//! // we would like to flatten it by using AsmJit's built-in API:
|
||
|
//! Error err = code.flatten();
|
||
|
//! if (err) {
|
||
|
//! // There are many reasons it can fail, so always handle a possible error.
|
||
|
//! printf("Failed to flatten the code: %s\n", DebugUtils::errorAsString(err));
|
||
|
//! exit(1);
|
||
|
//! }
|
||
|
//!
|
||
|
//! // After flattening all sections would contain assigned offsets
|
||
|
//! // relative to base. Offsets are 64-bit unsigned integers so we
|
||
|
//! // cast them to `size_t` for simplicity. On 32-bit targets it's
|
||
|
//! // guaranteed that the offset cannot be greater than `2^32 - 1`.
|
||
|
//! printf("Data section offset %zu", size_t(data->offset()));
|
||
|
//!
|
||
|
//! // The flattening doesn't resolve unresolved label links, this
|
||
|
//! // has to be done manually as flattening can be done separately.
|
||
|
//! err = code.resolveUnresolvedLinks();
|
||
|
//! if (err) {
|
||
|
//! // This is the kind of error that should always be handled...
|
||
|
//! printf("Failed to resolve label links: %s\n", DebugUtils::errorAsString(err));
|
||
|
//! exit(1);
|
||
|
//! }
|
||
|
//!
|
||
|
//! if (code.hasUnresolvedLinks()) {
|
||
|
//! // This would mean either unbound label or some other issue.
|
||
|
//! printf("The code has %zu unbound labels\n", code.unresovedLinkCount());
|
||
|
//! exit(1);
|
||
|
//! }
|
||
|
//! }
|
||
|
//! ```
|
||
|
|
||
|
// ============================================================================
|
||
|
// [Documentation - asmjit_assembler]
|
||
|
// ============================================================================
|
||
|
|
||
|
//! \defgroup asmjit_assembler Assembler
|
||
|
//! \brief Assembler interface and operands.
|
||
|
//!
|
||
|
//! ### Overview
|
||
|
//!
|
||
|
//! AsmJit's Assembler is used to emit machine code directly into a \ref
|
||
|
//! CodeBuffer. In general, code generation with assembler requires the knowledge
|
||
|
//! of the following:
|
||
|
//!
|
||
|
//! - \ref BaseAssembler and architecture-specific assemblers:
|
||
|
//! - \ref x86::Assembler - Assembler specific to X86 architecture
|
||
|
//! - \ref Operand and its variations:
|
||
|
//! - \ref BaseReg - Base class for a register operand, inherited by:
|
||
|
//! - \ref x86::Reg - Register operand specific to X86 architecture.
|
||
|
//! - \ref BaseMem - Base class for a memory operand, inherited by:
|
||
|
//! - \ref x86::Mem - Memory operand specific to X86 architecture.
|
||
|
//! - \ref Imm - Immediate (value) operand.
|
||
|
//! - \ref Label - Label operand.
|
||
|
//!
|
||
|
//! \note Assembler examples use \ref x86::Assembler as abstract interfaces cannot
|
||
|
//! be used to generate code.
|
||
|
//!
|
||
|
//! ### Operand Basics
|
||
|
//!
|
||
|
//! Let's start with operands. \ref Operand is a data structure that defines a
|
||
|
//! data layout of any operand. It can be inherited, but any class inheriting
|
||
|
//! it cannot add any members to it, only the existing layout can be reused.
|
||
|
//! AsmJit allows to construct operands dynamically, to store them, and to query
|
||
|
//! a complete information about them at run-time. Operands are small (always 16
|
||
|
//! bytes per \ref Operand) and can be copied and passed by value. Please never
|
||
|
//! allocate individual operands dynamically by using a `new` keyword - it would
|
||
|
//! work, but then you would have to be responsible for deleting such operands.
|
||
|
//! In AsmJit operands are always part of some other data structures like \ref
|
||
|
//! InstNode, which is part of \ref asmjit_builder tool.
|
||
|
//!
|
||
|
//! Operands contain only identifiers, but not pointers to any code-generation data.
|
||
|
//! For example \ref Label operand only provides label identifier, but not a pointer
|
||
|
//! to \ref LabelEntry structure. In AsmJit such IDs are used to link stuff together
|
||
|
//! without having to deal with pointers.
|
||
|
//!
|
||
|
//! AsmJit's operands all inherit from a base class called \ref Operand. Operands
|
||
|
//! have the following properties that are commonly accessible by getters and setters:
|
||
|
//!
|
||
|
//! - \ref Operand - Base operand, which only provides accessors that are common
|
||
|
//! to all operand types.
|
||
|
//! - \ref BaseReg - Describes either physical or virtual register. Physical
|
||
|
//! registers have id that matches the target's machine id directly whereas
|
||
|
//! virtual registers must be allocated into physical registers by a register
|
||
|
//! allocator pass. Register operand provides:
|
||
|
//! - Register Type - Unique id that describes each possible register provided
|
||
|
//! by the target architecture - for example X86 backend provides \ref
|
||
|
//! x86::Reg::RegType, which defines all variations of general purpose registers
|
||
|
//! (GPB-LO, GPB-HI, GPW, GPD, and GPQ) and all types of other registers like K,
|
||
|
//! MM, BND, XMM, YMM, and ZMM.
|
||
|
//! - Register Group - Groups multiple register types under a single group - for
|
||
|
//! example all general-purpose registers (of all sizes) on X86 are part of
|
||
|
//! \ref x86::Reg::kGroupGp and all SIMD registers (XMM, YMM, ZMM) are part
|
||
|
//! of \ref x86::Reg::kGroupVec.
|
||
|
//! - Register Size - Contains the size of the register in bytes. If the size
|
||
|
//! depends on the mode (32-bit vs 64-bit) then generally the higher size is
|
||
|
//! used (for example RIP register has size 8 by default).
|
||
|
//! - Register Id - Contains physical or virtual id of the register.
|
||
|
//! - \ref BaseMem - Used to reference a memory location. Memory operand provides:
|
||
|
//! - Base Register - A base register type and id (physical or virtual).
|
||
|
//! - Index Register - An index register type and id (physical or virtual).
|
||
|
//! - Offset - Displacement or absolute address to be referenced (32-bit if base
|
||
|
//! register is used and 64-bit if base register is not used).
|
||
|
//! - Flags that can describe various architecture dependent information (like
|
||
|
//! scale and segment-override on X86).
|
||
|
//! - \ref Imm - Immediate values are usually part of instructions (encoded within
|
||
|
//! the instruction itself) or data.
|
||
|
//! - \ref Label - used to reference a location in code or data. Labels must be
|
||
|
//! created by the \ref BaseEmitter or by \ref CodeHolder. Each label has its
|
||
|
//! unique id per \ref CodeHolder instance.
|
||
|
//!
|
||
|
//! ### Operand Manipulation
|
||
|
//!
|
||
|
//! AsmJit allows to construct operands dynamically, to store them, and to query
|
||
|
//! a complete information about them at run-time. Operands are small (always 16
|
||
|
//! bytes per `Operand`) and should be always copied (by value) if you intend to
|
||
|
//! store them (don't create operands by using `new` keyword, it's not recommended).
|
||
|
//! Operands are safe to be passed to `memcpy()` and `memset()`, which becomes
|
||
|
//! handy when working with arrays of operands. If you set all members of an \ref
|
||
|
//! Operand to zero the operand would become NONE operand, which is the same as a
|
||
|
//! default constructed Operand.
|
||
|
//!
|
||
|
//! The example below illustrates how operands can be used and modified even
|
||
|
//! without using any other code generation classes. The example uses X86
|
||
|
//! architecture-specific operands.
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/x86.h>
|
||
|
//!
|
||
|
//! using namespace asmjit;
|
||
|
//!
|
||
|
//! // Registers can be copied, it's a common practice.
|
||
|
//! x86::Gp dstRegByValue() { return x86::ecx; }
|
||
|
//!
|
||
|
//! void usingOperandsExample(x86::Assembler& a) {
|
||
|
//! // Gets `ecx` register returned by a function.
|
||
|
//! x86::Gp dst = dstRegByValue();
|
||
|
//! // Gets `rax` register directly from the provided `x86` namespace.
|
||
|
//! x86::Gp src = x86::rax;
|
||
|
//! // Constructs `r10` dynamically.
|
||
|
//! x86::Gp idx = x86::gpq(10);
|
||
|
//! // Constructs [src + idx] memory address - referencing [rax + r10].
|
||
|
//! x86::Mem m = x86::ptr(src, idx);
|
||
|
//!
|
||
|
//! // Examine `m`: Returns `x86::Reg::kTypeGpq`.
|
||
|
//! m.indexType();
|
||
|
//! // Examine `m`: Returns 10 (`r10`).
|
||
|
//! m.indexId();
|
||
|
//!
|
||
|
//! // Reconstruct `idx` stored in mem:
|
||
|
//! x86::Gp idx_2 = x86::Gp::fromTypeAndId(m.indexType(), m.indexId());
|
||
|
//!
|
||
|
//! // True, `idx` and idx_2` are identical.
|
||
|
//! idx == idx_2;
|
||
|
//!
|
||
|
//! // Possible - op will still be the same as `m`.
|
||
|
//! Operand op = m;
|
||
|
//! // True (can be casted to BaseMem or architecture-specific Mem).
|
||
|
//! op.isMem();
|
||
|
//!
|
||
|
//! // True, `op` is just a copy of `m`.
|
||
|
//! m == op;
|
||
|
//!
|
||
|
//! // Static cast is fine and valid here.
|
||
|
//! static_cast<BaseMem&>(op).addOffset(1);
|
||
|
//! // However, using `as<T>()` to cast to a derived type is preferred.
|
||
|
//! op.as<BaseMem>().addOffset(1);
|
||
|
//! // False, `op` now points to [rax + r10 + 2], which is not [rax + r10].
|
||
|
//! m == op;
|
||
|
//!
|
||
|
//! // Emitting 'mov' - type safe way.
|
||
|
//! a.mov(dst, m);
|
||
|
//! // Not possible, `mov` doesn't provide mov(x86::Gp, Operand) overload.
|
||
|
//! a.mov(dst, op);
|
||
|
//!
|
||
|
//! // Type-unsafe, but possible.
|
||
|
//! a.emit(x86::Inst::kIdMov, dst, m);
|
||
|
//! // Also possible, `emit()` is typeless and can be used with raw Operand.
|
||
|
//! a.emit(x86::Inst::kIdMov, dst, op);
|
||
|
//! }
|
||
|
//! ```
|
||
|
//!
|
||
|
//! Some operands have to be created explicitly by emitters. For example labels
|
||
|
//! must be created by \ref BaseEmitter::newLabel(), which creates a label entry
|
||
|
//! and returns a \ref Label operand with the id that refers to it. Such label
|
||
|
//! then can be used by emitters.
|
||
|
//!
|
||
|
//! ### Memory Operands
|
||
|
//!
|
||
|
//! Some architectures like X86 provide a complex memory addressing model that
|
||
|
//! allows to encode addresses having a BASE register, INDEX register with a
|
||
|
//! possible scale (left shift), and displacement (called offset in AsmJit).
|
||
|
//! Memory address on X86 can also specify memory segment (segment-override in
|
||
|
//! X86 terminology) and some instructions (gather / scatter) require INDEX to
|
||
|
//! be a \ref x86::Vec register instead of a general-purpose register.
|
||
|
//!
|
||
|
//! AsmJit allows to encode and work with all forms of addresses mentioned and
|
||
|
//! implemented by X86. In addition, it also allows to construct absolute 64-bit
|
||
|
//! memory address operands, which is only allowed in one form of 'mov' instruction.
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/x86.h>
|
||
|
//!
|
||
|
//! using namespace asmjit;
|
||
|
//!
|
||
|
//! void testX86Mem() {
|
||
|
//! // Makes it easier to access x86 stuff...
|
||
|
//! using namespace asmjit::x86;
|
||
|
//!
|
||
|
//! // BASE + OFFSET.
|
||
|
//! Mem a = ptr(rax); // a = [rax]
|
||
|
//! Mem b = ptr(rax, 15); // b = [rax + 15]
|
||
|
//!
|
||
|
//! // BASE + INDEX << SHIFT - Shift is in BITS as used by X86!
|
||
|
//! Mem c = ptr(rax, rbx); // c = [rax + rbx]
|
||
|
//! Mem d = ptr(rax, rbx, 2); // d = [rax + rbx << 2]
|
||
|
//! Mem e = ptr(rax, rbx, 2, 15); // e = [rax + rbx << 2 + 15]
|
||
|
//!
|
||
|
//! // BASE + VM (Vector Index) (encoded as MOD+VSIB).
|
||
|
//! Mem f = ptr(rax, xmm1); // f = [rax + xmm1]
|
||
|
//! Mem g = ptr(rax, xmm1, 2); // g = [rax + xmm1 << 2]
|
||
|
//! Mem h = ptr(rax, xmm1, 2, 15); // h = [rax + xmm1 << 2 + 15]
|
||
|
//!
|
||
|
//! // Absolute adddress:
|
||
|
//! uint64_t addr = (uint64_t)0x1234;
|
||
|
//! Mem i = ptr(addr); // i = [0x1234]
|
||
|
//! Mem j = ptr(addr, rbx); // j = [0x1234 + rbx]
|
||
|
//! Mem k = ptr(addr, rbx, 2); // k = [0x1234 + rbx << 2]
|
||
|
//!
|
||
|
//! // LABEL - Will be encoded as RIP (64-bit) or absolute address (32-bit).
|
||
|
//! Label L = ...;
|
||
|
//! Mem m = ptr(L); // m = [L]
|
||
|
//! Mem n = ptr(L, rbx); // n = [L + rbx]
|
||
|
//! Mem o = ptr(L, rbx, 2); // o = [L + rbx << 2]
|
||
|
//! Mem p = ptr(L, rbx, 2, 15); // p = [L + rbx << 2 + 15]
|
||
|
//!
|
||
|
//! // RIP - 64-bit only (RIP can't use INDEX).
|
||
|
//! Mem q = ptr(rip, 24); // q = [rip + 24]
|
||
|
//! }
|
||
|
//! ```
|
||
|
//!
|
||
|
//! Memory operands can optionally contain memory size. This is required by
|
||
|
//! instructions where the memory size cannot be deduced from other operands,
|
||
|
//! like `inc` and `dec` on X86:
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/x86.h>
|
||
|
//!
|
||
|
//! using namespace asmjit;
|
||
|
//!
|
||
|
//! void testX86Mem() {
|
||
|
//! // The same as: dword ptr [rax + rbx].
|
||
|
//! x86::Mem a = x86::dword_ptr(rax, rbx);
|
||
|
//!
|
||
|
//! // The same as: qword ptr [rdx + rsi << 0 + 1].
|
||
|
//! x86::Mem b = x86::qword_ptr(rdx, rsi, 0, 1);
|
||
|
//! }
|
||
|
//! ```
|
||
|
//!
|
||
|
//! Memory operands provide API that can be used to access its properties:
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/x86.h>
|
||
|
//!
|
||
|
//! using namespace asmjit;
|
||
|
//!
|
||
|
//! void testX86Mem() {
|
||
|
//! // The same as: dword ptr [rax + 12].
|
||
|
//! x86::Mem mem = x86::dword_ptr(rax, 12);
|
||
|
//!
|
||
|
//! mem.hasBase(); // true.
|
||
|
//! mem.hasIndex(); // false.
|
||
|
//! mem.size(); // 4.
|
||
|
//! mem.offset(); // 12.
|
||
|
//!
|
||
|
//! mem.setSize(0); // Sets the size to 0 (makes it sizeless).
|
||
|
//! mem.addOffset(-1); // Adds -1 to the offset and makes it 11.
|
||
|
//! mem.setOffset(0); // Sets the offset to 0.
|
||
|
//! mem.setBase(rcx); // Changes BASE to RCX.
|
||
|
//! mem.setIndex(rax); // Changes INDEX to RAX.
|
||
|
//! mem.hasIndex(); // true.
|
||
|
//! }
|
||
|
//! // ...
|
||
|
//! ```
|
||
|
//!
|
||
|
//! Making changes to memory operand is very comfortable when emitting loads
|
||
|
//! and stores:
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/x86.h>
|
||
|
//!
|
||
|
//! using namespace asmjit;
|
||
|
//!
|
||
|
//! void testX86Mem(CodeHolder& code) {
|
||
|
//! x86::Assembler a(code); // Your initialized x86::Assembler.
|
||
|
//! x86::Mem mSrc = x86::ptr(eax); // Construct [eax] memory operand.
|
||
|
//!
|
||
|
//! // One way of emitting bunch of loads is to use `mem.adjusted()`, which
|
||
|
//! // returns a new memory operand and keeps the source operand unchanged.
|
||
|
//! a.movaps(x86::xmm0, mSrc); // No adjustment needed to load [eax].
|
||
|
//! a.movaps(x86::xmm1, mSrc.adjusted(16)); // Loads from [eax + 16].
|
||
|
//! a.movaps(x86::xmm2, mSrc.adjusted(32)); // Loads from [eax + 32].
|
||
|
//! a.movaps(x86::xmm3, mSrc.adjusted(48)); // Loads from [eax + 48].
|
||
|
//!
|
||
|
//! // ... do something with xmm0-3 ...
|
||
|
//!
|
||
|
//! // Another way of adjusting memory is to change the operand in-place.
|
||
|
//! // If you want to keep the original operand you can simply clone it.
|
||
|
//! x86::Mem mDst = mSrc.clone(); // Clone mSrc.
|
||
|
//!
|
||
|
//! a.movaps(mDst, x86::xmm0); // Stores xmm0 to [eax].
|
||
|
//! mDst.addOffset(16); // Adds 16 to `mDst`.
|
||
|
//!
|
||
|
//! a.movaps(mDst, x86::xmm1); // Stores to [eax + 16] .
|
||
|
//! mDst.addOffset(16); // Adds 16 to `mDst`.
|
||
|
//!
|
||
|
//! a.movaps(mDst, x86::xmm2); // Stores to [eax + 32].
|
||
|
//! mDst.addOffset(16); // Adds 16 to `mDst`.
|
||
|
//!
|
||
|
//! a.movaps(mDst, x86::xmm3); // Stores to [eax + 48].
|
||
|
//! }
|
||
|
//! ```
|
||
|
//!
|
||
|
//! ### Assembler Examples
|
||
|
//!
|
||
|
//! - \ref x86::Assembler provides many X86/X64 examples.
|
||
|
|
||
|
// ============================================================================
|
||
|
// [Documentation - asmjit_builder]
|
||
|
// ============================================================================
|
||
|
|
||
|
//! \defgroup asmjit_builder Builder
|
||
|
//! \brief Builder interface, nodes, and passes.
|
||
|
//!
|
||
|
//! ### Overview
|
||
|
//!
|
||
|
//! Both \ref BaseBuilder and \ref BaseCompiler interfaces describe emitters
|
||
|
//! that emit into a representation that allows further processing. The code
|
||
|
//! stored in such representation is completely safe to be patched, simplified,
|
||
|
//! reordered, obfuscated, removed, injected, analyzed, or processed some other
|
||
|
//! way. Each instruction, label, directive, or other building block is stored
|
||
|
//! as \ref BaseNode (or derived class like \ref InstNode or \ref LabelNode)
|
||
|
//! and contains all the information necessary to pass that node later to the
|
||
|
//! assembler.
|
||
|
//!
|
||
|
//! \ref BaseBuilder is an emitter that inherits from \ref BaseEmitter interface.
|
||
|
//! It was designed to provide a maximum compatibility with the existing \ref
|
||
|
//! BaseAssembler emitter so users can move from assembler to builder when needed,
|
||
|
//! for example to implement post-processing, which is not possible with Assembler.
|
||
|
//!
|
||
|
//! ### Builder Nodes
|
||
|
//!
|
||
|
//! \ref BaseBuilder doesn't generate machine code directly, it uses an intermediate
|
||
|
//! representation based on nodes, however, it allows to serialize to \ref BaseAssembler
|
||
|
//! when the code is ready to be encoded.
|
||
|
//!
|
||
|
//! There are multiple node types used by both \ref BaseBuilder and \ref BaseCompiler :
|
||
|
//!
|
||
|
//! - Basic nodes:
|
||
|
//! - \ref BaseNode - Base class for all nodes.
|
||
|
//! - \ref InstNode - Represents an instruction node.
|
||
|
//! - \ref AlignNode - Represents an alignment directive (.align).
|
||
|
//! - \ref LabelNode - Represents a location where to bound a \ref Label.
|
||
|
//!
|
||
|
//! - Data nodes:
|
||
|
//! - \ref EmbedDataNode - Represents data.
|
||
|
//! - \ref EmbedLabelNode - Represents \ref Label address embedded as data.
|
||
|
//! - \ref EmbedLabelDeltaNode - Represents a difference of two labels
|
||
|
//! embedded in data.
|
||
|
//! - \ref ConstPoolNode - Represents a constant pool data embedded as data.
|
||
|
//!
|
||
|
//! - Informative nodes:
|
||
|
//! - \ref CommentNode - Represents a comment string, doesn't affect code
|
||
|
//! generation.
|
||
|
//! - \ref SentinelNode - A marker that can be used to remember certain
|
||
|
//! position in code or data, doesn't affect code generation. Used by
|
||
|
//! \ref FuncNode to mark the end of a function.
|
||
|
//!
|
||
|
//! - Other nodes are provided by \ref asmjit_compiler infrastructure.
|
||
|
//!
|
||
|
//! ### Builder Examples
|
||
|
//!
|
||
|
//! - \ref x86::Builder provides many X86/X64 examples.
|
||
|
|
||
|
// ============================================================================
|
||
|
// [Documentation - asmjit_compiler]
|
||
|
// ============================================================================
|
||
|
|
||
|
//! \defgroup asmjit_compiler Compiler
|
||
|
//! \brief Compiler interface.
|
||
|
//!
|
||
|
//! ### Overview
|
||
|
//!
|
||
|
//! \ref BaseCompiler is a high-level interface built on top of \ref BaseBuilder
|
||
|
//! interface, which provides register allocation and support for defining and
|
||
|
//! invoking functions. At the moment it's the easiest way of generating code
|
||
|
//! in AsmJit as most architecture and OS specifics is properly abstracted and
|
||
|
//! handled by AsmJit automatically. However, abstractions also mean restrictions,
|
||
|
//! which means that \ref BaseCompiler has more limitations than \ref BaseAssembler
|
||
|
//! or \ref BaseBuilder.
|
||
|
//!
|
||
|
//! Since \ref BaseCompiler provides register allocation it also establishes the
|
||
|
//! concept of functions - a function in Compiler sense is a unit in which virtual
|
||
|
//! registers are allocated into physical registers by the register allocator.
|
||
|
//! In addition, it enables to use such virtual registers in function invocations.
|
||
|
//!
|
||
|
//! \ref BaseCompiler automatically handles function calling conventions. It's
|
||
|
//! still architecture dependent, but makes the code generation much easies.
|
||
|
//! Functions are essential; the first-step to generate some code is to define a
|
||
|
//! signature of the function to be generated (before generating the function body
|
||
|
//! itself). Function arguments and return value(s) are handled by assigning
|
||
|
//! virtual registers to them. Similarly, function calls are handled the same way.
|
||
|
//!
|
||
|
//! ### Compiler Nodes
|
||
|
//!
|
||
|
//! \ref BaseCompiler adds some nodes that are required for function generation
|
||
|
//! and invocation:
|
||
|
//!
|
||
|
//! - \ref FuncNode - Represents a function definition.
|
||
|
//! - \ref FuncRetNode - Represents a function return.
|
||
|
//! - \ref InvokeNode - Represents a function invocation.
|
||
|
//!
|
||
|
//! \ref BaseCompiler also makes the use of passes (\ref Pass) and automatically
|
||
|
//! adds an architecture-dependent register allocator pass to the list of passes
|
||
|
//! when attached to \ref CodeHolder.
|
||
|
//!
|
||
|
//! ### Compiler Examples
|
||
|
//!
|
||
|
//! - \ref x86::Compiler provides many X86/X64 examples.
|
||
|
//!
|
||
|
//! ### Compiler Tips
|
||
|
//!
|
||
|
//! Users of AsmJit have done mistakes in the past, this section should provide
|
||
|
//! some useful tips for beginners:
|
||
|
//!
|
||
|
//! - Virtual registers in compiler are bound to a single function. At the
|
||
|
//! moment the implementation doesn't care whether a single virtual register
|
||
|
//! is used in multiple functions, but it sees it as two independent virtual
|
||
|
//! registers in that case. This means that virtual registers cannot be used
|
||
|
//! to implement global variables. Global variables are basically memory
|
||
|
//! addresses which functions can read from and write to, and they have to
|
||
|
//! be implemented in the same way.
|
||
|
//!
|
||
|
//! - Compiler provides a useful debugging functionality, which can be turned
|
||
|
//! on through \ref FormatOptions::Flags. Use \ref Logger::addFlags() to
|
||
|
//! turn on additional logging features when using Compiler.
|
||
|
|
||
|
// ============================================================================
|
||
|
// [Documentation - asmjit_function]
|
||
|
// ============================================================================
|
||
|
|
||
|
//! \defgroup asmjit_function Function
|
||
|
//! \brief Function definitions.
|
||
|
//!
|
||
|
//! ### Overview
|
||
|
//!
|
||
|
//! AsmJit provides functionality that can be used to define function signatures
|
||
|
//! and to calculate automatically optimal function frame that can be used directly
|
||
|
//! by a prolog and epilog insertion. This feature was exclusive to AsmJit's Compiler
|
||
|
//! for a very long time, but was abstracted out and is now available for all users
|
||
|
//! regardless of the emitter they use. The following use cases are possible:
|
||
|
//!
|
||
|
//! - Calculate function frame before the function is generated - this is the
|
||
|
//! only way available to \ref BaseAssembler users and it will be described
|
||
|
//! in this section.
|
||
|
//!
|
||
|
//! - Calculate function frame after the function is generated - this way is
|
||
|
//! generally used by \ref BaseBuilder and \ref BaseCompiler emitters and
|
||
|
//! this way is generally described in \ref asmjit_compiler section.
|
||
|
//!
|
||
|
//! The following concepts are used to describe and create functions in AsmJit:
|
||
|
//!
|
||
|
//! - \ref Type::Id - Type-id is an 8-bit value that describes a platform
|
||
|
//! independent type as we know from C/C++. It provides abstractions for
|
||
|
//! most common types like `int8_t`, `uint32_t`, `uintptr_t`, `float`,
|
||
|
//! `double`, and all possible vector types to match ISAs up to AVX512.
|
||
|
//! \ref Type::Id was introduced originally for \ref asmjit_compiler, but
|
||
|
//! it's now used by \ref FuncSignature as well.
|
||
|
//!
|
||
|
//! - \ref CallConv - Describes a calling convention - this class contains
|
||
|
//! instructions to assign registers and stack addresses to function
|
||
|
//! arguments and return value(s), but doesn't specify any function
|
||
|
//! signature itself. Calling conventions are architecture and OS dependent.
|
||
|
//!
|
||
|
//! - \ref FuncSignature - Describes a function signature, for example
|
||
|
//! `int func(int, int)`. FuncSignature contains a function calling convention
|
||
|
//! id, return value type, and function arguments. The signature itself is
|
||
|
//! platform independent and uses \ref Type::Id to describe types of function
|
||
|
//! arguments and function return value(s).
|
||
|
//!
|
||
|
//! - \ref FuncDetail - Architecture and ABI dependent information that describes
|
||
|
//! \ref CallConv and expanded \ref FuncSignature. Each function argument and
|
||
|
//! return value is represented as \ref FuncValue that contains the original
|
||
|
//! \ref Type::Id enriched with additional information that specifies whether
|
||
|
//! the value is passed or returned by register (and which register) or by
|
||
|
//! stack. Each value also contains some other metadata that provide additional
|
||
|
//! information required to handle it properly (for example whether a vector is
|
||
|
//! passed indirectly by a pointer as required by WIN64 calling convention).
|
||
|
//!
|
||
|
//! - \ref FuncFrame - Contains information about the function frame that can
|
||
|
//! be used by prolog/epilog inserter (PEI). Holds call stack size size and
|
||
|
//! alignment, local stack size and alignment, and various attributes that
|
||
|
//! describe how prolog and epilog should be constructed. `FuncFrame` doesn't
|
||
|
//! know anything about function's arguments or return values, it hold only
|
||
|
//! information necessary to create a valid and ABI conforming function prologs
|
||
|
//! and epilogs.
|
||
|
//!
|
||
|
//! - \ref FuncArgsAssignment - A helper class that can be used to reassign
|
||
|
//! function arguments into user specified registers. It's architecture and
|
||
|
//! ABI dependent mapping from function arguments described by \ref CallConv
|
||
|
//! and \ref FuncDetail into registers specified by the user.
|
||
|
//!
|
||
|
//! It's a lot of concepts where each represents one step in a function frame
|
||
|
//! calculation. It can be used to create function prologs, epilogs, and also
|
||
|
//! to calculate information necessary to perform function calls.
|
||
|
|
||
|
// ============================================================================
|
||
|
// [Documentation - asmjit_logging]
|
||
|
// ============================================================================
|
||
|
|
||
|
//! \defgroup asmjit_logging Logging
|
||
|
//! \brief Logging and formatting.
|
||
|
//!
|
||
|
//! ### Overview
|
||
|
//!
|
||
|
//! The initial phase of a project that generates machine code is not always smooth.
|
||
|
//! Failure cases are common not just at the beginning phase, but also during the
|
||
|
//! development or refactoring. AsmJit provides logging functionality to address
|
||
|
//! this issue. AsmJit does already a good job with function overloading to prevent
|
||
|
//! from emitting unencodable instructions, but it can't prevent from emitting machine
|
||
|
//! code that is correct at instruction level, but doesn't work when it's executed as
|
||
|
//! a whole. Logging has always been an important part of AsmJit's infrastructure and
|
||
|
//! looking at logs can sometimes reveal code generation issues quickly.
|
||
|
//!
|
||
|
//! AsmJit provides API for logging and formatting:
|
||
|
//! - \ref Logger - A logger that you can pass to \ref CodeHolder and all emitters
|
||
|
//! that inherit from \ref BaseEmitter.
|
||
|
//! - \ref FormatOptions - Formatting options that can change how instructions and
|
||
|
//! operands are formatted.
|
||
|
//! - \ref Formatter - A namespace that provides functions that can format input
|
||
|
//! data like \ref Operand, \ref BaseReg, \ref Label, and \ref BaseNode into
|
||
|
//! \ref String.
|
||
|
//!
|
||
|
//! AsmJit's \ref Logger serves the following purposes:
|
||
|
//! - Provides a basic foundation for logging.
|
||
|
//! - Abstract class leaving the implementation on users. The following built-in
|
||
|
//! inplementations are provided for simplicty:
|
||
|
//! - \ref FileLogger implements logging into a standard `FILE` stream.
|
||
|
//! - \ref StringLogger serializes all logs into a \ref String instance.
|
||
|
//!
|
||
|
//! AsmJit's \ref FormatOptions provides the following to customize the formatting of
|
||
|
//! instructions and operands through:
|
||
|
//! - \ref FormatOptions::Flags
|
||
|
//! - \ref FormatOptions::IndentationType
|
||
|
//!
|
||
|
//! ### Logging
|
||
|
//!
|
||
|
//! A \ref Logger is typically attached to a \ref CodeHolder, which propagates it
|
||
|
//! to all attached emitters automatically. The example below illustrates how to
|
||
|
//! use \ref FileLogger that outputs to standard output:
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/core.h>
|
||
|
//! #include <stdio.h>
|
||
|
//!
|
||
|
//! using namespace asmjit;
|
||
|
//!
|
||
|
//! int main() {
|
||
|
//! JitRuntime rt; // Runtime specialized for JIT code execution.
|
||
|
//! FileLogger logger(stdout); // Logger should always survive CodeHolder.
|
||
|
//!
|
||
|
//! CodeHolder code; // Holds code and relocation information.
|
||
|
//! code.init(rt.environment()); // Initialize to the same arch as JIT runtime.
|
||
|
//! code.setLogger(&logger); // Attach the `logger` to `code` holder.
|
||
|
//!
|
||
|
//! // ... code as usual, everything emitted will be logged to `stdout` ...
|
||
|
//! return 0;
|
||
|
//! }
|
||
|
//! ```
|
||
|
//!
|
||
|
//! If output to FILE stream is not desired it's possible to use \ref StringLogger,
|
||
|
//! which concatenates everything into a multi-line string:
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/core.h>
|
||
|
//! #include <stdio.h>
|
||
|
//! #include <utility>
|
||
|
//!
|
||
|
//! using namespace asmjit;
|
||
|
//!
|
||
|
//! int main() {
|
||
|
//! JitRuntime rt; // Runtime specialized for JIT code execution.
|
||
|
//! StringLogger logger; // Logger should always survive CodeHolder.
|
||
|
//!
|
||
|
//! CodeHolder code; // Holds code and relocation information.
|
||
|
//! code.init(rt.environment()); // Initialize to the same arch as JIT runtime.
|
||
|
//! code.setLogger(&logger); // Attach the `logger` to `code` holder.
|
||
|
//!
|
||
|
//! // ... code as usual, logging will be concatenated to logger string ...
|
||
|
//!
|
||
|
//! // You can either use the string from StringLogger directly or you can
|
||
|
//! // move it. Logger::data() returns its content as null terminated char[].
|
||
|
//! printf("Logger content: %s\n", logger.data());
|
||
|
//!
|
||
|
//! // It can be moved into your own string like this:
|
||
|
//! String content = std::move(logger.content());
|
||
|
//! printf("The same content: %s\n", content.data());
|
||
|
//!
|
||
|
//! return 0;
|
||
|
//! }
|
||
|
//! ```
|
||
|
//!
|
||
|
//! ### Formatting
|
||
|
//!
|
||
|
//! AsmJit uses \ref Formatter to format inputs that are then passed to \ref
|
||
|
//! Logger. Formatting is public and can be used by AsmJit users as well. The
|
||
|
//! most important thing to know regarding formatting is that \ref Formatter
|
||
|
//! always appends to the output string, so it can be used to build complex
|
||
|
//! strings without having to concatenate intermediate strings.
|
||
|
//!
|
||
|
//! The first example illustrates how to format operands:
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/core.h>
|
||
|
//! #include <stdio.h>
|
||
|
//!
|
||
|
//! using namespace asmjit;
|
||
|
//!
|
||
|
//! void logOperand(uint32_t arch, const Operand_& op) {
|
||
|
//! // The emitter is optional (named labels and virtual registers need it).
|
||
|
//! BaseEmitter* emitter = nullptr;
|
||
|
//!
|
||
|
//! // No flags by default.
|
||
|
//! uint32_t formatFlags = FormatOptions::kNoFlags;
|
||
|
//!
|
||
|
//! StringTmp<128> sb;
|
||
|
//! Formatter::formatOperand(sb, formatFlags, emitter, arch, op);
|
||
|
//! printf("%s\n", sb.data());
|
||
|
//! }
|
||
|
//!
|
||
|
//! void formattingExample() {
|
||
|
//! using namespace x86;
|
||
|
//!
|
||
|
//! // Architecture is not part of operand, it must be passed explicitly.
|
||
|
//! // Format flags. We pass it explicitly also to 'logOperand' to make
|
||
|
//! // compatible with what AsmJit normally does.
|
||
|
//! uint32_t arch = Environment::kArchX64;
|
||
|
//!
|
||
|
//! log(arch, rax); // Prints 'rax'.
|
||
|
//! log(arch, ptr(rax, rbx, 2)); // Prints '[rax + rbx * 4]`.
|
||
|
//! log(arch, dword_ptr(rax, rbx, 2)); // Prints 'dword [rax + rbx * 4]`.
|
||
|
//! log(arch, imm(42)); // Prints '42'.
|
||
|
//! }
|
||
|
//! ```
|
||
|
//!
|
||
|
//! Next example illustrates how to format whole instructions:
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/core.h>
|
||
|
//! #include <stdio.h>
|
||
|
//! #include <utility>
|
||
|
//!
|
||
|
//! using namespace asmjit;
|
||
|
//!
|
||
|
//! template<typename... Args>
|
||
|
//! void logInstruction(uint32_t arch, const BaseInst& inst, Args&&... args) {
|
||
|
//! // The emitter is optional (named labels and virtual registers need it).
|
||
|
//! BaseEmitter* emitter = nullptr;
|
||
|
//!
|
||
|
//! // No flags by default.
|
||
|
//! uint32_t formatFlags = FormatOptions::kNoFlags;
|
||
|
//!
|
||
|
//! // The formatter expects operands in an array.
|
||
|
//! Operand_ operands { std::forward<Args>(args)... };
|
||
|
//!
|
||
|
//! StringTmp<128> sb;
|
||
|
//! Formatter::formatInstruction(
|
||
|
//! sb, formatFlags, emitter, arch, inst, operands, sizeof...(args));
|
||
|
//! printf("%s\n", sb.data());
|
||
|
//! }
|
||
|
//!
|
||
|
//! void formattingExample() {
|
||
|
//! using namespace x86;
|
||
|
//!
|
||
|
//! // Architecture is not part of operand, it must be passed explicitly.
|
||
|
//! // Format flags. We pass it explicitly also to 'logOperand' to make
|
||
|
//! // compatible with what AsmJit normally does.
|
||
|
//! uint32_t arch = Environment::kArchX64;
|
||
|
//!
|
||
|
//! // Prints 'mov rax, rcx'.
|
||
|
//! logInstruction(arch, BaseInst(Inst::kIdMov), rax, rcx);
|
||
|
//!
|
||
|
//! // Prints 'vaddpd zmm0, zmm1, [rax] {1to8}'.
|
||
|
//! logInstruction(arch,
|
||
|
//! BaseInst(Inst::kIdVaddpd),
|
||
|
//! zmm0, zmm1, ptr(rax)._1toN());
|
||
|
//!
|
||
|
//! // BaseInst abstracts instruction id, instruction options, and extraReg.
|
||
|
//! // Prints 'lock add [rax], rcx'.
|
||
|
//! logInstruction(arch,
|
||
|
//! BaseInst(Inst::kIdAdd, Inst::kOptionLock),
|
||
|
//! x86::ptr(rax), rcx);
|
||
|
//!
|
||
|
//! // Similarly an extra register (like AVX-512 selector) can be used.
|
||
|
//! // Prints 'vaddpd zmm0 {k2} {z}, zmm1, [rax]'.
|
||
|
//! logInstruction(arch,
|
||
|
//! BaseInst(Inst::kIdAdd, Inst::kOptionZMask, k2),
|
||
|
//! zmm0, zmm1, ptr(rax));
|
||
|
//! }
|
||
|
//! ```
|
||
|
//!
|
||
|
//! And finally, the example below illustrates how to use a built-in function
|
||
|
//! to format the content of \ref BaseBuilder, which consists of nodes:
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/core.h>
|
||
|
//! #include <stdio.h>
|
||
|
//!
|
||
|
//! using namespace asmjit;
|
||
|
//!
|
||
|
//! void formattingExample(BaseBuilder* builder) {
|
||
|
//! uint32_t formatFlags = FormatOptions::kNoFlags;
|
||
|
//!
|
||
|
//! // This also shows how temporary strings can be used.
|
||
|
//! StringTmp<512> sb;
|
||
|
//!
|
||
|
//! // FormatNodeList requires the String for output, formatting flags, which
|
||
|
//! // were zero (no extra flags), and the builder instance, which we have
|
||
|
//! // provided. An overloaded version also exists, which accepts begin and
|
||
|
//! // and end nodes, which can be used to only format a range of nodes.
|
||
|
//! Formatter::formatNodeList(sb, formatFlags, builder);
|
||
|
//!
|
||
|
//! // You can do whatever else with the string, it's always null terminated,
|
||
|
//! // so it can be passed to C functions like printf().
|
||
|
//! printf("%s\n", sb.data());
|
||
|
//! }
|
||
|
//! ```
|
||
|
|
||
|
// ============================================================================
|
||
|
// [Documentation - asmjit_error_handling]
|
||
|
// ============================================================================
|
||
|
|
||
|
//! \defgroup asmjit_error_handling Error Handling
|
||
|
//! \brief Error handling.
|
||
|
//!
|
||
|
//! ### Overview
|
||
|
//!
|
||
|
//! AsmJit uses error codes to represent and return errors. Every function that
|
||
|
//! can fail returns an \ref Error code. Exceptions are never thrown by AsmJit
|
||
|
//! itself even in extreme conditions like out-of-memory, but it's possible to
|
||
|
//! override \ref ErrorHandler::handleError() to throw, in that case no error
|
||
|
//! will be returned and exception will be thrown instead. All functions where
|
||
|
//! this can happen are not marked `noexcept`.
|
||
|
//!
|
||
|
//! Errors should never be ignored, however, checking errors after each AsmJit
|
||
|
//! API call would simply overcomplicate the whole code generation experience.
|
||
|
//! \ref ErrorHandler exists to make the use of AsmJit API simpler as it allows
|
||
|
//! to customize how errors can be handled:
|
||
|
//!
|
||
|
//! - Record the error and continue (the way how the error is user-implemented).
|
||
|
//! - Throw an exception. AsmJit doesn't use exceptions and is completely
|
||
|
//! exception-safe, but it's perfectly legal to throw an exception from
|
||
|
//! the error handler.
|
||
|
//! - Use plain old C's `setjmp()` and `longjmp()`. Asmjit always puts Assembler,
|
||
|
//! Builder and Compiler to a consistent state before calling \ref
|
||
|
//! ErrorHandler::handleError(), so `longjmp()` can be used without issues to
|
||
|
//! cancel the code-generation if an error occurred. This method can be used if
|
||
|
//! exception handling in your project is turned off and you still want some
|
||
|
//! comfort. In most cases it should be safe as AsmJit uses \ref Zone memory
|
||
|
//! and the ownership of memory it allocates always ends with the instance that
|
||
|
//! allocated it. If using this approach please never jump outside the life-time
|
||
|
//! of \ref CodeHolder and \ref BaseEmitter.
|
||
|
//!
|
||
|
//! ### Using ErrorHandler
|
||
|
//!
|
||
|
//! An example of attaching \ref ErrorHandler to \ref CodeHolder.
|
||
|
//!
|
||
|
//! ```
|
||
|
//! #include <asmjit/x86.h>
|
||
|
//! #include <stdio.h>
|
||
|
//!
|
||
|
//! using namespace asmjit;
|
||
|
//!
|
||
|
//! // A simple error handler implementation, extend according to your needs.
|
||
|
//! class MyErrorHandler : public ErrorHandler {
|
||
|
//! public:
|
||
|
//! void handleError(Error err, const char* message, BaseEmitter* origin) override {
|
||
|
//! printf("AsmJit error: %s\n", message);
|
||
|
//! }
|
||
|
//! };
|
||
|
//!
|
||
|
//! int main() {
|
||
|
//! JitRuntime rt;
|
||
|
//!
|
||
|
//! MyErrorHandler myErrorHandler;
|
||
|
//! CodeHolder code;
|
||
|
//!
|
||
|
//! code.init(rt.environment());
|
||
|
//! code.setErrorHandler(&myErrorHandler);
|
||
|
//!
|
||
|
//! x86::Assembler a(&code);
|
||
|
//! // ... code generation ...
|
||
|
//!
|
||
|
//! return 0;
|
||
|
//! }
|
||
|
//! ```
|
||
|
//!
|
||
|
//! Useful classes in error handling group:
|
||
|
//!
|
||
|
//! - See \ref DebugUtils that provides utilities useful for debugging.
|
||
|
//! - See \ref Error that lists error codes that AsmJit uses.
|
||
|
//! - See \ref ErrorHandler for more details about error handling.
|
||
|
|
||
|
// ============================================================================
|
||
|
// [Documentation - asmjit_instruction_db]
|
||
|
// ============================================================================
|
||
|
|
||
|
//! \defgroup asmjit_instruction_db Instruction DB
|
||
|
//! \brief Instruction database (introspection, read/write, validation, ...).
|
||
|
//!
|
||
|
//! ### Overview
|
||
|
//!
|
||
|
//! AsmJit provides a public instruction database that can be used to query
|
||
|
//! information about a complete instruction. The instruction database requires
|
||
|
//! the knowledge of the following:
|
||
|
//!
|
||
|
//! - \ref BaseInst - Base instruction that contains instruction id, options,
|
||
|
//! and a possible extra-register that represents either REP prefix counter
|
||
|
//! or AVX-512 selector (mask).
|
||
|
//! - \ref Operand - Represents operands of an instruction.
|
||
|
//!
|
||
|
//! Each instruction can be then queried for the following information:
|
||
|
//!
|
||
|
//! - \ref InstRWInfo - Read/write information of instruction and its oprands.
|
||
|
//! - \ref OpRWInfo - Read/write information of a single operand, part of
|
||
|
//! \ref InstRWInfo data structure.
|
||
|
//! - \ref BaseFeatures - CPU features required to execute the instruction.
|
||
|
//!
|
||
|
//! In addition to query functionality AsmJit is also able to validate whether
|
||
|
//! an instruction and its operands are valid. This is useful for making sure
|
||
|
//! that what user tries to emit is correct and it can be also used by other
|
||
|
//! projects that parse user input, like AsmTK project.
|
||
|
//!
|
||
|
//! ### Query API
|
||
|
//!
|
||
|
//! The instruction query API is provided by \ref InstAPI namespace. The
|
||
|
//! following queries are possible:
|
||
|
//!
|
||
|
//! - \ref InstAPI::queryRWInfo() - queries read/write information of the
|
||
|
//! given instruction and its operands. Includes also CPU flags read/written.
|
||
|
//!
|
||
|
//! - \ref InstAPI::queryFeatures() - queries CPU features that are required
|
||
|
//! to execute the given instruction. A full instruction with operands must
|
||
|
//! be given as some architectures like X86 may require different features
|
||
|
//! for the same instruction based on its operands.
|
||
|
//!
|
||
|
//! - <a href="https://github.com/asmjit/asmjit/blob/master/test/asmjit_test_x86_instinfo.cpp">asmjit_test_x86_instinfo.cpp</a>
|
||
|
//! can be also used as a reference about accessing instruction information.
|
||
|
//!
|
||
|
//! ### Validation API
|
||
|
//!
|
||
|
//! The instruction validation API is provided by \ref InstAPI namespace in the
|
||
|
//! similar fashion like the Query API, however, validation can also be turned
|
||
|
//! on at \ref BaseEmitter level. The following is possible:
|
||
|
//!
|
||
|
//! - \ref InstAPI::validate() - low-level instruction validation function
|
||
|
//! that is used internally by emitters if strict validation is enabled.
|
||
|
//!
|
||
|
//! - \ref BaseEmitter::addValidationOptions() - can be used to enable
|
||
|
//! validation at emitter level, see \ref BaseEmitter::ValidationOptions.
|
||
|
|
||
|
|
||
|
// ============================================================================
|
||
|
// [Documentation - asmjit_virtual_memory]
|
||
|
// ============================================================================
|
||
|
|
||
|
//! \defgroup asmjit_virtual_memory Virtual Memory
|
||
|
//! \brief Virtual memory management.
|
||
|
//!
|
||
|
//! ### Overview
|
||
|
//!
|
||
|
//! AsmJit's virtual memory management is divided into two main categories:
|
||
|
//!
|
||
|
//! - Low level API that provides cross-platform abstractions for virtual
|
||
|
//! memory allocation. Implemented in \ref VirtMem namespace.
|
||
|
//! - High level API that makes it very easy to store generated code for
|
||
|
//! execution. See \ref JitRuntime, which is used by many examples for its
|
||
|
//! simplicity and easy integration with \ref CodeHolder. There is also
|
||
|
//! \ref JitAllocator, which lays somewhere between RAW memory allocation
|
||
|
//! and \ref JitRuntime.
|
||
|
|
||
|
// ============================================================================
|
||
|
// [Documentation - asmjit_zone_memory]
|
||
|
// ============================================================================
|
||
|
|
||
|
//! \defgroup asmjit_zone Zone Memory
|
||
|
//! \brief Zone memory allocator and containers.
|
||
|
//!
|
||
|
//! ### Overview
|
||
|
//!
|
||
|
//! AsmJit uses zone memory allocation (also known as Arena allocation) to allocate
|
||
|
//! most of the data it uses. It's a fast allocator that allows AsmJit to allocate
|
||
|
//! a lot of small data structures fast and without `malloc()` overhead. Since
|
||
|
//! code generators and all related classes are usually short-lived this approach
|
||
|
//! decreases memory usage and fragmentation as arena-based allocators always
|
||
|
//! allocate larger blocks of memory, which are then split into smaller chunks.
|
||
|
//!
|
||
|
//! Another advantage of zone memory allocation is that since the whole library
|
||
|
//! uses this strategy it's very easy to deallocate everything that a particular
|
||
|
//! instance is holding by simply releasing the memory the allocator holds. This
|
||
|
//! improves destruction time of such objects as there is no destruction at all.
|
||
|
//! Long-lived objects just reset its data in destructor or in their reset()
|
||
|
//! member function for a future reuse. For this purpose all containers in AsmJit
|
||
|
//! are also zone allocated.
|
||
|
//!
|
||
|
//! ### Zone Allocation
|
||
|
//!
|
||
|
//! - \ref Zone - Incremental zone memory allocator with minimum features. It
|
||
|
//! can only allocate memory without the possibility to return it back to
|
||
|
//! the allocator.
|
||
|
//!
|
||
|
//! - \ref ZoneTmp - A temporary \ref Zone with some initial static storage.
|
||
|
//! If the allocation requests fit the static storage allocated then there
|
||
|
//! will be no dynamic memory allocation during the lifetime of \ref ZoneTmp,
|
||
|
//! otherwise it would act as \ref Zone with one preallocated block on the
|
||
|
//! stack.
|
||
|
//!
|
||
|
//! - \ref ZoneAllocator - A wrapper of \ref Zone that provides the capability
|
||
|
//! of returning memory to the allocator. Such memory is stored in a pool for
|
||
|
//! later reuse.
|
||
|
//!
|
||
|
//! ### Zone Allocated Containers
|
||
|
//!
|
||
|
//! - \ref ZoneString - Zone allocated string.
|
||
|
//! - \ref ZoneHash - Zone allocated hash table.
|
||
|
//! - \ref ZoneTree - Zone allocated red-black tree.
|
||
|
//! - \ref ZoneList - Zone allocated double-linked list.
|
||
|
//! - \ref ZoneStack - Zone allocated stack.
|
||
|
//! - \ref ZoneVector - Zone allocated vector.
|
||
|
//! - \ref ZoneBitVector - Zone allocated vector of bits.
|
||
|
//!
|
||
|
//! ### Using Zone Allocated Containers
|
||
|
//!
|
||
|
//! The most common data structure exposed by AsmJit is \ref ZoneVector. It's very
|
||
|
//! similar to `std::vector`, but the implementation doesn't use exceptions and
|
||
|
//! uses the mentioned \ref ZoneAllocator for performance reasons. You don't have
|
||
|
//! to worry about allocations as you should not need to add items to AsmJit's
|
||
|
//! data structures directly as there should be API for all required operations.
|
||
|
//!
|
||
|
//! The following APIs in \ref CodeHolder returns \ref ZoneVector reference:
|
||
|
//!
|
||
|
//! ```
|
||
|
//! using namespace asmjit;
|
||
|
//!
|
||
|
//! void example(CodeHolder& code) {
|
||
|
//! // Contains all emitters attached to CodeHolder.
|
||
|
//! const ZoneVector<BaseEmitter*>& emitters = code.emitters();
|
||
|
//!
|
||
|
//! // Contains all section entries managed by CodeHolder.
|
||
|
//! const ZoneVector<Section*>& sections = code.sections();
|
||
|
//!
|
||
|
//! // Contains all label entries managed by CodeHolder.
|
||
|
//! const ZoneVector<LabelEntry*>& labelEntries = code.labelEntries();
|
||
|
//!
|
||
|
//! // Contains all relocation entries managed by CodeHolder.
|
||
|
//! const ZoneVector<RelocEntry*>& relocEntries = code.relocEntries();
|
||
|
//! }
|
||
|
//! ```
|
||
|
//!
|
||
|
//! \ref ZoneVector has overloaded array access operator to make it possible
|
||
|
//! to access its elements through operator[]. Some standard functions like
|
||
|
//! \ref ZoneVector::empty(), \ref ZoneVector::size(), and \ref ZoneVector::data()
|
||
|
//! are provided as well. Vectors are also iterable through a range-based for loop:
|
||
|
//!
|
||
|
//! ```
|
||
|
//! using namespace asmjit;
|
||
|
//!
|
||
|
//! void example(CodeHolder& code) {
|
||
|
//! for (LabelEntry* le : code.labelEntries()) {
|
||
|
//! printf("Label #%u {Bound=%s Offset=%llu}",
|
||
|
//! le->id(),
|
||
|
//! le->isBound() ? "true" : "false",
|
||
|
//! (unsigned long long)le->offset());
|
||
|
//! }
|
||
|
//! }
|
||
|
//! ```
|
||
|
//!
|
||
|
//! ### Design Considerations
|
||
|
//!
|
||
|
//! Zone-allocated containers do not store the allocator within the container.
|
||
|
//! This decision was made to reduce the footprint of such containers as AsmJit
|
||
|
//! tooling, especially Compiler's register allocation, may use many instances
|
||
|
//! of such containers to perform code analysis and register allocation.
|
||
|
//!
|
||
|
//! For example to append an item into a \ref ZoneVector it's required to pass
|
||
|
//! the allocator as the first argument, so it can be used in case that the
|
||
|
//! vector needs a reallocation. Such function also returns an error, which
|
||
|
//! must be propagated to the caller.
|
||
|
//!
|
||
|
//! ```
|
||
|
//! using namespace asmjit
|
||
|
//!
|
||
|
//! Error example(ZoneAllocator* allocator) {
|
||
|
//! ZoneVector<int> vector;
|
||
|
//!
|
||
|
//! // Unfortunately, allocator must be provided to all functions that mutate
|
||
|
//! // the vector. However, AsmJit users should never need to do this as all
|
||
|
//! // manipulation should be done through public API, which takes care of
|
||
|
//! // that.
|
||
|
//! for (int i = 0; i < 100; i++) {
|
||
|
//! ASMJIT_PROPAGATE(vector.append(allocator, i));
|
||
|
//! }
|
||
|
//!
|
||
|
//! // By default vector's destructor doesn't release anything as it knows
|
||
|
//! // that its content is zone allocated. However, \ref ZoneVector::release
|
||
|
//! // can be used to explicitly release the vector data to the allocator if
|
||
|
//! // necessary
|
||
|
//! vector.release(allocator);
|
||
|
//! }
|
||
|
//! ```
|
||
|
//!
|
||
|
//! Containers like \ref ZoneVector also provide a functionality to reserve a
|
||
|
//! certain number of items before any items are added to it. This approach is
|
||
|
//! used internally in most places as it allows to prepare space for data that
|
||
|
//! will be added to some container before the data itself was created.
|
||
|
//!
|
||
|
//! ```
|
||
|
//! using namespace asmjit
|
||
|
//!
|
||
|
//! Error example(ZoneAllocator* allocator) {
|
||
|
//! ZoneVector<int> vector;
|
||
|
//!
|
||
|
//! ASMJIT_PROPAGATE(vector.willGrow(100));
|
||
|
//! for (int i = 0; i < 100; i++) {
|
||
|
//! // Cannot fail.
|
||
|
//! vector.appendUnsafe(allocator, i);
|
||
|
//! }
|
||
|
//!
|
||
|
//! vector.release(allocator);
|
||
|
//! }
|
||
|
//! ```
|
||
|
|
||
|
// ============================================================================
|
||
|
// [Documentation - asmjit_utilities]
|
||
|
// ============================================================================
|
||
|
|
||
|
//! \defgroup asmjit_utilities Utilities
|
||
|
//! \brief Utility classes and functions.
|
||
|
//!
|
||
|
//! ### Overview
|
||
|
//!
|
||
|
//! AsmJit uses and provides utility classes and functions, that can be used
|
||
|
//! with AsmJit. The functionality can be divided into the following topics:
|
||
|
//!
|
||
|
//! ### String Functionality
|
||
|
//!
|
||
|
//! - \ref String - AsmJit's string container, which is used internally
|
||
|
//! and which doesn't use exceptions and has a stable layout, which is
|
||
|
//! not dependent on C++ standard library.
|
||
|
//! - \ref StringTmp - String that can have base storage allocated on
|
||
|
//! stack. The amount of storage on stack can be specified as a template
|
||
|
//! parameter.
|
||
|
//! - \ref FixedString - Fixed string container limited up to N characters.
|
||
|
//!
|
||
|
//! ### Code Generation Utilities
|
||
|
//!
|
||
|
//! - \ref ConstPool - Constant pool used by \ref BaseCompiler, but also
|
||
|
//! available to users that may find use of it.
|
||
|
//!
|
||
|
//! ### Support Functionality Used by AsmJit
|
||
|
//!
|
||
|
//! - \ref Support namespace provides many other utility functions and
|
||
|
//! classes that are used by AsmJit, and made public.
|
||
|
|
||
|
// ============================================================================
|
||
|
// [Documentation - asmjit_<arch> backends]
|
||
|
// ============================================================================
|
||
|
|
||
|
//! \defgroup asmjit_x86 X86 Backend
|
||
|
//! \brief X86/X64 backend.
|
||
|
|
||
|
// ============================================================================
|
||
|
// [Documentation - asmjit_ra]
|
||
|
// ============================================================================
|
||
|
|
||
|
//! \cond INTERNAL
|
||
|
//! \defgroup asmjit_ra RA
|
||
|
//! \brief Register allocator internals.
|
||
|
//! \endcond
|
||
|
|
||
|
} // {asmjit}
|
||
|
|
||
|
// ============================================================================
|
||
|
// [Core Headers]
|
||
|
// ============================================================================
|
||
|
|
||
|
#include "asmjit-scope-begin.h"
|
||
|
#include "core/archtraits.h"
|
||
|
#include "core/assembler.h"
|
||
|
#include "core/builder.h"
|
||
|
#include "core/codeholder.h"
|
||
|
#include "core/compiler.h"
|
||
|
#include "core/constpool.h"
|
||
|
#include "core/cpuinfo.h"
|
||
|
#include "core/datatypes.h"
|
||
|
#include "core/emitter.h"
|
||
|
#include "core/environment.h"
|
||
|
#include "core/errorhandler.h"
|
||
|
#include "core/features.h"
|
||
|
#include "core/formatter.h"
|
||
|
#include "core/func.h"
|
||
|
#include "core/globals.h"
|
||
|
#include "core/inst.h"
|
||
|
#include "core/jitallocator.h"
|
||
|
#include "core/jitruntime.h"
|
||
|
#include "core/logger.h"
|
||
|
#include "core/operand.h"
|
||
|
#include "core/osutils.h"
|
||
|
#include "core/string.h"
|
||
|
#include "core/support.h"
|
||
|
#include "core/target.h"
|
||
|
#include "core/type.h"
|
||
|
#include "core/virtmem.h"
|
||
|
#include "core/zone.h"
|
||
|
#include "core/zonehash.h"
|
||
|
#include "core/zonelist.h"
|
||
|
#include "core/zonetree.h"
|
||
|
#include "core/zonestack.h"
|
||
|
#include "core/zonestring.h"
|
||
|
#include "core/zonevector.h"
|
||
|
#include "asmjit-scope-end.h"
|
||
|
|
||
|
// ============================================================================
|
||
|
// [Deprecated]
|
||
|
// ============================================================================
|
||
|
|
||
|
#ifndef ASMJIT_NO_DEPRECATED
|
||
|
namespace asmjit {
|
||
|
|
||
|
#ifndef ASMJIT_NO_COMPILER
|
||
|
ASMJIT_DEPRECATED("Use InvokeNode instead of FuncCallNode")
|
||
|
typedef InvokeNode FuncCallNode;
|
||
|
#endif // !ASMJIT_NO_COMPILER
|
||
|
|
||
|
#ifndef ASMJIT_NO_LOGGING
|
||
|
namespace Logging { using namespace Formatter; }
|
||
|
#endif //! ASMJIT_NO_LOGGING
|
||
|
|
||
|
} // {asmjit}
|
||
|
#endif // !ASMJIT_NO_DEPRECATED
|
||
|
|
||
|
#endif // ASMJIT_CORE_H_INCLUDED
|