361 lines
15 KiB
C
361 lines
15 KiB
C
// [AsmJit]
|
|
// Complete x86/x64 JIT and Remote Assembler for C++.
|
|
//
|
|
// [License]
|
|
// Zlib - See LICENSE.md file in the package.
|
|
|
|
// [Guard]
|
|
#ifndef _ASMJIT_ASMJIT_H
|
|
#define _ASMJIT_ASMJIT_H
|
|
|
|
// ============================================================================
|
|
// [asmjit_mainpage]
|
|
// ============================================================================
|
|
|
|
//! \mainpage
|
|
//!
|
|
//! AsmJit - Complete x86/x64 JIT and Remote Assembler for C++.
|
|
//!
|
|
//! A complete JIT and remote assembler for C++ language. It can generate native
|
|
//! code for x86 and x64 architectures and supports the whole x86/x64 instruction
|
|
//! set - from legacy MMX to the newest AVX2. It has a type-safe API that allows
|
|
//! C++ compiler to do semantic checks at compile-time even before the assembled
|
|
//! code is generated and executed.
|
|
//!
|
|
//! AsmJit is not a virtual machine (VM). It doesn't have functionality to
|
|
//! implement VM out of the box; however, it can be be used as a JIT backend
|
|
//! of your own VM. The usage of AsmJit is not limited at all; it's suitable
|
|
//! for multimedia, VM backends, remote code generation, and many other tasks.
|
|
//!
|
|
//! \section AsmJit_Main_Concepts Code Generation Concepts
|
|
//!
|
|
//! AsmJit has two completely different code generation concepts. The difference
|
|
//! is in how the code is generated. The first concept, also referred as a low
|
|
//! level concept, is called `Assembler` and it's the same as writing RAW
|
|
//! assembly by inserting instructions that use physical registers directly. In
|
|
//! this case AsmJit does only instruction encoding, verification and final code
|
|
//! relocation.
|
|
//!
|
|
//! The second concept, also referred as a high level concept, is called
|
|
//! `Compiler`. Compiler lets you use virtually unlimited number of registers
|
|
//! (it calls them variables), which significantly simplifies the code generation
|
|
//! process. Compiler allocates these virtual registers to physical registers
|
|
//! after the code generation is done. This requires some extra effort - Compiler
|
|
//! has to generate information for each node (instruction, function declaration,
|
|
//! function call, etc...) in the code, perform a variable liveness analysis and
|
|
//! translate the code using variables to a code that uses only physical registers.
|
|
//!
|
|
//! In addition, Compiler understands functions and their calling conventions.
|
|
//! It has been designed in a way that the code generated is always a function
|
|
//! having a prototype like a real programming language. By having a function
|
|
//! prototype the Compiler is able to insert prolog and epilog sequence to the
|
|
//! function being generated and it's able to also generate a necessary code
|
|
//! to call other function from your own code.
|
|
//!
|
|
//! There is no conclusion on which concept is better. `Assembler` brings full
|
|
//! control and the best performance, while `Compiler` makes the code-generation
|
|
//! more fun and more portable.
|
|
//!
|
|
//! \section AsmJit_Main_Sections Documentation Sections
|
|
//!
|
|
//! AsmJit documentation is structured into the following sections:
|
|
//! - \ref asmjit_base "Base" - Base API (architecture independent).
|
|
//! - \ref asmjit_x86 "X86/X64" - X86/X64 API.
|
|
//!
|
|
//! \section AsmJit_Main_HomePage AsmJit Homepage
|
|
//!
|
|
//! - https://github.com/kobalicek/asmjit
|
|
|
|
// ============================================================================
|
|
// [asmjit_base]
|
|
// ============================================================================
|
|
|
|
//! \defgroup asmjit_base AsmJit Base API (architecture independent)
|
|
//!
|
|
//! \brief Base API.
|
|
//!
|
|
//! Base API contains all classes that are platform and architecture independent.
|
|
//!
|
|
//! Code-Generation and Operands
|
|
//! ----------------------------
|
|
//!
|
|
//! List of the most useful code-generation and operand classes:
|
|
//! - \ref asmjit::Assembler - Low-level code-generation.
|
|
//! - \ref asmjit::ExternalTool - An external tool that can serialize to `Assembler`:
|
|
//! - \ref asmjit::Compiler - High-level code-generation.
|
|
//! - \ref asmjit::Runtime - Describes where the code is stored and how it's executed:
|
|
//! - \ref asmjit::HostRuntime - Runtime that runs on the host machine:
|
|
//! - \ref asmjit::JitRuntime - Runtime designed for JIT code generation and execution.
|
|
//! - \ref asmjit::StaticRuntime - Runtime for code that starts at a specific address.
|
|
//! - \ref asmjit::Stream - Stream is a list of \ref HLNode objects stored as a double
|
|
//! linked list:
|
|
//! - \ref asmjit::HLNode - Base node interface:
|
|
//! - \ref asmjit::HLInst - Instruction node.
|
|
//! - \ref asmjit::HLData - Data node.
|
|
//! - \ref asmjit::HLAlign - Align directive node.
|
|
//! - \ref asmjit::HLLabel - Label node.
|
|
//! - \ref asmjit::HLComment - Comment node.
|
|
//! - \ref asmjit::HLSentinel - Sentinel node.
|
|
//! - \ref asmjit::HLHint - Instruction node.
|
|
//! - \ref asmjit::HLFunc - Function declaration node.
|
|
//! - \ref asmjit::HLRet - Function return node.
|
|
//! - \ref asmjit::HLCall - Function call node.
|
|
//! - \ref asmjit::HLCallArg - Function call argument node.
|
|
//! - \ref asmjit::Operand - base class for all operands:
|
|
//! - \ref asmjit::Reg - Register operand (`Assembler` only).
|
|
//! - \ref asmjit::Var - Variable operand (`Compiler` only).
|
|
//! - \ref asmjit::Mem - Memory operand.
|
|
//! - \ref asmjit::Imm - Immediate operand.
|
|
//! - \ref asmjit::Label - Label operand.
|
|
//!
|
|
//! The following snippet shows how to setup a basic JIT code generation:
|
|
//!
|
|
//! ~~~
|
|
//! using namespace asmjit;
|
|
//!
|
|
//! int main(int argc, char* argv[]) {
|
|
//! // JIT runtime is designed for JIT code generation and execution.
|
|
//! JitRuntime runtime;
|
|
//!
|
|
//! // Assembler instance requires to know the runtime to function.
|
|
//! X86Assembler a(&runtime);
|
|
//!
|
|
//! // Compiler (if you indend to use it) requires an assembler instance.
|
|
//! X86Compiler c(&a);
|
|
//!
|
|
//! return 0;
|
|
//! }
|
|
//! ~~~
|
|
//!
|
|
//! Logging and Error Handling
|
|
//! --------------------------
|
|
//!
|
|
//! AsmJit contains a robust interface that can be used to log the generated code
|
|
//! and to handle possible errors. Base logging interface is provided by \ref
|
|
//! Logger, which is abstract and can be used as a base for your own logger.
|
|
//! AsmJit also implements some trivial logging concepts out of the box to
|
|
//! simplify the development. \ref FileLogger logs into a C `FILE*` stream and
|
|
//! \ref StringLogger concatenates all log messages into a single string.
|
|
//!
|
|
//! The following snippet shows how to setup a basic logger and error handler:
|
|
//!
|
|
//! ~~~
|
|
//! using namespace asmjit;
|
|
//!
|
|
//! struct MyErrorHandler : public ErrorHandler {
|
|
//! virtual bool handleError(Error code, const char* message, void* origin) {
|
|
//! printf("Error 0x%0.8X: %s\n", code, message);
|
|
//!
|
|
//! // True - error handled and code generation can continue.
|
|
//! // False - error not handled, code generation should stop.
|
|
//! return false;
|
|
//! }
|
|
//! }
|
|
//!
|
|
//! int main(int argc, char* argv[]) {
|
|
//! JitRuntime runtime;
|
|
//! FileLogger logger(stderr);
|
|
//! MyErrorHandler eh;
|
|
//!
|
|
//! X86Assembler a(&runtime);
|
|
//! a.setLogger(&logger);
|
|
//! a.setErrorHandler(&eh);
|
|
//!
|
|
//! ...
|
|
//!
|
|
//! return 0;
|
|
//! }
|
|
//! ~~~
|
|
//!
|
|
//! AsmJit also contains an \ref ErrorHandler, which is an abstract class that
|
|
//! can be used to implement your own error handling. It can be associated with
|
|
//! \ref Assembler and used to report all errors. It's a very convenient way to
|
|
//! be aware of any error that happens during the code generation without making
|
|
//! the error handling complicated.
|
|
//!
|
|
//! List of the most useful logging and error handling classes:
|
|
//! - \ref asmjit::Logger - abstract logging interface:
|
|
//! - \ref asmjit::FileLogger - A logger that logs to `FILE*`.
|
|
//! - \ref asmjit::StringLogger - A logger that concatenates to a single string.
|
|
//! - \ref asmjit::ErrorHandler - Easy way to handle \ref Assembler and \ref
|
|
//! Compiler
|
|
//! errors.
|
|
//!
|
|
//! Zone Memory Allocator
|
|
//! ---------------------
|
|
//!
|
|
//! Zone memory allocator is an incremental memory allocator that can be used
|
|
//! to allocate data of short life-time. It has much better performance
|
|
//! characteristics than all other allocators, because the only thing it can do
|
|
//! is to increment a pointer and return its previous address. See \ref Zone
|
|
//! for more details.
|
|
//!
|
|
//! The whole AsmJit library is based on zone memory allocation for performance
|
|
//! reasons. It has many other benefits, but the performance was the main one
|
|
//! when designing the library.
|
|
//!
|
|
//! POD Containers
|
|
//! --------------
|
|
//!
|
|
//! POD containers are used by AsmJit to manage its own data structures. The
|
|
//! following classes can be used by AsmJit consumers:
|
|
//!
|
|
//! - \ref asmjit::BitArray - A fixed bit-array that is used internally.
|
|
//! - \ref asmjit::PodVector<T> - A simple array-like container for storing
|
|
//! POD data.
|
|
//! - \ref asmjit::PodList<T> - A single linked list.
|
|
//! - \ref asmjit::StringBuilder - A string builder that can append strings
|
|
//! and integers.
|
|
//!
|
|
//! Utility Functions
|
|
//! -----------------
|
|
//!
|
|
//! Utility functions are implementated static class \ref Utils. There are
|
|
//! utilities for bit manipulation and bit counting, utilities to get an
|
|
//! integer minimum / maximum and various other helpers required to perform
|
|
//! alignment checks and binary casting from float to integer and vice versa.
|
|
//!
|
|
//! String utilities are also implemented by a static class \ref Utils. They
|
|
//! are mostly used by AsmJit internals and not really important to end users.
|
|
//!
|
|
//! SIMD Utilities
|
|
//! --------------
|
|
//!
|
|
//! SIMD code generation often requires to embed constants after each function
|
|
//! or at the end of the whole code block. AsmJit contains `Vec64`, `Vec128`
|
|
//! and `Vec256` classes that can be used to prepare data useful when generating
|
|
//! SIMD code.
|
|
//!
|
|
//! X86/X64 code generators contain member functions `dmm`, `dxmm`, and `dymm`,
|
|
//! which can be used to embed 64-bit, 128-bit and 256-bit data structures into
|
|
//! the machine code.
|
|
|
|
// ============================================================================
|
|
// [asmjit_x86]
|
|
// ============================================================================
|
|
|
|
//! \defgroup asmjit_x86 AsmJit X86/X64 API
|
|
//!
|
|
//! \brief X86/X64 API
|
|
//!
|
|
//! X86/X64 Code Generation
|
|
//! -----------------------
|
|
//!
|
|
//! X86/X64 code generation is realized throught:
|
|
//! - \ref X86Assembler - low-level code generation.
|
|
//! - \ref X86Compiler - high-level code generation.
|
|
//!
|
|
//! X86/X64 Registers
|
|
//! -----------------
|
|
//!
|
|
//! There are static objects that represents X86 and X64 registers. They can
|
|
//! be used directly (like `eax`, `mm`, `xmm`, ...) or created through
|
|
//! these functions:
|
|
//!
|
|
//! - `asmjit::x86::gpb_lo()` - Get an 8-bit low GPB register.
|
|
//! - `asmjit::x86::gpb_hi()` - Get an 8-bit high GPB register.
|
|
//! - `asmjit::x86::gpw()` - Get a 16-bit GPW register.
|
|
//! - `asmjit::x86::gpd()` - Get a 32-bit GPD register.
|
|
//! - `asmjit::x86::gpq()` - Get a 64-bit GPQ Gp register.
|
|
//! - `asmjit::x86::gpz()` - Get a 32-bit or 64-bit GPD/GPQ register.
|
|
//! - `asmjit::x86::fp()` - Get a 80-bit FPU register.
|
|
//! - `asmjit::x86::mm()` - Get a 64-bit MMX register.
|
|
//! - `asmjit::x86::xmm()` - Get a 128-bit XMM register.
|
|
//! - `asmjit::x86::ymm()` - Get a 256-bit YMM register.
|
|
//! - `asmjit::x86::amm()` - Get a 512-bit ZMM register.
|
|
//!
|
|
//! X86/X64 Addressing
|
|
//! ------------------
|
|
//!
|
|
//! X86 and x64 architectures contains several addressing modes and most ones
|
|
//! are possible with AsmJit library. Memory represents are represented by
|
|
//! `BaseMem` class. These functions are used to make operands that represents
|
|
//! memory addresses:
|
|
//!
|
|
//! - `asmjit::x86::ptr()` - Address size not specified.
|
|
//! - `asmjit::x86::byte_ptr()` - 1 byte.
|
|
//! - `asmjit::x86::word_ptr()` - 2 bytes (GPW size).
|
|
//! - `asmjit::x86::dword_ptr()` - 4 bytes (GPD size).
|
|
//! - `asmjit::x86::qword_ptr()` - 8 bytes (GPQ/MMX size).
|
|
//! - `asmjit::x86::tword_ptr()` - 10 bytes (FPU size).
|
|
//! - `asmjit::x86::dqword_ptr()` - 16 bytes (XMM size).
|
|
//! - `asmjit::x86::yword_ptr()` - 32 bytes (YMM size).
|
|
//! - `asmjit::x86::zword_ptr()` - 64 bytes (ZMM size).
|
|
//!
|
|
//! Most useful function to make pointer should be `asmjit::x86::ptr()`. It
|
|
//! creates a pointer to the target with an unspecified size. Unspecified size
|
|
//! works in all intrinsics where are used registers (this means that size is
|
|
//! specified by register operand or by instruction itself). For example
|
|
//! `asmjit::x86::ptr()` can't be used with `Assembler::inc()` instruction. In
|
|
//! this case the size must be specified and it's also reason to differentiate
|
|
//! between pointer sizes.
|
|
//!
|
|
//! X86 and X86 support simple address forms like `[base + displacement]` and
|
|
//! also complex address forms like `[base + index * scale + displacement]`.
|
|
//!
|
|
//! X86/X64 Immediates
|
|
//! ------------------
|
|
//!
|
|
//! Immediate values are constants thats passed directly after instruction
|
|
//! opcode. To create such value use `asmjit::imm()` or `asmjit::imm_u()`
|
|
//! methods to create a signed or unsigned immediate value.
|
|
//!
|
|
//! X86/X64 CPU Information
|
|
//! -----------------------
|
|
//!
|
|
//! The CPUID instruction can be used to get an exhaustive information about
|
|
//! the host X86/X64 processor. AsmJit contains utilities that can get the most
|
|
//! important information related to the features supported by the CPU and the
|
|
//! host operating system, in addition to host processor name and number of
|
|
//! cores. Class `CpuInfo` provides generic information about a host or target
|
|
//! processor and contains also a specific X86/X64 information.
|
|
//!
|
|
//! By default AsmJit queries the CPU information after the library is loaded
|
|
//! and the queried information is reused by all instances of `JitRuntime`.
|
|
//! The global instance of `CpuInfo` can't be changed, because it will affect
|
|
//! the code generation of all `Runtime`s. If there is a need to have a
|
|
//! specific CPU information which contains modified features or processor
|
|
//! vendor it's possible by creating a new instance of the `CpuInfo` and setting
|
|
//! up its members.
|
|
//!
|
|
//! Cpu detection is important when generating a JIT code that may or may not
|
|
//! use certain CPU features. For example there used to be a SSE/SSE2 detection
|
|
//! in the past and today there is often AVX/AVX2 detection.
|
|
//!
|
|
//! The example below shows how to detect a SSE4.1 instruction set:
|
|
//!
|
|
//! ~~~
|
|
//! using namespace asmjit;
|
|
//!
|
|
//! const CpuInfo& cpuInfo = CpuInfo::getHost();
|
|
//!
|
|
//! if (cpuInfo.hasFeature(CpuInfo::kX86FeatureSSE4_1)) {
|
|
//! // Processor has SSE4.1.
|
|
//! }
|
|
//! else if (cpuInfo.hasFeature(CpuInfo::kX86FeatureSSE2)) {
|
|
//! // Processor doesn't have SSE4.1, but has SSE2.
|
|
//! }
|
|
//! else {
|
|
//! // Processor is archaic; it's a wonder AsmJit works here!
|
|
//! }
|
|
//! ~~~
|
|
|
|
// [Dependencies]
|
|
#include "./base.h"
|
|
|
|
// [ARM/ARM64]
|
|
#if defined(ASMJIT_BUILD_ARM32) || defined(ASMJIT_BUILD_ARM64)
|
|
#include "./arm.h"
|
|
#endif // ASMJIT_BUILD_ARM32 || ASMJIT_BUILD_ARM64
|
|
|
|
// [X86/X64]
|
|
#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)
|
|
#include "./x86.h"
|
|
#endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64
|
|
|
|
// [Host]
|
|
#include "./host.h"
|
|
|
|
// [Guard]
|
|
#endif // _ASMJIT_ASMJIT_H
|