
AsmJit
Low-Latency Machine Code Generation
Holds assembled code and data (including sections, labels, and relocation information).
CodeHolder connects emitters with their targets. It provides them interface that can be used to query information about the target environment (architecture, etc...) and API to create labels, sections, relocations, and to write data to a CodeBuffer, which is always part of Section. More than one emitter can be attached to a single CodeHolder instance at a time, which is used in practice
CodeHolder provides interface for all emitter types. Assemblers use CodeHolder to write into CodeBuffer, and higher level emitters like Builder and Compiler use CodeHolder to manage labels and sections so higher level code can be serialized to Assembler by BaseEmitter::finalize() and BaseBuilder::serializeTo().
In order to use CodeHolder, it must be first initialized by init(). After the CodeHolder has been successfully initialized it can be used to hold assembled code, sections, labels, relocations, and to attach / detach code emitters. After the end of code generation it can be used to query physical locations of labels and to relocate the assembled code into the right address.
If you intend to generate a lot of code, or tiny code, it's advised to reuse CodeHolder and emitter instances. There are currently two ways of reusing CodeHolder and emitters - one is using CodeHolder::init() followed by CodeHolder::reset(), and another is initializing once by CodeHolder::init() and then reinitializing by CodeHolder::reinit(). The first strategy is shown below:
While this approach is good for many use-cases, there is even a faster strategy called reinitialization, which is provided by CodeHolder::reinit(). The idea of reinit is to reinitialize the CodeHolder into a state, which was achieved by initializing it by CodeHolder::init(), by optionally attaching Logger, ErrorHandler, and emitters of any kind. See an example below:
Creates an uninitialized CodeHolder (you must init() it before it can be used).
An optional temporary
argument can be used to initialize the first block of Zone that the CodeHolder uses into a temporary memory provided by the user.
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
Destroys the CodeHolder and frees all resources it has allocated.
Tests whether the CodeHolder
has been initialized.
Emitters can be only attached to initialized CodeHolder
instances.
Initializes CodeHolder to hold code described by the given environment
and baseAddress
.
Initializes CodeHolder to hold code described by the given environment
, cpuFeatures
, and baseAddress
.
Reinitializes CodeHolder with the same environment, cpu features, and base address as it had, and notifies all attached emitters of reinitialization.
If the CodeHolder was not initialized, kErrorNotInitialized is returned.
Reinitialization is designed to be a faster alternative compared to reset() followed by init() chain. The purpose of reinitialization is a very quick reuse of CodeHolder and all attached emitters (most likely Assembler or Compiler) without paying the cost of complete initialization and then assignment of all the loggers, error handlers, and emitters.
Detaches all code-generators attached and resets the CodeHolder
.
Attaches an emitter to this CodeHolder
.
Detaches an emitter from this CodeHolder
.
Returns the allocator that the CodeHolder
uses.
Returns the target environment information.
Returns the minimum CPU features of the target architecture.
Tests whether a static base-address is set.
Returns a static base-address or Globals::kNoBaseAddress, if not set.
Returns a vector of attached emitters.
Attaches a logger
to CodeHolder and propagates it to all attached emitters.
Resets the logger to none.
Tests whether the CodeHolder has an attached error handler, see ErrorHandler.
Returns the attached error handler.
Attach an error handler to this CodeHolder
.
Resets the error handler to none.
Makes sure that at least n
bytes can be added to CodeHolder's buffer cb
.
cb
must be managed by CodeHolder
- otherwise the behavior of the function is undefined. Reserves the size of cb
to at least n
bytes.
cb
must be managed by CodeHolder
- otherwise the behavior of the function is undefined. Returns an array of Section*
records.
Returns an array of Section*
records sorted according to section order first, then section id.
Returns the number of sections.
Tests whether the given sectionId
is valid.
Creates a new section and return its pointer in sectionOut
.
Returns Error
, does not report a possible error to ErrorHandler
.
Returns a section entry of the given index.
Returns section-id that matches the given name
.
If there is no such section Section::kInvalidId
is returned.
Returns '.text' section (section that commonly represents code).
Tests whether '.addrtab' section exists.
Returns '.addrtab' section.
This section is used exclusively by AsmJit to store absolute 64-bit addresses that cannot be encoded in instructions like 'jmp' or 'call'.
Ensures that '.addrtab' section exists (creates it if it doesn't) and returns it.
Can return nullptr
on out of memory condition.
Used to add an address to an address table.
This implicitly calls ensureAddressTableSection()
and then creates AddressTableEntry
that is inserted to _addressTableEntries
. If the address already exists this operation does nothing as the same addresses use the same slot.
This function should be considered internal as it's used by assemblers to insert an absolute address into the address table. Inserting address into address table without creating a particular relocation entry makes no sense.
Returns array of LabelEntry
records.
Returns number of labels created.
Tests whether the label having labelId
is valid (i.e. created by newLabelId()
).
Tests whether the label
is valid (i.e. created by newLabelId()
).
Tests whether a label having labelId
is already bound.
Returns false
if the labelId
is not valid.
Tests whether the label
is already bound.
Returns false
if the label
is not valid.
Returns LabelEntry of the given label identifier labelId
(or label
if you are using overloads).
labelId
must be valid as it's used as an index to _labelEntries[]
array. In debug builds the array access uses an assertion, but such assertion is not present in release builds. To get whether a label is valid, check out CodeHolder::isLabelValid() function. This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
Returns offset of a Label
by its labelId
.
The offset returned is relative to the start of the section where the label is bound. Zero offset is returned for unbound labels, which is their initial offset value.
labelId
must be valid as it's used as an index to _labelEntries[]
array. In debug builds the array access uses an assertion, but such assertion is not present in release builds. To get whether a label is valid, check out CodeHolder::isLabelValid() function. This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
Returns offset of a label by it's labelId
relative to the base offset.
labelId
must be valid as it's used as an index to _labelEntries[]
array. In debug builds the array access uses an assertion, but such assertion is not present in release builds. To get whether a label is valid, check out CodeHolder::isLabelValid() function.This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
Creates a new anonymous label and return its id in labelIdOut
.
Returns Error
, does not report error to ErrorHandler
.
Creates a new named LabelEntry of the given label type
.
labelIdOut | Where to store the created Label id. |
name | The name of the label. |
nameSize | The length of name argument, or SIZE_MAX if name is a null terminated string, which means that the CodeHolder will use strlen() to determine the length. |
type | The type of the label to create, see LabelType. |
parentId | Parent id of a local label, otherwise it must be Globals::kInvalidId. |
Always | returns Error, does not report a possible error to the attached ErrorHandler. |
AsmJit has a support for local labels (LabelType::kLocal) which require a parent label id (parentId). The names of local labels can conflict with names of other local labels that have a different parent. In addition, AsmJit supports named anonymous labels, which are useful only for debugging purposes as the anonymous name will have a name, which will be formatted, but the label itself cannot be queried by such name.
Returns a label by name.
If the named label doesn't a default constructed Label is returned, which has its id set to Globals::kInvalidId.
Returns a label id by name.
If the named label doesn't exist Globals::kInvalidId is returned.
Tests whether there are any unresolved fixups related to unbound labels.
Returns the number of unresolved fixups.
Creates a new label-link used to store information about yet unbound labels.
Returns null
if the allocation failed.
Resolves cross-section fixups associated with each label that was used as a destination in code of a different section.
It's only useful to people that use multiple sections as it will do nothing if the code only contains a single section in which cross-section fixups are not possible.
Binds a label to a given sectionId
and offset
(relative to start of the section).
This function is generally used by BaseAssembler::bind()
to do the heavy lifting.
Tests whether the code contains relocation entries.
Returns array of RelocEntry*
records.
Returns a RelocEntry of the given id
.
Creates a new relocation entry of type relocType
.
Additional fields can be set after the relocation entry was created.
Flattens all sections by recalculating their offsets, starting at 0.
Returns computed the size of code & data of all sections.
flatten()
and relocateToBase()
. Relocates the code to the given baseAddress
.
baseAddress | Absolute base address where the code will be relocated to. Please note that nothing is copied to such base address, it's just an absolute value used by the relocation code to resolve all stored relocations. |
summaryOut | Optional argument that can be used to get back information about the relocation. |
Copies a single section into dst
.
Copies all sections into dst
.
This should only be used if the data was flattened and there are no gaps between the sections. The dstSize
is always checked and the copy will never write anything outside the provided buffer.
Environment information.
CPU features of the target architecture.
Base address or Globals::kNoBaseAddress.
Attached ErrorHandler
.
Zone allocator, used to manage internal containers.
First emitter attached to this CodeHolder (double-linked list).
Last emitter attached to this CodeHolder (double-linked list).
Section entries.
Section entries sorted by section order and then section id.
Label entries.
Relocation entries.
Label name -> LabelEntry::ExtraData (only used by labels that have a name and are not anonymous).
Pool containing Fixup instances for quickly recycling them.
Count of unresolved fixups of unbound labels (at the end of assembling this should be zero).
Pointer to an address table section (or null if this section doesn't exist).
Address table entries.