Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2008-2017, Petr Kobalicek
3 :
4 : This software is provided 'as-is', without any express or implied
5 : warranty. In no event will the authors be held liable for any damages
6 : arising from the use of this software.
7 :
8 : Permission is granted to anyone to use this software for any purpose,
9 : including commercial applications, and to alter it and redistribute it
10 : freely, subject to the following restrictions:
11 :
12 : 1. The origin of this software must not be misrepresented; you must not
13 : claim that you wrote the original software. If you use this software
14 : in a product, an acknowledgment in the product documentation would be
15 : appreciated but is not required.
16 : 2. Altered source versions must be plainly marked as such, and must not be
17 : misrepresented as being the original software.
18 : 3. This notice may not be removed or altered from any source distribution.
19 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
20 : #ifndef __PLUMED_asmjit_codeholder_h
21 : #define __PLUMED_asmjit_codeholder_h
22 : #ifdef __PLUMED_HAS_ASMJIT
23 : #pragma GCC diagnostic push
24 : #pragma GCC diagnostic ignored "-Wpedantic"
25 : // [AsmJit]
26 : // Complete x86/x64 JIT and Remote Assembler for C++.
27 : //
28 : // [License]
29 : // Zlib - See LICENSE.md file in the package.
30 :
31 : // [Guard]
32 : #ifndef _ASMJIT_BASE_CODEHOLDER_H
33 : #define _ASMJIT_BASE_CODEHOLDER_H
34 :
35 : // [Dependencies]
36 : #include "./arch.h"
37 : #include "./func.h"
38 : #include "./logging.h"
39 : #include "./operand.h"
40 : #include "./simdtypes.h"
41 : #include "./utils.h"
42 : #include "./zone.h"
43 :
44 : // [Api-Begin]
45 : #include "./asmjit_apibegin.h"
46 :
47 : namespace PLMD {
48 : namespace asmjit {
49 :
50 : //! \addtogroup asmjit_base
51 : //! \{
52 :
53 : // ============================================================================
54 : // [Forward Declarations]
55 : // ============================================================================
56 :
57 : class Assembler;
58 : class CodeEmitter;
59 : class CodeHolder;
60 :
61 : // ============================================================================
62 : // [asmjit::AlignMode]
63 : // ============================================================================
64 :
65 : //! Align mode.
66 : ASMJIT_ENUM(AlignMode) {
67 : kAlignCode = 0, //!< Align executable code.
68 : kAlignData = 1, //!< Align non-executable code.
69 : kAlignZero = 2, //!< Align by a sequence of zeros.
70 : kAlignCount //!< Count of alignment modes.
71 : };
72 :
73 : // ============================================================================
74 : // [asmjit::ErrorHandler]
75 : // ============================================================================
76 :
77 : //! Error handler can be used to override the default behavior of error handling
78 : //! available to all classes that inherit \ref CodeEmitter. See \ref handleError().
79 : class ASMJIT_VIRTAPI ErrorHandler {
80 : public:
81 : // --------------------------------------------------------------------------
82 : // [Construction / Destruction]
83 : // --------------------------------------------------------------------------
84 :
85 : //! Create a new `ErrorHandler` instance.
86 : ASMJIT_API ErrorHandler() noexcept;
87 : //! Destroy the `ErrorHandler` instance.
88 : ASMJIT_API virtual ~ErrorHandler() noexcept;
89 :
90 : // --------------------------------------------------------------------------
91 : // [Handle Error]
92 : // --------------------------------------------------------------------------
93 :
94 : //! Error handler (abstract).
95 : //!
96 : //! Error handler is called after an error happened and before it's propagated
97 : //! to the caller. There are multiple ways how the error handler can be used:
98 : //!
99 : //! 1. Returning `true` or `false` from `handleError()`. If `true` is returned
100 : //! it means that the error was reported and AsmJit can continue execution.
101 : //! The reported error still be propagated to the caller, but won't put the
102 : //! CodeEmitter into an error state (it won't set last-error). However,
103 : //! returning `false` means that the error cannot be handled - in such case
104 : //! it stores the error, which can be then retrieved by using `getLastError()`.
105 : //! Returning `false` is the default behavior when no error handler is present.
106 : //! To put the assembler into a non-error state again a `resetLastError()` must
107 : //! be called.
108 : //!
109 : //! 2. Throwing an exception. AsmJit doesn't use exceptions and is completely
110 : //! exception-safe, but you can throw exception from your error handler if
111 : //! this way is the preferred way of handling errors in your project. Throwing
112 : //! an exception acts virtually as returning `true` as AsmJit won't be able
113 : //! to store the error because the exception changes execution path.
114 : //!
115 : //! 3. Using plain old C's `setjmp()` and `longjmp()`. Asmjit always puts
116 : //! `CodeEmitter` to a consistent state before calling the `handleError()`
117 : //! so `longjmp()` can be used without any issues to cancel the code
118 : //! generation if an error occurred. There is no difference between
119 : //! exceptions and longjmp() from AsmJit's perspective.
120 : virtual bool handleError(Error err, const char* message, CodeEmitter* origin) = 0;
121 : };
122 :
123 : // ============================================================================
124 : // [asmjit::CodeInfo]
125 : // ============================================================================
126 :
127 : //! Basic information about a code (or target). It describes its architecture,
128 : //! code generation mode (or optimization level), and base address.
129 : class CodeInfo {
130 : public:
131 : // --------------------------------------------------------------------------
132 : // [Construction / Destruction]
133 : // --------------------------------------------------------------------------
134 :
135 : ASMJIT_INLINE CodeInfo() noexcept
136 7804 : : _archInfo(),
137 7804 : _stackAlignment(0),
138 7804 : _cdeclCallConv(CallConv::kIdNone),
139 7804 : _stdCallConv(CallConv::kIdNone),
140 7804 : _fastCallConv(CallConv::kIdNone),
141 7804 : _baseAddress(Globals::kNoBaseAddress) {}
142 : ASMJIT_INLINE CodeInfo(const CodeInfo& other) noexcept { init(other); }
143 :
144 : explicit ASMJIT_INLINE CodeInfo(uint32_t archType, uint32_t archMode = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept
145 : : _archInfo(archType, archMode),
146 : _packedMiscInfo(0),
147 : _baseAddress(baseAddress) {}
148 :
149 : // --------------------------------------------------------------------------
150 : // [Init / Reset]
151 : // --------------------------------------------------------------------------
152 :
153 : ASMJIT_INLINE bool isInitialized() const noexcept {
154 1944 : return _archInfo._type != ArchInfo::kTypeNone;
155 : }
156 :
157 : ASMJIT_INLINE void init(const CodeInfo& other) noexcept {
158 5832 : _archInfo = other._archInfo;
159 5832 : _packedMiscInfo = other._packedMiscInfo;
160 5832 : _baseAddress = other._baseAddress;
161 : }
162 :
163 : ASMJIT_INLINE void init(uint32_t archType, uint32_t archMode = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept {
164 : _archInfo.init(archType, archMode);
165 : _packedMiscInfo = 0;
166 : _baseAddress = baseAddress;
167 : }
168 :
169 : ASMJIT_INLINE void reset() noexcept {
170 : _archInfo.reset();
171 1944 : _stackAlignment = 0;
172 1944 : _cdeclCallConv = CallConv::kIdNone;
173 1944 : _stdCallConv = CallConv::kIdNone;
174 1944 : _fastCallConv = CallConv::kIdNone;
175 1944 : _baseAddress = Globals::kNoBaseAddress;
176 : }
177 :
178 : // --------------------------------------------------------------------------
179 : // [Architecture Information]
180 : // --------------------------------------------------------------------------
181 :
182 : //! Get architecture information, see \ref ArchInfo.
183 : ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _archInfo; }
184 :
185 : //! Get architecture type, see \ref ArchInfo::Type.
186 : ASMJIT_INLINE uint32_t getArchType() const noexcept { return _archInfo.getType(); }
187 : //! Get architecture sub-type, see \ref ArchInfo::SubType.
188 : ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return _archInfo.getSubType(); }
189 : //! Get a size of a GP register of the architecture the code is using.
190 : ASMJIT_INLINE uint32_t getGpSize() const noexcept { return _archInfo.getGpSize(); }
191 : //! Get number of GP registers available of the architecture the code is using.
192 : ASMJIT_INLINE uint32_t getGpCount() const noexcept { return _archInfo.getGpCount(); }
193 :
194 : // --------------------------------------------------------------------------
195 : // [High-Level Information]
196 : // --------------------------------------------------------------------------
197 :
198 : //! Get a natural stack alignment that must be honored (or 0 if not known).
199 1944 : ASMJIT_INLINE uint32_t getStackAlignment() const noexcept { return _stackAlignment; }
200 : //! Set a natural stack alignment that must be honored.
201 : ASMJIT_INLINE void setStackAlignment(uint8_t sa) noexcept { _stackAlignment = static_cast<uint8_t>(sa); }
202 :
203 : ASMJIT_INLINE uint32_t getCdeclCallConv() const noexcept { return _cdeclCallConv; }
204 : ASMJIT_INLINE void setCdeclCallConv(uint32_t cc) noexcept { _cdeclCallConv = static_cast<uint8_t>(cc); }
205 :
206 : ASMJIT_INLINE uint32_t getStdCallConv() const noexcept { return _stdCallConv; }
207 : ASMJIT_INLINE void setStdCallConv(uint32_t cc) noexcept { _stdCallConv = static_cast<uint8_t>(cc); }
208 :
209 : ASMJIT_INLINE uint32_t getFastCallConv() const noexcept { return _fastCallConv; }
210 : ASMJIT_INLINE void setFastCallConv(uint32_t cc) noexcept { _fastCallConv = static_cast<uint8_t>(cc); }
211 :
212 : // --------------------------------------------------------------------------
213 : // [Addressing Information]
214 : // --------------------------------------------------------------------------
215 :
216 : ASMJIT_INLINE bool hasBaseAddress() const noexcept { return _baseAddress != Globals::kNoBaseAddress; }
217 0 : ASMJIT_INLINE uint64_t getBaseAddress() const noexcept { return _baseAddress; }
218 : ASMJIT_INLINE void setBaseAddress(uint64_t p) noexcept { _baseAddress = p; }
219 : ASMJIT_INLINE void resetBaseAddress() noexcept { _baseAddress = Globals::kNoBaseAddress; }
220 :
221 : // --------------------------------------------------------------------------
222 : // [Operator Overload]
223 : // --------------------------------------------------------------------------
224 :
225 : ASMJIT_INLINE CodeInfo& operator=(const CodeInfo& other) noexcept { init(other); return *this; }
226 : ASMJIT_INLINE bool operator==(const CodeInfo& other) const noexcept { return ::memcmp(this, &other, sizeof(*this)) == 0; }
227 : ASMJIT_INLINE bool operator!=(const CodeInfo& other) const noexcept { return ::memcmp(this, &other, sizeof(*this)) != 0; }
228 :
229 : // --------------------------------------------------------------------------
230 : // [Members]
231 : // --------------------------------------------------------------------------
232 :
233 : ArchInfo _archInfo; //!< Architecture information.
234 :
235 : union {
236 : struct {
237 : uint8_t _stackAlignment; //!< Natural stack alignment (ARCH+OS).
238 : uint8_t _cdeclCallConv; //!< Default CDECL calling convention.
239 : uint8_t _stdCallConv; //!< Default STDCALL calling convention.
240 : uint8_t _fastCallConv; //!< Default FASTCALL calling convention.
241 : };
242 : uint32_t _packedMiscInfo; //!< \internal
243 : };
244 :
245 : uint64_t _baseAddress; //!< Base address.
246 : };
247 :
248 : // ============================================================================
249 : // [asmjit::CodeBuffer]
250 : // ============================================================================
251 :
252 : //! Code or data buffer.
253 : struct CodeBuffer {
254 : // --------------------------------------------------------------------------
255 : // [Accessors]
256 : // --------------------------------------------------------------------------
257 :
258 1944 : ASMJIT_INLINE bool hasData() const noexcept { return _data != nullptr; }
259 : ASMJIT_INLINE uint8_t* getData() noexcept { return _data; }
260 : ASMJIT_INLINE const uint8_t* getData() const noexcept { return _data; }
261 :
262 5832 : ASMJIT_INLINE size_t getLength() const noexcept { return _length; }
263 1944 : ASMJIT_INLINE size_t getCapacity() const noexcept { return _capacity; }
264 :
265 1944 : ASMJIT_INLINE bool isExternal() const noexcept { return _isExternal; }
266 1944 : ASMJIT_INLINE bool isFixedSize() const noexcept { return _isFixedSize; }
267 :
268 : // --------------------------------------------------------------------------
269 : // [Members]
270 : // --------------------------------------------------------------------------
271 :
272 : uint8_t* _data; //!< The content of the buffer (data).
273 : size_t _length; //!< Number of bytes of `data` used.
274 : size_t _capacity; //!< Buffer capacity (in bytes).
275 : bool _isExternal; //!< True if this is external buffer.
276 : bool _isFixedSize; //!< True if this buffer cannot grow.
277 : };
278 :
279 : // ============================================================================
280 : // [asmjit::SectionEntry]
281 : // ============================================================================
282 :
283 : //! Section entry.
284 : class SectionEntry {
285 : public:
286 : ASMJIT_ENUM(Id) {
287 : kInvalidId = 0xFFFFFFFFU //!< Invalid section id.
288 : };
289 :
290 : //! Section flags.
291 : ASMJIT_ENUM(Flags) {
292 : kFlagExec = 0x00000001U, //!< Executable (.text sections).
293 : kFlagConst = 0x00000002U, //!< Read-only (.text and .data sections).
294 : kFlagZero = 0x00000004U, //!< Zero initialized by the loader (BSS).
295 : kFlagInfo = 0x00000008U, //!< Info / comment flag.
296 : kFlagImplicit = 0x80000000U //!< Section created implicitly (can be deleted by the Runtime).
297 : };
298 :
299 : // --------------------------------------------------------------------------
300 : // [Accessors]
301 : // --------------------------------------------------------------------------
302 :
303 3888 : ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
304 : ASMJIT_INLINE const char* getName() const noexcept { return _name; }
305 :
306 : ASMJIT_INLINE void _setDefaultName(
307 : char c0 = 0, char c1 = 0, char c2 = 0, char c3 = 0,
308 : char c4 = 0, char c5 = 0, char c6 = 0, char c7 = 0) noexcept {
309 1944 : _nameAsU32[0] = Utils::pack32_4x8(c0, c1, c2, c3);
310 1944 : _nameAsU32[1] = Utils::pack32_4x8(c4, c5, c6, c7);
311 : }
312 :
313 : ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; }
314 : ASMJIT_INLINE bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; }
315 : ASMJIT_INLINE void addFlags(uint32_t flags) noexcept { _flags |= flags; }
316 : ASMJIT_INLINE void clearFlags(uint32_t flags) noexcept { _flags &= ~flags; }
317 :
318 : ASMJIT_INLINE uint32_t getAlignment() const noexcept { return _alignment; }
319 : ASMJIT_INLINE void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; }
320 :
321 : ASMJIT_INLINE size_t getPhysicalSize() const noexcept { return _buffer.getLength(); }
322 :
323 : ASMJIT_INLINE size_t getVirtualSize() const noexcept { return _virtualSize; }
324 : ASMJIT_INLINE void setVirtualSize(uint32_t size) noexcept { _virtualSize = size; }
325 :
326 : ASMJIT_INLINE CodeBuffer& getBuffer() noexcept { return _buffer; }
327 : ASMJIT_INLINE const CodeBuffer& getBuffer() const noexcept { return _buffer; }
328 :
329 : // --------------------------------------------------------------------------
330 : // [Members]
331 : // --------------------------------------------------------------------------
332 :
333 : uint32_t _id; //!< Section id.
334 : uint32_t _flags; //!< Section flags.
335 : uint32_t _alignment; //!< Section alignment requirements (0 if no requirements).
336 : uint32_t _virtualSize; //!< Virtual size of the section (zero initialized mostly).
337 : union {
338 : char _name[36]; //!< Section name (max 35 characters, PE allows max 8).
339 : uint32_t _nameAsU32[36 / 4]; //!< Section name as `uint32_t[]` (only optimization).
340 : };
341 : CodeBuffer _buffer; //!< Code or data buffer.
342 : };
343 :
344 : // ============================================================================
345 : // [asmjit::LabelLink]
346 : // ============================================================================
347 :
348 : //! Data structure used to link labels.
349 : struct LabelLink {
350 : LabelLink* prev; //!< Previous link (single-linked list).
351 : uint32_t sectionId; //!< Section id.
352 : uint32_t relocId; //!< Relocation id or RelocEntry::kInvalidId.
353 : size_t offset; //!< Label offset relative to the start of the section.
354 : intptr_t rel; //!< Inlined rel8/rel32.
355 : };
356 :
357 : // ============================================================================
358 : // [asmjit::LabelEntry]
359 : // ============================================================================
360 :
361 : //! Label entry.
362 : //!
363 : //! Contains the following properties:
364 : //! * Label id - This is the only thing that is set to the `Label` operand.
365 : //! * Label name - Optional, used mostly to create executables and libraries.
366 : //! * Label type - Type of the label, default `Label::kTypeAnonymous`.
367 : //! * Label parent id - Derived from many assemblers that allow to define a
368 : //! local label that falls under a global label. This allows to define
369 : //! many labels of the same name that have different parent (global) label.
370 : //! * Offset - offset of the label bound by `Assembler`.
371 : //! * Links - single-linked list that contains locations of code that has
372 : //! to be patched when the label gets bound. Every use of unbound label
373 : //! adds one link to `_links` list.
374 : //! * HVal - Hash value of label's name and optionally parentId.
375 : //! * HashNext - Hash-table implementation detail.
376 : class LabelEntry : public ZoneHashNode {
377 : public:
378 : // NOTE: Label id is stored in `_customData`, which is provided by ZoneHashNode
379 : // to fill a padding that a C++ compiler targeting 64-bit CPU will add to align
380 : // the structure to 64-bits.
381 :
382 : //! Get label id.
383 0 : ASMJIT_INLINE uint32_t getId() const noexcept { return _customData; }
384 : //! Set label id (internal, used only by \ref CodeHolder).
385 3888 : ASMJIT_INLINE void _setId(uint32_t id) noexcept { _customData = id; }
386 :
387 : //! Get label type, see \ref Label::Type.
388 : ASMJIT_INLINE uint32_t getType() const noexcept { return _type; }
389 : //! Get label flags, returns 0 at the moment.
390 : ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; }
391 :
392 0 : ASMJIT_INLINE bool hasParent() const noexcept { return _parentId != 0; }
393 : //! Get label's parent id.
394 : ASMJIT_INLINE uint32_t getParentId() const noexcept { return _parentId; }
395 :
396 : //! Get label's section id where it's bound to (or `SectionEntry::kInvalidId` if it's not bound yet).
397 : ASMJIT_INLINE uint32_t getSectionId() const noexcept { return _sectionId; }
398 :
399 : //! Get if the label has name.
400 : ASMJIT_INLINE bool hasName() const noexcept { return !_name.isEmpty(); }
401 :
402 : //! Get the label's name.
403 : //!
404 : //! NOTE: Local labels will return their local name without their parent
405 : //! part, for example ".L1".
406 : ASMJIT_INLINE const char* getName() const noexcept { return _name.getData(); }
407 :
408 : //! Get length of label's name.
409 : //!
410 : //! NOTE: Label name is always null terminated, so you can use `strlen()` to
411 : //! get it, however, it's also cached in `LabelEntry`, so if you want to know
412 : //! the length the easiest way is to use `LabelEntry::getNameLength()`.
413 : ASMJIT_INLINE size_t getNameLength() const noexcept { return _name.getLength(); }
414 :
415 : //! Get if the label is bound.
416 3888 : ASMJIT_INLINE bool isBound() const noexcept { return _sectionId != SectionEntry::kInvalidId; }
417 : //! Get the label offset (only useful if the label is bound).
418 0 : ASMJIT_INLINE intptr_t getOffset() const noexcept { return _offset; }
419 :
420 : //! Get the hash-value of label's name and its parent label (if any).
421 : //!
422 : //! Label hash is calculated as `HASH(Name) ^ ParentId`. The hash function
423 : //! is implemented in `Utils::hashString()` and `Utils::hashRound()`.
424 : ASMJIT_INLINE uint32_t getHVal() const noexcept { return _hVal; }
425 :
426 : // ------------------------------------------------------------------------
427 : // [Members]
428 : // ------------------------------------------------------------------------
429 :
430 : // Let's round the size of `LabelEntry` to 64 bytes (as ZoneHeap has 32
431 : // bytes granularity anyway). This gives `_name` the remaining space, which
432 : // is roughly 16 bytes on 64-bit and 28 bytes on 32-bit architectures.
433 : enum { kNameBytes = 64 - (sizeof(ZoneHashNode) + 16 + sizeof(intptr_t) + sizeof(LabelLink*)) };
434 :
435 : uint8_t _type; //!< Label type, see Label::Type.
436 : uint8_t _flags; //!< Must be zero.
437 : uint16_t _reserved16; //!< Reserved.
438 : uint32_t _parentId; //!< Label parent id or zero.
439 : uint32_t _sectionId; //!< Section id or `SectionEntry::kInvalidId`.
440 : uint32_t _reserved32; //!< Reserved.
441 : intptr_t _offset; //!< Label offset.
442 : LabelLink* _links; //!< Label links.
443 : SmallString<kNameBytes> _name; //!< Label name.
444 : };
445 :
446 : // ============================================================================
447 : // [asmjit::RelocEntry]
448 : // ============================================================================
449 :
450 : //! Relocation entry.
451 : struct RelocEntry {
452 : ASMJIT_ENUM(Id) {
453 : kInvalidId = 0xFFFFFFFFU //!< Invalid relocation id.
454 : };
455 :
456 : //! Relocation type.
457 : ASMJIT_ENUM(Type) {
458 : kTypeNone = 0, //!< Deleted entry (no relocation).
459 : kTypeAbsToAbs = 1, //!< Relocate absolute to absolute.
460 : kTypeRelToAbs = 2, //!< Relocate relative to absolute.
461 : kTypeAbsToRel = 3, //!< Relocate absolute to relative.
462 : kTypeTrampoline = 4 //!< Relocate absolute to relative or use trampoline.
463 : };
464 :
465 : // ------------------------------------------------------------------------
466 : // [Accessors]
467 : // ------------------------------------------------------------------------
468 :
469 0 : ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
470 :
471 0 : ASMJIT_INLINE uint32_t getType() const noexcept { return _type; }
472 0 : ASMJIT_INLINE uint32_t getSize() const noexcept { return _size; }
473 :
474 : ASMJIT_INLINE uint32_t getSourceSectionId() const noexcept { return _sourceSectionId; }
475 : ASMJIT_INLINE uint32_t getTargetSectionId() const noexcept { return _targetSectionId; }
476 :
477 0 : ASMJIT_INLINE uint64_t getSourceOffset() const noexcept { return _sourceOffset; }
478 0 : ASMJIT_INLINE uint64_t getData() const noexcept { return _data; }
479 :
480 : // ------------------------------------------------------------------------
481 : // [Members]
482 : // ------------------------------------------------------------------------
483 :
484 : uint32_t _id; //!< Relocation id.
485 : uint8_t _type; //!< Type of the relocation.
486 : uint8_t _size; //!< Size of the relocation (1, 2, 4 or 8 bytes).
487 : uint8_t _reserved[2]; //!< Reserved.
488 : uint32_t _sourceSectionId; //!< Source section id.
489 : uint32_t _targetSectionId; //!< Destination section id.
490 : uint64_t _sourceOffset; //!< Source offset (relative to start of the section).
491 : uint64_t _data; //!< Relocation data (target offset, target address, etc).
492 : };
493 :
494 : // ============================================================================
495 : // [asmjit::CodeHolder]
496 : // ============================================================================
497 :
498 : //! Contains basic information about the target architecture plus its settings,
499 : //! and holds code & data (including sections, labels, and relocation information).
500 : //! CodeHolder can store both binary and intermediate representation of assembly,
501 : //! which can be generated by \ref Assembler and/or \ref CodeBuilder.
502 : //!
503 : //! NOTE: CodeHolder has ability to attach an \ref ErrorHandler, however, this
504 : //! error handler is not triggered by CodeHolder itself, it's only used by the
505 : //! attached code generators.
506 : class CodeHolder {
507 : public:
508 : ASMJIT_NONCOPYABLE(CodeHolder)
509 :
510 : // --------------------------------------------------------------------------
511 : // [Construction / Destruction]
512 : // --------------------------------------------------------------------------
513 :
514 : //! Create an uninitialized CodeHolder (you must init() it before it can be used).
515 : ASMJIT_API CodeHolder() noexcept;
516 : //! Destroy the CodeHolder.
517 : ASMJIT_API ~CodeHolder() noexcept;
518 :
519 : // --------------------------------------------------------------------------
520 : // [Init / Reset]
521 : // --------------------------------------------------------------------------
522 :
523 : ASMJIT_INLINE bool isInitialized() const noexcept { return _codeInfo.isInitialized(); }
524 :
525 : //! Initialize to CodeHolder to hold code described by `codeInfo`.
526 : ASMJIT_API Error init(const CodeInfo& info) noexcept;
527 : //! Detach all code-generators attached and reset the \ref CodeHolder.
528 : ASMJIT_API void reset(bool releaseMemory = false) noexcept;
529 :
530 : // --------------------------------------------------------------------------
531 : // [Attach / Detach]
532 : // --------------------------------------------------------------------------
533 :
534 : //! Attach a \ref CodeEmitter to this \ref CodeHolder.
535 : ASMJIT_API Error attach(CodeEmitter* emitter) noexcept;
536 : //! Detach a \ref CodeEmitter from this \ref CodeHolder.
537 : ASMJIT_API Error detach(CodeEmitter* emitter) noexcept;
538 :
539 : // --------------------------------------------------------------------------
540 : // [Sync]
541 : // --------------------------------------------------------------------------
542 :
543 : //! Synchronize all states of all `CodeEmitter`s associated with the CodeHolder.
544 : //! This is required as some code generators don't sync every time they do
545 : //! something - for example \ref Assembler generally syncs when it needs to
546 : //! reallocate the \ref CodeBuffer, but not each time it encodes instruction
547 : //! or directive.
548 : ASMJIT_API void sync() noexcept;
549 :
550 : // --------------------------------------------------------------------------
551 : // [Code-Information]
552 : // --------------------------------------------------------------------------
553 :
554 : //! Get code/target information, see \ref CodeInfo.
555 : ASMJIT_INLINE const CodeInfo& getCodeInfo() const noexcept { return _codeInfo; }
556 : //! Get architecture information, see \ref ArchInfo.
557 : ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _codeInfo.getArchInfo(); }
558 :
559 : //! Get the target's architecture type.
560 : ASMJIT_INLINE uint32_t getArchType() const noexcept { return getArchInfo().getType(); }
561 : //! Get the target's architecture sub-type.
562 : ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return getArchInfo().getSubType(); }
563 :
564 : //! Get if a static base-address is set.
565 : ASMJIT_INLINE bool hasBaseAddress() const noexcept { return _codeInfo.hasBaseAddress(); }
566 : //! Get a static base-address (uint64_t).
567 : ASMJIT_INLINE uint64_t getBaseAddress() const noexcept { return _codeInfo.getBaseAddress(); }
568 :
569 : // --------------------------------------------------------------------------
570 : // [Global Information]
571 : // --------------------------------------------------------------------------
572 :
573 : //! Get global hints, internally propagated to all `CodeEmitter`s attached.
574 3888 : ASMJIT_INLINE uint32_t getGlobalHints() const noexcept { return _globalHints; }
575 : //! Get global options, internally propagated to all `CodeEmitter`s attached.
576 3888 : ASMJIT_INLINE uint32_t getGlobalOptions() const noexcept { return _globalOptions; }
577 :
578 : // --------------------------------------------------------------------------
579 : // [Result Information]
580 : // --------------------------------------------------------------------------
581 :
582 : //! Get the size code & data of all sections.
583 : ASMJIT_API size_t getCodeSize() const noexcept;
584 :
585 : //! Get size of all possible trampolines.
586 : //!
587 : //! Trampolines are needed to successfully generate relative jumps to absolute
588 : //! addresses. This value is only non-zero if jmp of call instructions were
589 : //! used with immediate operand (this means jumping or calling an absolute
590 : //! address directly).
591 3888 : ASMJIT_INLINE size_t getTrampolinesSize() const noexcept { return _trampolinesSize; }
592 :
593 : // --------------------------------------------------------------------------
594 : // [Logging & Error Handling]
595 : // --------------------------------------------------------------------------
596 :
597 : #if !defined(ASMJIT_DISABLE_LOGGING)
598 : //! Get if a logger attached.
599 : ASMJIT_INLINE bool hasLogger() const noexcept { return _logger != nullptr; }
600 : //! Get the attached logger.
601 1944 : ASMJIT_INLINE Logger* getLogger() const noexcept { return _logger; }
602 : //! Attach a `logger` to CodeHolder and propagate it to all attached `CodeEmitter`s.
603 : ASMJIT_API void setLogger(Logger* logger) noexcept;
604 : //! Reset the logger (does nothing if not attached).
605 : ASMJIT_INLINE void resetLogger() noexcept { setLogger(nullptr); }
606 : #endif // !ASMJIT_DISABLE_LOGGING
607 :
608 : //! Get if error-handler is attached.
609 : ASMJIT_INLINE bool hasErrorHandler() const noexcept { return _errorHandler != nullptr; }
610 : //! Get the error-handler.
611 : ASMJIT_INLINE ErrorHandler* getErrorHandler() const noexcept { return _errorHandler; }
612 : //! Set the error handler, will affect all attached `CodeEmitter`s.
613 : ASMJIT_API Error setErrorHandler(ErrorHandler* handler) noexcept;
614 : //! Reset the error handler (does nothing if not attached).
615 : ASMJIT_INLINE void resetErrorHandler() noexcept { setErrorHandler(nullptr); }
616 :
617 : // --------------------------------------------------------------------------
618 : // [Sections]
619 : // --------------------------------------------------------------------------
620 :
621 : //! Get array of `SectionEntry*` records.
622 : ASMJIT_INLINE const ZoneVector<SectionEntry*>& getSections() const noexcept { return _sections; }
623 :
624 : //! Get a section entry of the given index.
625 : ASMJIT_INLINE SectionEntry* getSectionEntry(size_t index) const noexcept { return _sections[index]; }
626 :
627 : ASMJIT_API Error growBuffer(CodeBuffer* cb, size_t n) noexcept;
628 : ASMJIT_API Error reserveBuffer(CodeBuffer* cb, size_t n) noexcept;
629 :
630 : // --------------------------------------------------------------------------
631 : // [Labels & Symbols]
632 : // --------------------------------------------------------------------------
633 :
634 : //! Create a new anonymous label and return its id in `idOut`.
635 : //!
636 : //! Returns `Error`, does not report error to \ref ErrorHandler.
637 : ASMJIT_API Error newLabelId(uint32_t& idOut) noexcept;
638 :
639 : //! Create a new named label label-type `type`.
640 : //!
641 : //! Returns `Error`, does not report error to \ref ErrorHandler.
642 : ASMJIT_API Error newNamedLabelId(uint32_t& idOut, const char* name, size_t nameLength, uint32_t type, uint32_t parentId) noexcept;
643 :
644 : //! Get a label id by name.
645 : ASMJIT_API uint32_t getLabelIdByName(const char* name, size_t nameLength = Globals::kInvalidIndex, uint32_t parentId = 0) noexcept;
646 :
647 : //! Create a new label-link used to store information about yet unbound labels.
648 : //!
649 : //! Returns `null` if the allocation failed.
650 : ASMJIT_API LabelLink* newLabelLink(LabelEntry* le, uint32_t sectionId, size_t offset, intptr_t rel) noexcept;
651 :
652 : //! Get array of `LabelEntry*` records.
653 : ASMJIT_INLINE const ZoneVector<LabelEntry*>& getLabelEntries() const noexcept { return _labels; }
654 :
655 : //! Get number of labels created.
656 : ASMJIT_INLINE size_t getLabelsCount() const noexcept { return _labels.getLength(); }
657 :
658 : //! Get number of label references, which are unresolved at the moment.
659 : ASMJIT_INLINE size_t getUnresolvedLabelsCount() const noexcept { return _unresolvedLabelsCount; }
660 :
661 : //! Get if the `label` is valid (i.e. created by `newLabelId()`).
662 : ASMJIT_INLINE bool isLabelValid(const Label& label) const noexcept {
663 : return isLabelValid(label.getId());
664 : }
665 : //! Get if the label having `id` is valid (i.e. created by `newLabelId()`).
666 : ASMJIT_INLINE bool isLabelValid(uint32_t labelId) const noexcept {
667 : size_t index = Operand::unpackId(labelId);
668 : return index < _labels.getLength();
669 : }
670 :
671 : //! Get if the `label` is already bound.
672 : //!
673 : //! Returns `false` if the `label` is not valid.
674 : ASMJIT_INLINE bool isLabelBound(const Label& label) const noexcept {
675 : return isLabelBound(label.getId());
676 : }
677 : //! \overload
678 : ASMJIT_INLINE bool isLabelBound(uint32_t id) const noexcept {
679 : size_t index = Operand::unpackId(id);
680 : return index < _labels.getLength() && _labels[index]->isBound();
681 : }
682 :
683 : //! Get a `label` offset or -1 if the label is not yet bound.
684 : ASMJIT_INLINE intptr_t getLabelOffset(const Label& label) const noexcept {
685 : return getLabelOffset(label.getId());
686 : }
687 : //! \overload
688 : ASMJIT_INLINE intptr_t getLabelOffset(uint32_t id) const noexcept {
689 : ASMJIT_ASSERT(isLabelValid(id));
690 : return _labels[Operand::unpackId(id)]->getOffset();
691 : }
692 :
693 : //! Get information about the given `label`.
694 : ASMJIT_INLINE LabelEntry* getLabelEntry(const Label& label) const noexcept {
695 : return getLabelEntry(label.getId());
696 : }
697 : //! Get information about a label having the given `id`.
698 : ASMJIT_INLINE LabelEntry* getLabelEntry(uint32_t id) const noexcept {
699 3888 : size_t index = static_cast<size_t>(Operand::unpackId(id));
700 3888 : return index < _labels.getLength() ? _labels[index] : static_cast<LabelEntry*>(nullptr);
701 : }
702 :
703 : // --------------------------------------------------------------------------
704 : // [Relocations]
705 : // --------------------------------------------------------------------------
706 :
707 : //! Create a new relocation entry of type `type` and size `size`.
708 : //!
709 : //! Additional fields can be set after the relocation entry was created.
710 : ASMJIT_API Error newRelocEntry(RelocEntry** dst, uint32_t type, uint32_t size) noexcept;
711 :
712 : //! Get if the code contains relocations.
713 : ASMJIT_INLINE bool hasRelocations() const noexcept { return !_relocations.isEmpty(); }
714 : //! Get array of `RelocEntry*` records.
715 : ASMJIT_INLINE const ZoneVector<RelocEntry*>& getRelocEntries() const noexcept { return _relocations; }
716 :
717 : ASMJIT_INLINE RelocEntry* getRelocEntry(uint32_t id) const noexcept { return _relocations[id]; }
718 :
719 : //! Relocate the code to `baseAddress` and copy it to `dst`.
720 : //!
721 : //! \param dst Contains the location where the relocated code should be
722 : //! copied. The pointer can be address returned by virtual memory allocator
723 : //! or any other address that has sufficient space.
724 : //!
725 : //! \param baseAddress Base address used for relocation. `JitRuntime` always
726 : //! sets the `baseAddress` to be the same as `dst`.
727 : //!
728 : //! \return The number bytes actually used. If the code emitter reserved
729 : //! space for possible trampolines, but didn't use it, the number of bytes
730 : //! used can actually be less than the expected worst case. Virtual memory
731 : //! allocator can shrink the memory it allocated initially.
732 : //!
733 : //! A given buffer will be overwritten, to get the number of bytes required,
734 : //! use `getCodeSize()`.
735 : ASMJIT_API size_t relocate(void* dst, uint64_t baseAddress = Globals::kNoBaseAddress) const noexcept;
736 :
737 : // --------------------------------------------------------------------------
738 : // [Members]
739 : // --------------------------------------------------------------------------
740 :
741 : CodeInfo _codeInfo; //!< Basic information about the code (architecture and other info).
742 :
743 : uint32_t _globalHints; //!< Global hints, propagated to all `CodeEmitter`s.
744 : uint32_t _globalOptions; //!< Global options, propagated to all `CodeEmitter`s.
745 :
746 : CodeEmitter* _emitters; //!< Linked-list of all attached `CodeEmitter`s.
747 : Assembler* _cgAsm; //!< Attached \ref Assembler (only one at a time).
748 :
749 : Logger* _logger; //!< Attached \ref Logger, used by all consumers.
750 : ErrorHandler* _errorHandler; //!< Attached \ref ErrorHandler.
751 :
752 : uint32_t _unresolvedLabelsCount; //!< Count of label references which were not resolved.
753 : uint32_t _trampolinesSize; //!< Size of all possible trampolines.
754 :
755 : Zone _baseZone; //!< Base zone (used to allocate core structures).
756 : Zone _dataZone; //!< Data zone (used to allocate extra data like label names).
757 : ZoneHeap _baseHeap; //!< Zone allocator, used to manage internal containers.
758 :
759 : ZoneVector<SectionEntry*> _sections; //!< Section entries.
760 : ZoneVector<LabelEntry*> _labels; //!< Label entries (each label is stored here).
761 : ZoneVector<RelocEntry*> _relocations; //!< Relocation entries.
762 : ZoneHash<LabelEntry> _namedLabels; //!< Label name -> LabelEntry (only named labels).
763 : };
764 :
765 : //! \}
766 :
767 : } // asmjit namespace
768 : } // namespace PLMD
769 :
770 : // [Api-End]
771 : #include "./asmjit_apiend.h"
772 :
773 : // [Guard]
774 : #endif // _ASMJIT_BASE_CODEHOLDER_H
775 : #pragma GCC diagnostic pop
776 : #endif // __PLUMED_HAS_ASMJIT
777 : #endif
|