#include <unistd.h>
#include <vector>
+#include <unordered_map>
#include "Options.h"
#include "ld.hpp"
#include "Architectures.hpp"
#include "MachOFileAbstraction.hpp"
+#include "code-sign-blobs/superblob.h"
namespace ld {
namespace tool {
while( more );
}
+ void append_delta_encoded_uleb128_run(uint64_t start, const std::vector<uint64_t>& locations) {
+ uint64_t lastAddr = start;
+ for(std::vector<uint64_t>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
+ uint64_t nextAddr = *it;
+ uint64_t delta = nextAddr - lastAddr;
+ assert(delta != 0);
+ append_uleb128(delta);
+ lastAddr = nextAddr;
+ }
+ }
+
void append_string(const char* str) {
for (const char* s = str; *s != '\0'; ++s)
_data.push_back(*s);
// overrides of ld::Atom
virtual ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual uint64_t objectAddress() const { return 0; }
virtual uint64_t size() const;
virtual void copyRawContent(uint8_t buffer[]) const;
}
mid.push_back(rebase_tmp(REBASE_OPCODE_DO_REBASE_ULEB_TIMES, 1));
address += sizeof(pint_t);
+ if ( address >= curSegEnd )
+ address = 0;
}
mid.push_back(rebase_tmp(REBASE_OPCODE_DONE, 0));
std::vector<const ld::Atom*>& exports = this->_writer._exportedAtoms;
uint64_t imageBaseAddress = this->_writer.headerAndLoadCommandsSection->address;
std::vector<mach_o::trie::Entry> entries;
+ unsigned int padding = 0;
entries.reserve(exports.size());
for (std::vector<const ld::Atom*>::const_iterator it = exports.begin(); it != exports.end(); ++it) {
const ld::Atom* atom = *it;
uint64_t flags = (atom->contentType() == ld::Atom::typeTLV) ? EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL : EXPORT_SYMBOL_FLAGS_KIND_REGULAR;
uint64_t other = 0;
uint64_t address = atom->finalAddress() - imageBaseAddress;
- if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) )
- flags |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
if ( atom->definition() == ld::Atom::definitionProxy ) {
entry.name = atom->name();
entry.flags = flags | EXPORT_SYMBOL_FLAGS_REEXPORT;
+ if ( atom->combine() == ld::Atom::combineByName )
+ entry.flags |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
entry.other = this->_writer.compressedOrdinalForAtom(atom);
if ( entry.other == BIND_SPECIAL_DYLIB_SELF ) {
- warning("not adding explict export for symbol %s because it is already re-exported from dylib %s", entry.name, atom->file()->path());
+ warning("not adding explict export for symbol %s because it is already re-exported from dylib %s", entry.name, atom->safeFilePath());
continue;
}
if ( atom->isAlias() ) {
entries.push_back(entry);
//fprintf(stderr, "re-export %s from lib %llu as %s\n", entry.importName, entry.other, entry.name);
}
+ else if ( atom->definition() == ld::Atom::definitionAbsolute ) {
+ entry.name = atom->name();
+ entry.flags = _options.canUseAbsoluteSymbols() ? EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE : EXPORT_SYMBOL_FLAGS_KIND_REGULAR;
+ entry.address = address;
+ entry.other = other;
+ entry.importName = NULL;
+ entries.push_back(entry);
+ }
else {
+ if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) )
+ flags |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
if ( atom->isThumb() )
address |= 1;
if ( atom->contentType() == ld::Atom::typeResolver ) {
entry.importName = NULL;
entries.push_back(entry);
}
+
+ if (_options.sharedRegionEligible() && strncmp(atom->section().segmentName(), "__DATA", 6) == 0) {
+ // Maximum address is 64bit which is 10 bytes as a uleb128. Minimum is 1 byte
+ // Pad the section out so we can deal with addresses getting larger when __DATA segment
+ // is moved before __TEXT in dyld shared cache.
+ padding += 9;
+ }
}
// sort vector by -exported_symbols_order, and any others by address
// create trie
mach_o::trie::makeTrie(entries, this->_encodedData.bytes());
+ //Add additional data padding for the unoptimized shared cache
+ for (unsigned int i = 0; i < padding; ++i)
+ this->_encodedData.append_byte(0);
+
// align to pointer size
this->_encodedData.pad_to_size(sizeof(pint_t));
template <typename A>
-class SplitSegInfoAtom : public LinkEditAtom
+class SplitSegInfoV1Atom : public LinkEditAtom
{
public:
- SplitSegInfoAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+ SplitSegInfoV1Atom(const Options& opts, ld::Internal& state, OutputFile& writer)
: LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
// overrides of ld::Atom
mutable std::vector<uint64_t> _thumbHi16Locations[16];
mutable std::vector<uint64_t> _armLo16Locations;
mutable std::vector<uint64_t> _armHi16Locations[16];
+ mutable std::vector<uint64_t> _adrpLocations;
static ld::Section _s_section;
};
template <typename A>
-ld::Section SplitSegInfoAtom<A>::_s_section("__LINKEDIT", "__splitSegInfo", ld::Section::typeLinkEdit, true);
+ld::Section SplitSegInfoV1Atom<A>::_s_section("__LINKEDIT", "__splitSegInfo", ld::Section::typeLinkEdit, true);
template <>
-void SplitSegInfoAtom<x86_64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
+void SplitSegInfoV1Atom<x86_64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
{
switch (kind) {
case ld::Fixup::kindStoreX86PCRel32:
case ld::Fixup::kindStoreTargetAddressX86PCRel32:
case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
_32bitPointerLocations.push_back(address);
break;
case ld::Fixup::kindStoreLittleEndian64:
}
template <>
-void SplitSegInfoAtom<x86>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
+void SplitSegInfoV1Atom<x86>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
{
switch (kind) {
case ld::Fixup::kindStoreLittleEndian32:
case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+ case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+ case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA:
_32bitPointerLocations.push_back(address);
break;
default:
}
template <>
-void SplitSegInfoAtom<arm>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
+void SplitSegInfoV1Atom<arm>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
{
switch (kind) {
case ld::Fixup::kindStoreLittleEndian32:
}
}
-
+#if SUPPORT_ARCH_arm64
+template <>
+void SplitSegInfoV1Atom<arm64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
+{
+ switch (kind) {
+ case ld::Fixup::kindStoreARM64Page21:
+ case ld::Fixup::kindStoreARM64GOTLoadPage21:
+ case ld::Fixup::kindStoreARM64GOTLeaPage21:
+ case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+ case ld::Fixup::kindStoreTargetAddressARM64Page21:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+ _adrpLocations.push_back(address);
+ break;
+ case ld::Fixup::kindStoreLittleEndian32:
+ case ld::Fixup::kindStoreARM64PCRelToGOT:
+ _32bitPointerLocations.push_back(address);
+ break;
+ case ld::Fixup::kindStoreLittleEndian64:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+ _64bitPointerLocations.push_back(address);
+ break;
+ default:
+ warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address);
+ break;
+ }
+}
+#endif
template <typename A>
-void SplitSegInfoAtom<A>::uleb128EncodeAddresses(const std::vector<uint64_t>& locations) const
+void SplitSegInfoV1Atom<A>::uleb128EncodeAddresses(const std::vector<uint64_t>& locations) const
{
pint_t addr = this->_options.baseAddress();
for(typename std::vector<uint64_t>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
template <typename A>
-void SplitSegInfoAtom<A>::encode() const
+void SplitSegInfoV1Atom<A>::encode() const
{
// sort into group by pointer adjustment kind
std::vector<OutputFile::SplitSegInfoEntry>& info = this->_writer._splitSegInfos;
for (std::vector<OutputFile::SplitSegInfoEntry>::const_iterator it = info.begin(); it != info.end(); ++it) {
- this->addSplitSegInfo(it->address, it->kind, it->extra);
+ this->addSplitSegInfo(it->fixupAddress, it->kind, it->extra);
}
// delta compress runs of addresses
this->_encodedData.append_byte(0); // terminator
}
+ if ( _adrpLocations.size() != 0 ) {
+ this->_encodedData.append_byte(3);
+ //fprintf(stderr, "type 3:\n");
+ std::sort(_adrpLocations.begin(), _adrpLocations.end());
+ this->uleb128EncodeAddresses(_adrpLocations);
+ this->_encodedData.append_byte(0); // terminator
+ }
+
if ( _thumbLo16Locations.size() != 0 ) {
this->_encodedData.append_byte(5);
//fprintf(stderr, "type 5:\n");
}
+template <typename A>
+class SplitSegInfoV2Atom : public LinkEditAtom
+{
+public:
+ SplitSegInfoV2Atom(const Options& opts, ld::Internal& state, OutputFile& writer)
+ : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+ // overrides of ld::Atom
+ virtual const char* name() const { return "split seg info"; }
+ // overrides of LinkEditAtom
+ virtual void encode() const;
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ // Whole :== <count> FromToSection+
+ // FromToSection :== <from-sect-index> <to-sect-index> <count> ToOffset+
+ // ToOffset :== <to-sect-offset-delta> <count> FromOffset+
+ // FromOffset :== <kind> <count> <from-sect-offset-delta>
+
+ typedef uint32_t SectionIndexes;
+ typedef std::map<uint8_t, std::vector<uint64_t> > FromOffsetMap;
+ typedef std::map<uint64_t, FromOffsetMap> ToOffsetMap;
+ typedef std::map<SectionIndexes, ToOffsetMap> WholeMap;
+
+
+ static ld::Section _s_section;
+};
+
+template <typename A>
+ld::Section SplitSegInfoV2Atom<A>::_s_section("__LINKEDIT", "__splitSegInfo", ld::Section::typeLinkEdit, true);
+
+
+template <typename A>
+void SplitSegInfoV2Atom<A>::encode() const
+{
+ // sort into group by adjustment kind
+ //fprintf(stderr, "_splitSegV2Infos.size=%lu\n", this->_writer._splitSegV2Infos.size());
+ WholeMap whole;
+ for (const OutputFile::SplitSegInfoV2Entry& entry : this->_writer._splitSegV2Infos) {
+ //fprintf(stderr, "from=%d, to=%d\n", entry.fixupSectionIndex, entry.targetSectionIndex);
+ SectionIndexes index = entry.fixupSectionIndex << 16 | entry.targetSectionIndex;
+ ToOffsetMap& toOffsets = whole[index];
+ FromOffsetMap& fromOffsets = toOffsets[entry.targetSectionOffset];
+ fromOffsets[entry.referenceKind].push_back(entry.fixupSectionOffset);
+ }
+
+ // Add marker that this is V2 data
+ this->_encodedData.reserve(8192);
+ this->_encodedData.append_byte(DYLD_CACHE_ADJ_V2_FORMAT);
+
+ // stream out
+ // Whole :== <count> FromToSection+
+ this->_encodedData.append_uleb128(whole.size());
+ for (auto& fromToSection : whole) {
+ uint8_t fromSectionIndex = fromToSection.first >> 16;
+ uint8_t toSectionIndex = fromToSection.first & 0xFFFF;
+ ToOffsetMap& toOffsets = fromToSection.second;
+ // FromToSection :== <from-sect-index> <to-sect-index> <count> ToOffset+
+ this->_encodedData.append_uleb128(fromSectionIndex);
+ this->_encodedData.append_uleb128(toSectionIndex);
+ this->_encodedData.append_uleb128(toOffsets.size());
+ //fprintf(stderr, "from sect=%d, to sect=%d, count=%lu\n", fromSectionIndex, toSectionIndex, toOffsets.size());
+ uint64_t lastToOffset = 0;
+ for (auto& fromToOffsets : toOffsets) {
+ uint64_t toSectionOffset = fromToOffsets.first;
+ FromOffsetMap& fromOffsets = fromToOffsets.second;
+ // ToOffset :== <to-sect-offset-delta> <count> FromOffset+
+ this->_encodedData.append_uleb128(toSectionOffset - lastToOffset);
+ this->_encodedData.append_uleb128(fromOffsets.size());
+ for (auto& kindAndOffsets : fromOffsets) {
+ uint8_t kind = kindAndOffsets.first;
+ std::vector<uint64_t>& fromOffsets = kindAndOffsets.second;
+ // FromOffset :== <kind> <count> <from-sect-offset-delta>
+ this->_encodedData.append_uleb128(kind);
+ this->_encodedData.append_uleb128(fromOffsets.size());
+ std::sort(fromOffsets.begin(), fromOffsets.end());
+ uint64_t lastFromOffset = 0;
+ for (uint64_t offset : fromOffsets) {
+ this->_encodedData.append_uleb128(offset - lastFromOffset);
+ lastFromOffset = offset;
+ }
+ }
+ lastToOffset = toSectionOffset;
+ }
+ }
+
+
+ // always add zero byte to mark end
+ this->_encodedData.append_byte(0);
+
+ // align to pointer size
+ this->_encodedData.pad_to_size(sizeof(pint_t));
+
+ this->_encoded = true;
+}
+
+
+
template <typename A>
class FunctionStartsAtom : public LinkEditAtom
{
void FunctionStartsAtom<A>::encode() const
{
this->_encodedData.reserve(8192);
- const uint64_t badAddress = 1;
+ const uint64_t badAddress = 0xFFFFFFFFFFFFFFFF;
uint64_t addr = badAddress;
// delta compress all function addresses
for (std::vector<ld::Internal::FinalSection*>::iterator it = this->_state.sections.begin(); it != this->_state.sections.end(); ++it) {
std::vector<const ld::Atom*>& atoms = sect->atoms;
for (std::vector<const ld::Atom*>::iterator ait = atoms.begin(); ait != atoms.end(); ++ait) {
const ld::Atom* atom = *ait;
+ // <rdar://problem/10422823> filter out zero-length atoms, so LC_FUNCTION_STARTS address can't spill into next section
+ if ( atom->size() == 0 )
+ continue;
uint64_t nextAddr = atom->finalAddress();
if ( atom->isThumb() )
nextAddr |= 1;
}
+// <rdar://problem/9218847> Need way to formalize data in code
+template <typename A>
+class DataInCodeAtom : public LinkEditAtom
+{
+public:
+ DataInCodeAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+ : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+ // overrides of ld::Atom
+ virtual const char* name() const { return "data-in-code info"; }
+ // overrides of LinkEditAtom
+ virtual void encode() const;
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ struct FixupByAddressSorter
+ {
+ bool operator()(const ld::Fixup* left, const ld::Fixup* right)
+ {
+ return (left->offsetInAtom < right->offsetInAtom);
+ }
+ };
+
+ void encodeEntry(uint32_t startImageOffset, int len, ld::Fixup::Kind kind) const {
+ //fprintf(stderr, "encodeEntry(start=0x%08X, len=0x%04X, kind=%04X\n", startImageOffset, len, kind);
+ do {
+ macho_data_in_code_entry<P> entry;
+ entry.set_offset(startImageOffset);
+ entry.set_length(len);
+ switch ( kind ) {
+ case ld::Fixup::kindDataInCodeStartData:
+ entry.set_kind(DICE_KIND_DATA);
+ break;
+ case ld::Fixup::kindDataInCodeStartJT8:
+ entry.set_kind(DICE_KIND_JUMP_TABLE8);
+ break;
+ case ld::Fixup::kindDataInCodeStartJT16:
+ entry.set_kind(DICE_KIND_JUMP_TABLE16);
+ break;
+ case ld::Fixup::kindDataInCodeStartJT32:
+ entry.set_kind(DICE_KIND_JUMP_TABLE32);
+ break;
+ case ld::Fixup::kindDataInCodeStartJTA32:
+ entry.set_kind(DICE_KIND_ABS_JUMP_TABLE32);
+ break;
+ default:
+ assert(0 && "bad L$start$ label to encode");
+ }
+ uint8_t* bp = (uint8_t*)&entry;
+ this->_encodedData.append_byte(bp[0]);
+ this->_encodedData.append_byte(bp[1]);
+ this->_encodedData.append_byte(bp[2]);
+ this->_encodedData.append_byte(bp[3]);
+ this->_encodedData.append_byte(bp[4]);
+ this->_encodedData.append_byte(bp[5]);
+ this->_encodedData.append_byte(bp[6]);
+ this->_encodedData.append_byte(bp[7]);
+ // in rare case data range is huge, create multiple entries
+ len -= 0xFFF8;
+ startImageOffset += 0xFFF8;
+ } while ( len > 0 );
+ }
+
+ static ld::Section _s_section;
+};
+
+template <typename A>
+ld::Section DataInCodeAtom<A>::_s_section("__LINKEDIT", "__dataInCode", ld::Section::typeLinkEdit, true);
+
+
+template <typename A>
+void DataInCodeAtom<A>::encode() const
+{
+ if ( this->_writer.hasDataInCode ) {
+ uint64_t mhAddress = 0;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = _state.sections.begin(); sit != _state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->type() == ld::Section::typeMachHeader )
+ mhAddress = sect->address;
+ if ( sect->type() != ld::Section::typeCode )
+ continue;
+ for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ // gather all code-in-data labels
+ std::vector<const ld::Fixup*> dataInCodeLabels;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+ switch ( fit->kind ) {
+ case ld::Fixup::kindDataInCodeStartData:
+ case ld::Fixup::kindDataInCodeStartJT8:
+ case ld::Fixup::kindDataInCodeStartJT16:
+ case ld::Fixup::kindDataInCodeStartJT32:
+ case ld::Fixup::kindDataInCodeStartJTA32:
+ case ld::Fixup::kindDataInCodeEnd:
+ dataInCodeLabels.push_back(fit);
+ break;
+ default:
+ break;
+ }
+ }
+ // to do: sort labels by address
+ std::sort(dataInCodeLabels.begin(), dataInCodeLabels.end(), FixupByAddressSorter());
+
+ // convert to array of struct data_in_code_entry
+ ld::Fixup::Kind prevKind = ld::Fixup::kindDataInCodeEnd;
+ uint32_t prevOffset = 0;
+ for ( std::vector<const ld::Fixup*>::iterator sfit = dataInCodeLabels.begin(); sfit != dataInCodeLabels.end(); ++sfit) {
+ if ( ((*sfit)->kind != prevKind) && (prevKind != ld::Fixup::kindDataInCodeEnd) ) {
+ int len = (*sfit)->offsetInAtom - prevOffset;
+ if ( len == 0 )
+ warning("multiple L$start$ labels found at same address in %s at offset 0x%04X", atom->name(), prevOffset);
+ this->encodeEntry(atom->finalAddress()+prevOffset-mhAddress, (*sfit)->offsetInAtom - prevOffset, prevKind);
+ }
+ prevKind = (*sfit)->kind;
+ prevOffset = (*sfit)->offsetInAtom;
+ }
+ if ( prevKind != ld::Fixup::kindDataInCodeEnd ) {
+ // add entry if function ends with data
+ this->encodeEntry(atom->finalAddress()+prevOffset-mhAddress, atom->size() - prevOffset, prevKind);
+ }
+ }
+ }
+ }
+
+ this->_encoded = true;
+}
+
+
+
+
+
+
+template <typename A>
+class OptimizationHintsAtom : public LinkEditAtom
+{
+public:
+ OptimizationHintsAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+ : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) {
+ assert(opts.outputKind() == Options::kObjectFile);
+ }
+
+ // overrides of ld::Atom
+ virtual const char* name() const { return "linker optimization hints"; }
+ // overrides of LinkEditAtom
+ virtual void encode() const;
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ static ld::Section _s_section;
+
+};
+
+template <typename A>
+ld::Section OptimizationHintsAtom<A>::_s_section("__LINKEDIT", "__opt_hints", ld::Section::typeLinkEdit, true);
+
+template <typename A>
+void OptimizationHintsAtom<A>::encode() const
+{
+ if ( _state.someObjectHasOptimizationHints ) {
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = _state.sections.begin(); sit != _state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->type() != ld::Section::typeCode )
+ continue;
+ for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ uint64_t address = atom->finalAddress();
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+ if ( fit->kind != ld::Fixup::kindLinkerOptimizationHint)
+ continue;
+ ld::Fixup::LOH_arm64 extra;
+ extra.addend = fit->u.addend;
+ _encodedData.append_uleb128(extra.info.kind);
+ _encodedData.append_uleb128(extra.info.count+1);
+ _encodedData.append_uleb128((extra.info.delta1 << 2) + fit->offsetInAtom + address);
+ if ( extra.info.count > 0 )
+ _encodedData.append_uleb128((extra.info.delta2 << 2) + fit->offsetInAtom + address);
+ if ( extra.info.count > 1 )
+ _encodedData.append_uleb128((extra.info.delta3 << 2) + fit->offsetInAtom + address);
+ if ( extra.info.count > 2 )
+ _encodedData.append_uleb128((extra.info.delta4 << 2) + fit->offsetInAtom + address);
+ }
+ }
+ }
+
+ this->_encodedData.pad_to_size(sizeof(pint_t));
+ }
+
+ this->_encoded = true;
+}
+
} // namespace tool
} // namespace ld