diff --git a/lld/MachO/UnwindInfoSection.h b/lld/MachO/UnwindInfoSection.h --- a/lld/MachO/UnwindInfoSection.h +++ b/lld/MachO/UnwindInfoSection.h @@ -23,19 +23,16 @@ // If all functions are free of unwind info, we can omit the unwind info // section entirely. bool isNeeded() const override { return !allEntriesAreOmitted; } - uint64_t getSize() const override { return unwindInfoSize; } void addSymbol(const Defined *); - void prepareRelocations(); + virtual void prepareRelocations() = 0; protected: UnwindInfoSection(); - virtual void prepareRelocations(ConcatInputSection *) = 0; llvm::MapVector, const Defined *> symbols; std::vector symbolsVec; - uint64_t unwindInfoSize = 0; bool allEntriesAreOmitted = true; }; diff --git a/lld/MachO/UnwindInfoSection.cpp b/lld/MachO/UnwindInfoSection.cpp --- a/lld/MachO/UnwindInfoSection.cpp +++ b/lld/MachO/UnwindInfoSection.cpp @@ -95,14 +95,44 @@ // TODO(gkm): prune __eh_frame entries superseded by __unwind_info, PR50410 // TODO(gkm): how do we align the 2nd-level pages? -template struct CompactUnwindLayout { - Ptr functionAddress; +// The offsets of various fields in the on-disk representation of each compact +// unwind entry. +struct CompactUnwindOffsets { + uint32_t functionAddress; uint32_t functionLength; - compact_unwind_encoding_t encoding; - Ptr personality; - Ptr lsda; + uint32_t encoding; + uint32_t personality; + uint32_t lsda; +#define SET_OFFSET(Ptr, x) this->x = offsetof(Layout, x) + CompactUnwindOffsets(size_t wordSize) { + if (wordSize == 8) { + SET_OFFSET(uint64_t, functionAddress); + SET_OFFSET(uint64_t, functionLength); + SET_OFFSET(uint64_t, encoding); + SET_OFFSET(uint64_t, personality); + SET_OFFSET(uint64_t, lsda); + } else { + assert(wordSize == 4); + SET_OFFSET(uint32_t, functionAddress); + SET_OFFSET(uint32_t, functionLength); + SET_OFFSET(uint32_t, encoding); + SET_OFFSET(uint32_t, personality); + SET_OFFSET(uint32_t, lsda); + } + } +#undef SET_OFFSET + + private: + template struct Layout { + Ptr functionAddress; + uint32_t functionLength; + compact_unwind_encoding_t encoding; + Ptr personality; + Ptr lsda; + }; }; +// LLD's internal representation of a compact unwind entry. struct CompactUnwindEntry { uint64_t functionAddress; uint32_t functionLength; @@ -122,16 +152,24 @@ EncodingMap localEncodingIndexes; }; -template +// UnwindInfoSectionImpl allows us to avoid cluttering our header file with a +// lengthy definition of UnwindInfoSection. class UnwindInfoSectionImpl final : public UnwindInfoSection { public: - void prepareRelocations(ConcatInputSection *) override; - void relocateCompactUnwind(std::vector &); - void encodePersonalities(); + UnwindInfoSectionImpl() : cuOffsets(target->wordSize) {} + uint64_t getSize() const override { return unwindInfoSize; } + void prepareRelocations() override; void finalize() override; void writeTo(uint8_t *buf) const override; private: + void prepareRelocations(ConcatInputSection *); + void relocateCompactUnwind(std::vector &); + void encodePersonalities(); + + uint64_t unwindInfoSize = 0; + std::vector symbolsVec; + CompactUnwindOffsets cuOffsets; std::vector> commonEncodings; EncodingMap commonEncodingIndexes; // The entries here will be in the same order as their originating symbols @@ -155,15 +193,6 @@ align = 4; } -void UnwindInfoSection::prepareRelocations() { - // This iteration needs to be deterministic, since prepareRelocations may add - // entries to the GOT. Hence the use of a MapVector for - // UnwindInfoSection::symbols. - for (const Defined *d : make_second_range(symbols)) - if (d->unwindEntry) - prepareRelocations(d->unwindEntry); -} - // Record function symbols that may need entries emitted in __unwind_info, which // stores unwind data for address ranges. // @@ -189,13 +218,21 @@ } } +void UnwindInfoSectionImpl::prepareRelocations() { + // This iteration needs to be deterministic, since prepareRelocations may add + // entries to the GOT. Hence the use of a MapVector for + // UnwindInfoSection::symbols. + for (const Defined *d : make_second_range(symbols)) + if (d->unwindEntry) + prepareRelocations(d->unwindEntry); +} + // Compact unwind relocations have different semantics, so we handle them in a // separate code path from regular relocations. First, we do not wish to add // rebase opcodes for __LD,__compact_unwind, because that section doesn't // actually end up in the final binary. Second, personality pointers always // reside in the GOT and must be treated specially. -template -void UnwindInfoSectionImpl::prepareRelocations(ConcatInputSection *isec) { +void UnwindInfoSectionImpl::prepareRelocations(ConcatInputSection *isec) { assert(!isec->shouldOmitFromOutput() && "__compact_unwind section should not be omitted"); @@ -212,7 +249,7 @@ // compact unwind entries that references them, and thus appear as section // relocs. There is no need to prepare them. We only prepare relocs for // personality functions. - if (r.offset != offsetof(CompactUnwindLayout, personality)) + if (r.offset != cuOffsets.personality) continue; if (auto *s = r.referent.dyn_cast()) { @@ -284,8 +321,7 @@ // before converting it to post-link form. There should only be absolute // relocations here: since we are not emitting the pre-link CU section, there // is no source address to make a relative location meaningful. -template -void UnwindInfoSectionImpl::relocateCompactUnwind( +void UnwindInfoSectionImpl::relocateCompactUnwind( std::vector &cuEntries) { parallelForEachN(0, symbolsVec.size(), [&](size_t i) { CompactUnwindEntry &cu = cuEntries[i]; @@ -295,15 +331,14 @@ return; auto buf = reinterpret_cast(d->unwindEntry->data.data()) - - sizeof(Ptr); - cu.functionLength = support::endian::read32le( - buf + offsetof(CompactUnwindLayout, functionLength)); - cu.encoding = support::endian::read32le( - buf + offsetof(CompactUnwindLayout, encoding)); + target->wordSize; + cu.functionLength = + support::endian::read32le(buf + cuOffsets.functionLength); + cu.encoding = support::endian::read32le(buf + cuOffsets.encoding); for (const Reloc &r : d->unwindEntry->relocs) { - if (r.offset == offsetof(CompactUnwindLayout, personality)) { + if (r.offset == cuOffsets.personality) { cu.personality = r.referent.get(); - } else if (r.offset == offsetof(CompactUnwindLayout, lsda)) { + } else if (r.offset == cuOffsets.lsda) { if (auto *referentSym = r.referent.dyn_cast()) cu.lsda = cast(referentSym)->isec; else @@ -315,7 +350,7 @@ // There should only be a handful of unique personality pointers, so we can // encode them as 2-bit indices into a small array. -template void UnwindInfoSectionImpl::encodePersonalities() { +void UnwindInfoSectionImpl::encodePersonalities() { for (size_t idx : cuIndices) { CompactUnwindEntry &cu = cuEntries[idx]; if (cu.personality == nullptr) @@ -365,7 +400,7 @@ // Scan the __LD,__compact_unwind entries and compute the space needs of // __TEXT,__unwind_info and __TEXT,__eh_frame. -template void UnwindInfoSectionImpl::finalize() { +void UnwindInfoSectionImpl::finalize() { if (symbols.empty()) return; @@ -519,8 +554,7 @@ // All inputs are relocated and output addresses are known, so write! -template -void UnwindInfoSectionImpl::writeTo(uint8_t *buf) const { +void UnwindInfoSectionImpl::writeTo(uint8_t *buf) const { assert(!cuIndices.empty() && "call only if there is unwind info"); // section header @@ -630,8 +664,5 @@ } UnwindInfoSection *macho::makeUnwindInfoSection() { - if (target->wordSize == 8) - return make>(); - else - return make>(); + return make(); }