diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -604,19 +604,18 @@ // https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg // For more details, see the comment in RelrSection::updateAllocSize(). template class RelrSection final : public RelrBaseSection { - using Elf_Relr = typename ELFT::Relr; + using uint = typename ELFT::uint; public: RelrSection(); bool updateAllocSize() override; - size_t getSize() const override { return relrRelocs.size() * this->entsize; } - void writeTo(uint8_t *buf) override { - memcpy(buf, relrRelocs.data(), getSize()); - } + size_t getSize() const override { return size * this->entsize; } + void writeTo(uint8_t *buf) override; private: - SmallVector relrRelocs; + SmallVector>, 0> vec; + size_t size = 0; }; struct SymbolTableEntry { diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -2015,9 +2015,6 @@ // even means address, odd means bitmap. // 2. Just a simple list of addresses is a valid encoding. - size_t oldSize = relrRelocs.size(); - relrRelocs.clear(); - // Same as Config->Wordsize but faster because this is a compile-time // constant. const size_t wordsize = sizeof(typename ELFT::uint); @@ -2026,57 +2023,63 @@ // Must be either 63 or 31. const size_t nBits = wordsize * 8 - 1; - // Get offsets for all relative relocations and sort them. - std::vector offsets; - for (const RelativeReloc &rel : relocs) - offsets.push_back(rel.getOffset()); - llvm::sort(offsets); + const size_t oldSize = size; + size = 0; + vec.clear(); + SmallVector offsets; + for (size_t i = 0, e = relocs.size(); i != e;) { + const OutputSection *osec = relocs[i].inputSec->getOutputSection(); + do + offsets.push_back(relocs[i].inputSec->getOffset(relocs[i].offsetInSec)); + while (++i != e && relocs[i].inputSec->getOutputSection() == osec); + llvm::sort(offsets); - // For each leading relocation, find following ones that can be folded - // as a bitmap and fold them. - for (size_t i = 0, e = offsets.size(); i < e;) { - // Add a leading relocation. - relrRelocs.push_back(Elf_Relr(offsets[i])); - uint64_t base = offsets[i] + wordsize; - ++i; + SmallVector entries; + for (size_t j = 0, end = offsets.size(); j != end;) { + entries.push_back(offsets[j]); + uint64_t base = offsets[j] + wordsize; + ++j; - // Find foldable relocations to construct bitmaps. - while (i < e) { - uint64_t bitmap = 0; - - while (i < e) { - uint64_t delta = offsets[i] - base; - - // If it is too far, it cannot be folded. - if (delta >= nBits * wordsize) + for (;;) { + uint64_t bitmap = 0; + for (; j != end; ++j) { + uint64_t d = offsets[j] - base; + if (d >= nBits * wordsize || d % wordsize) + break; + bitmap |= uint64_t(1) << (d / wordsize); + } + if (!bitmap) break; - - // If it is not a multiple of wordsize away, it cannot be folded. - if (delta % wordsize) - break; - - // Fold it. - bitmap |= 1ULL << (delta / wordsize); - ++i; + entries.push_back((bitmap << 1) | 1); + base += nBits * wordsize; } - - if (!bitmap) - break; - - relrRelocs.push_back(Elf_Relr((bitmap << 1) | 1)); - base += nBits * wordsize; } + + size += entries.size(); + vec.emplace_back(osec, std::move(entries)); + offsets.clear(); } // Don't allow the section to shrink; otherwise the size of the section can // oscillate infinitely. Trailing 1s do not decode to more relocations. - if (relrRelocs.size() < oldSize) { - log(".relr.dyn needs " + Twine(oldSize - relrRelocs.size()) + - " padding word(s)"); - relrRelocs.resize(oldSize, Elf_Relr(1)); + if (size < oldSize) { + log(".relr.dyn needs " + Twine(oldSize - size) + " padding word(s)"); + size = oldSize; } + return size != oldSize; +} - return relrRelocs.size() != oldSize; +template void RelrSection::writeTo(uint8_t *buf) { + auto *out = reinterpret_cast(buf); + for (const auto &v : vec) { + uint64_t addr = v.first->addr; + for (uint entry : v.second) + *out++ = entry & 1 ? entry : addr + entry; + size -= v.second.size(); + } + // See the comment above. + for (; size; --size) + *out++ = 1; } SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &strTabSec) diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1656,8 +1656,18 @@ for (Partition &part : partitions) { changed |= part.relaDyn->updateAllocSize(); - if (part.relrDyn) - changed |= part.relrDyn->updateAllocSize(); + + // OutptSection address addition in .relr.dyn's computation is delayed to + // writeTo. RelrSection::vec is fixed (no need to call updateAllocSize + // again) if InputSections' outSecOff values remain unchanged, which is + // the case if no output section has . = ALIGN(x). We emulate the + // condition with hasSectionsCommand. + if (part.relrDyn) { + if (assignPasses == 0 || script->hasSectionsCommand) + part.relrDyn->updateAllocSize(); + else + assert(!part.relrDyn->updateAllocSize()); + } } const Defined *changedSym = script->assignAddresses(); diff --git a/lld/test/ELF/pack-dyn-relocs-relr-loop.s b/lld/test/ELF/pack-dyn-relocs-relr-loop.s --- a/lld/test/ELF/pack-dyn-relocs-relr-loop.s +++ b/lld/test/ELF/pack-dyn-relocs-relr-loop.s @@ -1,6 +1,6 @@ # REQUIRES: aarch64 # RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o -# RUN: ld.lld -pie --pack-dyn-relocs=relr -z max-page-size=4096 --verbose %t.o -o %t 2>&1 | FileCheck %s +# RUN: ld.lld -pie --pack-dyn-relocs=relr -z max-page-size=4096 %t.o -o %t # RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELR %s ## This test makes sure we don't shrink .relr.dyn, otherwise its size may @@ -9,8 +9,6 @@ ## The test is very sensitive to the exact section sizes and offsets, ## make sure .data is located at a page boundary. -# CHECK: .relr.dyn needs 1 padding word(s) - # RELR: .relr.dyn { # RELR-NEXT: 0x2F30 R_AARCH64_RELATIVE - # RELR-NEXT: 0x2F38 R_AARCH64_RELATIVE -