asmjit 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/asmjit.gemspec +1 -1
- data/ext/asmjit/asmjit/.editorconfig +10 -0
- data/ext/asmjit/asmjit/.github/FUNDING.yml +1 -0
- data/ext/asmjit/asmjit/.github/workflows/build-config.json +47 -0
- data/ext/asmjit/asmjit/.github/workflows/build.yml +156 -0
- data/ext/asmjit/asmjit/.gitignore +6 -0
- data/ext/asmjit/asmjit/CMakeLists.txt +611 -0
- data/ext/asmjit/asmjit/LICENSE.md +17 -0
- data/ext/asmjit/asmjit/README.md +69 -0
- data/ext/asmjit/asmjit/src/asmjit/a64.h +62 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64archtraits_p.h +81 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.cpp +5115 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.h +72 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.cpp +51 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.h +57 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.cpp +60 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.h +247 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper.cpp +464 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper_p.h +50 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64emitter.h +1228 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter.cpp +298 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter_p.h +59 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64func.cpp +189 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64func_p.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64globals.h +1894 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi.cpp +278 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi_p.h +41 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.cpp +1957 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.h +74 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb_p.h +876 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.cpp +85 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.h +312 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass.cpp +852 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass_p.h +105 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64utils.h +179 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armformatter.cpp +143 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armformatter_p.h +44 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armglobals.h +21 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armoperand.h +621 -0
- data/ext/asmjit/asmjit/src/asmjit/arm.h +62 -0
- data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-begin.h +17 -0
- data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-end.h +9 -0
- data/ext/asmjit/asmjit/src/asmjit/asmjit.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/core/api-build_p.h +55 -0
- data/ext/asmjit/asmjit/src/asmjit/core/api-config.h +613 -0
- data/ext/asmjit/asmjit/src/asmjit/core/archcommons.h +229 -0
- data/ext/asmjit/asmjit/src/asmjit/core/archtraits.cpp +160 -0
- data/ext/asmjit/asmjit/src/asmjit/core/archtraits.h +290 -0
- data/ext/asmjit/asmjit/src/asmjit/core/assembler.cpp +406 -0
- data/ext/asmjit/asmjit/src/asmjit/core/assembler.h +129 -0
- data/ext/asmjit/asmjit/src/asmjit/core/builder.cpp +889 -0
- data/ext/asmjit/asmjit/src/asmjit/core/builder.h +1391 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codebuffer.h +113 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codeholder.cpp +1149 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codeholder.h +1035 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codewriter.cpp +175 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codewriter_p.h +179 -0
- data/ext/asmjit/asmjit/src/asmjit/core/compiler.cpp +582 -0
- data/ext/asmjit/asmjit/src/asmjit/core/compiler.h +737 -0
- data/ext/asmjit/asmjit/src/asmjit/core/compilerdefs.h +173 -0
- data/ext/asmjit/asmjit/src/asmjit/core/constpool.cpp +363 -0
- data/ext/asmjit/asmjit/src/asmjit/core/constpool.h +250 -0
- data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.cpp +1162 -0
- data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.h +813 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emithelper.cpp +323 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emithelper_p.h +58 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitter.cpp +333 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitter.h +741 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitterutils.cpp +129 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitterutils_p.h +89 -0
- data/ext/asmjit/asmjit/src/asmjit/core/environment.cpp +46 -0
- data/ext/asmjit/asmjit/src/asmjit/core/environment.h +508 -0
- data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.cpp +14 -0
- data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.h +228 -0
- data/ext/asmjit/asmjit/src/asmjit/core/formatter.cpp +584 -0
- data/ext/asmjit/asmjit/src/asmjit/core/formatter.h +247 -0
- data/ext/asmjit/asmjit/src/asmjit/core/formatter_p.h +34 -0
- data/ext/asmjit/asmjit/src/asmjit/core/func.cpp +286 -0
- data/ext/asmjit/asmjit/src/asmjit/core/func.h +1445 -0
- data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext.cpp +293 -0
- data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext_p.h +199 -0
- data/ext/asmjit/asmjit/src/asmjit/core/globals.cpp +133 -0
- data/ext/asmjit/asmjit/src/asmjit/core/globals.h +393 -0
- data/ext/asmjit/asmjit/src/asmjit/core/inst.cpp +113 -0
- data/ext/asmjit/asmjit/src/asmjit/core/inst.h +772 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.cpp +1242 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.h +261 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.cpp +80 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.h +89 -0
- data/ext/asmjit/asmjit/src/asmjit/core/logger.cpp +69 -0
- data/ext/asmjit/asmjit/src/asmjit/core/logger.h +198 -0
- data/ext/asmjit/asmjit/src/asmjit/core/misc_p.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/core/operand.cpp +132 -0
- data/ext/asmjit/asmjit/src/asmjit/core/operand.h +1611 -0
- data/ext/asmjit/asmjit/src/asmjit/core/osutils.cpp +84 -0
- data/ext/asmjit/asmjit/src/asmjit/core/osutils.h +61 -0
- data/ext/asmjit/asmjit/src/asmjit/core/osutils_p.h +68 -0
- data/ext/asmjit/asmjit/src/asmjit/core/raassignment_p.h +418 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rabuilders_p.h +612 -0
- data/ext/asmjit/asmjit/src/asmjit/core/radefs_p.h +1204 -0
- data/ext/asmjit/asmjit/src/asmjit/core/ralocal.cpp +1166 -0
- data/ext/asmjit/asmjit/src/asmjit/core/ralocal_p.h +254 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rapass.cpp +1969 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rapass_p.h +1183 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rastack.cpp +184 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rastack_p.h +171 -0
- data/ext/asmjit/asmjit/src/asmjit/core/string.cpp +559 -0
- data/ext/asmjit/asmjit/src/asmjit/core/string.h +372 -0
- data/ext/asmjit/asmjit/src/asmjit/core/support.cpp +494 -0
- data/ext/asmjit/asmjit/src/asmjit/core/support.h +1773 -0
- data/ext/asmjit/asmjit/src/asmjit/core/target.cpp +14 -0
- data/ext/asmjit/asmjit/src/asmjit/core/target.h +53 -0
- data/ext/asmjit/asmjit/src/asmjit/core/type.cpp +74 -0
- data/ext/asmjit/asmjit/src/asmjit/core/type.h +419 -0
- data/ext/asmjit/asmjit/src/asmjit/core/virtmem.cpp +722 -0
- data/ext/asmjit/asmjit/src/asmjit/core/virtmem.h +242 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zone.cpp +353 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zone.h +615 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonehash.cpp +309 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonehash.h +186 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonelist.cpp +163 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonelist.h +209 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonestack.cpp +176 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonestack.h +239 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonestring.h +120 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonetree.cpp +99 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonetree.h +380 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonevector.cpp +356 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonevector.h +690 -0
- data/ext/asmjit/asmjit/src/asmjit/core.h +1861 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86archtraits_p.h +148 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.cpp +5110 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.h +685 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.cpp +52 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.h +351 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.cpp +61 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.h +721 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper.cpp +619 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper_p.h +60 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86emitter.h +4315 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter.cpp +944 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter_p.h +58 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86func.cpp +503 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86func_p.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86globals.h +2169 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi.cpp +1732 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi_p.h +41 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.cpp +4427 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.h +563 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb_p.h +311 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86opcode_p.h +436 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.cpp +231 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.h +1085 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass.cpp +1509 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass_p.h +94 -0
- data/ext/asmjit/asmjit/src/asmjit/x86.h +93 -0
- data/ext/asmjit/asmjit/src/asmjit.natvis +245 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler.cpp +84 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler.h +85 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler_a64.cpp +4006 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler_x64.cpp +17833 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler_x86.cpp +8300 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler.cpp +253 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler.h +73 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler_a64.cpp +690 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler_x86.cpp +4317 -0
- data/ext/asmjit/asmjit/test/asmjit_test_emitters.cpp +197 -0
- data/ext/asmjit/asmjit/test/asmjit_test_instinfo.cpp +181 -0
- data/ext/asmjit/asmjit/test/asmjit_test_misc.h +257 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf.cpp +62 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf.h +61 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf_a64.cpp +699 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf_x86.cpp +5032 -0
- data/ext/asmjit/asmjit/test/asmjit_test_unit.cpp +172 -0
- data/ext/asmjit/asmjit/test/asmjit_test_x86_sections.cpp +172 -0
- data/ext/asmjit/asmjit/test/asmjitutils.h +38 -0
- data/ext/asmjit/asmjit/test/broken.cpp +312 -0
- data/ext/asmjit/asmjit/test/broken.h +148 -0
- data/ext/asmjit/asmjit/test/cmdline.h +61 -0
- data/ext/asmjit/asmjit/test/performancetimer.h +41 -0
- data/ext/asmjit/asmjit/tools/configure-makefiles.sh +13 -0
- data/ext/asmjit/asmjit/tools/configure-ninja.sh +13 -0
- data/ext/asmjit/asmjit/tools/configure-sanitizers.sh +13 -0
- data/ext/asmjit/asmjit/tools/configure-vs2019-x64.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-vs2019-x86.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-vs2022-x64.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-vs2022-x86.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-xcode.sh +8 -0
- data/ext/asmjit/asmjit/tools/enumgen.js +417 -0
- data/ext/asmjit/asmjit/tools/enumgen.sh +3 -0
- data/ext/asmjit/asmjit/tools/tablegen-arm.js +365 -0
- data/ext/asmjit/asmjit/tools/tablegen-arm.sh +3 -0
- data/ext/asmjit/asmjit/tools/tablegen-x86.js +2638 -0
- data/ext/asmjit/asmjit/tools/tablegen-x86.sh +3 -0
- data/ext/asmjit/asmjit/tools/tablegen.js +947 -0
- data/ext/asmjit/asmjit/tools/tablegen.sh +4 -0
- data/ext/asmjit/asmjit.cc +18 -0
- data/lib/asmjit/version.rb +1 -1
- metadata +197 -2
@@ -0,0 +1,1861 @@
|
|
1
|
+
// This file is part of AsmJit project <https://asmjit.com>
|
2
|
+
//
|
3
|
+
// See asmjit.h or LICENSE.md for license and copyright information
|
4
|
+
// SPDX-License-Identifier: Zlib
|
5
|
+
|
6
|
+
#ifndef ASMJIT_CORE_H_INCLUDED
|
7
|
+
#define ASMJIT_CORE_H_INCLUDED
|
8
|
+
|
9
|
+
//! Root namespace used by AsmJit.
|
10
|
+
namespace asmjit {
|
11
|
+
|
12
|
+
//! \mainpage API Reference
|
13
|
+
//!
|
14
|
+
//! AsmJit C++ API reference documentation generated by Doxygen.
|
15
|
+
//!
|
16
|
+
//! AsmJit library uses one global namespace called \ref asmjit, which provides the whole functionality. Core
|
17
|
+
//! functionality is within \ref asmjit namespace and architecture specific functionality is always in its own
|
18
|
+
//! namespace. For example \ref asmjit::x86 provides both 32-bit and 64-bit X86 code generation.
|
19
|
+
//!
|
20
|
+
//! \section main_groups Documentation Groups
|
21
|
+
//!
|
22
|
+
//! AsmJit documentation is structured into groups. Groups can be followed in order to learn AsmJit, but knowledge
|
23
|
+
//! from multiple groups is required to use AsmJit properly:
|
24
|
+
//!
|
25
|
+
//! $$DOCS_GROUP_OVERVIEW$$
|
26
|
+
//!
|
27
|
+
//! \note It's important to understand that in order to learn AsmJit all groups are important. Some groups can be
|
28
|
+
//! omitted if a particular tool is out of interest - for example \ref asmjit_assembler users don't need to know
|
29
|
+
//! about \ref asmjit_builder, but it's not the opposite. \ref asmjit_builder users should know about \ref
|
30
|
+
//! asmjit_assembler as it also uses operands, labels, and other concepts. Similarly \ref asmjit_compiler users
|
31
|
+
//! should know how both \ref asmjit_assembler and \ref asmjit_builder tools work.
|
32
|
+
//!
|
33
|
+
//! \section where_to_start Where To Start
|
34
|
+
//!
|
35
|
+
//! AsmJit \ref asmjit_core provides the following two classes that are essential from the code generation perspective:
|
36
|
+
//!
|
37
|
+
//! - \ref CodeHolder provides functionality to temporarily hold the generated code. It stores all the necessary
|
38
|
+
//! information about the code - code buffers, sections, labels, symbols, and information about relocations.
|
39
|
+
//!
|
40
|
+
//! - \ref BaseEmitter provides interface used by emitter implementations. The interface provides basic building
|
41
|
+
//! blocks that are then implemented by \ref BaseAssembler, \ref BaseBuilder, and \ref BaseCompiler.
|
42
|
+
//!
|
43
|
+
//! Code emitters:
|
44
|
+
//!
|
45
|
+
//! - \ref asmjit_assembler - provides direct machine code generation.
|
46
|
+
//!
|
47
|
+
//! - \ref asmjit_builder - provides intermediate code generation that can be processed before it's serialized to
|
48
|
+
//! \ref BaseAssembler.
|
49
|
+
//!
|
50
|
+
//! - \ref asmjit_compiler - provides high-level code generation with built-in register allocation.
|
51
|
+
//!
|
52
|
+
//! - \ref FuncNode - provides insight into how function looks from the Compiler perspective and how it's stored in
|
53
|
+
//! a node-list.
|
54
|
+
//!
|
55
|
+
//! \section main_recommendations Recommendations
|
56
|
+
//!
|
57
|
+
//! The following steps are recommended for all AsmJit users:
|
58
|
+
//!
|
59
|
+
//! - Make sure that you use \ref Logger, see \ref asmjit_logging.
|
60
|
+
//!
|
61
|
+
//! - Make sure that you use \ref ErrorHandler, see \ref asmjit_error_handling.
|
62
|
+
//!
|
63
|
+
//! - Instruction validation in your debug builds can reveal problems too. AsmJit provides validation at instruction
|
64
|
+
//! level that can be enabled via \ref BaseEmitter::addDiagnosticOptions(). See \ref DiagnosticOptions for more
|
65
|
+
//! details.
|
66
|
+
//!
|
67
|
+
//! - If you are a Compiler user, use diagnostic options and read carefully if anything suspicious pops out.
|
68
|
+
//! Diagnostic options can be enabled via \ref BaseEmitter::addDiagnosticOptions(). If unsure which ones to use,
|
69
|
+
//! enable annotations and all debug options: `DiagnosticOptions::kRAAnnotate | DiagnosticOptions::kRADebugAll`.
|
70
|
+
//!
|
71
|
+
//! - Make sure you put a breakpoint into \ref DebugUtils::errored() function if you have a problem with AsmJit
|
72
|
+
//! returning errors during instruction encoding or register allocation. Having an active breakpoint there can
|
73
|
+
//! help to reveal the origin of the error, to inspect variables and other conditions that caused it.
|
74
|
+
//!
|
75
|
+
//! The reason for using \ref Logger and \ref ErrorHandler is that they provide a very useful information about what's
|
76
|
+
//! happening inside emitters. In many cases the information provided by these two is crucial to quickly identify and
|
77
|
+
//! fix issues that happen during development (for example wrong instruction, address, or register used). In addition,
|
78
|
+
//! output from \ref Logger is always necessary when filling bug reports. In other words, using logging and proper error
|
79
|
+
//! handling can save a lot of time during the development and can also save users from submitting issues.
|
80
|
+
//!
|
81
|
+
//! \section main_other Other Pages
|
82
|
+
//!
|
83
|
+
//! - <a href="annotated.html">Class List</a> - List of classes sorted alphabetically
|
84
|
+
//! - <a href="namespaceasmjit.html">AsmJit Namespace</a> - List of symbols provided by `asmjit` namespace
|
85
|
+
|
86
|
+
|
87
|
+
//! \defgroup asmjit_build Build Instructions
|
88
|
+
//! \brief Build instructions, supported environments, and feature selection.
|
89
|
+
//!
|
90
|
+
//! ### Overview
|
91
|
+
//!
|
92
|
+
//! AsmJit is designed to be easy embeddable in any project. However, it depends on some compile-time definitions that
|
93
|
+
//! can be used to enable or disable features to decrease the resulting binary size. A typical way of building AsmJit
|
94
|
+
//! is to use [cmake](https://www.cmake.org), but it's also possible to just include AsmJit source code in your project
|
95
|
+
//! and to just build it. The easiest way to include AsmJit in your project is to just include **src** directory in
|
96
|
+
//! your project and to define \ref ASMJIT_STATIC. AsmJit can be just updated from time to time without any changes to
|
97
|
+
//! this integration process. Do not embed AsmJit's `test` files in such case as these are used exclusively for testing.
|
98
|
+
//!
|
99
|
+
//! ### Supported C++ Compilers
|
100
|
+
//!
|
101
|
+
//! - Requirements:
|
102
|
+
//!
|
103
|
+
//! - AsmJit won't build without C++11 enabled. If you use older GCC or Clang you would have to enable at least
|
104
|
+
//! C++11 standard through compiler flags.
|
105
|
+
//!
|
106
|
+
//! - Tested:
|
107
|
+
//!
|
108
|
+
//! - **Clang** - Tested by GitHub Actions - Clang 3.9+ (with C++11 enabled) is officially supported (older Clang
|
109
|
+
//! versions having C++11 support are probably fine, but are not regularly tested).
|
110
|
+
//!
|
111
|
+
//! - **GNU** - Tested by GitHub Actions - GCC 4.8+ (with C++11 enabled) is officially supported.
|
112
|
+
//!
|
113
|
+
//! - **MINGW** - Should work, but it's not tested in our CI environment.
|
114
|
+
//!
|
115
|
+
//! - **MSVC** - Tested by GitHub Actions - VS2017+ is officially supported, VS2015 is reported to work.
|
116
|
+
//!
|
117
|
+
//! - Untested:
|
118
|
+
//!
|
119
|
+
//! - **Intel** - No maintainers and no CI environment to regularly test this compiler.
|
120
|
+
//!
|
121
|
+
//! - **Other** C++ compilers would require basic support in
|
122
|
+
//! [core/api-config.h](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/api-config.h).
|
123
|
+
//!
|
124
|
+
//! ### Supported Operating Systems and Platforms
|
125
|
+
//!
|
126
|
+
//! - Tested:
|
127
|
+
//!
|
128
|
+
//! - **Linux** - Tested by GitHub Actions (any distribution is generally supported).
|
129
|
+
//!
|
130
|
+
//! - **Mac OS** - Tested by GitHub Actions (any version is supported).
|
131
|
+
//!
|
132
|
+
//! - **Windows** - Tested by GitHub Actions - (Windows 7+ is officially supported).
|
133
|
+
//!
|
134
|
+
//! - **Emscripten** - Works if compiled with \ref ASMJIT_NO_JIT. AsmJit cannot generate WASM code, but can be
|
135
|
+
//! used to generate X86/X64 code within a browser, for example.
|
136
|
+
//!
|
137
|
+
//! - Untested:
|
138
|
+
//!
|
139
|
+
//! - **BSDs** - No maintainers, no CI environment to regularly test BSDs, but they should work out of box.
|
140
|
+
//!
|
141
|
+
//! - **Haiku** - Not regularly tested, but reported to work.
|
142
|
+
//!
|
143
|
+
//! - **Other** operating systems would require some testing and support in the following files:
|
144
|
+
//! - [core/api-config.h](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/api-config.h)
|
145
|
+
//! - [core/osutils.cpp](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/osutils.cpp)
|
146
|
+
//! - [core/virtmem.cpp](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/virtmem.cpp)
|
147
|
+
//!
|
148
|
+
//! ### Supported Backends / Architectures
|
149
|
+
//!
|
150
|
+
//! - **X86** and **X86_64** - Both 32-bit and 64-bit backends tested on CI.
|
151
|
+
//! - **AArch64** - AArch64 backend is currently only partially tested (there is no native AArch64 runner to test
|
152
|
+
//! AsmJit Builder/Compiler)
|
153
|
+
//!
|
154
|
+
//! ### Static Builds and Embedding
|
155
|
+
//!
|
156
|
+
//! These definitions can be used to enable static library build. Embed is used when AsmJit's source code is embedded
|
157
|
+
//! directly in another project, implies static build as well.
|
158
|
+
//!
|
159
|
+
//! - \ref ASMJIT_EMBED - Asmjit is embedded, implies \ref ASMJIT_STATIC.
|
160
|
+
//! - \ref ASMJIT_STATIC - Enable static-library build.
|
161
|
+
//!
|
162
|
+
//! \note Projects that use AsmJit statically must define \ref ASMJIT_STATIC in all compilation units that use AsmJit,
|
163
|
+
//! otherwise AsmJit would use dynamic library imports in \ref ASMJIT_API decorator. The recommendation is to define
|
164
|
+
//! this macro across the whole project that uses AsmJit this way.
|
165
|
+
//!
|
166
|
+
//! ### Build Configuration
|
167
|
+
//!
|
168
|
+
//! These definitions control whether asserts are active or not. By default AsmJit would autodetect build configuration
|
169
|
+
//! from existing pre-processor definitions, but this behavior can be overridden, for example to enable debug asserts
|
170
|
+
//! in release configuration.
|
171
|
+
//!
|
172
|
+
//! - \ref ASMJIT_BUILD_DEBUG - Overrides build configuration to debug, asserts will be enabled in this case.
|
173
|
+
//! - \ref ASMJIT_BUILD_RELEASE - Overrides build configuration to release, asserts will be disabled in this case.
|
174
|
+
//!
|
175
|
+
//! \note There is usually no need to override the build configuration. AsmJit detects the build configuration by
|
176
|
+
//! checking whether `NDEBUG` is defined and automatically defines \ref ASMJIT_BUILD_RELEASE if configuration overrides
|
177
|
+
//! were not used. We only recommend using build configuration overrides in special situations, like using AsmJit in
|
178
|
+
//! release configuration with asserts enabled for whatever reason.
|
179
|
+
//!
|
180
|
+
//! ### AsmJit Backends
|
181
|
+
//!
|
182
|
+
//! AsmJit currently supports only X86/X64 backend, but the plan is to add more backends in the future. By default
|
183
|
+
//! AsmJit builds only the host backend, which is autodetected at compile-time, but this can be overridden.
|
184
|
+
//!
|
185
|
+
//! - \ref ASMJIT_NO_X86 - Disable X86/X64 backends.
|
186
|
+
//! - \ref ASMJIT_NO_FOREIGN - Disables the support for foreign architectures.
|
187
|
+
//!
|
188
|
+
//! ### Features Selection
|
189
|
+
//!
|
190
|
+
//! AsmJit builds by defaults all supported features, which includes all emitters, logging, instruction validation and
|
191
|
+
//! introspection, and JIT memory allocation. Features can be disabled at compile time by using `ASMJIT_NO_...`
|
192
|
+
//! definitions.
|
193
|
+
//!
|
194
|
+
//! - \ref ASMJIT_NO_DEPRECATED - Disables deprecated API at compile time so it won't be available and the
|
195
|
+
//! compilation will fail if there is attempt to use such API. This includes deprecated classes, namespaces,
|
196
|
+
//! enumerations, and functions.
|
197
|
+
//!
|
198
|
+
//! - \ref ASMJIT_NO_BUILDER - Disables \ref asmjit_builder functionality completely. This implies \ref
|
199
|
+
//! ASMJIT_NO_COMPILER as \ref asmjit_compiler cannot be used without \ref asmjit_builder.
|
200
|
+
//!
|
201
|
+
//! - \ref ASMJIT_NO_COMPILER - Disables \ref asmjit_compiler functionality completely.
|
202
|
+
//!
|
203
|
+
//! - \ref ASMJIT_NO_JIT - Disables JIT memory management and \ref JitRuntime.
|
204
|
+
//!
|
205
|
+
//! - \ref ASMJIT_NO_LOGGING - Disables \ref Logger and \ref Formatter.
|
206
|
+
//!
|
207
|
+
//! - \ref ASMJIT_NO_TEXT - Disables everything that contains string representation of AsmJit constants, should
|
208
|
+
//! be used together with \ref ASMJIT_NO_LOGGING as logging doesn't make sense without the ability to query
|
209
|
+
//! instruction names, register names, etc...
|
210
|
+
//!
|
211
|
+
//! - \ref ASMJIT_NO_VALIDATION - Disables validation API.
|
212
|
+
//!
|
213
|
+
//! - \ref ASMJIT_NO_INTROSPECTION - Disables instruction introspection API, must be used together with \ref
|
214
|
+
//! ASMJIT_NO_COMPILER as \ref asmjit_compiler requires introspection for its liveness analysis and register
|
215
|
+
//! allocation.
|
216
|
+
//!
|
217
|
+
//! \note It's not recommended to disable features if you plan to build AsmJit as a shared library that will be
|
218
|
+
//! used by multiple projects that you don't control how AsmJit was built (for example AsmJit in a Linux distribution).
|
219
|
+
//! The possibility to disable certain features exists mainly for customized AsmJit builds.
|
220
|
+
|
221
|
+
|
222
|
+
//! \defgroup asmjit_breaking_changes Breaking Changes
|
223
|
+
//! \brief Documentation of breaking changes
|
224
|
+
//!
|
225
|
+
//! ### Overview
|
226
|
+
//!
|
227
|
+
//! AsmJit is a live project that is being actively developed. Deprecating the existing API in favor of a new
|
228
|
+
//! one is preferred, but it's not always possible if the changes are significant. AsmJit authors prefer to do
|
229
|
+
//! accumulated breaking changes at once instead of breaking the API often. This page documents deprecated and
|
230
|
+
//! removed APIs and should serve as a how-to guide for people that want to port existing code to work with the
|
231
|
+
//! newest AsmJit.
|
232
|
+
//!
|
233
|
+
//! ### Tips
|
234
|
+
//!
|
235
|
+
//! Useful tips before you start:
|
236
|
+
//!
|
237
|
+
//! - Visit our [Public Gitter Channel](https://gitter.im/asmjit/asmjit) if you need a quick help.
|
238
|
+
//!
|
239
|
+
//! - Build AsmJit with `ASMJIT_NO_DEPRECATED` macro defined to make sure that you are not using deprecated
|
240
|
+
//! functionality at all. Deprecated functions are decorated with `ASMJIT_DEPRECATED()` macro, but sometimes
|
241
|
+
//! it's not possible to decorate everything like classes, which are used by deprecated functions as well,
|
242
|
+
//! because some compilers would warn about that. If your project compiles fine with `ASMJIT_NO_DEPRECATED`
|
243
|
+
//! it's not using anything, which was deprecated.
|
244
|
+
//!
|
245
|
+
//! ### Changes committed at 2021-12-13
|
246
|
+
//!
|
247
|
+
//! Core changes:
|
248
|
+
//!
|
249
|
+
//! - Removed old deprecated API.
|
250
|
+
//!
|
251
|
+
//! - Many enumerations were changed to enum class, and many public APIs were changed to use such enums instead
|
252
|
+
//! of uint32_t. This change makes some APIs backward incompatible - there are no deprecations this time.
|
253
|
+
//!
|
254
|
+
//! - Extracted operand signature manipulation to `OperandSignature`.
|
255
|
+
//! - Setting function arguments through `Compiler::setArg()` was deprecated, use FuncNode::setArg() instead.
|
256
|
+
//! - Moved `{arch}::Features::k` to `CpuFeatures::{arch}::k`.
|
257
|
+
//! - Moved `BaseEmitter::kEncodingOption` to `EncodingOptions::k`.
|
258
|
+
//! - Moved `BaseEmitter::kFlag` to `EmitterFlags::k`.
|
259
|
+
//! - Moved `BaseEmitter::kType` to `EmitterType::k`.
|
260
|
+
//! - Moved `BaseEmitter::kValidationOption` to `DiagnosticOptions::kValidate`.
|
261
|
+
//! - Moved `BaseFeatures` to `CpuFeatures`.
|
262
|
+
//! - Moved `BaseInst::kControl` to `InstControlFlow::k`.
|
263
|
+
//! - Moved `BaseInst::kOption` and `x86::Inst::kOption` to `InstOptions::k`.
|
264
|
+
//! - Moved `BaseNode::kNode` to `NodeType::k`.
|
265
|
+
//! - Moved `BaseReg::kGroup` and `x86::Reg::kGroup` to `RegGroup::k`.
|
266
|
+
//! - Moved `BaseReg::kType` and `x86::Reg::kType` to `RegType::k`.
|
267
|
+
//! - Moved `CallConv::kFlag` to `CallConvFlags::k`.
|
268
|
+
//! - Moved `CallConv::kId` to `CallConvId::k`.
|
269
|
+
//! - Moved `CallConv::kStrategy` to `CallConvStrategy::k`.
|
270
|
+
//! - Moved `CodeBuffer::kFlag` to `CodeBufferFlags`.
|
271
|
+
//! - Moved `ConstPool::kScope` to `ConstPoolScope::k`.
|
272
|
+
//! - Moved `Environment::kArch` to `Arch::k`.
|
273
|
+
//! - Moved `Environment::kSubArch` to `SubArch::k`.
|
274
|
+
//! - Moved `Environment::kFormat` to `OjectFormat::k`.
|
275
|
+
//! - Moved `Environment::kPlatform` to `Platform::k`.
|
276
|
+
//! - Moved `Environment::kAbi` to `PlatformABI::k`.
|
277
|
+
//! - Moved `Environment::kVendor` to `Vendor::k`.
|
278
|
+
//! - Moved `FormatOptions::kFlag` to `FormatFlags::k` and `DiagnosticOptions::k` (Compiler diagnostics flags).
|
279
|
+
//! - Moved `FormatOptions::kIndentation` to `FormatIndentationGroup::k`.
|
280
|
+
//! - Moved `FuncFrame::kAttr` to `FuncAttributes::k`.
|
281
|
+
//! - Moved `Globals::kReset` to `ResetPolicy::k`.
|
282
|
+
//! - Moved `InstDB::kAvx512Flag` to `InstDB::Avx512Flags::k`.
|
283
|
+
//! - Moved `InstDB::kFlag` to `InstDB::InstFlags::k`.
|
284
|
+
//! - Moved `InstDB::kMemFlag` to `InstDB::OpFlags::kMem`.
|
285
|
+
//! - Moved `InstDB::kMode` to `InstDB::Mode::k`.
|
286
|
+
//! - Moved `InstDB::kOpFlag` to `InstDB::OpFlags::k{OpType}...`.
|
287
|
+
//! - Moved `JitAllocator::kOption` to `JitAllocatorOptions::k`.
|
288
|
+
//! - Moved `Label::kType` to `LabelType::k`.
|
289
|
+
//! - Moved `Operand::kOpType` to `OperandType::k`.
|
290
|
+
//! - Moved `OpRWInfo::kFlag` to `OpRWFlags::k`.
|
291
|
+
//! - Moved `Type::kId` to `TypeId::k`.
|
292
|
+
//! - Moved `VirtMem::k` to `VirtMem::MemoryFlags::k`.
|
293
|
+
//!
|
294
|
+
//! ### Changes committed at 2020-05-30
|
295
|
+
//!
|
296
|
+
//! AsmJit has been cleaned up significantly, many todo items have been fixed and many functions and classes have
|
297
|
+
//! been redesigned, some in an incompatible way.
|
298
|
+
//!
|
299
|
+
//! Core changes:
|
300
|
+
//!
|
301
|
+
//! - `Imm` operand has now only `Imm::value()` and `Imm::valueAs()` functions that return its value content,
|
302
|
+
//! and `Imm::setValue()` function that sets the content. Functions like `setI8()`, `setU8()` were deprecated.
|
303
|
+
//!
|
304
|
+
//! Old functions were deprecated, but code using them should still compile.
|
305
|
+
//!
|
306
|
+
//! - `ArchInfo` has been replaced with `Environment`. Environment provides more details about the architecture,
|
307
|
+
//! but drops some properties that were used by arch info - `gpSize(`) and `gpCount()`. `gpSize()` can be replaced
|
308
|
+
//! with `registerSize()` getter, which returns a native register size of the architecture the environment uses.
|
309
|
+
//! However, `gpCount()` was removed - at the moment `ArchTraits` can be used to access such properties.
|
310
|
+
//!
|
311
|
+
//! Some other functions were renamed, like `ArchInfo::isX86Family()` is now `Environment::isFamilyX86()`, etc.
|
312
|
+
//! The reason for changing the order was support for more propertries and all the accessors now start with the
|
313
|
+
//! type of the property, like `Environment::isPlatformWindows()`.
|
314
|
+
//!
|
315
|
+
//! This function causes many other classes to provide `environment()` getter instead of `archInfo()` getter.
|
316
|
+
//! In addition, AsmJit now uses `arch()` to get an architecture instead of `archId()`. `ArchInfo::kIdXXX` was
|
317
|
+
//! renamed to `Environment::kArchXXX`.
|
318
|
+
//!
|
319
|
+
//! Some functions were deprecated, some removed...
|
320
|
+
//!
|
321
|
+
//! - `CodeInfo` has been removed in favor of `Environment`. If you used `CodeInfo` to set architecture and base
|
322
|
+
//! address, this is now possible with `Environment` and setting base address explicitly by `CodeHolder::init()`
|
323
|
+
//! - the first argument is `Environment`, and the second argument is base address, which defaults to
|
324
|
+
//! `Globals::kNoBaseAddress`.
|
325
|
+
//!
|
326
|
+
//! CodeInfo class was deprecated, but the code using it should still compile with warnings.
|
327
|
+
//!
|
328
|
+
//! - `CallConv` has been updated to offer a more unified way of representing calling conventions - many calling
|
329
|
+
//! conventions were abstracted to follow standard naming like `CallConvId::kCDecl` or `CallConvId::kStdCall`.
|
330
|
+
//!
|
331
|
+
//! This change means that other APIs like `FuncDetail::init()` now require both, calling convention and target
|
332
|
+
//! `Environment`.
|
333
|
+
//!
|
334
|
+
//! - `Logging` namespace has been renamed to `Formatter`, which now provides general functionality for formatting
|
335
|
+
//! in AsmJit.
|
336
|
+
//!
|
337
|
+
//! Logging namespace should still work, but its use is deprecated. Unfortunately this will be without deprecation
|
338
|
+
//! warnings, so make sure you don't use it.
|
339
|
+
//!
|
340
|
+
//! - `Data64`, `Data128`, and `Data256` structs were deprecated and should no longer be used. There is no replacement,
|
341
|
+
//! AsmJit users should simply create their own structures if they need them or use the new repeated embed API in
|
342
|
+
//! emitters, see `BaseEmitter::embedDataArray()`.
|
343
|
+
//!
|
344
|
+
//! Emitter changes:
|
345
|
+
//!
|
346
|
+
//! - `BaseEmitter::emit()` function signature has been changed to accept 3 operands by reference and the rest 3
|
347
|
+
//! operands as a continuous array. This change is purely cosmetic and shouldn't affect users as emit() has many
|
348
|
+
//! overloads that dispatch to the right function.
|
349
|
+
//!
|
350
|
+
//! - `x86::Emitter` (Assembler, Builder, Compiler) deprecates embed utilities like `dint8()`, `duint8()`, `duint16()`,
|
351
|
+
//! `dxmm()`, etc... in favor of a new and more powerful `BaseEmitter::embedDataArray()`. This function also allows
|
352
|
+
//! emitting repeated values and/or patterns, which is used by helpers `BaseEmitter::embedUInt8()`, and others...
|
353
|
+
//!
|
354
|
+
//! - Validation is now available through `BaseEmitter::DiagnosticOptions`, which can be enabled/disabled through
|
355
|
+
//! `BaseEmitter::addDiagnosticOptions()` and `BaseEmitter::clearDiagnosticOptions()`, respectively. Validation
|
356
|
+
//! options now separate between encoding and Builder/Compiler so it's possible to choose the granularity required.
|
357
|
+
//!
|
358
|
+
//! Builder changes:
|
359
|
+
//!
|
360
|
+
//! - Internal functions for creating nodes were redesigned. They now accept a pointer to the node created as
|
361
|
+
//! a first parameter. These changes should not affect AsmJit users as these functions were used internally.
|
362
|
+
//!
|
363
|
+
//! Compiler changes:
|
364
|
+
//!
|
365
|
+
//! - `FuncCallNode` has been renamed to `InvokeNode`. Additionally, function calls should now use
|
366
|
+
//! `x86::Compiler::invoke()` instead of `call()`. The reason behind this is to remove the confusion between a
|
367
|
+
//! `call` instruction and AsmJit's `call()` intrinsic, which is now `invoke()`.
|
368
|
+
//!
|
369
|
+
//! - Creating new nodes also changed. Now the preferred way of invoking a function is to call
|
370
|
+
//! `x86::Compiler::invoke()` where the first argument is `InvokeNode**`. The function now returns an error and
|
371
|
+
//! would call `ErrorHandler` in case of a failure. Error handling was unspecified in the past - the function was
|
372
|
+
//! marked noexcept, but called error handler, which could throw.
|
373
|
+
//!
|
374
|
+
//! The reason behind this change is to make the API consistent with other changes and to also make it possible
|
375
|
+
//! to inspect the possible error. In the previous API it returned a new node or `nullptr` in case of error,
|
376
|
+
//! which the user couldn't inspect unless there was an attached `ErrorHandler`.
|
377
|
+
//!
|
378
|
+
//! Samples:
|
379
|
+
//!
|
380
|
+
//! ```
|
381
|
+
//! #include <asmjit/x86.h>
|
382
|
+
//!
|
383
|
+
//! using namespace asmjit;
|
384
|
+
//!
|
385
|
+
//! // The basic setup of JitRuntime and CodeHolder changed, use environment()
|
386
|
+
//! // instead of codeInfo().
|
387
|
+
//! void basicSetup() {
|
388
|
+
//! JitRuntime rt;
|
389
|
+
//! CodeHolder code(rt.environment());
|
390
|
+
//! }
|
391
|
+
//!
|
392
|
+
//! // Calling a function (Compiler) changed - use invoke() instead of call().
|
393
|
+
//! void functionInvocation(x86::Compiler& cc) {
|
394
|
+
//! InvokeNode* invokeNode;
|
395
|
+
//! cc.invoke(&invokeNode, targetOperand, FuncSignatureT<...>(...));
|
396
|
+
//! }
|
397
|
+
//! ```
|
398
|
+
|
399
|
+
|
400
|
+
//! \defgroup asmjit_core Core
|
401
|
+
//! \brief Globals, code storage, and emitter interface.
|
402
|
+
//!
|
403
|
+
//! ### Overview
|
404
|
+
//!
|
405
|
+
//! AsmJit library uses \ref CodeHolder to hold code during code generation and emitters inheriting from \ref
|
406
|
+
//! BaseEmitter to emit code. CodeHolder uses containers to manage its data:
|
407
|
+
//!
|
408
|
+
//! - \ref Section - stores information about a code or data section.
|
409
|
+
//! - \ref CodeBuffer - stores actual code or data, part of \ref Section.
|
410
|
+
//! - \ref LabelEntry - stores information about a label - its name, offset, section where it belongs to, and
|
411
|
+
//! other bits.
|
412
|
+
//! - \ref LabelLink - stores information about yet unbound label, which was already used by the assembler.
|
413
|
+
//! - \ref RelocEntry - stores information about a relocation.
|
414
|
+
//! - \ref AddressTableEntry - stores information about an address, which was used in a jump or call. Such
|
415
|
+
//! address may need relocation.
|
416
|
+
//!
|
417
|
+
//! To generate code you would need to instantiate at least the following classes:
|
418
|
+
//!
|
419
|
+
//! - \ref CodeHolder - to hold code during code generation.
|
420
|
+
//! - \ref BaseEmitter - to emit code into \ref CodeHolder.
|
421
|
+
//! - \ref Target (optional) - most likely \ref JitRuntime to keep the generated code in executable memory. \ref
|
422
|
+
//! Target can be customized by inheriting from it.
|
423
|
+
//!
|
424
|
+
//! There are also other core classes that are important:
|
425
|
+
//!
|
426
|
+
//! - \ref Environment - describes where the code will run. Environment brings the concept of target triples or
|
427
|
+
//! tuples into AsmJit, which means that users can specify target architecture, platform, and ABI.
|
428
|
+
//! - \ref TypeId - encapsulates lightweight type functionality that can be used to describe primitive and vector
|
429
|
+
//! types. Types are used by higher level utilities, for example by \ref asmjit_function and \ref asmjit_compiler.
|
430
|
+
//! - \ref CpuInfo - encapsulates CPU information - stores both CPU information and CPU features described by \ref
|
431
|
+
//! CpuFeatures.
|
432
|
+
//!
|
433
|
+
//! AsmJit also provides global constants:
|
434
|
+
//!
|
435
|
+
//! - \ref Globals - namespace that provides global constants.
|
436
|
+
//! - \ref ByteOrder - byte-order constants and functionality.
|
437
|
+
//!
|
438
|
+
//! \note CodeHolder examples use \ref x86::Assembler as abstract interfaces cannot be used to generate code.
|
439
|
+
//!
|
440
|
+
//! ### CodeHolder & Emitters
|
441
|
+
//!
|
442
|
+
//! The example below shows how the mentioned classes interact to generate X86 code:
|
443
|
+
//!
|
444
|
+
//! ```
|
445
|
+
//! #include <asmjit/x86.h>
|
446
|
+
//! #include <stdio.h>
|
447
|
+
//!
|
448
|
+
//! using namespace asmjit;
|
449
|
+
//!
|
450
|
+
//! // Signature of the generated function.
|
451
|
+
//! typedef int (*Func)(void);
|
452
|
+
//!
|
453
|
+
//! int main() {
|
454
|
+
//! JitRuntime rt; // Runtime specialized for JIT code execution.
|
455
|
+
//!
|
456
|
+
//! CodeHolder code; // Holds code and relocation information.
|
457
|
+
//! code.init(rt.environment()); // Initialize code to match the JIT environment.
|
458
|
+
//!
|
459
|
+
//! x86::Assembler a(&code); // Create and attach x86::Assembler to code.
|
460
|
+
//! a.mov(x86::eax, 1); // Move one to eax register.
|
461
|
+
//! a.ret(); // Return from function.
|
462
|
+
//! // ===== x86::Assembler is no longer needed from here and can be destroyed =====
|
463
|
+
//!
|
464
|
+
//! Func fn; // Holds address to the generated function.
|
465
|
+
//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime.
|
466
|
+
//! if (err) return 1; // Handle a possible error returned by AsmJit.
|
467
|
+
//! // ===== CodeHolder is no longer needed from here and can be destroyed =====
|
468
|
+
//!
|
469
|
+
//! int result = fn(); // Execute the generated code.
|
470
|
+
//! printf("%d\n", result); // Print the resulting "1".
|
471
|
+
//!
|
472
|
+
//! // All classes use RAII, all resources will be released before `main()` returns,
|
473
|
+
//! // the generated function can be, however, released explicitly if you intend to
|
474
|
+
//! // reuse or keep the runtime alive, which you should in a production-ready code.
|
475
|
+
//! rt.release(fn);
|
476
|
+
//!
|
477
|
+
//! return 0;
|
478
|
+
//! }
|
479
|
+
//! ```
|
480
|
+
//!
|
481
|
+
//! The example above used \ref x86::Assembler as an emitter. AsmJit provides the following emitters that offer various
|
482
|
+
//! levels of abstraction:
|
483
|
+
//!
|
484
|
+
//! - \ref asmjit_assembler - Low-level emitter that emits directly to \ref CodeBuffer.
|
485
|
+
//! - \ref asmjit_builder - Low-level emitter that emits to a \ref BaseNode list.
|
486
|
+
//! - \ref asmjit_compiler - High-level emitter that provides register allocation.
|
487
|
+
//!
|
488
|
+
//! ### Targets and JitRuntime
|
489
|
+
//!
|
490
|
+
//! AsmJit's \ref Target is an interface that provides basic target abstraction. At the moment AsmJit provides only
|
491
|
+
//! one implementation called \ref JitRuntime, which as the name suggests provides JIT code target and execution
|
492
|
+
//! runtime. \ref JitRuntime provides all the necessary stuff to implement a simple JIT compiler with basic memory
|
493
|
+
//! management. It only provides \ref JitRuntime::add() and \ref JitRuntime::release() functions that are used to
|
494
|
+
//! either add code to the runtime or release it. \ref JitRuntime doesn't do any decisions on when the code should be
|
495
|
+
//! released, the decision is up to the developer.
|
496
|
+
//!
|
497
|
+
//! See more at \ref asmjit_virtual_memory group.
|
498
|
+
//!
|
499
|
+
//! ### More About Environment
|
500
|
+
//!
|
501
|
+
//! In the previous example the \ref Environment is retrieved from \ref JitRuntime. It's logical as \ref JitRuntime
|
502
|
+
//! always returns an \ref Environment that is compatible with the host. For example if your application runs on X86_64
|
503
|
+
//! CPU the \ref Environment returned will use \ref Arch::kX64 architecture in contrast to \ref Arch::kX86, which will
|
504
|
+
//! be used in 32-bit mode on an X86 target.
|
505
|
+
//!
|
506
|
+
//! AsmJit allows to setup the \ref Environment manually and to select a different architecture and ABI when necessary.
|
507
|
+
//! So let's do something else this time, let's always generate a 32-bit code and print its binary representation. To
|
508
|
+
//! do that, we can create our own \ref Environment and initialize it to \ref Arch::kX86.
|
509
|
+
//!
|
510
|
+
//! ```
|
511
|
+
//! #include <asmjit/x86.h>
|
512
|
+
//! #include <stdio.h>
|
513
|
+
//!
|
514
|
+
//! using namespace asmjit;
|
515
|
+
//!
|
516
|
+
//! int main(int argc, char* argv[]) {
|
517
|
+
//! using namespace asmjit::x86;
|
518
|
+
//!
|
519
|
+
//! // Create a custom environment initialized to 32-bit X86 architecture.
|
520
|
+
//! Environment env;
|
521
|
+
//! env.setArch(Arch::kX86);
|
522
|
+
//!
|
523
|
+
//! CodeHolder code; // Create a CodeHolder.
|
524
|
+
//! code.init(env); // Initialize CodeHolder with custom environment.
|
525
|
+
//!
|
526
|
+
//! // Generate a 32-bit function that sums 4 floats and looks like:
|
527
|
+
//! // void func(float* dst, const float* a, const float* b)
|
528
|
+
//! x86::Assembler a(&code); // Create and attach x86::Assembler to `code`.
|
529
|
+
//!
|
530
|
+
//! a.mov(eax, dword_ptr(esp, 4)); // Load the destination pointer.
|
531
|
+
//! a.mov(ecx, dword_ptr(esp, 8)); // Load the first source pointer.
|
532
|
+
//! a.mov(edx, dword_ptr(esp, 12)); // Load the second source pointer.
|
533
|
+
//!
|
534
|
+
//! a.movups(xmm0, ptr(ecx)); // Load 4 floats from [ecx] to XMM0.
|
535
|
+
//! a.movups(xmm1, ptr(edx)); // Load 4 floats from [edx] to XMM1.
|
536
|
+
//! a.addps(xmm0, xmm1); // Add 4 floats in XMM1 to XMM0.
|
537
|
+
//! a.movups(ptr(eax), xmm0); // Store the result to [eax].
|
538
|
+
//! a.ret(); // Return from function.
|
539
|
+
//!
|
540
|
+
//! // We have no Runtime this time, it's on us what we do with the code.
|
541
|
+
//! // CodeHolder stores code in Section, which provides some basic properties
|
542
|
+
//! // and CodeBuffer structure. We are interested in section's CodeBuffer.
|
543
|
+
//! //
|
544
|
+
//! // NOTE: The first section is always '.text', it can be retrieved by
|
545
|
+
//! // code.sectionById(0) or simply by code.textSection().
|
546
|
+
//! CodeBuffer& buffer = code.textSection()->buffer();
|
547
|
+
//!
|
548
|
+
//! // Print the machine-code generated or do something else with it...
|
549
|
+
//! // 8B4424048B4C24048B5424040F28010F58010F2900C3
|
550
|
+
//! for (size_t i = 0; i < buffer.length; i++)
|
551
|
+
//! printf("%02X", buffer.data[i]);
|
552
|
+
//!
|
553
|
+
//! return 0;
|
554
|
+
//! }
|
555
|
+
//! ```
|
556
|
+
//!
|
557
|
+
//! ### Explicit Code Relocation
|
558
|
+
//!
|
559
|
+
//! In addition to \ref Environment, \ref CodeHolder can be configured to specify a base-address (or a virtual base
|
560
|
+
//! address in a linker terminology), which could be static (useful when you know the location where the target's
|
561
|
+
//! machine code will be) or dynamic. AsmJit assumes dynamic base-address by default and relocates the code held by
|
562
|
+
//! \ref CodeHolder to a user provided address on-demand. To be able to relocate to a user provided address it needs
|
563
|
+
//! to store some information about relocations, which is represented by \ref RelocEntry. Relocation entries are only
|
564
|
+
//! required if you call external functions from the generated code that cannot be encoded by using a 32-bit
|
565
|
+
//! displacement (64-bit displacements are not provided by aby supported architecture).
|
566
|
+
//!
|
567
|
+
//! There is also a concept called \ref LabelLink - label link is a lightweight data structure that doesn't have any
|
568
|
+
//! identifier and is stored in \ref LabelEntry as a single-linked list. Label link represents either unbound yet used
|
569
|
+
//! label and cross-sections links (only relevant to code that uses multiple sections). Since crossing sections is
|
570
|
+
//! something that cannot be resolved immediately these links persist until offsets of these sections are assigned and
|
571
|
+
//! until \ref CodeHolder::resolveUnresolvedLinks() is called. It's an error if you end up with code that has
|
572
|
+
//! unresolved label links after flattening. You can verify it by calling \ref CodeHolder::hasUnresolvedLinks(), which
|
573
|
+
//! inspects the value returned by \ref CodeHolder::unresolvedLinkCount().
|
574
|
+
//!
|
575
|
+
//! AsmJit can flatten code that uses multiple sections by assigning each section an incrementing offset that respects
|
576
|
+
//! its alignment. Use \ref CodeHolder::flatten() to do that. After the sections are flattened their offsets and
|
577
|
+
//! virtual sizes are adjusted to respect each section's buffer size and alignment. The \ref
|
578
|
+
//! CodeHolder::resolveUnresolvedLinks() function must be called before relocating the code held by \ref CodeHolder.
|
579
|
+
//! You can also flatten your code manually by iterating over all sections and calculating their offsets (relative to
|
580
|
+
//! base) by your own algorithm. In that case \ref CodeHolder::flatten() should not be called, however,
|
581
|
+
//! \ref CodeHolder::resolveUnresolvedLinks() should be.
|
582
|
+
//!
|
583
|
+
//! The example below shows how to use a built-in virtual memory allocator \ref JitAllocator instead of using \ref
|
584
|
+
//! JitRuntime (just in case you want to use your own memory management) and how to relocate the generated code
|
585
|
+
//! into your own memory block - you can use your own virtual memory allocator if you prefer that, but that's OS
|
586
|
+
//! specific and not covered by the documentation.
|
587
|
+
//!
|
588
|
+
//! The following code is similar to the previous one, but implements a function working in both 32-bit and 64-bit
|
589
|
+
//! environments:
|
590
|
+
//!
|
591
|
+
//! ```
|
592
|
+
//! #include <asmjit/x86.h>
|
593
|
+
//! #include <stdio.h>
|
594
|
+
//!
|
595
|
+
//! using namespace asmjit;
|
596
|
+
//!
|
597
|
+
//! typedef void (*SumIntsFunc)(int* dst, const int* a, const int* b);
|
598
|
+
//!
|
599
|
+
//! int main() {
|
600
|
+
//! // Create a custom environment that matches the current host environment.
|
601
|
+
//! Environment env = Environment::host();
|
602
|
+
//!
|
603
|
+
//! CodeHolder code; // Create a CodeHolder.
|
604
|
+
//! code.init(env); // Initialize CodeHolder with environment.
|
605
|
+
//!
|
606
|
+
//! x86::Assembler a(&code); // Create and attach x86::Assembler to `code`.
|
607
|
+
//!
|
608
|
+
//! // Signature: 'void func(int* dst, const int* a, const int* b)'.
|
609
|
+
//! x86::Gp dst;
|
610
|
+
//! x86::Gp src_a;
|
611
|
+
//! x86::Gp src_b;
|
612
|
+
//!
|
613
|
+
//! // Handle the difference between 32-bit and 64-bit calling conventions
|
614
|
+
//! // (arguments passed through stack vs. arguments passed by registers).
|
615
|
+
//! if (env.is32Bit()) {
|
616
|
+
//! dst = x86::eax;
|
617
|
+
//! src_a = x86::ecx;
|
618
|
+
//! src_b = x86::edx;
|
619
|
+
//! a.mov(dst , x86::dword_ptr(x86::esp, 4));
|
620
|
+
//! a.mov(src_a, x86::dword_ptr(x86::esp, 8));
|
621
|
+
//! a.mov(src_b, x86::dword_ptr(x86::esp, 12));
|
622
|
+
//! }
|
623
|
+
//! else {
|
624
|
+
//! if (env.isPlatformWindows()) {
|
625
|
+
//! dst = x86::rcx; // First argument (destination pointer).
|
626
|
+
//! src_a = x86::rdx; // Second argument (source 'a' pointer).
|
627
|
+
//! src_b = x86::r8; // Third argument (source 'b' pointer).
|
628
|
+
//! }
|
629
|
+
//! else {
|
630
|
+
//! dst = x86::rdi; // First argument (destination pointer).
|
631
|
+
//! src_a = x86::rsi; // Second argument (source 'a' pointer).
|
632
|
+
//! src_b = x86::rdx; // Third argument (source 'b' pointer).
|
633
|
+
//! }
|
634
|
+
//! }
|
635
|
+
//!
|
636
|
+
//! a.movdqu(x86::xmm0, x86::ptr(src_a)); // Load 4 ints from [src_a] to XMM0.
|
637
|
+
//! a.movdqu(x86::xmm1, x86::ptr(src_b)); // Load 4 ints from [src_b] to XMM1.
|
638
|
+
//! a.paddd(x86::xmm0, x86::xmm1); // Add 4 ints in XMM1 to XMM0.
|
639
|
+
//! a.movdqu(x86::ptr(dst), x86::xmm0); // Store the result to [dst].
|
640
|
+
//! a.ret(); // Return from function.
|
641
|
+
//!
|
642
|
+
//! // Even when we didn't use multiple sections AsmJit could insert one section
|
643
|
+
//! // called '.addrtab' (address table section), which would be filled by data
|
644
|
+
//! // required by relocations (absolute jumps and calls). You can omit this code
|
645
|
+
//! // if you are 100% sure your code doesn't contain multiple sections and
|
646
|
+
//! // such relocations. You can use `CodeHolder::hasAddressTable()` to verify
|
647
|
+
//! // whether the address table section does exist.
|
648
|
+
//! code.flatten();
|
649
|
+
//! code.resolveUnresolvedLinks();
|
650
|
+
//!
|
651
|
+
//! // After the code was generated it can be relocated manually to any memory
|
652
|
+
//! // location, however, we need to know it's size before we perform memory
|
653
|
+
//! // allocation. `CodeHolder::codeSize()` returns the worst estimated code
|
654
|
+
//! // size in case that relocations are not possible without trampolines (in
|
655
|
+
//! // that case some extra code at the end of the current code buffer is
|
656
|
+
//! // generated during relocation).
|
657
|
+
//! size_t estimatedSize = code.codeSize();
|
658
|
+
//!
|
659
|
+
//! // Instead of rolling up our own memory allocator we can use the one AsmJit
|
660
|
+
//! // provides. It's decoupled so you don't need to use `JitRuntime` for that.
|
661
|
+
//! JitAllocator allocator;
|
662
|
+
//!
|
663
|
+
//! // Allocate an executable virtual memory and handle a possible failure.
|
664
|
+
//! void* p = allocator.alloc(estimatedSize);
|
665
|
+
//! if (!p)
|
666
|
+
//! return 0;
|
667
|
+
//!
|
668
|
+
//! // Now relocate the code to the address provided by the memory allocator.
|
669
|
+
//! // Please note that this DOESN'T COPY anything to `p`. This function will
|
670
|
+
//! // store the address in CodeHolder and use relocation entries to patch the
|
671
|
+
//! // existing code in all sections to respect the base address provided.
|
672
|
+
//! code.relocateToBase((uint64_t)p);
|
673
|
+
//!
|
674
|
+
//! // This is purely optional. There are cases in which the relocation can omit
|
675
|
+
//! // unneeded data, which would shrink the size of address table. If that
|
676
|
+
//! // happened the codeSize returned after relocateToBase() would be smaller
|
677
|
+
//! // than the originally `estimatedSize`.
|
678
|
+
//! size_t codeSize = code.codeSize();
|
679
|
+
//!
|
680
|
+
//! // This will copy code from all sections to `p`. Iterating over all sections
|
681
|
+
//! // and calling `memcpy()` would work as well, however, this function supports
|
682
|
+
//! // additional options that can be used to also zero pad sections' virtual
|
683
|
+
//! // size, etc.
|
684
|
+
//! //
|
685
|
+
//! // With some additional features, copyFlattenData() does roughly this:
|
686
|
+
//! // for (Section* section : code.sections())
|
687
|
+
//! // memcpy((uint8_t*)p + section->offset(),
|
688
|
+
//! // section->data(),
|
689
|
+
//! // section->bufferSize());
|
690
|
+
//! code.copyFlattenedData(p, codeSize, CopySectionFlags::kPadSectionBuffer);
|
691
|
+
//!
|
692
|
+
//! // Execute the generated function.
|
693
|
+
//! int inA[4] = { 4, 3, 2, 1 };
|
694
|
+
//! int inB[4] = { 1, 5, 2, 8 };
|
695
|
+
//! int out[4];
|
696
|
+
//!
|
697
|
+
//! // This code uses AsmJit's ptr_as_func<> to cast between void* and SumIntsFunc.
|
698
|
+
//! ptr_as_func<SumIntsFunc>(p)(out, inA, inB);
|
699
|
+
//!
|
700
|
+
//! // Prints {5 8 4 9}
|
701
|
+
//! printf("{%d %d %d %d}\n", out[0], out[1], out[2], out[3]);
|
702
|
+
//!
|
703
|
+
//! // Release 'p' is it's no longer needed. It will be destroyed with 'vm'
|
704
|
+
//! // instance anyway, but it's a good practice to release it explicitly
|
705
|
+
//! // when you know that the function will not be needed anymore.
|
706
|
+
//! allocator.release(p);
|
707
|
+
//!
|
708
|
+
//! return 0;
|
709
|
+
//! }
|
710
|
+
//! ```
|
711
|
+
//!
|
712
|
+
//! If you know the base-address in advance (before the code generation) it can be passed as a second argument to
|
713
|
+
//! \ref CodeHolder::init(). In that case the Assembler will know the absolute position of each instruction and
|
714
|
+
//! would be able to use it during instruction encoding to prevent relocations where possible. The following example
|
715
|
+
//! shows how to configure the base address:
|
716
|
+
//!
|
717
|
+
//! ```
|
718
|
+
//! #include <asmjit/x86.h>
|
719
|
+
//! #include <stdio.h>
|
720
|
+
//!
|
721
|
+
//! using namespace asmjit;
|
722
|
+
//!
|
723
|
+
//! void initializeCodeHolder(CodeHolder& code) {
|
724
|
+
//! Environment env = Environment::host();
|
725
|
+
//! uint64_t baseAddress = uint64_t(0x1234);
|
726
|
+
//!
|
727
|
+
//! // initialize CodeHolder with environment and custom base address.
|
728
|
+
//! code.init(env, baseAddress);
|
729
|
+
//! }
|
730
|
+
//! ```
|
731
|
+
//!
|
732
|
+
//! ### Label Offsets and Links
|
733
|
+
//!
|
734
|
+
//! When a label that is not yet bound is used by the Assembler, it creates a \ref LabelLink, which is then added to
|
735
|
+
//! a \ref LabelEntry. These links are also created if a label is used in a different section than in which it was
|
736
|
+
//! bound. Let's examine some functions that can be used to check whether there are any unresolved links.
|
737
|
+
//!
|
738
|
+
//! ```
|
739
|
+
//! #include <asmjit/core.h>
|
740
|
+
//! #include <stdio.h>
|
741
|
+
//!
|
742
|
+
//! using namespace asmjit;
|
743
|
+
//!
|
744
|
+
//! void labelLinksExample(CodeHolder& code, const Label& label) {
|
745
|
+
//! // Tests whether the `label` is bound.
|
746
|
+
//! bool isBound = code.isLabelBound(label);
|
747
|
+
//! printf("Label %u is %s\n", label.id(), isBound ? "bound" : "not bound");
|
748
|
+
//!
|
749
|
+
//! // Returns true if the code contains either referenced, but unbound
|
750
|
+
//! // labels, or cross-section label links that are not resolved yet.
|
751
|
+
//! bool hasUnresolved = code.hasUnresolvedLinks(); // Boolean answer.
|
752
|
+
//! size_t nUnresolved = code.unresolvedLinkCount(); // Count of unresolved links.
|
753
|
+
//!
|
754
|
+
//! printf("Number of unresolved links: %zu\n", nUnresolved);
|
755
|
+
//! }
|
756
|
+
//! ```
|
757
|
+
//!
|
758
|
+
//! There is no function that would return the number of unbound labels as this is completely unimportant from
|
759
|
+
//! CodeHolder's perspective. If a label is not used then it doesn't matter whether it's bound or not, only actually
|
760
|
+
//! used labels matter. After a Label is bound it's possible to query its offset offset relative to the start of the
|
761
|
+
//! section where it was bound:
|
762
|
+
//!
|
763
|
+
//! ```
|
764
|
+
//! #include <asmjit/core.h>
|
765
|
+
//! #include <stdio.h>
|
766
|
+
//!
|
767
|
+
//! using namespace asmjit;
|
768
|
+
//!
|
769
|
+
//! void labelOffsetExample(CodeHolder& code, const Label& label) {
|
770
|
+
//! // Label offset is known after it's bound. The offset provided is relative
|
771
|
+
//! // to the start of the section, see below for alternative. If the given
|
772
|
+
//! // label is not bound the offset returned will be zero. It's recommended
|
773
|
+
//! // to always check whether the label is bound before using its offset.
|
774
|
+
//! uint64_t sectionOffset = code.labelOffset(label);
|
775
|
+
//! printf("Label offset relative to section: %llu\n", (unsigned long long)sectionOffset);
|
776
|
+
//!
|
777
|
+
//! // If you use multiple sections and want the offset relative to the base.
|
778
|
+
//! // NOTE: This function expects that the section has already an offset and
|
779
|
+
//! // the label-link was resolved (if this is not true you will still get an
|
780
|
+
//! // offset relative to the start of the section).
|
781
|
+
//! uint64_t baseOffset = code.labelOffsetFromBase(label);
|
782
|
+
//! printf("Label offset relative to base: %llu\n", (unsigned long long)baseOffset);
|
783
|
+
//! }
|
784
|
+
//! ```
|
785
|
+
//!
|
786
|
+
//! ### Sections
|
787
|
+
//!
|
788
|
+
//! AsmJit allows to create multiple sections within the same \ref CodeHolder. A test-case
|
789
|
+
//! [asmjit_test_x86_sections.cpp](https://github.com/asmjit/asmjit/blob/master/test/asmjit_test_x86_sections.cpp)
|
790
|
+
//! can be used as a reference point although the following example should also provide a useful insight:
|
791
|
+
//!
|
792
|
+
//! ```
|
793
|
+
//! #include <asmjit/x86.h>
|
794
|
+
//! #include <stdio.h>
|
795
|
+
//!
|
796
|
+
//! using namespace asmjit;
|
797
|
+
//!
|
798
|
+
//! void sectionsExample(CodeHolder& code) {
|
799
|
+
//! // Text section is always provided as the first section.
|
800
|
+
//! Section* text = code.textSection(); // or code.sectionById(0);
|
801
|
+
//!
|
802
|
+
//! // To create another section use CodeHolder::newSection().
|
803
|
+
//! Section* data;
|
804
|
+
//! Error err = code.newSection(&data,
|
805
|
+
//! ".data", // Section name
|
806
|
+
//! SIZE_MAX, // Name length if the name is not null terminated (or SIZE_MAX).
|
807
|
+
//! SectionFlags::kNone, // Section flags, see SectionFlags.
|
808
|
+
//! 8, // Section alignment, must be power of 2.
|
809
|
+
//! 0); // Section order value (optional, default 0).
|
810
|
+
//!
|
811
|
+
//! // When you switch sections in Assembler, Builder, or Compiler the cursor
|
812
|
+
//! // will always move to the end of that section. When you create an Assembler
|
813
|
+
//! // the cursor would be placed at the end of the first (.text) section, which
|
814
|
+
//! // is initially empty.
|
815
|
+
//! x86::Assembler a(&code);
|
816
|
+
//! Label L_Data = a.newLabel();
|
817
|
+
//!
|
818
|
+
//! a.mov(x86::eax, x86::ebx); // Emits in .text section.
|
819
|
+
//!
|
820
|
+
//! a.section(data); // Switches to the end of .data section.
|
821
|
+
//! a.bind(L_Data); // Binds label in this .data section
|
822
|
+
//! a.db(0x01); // Emits byte in .data section.
|
823
|
+
//!
|
824
|
+
//! a.section(text); // Switches to the end of .text section.
|
825
|
+
//! a.add(x86::ebx, x86::eax); // Emits in .text section.
|
826
|
+
//!
|
827
|
+
//! // References a label in .text section, which was bound in .data section.
|
828
|
+
//! // This would create a LabelLink even when the L_Data is already bound,
|
829
|
+
//! // because the reference crosses sections. See below...
|
830
|
+
//! a.lea(x86::rsi, x86::ptr(L_Data));
|
831
|
+
//! }
|
832
|
+
//! ```
|
833
|
+
//!
|
834
|
+
//! The last line in the example above shows that a LabelLink would be created even for bound labels that cross
|
835
|
+
//! sections. In this case a referenced label was bound in another section, which means that the link couldn't be
|
836
|
+
//! resolved at that moment. If your code uses sections, but you wish AsmJit to flatten these sections (you don't
|
837
|
+
//! plan to flatten them manually) then there is an API for that.
|
838
|
+
//!
|
839
|
+
//! ```
|
840
|
+
//! #include <asmjit/x86.h>
|
841
|
+
//! #include <stdio.h>
|
842
|
+
//!
|
843
|
+
//! using namespace asmjit;
|
844
|
+
//!
|
845
|
+
//! // ... (continuing the previous example) ...
|
846
|
+
//! void sectionsExampleContinued(CodeHolder& code) {
|
847
|
+
//! // Suppose we have some code that contains multiple sections and
|
848
|
+
//! // we would like to flatten it by using AsmJit's built-in API:
|
849
|
+
//! Error err = code.flatten();
|
850
|
+
//! if (err) {
|
851
|
+
//! // There are many reasons it can fail, so always handle a possible error.
|
852
|
+
//! printf("Failed to flatten the code: %s\n", DebugUtils::errorAsString(err));
|
853
|
+
//! exit(1);
|
854
|
+
//! }
|
855
|
+
//!
|
856
|
+
//! // After flattening all sections would contain assigned offsets
|
857
|
+
//! // relative to base. Offsets are 64-bit unsigned integers so we
|
858
|
+
//! // cast them to `size_t` for simplicity. On 32-bit targets it's
|
859
|
+
//! // guaranteed that the offset cannot be greater than `2^32 - 1`.
|
860
|
+
//! printf("Data section offset %zu", size_t(data->offset()));
|
861
|
+
//!
|
862
|
+
//! // The flattening doesn't resolve unresolved label links, this
|
863
|
+
//! // has to be done manually as flattening can be done separately.
|
864
|
+
//! err = code.resolveUnresolvedLinks();
|
865
|
+
//! if (err) {
|
866
|
+
//! // This is the kind of error that should always be handled...
|
867
|
+
//! printf("Failed to resolve label links: %s\n", DebugUtils::errorAsString(err));
|
868
|
+
//! exit(1);
|
869
|
+
//! }
|
870
|
+
//!
|
871
|
+
//! if (code.hasUnresolvedLinks()) {
|
872
|
+
//! // This would mean either unbound label or some other issue.
|
873
|
+
//! printf("The code has %zu unbound labels\n", code.unresovedLinkCount());
|
874
|
+
//! exit(1);
|
875
|
+
//! }
|
876
|
+
//! }
|
877
|
+
//! ```
|
878
|
+
|
879
|
+
|
880
|
+
//! \defgroup asmjit_assembler Assembler
|
881
|
+
//! \brief Assembler interface and operands.
|
882
|
+
//!
|
883
|
+
//! ### Overview
|
884
|
+
//!
|
885
|
+
//! AsmJit's Assembler is used to emit machine code directly into a \ref CodeBuffer. In general, code generation
|
886
|
+
//! with assembler requires the knowledge of the following:
|
887
|
+
//!
|
888
|
+
//! - \ref BaseAssembler and architecture-specific assemblers:
|
889
|
+
//! - \ref x86::Assembler - Assembler specific to X86 architecture
|
890
|
+
//! - \ref Operand and its variations:
|
891
|
+
//! - \ref BaseReg - Base class for a register operand, inherited by:
|
892
|
+
//! - \ref x86::Reg - Register operand specific to X86 architecture.
|
893
|
+
//! - \ref BaseMem - Base class for a memory operand, inherited by:
|
894
|
+
//! - \ref x86::Mem - Memory operand specific to X86 architecture.
|
895
|
+
//! - \ref Imm - Immediate (value) operand.
|
896
|
+
//! - \ref Label - Label operand.
|
897
|
+
//!
|
898
|
+
//! \note Assembler examples use \ref x86::Assembler as abstract interfaces cannot be used to generate code.
|
899
|
+
//!
|
900
|
+
//! ### Operand Basics
|
901
|
+
//!
|
902
|
+
//! Let's start with operands. \ref Operand is a data structure that defines a data layout of any operand. It can be
|
903
|
+
//! inherited, but any class inheriting it cannot add any members to it, only the existing layout can be reused.
|
904
|
+
//! AsmJit allows to construct operands dynamically, to store them, and to query a complete information about them
|
905
|
+
//! at run-time. Operands are small (always 16 bytes per \ref Operand) and can be copied and passed by value. Please
|
906
|
+
//! never allocate individual operands dynamically by using a `new` keyword - it would work, but then you would have
|
907
|
+
//! to be responsible for deleting such operands. In AsmJit operands are always part of some other data structures
|
908
|
+
//! like \ref InstNode, which is part of \ref asmjit_builder tool.
|
909
|
+
//!
|
910
|
+
//! Operands contain only identifiers, but not pointers to any code-generation data. For example \ref Label operand
|
911
|
+
//! only provides label identifier, but not a pointer to \ref LabelEntry structure. In AsmJit such IDs are used to
|
912
|
+
//! link stuff together without having to deal with pointers.
|
913
|
+
//!
|
914
|
+
//! AsmJit's operands all inherit from a base class called \ref Operand. Operands have the following properties that
|
915
|
+
//! are commonly accessible by getters and setters:
|
916
|
+
//!
|
917
|
+
//! - \ref Operand - Base operand, which only provides accessors that are common to all operand types.
|
918
|
+
//! - \ref BaseReg - Describes either physical or virtual register. Physical registers have id that matches the
|
919
|
+
//! target's machine id directly whereas virtual registers must be allocated into physical registers by a register
|
920
|
+
//! allocator pass. Register operand provides:
|
921
|
+
//! - Register Type (\ref RegType) - Unique id that describes each possible register provided by the target
|
922
|
+
//! architecture - for example X86 backend provides general purpose registers (GPB-LO, GPB-HI, GPW, GPD, and GPQ)
|
923
|
+
//! and all types of other registers like K, MM, BND, XMM, YMM, ZMM, and TMM.
|
924
|
+
//! - Register Group (\ref RegGroup) - Groups multiple register types under a single group - for example all
|
925
|
+
//! general-purpose registers (of all sizes) on X86 are part of \ref RegGroup::kGp and all SIMD registers
|
926
|
+
//! (XMM, YMM, ZMM) are part of \ref RegGroup::kVec.
|
927
|
+
//! - Register Size - Contains the size of the register in bytes. If the size depends on the mode (32-bit vs
|
928
|
+
//! 64-bit) then generally the higher size is used (for example RIP register has size 8 by default).
|
929
|
+
//! - Register Id - Contains physical or virtual id of the register.
|
930
|
+
//! - \ref BaseMem - Used to reference a memory location. Memory operand provides:
|
931
|
+
//! - Base Register - A base register type and id (physical or virtual).
|
932
|
+
//! - Index Register - An index register type and id (physical or virtual).
|
933
|
+
//! - Offset - Displacement or absolute address to be referenced (32-bit if base register is used and 64-bit if
|
934
|
+
//! base register is not used).
|
935
|
+
//! - Flags that can describe various architecture dependent information (like scale and segment-override on X86).
|
936
|
+
//! - \ref Imm - Immediate values are usually part of instructions (encoded within the instruction itself) or data.
|
937
|
+
//! - \ref Label - used to reference a location in code or data. Labels must be created by the \ref BaseEmitter or
|
938
|
+
//! by \ref CodeHolder. Each label has its unique id per \ref CodeHolder instance.
|
939
|
+
//!
|
940
|
+
//! ### Operand Manipulation
|
941
|
+
//!
|
942
|
+
//! AsmJit allows to construct operands dynamically, to store them, and to query a complete information about them at
|
943
|
+
//! run-time. Operands are small (always 16 bytes per `Operand`) and should be always copied (by value) if you intend
|
944
|
+
//! to store them (don't create operands by using `new` keyword, it's not recommended). Operands are safe to be passed
|
945
|
+
//! to `memcpy()` and `memset()`, which becomes handy when working with arrays of operands. If you set all members of
|
946
|
+
//! an \ref Operand to zero the operand would become NONE operand, which is the same as a default constructed Operand.
|
947
|
+
//!
|
948
|
+
//! The example below illustrates how operands can be used and modified even without using any other code generation
|
949
|
+
//! classes. The example uses X86 architecture-specific operands.
|
950
|
+
//!
|
951
|
+
//! ```
|
952
|
+
//! #include <asmjit/x86.h>
|
953
|
+
//!
|
954
|
+
//! using namespace asmjit;
|
955
|
+
//!
|
956
|
+
//! // Registers can be copied, it's a common practice.
|
957
|
+
//! x86::Gp dstRegByValue() { return x86::ecx; }
|
958
|
+
//!
|
959
|
+
//! void usingOperandsExample(x86::Assembler& a) {
|
960
|
+
//! // Gets `ecx` register returned by a function.
|
961
|
+
//! x86::Gp dst = dstRegByValue();
|
962
|
+
//! // Gets `rax` register directly from the provided `x86` namespace.
|
963
|
+
//! x86::Gp src = x86::rax;
|
964
|
+
//! // Constructs `r10` dynamically.
|
965
|
+
//! x86::Gp idx = x86::gpq(10);
|
966
|
+
//! // Constructs [src + idx] memory address - referencing [rax + r10].
|
967
|
+
//! x86::Mem m = x86::ptr(src, idx);
|
968
|
+
//!
|
969
|
+
//! // Examine `m`: Returns `RegType::kX86_Gpq`.
|
970
|
+
//! m.indexType();
|
971
|
+
//! // Examine `m`: Returns 10 (`r10`).
|
972
|
+
//! m.indexId();
|
973
|
+
//!
|
974
|
+
//! // Reconstruct `idx` stored in mem:
|
975
|
+
//! x86::Gp idx_2 = x86::Gp::fromTypeAndId(m.indexType(), m.indexId());
|
976
|
+
//!
|
977
|
+
//! // True, `idx` and idx_2` are identical.
|
978
|
+
//! idx == idx_2;
|
979
|
+
//!
|
980
|
+
//! // Possible - op will still be the same as `m`.
|
981
|
+
//! Operand op = m;
|
982
|
+
//! // True (can be casted to BaseMem or architecture-specific Mem).
|
983
|
+
//! op.isMem();
|
984
|
+
//!
|
985
|
+
//! // True, `op` is just a copy of `m`.
|
986
|
+
//! m == op;
|
987
|
+
//!
|
988
|
+
//! // Static cast is fine and valid here.
|
989
|
+
//! static_cast<BaseMem&>(op).addOffset(1);
|
990
|
+
//! // However, using `as<T>()` to cast to a derived type is preferred.
|
991
|
+
//! op.as<BaseMem>().addOffset(1);
|
992
|
+
//! // False, `op` now points to [rax + r10 + 2], which is not [rax + r10].
|
993
|
+
//! m == op;
|
994
|
+
//!
|
995
|
+
//! // Emitting 'mov' - type safe way.
|
996
|
+
//! a.mov(dst, m);
|
997
|
+
//! // Not possible, `mov` doesn't provide mov(x86::Gp, Operand) overload.
|
998
|
+
//! a.mov(dst, op);
|
999
|
+
//!
|
1000
|
+
//! // Type-unsafe, but possible.
|
1001
|
+
//! a.emit(x86::Inst::kIdMov, dst, m);
|
1002
|
+
//! // Also possible, `emit()` is typeless and can be used with raw Operand.
|
1003
|
+
//! a.emit(x86::Inst::kIdMov, dst, op);
|
1004
|
+
//! }
|
1005
|
+
//! ```
|
1006
|
+
//!
|
1007
|
+
//! Some operands have to be created explicitly by emitters. For example labels must be created by \ref
|
1008
|
+
//! BaseEmitter::newLabel(), which creates a label entry and returns a \ref Label operand with the id that refers
|
1009
|
+
//! to it. Such label then can be used by emitters.
|
1010
|
+
//!
|
1011
|
+
//! ### Memory Operands
|
1012
|
+
//!
|
1013
|
+
//! Some architectures like X86 provide a complex memory addressing model that allows to encode addresses having a
|
1014
|
+
//! BASE register, INDEX register with a possible scale (left shift), and displacement (called offset in AsmJit).
|
1015
|
+
//! Memory address on X86 can also specify memory segment (segment-override in X86 terminology) and some instructions
|
1016
|
+
//! (gather / scatter) require INDEX to be a \ref x86::Vec register instead of a general-purpose register.
|
1017
|
+
//!
|
1018
|
+
//! AsmJit allows to encode and work with all forms of addresses mentioned and implemented by X86. In addition, it
|
1019
|
+
//! also allows to construct absolute 64-bit memory address operands, which is only allowed in one form of 'mov'
|
1020
|
+
//! instruction.
|
1021
|
+
//!
|
1022
|
+
//! ```
|
1023
|
+
//! #include <asmjit/x86.h>
|
1024
|
+
//!
|
1025
|
+
//! using namespace asmjit;
|
1026
|
+
//!
|
1027
|
+
//! void testX86Mem() {
|
1028
|
+
//! // Makes it easier to access x86 stuff...
|
1029
|
+
//! using namespace asmjit::x86;
|
1030
|
+
//!
|
1031
|
+
//! // BASE + OFFSET.
|
1032
|
+
//! Mem a = ptr(rax); // a = [rax]
|
1033
|
+
//! Mem b = ptr(rax, 15); // b = [rax + 15]
|
1034
|
+
//!
|
1035
|
+
//! // BASE + INDEX << SHIFT - Shift is in BITS as used by X86!
|
1036
|
+
//! Mem c = ptr(rax, rbx); // c = [rax + rbx]
|
1037
|
+
//! Mem d = ptr(rax, rbx, 2); // d = [rax + rbx << 2]
|
1038
|
+
//! Mem e = ptr(rax, rbx, 2, 15); // e = [rax + rbx << 2 + 15]
|
1039
|
+
//!
|
1040
|
+
//! // BASE + VM (Vector Index) (encoded as MOD+VSIB).
|
1041
|
+
//! Mem f = ptr(rax, xmm1); // f = [rax + xmm1]
|
1042
|
+
//! Mem g = ptr(rax, xmm1, 2); // g = [rax + xmm1 << 2]
|
1043
|
+
//! Mem h = ptr(rax, xmm1, 2, 15); // h = [rax + xmm1 << 2 + 15]
|
1044
|
+
//!
|
1045
|
+
//! // Absolute address:
|
1046
|
+
//! uint64_t addr = (uint64_t)0x1234;
|
1047
|
+
//! Mem i = ptr(addr); // i = [0x1234]
|
1048
|
+
//! Mem j = ptr(addr, rbx); // j = [0x1234 + rbx]
|
1049
|
+
//! Mem k = ptr(addr, rbx, 2); // k = [0x1234 + rbx << 2]
|
1050
|
+
//!
|
1051
|
+
//! // LABEL - Will be encoded as RIP (64-bit) or absolute address (32-bit).
|
1052
|
+
//! Label L = ...;
|
1053
|
+
//! Mem m = ptr(L); // m = [L]
|
1054
|
+
//! Mem n = ptr(L, rbx); // n = [L + rbx]
|
1055
|
+
//! Mem o = ptr(L, rbx, 2); // o = [L + rbx << 2]
|
1056
|
+
//! Mem p = ptr(L, rbx, 2, 15); // p = [L + rbx << 2 + 15]
|
1057
|
+
//!
|
1058
|
+
//! // RIP - 64-bit only (RIP can't use INDEX).
|
1059
|
+
//! Mem q = ptr(rip, 24); // q = [rip + 24]
|
1060
|
+
//! }
|
1061
|
+
//! ```
|
1062
|
+
//!
|
1063
|
+
//! Memory operands can optionally contain memory size. This is required by instructions where the memory size cannot
|
1064
|
+
//! be deduced from other operands, like `inc` and `dec` on X86:
|
1065
|
+
//!
|
1066
|
+
//! ```
|
1067
|
+
//! #include <asmjit/x86.h>
|
1068
|
+
//!
|
1069
|
+
//! using namespace asmjit;
|
1070
|
+
//!
|
1071
|
+
//! void testX86Mem() {
|
1072
|
+
//! // The same as: dword ptr [rax + rbx].
|
1073
|
+
//! x86::Mem a = x86::dword_ptr(rax, rbx);
|
1074
|
+
//!
|
1075
|
+
//! // The same as: qword ptr [rdx + rsi << 0 + 1].
|
1076
|
+
//! x86::Mem b = x86::qword_ptr(rdx, rsi, 0, 1);
|
1077
|
+
//! }
|
1078
|
+
//! ```
|
1079
|
+
//!
|
1080
|
+
//! Memory operands provide API that can be used to access its properties:
|
1081
|
+
//!
|
1082
|
+
//! ```
|
1083
|
+
//! #include <asmjit/x86.h>
|
1084
|
+
//!
|
1085
|
+
//! using namespace asmjit;
|
1086
|
+
//!
|
1087
|
+
//! void testX86Mem() {
|
1088
|
+
//! // The same as: dword ptr [rax + 12].
|
1089
|
+
//! x86::Mem mem = x86::dword_ptr(rax, 12);
|
1090
|
+
//!
|
1091
|
+
//! mem.hasBase(); // true.
|
1092
|
+
//! mem.hasIndex(); // false.
|
1093
|
+
//! mem.size(); // 4.
|
1094
|
+
//! mem.offset(); // 12.
|
1095
|
+
//!
|
1096
|
+
//! mem.setSize(0); // Sets the size to 0 (makes it sizeless).
|
1097
|
+
//! mem.addOffset(-1); // Adds -1 to the offset and makes it 11.
|
1098
|
+
//! mem.setOffset(0); // Sets the offset to 0.
|
1099
|
+
//! mem.setBase(rcx); // Changes BASE to RCX.
|
1100
|
+
//! mem.setIndex(rax); // Changes INDEX to RAX.
|
1101
|
+
//! mem.hasIndex(); // true.
|
1102
|
+
//! }
|
1103
|
+
//! // ...
|
1104
|
+
//! ```
|
1105
|
+
//!
|
1106
|
+
//! Making changes to memory operand is very comfortable when emitting loads
|
1107
|
+
//! and stores:
|
1108
|
+
//!
|
1109
|
+
//! ```
|
1110
|
+
//! #include <asmjit/x86.h>
|
1111
|
+
//!
|
1112
|
+
//! using namespace asmjit;
|
1113
|
+
//!
|
1114
|
+
//! void testX86Mem(CodeHolder& code) {
|
1115
|
+
//! x86::Assembler a(code); // Your initialized x86::Assembler.
|
1116
|
+
//! x86::Mem mSrc = x86::ptr(eax); // Construct [eax] memory operand.
|
1117
|
+
//!
|
1118
|
+
//! // One way of emitting bunch of loads is to use `mem.adjusted()`, which
|
1119
|
+
//! // returns a new memory operand and keeps the source operand unchanged.
|
1120
|
+
//! a.movaps(x86::xmm0, mSrc); // No adjustment needed to load [eax].
|
1121
|
+
//! a.movaps(x86::xmm1, mSrc.adjusted(16)); // Loads from [eax + 16].
|
1122
|
+
//! a.movaps(x86::xmm2, mSrc.adjusted(32)); // Loads from [eax + 32].
|
1123
|
+
//! a.movaps(x86::xmm3, mSrc.adjusted(48)); // Loads from [eax + 48].
|
1124
|
+
//!
|
1125
|
+
//! // ... do something with xmm0-3 ...
|
1126
|
+
//!
|
1127
|
+
//! // Another way of adjusting memory is to change the operand in-place.
|
1128
|
+
//! // If you want to keep the original operand you can simply clone it.
|
1129
|
+
//! x86::Mem mDst = mSrc.clone(); // Clone mSrc.
|
1130
|
+
//!
|
1131
|
+
//! a.movaps(mDst, x86::xmm0); // Stores xmm0 to [eax].
|
1132
|
+
//! mDst.addOffset(16); // Adds 16 to `mDst`.
|
1133
|
+
//!
|
1134
|
+
//! a.movaps(mDst, x86::xmm1); // Stores to [eax + 16] .
|
1135
|
+
//! mDst.addOffset(16); // Adds 16 to `mDst`.
|
1136
|
+
//!
|
1137
|
+
//! a.movaps(mDst, x86::xmm2); // Stores to [eax + 32].
|
1138
|
+
//! mDst.addOffset(16); // Adds 16 to `mDst`.
|
1139
|
+
//!
|
1140
|
+
//! a.movaps(mDst, x86::xmm3); // Stores to [eax + 48].
|
1141
|
+
//! }
|
1142
|
+
//! ```
|
1143
|
+
//!
|
1144
|
+
//! ### Assembler Examples
|
1145
|
+
//!
|
1146
|
+
//! - \ref x86::Assembler provides many X86/X64 examples.
|
1147
|
+
|
1148
|
+
|
1149
|
+
//! \defgroup asmjit_builder Builder
|
1150
|
+
//! \brief Builder interface, nodes, and passes.
|
1151
|
+
//!
|
1152
|
+
//! ### Overview
|
1153
|
+
//!
|
1154
|
+
//! Both \ref BaseBuilder and \ref BaseCompiler interfaces describe emitters that emit into a representation that
|
1155
|
+
//! allows further processing. The code stored in such representation is completely safe to be patched, simplified,
|
1156
|
+
//! reordered, obfuscated, removed, injected, analyzed, or processed some other way. Each instruction, label,
|
1157
|
+
//! directive, or other building block is stored as \ref BaseNode (or derived class like \ref InstNode or \ref
|
1158
|
+
//! LabelNode) and contains all the information necessary to pass that node later to the assembler.
|
1159
|
+
//!
|
1160
|
+
//! \ref BaseBuilder is an emitter that inherits from \ref BaseEmitter interface. It was designed to provide a maximum
|
1161
|
+
//! compatibility with the existing \ref BaseAssembler emitter so users can move from assembler to builder when needed,
|
1162
|
+
//! for example to implement post-processing, which is not possible with Assembler.
|
1163
|
+
//!
|
1164
|
+
//! ### Builder Nodes
|
1165
|
+
//!
|
1166
|
+
//! \ref BaseBuilder doesn't generate machine code directly, it uses an intermediate representation based on nodes,
|
1167
|
+
//! however, it allows to serialize to \ref BaseAssembler when the code is ready to be encoded.
|
1168
|
+
//!
|
1169
|
+
//! There are multiple node types used by both \ref BaseBuilder and \ref BaseCompiler :
|
1170
|
+
//!
|
1171
|
+
//! - Basic nodes:
|
1172
|
+
//! - \ref BaseNode - Base class for all nodes.
|
1173
|
+
//! - \ref InstNode - Represents an instruction node.
|
1174
|
+
//! - \ref AlignNode - Represents an alignment directive (.align).
|
1175
|
+
//! - \ref LabelNode - Represents a location where to bound a \ref Label.
|
1176
|
+
//!
|
1177
|
+
//! - Data nodes:
|
1178
|
+
//! - \ref EmbedDataNode - Represents data.
|
1179
|
+
//! - \ref EmbedLabelNode - Represents \ref Label address embedded as data.
|
1180
|
+
//! - \ref EmbedLabelDeltaNode - Represents a difference of two labels embedded in data.
|
1181
|
+
//! - \ref ConstPoolNode - Represents a constant pool data embedded as data.
|
1182
|
+
//!
|
1183
|
+
//! - Informative nodes:
|
1184
|
+
//! - \ref CommentNode - Represents a comment string, doesn't affect code generation.
|
1185
|
+
//! - \ref SentinelNode - A marker that can be used to remember certain position in code or data, doesn't affect
|
1186
|
+
//! code generation. Used by \ref FuncNode to mark the end of a function.
|
1187
|
+
//!
|
1188
|
+
//! - Other nodes are provided by \ref asmjit_compiler infrastructure.
|
1189
|
+
//!
|
1190
|
+
//! ### Builder Examples
|
1191
|
+
//!
|
1192
|
+
//! - \ref x86::Builder provides many X86/X64 examples.
|
1193
|
+
|
1194
|
+
|
1195
|
+
//! \defgroup asmjit_compiler Compiler
|
1196
|
+
//! \brief Compiler interface.
|
1197
|
+
//!
|
1198
|
+
//! ### Overview
|
1199
|
+
//!
|
1200
|
+
//! \ref BaseCompiler is a high-level interface, which provides register allocation and support for defining and
|
1201
|
+
//! invoking functions, built on top of \ref BaseBuilder interface At the moment it's the easiest way of generating
|
1202
|
+
//! code in AsmJit as most architecture and OS specifics is properly abstracted and handled by AsmJit automatically.
|
1203
|
+
//! However, abstractions also mean restrictions, which means that \ref BaseCompiler has more limitations than \ref
|
1204
|
+
//! BaseAssembler or \ref BaseBuilder.
|
1205
|
+
//!
|
1206
|
+
//! Since \ref BaseCompiler provides register allocation it also establishes the concept of functions - a function
|
1207
|
+
//! in Compiler sense is a unit in which virtual registers are allocated into physical registers by the register
|
1208
|
+
//! allocator. In addition, it enables to use such virtual registers in function invocations.
|
1209
|
+
//!
|
1210
|
+
//! \ref BaseCompiler automatically handles function calling conventions. It's still architecture dependent, but
|
1211
|
+
//! makes the code generation much easies. Functions are essential; the first-step to generate some code is to define
|
1212
|
+
//! a signature of the function to be generated (before generating the function body itself). Function arguments and
|
1213
|
+
//! return value(s) are handled by assigning virtual registers to them. Similarly, function calls are handled the same
|
1214
|
+
//! way.
|
1215
|
+
//!
|
1216
|
+
//! ### Compiler Nodes
|
1217
|
+
//!
|
1218
|
+
//! \ref BaseCompiler adds some nodes that are required for function generation and invocation:
|
1219
|
+
//!
|
1220
|
+
//! - \ref FuncNode - Represents a function definition.
|
1221
|
+
//! - \ref FuncRetNode - Represents a function return.
|
1222
|
+
//! - \ref InvokeNode - Represents a function invocation.
|
1223
|
+
//!
|
1224
|
+
//! \ref BaseCompiler also makes the use of passes (\ref Pass) and automatically adds an architecture-dependent
|
1225
|
+
//! register allocator pass to the list of passes when attached to \ref CodeHolder.
|
1226
|
+
//!
|
1227
|
+
//! ### Compiler Examples
|
1228
|
+
//!
|
1229
|
+
//! - \ref x86::Compiler provides many X86/X64 examples.
|
1230
|
+
//!
|
1231
|
+
//! ### Compiler Tips
|
1232
|
+
//!
|
1233
|
+
//! Users of AsmJit have done mistakes in the past, this section should provide some useful tips for beginners:
|
1234
|
+
//!
|
1235
|
+
//! - Virtual registers in compiler are bound to a single function. At the moment the implementation doesn't
|
1236
|
+
//! care whether a single virtual register is used in multiple functions, but it sees it as two independent
|
1237
|
+
//! virtual registers in that case. This means that virtual registers cannot be used to implement global
|
1238
|
+
//! variables. Global variables are basically memory addresses which functions can read from and write to,
|
1239
|
+
//! and they have to be implemented in the same way.
|
1240
|
+
//!
|
1241
|
+
//! - Compiler provides a useful debugging functionality, which can be turned on through \ref FormatFlags. Use
|
1242
|
+
//! \ref Logger::addFlags() to turn on additional logging features when using Compiler.
|
1243
|
+
|
1244
|
+
|
1245
|
+
//! \defgroup asmjit_function Function
|
1246
|
+
//! \brief Function definitions.
|
1247
|
+
//!
|
1248
|
+
//! ### Overview
|
1249
|
+
//!
|
1250
|
+
//! AsmJit provides functionality that can be used to define function signatures and to calculate automatically
|
1251
|
+
//! optimal function frame that can be used directly by a prolog and epilog insertion. This feature was exclusive
|
1252
|
+
//! to AsmJit's Compiler for a very long time, but was abstracted out and is now available for all users regardless
|
1253
|
+
//! of the emitter they use. The following use cases are possible:
|
1254
|
+
//!
|
1255
|
+
//! - Calculate function frame before the function is generated - this is the only way available to \ref
|
1256
|
+
//! BaseAssembler users and it will be described in this section.
|
1257
|
+
//!
|
1258
|
+
//! - Calculate function frame after the function is generated - this way is generally used by \ref BaseBuilder
|
1259
|
+
//! and \ref BaseCompiler emitters and this way is generally described in \ref asmjit_compiler section.
|
1260
|
+
//!
|
1261
|
+
//! The following concepts are used to describe and create functions in AsmJit:
|
1262
|
+
//!
|
1263
|
+
//! - \ref TypeId - Type-id is an 8-bit value that describes a platform independent type as we know from C/C++.
|
1264
|
+
//! It provides abstractions for most common types like `int8_t`, `uint32_t`, `uintptr_t`, `float`, `double`,
|
1265
|
+
//! and all possible vector types to match ISAs up to AVX512. \ref TypeId was introduced originally for \ref
|
1266
|
+
//! asmjit_compiler, but it's now used by \ref FuncSignature as well.
|
1267
|
+
//!
|
1268
|
+
//! - \ref CallConv - Describes a calling convention - this class contains instructions to assign registers and
|
1269
|
+
//! stack addresses to function arguments and return value(s), but doesn't specify any function signature itself.
|
1270
|
+
//! Calling conventions are architecture and OS dependent.
|
1271
|
+
//!
|
1272
|
+
//! - \ref FuncSignature - Describes a function signature, for example `int func(int, int)`. FuncSignature contains
|
1273
|
+
//! a function calling convention id, return value type, and function arguments. The signature itself is platform
|
1274
|
+
//! independent and uses \ref TypeId to describe types of function arguments and function return value(s).
|
1275
|
+
//!
|
1276
|
+
//! - \ref FuncDetail - Architecture and ABI dependent information that describes \ref CallConv and expanded \ref
|
1277
|
+
//! FuncSignature. Each function argument and return value is represented as \ref FuncValue that contains the
|
1278
|
+
//! original \ref TypeId enriched with additional information that specifies whether the value is passed or
|
1279
|
+
//! returned by register (and which register) or by stack. Each value also contains some other metadata that
|
1280
|
+
//! provide additional information required to handle it properly (for example whether a vector is passed
|
1281
|
+
//! indirectly by a pointer as required by WIN64 calling convention).
|
1282
|
+
//!
|
1283
|
+
//! - \ref FuncFrame - Contains information about the function frame that can be used by prolog/epilog inserter
|
1284
|
+
//! (PEI). Holds call stack size size and alignment, local stack size and alignment, and various attributes that
|
1285
|
+
//! describe how prolog and epilog should be constructed. `FuncFrame` doesn't know anything about function's
|
1286
|
+
//! arguments or return values, it hold only information necessary to create a valid and ABI conforming function
|
1287
|
+
//! prologs and epilogs.
|
1288
|
+
//!
|
1289
|
+
//! - \ref FuncArgsAssignment - A helper class that can be used to reassign function arguments into user specified
|
1290
|
+
//! registers. It's architecture and ABI dependent mapping from function arguments described by \ref CallConv
|
1291
|
+
//! and \ref FuncDetail into registers specified by the user.
|
1292
|
+
//!
|
1293
|
+
//! It's a lot of concepts where each represents one step in a function frame calculation. It can be used to create
|
1294
|
+
//! function prologs, epilogs, and also to calculate information necessary to perform function calls.
|
1295
|
+
|
1296
|
+
|
1297
|
+
//! \defgroup asmjit_logging Logging
|
1298
|
+
//! \brief Logging and formatting.
|
1299
|
+
//!
|
1300
|
+
//! ### Overview
|
1301
|
+
//!
|
1302
|
+
//! The initial phase of a project that generates machine code is not always smooth. Failure cases are common not just
|
1303
|
+
//! at the beginning phase, but also during the development or refactoring. AsmJit provides logging functionality to
|
1304
|
+
//! address this issue. AsmJit does already a good job with function overloading to prevent from emitting unencodable
|
1305
|
+
//! instructions, but it can't prevent from emitting machine code that is correct at instruction level, but doesn't
|
1306
|
+
//! work when it's executed asa whole. Logging has always been an important part of AsmJit's infrastructure and looking
|
1307
|
+
//! at logs can sometimes reveal code generation issues quickly.
|
1308
|
+
//!
|
1309
|
+
//! AsmJit provides API for logging and formatting:
|
1310
|
+
//!
|
1311
|
+
//! - \ref Logger - A logger that you can pass to \ref CodeHolder and all emitters that inherit from \ref BaseEmitter.
|
1312
|
+
//!
|
1313
|
+
//! - \ref FormatOptions - Formatting options that can change how instructions and operands are formatted.
|
1314
|
+
//!
|
1315
|
+
//! - \ref Formatter - A namespace that provides functions that can format input data like \ref Operand, \ref BaseReg,
|
1316
|
+
//! \ref Label, and \ref BaseNode into \ref String.
|
1317
|
+
//!
|
1318
|
+
//! AsmJit's \ref Logger serves the following purposes:
|
1319
|
+
//!
|
1320
|
+
//! - Provides a basic foundation for logging.
|
1321
|
+
//!
|
1322
|
+
//! - Abstract class leaving the implementation on users. The following built-in implementations are provided for
|
1323
|
+
//! simplicity:
|
1324
|
+
//!
|
1325
|
+
//! - \ref FileLogger implements logging into a standard `FILE` stream.
|
1326
|
+
//! - \ref StringLogger serializes all logs into a \ref String instance.
|
1327
|
+
//!
|
1328
|
+
//! AsmJit's \ref FormatOptions provides the following to customize the formatting of instructions and operands through:
|
1329
|
+
//!
|
1330
|
+
//! - \ref FormatFlags
|
1331
|
+
//! - \ref FormatIndentationGroup
|
1332
|
+
//!
|
1333
|
+
//! ### Logging
|
1334
|
+
//!
|
1335
|
+
//! A \ref Logger is typically attached to a \ref CodeHolder, which propagates it to all attached emitters
|
1336
|
+
//! automatically. The example below illustrates how to use \ref FileLogger that outputs to standard output:
|
1337
|
+
//!
|
1338
|
+
//! ```
|
1339
|
+
//! #include <asmjit/core.h>
|
1340
|
+
//! #include <stdio.h>
|
1341
|
+
//!
|
1342
|
+
//! using namespace asmjit;
|
1343
|
+
//!
|
1344
|
+
//! int main() {
|
1345
|
+
//! JitRuntime rt; // Runtime specialized for JIT code execution.
|
1346
|
+
//! FileLogger logger(stdout); // Logger should always survive CodeHolder.
|
1347
|
+
//!
|
1348
|
+
//! CodeHolder code; // Holds code and relocation information.
|
1349
|
+
//! code.init(rt.environment()); // Initialize to the same arch as JIT runtime.
|
1350
|
+
//! code.setLogger(&logger); // Attach the `logger` to `code` holder.
|
1351
|
+
//!
|
1352
|
+
//! // ... code as usual, everything emitted will be logged to `stdout` ...
|
1353
|
+
//! return 0;
|
1354
|
+
//! }
|
1355
|
+
//! ```
|
1356
|
+
//!
|
1357
|
+
//! If output to FILE stream is not desired it's possible to use \ref StringLogger, which concatenates everything
|
1358
|
+
//! into a multi-line string:
|
1359
|
+
//!
|
1360
|
+
//! ```
|
1361
|
+
//! #include <asmjit/core.h>
|
1362
|
+
//! #include <stdio.h>
|
1363
|
+
//! #include <utility>
|
1364
|
+
//!
|
1365
|
+
//! using namespace asmjit;
|
1366
|
+
//!
|
1367
|
+
//! int main() {
|
1368
|
+
//! JitRuntime rt; // Runtime specialized for JIT code execution.
|
1369
|
+
//! StringLogger logger; // Logger should always survive CodeHolder.
|
1370
|
+
//!
|
1371
|
+
//! CodeHolder code; // Holds code and relocation information.
|
1372
|
+
//! code.init(rt.environment()); // Initialize to the same arch as JIT runtime.
|
1373
|
+
//! code.setLogger(&logger); // Attach the `logger` to `code` holder.
|
1374
|
+
//!
|
1375
|
+
//! // ... code as usual, logging will be concatenated to logger string ...
|
1376
|
+
//!
|
1377
|
+
//! // You can either use the string from StringLogger directly or you can
|
1378
|
+
//! // move it. Logger::data() returns its content as null terminated char[].
|
1379
|
+
//! printf("Logger content: %s\n", logger.data());
|
1380
|
+
//!
|
1381
|
+
//! // It can be moved into your own string like this:
|
1382
|
+
//! String content = std::move(logger.content());
|
1383
|
+
//! printf("The same content: %s\n", content.data());
|
1384
|
+
//!
|
1385
|
+
//! return 0;
|
1386
|
+
//! }
|
1387
|
+
//! ```
|
1388
|
+
//!
|
1389
|
+
//! ### Formatting
|
1390
|
+
//!
|
1391
|
+
//! AsmJit uses \ref Formatter to format inputs that are then passed to \ref Logger. Formatting is public and can be
|
1392
|
+
//! used by AsmJit users as well. The most important thing to know regarding formatting is that \ref Formatter always
|
1393
|
+
//! appends to the output string, so it can be used to build complex strings without having to concatenate
|
1394
|
+
//! intermediate strings.
|
1395
|
+
//!
|
1396
|
+
//! The first example illustrates how to format operands:
|
1397
|
+
//!
|
1398
|
+
//! ```
|
1399
|
+
//! #include <asmjit/core.h>
|
1400
|
+
//! #include <stdio.h>
|
1401
|
+
//!
|
1402
|
+
//! using namespace asmjit;
|
1403
|
+
//!
|
1404
|
+
//! void logOperand(Arch arch, const Operand_& op) {
|
1405
|
+
//! // The emitter is optional (named labels and virtual registers need it).
|
1406
|
+
//! BaseEmitter* emitter = nullptr;
|
1407
|
+
//!
|
1408
|
+
//! // No flags by default.
|
1409
|
+
//! FormatFlags formatFlags = FormatFlags::kNone;
|
1410
|
+
//!
|
1411
|
+
//! StringTmp<128> sb;
|
1412
|
+
//! Formatter::formatOperand(sb, formatFlags, emitter, arch, op);
|
1413
|
+
//! printf("%s\n", sb.data());
|
1414
|
+
//! }
|
1415
|
+
//!
|
1416
|
+
//! void formattingExample() {
|
1417
|
+
//! using namespace x86;
|
1418
|
+
//!
|
1419
|
+
//! // Architecture is not part of operand, it must be passed explicitly.
|
1420
|
+
//! // Format flags. We pass it explicitly also to 'logOperand' to make
|
1421
|
+
//! // compatible with what AsmJit normally does.
|
1422
|
+
//! Arch arch = Arch::kX64;
|
1423
|
+
//!
|
1424
|
+
//! log(arch, rax); // Prints 'rax'.
|
1425
|
+
//! log(arch, ptr(rax, rbx, 2)); // Prints '[rax + rbx * 4]`.
|
1426
|
+
//! log(arch, dword_ptr(rax, rbx, 2)); // Prints 'dword [rax + rbx * 4]`.
|
1427
|
+
//! log(arch, imm(42)); // Prints '42'.
|
1428
|
+
//! }
|
1429
|
+
//! ```
|
1430
|
+
//!
|
1431
|
+
//! Next example illustrates how to format whole instructions:
|
1432
|
+
//!
|
1433
|
+
//! ```
|
1434
|
+
//! #include <asmjit/core.h>
|
1435
|
+
//! #include <stdio.h>
|
1436
|
+
//! #include <utility>
|
1437
|
+
//!
|
1438
|
+
//! using namespace asmjit;
|
1439
|
+
//!
|
1440
|
+
//! template<typename... Args>
|
1441
|
+
//! void logInstruction(Arch arch, const BaseInst& inst, Args&&... args) {
|
1442
|
+
//! // The emitter is optional (named labels and virtual registers need it).
|
1443
|
+
//! BaseEmitter* emitter = nullptr;
|
1444
|
+
//!
|
1445
|
+
//! // No flags by default.
|
1446
|
+
//! FormatFlags formatFlags = FormatFlags::kNone;
|
1447
|
+
//!
|
1448
|
+
//! // The formatter expects operands in an array.
|
1449
|
+
//! Operand_ operands { std::forward<Args>(args)... };
|
1450
|
+
//!
|
1451
|
+
//! StringTmp<128> sb;
|
1452
|
+
//! Formatter::formatInstruction(
|
1453
|
+
//! sb, formatFlags, emitter, arch, inst, operands, sizeof...(args));
|
1454
|
+
//! printf("%s\n", sb.data());
|
1455
|
+
//! }
|
1456
|
+
//!
|
1457
|
+
//! void formattingExample() {
|
1458
|
+
//! using namespace x86;
|
1459
|
+
//!
|
1460
|
+
//! // Architecture is not part of operand, it must be passed explicitly.
|
1461
|
+
//! // Format flags. We pass it explicitly also to 'logOperand' to make
|
1462
|
+
//! // compatible with what AsmJit normally does.
|
1463
|
+
//! Arch arch = Arch::kX64;
|
1464
|
+
//!
|
1465
|
+
//! // Prints 'mov rax, rcx'.
|
1466
|
+
//! logInstruction(arch, BaseInst(Inst::kIdMov), rax, rcx);
|
1467
|
+
//!
|
1468
|
+
//! // Prints 'vaddpd zmm0, zmm1, [rax] {1to8}'.
|
1469
|
+
//! logInstruction(arch,
|
1470
|
+
//! BaseInst(Inst::kIdVaddpd),
|
1471
|
+
//! zmm0, zmm1, ptr(rax)._1toN());
|
1472
|
+
//!
|
1473
|
+
//! // BaseInst abstracts instruction id, instruction options, and extraReg.
|
1474
|
+
//! // Prints 'lock add [rax], rcx'.
|
1475
|
+
//! logInstruction(arch,
|
1476
|
+
//! BaseInst(Inst::kIdAdd, InstOptions::kX86_Lock),
|
1477
|
+
//! x86::ptr(rax), rcx);
|
1478
|
+
//!
|
1479
|
+
//! // Similarly an extra register (like AVX-512 selector) can be used.
|
1480
|
+
//! // Prints 'vaddpd zmm0 {k2} {z}, zmm1, [rax]'.
|
1481
|
+
//! logInstruction(arch,
|
1482
|
+
//! BaseInst(Inst::kIdAdd, InstOptions::kX86_ZMask, k2),
|
1483
|
+
//! zmm0, zmm1, ptr(rax));
|
1484
|
+
//! }
|
1485
|
+
//! ```
|
1486
|
+
//!
|
1487
|
+
//! And finally, the example below illustrates how to use a built-in function to format the content of
|
1488
|
+
//! \ref BaseBuilder, which consists of nodes:
|
1489
|
+
//!
|
1490
|
+
//! ```
|
1491
|
+
//! #include <asmjit/core.h>
|
1492
|
+
//! #include <stdio.h>
|
1493
|
+
//!
|
1494
|
+
//! using namespace asmjit;
|
1495
|
+
//!
|
1496
|
+
//! void formattingExample(BaseBuilder* builder) {
|
1497
|
+
//! FormatFlags formatFlags = FormatFlags::kNone;
|
1498
|
+
//!
|
1499
|
+
//! // This also shows how temporary strings can be used.
|
1500
|
+
//! StringTmp<512> sb;
|
1501
|
+
//!
|
1502
|
+
//! // FormatNodeList requires the String for output, formatting flags, which
|
1503
|
+
//! // were zero (no extra flags), and the builder instance, which we have
|
1504
|
+
//! // provided. An overloaded version also exists, which accepts begin and
|
1505
|
+
//! // and end nodes, which can be used to only format a range of nodes.
|
1506
|
+
//! Formatter::formatNodeList(sb, formatFlags, builder);
|
1507
|
+
//!
|
1508
|
+
//! // You can do whatever else with the string, it's always null terminated,
|
1509
|
+
//! // so it can be passed to C functions like printf().
|
1510
|
+
//! printf("%s\n", sb.data());
|
1511
|
+
//! }
|
1512
|
+
//! ```
|
1513
|
+
|
1514
|
+
|
1515
|
+
//! \defgroup asmjit_error_handling Error Handling
|
1516
|
+
//! \brief Error handling.
|
1517
|
+
//!
|
1518
|
+
//! ### Overview
|
1519
|
+
//!
|
1520
|
+
//! AsmJit uses error codes to represent and return errors. Every function that can fail returns an \ref Error code.
|
1521
|
+
//! Exceptions are never thrown by AsmJit itself even in extreme conditions like out-of-memory, but it's possible to
|
1522
|
+
//! override \ref ErrorHandler::handleError() to throw, in that case no error will be returned and exception will be
|
1523
|
+
//! thrown instead. All functions where this can happen are not marked `noexcept`.
|
1524
|
+
//!
|
1525
|
+
//! Errors should never be ignored, however, checking errors after each AsmJit API call would simply overcomplicate
|
1526
|
+
//! the whole code generation experience. \ref ErrorHandler exists to make the use of AsmJit API simpler as it allows
|
1527
|
+
//! to customize how errors can be handled:
|
1528
|
+
//!
|
1529
|
+
//! - Record the error and continue (the way how the error is user-implemented).
|
1530
|
+
//! - Throw an exception. AsmJit doesn't use exceptions and is completely exception-safe, but it's perfectly legal
|
1531
|
+
//! to throw an exception from the error handler.
|
1532
|
+
//! - Use plain old C's `setjmp()` and `longjmp()`. Asmjit always puts Assembler, Builder and Compiler to a
|
1533
|
+
//! consistent state before calling \ref ErrorHandler::handleError(), so `longjmp()` can be used without issues
|
1534
|
+
//! to cancel the code-generation if an error occurred. This method can be used if exception handling in your
|
1535
|
+
//! project is turned off and you still want some comfort. In most cases it should be safe as AsmJit uses \ref
|
1536
|
+
//! Zone memory and the ownership of memory it allocates always ends with the instance that allocated it. If
|
1537
|
+
//! using this approach please never jump outside the life-time of \ref CodeHolder and \ref BaseEmitter.
|
1538
|
+
//!
|
1539
|
+
//! ### Using ErrorHandler
|
1540
|
+
//!
|
1541
|
+
//! An example of attaching \ref ErrorHandler to \ref CodeHolder.
|
1542
|
+
//!
|
1543
|
+
//! ```
|
1544
|
+
//! #include <asmjit/x86.h>
|
1545
|
+
//! #include <stdio.h>
|
1546
|
+
//!
|
1547
|
+
//! using namespace asmjit;
|
1548
|
+
//!
|
1549
|
+
//! // A simple error handler implementation, extend according to your needs.
|
1550
|
+
//! class MyErrorHandler : public ErrorHandler {
|
1551
|
+
//! public:
|
1552
|
+
//! void handleError(Error err, const char* message, BaseEmitter* origin) override {
|
1553
|
+
//! printf("AsmJit error: %s\n", message);
|
1554
|
+
//! }
|
1555
|
+
//! };
|
1556
|
+
//!
|
1557
|
+
//! int main() {
|
1558
|
+
//! JitRuntime rt;
|
1559
|
+
//!
|
1560
|
+
//! MyErrorHandler myErrorHandler;
|
1561
|
+
//! CodeHolder code;
|
1562
|
+
//!
|
1563
|
+
//! code.init(rt.environment());
|
1564
|
+
//! code.setErrorHandler(&myErrorHandler);
|
1565
|
+
//!
|
1566
|
+
//! x86::Assembler a(&code);
|
1567
|
+
//! // ... code generation ...
|
1568
|
+
//!
|
1569
|
+
//! return 0;
|
1570
|
+
//! }
|
1571
|
+
//! ```
|
1572
|
+
//!
|
1573
|
+
//! Useful classes in error handling group:
|
1574
|
+
//!
|
1575
|
+
//! - See \ref DebugUtils that provides utilities useful for debugging.
|
1576
|
+
//! - See \ref Error that lists error codes that AsmJit uses.
|
1577
|
+
//! - See \ref ErrorHandler for more details about error handling.
|
1578
|
+
|
1579
|
+
|
1580
|
+
//! \defgroup asmjit_instruction_db Instruction DB
|
1581
|
+
//! \brief Instruction database (introspection, read/write, validation, ...).
|
1582
|
+
//!
|
1583
|
+
//! ### Overview
|
1584
|
+
//!
|
1585
|
+
//! AsmJit provides a public instruction database that can be used to query information about a complete instruction.
|
1586
|
+
//! The instruction database requires the knowledge of the following:
|
1587
|
+
//!
|
1588
|
+
//! - \ref BaseInst - Base instruction that contains instruction id, options, and a possible extra-register that
|
1589
|
+
//! represents either REP prefix counter or AVX-512 selector (mask).
|
1590
|
+
//!
|
1591
|
+
//! - \ref Operand - Represents operands of an instruction.
|
1592
|
+
//!
|
1593
|
+
//! Each instruction can be then queried for the following information:
|
1594
|
+
//!
|
1595
|
+
//! - \ref InstRWInfo - Read/write information of instruction and its oprands (includes \ref OpRWInfo).
|
1596
|
+
//!
|
1597
|
+
//! - \ref CpuFeatures - CPU features required to execute the instruction.
|
1598
|
+
//!
|
1599
|
+
//! In addition to query functionality AsmJit is also able to validate whether an instruction and its operands are
|
1600
|
+
//! valid. This is useful for making sure that what user tries to emit is correct and it can be also used by other
|
1601
|
+
//! projects that parse user input, like AsmTK project.
|
1602
|
+
//!
|
1603
|
+
//! ### Query API
|
1604
|
+
//!
|
1605
|
+
//! The instruction query API is provided by \ref InstAPI namespace. The following queries are possible:
|
1606
|
+
//!
|
1607
|
+
//! - \ref InstAPI::queryRWInfo() - queries read/write information of the given instruction and its operands.
|
1608
|
+
//! Includes also CPU flags read/written.
|
1609
|
+
//!
|
1610
|
+
//! - \ref InstAPI::queryFeatures() - queries CPU features that are required to execute the given instruction. A full
|
1611
|
+
//! instruction with operands must be given as some architectures like X86 may require different features for the
|
1612
|
+
//! same instruction based on its operands.
|
1613
|
+
//!
|
1614
|
+
//! - <a href="https://github.com/asmjit/asmjit/blob/master/test/asmjit_test_instinfo.cpp">asmjit_test_instinfo.cpp</a>
|
1615
|
+
//! can be also used as a reference about accessing instruction information.
|
1616
|
+
//!
|
1617
|
+
//! ### Validation API
|
1618
|
+
//!
|
1619
|
+
//! The instruction validation API is provided by \ref InstAPI namespace in the similar fashion like the Query API,
|
1620
|
+
//! however, validation can also be turned on at \ref BaseEmitter level. The following is possible:
|
1621
|
+
//!
|
1622
|
+
//! - \ref InstAPI::validate() - low-level instruction validation function that is used internally by emitters
|
1623
|
+
//! if strict validation is enabled.
|
1624
|
+
//!
|
1625
|
+
//! - \ref BaseEmitter::addDiagnosticOptions() - can be used to enable validation at emitter level, see \ref
|
1626
|
+
//! DiagnosticOptions.
|
1627
|
+
|
1628
|
+
|
1629
|
+
//! \defgroup asmjit_virtual_memory Virtual Memory
|
1630
|
+
//! \brief Virtual memory management.
|
1631
|
+
//!
|
1632
|
+
//! ### Overview
|
1633
|
+
//!
|
1634
|
+
//! AsmJit's virtual memory management is divided into two main categories:
|
1635
|
+
//!
|
1636
|
+
//! - Low level API that provides cross-platform abstractions for virtual memory allocation. Implemented in
|
1637
|
+
//! \ref VirtMem namespace.
|
1638
|
+
//!
|
1639
|
+
//! - High level API that makes it very easy to store generated code for execution. See \ref JitRuntime, which is
|
1640
|
+
//! used by many examples for its simplicity and easy integration with \ref CodeHolder. There is also \ref
|
1641
|
+
//! JitAllocator, which lays somewhere between RAW memory allocation and \ref JitRuntime.
|
1642
|
+
|
1643
|
+
|
1644
|
+
//! \defgroup asmjit_zone Zone Memory
|
1645
|
+
//! \brief Zone memory allocator and containers.
|
1646
|
+
//!
|
1647
|
+
//! ### Overview
|
1648
|
+
//!
|
1649
|
+
//! AsmJit uses zone memory allocation (also known as Arena allocation) to allocate most of the data it uses. It's a
|
1650
|
+
//! fast allocator that allows AsmJit to allocate a lot of small data structures fast and without `malloc()` overhead.
|
1651
|
+
//! Since code generators and all related classes are usually short-lived this approach decreases memory usage and
|
1652
|
+
//! fragmentation as arena-based allocators always allocate larger blocks of memory, which are then split into smaller
|
1653
|
+
//! chunks.
|
1654
|
+
//!
|
1655
|
+
//! Another advantage of zone memory allocation is that since the whole library uses this strategy it's very easy to
|
1656
|
+
//! deallocate everything that a particular instance is holding by simply releasing the memory the allocator holds.
|
1657
|
+
//! This improves destruction time of such objects as there is no destruction at all. Long-lived objects just reset
|
1658
|
+
//! its data in destructor or in their reset() member function for a future reuse. For this purpose all containers in
|
1659
|
+
//! AsmJit are also zone allocated.
|
1660
|
+
//!
|
1661
|
+
//! ### Zone Allocation
|
1662
|
+
//!
|
1663
|
+
//! - \ref Zone - Incremental zone memory allocator with minimum features. It can only allocate memory without the
|
1664
|
+
//! possibility to return it back to the allocator.
|
1665
|
+
//!
|
1666
|
+
//! - \ref ZoneTmp - A temporary \ref Zone with some initial static storage. If the allocation requests fit the
|
1667
|
+
//! static storage allocated then there will be no dynamic memory allocation during the lifetime of \ref ZoneTmp,
|
1668
|
+
//! otherwise it would act as \ref Zone with one preallocated block on the stack.
|
1669
|
+
//!
|
1670
|
+
//! - \ref ZoneAllocator - A wrapper of \ref Zone that provides the capability of returning memory to the allocator.
|
1671
|
+
//! Such memory is stored in a pool for later reuse.
|
1672
|
+
//!
|
1673
|
+
//! ### Zone Allocated Containers
|
1674
|
+
//!
|
1675
|
+
//! - \ref ZoneString - Zone allocated string.
|
1676
|
+
//! - \ref ZoneHash - Zone allocated hash table.
|
1677
|
+
//! - \ref ZoneTree - Zone allocated red-black tree.
|
1678
|
+
//! - \ref ZoneList - Zone allocated double-linked list.
|
1679
|
+
//! - \ref ZoneStack - Zone allocated stack.
|
1680
|
+
//! - \ref ZoneVector - Zone allocated vector.
|
1681
|
+
//! - \ref ZoneBitVector - Zone allocated vector of bits.
|
1682
|
+
//!
|
1683
|
+
//! ### Using Zone Allocated Containers
|
1684
|
+
//!
|
1685
|
+
//! The most common data structure exposed by AsmJit is \ref ZoneVector. It's very similar to `std::vector`, but the
|
1686
|
+
//! implementation doesn't use exceptions and uses the mentioned \ref ZoneAllocator for performance reasons. You don't
|
1687
|
+
//! have to worry about allocations as you should not need to add items to AsmJit's data structures directly as there
|
1688
|
+
//! should be API for all required operations.
|
1689
|
+
//!
|
1690
|
+
//! The following APIs in \ref CodeHolder returns \ref ZoneVector reference:
|
1691
|
+
//!
|
1692
|
+
//! ```
|
1693
|
+
//! using namespace asmjit;
|
1694
|
+
//!
|
1695
|
+
//! void example(CodeHolder& code) {
|
1696
|
+
//! // Contains all emitters attached to CodeHolder.
|
1697
|
+
//! const ZoneVector<BaseEmitter*>& emitters = code.emitters();
|
1698
|
+
//!
|
1699
|
+
//! // Contains all section entries managed by CodeHolder.
|
1700
|
+
//! const ZoneVector<Section*>& sections = code.sections();
|
1701
|
+
//!
|
1702
|
+
//! // Contains all label entries managed by CodeHolder.
|
1703
|
+
//! const ZoneVector<LabelEntry*>& labelEntries = code.labelEntries();
|
1704
|
+
//!
|
1705
|
+
//! // Contains all relocation entries managed by CodeHolder.
|
1706
|
+
//! const ZoneVector<RelocEntry*>& relocEntries = code.relocEntries();
|
1707
|
+
//! }
|
1708
|
+
//! ```
|
1709
|
+
//!
|
1710
|
+
//! \ref ZoneVector has overloaded array access operator to make it possible to access its elements through operator[].
|
1711
|
+
//! Some standard functions like \ref ZoneVector::empty(), \ref ZoneVector::size(), and \ref ZoneVector::data() are
|
1712
|
+
//! provided as well. Vectors are also iterable through a range-based for loop:
|
1713
|
+
//!
|
1714
|
+
//! ```
|
1715
|
+
//! using namespace asmjit;
|
1716
|
+
//!
|
1717
|
+
//! void example(CodeHolder& code) {
|
1718
|
+
//! for (LabelEntry* le : code.labelEntries()) {
|
1719
|
+
//! printf("Label #%u {Bound=%s Offset=%llu}",
|
1720
|
+
//! le->id(),
|
1721
|
+
//! le->isBound() ? "true" : "false",
|
1722
|
+
//! (unsigned long long)le->offset());
|
1723
|
+
//! }
|
1724
|
+
//! }
|
1725
|
+
//! ```
|
1726
|
+
//!
|
1727
|
+
//! ### Design Considerations
|
1728
|
+
//!
|
1729
|
+
//! Zone-allocated containers do not store the allocator within the container. This decision was made to reduce the
|
1730
|
+
//! footprint of such containers as AsmJit tooling, especially Compiler's register allocation, may use many instances
|
1731
|
+
//! of such containers to perform code analysis and register allocation.
|
1732
|
+
//!
|
1733
|
+
//! For example to append an item into a \ref ZoneVector it's required to pass the allocator as the first argument,
|
1734
|
+
//! so it can be used in case that the vector needs a reallocation. Such function also returns an error, which must
|
1735
|
+
//! be propagated to the caller.
|
1736
|
+
//!
|
1737
|
+
//! ```
|
1738
|
+
//! using namespace asmjit
|
1739
|
+
//!
|
1740
|
+
//! Error example(ZoneAllocator* allocator) {
|
1741
|
+
//! ZoneVector<int> vector;
|
1742
|
+
//!
|
1743
|
+
//! // Unfortunately, allocator must be provided to all functions that mutate
|
1744
|
+
//! // the vector. However, AsmJit users should never need to do this as all
|
1745
|
+
//! // manipulation should be done through public API, which takes care of
|
1746
|
+
//! // that.
|
1747
|
+
//! for (int i = 0; i < 100; i++) {
|
1748
|
+
//! ASMJIT_PROPAGATE(vector.append(allocator, i));
|
1749
|
+
//! }
|
1750
|
+
//!
|
1751
|
+
//! // By default vector's destructor doesn't release anything as it knows
|
1752
|
+
//! // that its content is zone allocated. However, \ref ZoneVector::release
|
1753
|
+
//! // can be used to explicitly release the vector data to the allocator if
|
1754
|
+
//! // necessary
|
1755
|
+
//! vector.release(allocator);
|
1756
|
+
//! }
|
1757
|
+
//! ```
|
1758
|
+
//!
|
1759
|
+
//! Containers like \ref ZoneVector also provide a functionality to reserve a certain number of items before any items
|
1760
|
+
//! are added to it. This approach is used internally in most places as it allows to prepare space for data that will
|
1761
|
+
//! be added to some container before the data itself was created.
|
1762
|
+
//!
|
1763
|
+
//! ```
|
1764
|
+
//! using namespace asmjit
|
1765
|
+
//!
|
1766
|
+
//! Error example(ZoneAllocator* allocator) {
|
1767
|
+
//! ZoneVector<int> vector;
|
1768
|
+
//!
|
1769
|
+
//! ASMJIT_PROPAGATE(vector.willGrow(100));
|
1770
|
+
//! for (int i = 0; i < 100; i++) {
|
1771
|
+
//! // Cannot fail.
|
1772
|
+
//! vector.appendUnsafe(allocator, i);
|
1773
|
+
//! }
|
1774
|
+
//!
|
1775
|
+
//! vector.release(allocator);
|
1776
|
+
//! }
|
1777
|
+
//! ```
|
1778
|
+
|
1779
|
+
|
1780
|
+
//! \defgroup asmjit_utilities Utilities
|
1781
|
+
//! \brief Utility classes and functions.
|
1782
|
+
//!
|
1783
|
+
//! ### Overview
|
1784
|
+
//!
|
1785
|
+
//! AsmJit uses and provides utility classes and functions, that can be used with AsmJit. The functionality can be
|
1786
|
+
//! divided into the following topics:
|
1787
|
+
//!
|
1788
|
+
//! ### String Functionality
|
1789
|
+
//!
|
1790
|
+
//! - \ref String - AsmJit's string container, which is used internally and which doesn't use exceptions and has
|
1791
|
+
//! a stable layout, which is not dependent on C++ standard library.
|
1792
|
+
//!
|
1793
|
+
//! - \ref StringTmp - String that can have base storage allocated on stack. The amount of storage on stack can
|
1794
|
+
//! be specified as a template parameter.
|
1795
|
+
//!
|
1796
|
+
//! - \ref FixedString - Fixed string container limited up to N characters.
|
1797
|
+
//!
|
1798
|
+
//! ### Code Generation Utilities
|
1799
|
+
//!
|
1800
|
+
//! - \ref ConstPool - Constant pool used by \ref BaseCompiler, but also available to users that may find use of it.
|
1801
|
+
//!
|
1802
|
+
//! ### Support Functionality Used by AsmJit
|
1803
|
+
//!
|
1804
|
+
//! - \ref Support namespace provides many other utility functions and classes that are used by AsmJit, and made
|
1805
|
+
//! public.
|
1806
|
+
|
1807
|
+
|
1808
|
+
//! \defgroup asmjit_x86 X86 Backend
|
1809
|
+
//! \brief X86/X64 backend.
|
1810
|
+
|
1811
|
+
|
1812
|
+
//! \defgroup asmjit_arm ARM Commons
|
1813
|
+
//! \brief ARM commons shared between AArch32 and AArch64.
|
1814
|
+
|
1815
|
+
|
1816
|
+
//! \defgroup asmjit_a64 AArch64 Backend
|
1817
|
+
//! \brief AArch64 backend.
|
1818
|
+
|
1819
|
+
|
1820
|
+
//! \cond INTERNAL
|
1821
|
+
//! \defgroup asmjit_ra RA
|
1822
|
+
//! \brief Register allocator internals.
|
1823
|
+
//! \endcond
|
1824
|
+
|
1825
|
+
} // {asmjit}
|
1826
|
+
|
1827
|
+
#include "asmjit-scope-begin.h"
|
1828
|
+
#include "core/archtraits.h"
|
1829
|
+
#include "core/assembler.h"
|
1830
|
+
#include "core/builder.h"
|
1831
|
+
#include "core/codeholder.h"
|
1832
|
+
#include "core/compiler.h"
|
1833
|
+
#include "core/constpool.h"
|
1834
|
+
#include "core/cpuinfo.h"
|
1835
|
+
#include "core/emitter.h"
|
1836
|
+
#include "core/environment.h"
|
1837
|
+
#include "core/errorhandler.h"
|
1838
|
+
#include "core/formatter.h"
|
1839
|
+
#include "core/func.h"
|
1840
|
+
#include "core/globals.h"
|
1841
|
+
#include "core/inst.h"
|
1842
|
+
#include "core/jitallocator.h"
|
1843
|
+
#include "core/jitruntime.h"
|
1844
|
+
#include "core/logger.h"
|
1845
|
+
#include "core/operand.h"
|
1846
|
+
#include "core/osutils.h"
|
1847
|
+
#include "core/string.h"
|
1848
|
+
#include "core/support.h"
|
1849
|
+
#include "core/target.h"
|
1850
|
+
#include "core/type.h"
|
1851
|
+
#include "core/virtmem.h"
|
1852
|
+
#include "core/zone.h"
|
1853
|
+
#include "core/zonehash.h"
|
1854
|
+
#include "core/zonelist.h"
|
1855
|
+
#include "core/zonetree.h"
|
1856
|
+
#include "core/zonestack.h"
|
1857
|
+
#include "core/zonestring.h"
|
1858
|
+
#include "core/zonevector.h"
|
1859
|
+
#include "asmjit-scope-end.h"
|
1860
|
+
|
1861
|
+
#endif // ASMJIT_CORE_H_INCLUDED
|