Line data Source code
1 : #ifdef __PLUMED_HAS_ASMJIT
2 : // This file is part of AsmJit project <https://asmjit.com>
3 : //
4 : // See asmjit.h or LICENSE.md for license and copyright information
5 : // SPDX-License-Identifier: Zlib
6 :
7 : #ifndef ASMJIT_CORE_CODEHOLDER_H_INCLUDED
8 : #define ASMJIT_CORE_CODEHOLDER_H_INCLUDED
9 :
10 : #include "archtraits.h"
11 : #include "codebuffer.h"
12 : #include "errorhandler.h"
13 : #include "operand.h"
14 : #include "moved_string.h"
15 : #include "support.h"
16 : #include "target.h"
17 : #include "zone.h"
18 : #include "zonehash.h"
19 : #include "zonestring.h"
20 : #include "zonetree.h"
21 : #include "zonevector.h"
22 :
23 : ASMJIT_BEGIN_NAMESPACE
24 :
25 : //! \addtogroup asmjit_core
26 : //! \{
27 :
28 : class BaseEmitter;
29 : class CodeHolder;
30 : class LabelEntry;
31 : class Logger;
32 :
33 : //! Operator type that can be used within an \ref Expression.
34 : enum class ExpressionOpType : uint8_t {
35 : //! Addition.
36 : kAdd = 0,
37 : //! Subtraction.
38 : kSub = 1,
39 : //! Multiplication
40 : kMul = 2,
41 : //! Logical left shift.
42 : kSll = 3,
43 : //! Logical right shift.
44 : kSrl = 4,
45 : //! Arithmetic right shift.
46 : kSra = 5
47 : };
48 :
49 : //! Value tyoe that can be used within an \ref Expression.
50 : enum class ExpressionValueType : uint8_t {
51 : //! No value or invalid.
52 : kNone = 0,
53 : //! Value is 64-bit unsigned integer (constant).
54 : kConstant = 1,
55 : //! Value is \ref LabelEntry, which references a \ref Label.
56 : kLabel = 2,
57 : //! Value is \ref Expression
58 : kExpression = 3
59 : };
60 :
61 : //! Expression node that can reference constants, labels, and another expressions.
62 : struct Expression {
63 : //! Expression value.
64 : union Value {
65 : //! Constant.
66 : uint64_t constant;
67 : //! Pointer to another expression.
68 : Expression* expression;
69 : //! Pointer to \ref LabelEntry.
70 : LabelEntry* label;
71 : };
72 :
73 : //! \name Members
74 : //! \{
75 :
76 : //! Operation type.
77 : ExpressionOpType opType;
78 : //! Value types of \ref value.
79 : ExpressionValueType valueType[2];
80 : //! Reserved for future use, should be initialized to zero.
81 : uint8_t reserved[5];
82 : //! Expression left and right values.
83 : Value value[2];
84 :
85 : //! \}
86 :
87 : //! \name Accessors
88 : //! \{
89 :
90 : //! Resets the whole expression.
91 : //!
92 : //! Changes both values to \ref ExpressionValueType::kNone.
93 0 : inline void reset() noexcept { memset(this, 0, sizeof(*this)); }
94 :
95 : //! Sets the value type at `index` to \ref ExpressionValueType::kConstant and its content to `constant`.
96 : inline void setValueAsConstant(size_t index, uint64_t constant) noexcept {
97 : valueType[index] = ExpressionValueType::kConstant;
98 : value[index].constant = constant;
99 : }
100 :
101 : //! Sets the value type at `index` to \ref ExpressionValueType::kLabel and its content to `labelEntry`.
102 : inline void setValueAsLabel(size_t index, LabelEntry* labelEntry) noexcept {
103 0 : valueType[index] = ExpressionValueType::kLabel;
104 0 : value[index].label = labelEntry;
105 : }
106 :
107 : //! Sets the value type at `index` to \ref ExpressionValueType::kExpression and its content to `expression`.
108 : inline void setValueAsExpression(size_t index, Expression* expression) noexcept {
109 : valueType[index] = ExpressionValueType::kExpression;
110 : value[index].expression = expression;
111 : }
112 :
113 : //! \}
114 : };
115 :
116 : //! Section flags, used by \ref Section.
117 : enum class SectionFlags : uint32_t {
118 : //! No flags.
119 : kNone = 0,
120 : //! Executable (.text sections).
121 : kExecutable = 0x00000001u,
122 : //! Read-only (.text and .data sections).
123 : kReadOnly = 0x00000002u,
124 : //! Zero initialized by the loader (BSS).
125 : kZeroInitialized = 0x00000004u,
126 : //! Info / comment flag.
127 : kComment = 0x00000008u,
128 : //! Section created implicitly, can be deleted by \ref Target.
129 : kImplicit = 0x80000000u
130 : };
131 : ASMJIT_DEFINE_ENUM_FLAGS(SectionFlags)
132 :
133 : //! Flags that can be used with \ref CodeHolder::copySectionData() and \ref CodeHolder::copyFlattenedData().
134 : enum class CopySectionFlags : uint32_t {
135 : //! No flags.
136 : kNone = 0,
137 :
138 : //! If virtual size of a section is greater than the size of its \ref CodeBuffer then all bytes between the buffer
139 : //! size and virtual size will be zeroed. If this option is not set then those bytes would be left as is, which
140 : //! means that if the user didn't initialize them they would have a previous content, which may be unwanted.
141 : kPadSectionBuffer = 0x00000001u,
142 :
143 : //! Clears the target buffer if the flattened data is less than the destination size. This option works
144 : //! only with \ref CodeHolder::copyFlattenedData() as it processes multiple sections. It is ignored by
145 : //! \ref CodeHolder::copySectionData().
146 : kPadTargetBuffer = 0x00000002u
147 : };
148 : ASMJIT_DEFINE_ENUM_FLAGS(CopySectionFlags)
149 :
150 : //! Section entry.
151 : class Section {
152 : public:
153 : //! \name Members
154 : //! \{
155 :
156 : //! Section id.
157 : uint32_t _id;
158 : //! Section flags.
159 : SectionFlags _flags;
160 : //! Section alignment requirements (0 if no requirements).
161 : uint32_t _alignment;
162 : //! Order (lower value means higher priority).
163 : int32_t _order;
164 : //! Offset of this section from base-address.
165 : uint64_t _offset;
166 : //! Virtual size of the section (zero initialized sections).
167 : uint64_t _virtualSize;
168 : //! Section name (max 35 characters, PE allows max 8).
169 : FixedString<Globals::kMaxSectionNameSize + 1> _name;
170 : //! Code or data buffer.
171 : CodeBuffer _buffer;
172 :
173 : //! \}
174 :
175 : //! \name Accessors
176 : //! \{
177 :
178 : //! Returns the section id.
179 82476 : inline uint32_t id() const noexcept { return _id; }
180 : //! Returns the section name, as a null terminated string.
181 0 : inline const char* name() const noexcept { return _name.str; }
182 :
183 : //! Returns the section data.
184 : inline uint8_t* data() noexcept { return _buffer.data(); }
185 : //! \overload
186 : inline const uint8_t* data() const noexcept { return _buffer.data(); }
187 :
188 : //! Returns the section flags.
189 : inline SectionFlags flags() const noexcept { return _flags; }
190 : //! Tests whether the section has the given `flag`.
191 : inline bool hasFlag(SectionFlags flag) const noexcept { return Support::test(_flags, flag); }
192 : //! Adds `flags` to the section flags.
193 : inline void addFlags(SectionFlags flags) noexcept { _flags |= flags; }
194 : //! Removes `flags` from the section flags.
195 : inline void clearFlags(SectionFlags flags) noexcept { _flags &= ~flags; }
196 :
197 : //! Returns the minimum section alignment
198 109968 : inline uint32_t alignment() const noexcept { return _alignment; }
199 : //! Sets the minimum section alignment
200 : inline void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; }
201 :
202 : //! Returns the section order, which has a higher priority than section id.
203 0 : inline int32_t order() const noexcept { return _order; }
204 :
205 : //! Returns the section offset, relative to base.
206 27492 : inline uint64_t offset() const noexcept { return _offset; }
207 : //! Set the section offset.
208 : inline void setOffset(uint64_t offset) noexcept { _offset = offset; }
209 :
210 : //! Returns the virtual size of the section.
211 : //!
212 : //! Virtual size is initially zero and is never changed by AsmJit. It's normal if virtual size is smaller than
213 : //! size returned by `bufferSize()` as the buffer stores real data emitted by assemblers or appended by users.
214 : //!
215 : //! Use `realSize()` to get the real and final size of this section.
216 137460 : inline uint64_t virtualSize() const noexcept { return _virtualSize; }
217 : //! Sets the virtual size of the section.
218 : inline void setVirtualSize(uint64_t virtualSize) noexcept { _virtualSize = virtualSize; }
219 :
220 : //! Returns the buffer size of the section.
221 : inline size_t bufferSize() const noexcept { return _buffer.size(); }
222 : //! Returns the real size of the section calculated from virtual and buffer sizes.
223 : inline uint64_t realSize() const noexcept { return Support::max<uint64_t>(virtualSize(), bufferSize()); }
224 :
225 : //! Returns the `CodeBuffer` used by this section.
226 : inline CodeBuffer& buffer() noexcept { return _buffer; }
227 : //! Returns the `CodeBuffer` used by this section (const).
228 : inline const CodeBuffer& buffer() const noexcept { return _buffer; }
229 :
230 : //! \}
231 : };
232 :
233 : //! Entry in an address table.
234 : class AddressTableEntry : public ZoneTreeNodeT<AddressTableEntry> {
235 : public:
236 : ASMJIT_NONCOPYABLE(AddressTableEntry)
237 :
238 : //! \name Members
239 : //! \{
240 :
241 : //! Address.
242 : uint64_t _address;
243 : //! Slot.
244 : uint32_t _slot;
245 :
246 : //! \}
247 :
248 : //! \name Construction & Destruction
249 : //! \{
250 :
251 : inline explicit AddressTableEntry(uint64_t address) noexcept
252 0 : : _address(address),
253 0 : _slot(0xFFFFFFFFu) {}
254 :
255 : //! \}
256 :
257 : //! \name Accessors
258 : //! \{
259 :
260 : inline uint64_t address() const noexcept { return _address; }
261 0 : inline uint32_t slot() const noexcept { return _slot; }
262 :
263 0 : inline bool hasAssignedSlot() const noexcept { return _slot != 0xFFFFFFFFu; }
264 :
265 0 : inline bool operator<(const AddressTableEntry& other) const noexcept { return _address < other._address; }
266 0 : inline bool operator>(const AddressTableEntry& other) const noexcept { return _address > other._address; }
267 :
268 0 : inline bool operator<(uint64_t queryAddress) const noexcept { return _address < queryAddress; }
269 0 : inline bool operator>(uint64_t queryAddress) const noexcept { return _address > queryAddress; }
270 :
271 : //! \}
272 : };
273 :
274 : //! Offset format type, used by \ref OffsetFormat.
275 : enum class OffsetType : uint8_t {
276 : //! A value having `_immBitCount` bits and shifted by `_immBitShift`.
277 : //!
278 : //! This offset type is sufficient for many targets that store offset as a continuous set bits within an
279 : //! instruction word / sequence of bytes.
280 : kSignedOffset,
281 :
282 : //! An unsigned value having `_immBitCount` bits and shifted by `_immBitShift`.
283 : kUnsignedOffset,
284 :
285 : // AArch64 Specific Offset Formats
286 : // -------------------------------
287 :
288 : //! AARCH64 ADR format of `[.|immlo:2|.....|immhi:19|.....]`.
289 : kAArch64_ADR,
290 :
291 : //! AARCH64 ADRP format of `[.|immlo:2|.....|immhi:19|.....]` (4kB pages).
292 : kAArch64_ADRP,
293 :
294 : //! Maximum value of `OffsetFormatType`.
295 : kMaxValue = kAArch64_ADRP
296 : };
297 :
298 : //! Provides information about formatting offsets, absolute addresses, or their parts. Offset format is used by both
299 : //! \ref RelocEntry and \ref LabelLink. The illustration below describes the relation of region size and offset size.
300 : //! Region size is the size of the whole unit whereas offset size is the size of the unit that will be patched.
301 : //!
302 : //! ```
303 : //! +-> Code buffer | The subject of the relocation (region) |
304 : //! | | (Word-Offset) (Word-Size) |
305 : //! |xxxxxxxxxxxxxxx|................|*PATCHED*|................|xxxxxxxxxxxx->
306 : //! | |
307 : //! [Word Offset points here]----+ +--- [WordOffset + WordSize]
308 : //! ```
309 : //!
310 : //! Once the offset word has been located it can be patched like this:
311 : //!
312 : //! ```
313 : //! |ImmDiscardLSB (discard LSB bits).
314 : //! |..
315 : //! [0000000000000iiiiiiiiiiiiiiiiiDD] - Offset value (32-bit)
316 : //! [000000000000000iiiiiiiiiiiiiiiii] - Offset value after discard LSB.
317 : //! [00000000000iiiiiiiiiiiiiiiii0000] - Offset value shifted by ImmBitShift.
318 : //! [xxxxxxxxxxxiiiiiiiiiiiiiiiiixxxx] - Patched word (32-bit)
319 : //! |...............|
320 : //! (ImmBitCount) +- ImmBitShift
321 : //! ```
322 : struct OffsetFormat {
323 : //! \name Members
324 : //! \{
325 :
326 : //! Type of the offset.
327 : OffsetType _type;
328 : //! Encoding flags.
329 : uint8_t _flags;
330 : //! Size of the region (in bytes) containing the offset value, if the offset value is part of an instruction,
331 : //! otherwise it would be the same as `_valueSize`.
332 : uint8_t _regionSize;
333 : //! Size of the offset value, in bytes (1, 2, 4, or 8).
334 : uint8_t _valueSize;
335 : //! Offset of the offset value, in bytes, relative to the start of the region or data. Value offset would be
336 : //! zero if both region size and value size are equal.
337 : uint8_t _valueOffset;
338 : //! Size of the offset immediate value in bits.
339 : uint8_t _immBitCount;
340 : //! Shift of the offset immediate value in bits in the target word.
341 : uint8_t _immBitShift;
342 : //! Number of least significant bits to discard before writing the immediate to the destination. All discarded
343 : //! bits must be zero otherwise the value is invalid.
344 : uint8_t _immDiscardLsb;
345 :
346 : //! \}
347 :
348 : //! \name Accessors
349 : //! \{
350 :
351 : //! Returns the type of the offset.
352 0 : inline OffsetType type() const noexcept { return _type; }
353 :
354 : //! Returns flags.
355 : inline uint32_t flags() const noexcept { return _flags; }
356 :
357 : //! Returns the size of the region/instruction where the offset is encoded.
358 0 : inline uint32_t regionSize() const noexcept { return _regionSize; }
359 :
360 : //! Returns the offset of the word relative to the start of the region where the offset is.
361 0 : inline uint32_t valueOffset() const noexcept { return _valueOffset; }
362 :
363 : //! Returns the size of the data-type (word) that contains the offset, in bytes.
364 0 : inline uint32_t valueSize() const noexcept { return _valueSize; }
365 : //! Returns the count of bits of the offset value in the data it's stored in.
366 0 : inline uint32_t immBitCount() const noexcept { return _immBitCount; }
367 : //! Returns the bit-shift of the offset value in the data it's stored in.
368 0 : inline uint32_t immBitShift() const noexcept { return _immBitShift; }
369 : //! Returns the number of least significant bits of the offset value, that must be zero and that are not part of
370 : //! the encoded data.
371 0 : inline uint32_t immDiscardLsb() const noexcept { return _immDiscardLsb; }
372 :
373 : //! Resets this offset format to a simple data value of `dataSize` bytes.
374 : //!
375 : //! The region will be the same size as data and immediate bits would correspond to `dataSize * 8`. There will be
376 : //! no immediate bit shift or discarded bits.
377 : inline void resetToSimpleValue(OffsetType type, size_t valueSize) noexcept {
378 : ASMJIT_ASSERT(valueSize <= 8u);
379 :
380 0 : _type = type;
381 0 : _flags = uint8_t(0);
382 0 : _regionSize = uint8_t(valueSize);
383 0 : _valueSize = uint8_t(valueSize);
384 0 : _valueOffset = uint8_t(0);
385 0 : _immBitCount = uint8_t(valueSize * 8u);
386 0 : _immBitShift = uint8_t(0);
387 0 : _immDiscardLsb = uint8_t(0);
388 : }
389 :
390 : inline void resetToImmValue(OffsetType type, size_t valueSize, uint32_t immBitShift, uint32_t immBitCount, uint32_t immDiscardLsb) noexcept {
391 : ASMJIT_ASSERT(valueSize <= 8u);
392 : ASMJIT_ASSERT(immBitShift < valueSize * 8u);
393 : ASMJIT_ASSERT(immBitCount <= 64u);
394 : ASMJIT_ASSERT(immDiscardLsb <= 64u);
395 :
396 0 : _type = type;
397 0 : _flags = uint8_t(0);
398 0 : _regionSize = uint8_t(valueSize);
399 0 : _valueSize = uint8_t(valueSize);
400 0 : _valueOffset = uint8_t(0);
401 0 : _immBitCount = uint8_t(immBitCount);
402 0 : _immBitShift = uint8_t(immBitShift);
403 0 : _immDiscardLsb = uint8_t(immDiscardLsb);
404 : }
405 :
406 : inline void setRegion(size_t regionSize, size_t valueOffset) noexcept {
407 : _regionSize = uint8_t(regionSize);
408 : _valueOffset = uint8_t(valueOffset);
409 : }
410 :
411 : inline void setLeadingAndTrailingSize(size_t leadingSize, size_t trailingSize) noexcept {
412 0 : _regionSize = uint8_t(leadingSize + trailingSize + _valueSize);
413 0 : _valueOffset = uint8_t(leadingSize);
414 : }
415 :
416 : //! \}
417 : };
418 :
419 : //! Relocation type.
420 : enum class RelocType : uint32_t {
421 : //! None/deleted (no relocation).
422 : kNone = 0,
423 : //! Expression evaluation, `_payload` is pointer to `Expression`.
424 : kExpression = 1,
425 : //! Relocate absolute to absolute.
426 : kAbsToAbs = 2,
427 : //! Relocate relative to absolute.
428 : kRelToAbs = 3,
429 : //! Relocate absolute to relative.
430 : kAbsToRel = 4,
431 : //! Relocate absolute to relative or use trampoline.
432 : kX64AddressEntry = 5
433 : };
434 :
435 : //! Relocation entry.
436 : struct RelocEntry {
437 : //! \name Members
438 : //! \{
439 :
440 : //! Relocation id.
441 : uint32_t _id;
442 : //! Type of the relocation.
443 : RelocType _relocType;
444 : //! Format of the relocated value.
445 : OffsetFormat _format;
446 : //! Source section id.
447 : uint32_t _sourceSectionId;
448 : //! Target section id.
449 : uint32_t _targetSectionId;
450 : //! Source offset (relative to start of the section).
451 : uint64_t _sourceOffset;
452 : //! Payload (target offset, target address, expression, etc).
453 : uint64_t _payload;
454 :
455 : //! \}
456 :
457 : //! \name Accessors
458 : //! \{
459 :
460 0 : inline uint32_t id() const noexcept { return _id; }
461 :
462 0 : inline RelocType relocType() const noexcept { return _relocType; }
463 0 : inline const OffsetFormat& format() const noexcept { return _format; }
464 :
465 0 : inline uint32_t sourceSectionId() const noexcept { return _sourceSectionId; }
466 0 : inline uint32_t targetSectionId() const noexcept { return _targetSectionId; }
467 :
468 0 : inline uint64_t sourceOffset() const noexcept { return _sourceOffset; }
469 0 : inline uint64_t payload() const noexcept { return _payload; }
470 :
471 : Expression* payloadAsExpression() const noexcept {
472 : return reinterpret_cast<Expression*>(uintptr_t(_payload));
473 : }
474 :
475 : //! \}
476 : };
477 :
478 : //! Type of the \ref Label.
479 : enum class LabelType : uint8_t {
480 : //! Anonymous label that can optionally have a name, which is only used for debugging purposes.
481 : kAnonymous = 0,
482 : //! Local label (always has parentId).
483 : kLocal = 1,
484 : //! Global label (never has parentId).
485 : kGlobal = 2,
486 : //! External label (references an external symbol).
487 : kExternal = 3,
488 :
489 : //! Maximum value of `LabelType`.
490 : kMaxValue = kExternal
491 : };
492 :
493 : //! Data structure used to link either unbound labels or cross-section links.
494 : struct LabelLink {
495 : //! Next link (single-linked list).
496 : LabelLink* next;
497 : //! Section id where the label is bound.
498 : uint32_t sectionId;
499 : //! Relocation id or Globals::kInvalidId.
500 : uint32_t relocId;
501 : //! Label offset relative to the start of the section.
502 : size_t offset;
503 : //! Inlined rel8/rel32.
504 : intptr_t rel;
505 : //! Offset format information.
506 : OffsetFormat format;
507 : };
508 :
509 : //! Label entry.
510 : //!
511 : //! Contains the following properties:
512 : //! - Label id - This is the only thing that is set to the `Label` operand.
513 : //! - Label name - Optional, used mostly to create executables and libraries.
514 : //! - Label type - Type of the label, default `LabelType::kAnonymous`.
515 : //! - Label parent id - Derived from many assemblers that allow to define a local label that falls under a global
516 : //! label. This allows to define many labels of the same name that have different parent (global) label.
517 : //! - Offset - offset of the label bound by `Assembler`.
518 : //! - Links - single-linked list that contains locations of code that has to be patched when the label gets bound.
519 : //! Every use of unbound label adds one link to `_links` list.
520 : //! - HVal - Hash value of label's name and optionally parentId.
521 : //! - HashNext - Hash-table implementation detail.
522 : class LabelEntry : public ZoneHashNode {
523 : public:
524 : //! \name Constants
525 : //! \{
526 :
527 : enum : uint32_t {
528 : //! SSO size of \ref _name.
529 : //!
530 : //! \cond INTERNAL
531 : //! Let's round the size of `LabelEntry` to 64 bytes (as `ZoneAllocator` has granularity of 32 bytes anyway). This
532 : //! gives `_name` the remaining space, which is should be 16 bytes on 64-bit and 28 bytes on 32-bit architectures.
533 : //! \endcond
534 : kStaticNameSize = 64 - (sizeof(ZoneHashNode) + 8 + sizeof(Section*) + sizeof(size_t) + sizeof(LabelLink*))
535 : };
536 :
537 : //! \}
538 :
539 : //! \name Members
540 : //! \{
541 :
542 : //! Type of the label.
543 : LabelType _type;
544 : //! Must be zero.
545 : uint8_t _reserved[3];
546 : //! Label parent id or zero.
547 : uint32_t _parentId;
548 : //! Label offset relative to the start of the `_section`.
549 : uint64_t _offset;
550 : //! Section where the label was bound.
551 : Section* _section;
552 : //! Label links.
553 : LabelLink* _links;
554 : //! Label name.
555 : ZoneString<kStaticNameSize> _name;
556 :
557 : //! \}
558 :
559 : //! \name Accessors
560 : //! \{
561 :
562 : // NOTE: Label id is stored in `_customData`, which is provided by ZoneHashNode to fill a padding that a C++
563 : // compiler targeting 64-bit CPU will add to align the structure to 64-bits.
564 :
565 : //! Returns label id.
566 54984 : inline uint32_t id() const noexcept { return _customData; }
567 : //! Sets label id (internal, used only by `CodeHolder`).
568 54984 : inline void _setId(uint32_t id) noexcept { _customData = id; }
569 :
570 : //! Returns label type.
571 0 : inline LabelType type() const noexcept { return _type; }
572 :
573 : //! Tests whether the label has a parent label.
574 0 : inline bool hasParent() const noexcept { return _parentId != Globals::kInvalidId; }
575 : //! Returns label's parent id.
576 0 : inline uint32_t parentId() const noexcept { return _parentId; }
577 :
578 : //! Returns the section where the label was bound.
579 : //!
580 : //! If the label was not yet bound the return value is `nullptr`.
581 0 : inline Section* section() const noexcept { return _section; }
582 :
583 : //! Tests whether the label has name.
584 : inline bool hasName() const noexcept { return !_name.empty(); }
585 :
586 : //! Returns the label's name.
587 : //!
588 : //! \note Local labels will return their local name without their parent part, for example ".L1".
589 : inline const char* name() const noexcept { return _name.data(); }
590 :
591 : //! Returns size of label's name.
592 : //!
593 : //! \note Label name is always null terminated, so you can use `strlen()` to get it, however, it's also cached in
594 : //! `LabelEntry` itself, so if you want to know the size the fastest way is to call `LabelEntry::nameSize()`.
595 : inline uint32_t nameSize() const noexcept { return _name.size(); }
596 :
597 : //! Returns links associated with this label.
598 : inline LabelLink* links() const noexcept { return _links; }
599 :
600 : //! Tests whether the label is bound.
601 54984 : inline bool isBound() const noexcept { return _section != nullptr; }
602 : //! Tests whether the label is bound to a the given `sectionId`.
603 0 : inline bool isBoundTo(Section* section) const noexcept { return _section == section; }
604 :
605 : //! Returns the label offset (only useful if the label is bound).
606 0 : inline uint64_t offset() const noexcept { return _offset; }
607 :
608 : //! Returns the hash-value of label's name and its parent label (if any).
609 : //!
610 : //! Label hash is calculated as `HASH(Name) ^ ParentId`. The hash function is implemented in `Support::hashString()`
611 : //! and `Support::hashRound()`.
612 : inline uint32_t hashCode() const noexcept { return _hashCode; }
613 :
614 : //! \}
615 : };
616 :
617 : //! Holds assembled code and data (including sections, labels, and relocation information).
618 : //!
619 : //! CodeHolder connects emitters with their targets. It provides them interface that can be used to query information
620 : //! about the target environment (architecture, etc...) and API to create labels, sections, relocations, and to write
621 : //! data to a \ref CodeBuffer, which is always part of \ref Section. More than one emitter can be attached to a single
622 : //! CodeHolder instance at a time, which is used in practice
623 : //!
624 : //! CodeHolder provides interface for all emitter types. Assemblers use CodeHolder to write into \ref CodeBuffer, and
625 : //! higher level emitters like Builder and Compiler use CodeHolder to manage labels and sections so higher level code
626 : //! can be serialized to Assembler by \ref BaseEmitter::finalize() and \ref BaseBuilder::serializeTo().
627 : //!
628 : //! In order to use CodeHolder, it must be first initialized by \ref init(). After the CodeHolder has been successfully
629 : //! initialized it can be used to hold assembled code, sections, labels, relocations, and to attach / detach code
630 : //! emitters. After the end of code generation it can be used to query physical locations of labels and to relocate
631 : //! the assembled code into the right address.
632 : //!
633 : //! \note \ref CodeHolder has an ability to attach an \ref ErrorHandler, however, the error handler is not triggered
634 : //! by \ref CodeHolder itself, it's instead propagated to all emitters that attach to it.
635 : class CodeHolder {
636 : public:
637 : ASMJIT_NONCOPYABLE(CodeHolder)
638 :
639 : //! \name Members
640 : //! \{
641 :
642 : //! Environment information.
643 : Environment _environment;
644 : //! Base address or \ref Globals::kNoBaseAddress.
645 : uint64_t _baseAddress;
646 :
647 : //! Attached `Logger`, used by all consumers.
648 : Logger* _logger;
649 : //! Attached `ErrorHandler`.
650 : ErrorHandler* _errorHandler;
651 :
652 : //! Code zone (used to allocate core structures).
653 : Zone _zone;
654 : //! Zone allocator, used to manage internal containers.
655 : ZoneAllocator _allocator;
656 :
657 : //! Attached emitters.
658 : ZoneVector<BaseEmitter*> _emitters;
659 : //! Section entries.
660 : ZoneVector<Section*> _sections;
661 : //! Section entries sorted by section order and then section id.
662 : ZoneVector<Section*> _sectionsByOrder;
663 : //! Label entries.
664 : ZoneVector<LabelEntry*> _labelEntries;
665 : //! Relocation entries.
666 : ZoneVector<RelocEntry*> _relocations;
667 : //! Label name -> LabelEntry (only named labels).
668 : ZoneHash<LabelEntry> _namedLabels;
669 :
670 : //! Count of label links, which are not resolved.
671 : size_t _unresolvedLinkCount;
672 : //! Pointer to an address table section (or null if this section doesn't exist).
673 : Section* _addressTableSection;
674 : //! Address table entries.
675 : ZoneTree<AddressTableEntry> _addressTableEntries;
676 :
677 : //! \}
678 :
679 : //! \name Construction & Destruction
680 : //! \{
681 :
682 : //! Creates an uninitialized CodeHolder (you must init() it before it can be used).
683 : //!
684 : //! An optional `temporary` argument can be used to initialize the first block of \ref Zone that the CodeHolder
685 : //! uses into a temporary memory provided by the user.
686 : ASMJIT_API explicit CodeHolder(const Support::Temporary* temporary = nullptr) noexcept;
687 :
688 : //! \overload
689 : inline explicit CodeHolder(const Support::Temporary& temporary) noexcept
690 : : CodeHolder(&temporary) {}
691 :
692 : //! Destroys the CodeHolder and frees all resources it has allocated.
693 : ASMJIT_API ~CodeHolder() noexcept;
694 :
695 : //! Tests whether the `CodeHolder` has been initialized.
696 : //!
697 : //! Emitters can be only attached to initialized `CodeHolder` instances.
698 : inline bool isInitialized() const noexcept { return _environment.isInitialized(); }
699 :
700 : //! Initializes CodeHolder to hold code described by the given `environment` and `baseAddress`.
701 : ASMJIT_API Error init(const Environment& environment, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept;
702 : //! Detaches all code-generators attached and resets the `CodeHolder`.
703 : ASMJIT_API void reset(ResetPolicy resetPolicy = ResetPolicy::kSoft) noexcept;
704 :
705 : //! \}
706 :
707 : //! \name Attach & Detach
708 : //! \{
709 :
710 : //! Attaches an emitter to this `CodeHolder`.
711 : ASMJIT_API Error attach(BaseEmitter* emitter) noexcept;
712 : //! Detaches an emitter from this `CodeHolder`.
713 : ASMJIT_API Error detach(BaseEmitter* emitter) noexcept;
714 :
715 : //! \}
716 :
717 : //! \name Allocators
718 : //! \{
719 :
720 : //! Returns the allocator that the `CodeHolder` uses.
721 : //!
722 : //! \note This should be only used for AsmJit's purposes. Code holder uses arena allocator to allocate everything,
723 : //! so anything allocated through this allocator will be invalidated by \ref CodeHolder::reset() or by CodeHolder's
724 : //! destructor.
725 27492 : inline ZoneAllocator* allocator() const noexcept { return const_cast<ZoneAllocator*>(&_allocator); }
726 :
727 : //! \}
728 :
729 : //! \name Code & Architecture
730 : //! \{
731 :
732 : //! Returns the target environment information.
733 : inline const Environment& environment() const noexcept { return _environment; }
734 :
735 : //! Returns the target architecture.
736 : inline Arch arch() const noexcept { return environment().arch(); }
737 : //! Returns the target sub-architecture.
738 : inline SubArch subArch() const noexcept { return environment().subArch(); }
739 :
740 : //! Tests whether a static base-address is set.
741 : inline bool hasBaseAddress() const noexcept { return _baseAddress != Globals::kNoBaseAddress; }
742 : //! Returns a static base-address or \ref Globals::kNoBaseAddress, if not set.
743 0 : inline uint64_t baseAddress() const noexcept { return _baseAddress; }
744 :
745 : //! \}
746 :
747 : //! \name Emitters
748 : //! \{
749 :
750 : //! Returns a vector of attached emitters.
751 : inline const ZoneVector<BaseEmitter*>& emitters() const noexcept { return _emitters; }
752 :
753 : //! \}
754 :
755 : //! \name Logging
756 : //! \{
757 :
758 : //! Returns the attached logger.
759 54984 : inline Logger* logger() const noexcept { return _logger; }
760 : //! Attaches a `logger` to CodeHolder and propagates it to all attached emitters.
761 : ASMJIT_API void setLogger(Logger* logger) noexcept;
762 : //! Resets the logger to none.
763 : inline void resetLogger() noexcept { setLogger(nullptr); }
764 :
765 : //! \name Error Handling
766 : //! \{
767 :
768 : //! Tests whether the CodeHolder has an attached error handler, see \ref ErrorHandler.
769 : inline bool hasErrorHandler() const noexcept { return _errorHandler != nullptr; }
770 : //! Returns the attached error handler.
771 82476 : inline ErrorHandler* errorHandler() const noexcept { return _errorHandler; }
772 : //! Attach an error handler to this `CodeHolder`.
773 : ASMJIT_API void setErrorHandler(ErrorHandler* errorHandler) noexcept;
774 : //! Resets the error handler to none.
775 : inline void resetErrorHandler() noexcept { setErrorHandler(nullptr); }
776 :
777 : //! \}
778 :
779 : //! \name Code Buffer
780 : //! \{
781 :
782 : //! Makes sure that at least `n` bytes can be added to CodeHolder's buffer `cb`.
783 : //!
784 : //! \note The buffer `cb` must be managed by `CodeHolder` - otherwise the behavior of the function is undefined.
785 : ASMJIT_API Error growBuffer(CodeBuffer* cb, size_t n) noexcept;
786 :
787 : //! Reserves the size of `cb` to at least `n` bytes.
788 : //!
789 : //! \note The buffer `cb` must be managed by `CodeHolder` - otherwise the behavior of the function is undefined.
790 : ASMJIT_API Error reserveBuffer(CodeBuffer* cb, size_t n) noexcept;
791 :
792 : //! \}
793 :
794 : //! \name Sections
795 : //! \{
796 :
797 : //! Returns an array of `Section*` records.
798 : inline const ZoneVector<Section*>& sections() const noexcept { return _sections; }
799 : //! Returns an array of `Section*` records sorted according to section order first, then section id.
800 : inline const ZoneVector<Section*>& sectionsByOrder() const noexcept { return _sectionsByOrder; }
801 : //! Returns the number of sections.
802 : inline uint32_t sectionCount() const noexcept { return _sections.size(); }
803 :
804 : //! Tests whether the given `sectionId` is valid.
805 : inline bool isSectionValid(uint32_t sectionId) const noexcept { return sectionId < _sections.size(); }
806 :
807 : //! Creates a new section and return its pointer in `sectionOut`.
808 : //!
809 : //! Returns `Error`, does not report a possible error to `ErrorHandler`.
810 : ASMJIT_API Error newSection(Section** sectionOut, const char* name, size_t nameSize = SIZE_MAX, SectionFlags flags = SectionFlags::kNone, uint32_t alignment = 1, int32_t order = 0) noexcept;
811 :
812 : //! Returns a section entry of the given index.
813 27492 : inline Section* sectionById(uint32_t sectionId) const noexcept { return _sections[sectionId]; }
814 :
815 : //! Returns section-id that matches the given `name`.
816 : //!
817 : //! If there is no such section `Section::kInvalidId` is returned.
818 : ASMJIT_API Section* sectionByName(const char* name, size_t nameSize = SIZE_MAX) const noexcept;
819 :
820 : //! Returns '.text' section (section that commonly represents code).
821 : //!
822 : //! \note Text section is always the first section in \ref CodeHolder::sections() array.
823 : inline Section* textSection() const noexcept { return _sections[0]; }
824 :
825 : //! Tests whether '.addrtab' section exists.
826 : inline bool hasAddressTable() const noexcept { return _addressTableSection != nullptr; }
827 :
828 : //! Returns '.addrtab' section.
829 : //!
830 : //! This section is used exclusively by AsmJit to store absolute 64-bit
831 : //! addresses that cannot be encoded in instructions like 'jmp' or 'call'.
832 : //!
833 : //! \note This section is created on demand, the returned pointer can be null.
834 : inline Section* addressTableSection() const noexcept { return _addressTableSection; }
835 :
836 : //! Ensures that '.addrtab' section exists (creates it if it doesn't) and
837 : //! returns it. Can return `nullptr` on out of memory condition.
838 : ASMJIT_API Section* ensureAddressTableSection() noexcept;
839 :
840 : //! Used to add an address to an address table.
841 : //!
842 : //! This implicitly calls `ensureAddressTableSection()` and then creates `AddressTableEntry` that is inserted
843 : //! to `_addressTableEntries`. If the address already exists this operation does nothing as the same addresses
844 : //! use the same slot.
845 : //!
846 : //! This function should be considered internal as it's used by assemblers to insert an absolute address into the
847 : //! address table. Inserting address into address table without creating a particula relocation entry makes no sense.
848 : ASMJIT_API Error addAddressToAddressTable(uint64_t address) noexcept;
849 :
850 : //! \}
851 :
852 : //! \name Labels & Symbols
853 : //! \{
854 :
855 : //! Returns array of `LabelEntry*` records.
856 : inline const ZoneVector<LabelEntry*>& labelEntries() const noexcept { return _labelEntries; }
857 :
858 : //! Returns number of labels created.
859 : inline uint32_t labelCount() const noexcept { return _labelEntries.size(); }
860 :
861 : //! Tests whether the label having `id` is valid (i.e. created by `newLabelEntry()`).
862 : inline bool isLabelValid(uint32_t labelId) const noexcept {
863 : return labelId < _labelEntries.size();
864 : }
865 :
866 : //! Tests whether the `label` is valid (i.e. created by `newLabelEntry()`).
867 : inline bool isLabelValid(const Label& label) const noexcept {
868 : return label.id() < _labelEntries.size();
869 : }
870 :
871 : //! \overload
872 : inline bool isLabelBound(uint32_t labelId) const noexcept {
873 : return isLabelValid(labelId) && _labelEntries[labelId]->isBound();
874 : }
875 :
876 : //! Tests whether the `label` is already bound.
877 : //!
878 : //! Returns `false` if the `label` is not valid.
879 : inline bool isLabelBound(const Label& label) const noexcept {
880 : return isLabelBound(label.id());
881 : }
882 :
883 : //! Returns LabelEntry of the given label `id`.
884 : inline LabelEntry* labelEntry(uint32_t labelId) const noexcept {
885 54984 : return isLabelValid(labelId) ? _labelEntries[labelId] : static_cast<LabelEntry*>(nullptr);
886 : }
887 :
888 : //! Returns LabelEntry of the given `label`.
889 : inline LabelEntry* labelEntry(const Label& label) const noexcept {
890 : return labelEntry(label.id());
891 : }
892 :
893 : //! Returns offset of a `Label` by its `labelId`.
894 : //!
895 : //! The offset returned is relative to the start of the section. Zero offset is returned for unbound labels,
896 : //! which is their initial offset value.
897 : inline uint64_t labelOffset(uint32_t labelId) const noexcept {
898 : ASMJIT_ASSERT(isLabelValid(labelId));
899 : return _labelEntries[labelId]->offset();
900 : }
901 :
902 : //! \overload
903 : inline uint64_t labelOffset(const Label& label) const noexcept {
904 : return labelOffset(label.id());
905 : }
906 :
907 : //! Returns offset of a label by it's `labelId` relative to the base offset.
908 : //!
909 : //! \remarks The offset of the section where the label is bound must be valid in order to use this function,
910 : //! otherwise the value returned will not be reliable.
911 : inline uint64_t labelOffsetFromBase(uint32_t labelId) const noexcept {
912 : ASMJIT_ASSERT(isLabelValid(labelId));
913 : const LabelEntry* le = _labelEntries[labelId];
914 : return (le->isBound() ? le->section()->offset() : uint64_t(0)) + le->offset();
915 : }
916 :
917 : //! \overload
918 : inline uint64_t labelOffsetFromBase(const Label& label) const noexcept {
919 : return labelOffsetFromBase(label.id());
920 : }
921 :
922 : //! Creates a new anonymous label and return its id in `idOut`.
923 : //!
924 : //! Returns `Error`, does not report error to `ErrorHandler`.
925 : ASMJIT_API Error newLabelEntry(LabelEntry** entryOut) noexcept;
926 :
927 : //! Creates a new named \ref LabelEntry of the given label `type`.
928 : //!
929 : //! \param entryOut Where to store the created \ref LabelEntry.
930 : //! \param name The name of the label.
931 : //! \param nameSize The length of `name` argument, or `SIZE_MAX` if `name` is a null terminated string, which
932 : //! means that the `CodeHolder` will use `strlen()` to determine the length.
933 : //! \param type The type of the label to create, see \ref LabelType.
934 : //! \param parentId Parent id of a local label, otherwise it must be \ref Globals::kInvalidId.
935 : //! \retval Always returns \ref Error, does not report a possible error to the attached \ref ErrorHandler.
936 : //!
937 : //! AsmJit has a support for local labels (\ref LabelType::kLocal) which require a parent label id (parentId).
938 : //! The names of local labels can conflict with names of other local labels that have a different parent. In
939 : //! addition, AsmJit supports named anonymous labels, which are useful only for debugging purposes as the
940 : //! anonymous name will have a name, which will be formatted, but the label itself cannot be queried by such
941 : //! name.
942 : ASMJIT_API Error newNamedLabelEntry(LabelEntry** entryOut, const char* name, size_t nameSize, LabelType type, uint32_t parentId = Globals::kInvalidId) noexcept;
943 :
944 : //! Returns a label by name.
945 : //!
946 : //! If the named label doesn't a default constructed \ref Label is returned,
947 : //! which has its id set to \ref Globals::kInvalidId.
948 : inline Label labelByName(const char* name, size_t nameSize = SIZE_MAX, uint32_t parentId = Globals::kInvalidId) noexcept {
949 : return Label(labelIdByName(name, nameSize, parentId));
950 : }
951 :
952 : //! Returns a label id by name.
953 : //!
954 : //! If the named label doesn't exist \ref Globals::kInvalidId is returned.
955 : ASMJIT_API uint32_t labelIdByName(const char* name, size_t nameSize = SIZE_MAX, uint32_t parentId = Globals::kInvalidId) noexcept;
956 :
957 : //! Tests whether there are any unresolved label links.
958 27492 : inline bool hasUnresolvedLinks() const noexcept { return _unresolvedLinkCount != 0; }
959 : //! Returns the number of label links, which are unresolved.
960 : inline size_t unresolvedLinkCount() const noexcept { return _unresolvedLinkCount; }
961 :
962 : //! Creates a new label-link used to store information about yet unbound labels.
963 : //!
964 : //! Returns `null` if the allocation failed.
965 : ASMJIT_API LabelLink* newLabelLink(LabelEntry* le, uint32_t sectionId, size_t offset, intptr_t rel, const OffsetFormat& format) noexcept;
966 :
967 : //! Resolves cross-section links (`LabelLink`) associated with each label that was used as a destination in code
968 : //! of a different section. It's only useful to people that use multiple sections as it will do nothing if the code
969 : //! only contains a single section in which cross-section links are not possible.
970 : ASMJIT_API Error resolveUnresolvedLinks() noexcept;
971 :
972 : //! Binds a label to a given `sectionId` and `offset` (relative to start of the section).
973 : //!
974 : //! This function is generally used by `BaseAssembler::bind()` to do the heavy lifting.
975 : ASMJIT_API Error bindLabel(const Label& label, uint32_t sectionId, uint64_t offset) noexcept;
976 :
977 : //! \}
978 :
979 : //! \name Relocations
980 : //! \{
981 :
982 : //! Tests whether the code contains relocation entries.
983 : inline bool hasRelocEntries() const noexcept { return !_relocations.empty(); }
984 : //! Returns array of `RelocEntry*` records.
985 : inline const ZoneVector<RelocEntry*>& relocEntries() const noexcept { return _relocations; }
986 :
987 : //! Returns a RelocEntry of the given `id`.
988 : inline RelocEntry* relocEntry(uint32_t id) const noexcept { return _relocations[id]; }
989 :
990 : //! Creates a new relocation entry of type `relocType`.
991 : //!
992 : //! Additional fields can be set after the relocation entry was created.
993 : ASMJIT_API Error newRelocEntry(RelocEntry** dst, RelocType relocType) noexcept;
994 :
995 : //! \}
996 :
997 : //! \name Utilities
998 : //! \{
999 :
1000 : //! Flattens all sections by recalculating their offsets, starting at 0.
1001 : //!
1002 : //! \note This should never be called more than once.
1003 : ASMJIT_API Error flatten() noexcept;
1004 :
1005 : //! Returns computed the size of code & data of all sections.
1006 : //!
1007 : //! \note All sections will be iterated over and the code size returned would represent the minimum code size of
1008 : //! all combined sections after applying minimum alignment. Code size may decrease after calling `flatten()` and
1009 : //! `relocateToBase()`.
1010 : ASMJIT_API size_t codeSize() const noexcept;
1011 :
1012 : //! Relocates the code to the given `baseAddress`.
1013 : //!
1014 : //! \param baseAddress Absolute base address where the code will be relocated to. Please note that nothing is
1015 : //! copied to such base address, it's just an absolute value used by the relocator to resolve all stored relocations.
1016 : //!
1017 : //! \note This should never be called more than once.
1018 : ASMJIT_API Error relocateToBase(uint64_t baseAddress) noexcept;
1019 :
1020 : //! Copies a single section into `dst`.
1021 : ASMJIT_API Error copySectionData(void* dst, size_t dstSize, uint32_t sectionId, CopySectionFlags copyFlags = CopySectionFlags::kNone) noexcept;
1022 :
1023 : //! Copies all sections into `dst`.
1024 : //!
1025 : //! This should only be used if the data was flattened and there are no gaps between the sections. The `dstSize`
1026 : //! is always checked and the copy will never write anything outside the provided buffer.
1027 : ASMJIT_API Error copyFlattenedData(void* dst, size_t dstSize, CopySectionFlags copyFlags = CopySectionFlags::kNone) noexcept;
1028 :
1029 : //! \}
1030 : };
1031 :
1032 : //! \}
1033 :
1034 : ASMJIT_END_NAMESPACE
1035 :
1036 : #endif // ASMJIT_CORE_CODEHOLDER_H_INCLUDED
1037 :
1038 : #endif // __PLUMED_HAS_ASMJIT
|