return V;
}
+// Returns I'th piece's data.
template <class ELFT>
-ArrayRef<uint8_t> MergeInputSection<ELFT>::getData(
- std::vector<SectionPiece>::const_iterator I) const {
- auto Next = I + 1;
- size_t End = Next == Pieces.end() ? this->Data.size() : Next->InputOff;
- return this->Data.slice(I->InputOff, End - I->InputOff);
+CachedHashStringRef MergeInputSection<ELFT>::getData(size_t I) const {
+ size_t End =
+ (Pieces.size() - 1 == I) ? this->Data.size() : Pieces[I + 1].InputOff;
+ const SectionPiece &P = Pieces[I];
+ StringRef S = toStringRef(this->Data.slice(P.InputOff, End - P.InputOff));
+ return {S, Hashes[I]};
}
// Split non-SHF_STRINGS section. Such section is a sequence of
// it is not just an addition to a base output offset.
template <class ELFT>
typename ELFT::uint MergeInputSection<ELFT>::getOffset(uintX_t Offset) const {
+ // Initialize OffsetMap lazily.
+ std::call_once(InitOffsetMap, [&] {
+ OffsetMap.reserve(Pieces.size());
+ for (const SectionPiece &Piece : Pieces)
+ OffsetMap[Piece.InputOff] = Piece.OutputOff;
+ });
+
+ // Find a string starting at a given offset.
auto It = OffsetMap.find(Offset);
if (It != OffsetMap.end())
return It->second;
return Piece.OutputOff + Addend;
}
-// Create a map from input offsets to output offsets for all section pieces.
-// It is called after finalize().
-template <class ELFT> void MergeInputSection<ELFT>::finalizePieces() {
- OffsetMap.reserve(this->Pieces.size());
- auto HashI = Hashes.begin();
- for (auto I = Pieces.begin(), E = Pieces.end(); I != E; ++I) {
- uint32_t Hash = *HashI;
- ++HashI;
- SectionPiece &Piece = *I;
- if (!Piece.Live)
- continue;
- if (Piece.OutputOff == -1) {
- // Offsets of tail-merged strings are computed lazily.
- auto *OutSec = static_cast<MergeOutputSection<ELFT> *>(this->OutSec);
- ArrayRef<uint8_t> D = this->getData(I);
- StringRef S((const char *)D.data(), D.size());
- CachedHashStringRef V(S, Hash);
- Piece.OutputOff = OutSec->getOffset(V);
- }
- OffsetMap[Piece.InputOff] = Piece.OutputOff;
- }
-}
-
template class elf::InputSectionBase<ELF32LE>;
template class elf::InputSectionBase<ELF32BE>;
template class elf::InputSectionBase<ELF64LE>;
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Object/ELF.h"
+#include <mutex>
namespace lld {
namespace elf {
// in the output section.
uintX_t getOffset(uintX_t Offset) const;
- void finalizePieces();
-
// Splittable sections are handled as a sequence of data
// rather than a single large blob of data.
std::vector<SectionPiece> Pieces;
- ArrayRef<uint8_t> getData(std::vector<SectionPiece>::const_iterator I) const;
- std::vector<uint32_t> Hashes;
+ llvm::CachedHashStringRef getData(size_t Idx) const;
// Returns the SectionPiece at a given input section offset.
SectionPiece *getSectionPiece(uintX_t Offset);
std::vector<SectionPiece> splitStrings(ArrayRef<uint8_t> A, size_t Size);
std::vector<SectionPiece> splitNonStrings(ArrayRef<uint8_t> A, size_t Size);
- llvm::DenseMap<uintX_t, uintX_t> OffsetMap;
+ std::vector<uint32_t> Hashes;
+
+ mutable llvm::DenseMap<uintX_t, uintX_t> OffsetMap;
+ mutable std::once_flag InitOffsetMap;
+
llvm::DenseSet<uintX_t> LiveOffsets;
};
this->updateAlignment(Sec->Alignment);
this->Entsize = Sec->Entsize;
Sections.push_back(Sec);
-
- auto HashI = Sec->Hashes.begin();
- for (auto I = Sec->Pieces.begin(), E = Sec->Pieces.end(); I != E; ++I) {
- SectionPiece &Piece = *I;
- uint32_t Hash = *HashI;
- ++HashI;
- if (!Piece.Live)
- continue;
- StringRef Data = toStringRef(Sec->getData(I));
- CachedHashStringRef V(Data, Hash);
- uintX_t OutputOffset = Builder.add(V);
- if (!shouldTailMerge())
- Piece.OutputOff = OutputOffset;
- }
-}
-
-template <class ELFT>
-unsigned MergeOutputSection<ELFT>::getOffset(CachedHashStringRef Val) {
- return Builder.getOffset(Val);
}
template <class ELFT> bool MergeOutputSection<ELFT>::shouldTailMerge() const {
- return Config->Optimize >= 2 && this->Flags & SHF_STRINGS;
+ return (this->Flags & SHF_STRINGS) && Config->Optimize >= 2;
}
template <class ELFT> void MergeOutputSection<ELFT>::finalize() {
+ // Add all string pieces to the string table builder to create section
+ // contents. If we are not tail-optimizing, offsets of strings are fixed
+ // when they are added to the builder (string table builder contains a
+ // hash table from strings to offsets), so we record them if available.
+ for (MergeInputSection<ELFT> *Sec : Sections) {
+ for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) {
+ if (!Sec->Pieces[I].Live)
+ continue;
+ uint32_t OutputOffset = Builder.add(Sec->getData(I));
+
+ // Save the offset in the generated string table.
+ if (!shouldTailMerge())
+ Sec->Pieces[I].OutputOff = OutputOffset;
+ }
+ }
+
+ // Fix the string table content. After this, the contents
+ // will never change.
if (shouldTailMerge())
Builder.finalize();
else
Builder.finalizeInOrder();
this->Size = Builder.getSize();
-}
-template <class ELFT> void MergeOutputSection<ELFT>::finalizePieces() {
- for (MergeInputSection<ELFT> *Sec : Sections)
- Sec->finalizePieces();
+ // finalize() fixed tail-optimized strings, so we can now get
+ // offsets of strings. Get an offset for each string and save it
+ // to a corresponding StringPiece for easy access.
+ if (shouldTailMerge()) {
+ for (MergeInputSection<ELFT> *Sec : Sections) {
+ for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) {
+ if (!Sec->Pieces[I].Live)
+ continue;
+ Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I));
+ }
+ }
+ }
}
template <class ELFT>
OutputSectionBase *FirstInPtLoad = nullptr;
virtual void finalize() {}
- virtual void finalizePieces() {}
virtual void assignOffsets() {}
virtual void writeTo(uint8_t *Buf) {}
virtual ~OutputSectionBase() = default;
uintX_t Alignment);
void addSection(InputSectionData *S) override;
void writeTo(uint8_t *Buf) override;
- unsigned getOffset(llvm::CachedHashStringRef Val);
void finalize() override;
- void finalizePieces() override;
bool shouldTailMerge() const;
Kind getKind() const override { return Merge; }
static bool classof(const OutputSectionBase *B) {
{In<ELFT>::SymTab, In<ELFT>::ShStrTab, In<ELFT>::StrTab,
In<ELFT>::DynStrTab, In<ELFT>::Got, In<ELFT>::MipsGot, In<ELFT>::GotPlt,
In<ELFT>::RelaDyn, In<ELFT>::RelaPlt, In<ELFT>::Dynamic});
-
- // Now that all output offsets are fixed. Finalize mergeable sections
- // to fix their maps from input offsets to output offsets.
- for (OutputSectionBase *Sec : OutputSections)
- Sec->finalizePieces();
}
template <class ELFT> bool Writer<ELFT>::needsGot() {