LCOV - code coverage report
Current view: top level - asmjit - codeholder.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 125 412 30.3 %
Date: 2026-11-05 10:19:06 Functions: 14 33 42.4 %

          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             : #include "api-build_p.h"
       8             : #include "assembler.h"
       9             : #include "codewriter_p.h"
      10             : #include "logger.h"
      11             : #include "support.h"
      12             : 
      13             : #include <algorithm>
      14             : #include <tuple>
      15             : 
      16             : ASMJIT_BEGIN_NAMESPACE
      17             : 
      18             : // Globals
      19             : // =======
      20             : 
      21             : static const char CodeHolder_addrTabName[] = ".addrtab";
      22             : 
      23             : //! Encode MOD byte.
      24             : static inline uint32_t x86EncodeMod(uint32_t m, uint32_t o, uint32_t rm) noexcept {
      25             :   return (m << 6) | (o << 3) | rm;
      26             : }
      27             : 
      28             : // LabelLinkIterator
      29             : // =================
      30             : 
      31             : class LabelLinkIterator {
      32             : public:
      33       54984 :   inline LabelLinkIterator(LabelEntry* le) noexcept { reset(le); }
      34             : 
      35             :   inline explicit operator bool() const noexcept { return isValid(); }
      36             :   inline bool isValid() const noexcept { return _link != nullptr; }
      37             : 
      38             :   inline LabelLink* link() const noexcept { return _link; }
      39             :   inline LabelLink* operator->() const noexcept { return _link; }
      40             : 
      41             :   inline void reset(LabelEntry* le) noexcept {
      42       54984 :     _pPrev = &le->_links;
      43       54984 :     _link = *_pPrev;
      44             :   }
      45             : 
      46             :   inline void next() noexcept {
      47           0 :     _pPrev = &_link->next;
      48           0 :     _link = *_pPrev;
      49           0 :   }
      50             : 
      51             :   inline void resolveAndNext(CodeHolder* code) noexcept {
      52             :     LabelLink* linkToDelete = _link;
      53             : 
      54           0 :     _link = _link->next;
      55           0 :     *_pPrev = _link;
      56             : 
      57           0 :     code->_unresolvedLinkCount--;
      58             :     code->_allocator.release(linkToDelete, sizeof(LabelLink));
      59           0 :   }
      60             : 
      61             :   LabelLink** _pPrev;
      62             :   LabelLink* _link;
      63             : };
      64             : 
      65             : // CodeHolder - Utilities
      66             : // ======================
      67             : 
      68       27492 : static void CodeHolder_resetInternal(CodeHolder* self, ResetPolicy resetPolicy) noexcept {
      69             :   uint32_t i;
      70             :   const ZoneVector<BaseEmitter*>& emitters = self->emitters();
      71             : 
      72             :   i = emitters.size();
      73       27492 :   while (i)
      74           0 :     self->detach(emitters[--i]);
      75             : 
      76             :   // Reset everything into its construction state.
      77             :   self->_environment.reset();
      78       27492 :   self->_baseAddress = Globals::kNoBaseAddress;
      79       27492 :   self->_logger = nullptr;
      80       27492 :   self->_errorHandler = nullptr;
      81             : 
      82             :   // Reset all sections.
      83             :   uint32_t numSections = self->_sections.size();
      84       54984 :   for (i = 0; i < numSections; i++) {
      85       27492 :     Section* section = self->_sections[i];
      86       27492 :     if (section->_buffer.data() && !section->_buffer.isExternal())
      87       27492 :       ::free(section->_buffer._data);
      88       27492 :     section->_buffer._data = nullptr;
      89       27492 :     section->_buffer._capacity = 0;
      90             :   }
      91             : 
      92             :   // Reset zone allocator and all containers using it.
      93             :   ZoneAllocator* allocator = self->allocator();
      94             : 
      95             :   self->_emitters.reset();
      96             :   self->_namedLabels.reset();
      97             :   self->_relocations.reset();
      98             :   self->_labelEntries.reset();
      99             :   self->_sections.reset();
     100             :   self->_sectionsByOrder.reset();
     101             : 
     102       27492 :   self->_unresolvedLinkCount = 0;
     103       27492 :   self->_addressTableSection = nullptr;
     104             :   self->_addressTableEntries.reset();
     105             : 
     106       27492 :   allocator->reset(&self->_zone);
     107       27492 :   self->_zone.reset(resetPolicy);
     108       27492 : }
     109             : 
     110           0 : static void CodeHolder_onSettingsUpdated(CodeHolder* self) noexcept {
     111             :   // Notify all attached emitters about a settings update.
     112           0 :   for (BaseEmitter* emitter : self->emitters()) {
     113           0 :     emitter->onSettingsUpdated();
     114             :   }
     115           0 : }
     116             : 
     117             : // CodeHolder - Construction & Destruction
     118             : // =======================================
     119             : 
     120       27492 : CodeHolder::CodeHolder(const Support::Temporary* temporary) noexcept
     121             :   : _environment(),
     122       27492 :     _baseAddress(Globals::kNoBaseAddress),
     123       27492 :     _logger(nullptr),
     124       27492 :     _errorHandler(nullptr),
     125       27492 :     _zone(16384 - Zone::kBlockOverhead, 1, temporary),
     126       27492 :     _allocator(&_zone),
     127       27492 :     _unresolvedLinkCount(0),
     128       27492 :     _addressTableSection(nullptr) {}
     129             : 
     130       27492 : CodeHolder::~CodeHolder() noexcept {
     131       27492 :   CodeHolder_resetInternal(this, ResetPolicy::kHard);
     132       27492 : }
     133             : 
     134             : // CodeHolder - Init & Reset
     135             : // =========================
     136             : 
     137             : inline void CodeHolder_setSectionDefaultName(
     138             :   Section* section,
     139             :   char c0 = 0, char c1 = 0, char c2 = 0, char c3 = 0,
     140             :   char c4 = 0, char c5 = 0, char c6 = 0, char c7 = 0) noexcept {
     141             : 
     142       27492 :   section->_name.u32[0] = Support::bytepack32_4x8(uint8_t(c0), uint8_t(c1), uint8_t(c2), uint8_t(c3));
     143       27492 :   section->_name.u32[1] = Support::bytepack32_4x8(uint8_t(c4), uint8_t(c5), uint8_t(c6), uint8_t(c7));
     144             : }
     145             : 
     146       27492 : Error CodeHolder::init(const Environment& environment, uint64_t baseAddress) noexcept {
     147             :   // Cannot reinitialize if it's locked or there is one or more emitter attached.
     148       27492 :   if (isInitialized())
     149             :     return DebugUtils::errored(kErrorAlreadyInitialized);
     150             : 
     151             :   // If we are just initializing there should be no emitters attached.
     152             :   ASMJIT_ASSERT(_emitters.empty());
     153             : 
     154             :   // Create a default section and insert it to the `_sections` array.
     155       27492 :   Error err = _sections.willGrow(&_allocator) |
     156       27492 :               _sectionsByOrder.willGrow(&_allocator);
     157       27492 :   if (err == kErrorOk) {
     158       27492 :     Section* section = _allocator.allocZeroedT<Section>();
     159       27492 :     if (ASMJIT_LIKELY(section)) {
     160       27492 :       section->_flags = SectionFlags::kExecutable | SectionFlags::kReadOnly;
     161             :       CodeHolder_setSectionDefaultName(section, '.', 't', 'e', 'x', 't');
     162             :       _sections.appendUnsafe(section);
     163             :       _sectionsByOrder.appendUnsafe(section);
     164             :     }
     165             :     else {
     166             :       err = DebugUtils::errored(kErrorOutOfMemory);
     167             :     }
     168             :   }
     169             : 
     170       27492 :   if (ASMJIT_UNLIKELY(err)) {
     171           0 :     _zone.reset();
     172           0 :     return err;
     173             :   }
     174             :   else {
     175       27492 :     _environment = environment;
     176       27492 :     _baseAddress = baseAddress;
     177       27492 :     return kErrorOk;
     178             :   }
     179             : }
     180             : 
     181           0 : void CodeHolder::reset(ResetPolicy resetPolicy) noexcept {
     182           0 :   CodeHolder_resetInternal(this, resetPolicy);
     183           0 : }
     184             : 
     185             : // CodeHolder - Attach / Detach
     186             : // ============================
     187             : 
     188       54984 : Error CodeHolder::attach(BaseEmitter* emitter) noexcept {
     189             :   // Catch a possible misuse of the API.
     190       54984 :   if (ASMJIT_UNLIKELY(!emitter))
     191             :     return DebugUtils::errored(kErrorInvalidArgument);
     192             : 
     193             :   // Invalid emitter, this should not be possible.
     194             :   EmitterType type = emitter->emitterType();
     195       54984 :   if (ASMJIT_UNLIKELY(type == EmitterType::kNone || uint32_t(type) > uint32_t(EmitterType::kMaxValue)))
     196             :     return DebugUtils::errored(kErrorInvalidState);
     197             : 
     198       54984 :   uint64_t archMask = emitter->_archMask;
     199       54984 :   if (ASMJIT_UNLIKELY(!(archMask & (uint64_t(1) << uint32_t(arch())))))
     200             :     return DebugUtils::errored(kErrorInvalidArch);
     201             : 
     202             :   // This is suspicious, but don't fail if `emitter` is already attached
     203             :   // to this code holder. This is not error, but it's not recommended.
     204       54984 :   if (emitter->_code != nullptr) {
     205           0 :     if (emitter->_code == this)
     206           0 :       return kErrorOk;
     207             :     return DebugUtils::errored(kErrorInvalidState);
     208             :   }
     209             : 
     210             :   // Reserve the space now as we cannot fail after `onAttach()` succeeded.
     211       54984 :   ASMJIT_PROPAGATE(_emitters.willGrow(&_allocator, 1));
     212       54984 :   ASMJIT_PROPAGATE(emitter->onAttach(this));
     213             : 
     214             :   // Connect CodeHolder <-> BaseEmitter.
     215             :   ASMJIT_ASSERT(emitter->_code == this);
     216             :   _emitters.appendUnsafe(emitter);
     217             : 
     218       54984 :   return kErrorOk;
     219             : }
     220             : 
     221       54984 : Error CodeHolder::detach(BaseEmitter* emitter) noexcept {
     222       54984 :   if (ASMJIT_UNLIKELY(!emitter))
     223             :     return DebugUtils::errored(kErrorInvalidArgument);
     224             : 
     225       54984 :   if (ASMJIT_UNLIKELY(emitter->_code != this))
     226             :     return DebugUtils::errored(kErrorInvalidState);
     227             : 
     228             :   // NOTE: We always detach if we were asked to, if error happens during
     229             :   // `emitter->onDetach()` we just propagate it, but the BaseEmitter will
     230             :   // be detached.
     231             :   Error err = kErrorOk;
     232       54984 :   if (!emitter->isDestroyed())
     233           0 :     err = emitter->onDetach(this);
     234             : 
     235             :   // Disconnect CodeHolder <-> BaseEmitter.
     236             :   uint32_t index = _emitters.indexOf(emitter);
     237             :   ASMJIT_ASSERT(index != Globals::kNotFound);
     238             : 
     239       54984 :   _emitters.removeAt(index);
     240       54984 :   emitter->_code = nullptr;
     241             : 
     242       54984 :   return err;
     243             : }
     244             : 
     245             : // CodeHolder - Logging
     246             : // ====================
     247             : 
     248           0 : void CodeHolder::setLogger(Logger* logger) noexcept {
     249             : #ifndef ASMJIT_NO_LOGGING
     250           0 :   _logger = logger;
     251           0 :   CodeHolder_onSettingsUpdated(this);
     252             : #else
     253             :   DebugUtils::unused(logger);
     254             : #endif
     255           0 : }
     256             : 
     257             : // CodeHolder - Error Handling
     258             : // ===========================
     259             : 
     260           0 : void CodeHolder::setErrorHandler(ErrorHandler* errorHandler) noexcept {
     261           0 :   _errorHandler = errorHandler;
     262           0 :   CodeHolder_onSettingsUpdated(this);
     263           0 : }
     264             : 
     265             : // CodeHolder - Code Buffer
     266             : // ========================
     267             : 
     268       27492 : static Error CodeHolder_reserveInternal(CodeHolder* self, CodeBuffer* cb, size_t n) noexcept {
     269       27492 :   uint8_t* oldData = cb->_data;
     270             :   uint8_t* newData;
     271             : 
     272       27492 :   if (oldData && !cb->isExternal())
     273           0 :     newData = static_cast<uint8_t*>(::realloc(oldData, n));
     274             :   else
     275       27492 :     newData = static_cast<uint8_t*>(::malloc(n));
     276             : 
     277       27492 :   if (ASMJIT_UNLIKELY(!newData))
     278             :     return DebugUtils::errored(kErrorOutOfMemory);
     279             : 
     280       27492 :   cb->_data = newData;
     281       27492 :   cb->_capacity = n;
     282             : 
     283             :   // Update pointers used by assemblers, if attached.
     284       82476 :   for (BaseEmitter* emitter : self->emitters()) {
     285       54984 :     if (emitter->isAssembler()) {
     286             :       BaseAssembler* a = static_cast<BaseAssembler*>(emitter);
     287       27492 :       if (&a->_section->_buffer == cb) {
     288             :         size_t offset = a->offset();
     289             : 
     290       27492 :         a->_bufferData = newData;
     291       27492 :         a->_bufferEnd  = newData + n;
     292       27492 :         a->_bufferPtr  = newData + offset;
     293             :       }
     294             :     }
     295             :   }
     296             : 
     297             :   return kErrorOk;
     298             : }
     299             : 
     300       27492 : Error CodeHolder::growBuffer(CodeBuffer* cb, size_t n) noexcept {
     301             :   // The size of the section must be valid.
     302             :   size_t size = cb->size();
     303       27492 :   if (ASMJIT_UNLIKELY(n > std::numeric_limits<uintptr_t>::max() - size))
     304             :     return DebugUtils::errored(kErrorOutOfMemory);
     305             : 
     306             :   // We can now check if growing the buffer is really necessary. It's unlikely
     307             :   // that this function is called while there is still room for `n` bytes.
     308             :   size_t capacity = cb->capacity();
     309       27492 :   size_t required = cb->size() + n;
     310       27492 :   if (ASMJIT_UNLIKELY(required <= capacity))
     311             :     return kErrorOk;
     312             : 
     313       27492 :   if (cb->isFixed())
     314             :     return DebugUtils::errored(kErrorTooLarge);
     315             : 
     316             :   size_t kInitialCapacity = 8096;
     317       27492 :   if (capacity < kInitialCapacity)
     318             :     capacity = kInitialCapacity;
     319             :   else
     320           0 :     capacity += Globals::kAllocOverhead;
     321             : 
     322             :   do {
     323             :     size_t old = capacity;
     324       27492 :     if (capacity < Globals::kGrowThreshold)
     325       27492 :       capacity *= 2;
     326             :     else
     327           0 :       capacity += Globals::kGrowThreshold;
     328             : 
     329             :     // Overflow.
     330       27492 :     if (ASMJIT_UNLIKELY(old > capacity))
     331             :       return DebugUtils::errored(kErrorOutOfMemory);
     332       27492 :   } while (capacity - Globals::kAllocOverhead < required);
     333             : 
     334       27492 :   return CodeHolder_reserveInternal(this, cb, capacity - Globals::kAllocOverhead);
     335             : }
     336             : 
     337           0 : Error CodeHolder::reserveBuffer(CodeBuffer* cb, size_t n) noexcept {
     338             :   size_t capacity = cb->capacity();
     339             : 
     340           0 :   if (n <= capacity)
     341             :     return kErrorOk;
     342             : 
     343           0 :   if (cb->isFixed())
     344             :     return DebugUtils::errored(kErrorTooLarge);
     345             : 
     346           0 :   return CodeHolder_reserveInternal(this, cb, n);
     347             : }
     348             : 
     349             : // CodeHolder - Sections
     350             : // =====================
     351             : 
     352           0 : Error CodeHolder::newSection(Section** sectionOut, const char* name, size_t nameSize, SectionFlags flags, uint32_t alignment, int32_t order) noexcept {
     353           0 :   *sectionOut = nullptr;
     354             : 
     355           0 :   if (nameSize == SIZE_MAX)
     356           0 :     nameSize = strlen(name);
     357             : 
     358             :   if (alignment == 0)
     359             :     alignment = 1;
     360             : 
     361           0 :   if (ASMJIT_UNLIKELY(!Support::isPowerOf2(alignment)))
     362             :     return DebugUtils::errored(kErrorInvalidArgument);
     363             : 
     364           0 :   if (ASMJIT_UNLIKELY(nameSize > Globals::kMaxSectionNameSize))
     365             :     return DebugUtils::errored(kErrorInvalidSectionName);
     366             : 
     367             :   uint32_t sectionId = _sections.size();
     368           0 :   if (ASMJIT_UNLIKELY(sectionId == Globals::kInvalidId))
     369             :     return DebugUtils::errored(kErrorTooManySections);
     370             : 
     371           0 :   ASMJIT_PROPAGATE(_sections.willGrow(&_allocator));
     372           0 :   ASMJIT_PROPAGATE(_sectionsByOrder.willGrow(&_allocator));
     373             : 
     374           0 :   Section* section = _allocator.allocZeroedT<Section>();
     375           0 :   if (ASMJIT_UNLIKELY(!section))
     376             :     return DebugUtils::errored(kErrorOutOfMemory);
     377             : 
     378           0 :   section->_id = sectionId;
     379           0 :   section->_flags = flags;
     380           0 :   section->_alignment = alignment;
     381           0 :   section->_order = order;
     382           0 :   memcpy(section->_name.str, name, nameSize);
     383             : 
     384           0 :   Section** insertPosition = std::lower_bound(_sectionsByOrder.begin(), _sectionsByOrder.end(), section, [](const Section* a, const Section* b) {
     385           0 :     return std::make_tuple(a->order(), a->id()) < std::make_tuple(b->order(), b->id());
     386             :   });
     387             : 
     388             :   _sections.appendUnsafe(section);
     389           0 :   _sectionsByOrder.insertUnsafe((size_t)(insertPosition - _sectionsByOrder.data()), section);
     390             : 
     391           0 :   *sectionOut = section;
     392           0 :   return kErrorOk;
     393             : }
     394             : 
     395           0 : Section* CodeHolder::sectionByName(const char* name, size_t nameSize) const noexcept {
     396           0 :   if (nameSize == SIZE_MAX)
     397           0 :     nameSize = strlen(name);
     398             : 
     399             :   // This could be also put in a hash-table similarly like we do with labels,
     400             :   // however it's questionable as the number of sections should be pretty low
     401             :   // in general. Create an issue if this becomes a problem.
     402           0 :   if (nameSize <= Globals::kMaxSectionNameSize) {
     403           0 :     for (Section* section : _sections)
     404           0 :       if (memcmp(section->_name.str, name, nameSize) == 0 && section->_name.str[nameSize] == '\0')
     405             :         return section;
     406             :   }
     407             : 
     408             :   return nullptr;
     409             : }
     410             : 
     411           0 : Section* CodeHolder::ensureAddressTableSection() noexcept {
     412           0 :   if (_addressTableSection)
     413             :     return _addressTableSection;
     414             : 
     415           0 :   newSection(&_addressTableSection,
     416             :              CodeHolder_addrTabName,
     417             :              sizeof(CodeHolder_addrTabName) - 1,
     418             :              SectionFlags::kNone,
     419             :              _environment.registerSize(),
     420             :              std::numeric_limits<int32_t>::max());
     421           0 :   return _addressTableSection;
     422             : }
     423             : 
     424           0 : Error CodeHolder::addAddressToAddressTable(uint64_t address) noexcept {
     425           0 :   AddressTableEntry* entry = _addressTableEntries.get(address);
     426           0 :   if (entry)
     427             :     return kErrorOk;
     428             : 
     429           0 :   Section* section = ensureAddressTableSection();
     430           0 :   if (ASMJIT_UNLIKELY(!section))
     431             :     return DebugUtils::errored(kErrorOutOfMemory);
     432             : 
     433           0 :   entry = _zone.newT<AddressTableEntry>(address);
     434           0 :   if (ASMJIT_UNLIKELY(!entry))
     435             :     return DebugUtils::errored(kErrorOutOfMemory);
     436             : 
     437           0 :   _addressTableEntries.insert(entry);
     438           0 :   section->_virtualSize += _environment.registerSize();
     439             : 
     440           0 :   return kErrorOk;
     441             : }
     442             : 
     443             : // CodeHolder - Labels & Symbols
     444             : // =============================
     445             : 
     446             : //! Only used to lookup a label from `_namedLabels`.
     447             : class LabelByName {
     448             : public:
     449             :   inline LabelByName(const char* key, size_t keySize, uint32_t hashCode, uint32_t parentId) noexcept
     450           0 :     : _key(key),
     451           0 :       _keySize(uint32_t(keySize)),
     452           0 :       _hashCode(hashCode),
     453           0 :       _parentId(parentId) {}
     454             : 
     455           0 :   inline uint32_t hashCode() const noexcept { return _hashCode; }
     456             : 
     457           0 :   inline bool matches(const LabelEntry* entry) const noexcept {
     458           0 :     return entry->nameSize() == _keySize &&
     459           0 :            entry->parentId() == _parentId &&
     460           0 :            ::memcmp(entry->name(), _key, _keySize) == 0;
     461             :   }
     462             : 
     463             :   const char* _key;
     464             :   uint32_t _keySize;
     465             :   uint32_t _hashCode;
     466             :   uint32_t _parentId;
     467             : };
     468             : 
     469             : // Returns a hash of `name` and fixes `nameSize` if it's `SIZE_MAX`.
     470           0 : static uint32_t CodeHolder_hashNameAndGetSize(const char* name, size_t& nameSize) noexcept {
     471             :   uint32_t hashCode = 0;
     472           0 :   if (nameSize == SIZE_MAX) {
     473             :     size_t i = 0;
     474             :     for (;;) {
     475           0 :       uint8_t c = uint8_t(name[i]);
     476           0 :       if (!c) break;
     477           0 :       hashCode = Support::hashRound(hashCode, c);
     478           0 :       i++;
     479           0 :     }
     480           0 :     nameSize = i;
     481             :   }
     482             :   else {
     483           0 :     for (size_t i = 0; i < nameSize; i++) {
     484           0 :       uint8_t c = uint8_t(name[i]);
     485           0 :       if (ASMJIT_UNLIKELY(!c)) return DebugUtils::errored(kErrorInvalidLabelName);
     486           0 :       hashCode = Support::hashRound(hashCode, c);
     487             :     }
     488             :   }
     489             :   return hashCode;
     490             : }
     491             : 
     492           0 : LabelLink* CodeHolder::newLabelLink(LabelEntry* le, uint32_t sectionId, size_t offset, intptr_t rel, const OffsetFormat& format) noexcept {
     493           0 :   LabelLink* link = _allocator.allocT<LabelLink>();
     494           0 :   if (ASMJIT_UNLIKELY(!link)) return nullptr;
     495             : 
     496           0 :   link->next = le->_links;
     497           0 :   le->_links = link;
     498             : 
     499           0 :   link->sectionId = sectionId;
     500           0 :   link->relocId = Globals::kInvalidId;
     501           0 :   link->offset = offset;
     502           0 :   link->rel = rel;
     503           0 :   link->format = format;
     504             : 
     505           0 :   _unresolvedLinkCount++;
     506           0 :   return link;
     507             : }
     508             : 
     509       54984 : Error CodeHolder::newLabelEntry(LabelEntry** entryOut) noexcept {
     510       54984 :   *entryOut = nullptr;
     511             : 
     512             :   uint32_t labelId = _labelEntries.size();
     513       54984 :   if (ASMJIT_UNLIKELY(labelId == Globals::kInvalidId))
     514             :     return DebugUtils::errored(kErrorTooManyLabels);
     515             : 
     516       54984 :   ASMJIT_PROPAGATE(_labelEntries.willGrow(&_allocator));
     517       54984 :   LabelEntry* le = _allocator.allocZeroedT<LabelEntry>();
     518             : 
     519       54984 :   if (ASMJIT_UNLIKELY(!le))
     520             :     return DebugUtils::errored(kErrorOutOfMemory);
     521             : 
     522             :   le->_setId(labelId);
     523       54984 :   le->_parentId = Globals::kInvalidId;
     524       54984 :   le->_offset = 0;
     525             :   _labelEntries.appendUnsafe(le);
     526             : 
     527       54984 :   *entryOut = le;
     528       54984 :   return kErrorOk;
     529             : }
     530             : 
     531           0 : Error CodeHolder::newNamedLabelEntry(LabelEntry** entryOut, const char* name, size_t nameSize, LabelType type, uint32_t parentId) noexcept {
     532           0 :   *entryOut = nullptr;
     533           0 :   uint32_t hashCode = CodeHolder_hashNameAndGetSize(name, nameSize);
     534             : 
     535           0 :   if (ASMJIT_UNLIKELY(nameSize == 0)) {
     536           0 :     if (type == LabelType::kAnonymous)
     537           0 :       return newLabelEntry(entryOut);
     538             :     else
     539             :       return DebugUtils::errored(kErrorInvalidLabelName);
     540             :   }
     541             : 
     542           0 :   if (ASMJIT_UNLIKELY(nameSize > Globals::kMaxLabelNameSize))
     543             :     return DebugUtils::errored(kErrorLabelNameTooLong);
     544             : 
     545           0 :   switch (type) {
     546           0 :     case LabelType::kAnonymous: {
     547             :       // Anonymous labels cannot have a parent (or more specifically, parent is useless here).
     548           0 :       if (ASMJIT_UNLIKELY(parentId != Globals::kInvalidId))
     549             :         return DebugUtils::errored(kErrorInvalidParentLabel);
     550             : 
     551             :       uint32_t labelId = _labelEntries.size();
     552           0 :       if (ASMJIT_UNLIKELY(labelId == Globals::kInvalidId))
     553             :         return DebugUtils::errored(kErrorTooManyLabels);
     554             : 
     555           0 :       ASMJIT_PROPAGATE(_labelEntries.willGrow(&_allocator));
     556           0 :       LabelEntry* le = _allocator.allocZeroedT<LabelEntry>();
     557             : 
     558           0 :       if (ASMJIT_UNLIKELY(!le))
     559             :         return DebugUtils::errored(kErrorOutOfMemory);
     560             : 
     561             :       // NOTE: This LabelEntry has a name, but we leave its hashCode as zero as it's anonymous.
     562             :       le->_setId(labelId);
     563           0 :       le->_parentId = Globals::kInvalidId;
     564           0 :       le->_offset = 0;
     565           0 :       ASMJIT_PROPAGATE(le->_name.setData(&_zone, name, nameSize));
     566             : 
     567             :       _labelEntries.appendUnsafe(le);
     568             : 
     569           0 :       *entryOut = le;
     570           0 :       return kErrorOk;
     571             :     }
     572             : 
     573           0 :     case LabelType::kLocal: {
     574           0 :       if (ASMJIT_UNLIKELY(parentId >= _labelEntries.size()))
     575             :         return DebugUtils::errored(kErrorInvalidParentLabel);
     576             : 
     577           0 :       hashCode ^= parentId;
     578           0 :       break;
     579             :     }
     580             : 
     581           0 :     case LabelType::kGlobal:
     582             :     case LabelType::kExternal: {
     583           0 :       if (ASMJIT_UNLIKELY(parentId != Globals::kInvalidId))
     584             :         return DebugUtils::errored(kErrorInvalidParentLabel);
     585             :       break;
     586             :     }
     587             : 
     588             :     default: {
     589             :       return DebugUtils::errored(kErrorInvalidArgument);
     590             :     }
     591             :   }
     592             : 
     593             :   // Don't allow to insert duplicates. Local labels allow duplicates that have
     594             :   // different id, this is already accomplished by having a different hashes
     595             :   // between the same label names having different parent labels.
     596           0 :   LabelEntry* le = _namedLabels.get(LabelByName(name, nameSize, hashCode, parentId));
     597           0 :   if (ASMJIT_UNLIKELY(le))
     598             :     return DebugUtils::errored(kErrorLabelAlreadyDefined);
     599             : 
     600             :   Error err = kErrorOk;
     601             :   uint32_t labelId = _labelEntries.size();
     602             : 
     603           0 :   if (ASMJIT_UNLIKELY(labelId == Globals::kInvalidId))
     604             :     return DebugUtils::errored(kErrorTooManyLabels);
     605             : 
     606           0 :   ASMJIT_PROPAGATE(_labelEntries.willGrow(&_allocator));
     607           0 :   le = _allocator.allocZeroedT<LabelEntry>();
     608             : 
     609           0 :   if (ASMJIT_UNLIKELY(!le))
     610             :     return DebugUtils::errored(kErrorOutOfMemory);
     611             : 
     612           0 :   le->_hashCode = hashCode;
     613             :   le->_setId(labelId);
     614           0 :   le->_type = type;
     615           0 :   le->_parentId = parentId;
     616           0 :   le->_offset = 0;
     617           0 :   ASMJIT_PROPAGATE(le->_name.setData(&_zone, name, nameSize));
     618             : 
     619             :   _labelEntries.appendUnsafe(le);
     620             :   _namedLabels.insert(allocator(), le);
     621             : 
     622           0 :   *entryOut = le;
     623           0 :   return err;
     624             : }
     625             : 
     626           0 : uint32_t CodeHolder::labelIdByName(const char* name, size_t nameSize, uint32_t parentId) noexcept {
     627           0 :   uint32_t hashCode = CodeHolder_hashNameAndGetSize(name, nameSize);
     628           0 :   if (ASMJIT_UNLIKELY(!nameSize))
     629             :     return 0;
     630             : 
     631           0 :   if (parentId != Globals::kInvalidId)
     632           0 :     hashCode ^= parentId;
     633             : 
     634           0 :   LabelEntry* le = _namedLabels.get(LabelByName(name, nameSize, hashCode, parentId));
     635           0 :   return le ? le->id() : uint32_t(Globals::kInvalidId);
     636             : }
     637             : 
     638       27492 : ASMJIT_API Error CodeHolder::resolveUnresolvedLinks() noexcept {
     639       27492 :   if (!hasUnresolvedLinks())
     640             :     return kErrorOk;
     641             : 
     642             :   Error err = kErrorOk;
     643           0 :   for (LabelEntry* le : labelEntries()) {
     644           0 :     if (!le->isBound())
     645             :       continue;
     646             : 
     647             :     LabelLinkIterator link(le);
     648           0 :     if (link) {
     649             :       Support::FastUInt8 of = 0;
     650             :       Section* toSection = le->section();
     651             :       uint64_t toOffset = Support::addOverflow(toSection->offset(), le->offset(), &of);
     652             : 
     653             :       do {
     654           0 :         uint32_t linkSectionId = link->sectionId;
     655           0 :         if (link->relocId == Globals::kInvalidId) {
     656             :           Section* fromSection = sectionById(linkSectionId);
     657           0 :           size_t linkOffset = link->offset;
     658             : 
     659             :           CodeBuffer& buf = _sections[linkSectionId]->buffer();
     660             :           ASMJIT_ASSERT(linkOffset < buf.size());
     661             : 
     662             :           // Calculate the offset relative to the start of the virtual base.
     663             :           Support::FastUInt8 localOF = of;
     664             :           uint64_t fromOffset = Support::addOverflow<uint64_t>(fromSection->offset(), linkOffset, &localOF);
     665           0 :           int64_t displacement = int64_t(toOffset - fromOffset + uint64_t(int64_t(link->rel)));
     666             : 
     667           0 :           if (!localOF) {
     668             :             ASMJIT_ASSERT(size_t(linkOffset) < buf.size());
     669             :             ASMJIT_ASSERT(buf.size() - size_t(linkOffset) >= link->format.valueSize());
     670             : 
     671             :             // Overwrite a real displacement in the CodeBuffer.
     672           0 :             if (CodeWriterUtils::writeOffset(buf._data + linkOffset, displacement, link->format)) {
     673             :               link.resolveAndNext(this);
     674             :               continue;
     675             :             }
     676             :           }
     677             : 
     678             :           err = DebugUtils::errored(kErrorInvalidDisplacement);
     679             :           // Falls through to `link.next()`.
     680             :         }
     681             : 
     682             :         link.next();
     683           0 :       } while (link);
     684             :     }
     685             :   }
     686             : 
     687             :   return err;
     688             : }
     689             : 
     690       54984 : ASMJIT_API Error CodeHolder::bindLabel(const Label& label, uint32_t toSectionId, uint64_t toOffset) noexcept {
     691             :   LabelEntry* le = labelEntry(label);
     692       54984 :   if (ASMJIT_UNLIKELY(!le))
     693             :     return DebugUtils::errored(kErrorInvalidLabel);
     694             : 
     695       54984 :   if (ASMJIT_UNLIKELY(toSectionId > _sections.size()))
     696             :     return DebugUtils::errored(kErrorInvalidSection);
     697             : 
     698             :   // Label can be bound only once.
     699       54984 :   if (ASMJIT_UNLIKELY(le->isBound()))
     700             :     return DebugUtils::errored(kErrorLabelAlreadyBound);
     701             : 
     702             :   // Bind the label.
     703       54984 :   Section* section = _sections[toSectionId];
     704       54984 :   le->_section = section;
     705       54984 :   le->_offset = toOffset;
     706             : 
     707             :   Error err = kErrorOk;
     708             :   CodeBuffer& buf = section->buffer();
     709             : 
     710             :   // Fix all links to this label we have collected so far if they are within
     711             :   // the same section. We ignore any inter-section links as these have to be
     712             :   // fixed later.
     713             :   LabelLinkIterator link(le);
     714       54984 :   while (link) {
     715           0 :     uint32_t linkSectionId = link->sectionId;
     716           0 :     size_t linkOffset = link->offset;
     717             : 
     718           0 :     uint32_t relocId = link->relocId;
     719           0 :     if (relocId != Globals::kInvalidId) {
     720             :       // Adjust relocation data only.
     721           0 :       RelocEntry* re = _relocations[relocId];
     722           0 :       re->_payload += toOffset;
     723           0 :       re->_targetSectionId = toSectionId;
     724             :     }
     725             :     else {
     726           0 :       if (linkSectionId != toSectionId) {
     727             :         link.next();
     728           0 :         continue;
     729             :       }
     730             : 
     731             :       ASMJIT_ASSERT(linkOffset < buf.size());
     732           0 :       int64_t displacement = int64_t(toOffset - uint64_t(linkOffset) + uint64_t(int64_t(link->rel)));
     733             : 
     734             :       // Size of the value we are going to patch. Only BYTE/DWORD is allowed.
     735             :       ASMJIT_ASSERT(buf.size() - size_t(linkOffset) >= link->format.regionSize());
     736             : 
     737             :       // Overwrite a real displacement in the CodeBuffer.
     738           0 :       if (!CodeWriterUtils::writeOffset(buf._data + linkOffset, displacement, link->format)) {
     739             :         err = DebugUtils::errored(kErrorInvalidDisplacement);
     740             :         link.next();
     741           0 :         continue;
     742             :       }
     743             :     }
     744             : 
     745             :     link.resolveAndNext(this);
     746             :   }
     747             : 
     748             :   return err;
     749             : }
     750             : 
     751             : // CodeHolder - Relocations
     752             : // ========================
     753             : 
     754           0 : Error CodeHolder::newRelocEntry(RelocEntry** dst, RelocType relocType) noexcept {
     755           0 :   ASMJIT_PROPAGATE(_relocations.willGrow(&_allocator));
     756             : 
     757             :   uint32_t relocId = _relocations.size();
     758           0 :   if (ASMJIT_UNLIKELY(relocId == Globals::kInvalidId))
     759             :     return DebugUtils::errored(kErrorTooManyRelocations);
     760             : 
     761           0 :   RelocEntry* re = _allocator.allocZeroedT<RelocEntry>();
     762           0 :   if (ASMJIT_UNLIKELY(!re))
     763             :     return DebugUtils::errored(kErrorOutOfMemory);
     764             : 
     765           0 :   re->_id = relocId;
     766           0 :   re->_relocType = relocType;
     767           0 :   re->_sourceSectionId = Globals::kInvalidId;
     768           0 :   re->_targetSectionId = Globals::kInvalidId;
     769             :   _relocations.appendUnsafe(re);
     770             : 
     771           0 :   *dst = re;
     772           0 :   return kErrorOk;
     773             : }
     774             : 
     775             : // CodeHolder - Expression Evaluation
     776             : // ==================================
     777             : 
     778           0 : static Error CodeHolder_evaluateExpression(CodeHolder* self, Expression* exp, uint64_t* out) noexcept {
     779             :   uint64_t value[2];
     780           0 :   for (size_t i = 0; i < 2; i++) {
     781             :     uint64_t v;
     782           0 :     switch (exp->valueType[i]) {
     783           0 :       case ExpressionValueType::kNone: {
     784           0 :         v = 0;
     785           0 :         break;
     786             :       }
     787             : 
     788           0 :       case ExpressionValueType::kConstant: {
     789           0 :         v = exp->value[i].constant;
     790           0 :         break;
     791             :       }
     792             : 
     793           0 :       case ExpressionValueType::kLabel: {
     794           0 :         LabelEntry* le = exp->value[i].label;
     795           0 :         if (!le->isBound())
     796           0 :           return DebugUtils::errored(kErrorExpressionLabelNotBound);
     797           0 :         v = le->section()->offset() + le->offset();
     798           0 :         break;
     799             :       }
     800             : 
     801           0 :       case ExpressionValueType::kExpression: {
     802           0 :         Expression* nested = exp->value[i].expression;
     803           0 :         ASMJIT_PROPAGATE(CodeHolder_evaluateExpression(self, nested, &v));
     804             :         break;
     805             :       }
     806             : 
     807             :       default:
     808             :         return DebugUtils::errored(kErrorInvalidState);
     809             :     }
     810             : 
     811           0 :     value[i] = v;
     812             :   }
     813             : 
     814             :   uint64_t result;
     815             :   uint64_t& a = value[0];
     816             :   uint64_t& b = value[1];
     817             : 
     818           0 :   switch (exp->opType) {
     819           0 :     case ExpressionOpType::kAdd:
     820           0 :       result = a + b;
     821           0 :       break;
     822             : 
     823           0 :     case ExpressionOpType::kSub:
     824           0 :       result = a - b;
     825           0 :       break;
     826             : 
     827           0 :     case ExpressionOpType::kMul:
     828           0 :       result = a * b;
     829           0 :       break;
     830             : 
     831           0 :     case ExpressionOpType::kSll:
     832           0 :       result = (b > 63) ? uint64_t(0) : uint64_t(a << b);
     833             :       break;
     834             : 
     835           0 :     case ExpressionOpType::kSrl:
     836           0 :       result = (b > 63) ? uint64_t(0) : uint64_t(a >> b);
     837             :       break;
     838             : 
     839           0 :     case ExpressionOpType::kSra:
     840             :       result = Support::sar(a, Support::min<uint64_t>(b, 63));
     841           0 :       break;
     842             : 
     843             :     default:
     844             :       return DebugUtils::errored(kErrorInvalidState);
     845             :   }
     846             : 
     847           0 :   *out = result;
     848           0 :   return kErrorOk;
     849             : }
     850             : 
     851             : // CodeHolder - Utilities
     852             : // ======================
     853             : 
     854       27492 : Error CodeHolder::flatten() noexcept {
     855             :   uint64_t offset = 0;
     856       54984 :   for (Section* section : _sectionsByOrder) {
     857             :     uint64_t realSize = section->realSize();
     858       27492 :     if (realSize) {
     859             :       uint64_t alignedOffset = Support::alignUp(offset, section->alignment());
     860       27492 :       if (ASMJIT_UNLIKELY(alignedOffset < offset))
     861             :         return DebugUtils::errored(kErrorTooLarge);
     862             : 
     863             :       Support::FastUInt8 of = 0;
     864             :       offset = Support::addOverflow(alignedOffset, realSize, &of);
     865             : 
     866       27492 :       if (ASMJIT_UNLIKELY(of))
     867             :         return DebugUtils::errored(kErrorTooLarge);
     868             :     }
     869             :   }
     870             : 
     871             :   // Now we know that we can assign offsets of all sections properly.
     872             :   Section* prev = nullptr;
     873             :   offset = 0;
     874       54984 :   for (Section* section : _sectionsByOrder) {
     875             :     uint64_t realSize = section->realSize();
     876       27492 :     if (realSize)
     877             :       offset = Support::alignUp(offset, section->alignment());
     878       27492 :     section->_offset = offset;
     879             : 
     880             :     // Make sure the previous section extends a bit to cover the alignment.
     881       27492 :     if (prev)
     882           0 :       prev->_virtualSize = offset - prev->_offset;
     883             : 
     884             :     prev = section;
     885       27492 :     offset += realSize;
     886             :   }
     887             : 
     888             :   return kErrorOk;
     889             : }
     890             : 
     891       54984 : size_t CodeHolder::codeSize() const noexcept {
     892             :   Support::FastUInt8 of = 0;
     893             :   uint64_t offset = 0;
     894             : 
     895      109968 :   for (Section* section : _sectionsByOrder) {
     896             :     uint64_t realSize = section->realSize();
     897             : 
     898       54984 :     if (realSize) {
     899             :       uint64_t alignedOffset = Support::alignUp(offset, section->alignment());
     900             :       ASMJIT_ASSERT(alignedOffset >= offset);
     901             :       offset = Support::addOverflow(alignedOffset, realSize, &of);
     902             :     }
     903             :   }
     904             : 
     905       54984 :   if ((sizeof(uint64_t) > sizeof(size_t) && offset > SIZE_MAX) || of)
     906           0 :     return SIZE_MAX;
     907             : 
     908             :   return size_t(offset);
     909             : }
     910             : 
     911       27492 : Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept {
     912             :   // Base address must be provided.
     913       27492 :   if (ASMJIT_UNLIKELY(baseAddress == Globals::kNoBaseAddress))
     914             :     return DebugUtils::errored(kErrorInvalidArgument);
     915             : 
     916       27492 :   _baseAddress = baseAddress;
     917             :   uint32_t addressSize = _environment.registerSize();
     918             : 
     919       27492 :   Section* addressTableSection = _addressTableSection;
     920             :   uint32_t addressTableEntryCount = 0;
     921             :   uint8_t* addressTableEntryData = nullptr;
     922             : 
     923       27492 :   if (addressTableSection) {
     924           0 :     ASMJIT_PROPAGATE(
     925             :       reserveBuffer(&addressTableSection->_buffer, size_t(addressTableSection->virtualSize())));
     926             :     addressTableEntryData = addressTableSection->_buffer.data();
     927             :   }
     928             : 
     929             :   // Relocate all recorded locations.
     930       27492 :   for (const RelocEntry* re : _relocations) {
     931             :     // Possibly deleted or optimized-out entry.
     932           0 :     if (re->relocType() == RelocType::kNone)
     933           0 :       continue;
     934             : 
     935             :     Section* sourceSection = sectionById(re->sourceSectionId());
     936             :     Section* targetSection = nullptr;
     937             : 
     938           0 :     if (re->targetSectionId() != Globals::kInvalidId)
     939             :       targetSection = sectionById(re->targetSectionId());
     940             : 
     941           0 :     uint64_t value = re->payload();
     942             :     uint64_t sectionOffset = sourceSection->offset();
     943             :     uint64_t sourceOffset = re->sourceOffset();
     944             : 
     945             :     // Make sure that the `RelocEntry` doesn't go out of bounds.
     946           0 :     size_t regionSize = re->format().regionSize();
     947           0 :     if (ASMJIT_UNLIKELY(re->sourceOffset() >= sourceSection->bufferSize() ||
     948             :                         sourceSection->bufferSize() - size_t(re->sourceOffset()) < regionSize))
     949           0 :       return DebugUtils::errored(kErrorInvalidRelocEntry);
     950             : 
     951             :     uint8_t* buffer = sourceSection->data();
     952             : 
     953           0 :     switch (re->relocType()) {
     954           0 :       case RelocType::kExpression: {
     955           0 :         Expression* expression = (Expression*)(uintptr_t(value));
     956           0 :         ASMJIT_PROPAGATE(CodeHolder_evaluateExpression(this, expression, &value));
     957             :         break;
     958             :       }
     959             : 
     960             :       case RelocType::kAbsToAbs: {
     961             :         break;
     962             :       }
     963             : 
     964           0 :       case RelocType::kRelToAbs: {
     965             :         // Value is currently a relative offset from the start of its section.
     966             :         // We have to convert it to an absolute offset (including base address).
     967           0 :         if (ASMJIT_UNLIKELY(!targetSection))
     968             :           return DebugUtils::errored(kErrorInvalidRelocEntry);
     969             : 
     970             :         //value += baseAddress + sectionOffset + sourceOffset + regionSize;
     971           0 :         value += baseAddress + targetSection->offset();
     972           0 :         break;
     973             :       }
     974             : 
     975           0 :       case RelocType::kAbsToRel: {
     976           0 :         value -= baseAddress + sectionOffset + sourceOffset + regionSize;
     977             : 
     978             :         // Sign extend as we are not interested in the high 32-bit word in a 32-bit address space.
     979           0 :         if (addressSize <= 4)
     980           0 :           value = uint64_t(int64_t(int32_t(value & 0xFFFFFFFFu)));
     981           0 :         else if (!Support::isInt32(int64_t(value)))
     982             :           return DebugUtils::errored(kErrorRelocOffsetOutOfRange);
     983             : 
     984             :         break;
     985             :       }
     986             : 
     987             :       case RelocType::kX64AddressEntry: {
     988           0 :         size_t valueOffset = size_t(re->sourceOffset()) + re->format().valueOffset();
     989           0 :         if (re->format().valueSize() != 4 || valueOffset < 2)
     990             :           return DebugUtils::errored(kErrorInvalidRelocEntry);
     991             : 
     992             :         // First try whether a relative 32-bit displacement would work.
     993           0 :         value -= baseAddress + sectionOffset + sourceOffset + regionSize;
     994           0 :         if (!Support::isInt32(int64_t(value))) {
     995             :           // Relative 32-bit displacement is not possible, use '.addrtab' section.
     996           0 :           AddressTableEntry* atEntry = _addressTableEntries.get(re->payload());
     997           0 :           if (ASMJIT_UNLIKELY(!atEntry))
     998             :             return DebugUtils::errored(kErrorInvalidRelocEntry);
     999             : 
    1000             :           // Cannot be null as we have just matched the `AddressTableEntry`.
    1001             :           ASMJIT_ASSERT(addressTableSection != nullptr);
    1002             : 
    1003           0 :           if (!atEntry->hasAssignedSlot())
    1004           0 :             atEntry->_slot = addressTableEntryCount++;
    1005             : 
    1006           0 :           size_t atEntryIndex = size_t(atEntry->slot()) * addressSize;
    1007           0 :           uint64_t addrSrc = sectionOffset + sourceOffset + regionSize;
    1008           0 :           uint64_t addrDst = addressTableSection->offset() + uint64_t(atEntryIndex);
    1009             : 
    1010           0 :           value = addrDst - addrSrc;
    1011           0 :           if (!Support::isInt32(int64_t(value)))
    1012             :             return DebugUtils::errored(kErrorRelocOffsetOutOfRange);
    1013             : 
    1014             :           // Bytes that replace [REX, OPCODE] bytes.
    1015             :           uint32_t byte0 = 0xFF;
    1016           0 :           uint32_t byte1 = buffer[valueOffset - 1];
    1017             : 
    1018           0 :           if (byte1 == 0xE8) {
    1019             :             // Patch CALL/MOD byte to FF /2 (-> 0x15).
    1020             :             byte1 = x86EncodeMod(0, 2, 5);
    1021             :           }
    1022           0 :           else if (byte1 == 0xE9) {
    1023             :             // Patch JMP/MOD byte to FF /4 (-> 0x25).
    1024             :             byte1 = x86EncodeMod(0, 4, 5);
    1025             :           }
    1026             :           else {
    1027             :             return DebugUtils::errored(kErrorInvalidRelocEntry);
    1028             :           }
    1029             : 
    1030             :           // Patch `jmp/call` instruction.
    1031           0 :           buffer[valueOffset - 2] = uint8_t(byte0);
    1032           0 :           buffer[valueOffset - 1] = uint8_t(byte1);
    1033             : 
    1034           0 :           Support::writeU64uLE(addressTableEntryData + atEntryIndex, re->payload());
    1035             :         }
    1036             :         break;
    1037             :       }
    1038             : 
    1039             :       default:
    1040             :         return DebugUtils::errored(kErrorInvalidRelocEntry);
    1041             :     }
    1042             : 
    1043           0 :     if (!CodeWriterUtils::writeOffset(buffer + re->sourceOffset(), int64_t(value), re->format())) {
    1044             :       return DebugUtils::errored(kErrorInvalidRelocEntry);
    1045             :     }
    1046             :   }
    1047             : 
    1048             :   // Fixup the virtual size of the address table if it's the last section.
    1049       27492 :   if (_sectionsByOrder.last() == addressTableSection) {
    1050             :     ASMJIT_ASSERT(addressTableSection != nullptr);
    1051             : 
    1052           0 :     size_t addressTableSize = addressTableEntryCount * addressSize;
    1053           0 :     addressTableSection->_buffer._size = addressTableSize;
    1054           0 :     addressTableSection->_virtualSize = addressTableSize;
    1055             :   }
    1056             : 
    1057             :   return kErrorOk;
    1058             : }
    1059             : 
    1060           0 : Error CodeHolder::copySectionData(void* dst, size_t dstSize, uint32_t sectionId, CopySectionFlags copyFlags) noexcept {
    1061           0 :   if (ASMJIT_UNLIKELY(!isSectionValid(sectionId)))
    1062             :     return DebugUtils::errored(kErrorInvalidSection);
    1063             : 
    1064             :   Section* section = sectionById(sectionId);
    1065             :   size_t bufferSize = section->bufferSize();
    1066             : 
    1067           0 :   if (ASMJIT_UNLIKELY(dstSize < bufferSize))
    1068             :     return DebugUtils::errored(kErrorInvalidArgument);
    1069             : 
    1070             :   memcpy(dst, section->data(), bufferSize);
    1071             : 
    1072           0 :   if (bufferSize < dstSize && Support::test(copyFlags, CopySectionFlags::kPadSectionBuffer)) {
    1073           0 :     size_t paddingSize = dstSize - bufferSize;
    1074           0 :     memset(static_cast<uint8_t*>(dst) + bufferSize, 0, paddingSize);
    1075             :   }
    1076             : 
    1077             :   return kErrorOk;
    1078             : }
    1079             : 
    1080           0 : Error CodeHolder::copyFlattenedData(void* dst, size_t dstSize, CopySectionFlags copyFlags) noexcept {
    1081             :   size_t end = 0;
    1082           0 :   for (Section* section : _sectionsByOrder) {
    1083           0 :     if (section->offset() > dstSize)
    1084             :       return DebugUtils::errored(kErrorInvalidArgument);
    1085             : 
    1086             :     size_t bufferSize = section->bufferSize();
    1087             :     size_t offset = size_t(section->offset());
    1088             : 
    1089           0 :     if (ASMJIT_UNLIKELY(dstSize - offset < bufferSize))
    1090             :       return DebugUtils::errored(kErrorInvalidArgument);
    1091             : 
    1092           0 :     uint8_t* dstTarget = static_cast<uint8_t*>(dst) + offset;
    1093             :     size_t paddingSize = 0;
    1094             :     memcpy(dstTarget, section->data(), bufferSize);
    1095             : 
    1096           0 :     if (Support::test(copyFlags, CopySectionFlags::kPadSectionBuffer) && bufferSize < section->virtualSize()) {
    1097           0 :       paddingSize = Support::min<size_t>(dstSize - offset, size_t(section->virtualSize())) - bufferSize;
    1098           0 :       memset(dstTarget + bufferSize, 0, paddingSize);
    1099             :     }
    1100             : 
    1101           0 :     end = Support::max(end, offset + bufferSize + paddingSize);
    1102             :   }
    1103             : 
    1104           0 :   if (end < dstSize && Support::test(copyFlags, CopySectionFlags::kPadTargetBuffer)) {
    1105           0 :     memset(static_cast<uint8_t*>(dst) + end, 0, dstSize - end);
    1106             :   }
    1107             : 
    1108             :   return kErrorOk;
    1109             : }
    1110             : 
    1111             : // CodeHolder - Tests
    1112             : // ==================
    1113             : 
    1114             : #if defined(ASMJIT_TEST)
    1115             : UNIT(code_holder) {
    1116             :   CodeHolder code;
    1117             : 
    1118             :   INFO("Verifying CodeHolder::init()");
    1119             :   Environment env;
    1120             :   env.init(Arch::kX86);
    1121             : 
    1122             :   code.init(env);
    1123             :   EXPECT(code.arch() == Arch::kX86);
    1124             : 
    1125             :   INFO("Verifying named labels");
    1126             :   LabelEntry* le;
    1127             :   EXPECT(code.newNamedLabelEntry(&le, "NamedLabel", SIZE_MAX, LabelType::kGlobal) == kErrorOk);
    1128             :   EXPECT(strcmp(le->name(), "NamedLabel") == 0);
    1129             :   EXPECT(code.labelIdByName("NamedLabel") == le->id());
    1130             : 
    1131             :   INFO("Verifying section ordering");
    1132             :   Section* section1;
    1133             :   EXPECT(code.newSection(&section1, "high-priority", SIZE_MAX, SectionFlags::kNone, 1, -1) == kErrorOk);
    1134             :   EXPECT(code.sections()[1] == section1);
    1135             :   EXPECT(code.sectionsByOrder()[0] == section1);
    1136             : 
    1137             :   Section* section0;
    1138             :   EXPECT(code.newSection(&section0, "higher-priority", SIZE_MAX, SectionFlags::kNone, 1, -2) == kErrorOk);
    1139             :   EXPECT(code.sections()[2] == section0);
    1140             :   EXPECT(code.sectionsByOrder()[0] == section0);
    1141             :   EXPECT(code.sectionsByOrder()[1] == section1);
    1142             : 
    1143             :   Section* section3;
    1144             :   EXPECT(code.newSection(&section3, "low-priority", SIZE_MAX, SectionFlags::kNone, 1, 2) == kErrorOk);
    1145             :   EXPECT(code.sections()[3] == section3);
    1146             :   EXPECT(code.sectionsByOrder()[3] == section3);
    1147             : }
    1148             : #endif
    1149             : 
    1150             : ASMJIT_END_NAMESPACE
    1151             : 
    1152             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16