// [AsmJit] // Complete x86/x64 JIT and Remote Assembler for C++. // // [License] // Zlib - See LICENSE.md file in the package. // [Guard] #ifndef _ASMJIT_BASE_CODEHOLDER_H #define _ASMJIT_BASE_CODEHOLDER_H // [Dependencies] #include "../base/arch.h" #include "../base/func.h" #include "../base/logging.h" #include "../base/operand.h" #include "../base/simdtypes.h" #include "../base/utils.h" #include "../base/zone.h" // [Api-Begin] #include "../asmjit_apibegin.h" namespace asmjit { //! \addtogroup asmjit_base //! \{ // ============================================================================ // [Forward Declarations] // ============================================================================ class Assembler; class CodeEmitter; class CodeHolder; // ============================================================================ // [asmjit::AlignMode] // ============================================================================ //! Align mode. ASMJIT_ENUM(AlignMode) { kAlignCode = 0, //!< Align executable code. kAlignData = 1, //!< Align non-executable code. kAlignZero = 2, //!< Align by a sequence of zeros. kAlignCount //!< Count of alignment modes. }; // ============================================================================ // [asmjit::ErrorHandler] // ============================================================================ //! Error handler can be used to override the default behavior of error handling //! available to all classes that inherit \ref CodeEmitter. See \ref handleError(). class ASMJIT_VIRTAPI ErrorHandler { public: // -------------------------------------------------------------------------- // [Construction / Destruction] // -------------------------------------------------------------------------- //! Create a new `ErrorHandler` instance. ASMJIT_API ErrorHandler() noexcept; //! Destroy the `ErrorHandler` instance. ASMJIT_API virtual ~ErrorHandler() noexcept; // -------------------------------------------------------------------------- // [Handle Error] // -------------------------------------------------------------------------- //! Error handler (abstract). //! //! Error handler is called after an error happened and before it's propagated //! to the caller. There are multiple ways how the error handler can be used: //! //! 1. Returning `true` or `false` from `handleError()`. If `true` is returned //! it means that the error was reported and AsmJit can continue execution. //! The reported error still be propagated to the caller, but won't put the //! CodeEmitter into an error state (it won't set last-error). However, //! returning `false` means that the error cannot be handled - in such case //! it stores the error, which can be then retrieved by using `getLastError()`. //! Returning `false` is the default behavior when no error handler is present. //! To put the assembler into a non-error state again a `resetLastError()` must //! be called. //! //! 2. Throwing an exception. AsmJit doesn't use exceptions and is completely //! exception-safe, but you can throw exception from your error handler if //! this way is the preferred way of handling errors in your project. Throwing //! an exception acts virtually as returning `true` as AsmJit won't be able //! to store the error because the exception changes execution path. //! //! 3. Using plain old C's `setjmp()` and `longjmp()`. Asmjit always puts //! `CodeEmitter` to a consistent state before calling the `handleError()` //! so `longjmp()` can be used without any issues to cancel the code //! generation if an error occurred. There is no difference between //! exceptions and longjmp() from AsmJit's perspective. virtual bool handleError(Error err, const char* message, CodeEmitter* origin) = 0; }; // ============================================================================ // [asmjit::CodeInfo] // ============================================================================ //! Basic information about a code (or target). It describes its architecture, //! code generation mode (or optimization level), and base address. class CodeInfo { public: // -------------------------------------------------------------------------- // [Construction / Destruction] // -------------------------------------------------------------------------- ASMJIT_INLINE CodeInfo() noexcept : _archInfo(), _stackAlignment(0), _cdeclCallConv(CallConv::kIdNone), _stdCallConv(CallConv::kIdNone), _fastCallConv(CallConv::kIdNone), _baseAddress(Globals::kNoBaseAddress) {} ASMJIT_INLINE CodeInfo(const CodeInfo& other) noexcept { init(other); } explicit ASMJIT_INLINE CodeInfo(uint32_t archType, uint32_t archMode = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept : _archInfo(archType, archMode), _packedMiscInfo(0), _baseAddress(baseAddress) {} // -------------------------------------------------------------------------- // [Init / Reset] // -------------------------------------------------------------------------- ASMJIT_INLINE bool isInitialized() const noexcept { return _archInfo._type != ArchInfo::kTypeNone; } ASMJIT_INLINE void init(const CodeInfo& other) noexcept { _archInfo = other._archInfo; _packedMiscInfo = other._packedMiscInfo; _baseAddress = other._baseAddress; } ASMJIT_INLINE void init(uint32_t archType, uint32_t archMode = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept { _archInfo.init(archType, archMode); _packedMiscInfo = 0; _baseAddress = baseAddress; } ASMJIT_INLINE void reset() noexcept { _archInfo.reset(); _stackAlignment = 0; _cdeclCallConv = CallConv::kIdNone; _stdCallConv = CallConv::kIdNone; _fastCallConv = CallConv::kIdNone; _baseAddress = Globals::kNoBaseAddress; } // -------------------------------------------------------------------------- // [Architecture Information] // -------------------------------------------------------------------------- //! Get architecture information, see \ref ArchInfo. ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _archInfo; } //! Get architecture type, see \ref ArchInfo::Type. ASMJIT_INLINE uint32_t getArchType() const noexcept { return _archInfo.getType(); } //! Get architecture sub-type, see \ref ArchInfo::SubType. ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return _archInfo.getSubType(); } //! Get a size of a GP register of the architecture the code is using. ASMJIT_INLINE uint32_t getGpSize() const noexcept { return _archInfo.getGpSize(); } //! Get number of GP registers available of the architecture the code is using. ASMJIT_INLINE uint32_t getGpCount() const noexcept { return _archInfo.getGpCount(); } // -------------------------------------------------------------------------- // [High-Level Information] // -------------------------------------------------------------------------- //! Get a natural stack alignment that must be honored (or 0 if not known). ASMJIT_INLINE uint32_t getStackAlignment() const noexcept { return _stackAlignment; } //! Set a natural stack alignment that must be honored. ASMJIT_INLINE void setStackAlignment(uint8_t sa) noexcept { _stackAlignment = static_cast(sa); } ASMJIT_INLINE uint32_t getCdeclCallConv() const noexcept { return _cdeclCallConv; } ASMJIT_INLINE void setCdeclCallConv(uint32_t cc) noexcept { _cdeclCallConv = static_cast(cc); } ASMJIT_INLINE uint32_t getStdCallConv() const noexcept { return _stdCallConv; } ASMJIT_INLINE void setStdCallConv(uint32_t cc) noexcept { _stdCallConv = static_cast(cc); } ASMJIT_INLINE uint32_t getFastCallConv() const noexcept { return _fastCallConv; } ASMJIT_INLINE void setFastCallConv(uint32_t cc) noexcept { _fastCallConv = static_cast(cc); } // -------------------------------------------------------------------------- // [Addressing Information] // -------------------------------------------------------------------------- ASMJIT_INLINE bool hasBaseAddress() const noexcept { return _baseAddress != Globals::kNoBaseAddress; } ASMJIT_INLINE uint64_t getBaseAddress() const noexcept { return _baseAddress; } ASMJIT_INLINE void setBaseAddress(uint64_t p) noexcept { _baseAddress = p; } ASMJIT_INLINE void resetBaseAddress() noexcept { _baseAddress = Globals::kNoBaseAddress; } // -------------------------------------------------------------------------- // [Operator Overload] // -------------------------------------------------------------------------- ASMJIT_INLINE CodeInfo& operator=(const CodeInfo& other) noexcept { init(other); return *this; } ASMJIT_INLINE bool operator==(const CodeInfo& other) const noexcept { return ::memcmp(this, &other, sizeof(*this)) == 0; } ASMJIT_INLINE bool operator!=(const CodeInfo& other) const noexcept { return ::memcmp(this, &other, sizeof(*this)) != 0; } // -------------------------------------------------------------------------- // [Members] // -------------------------------------------------------------------------- ArchInfo _archInfo; //!< Architecture information. union { struct { uint8_t _stackAlignment; //!< Natural stack alignment (ARCH+OS). uint8_t _cdeclCallConv; //!< Default CDECL calling convention. uint8_t _stdCallConv; //!< Default STDCALL calling convention. uint8_t _fastCallConv; //!< Default FASTCALL calling convention. }; uint32_t _packedMiscInfo; //!< \internal }; uint64_t _baseAddress; //!< Base address. }; // ============================================================================ // [asmjit::CodeBuffer] // ============================================================================ //! Code or data buffer. struct CodeBuffer { // -------------------------------------------------------------------------- // [Accessors] // -------------------------------------------------------------------------- ASMJIT_INLINE bool hasData() const noexcept { return _data != nullptr; } ASMJIT_INLINE uint8_t* getData() noexcept { return _data; } ASMJIT_INLINE const uint8_t* getData() const noexcept { return _data; } ASMJIT_INLINE size_t getLength() const noexcept { return _length; } ASMJIT_INLINE size_t getCapacity() const noexcept { return _capacity; } ASMJIT_INLINE bool isExternal() const noexcept { return _isExternal; } ASMJIT_INLINE bool isFixedSize() const noexcept { return _isFixedSize; } // -------------------------------------------------------------------------- // [Members] // -------------------------------------------------------------------------- uint8_t* _data; //!< The content of the buffer (data). size_t _length; //!< Number of bytes of `data` used. size_t _capacity; //!< Buffer capacity (in bytes). bool _isExternal; //!< True if this is external buffer. bool _isFixedSize; //!< True if this buffer cannot grow. }; // ============================================================================ // [asmjit::SectionEntry] // ============================================================================ //! Section entry. class SectionEntry { public: ASMJIT_ENUM(Id) { kInvalidId = 0xFFFFFFFFU //!< Invalid section id. }; //! Section flags. ASMJIT_ENUM(Flags) { kFlagExec = 0x00000001U, //!< Executable (.text sections). kFlagConst = 0x00000002U, //!< Read-only (.text and .data sections). kFlagZero = 0x00000004U, //!< Zero initialized by the loader (BSS). kFlagInfo = 0x00000008U, //!< Info / comment flag. kFlagImplicit = 0x80000000U //!< Section created implicitly (can be deleted by the Runtime). }; // -------------------------------------------------------------------------- // [Accessors] // -------------------------------------------------------------------------- ASMJIT_INLINE uint32_t getId() const noexcept { return _id; } ASMJIT_INLINE const char* getName() const noexcept { return _name; } ASMJIT_INLINE void _setDefaultName( char c0 = 0, char c1 = 0, char c2 = 0, char c3 = 0, char c4 = 0, char c5 = 0, char c6 = 0, char c7 = 0) noexcept { _nameAsU32[0] = Utils::pack32_4x8(c0, c1, c2, c3); _nameAsU32[1] = Utils::pack32_4x8(c4, c5, c6, c7); } ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; } ASMJIT_INLINE bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } ASMJIT_INLINE void addFlags(uint32_t flags) noexcept { _flags |= flags; } ASMJIT_INLINE void clearFlags(uint32_t flags) noexcept { _flags &= ~flags; } ASMJIT_INLINE uint32_t getAlignment() const noexcept { return _alignment; } ASMJIT_INLINE void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; } ASMJIT_INLINE size_t getPhysicalSize() const noexcept { return _buffer.getLength(); } ASMJIT_INLINE size_t getVirtualSize() const noexcept { return _virtualSize; } ASMJIT_INLINE void setVirtualSize(uint32_t size) noexcept { _virtualSize = size; } ASMJIT_INLINE CodeBuffer& getBuffer() noexcept { return _buffer; } ASMJIT_INLINE const CodeBuffer& getBuffer() const noexcept { return _buffer; } // -------------------------------------------------------------------------- // [Members] // -------------------------------------------------------------------------- uint32_t _id; //!< Section id. uint32_t _flags; //!< Section flags. uint32_t _alignment; //!< Section alignment requirements (0 if no requirements). uint32_t _virtualSize; //!< Virtual size of the section (zero initialized mostly). union { char _name[36]; //!< Section name (max 35 characters, PE allows max 8). uint32_t _nameAsU32[36 / 4]; //!< Section name as `uint32_t[]` (only optimization). }; CodeBuffer _buffer; //!< Code or data buffer. }; // ============================================================================ // [asmjit::LabelLink] // ============================================================================ //! Data structure used to link labels. struct LabelLink { LabelLink* prev; //!< Previous link (single-linked list). uint32_t sectionId; //!< Section id. uint32_t relocId; //!< Relocation id or RelocEntry::kInvalidId. size_t offset; //!< Label offset relative to the start of the section. intptr_t rel; //!< Inlined rel8/rel32. }; // ============================================================================ // [asmjit::LabelEntry] // ============================================================================ //! Label entry. //! //! Contains the following properties: //! * Label id - This is the only thing that is set to the `Label` operand. //! * Label name - Optional, used mostly to create executables and libraries. //! * Label type - Type of the label, default `Label::kTypeAnonymous`. //! * Label parent id - Derived from many assemblers that allow to define a //! local label that falls under a global label. This allows to define //! many labels of the same name that have different parent (global) label. //! * Offset - offset of the label bound by `Assembler`. //! * Links - single-linked list that contains locations of code that has //! to be patched when the label gets bound. Every use of unbound label //! adds one link to `_links` list. //! * HVal - Hash value of label's name and optionally parentId. //! * HashNext - Hash-table implementation detail. class LabelEntry : public ZoneHashNode { public: // NOTE: Label id is stored in `_customData`, which is provided by ZoneHashNode // to fill a padding that a C++ compiler targeting 64-bit CPU will add to align // the structure to 64-bits. //! Get label id. ASMJIT_INLINE uint32_t getId() const noexcept { return _customData; } //! Set label id (internal, used only by \ref CodeHolder). ASMJIT_INLINE void _setId(uint32_t id) noexcept { _customData = id; } //! Get label type, see \ref Label::Type. ASMJIT_INLINE uint32_t getType() const noexcept { return _type; } //! Get label flags, returns 0 at the moment. ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; } ASMJIT_INLINE bool hasParent() const noexcept { return _parentId != 0; } //! Get label's parent id. ASMJIT_INLINE uint32_t getParentId() const noexcept { return _parentId; } //! Get label's section id where it's bound to (or `SectionEntry::kInvalidId` if it's not bound yet). ASMJIT_INLINE uint32_t getSectionId() const noexcept { return _sectionId; } //! Get if the label has name. ASMJIT_INLINE bool hasName() const noexcept { return !_name.isEmpty(); } //! Get the label's name. //! //! NOTE: Local labels will return their local name without their parent //! part, for example ".L1". ASMJIT_INLINE const char* getName() const noexcept { return _name.getData(); } //! Get length of label's name. //! //! NOTE: Label name is always null terminated, so you can use `strlen()` to //! get it, however, it's also cached in `LabelEntry`, so if you want to know //! the length the easiest way is to use `LabelEntry::getNameLength()`. ASMJIT_INLINE size_t getNameLength() const noexcept { return _name.getLength(); } //! Get if the label is bound. ASMJIT_INLINE bool isBound() const noexcept { return _sectionId != SectionEntry::kInvalidId; } //! Get the label offset (only useful if the label is bound). ASMJIT_INLINE intptr_t getOffset() const noexcept { return _offset; } //! Get the hash-value of label's name and its parent label (if any). //! //! Label hash is calculated as `HASH(Name) ^ ParentId`. The hash function //! is implemented in `Utils::hashString()` and `Utils::hashRound()`. ASMJIT_INLINE uint32_t getHVal() const noexcept { return _hVal; } // ------------------------------------------------------------------------ // [Members] // ------------------------------------------------------------------------ // Let's round the size of `LabelEntry` to 64 bytes (as ZoneHeap has 32 // bytes granularity anyway). This gives `_name` the remaining space, which // is roughly 16 bytes on 64-bit and 28 bytes on 32-bit architectures. enum { kNameBytes = 64 - (sizeof(ZoneHashNode) + 16 + sizeof(intptr_t) + sizeof(LabelLink*)) }; uint8_t _type; //!< Label type, see Label::Type. uint8_t _flags; //!< Must be zero. uint16_t _reserved16; //!< Reserved. uint32_t _parentId; //!< Label parent id or zero. uint32_t _sectionId; //!< Section id or `SectionEntry::kInvalidId`. uint32_t _reserved32; //!< Reserved. intptr_t _offset; //!< Label offset. LabelLink* _links; //!< Label links. SmallString _name; //!< Label name. }; // ============================================================================ // [asmjit::RelocEntry] // ============================================================================ //! Relocation entry. struct RelocEntry { ASMJIT_ENUM(Id) { kInvalidId = 0xFFFFFFFFU //!< Invalid relocation id. }; //! Relocation type. ASMJIT_ENUM(Type) { kTypeNone = 0, //!< Deleted entry (no relocation). kTypeAbsToAbs = 1, //!< Relocate absolute to absolute. kTypeRelToAbs = 2, //!< Relocate relative to absolute. kTypeAbsToRel = 3, //!< Relocate absolute to relative. kTypeTrampoline = 4 //!< Relocate absolute to relative or use trampoline. }; // ------------------------------------------------------------------------ // [Accessors] // ------------------------------------------------------------------------ ASMJIT_INLINE uint32_t getId() const noexcept { return _id; } ASMJIT_INLINE uint32_t getType() const noexcept { return _type; } ASMJIT_INLINE uint32_t getSize() const noexcept { return _size; } ASMJIT_INLINE uint32_t getSourceSectionId() const noexcept { return _sourceSectionId; } ASMJIT_INLINE uint32_t getTargetSectionId() const noexcept { return _targetSectionId; } ASMJIT_INLINE uint64_t getSourceOffset() const noexcept { return _sourceOffset; } ASMJIT_INLINE uint64_t getData() const noexcept { return _data; } // ------------------------------------------------------------------------ // [Members] // ------------------------------------------------------------------------ uint32_t _id; //!< Relocation id. uint8_t _type; //!< Type of the relocation. uint8_t _size; //!< Size of the relocation (1, 2, 4 or 8 bytes). uint8_t _reserved[2]; //!< Reserved. uint32_t _sourceSectionId; //!< Source section id. uint32_t _targetSectionId; //!< Destination section id. uint64_t _sourceOffset; //!< Source offset (relative to start of the section). uint64_t _data; //!< Relocation data (target offset, target address, etc). }; // ============================================================================ // [asmjit::CodeHolder] // ============================================================================ //! Contains basic information about the target architecture plus its settings, //! and holds code & data (including sections, labels, and relocation information). //! CodeHolder can store both binary and intermediate representation of assembly, //! which can be generated by \ref Assembler and/or \ref CodeBuilder. //! //! NOTE: CodeHolder has ability to attach an \ref ErrorHandler, however, this //! error handler is not triggered by CodeHolder itself, it's only used by the //! attached code generators. class CodeHolder { public: ASMJIT_NONCOPYABLE(CodeHolder) // -------------------------------------------------------------------------- // [Construction / Destruction] // -------------------------------------------------------------------------- //! Create an uninitialized CodeHolder (you must init() it before it can be used). ASMJIT_API CodeHolder() noexcept; //! Destroy the CodeHolder. ASMJIT_API ~CodeHolder() noexcept; // -------------------------------------------------------------------------- // [Init / Reset] // -------------------------------------------------------------------------- ASMJIT_INLINE bool isInitialized() const noexcept { return _codeInfo.isInitialized(); } //! Initialize to CodeHolder to hold code described by `codeInfo`. ASMJIT_API Error init(const CodeInfo& info) noexcept; //! Detach all code-generators attached and reset the \ref CodeHolder. ASMJIT_API void reset(bool releaseMemory = false) noexcept; // -------------------------------------------------------------------------- // [Attach / Detach] // -------------------------------------------------------------------------- //! Attach a \ref CodeEmitter to this \ref CodeHolder. ASMJIT_API Error attach(CodeEmitter* emitter) noexcept; //! Detach a \ref CodeEmitter from this \ref CodeHolder. ASMJIT_API Error detach(CodeEmitter* emitter) noexcept; // -------------------------------------------------------------------------- // [Sync] // -------------------------------------------------------------------------- //! Synchronize all states of all `CodeEmitter`s associated with the CodeHolder. //! This is required as some code generators don't sync every time they do //! something - for example \ref Assembler generally syncs when it needs to //! reallocate the \ref CodeBuffer, but not each time it encodes instruction //! or directive. ASMJIT_API void sync() noexcept; // -------------------------------------------------------------------------- // [Code-Information] // -------------------------------------------------------------------------- //! Get code/target information, see \ref CodeInfo. ASMJIT_INLINE const CodeInfo& getCodeInfo() const noexcept { return _codeInfo; } //! Get architecture information, see \ref ArchInfo. ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _codeInfo.getArchInfo(); } //! Get the target's architecture type. ASMJIT_INLINE uint32_t getArchType() const noexcept { return getArchInfo().getType(); } //! Get the target's architecture sub-type. ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return getArchInfo().getSubType(); } //! Get if a static base-address is set. ASMJIT_INLINE bool hasBaseAddress() const noexcept { return _codeInfo.hasBaseAddress(); } //! Get a static base-address (uint64_t). ASMJIT_INLINE uint64_t getBaseAddress() const noexcept { return _codeInfo.getBaseAddress(); } // -------------------------------------------------------------------------- // [Global Information] // -------------------------------------------------------------------------- //! Get global hints, internally propagated to all `CodeEmitter`s attached. ASMJIT_INLINE uint32_t getGlobalHints() const noexcept { return _globalHints; } //! Get global options, internally propagated to all `CodeEmitter`s attached. ASMJIT_INLINE uint32_t getGlobalOptions() const noexcept { return _globalOptions; } // -------------------------------------------------------------------------- // [Result Information] // -------------------------------------------------------------------------- //! Get the size code & data of all sections. ASMJIT_API size_t getCodeSize() const noexcept; //! Get size of all possible trampolines. //! //! Trampolines are needed to successfully generate relative jumps to absolute //! addresses. This value is only non-zero if jmp of call instructions were //! used with immediate operand (this means jumping or calling an absolute //! address directly). ASMJIT_INLINE size_t getTrampolinesSize() const noexcept { return _trampolinesSize; } // -------------------------------------------------------------------------- // [Logging & Error Handling] // -------------------------------------------------------------------------- #if !defined(ASMJIT_DISABLE_LOGGING) //! Get if a logger attached. ASMJIT_INLINE bool hasLogger() const noexcept { return _logger != nullptr; } //! Get the attached logger. ASMJIT_INLINE Logger* getLogger() const noexcept { return _logger; } //! Attach a `logger` to CodeHolder and propagate it to all attached `CodeEmitter`s. ASMJIT_API void setLogger(Logger* logger) noexcept; //! Reset the logger (does nothing if not attached). ASMJIT_INLINE void resetLogger() noexcept { setLogger(nullptr); } #endif // !ASMJIT_DISABLE_LOGGING //! Get if error-handler is attached. ASMJIT_INLINE bool hasErrorHandler() const noexcept { return _errorHandler != nullptr; } //! Get the error-handler. ASMJIT_INLINE ErrorHandler* getErrorHandler() const noexcept { return _errorHandler; } //! Set the error handler, will affect all attached `CodeEmitter`s. ASMJIT_API Error setErrorHandler(ErrorHandler* handler) noexcept; //! Reset the error handler (does nothing if not attached). ASMJIT_INLINE void resetErrorHandler() noexcept { setErrorHandler(nullptr); } // -------------------------------------------------------------------------- // [Sections] // -------------------------------------------------------------------------- //! Get array of `SectionEntry*` records. ASMJIT_INLINE const ZoneVector& getSections() const noexcept { return _sections; } //! Get a section entry of the given index. ASMJIT_INLINE SectionEntry* getSectionEntry(size_t index) const noexcept { return _sections[index]; } ASMJIT_API Error growBuffer(CodeBuffer* cb, size_t n) noexcept; ASMJIT_API Error reserveBuffer(CodeBuffer* cb, size_t n) noexcept; // -------------------------------------------------------------------------- // [Labels & Symbols] // -------------------------------------------------------------------------- //! Create a new anonymous label and return its id in `idOut`. //! //! Returns `Error`, does not report error to \ref ErrorHandler. ASMJIT_API Error newLabelId(uint32_t& idOut) noexcept; //! Create a new named label label-type `type`. //! //! Returns `Error`, does not report error to \ref ErrorHandler. ASMJIT_API Error newNamedLabelId(uint32_t& idOut, const char* name, size_t nameLength, uint32_t type, uint32_t parentId) noexcept; //! Get a label id by name. ASMJIT_API uint32_t getLabelIdByName(const char* name, size_t nameLength = Globals::kInvalidIndex, uint32_t parentId = 0) noexcept; //! Create a new label-link used to store information about yet unbound labels. //! //! Returns `null` if the allocation failed. ASMJIT_API LabelLink* newLabelLink(LabelEntry* le, uint32_t sectionId, size_t offset, intptr_t rel) noexcept; //! Get array of `LabelEntry*` records. ASMJIT_INLINE const ZoneVector& getLabelEntries() const noexcept { return _labels; } //! Get number of labels created. ASMJIT_INLINE size_t getLabelsCount() const noexcept { return _labels.getLength(); } //! Get number of label references, which are unresolved at the moment. ASMJIT_INLINE size_t getUnresolvedLabelsCount() const noexcept { return _unresolvedLabelsCount; } //! Get if the `label` is valid (i.e. created by `newLabelId()`). ASMJIT_INLINE bool isLabelValid(const Label& label) const noexcept { return isLabelValid(label.getId()); } //! Get if the label having `id` is valid (i.e. created by `newLabelId()`). ASMJIT_INLINE bool isLabelValid(uint32_t labelId) const noexcept { size_t index = Operand::unpackId(labelId); return index < _labels.getLength(); } //! Get if the `label` is already bound. //! //! Returns `false` if the `label` is not valid. ASMJIT_INLINE bool isLabelBound(const Label& label) const noexcept { return isLabelBound(label.getId()); } //! \overload ASMJIT_INLINE bool isLabelBound(uint32_t id) const noexcept { size_t index = Operand::unpackId(id); return index < _labels.getLength() && _labels[index]->isBound(); } //! Get a `label` offset or -1 if the label is not yet bound. ASMJIT_INLINE intptr_t getLabelOffset(const Label& label) const noexcept { return getLabelOffset(label.getId()); } //! \overload ASMJIT_INLINE intptr_t getLabelOffset(uint32_t id) const noexcept { ASMJIT_ASSERT(isLabelValid(id)); return _labels[Operand::unpackId(id)]->getOffset(); } //! Get information about the given `label`. ASMJIT_INLINE LabelEntry* getLabelEntry(const Label& label) const noexcept { return getLabelEntry(label.getId()); } //! Get information about a label having the given `id`. ASMJIT_INLINE LabelEntry* getLabelEntry(uint32_t id) const noexcept { size_t index = static_cast(Operand::unpackId(id)); return index < _labels.getLength() ? _labels[index] : static_cast(nullptr); } // -------------------------------------------------------------------------- // [Relocations] // -------------------------------------------------------------------------- //! Create a new relocation entry of type `type` and size `size`. //! //! Additional fields can be set after the relocation entry was created. ASMJIT_API Error newRelocEntry(RelocEntry** dst, uint32_t type, uint32_t size) noexcept; //! Get if the code contains relocations. ASMJIT_INLINE bool hasRelocations() const noexcept { return !_relocations.isEmpty(); } //! Get array of `RelocEntry*` records. ASMJIT_INLINE const ZoneVector& getRelocEntries() const noexcept { return _relocations; } ASMJIT_INLINE RelocEntry* getRelocEntry(uint32_t id) const noexcept { return _relocations[id]; } //! Relocate the code to `baseAddress` and copy it to `dst`. //! //! \param dst Contains the location where the relocated code should be //! copied. The pointer can be address returned by virtual memory allocator //! or any other address that has sufficient space. //! //! \param baseAddress Base address used for relocation. `JitRuntime` always //! sets the `baseAddress` to be the same as `dst`. //! //! \return The number bytes actually used. If the code emitter reserved //! space for possible trampolines, but didn't use it, the number of bytes //! used can actually be less than the expected worst case. Virtual memory //! allocator can shrink the memory it allocated initially. //! //! A given buffer will be overwritten, to get the number of bytes required, //! use `getCodeSize()`. ASMJIT_API size_t relocate(void* dst, uint64_t baseAddress = Globals::kNoBaseAddress) const noexcept; // -------------------------------------------------------------------------- // [Members] // -------------------------------------------------------------------------- CodeInfo _codeInfo; //!< Basic information about the code (architecture and other info). uint32_t _globalHints; //!< Global hints, propagated to all `CodeEmitter`s. uint32_t _globalOptions; //!< Global options, propagated to all `CodeEmitter`s. CodeEmitter* _emitters; //!< Linked-list of all attached `CodeEmitter`s. Assembler* _cgAsm; //!< Attached \ref Assembler (only one at a time). Logger* _logger; //!< Attached \ref Logger, used by all consumers. ErrorHandler* _errorHandler; //!< Attached \ref ErrorHandler. uint32_t _unresolvedLabelsCount; //!< Count of label references which were not resolved. uint32_t _trampolinesSize; //!< Size of all possible trampolines. Zone _baseZone; //!< Base zone (used to allocate core structures). Zone _dataZone; //!< Data zone (used to allocate extra data like label names). ZoneHeap _baseHeap; //!< Zone allocator, used to manage internal containers. ZoneVector _sections; //!< Section entries. ZoneVector _labels; //!< Label entries (each label is stored here). ZoneVector _relocations; //!< Relocation entries. ZoneHash _namedLabels; //!< Label name -> LabelEntry (only named labels). }; //! \} } // asmjit namespace // [Api-End] #include "../asmjit_apiend.h" // [Guard] #endif // _ASMJIT_BASE_CODEHOLDER_H