AsmJit C++ API reference documentation generated by Doxygen.AsmJit library uses one global namespace called asmjit, which provides the whole functionality. Core functionality is within asmjit namespace and architecture specific functionality is always in its own namespace. For example asmjit::x86 provides both 32-bit and 64-bit X86 code generation.
AsmJit documentation is structured into groups. Groups can be followed in order to learn AsmJit, but knowledge from multiple groups is required to use AsmJit properly:
- It's important to understand that in order to learn AsmJit all groups are important. Some groups can be omitted if a particular tool is out of interest - for example Assembler users don't need to know about Builder, but it's not the opposite. Builder users should know about Assembler as it also uses operands, labels, and other concepts. Similarly Compiler users should know how both Assembler and Builder tools work.
Where To Start
AsmJit Core provides the following two classes that are essential from the code generation perspective:
- CodeHolder provides functionality to temporarily hold the generated code. It stores all the necessary information about the code - code buffers, sections, labels, symbols, and information about relocations.
- BaseEmitter provides interface used by emitter implementations. The interface provides basic building blocks that are then implemented by BaseAssembler, BaseBuilder, and BaseCompiler.
- Assembler - provides direct machine code generation.
- Builder - provides intermediate code generation that can be processed before it's serialized to BaseAssembler.
- Compiler - provides high-level code generation with built-in register allocation.
- FuncNode - provides insight into how function looks from the Compiler perspective and how it's stored in a node-list.
The following steps are recommended for all AsmJit users:
- Make sure that you use Logger, see Logging.
- Make sure that you use ErrorHandler, see Error Handling.
- Instruction validation in your debug builds can reveal problems too. AsmJit provides validation at instruction level that can be enabled via BaseEmitter::addDiagnosticOptions(). See DiagnosticOptions for more details.
- If you are a Compiler user, use diagnostic options and read carefully if anything suspicious pops out. Diagnostic options can be enabled via BaseEmitter::addDiagnosticOptions(). If unsure which ones to use, enable annotations and all debug options:
DiagnosticOptions::kRAAnnotate | DiagnosticOptions::kRADebugAll.
- Make sure you put a breakpoint into DebugUtils::errored() function if you have a problem with AsmJit returning errors during instruction encoding or register allocation. Having an active breakpoint there can help to reveal the origin of the error, to inspect variables and other conditions that caused it.
The reason for using Logger and ErrorHandler is that they provide a very useful information about what's happening inside emitters. In many cases the information provided by these two is crucial to quickly identify and fix issues that happen during development (for example wrong instruction, address, or register used). In addition, output from Logger is always necessary when filling bug reports. In other words, using logging and proper error handling can save a lot of time during the development and can also save users from submitting issues.