+
+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;
+}
+
+
+