Replace MergeOutputSection with a synthetic section.
With a synthetic merge section we can have, for example, a single .rodata section with stings, fixed sized constants and non merge constants. I can be simplified further by not setting Entsize, but that is probably better done is a followup patch. This should allow some cleanup in the linker script code now that every output section command maps to just one output section. llvm-svn: 294005
This commit is contained in:
parent
43b61561b0
commit
9e9754b520
|
@ -80,7 +80,8 @@ InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File,
|
|||
// If it is not a mergeable section, overwrite the flag so that the flag
|
||||
// is consistent with the class. This inconsistency could occur when
|
||||
// string merging is disabled using -O0 flag.
|
||||
if (!Config->Relocatable && !isa<MergeInputSection<ELFT>>(this))
|
||||
if (!Config->Relocatable && !isa<MergeInputSection<ELFT>>(this) &&
|
||||
!isa<SyntheticSection<ELFT>>(this))
|
||||
this->Flags &= ~(SHF_MERGE | SHF_STRINGS);
|
||||
}
|
||||
|
||||
|
@ -118,11 +119,21 @@ typename ELFT::uint InputSectionBase<ELFT>::getOffset(uintX_t Offset) const {
|
|||
// identify the start of the output .eh_frame.
|
||||
return Offset;
|
||||
case Merge:
|
||||
return cast<MergeInputSection<ELFT>>(this)->getOffset(Offset);
|
||||
const MergeInputSection<ELFT> *MS = cast<MergeInputSection<ELFT>>(this);
|
||||
if (MS->MergeSec)
|
||||
return MS->MergeSec->OutSecOff + MS->getOffset(Offset);
|
||||
return MS->getOffset(Offset);
|
||||
}
|
||||
llvm_unreachable("invalid section kind");
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
OutputSectionBase *InputSectionBase<ELFT>::getOutputSection() const {
|
||||
if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(this))
|
||||
return MS->MergeSec ? MS->MergeSec->OutSec : nullptr;
|
||||
return OutSec;
|
||||
}
|
||||
|
||||
// Uncompress section contents. Note that this function is called
|
||||
// from parallel_for_each, so it must be thread-safe.
|
||||
template <class ELFT> void InputSectionBase<ELFT>::uncompress() {
|
||||
|
|
|
@ -28,6 +28,7 @@ class SymbolBody;
|
|||
struct SectionPiece;
|
||||
|
||||
template <class ELFT> class DefinedRegular;
|
||||
template <class ELFT> class MergeSyntheticSection;
|
||||
template <class ELFT> class ObjectFile;
|
||||
template <class ELFT> class OutputSection;
|
||||
class OutputSectionBase;
|
||||
|
@ -130,6 +131,8 @@ public:
|
|||
// Returns the size of this section (even if this is a common or BSS.)
|
||||
size_t getSize() const;
|
||||
|
||||
OutputSectionBase *getOutputSection() const;
|
||||
|
||||
ObjectFile<ELFT> *getFile() const { return File; }
|
||||
llvm::object::ELFFile<ELFT> getObj() const { return File->getObj(); }
|
||||
uintX_t getOffset(const DefinedRegular<ELFT> &Sym) const;
|
||||
|
@ -206,6 +209,11 @@ public:
|
|||
SectionPiece *getSectionPiece(uintX_t Offset);
|
||||
const SectionPiece *getSectionPiece(uintX_t Offset) const;
|
||||
|
||||
// MergeInputSections are aggregated to a synthetic input sections,
|
||||
// and then added to an OutputSection. This pointer points to a
|
||||
// synthetic MergeSyntheticSection which this section belongs to.
|
||||
MergeSyntheticSection<ELFT> *MergeSec = nullptr;
|
||||
|
||||
private:
|
||||
void splitStrings(ArrayRef<uint8_t> A, size_t Size);
|
||||
void splitNonStrings(ArrayRef<uint8_t> A, size_t Size);
|
||||
|
|
|
@ -478,71 +478,6 @@ template <class ELFT> void EhOutputSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
MergeOutputSection<ELFT>::MergeOutputSection(StringRef Name, uint32_t Type,
|
||||
uintX_t Flags, uintX_t Alignment)
|
||||
: OutputSectionBase(Name, Type, Flags),
|
||||
Builder(StringTableBuilder::RAW, Alignment) {}
|
||||
|
||||
template <class ELFT> void MergeOutputSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
Builder.write(Buf);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void MergeOutputSection<ELFT>::addSection(InputSectionData *C) {
|
||||
auto *Sec = cast<MergeInputSection<ELFT>>(C);
|
||||
Sec->OutSec = this;
|
||||
this->updateAlignment(Sec->Alignment);
|
||||
this->Entsize = Sec->Entsize;
|
||||
Sections.push_back(Sec);
|
||||
}
|
||||
|
||||
template <class ELFT> bool MergeOutputSection<ELFT>::shouldTailMerge() const {
|
||||
return (this->Flags & SHF_STRINGS) && Config->Optimize >= 2;
|
||||
}
|
||||
|
||||
template <class ELFT> void MergeOutputSection<ELFT>::finalizeTailMerge() {
|
||||
// Add all string pieces to the string table builder to create section
|
||||
// contents.
|
||||
for (MergeInputSection<ELFT> *Sec : Sections)
|
||||
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
|
||||
if (Sec->Pieces[I].Live)
|
||||
Builder.add(Sec->getData(I));
|
||||
|
||||
// Fix the string table content. After this, the contents will never change.
|
||||
Builder.finalize();
|
||||
this->Size = Builder.getSize();
|
||||
|
||||
// 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.
|
||||
for (MergeInputSection<ELFT> *Sec : Sections)
|
||||
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
|
||||
if (Sec->Pieces[I].Live)
|
||||
Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I));
|
||||
}
|
||||
|
||||
template <class ELFT> void MergeOutputSection<ELFT>::finalizeNoTailMerge() {
|
||||
// Add all string pieces to the string table builder to create section
|
||||
// contents. Because 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).
|
||||
for (MergeInputSection<ELFT> *Sec : Sections)
|
||||
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
|
||||
if (Sec->Pieces[I].Live)
|
||||
Sec->Pieces[I].OutputOff = Builder.add(Sec->getData(I));
|
||||
|
||||
Builder.finalizeInOrder();
|
||||
this->Size = Builder.getSize();
|
||||
}
|
||||
|
||||
template <class ELFT> void MergeOutputSection<ELFT>::finalize() {
|
||||
if (shouldTailMerge())
|
||||
finalizeTailMerge();
|
||||
else
|
||||
finalizeNoTailMerge();
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
static typename ELFT::uint getOutFlags(InputSectionBase<ELFT> *S) {
|
||||
return S->Flags & ~SHF_GROUP & ~SHF_COMPRESSED;
|
||||
|
@ -602,24 +537,15 @@ static SectionKey createKey(InputSectionBase<ELFT> *C, StringRef OutsecName) {
|
|||
//
|
||||
// Given the above issues, we instead merge sections by name and error on
|
||||
// incompatible types and flags.
|
||||
//
|
||||
// The exception being SHF_MERGE, where we create different output sections
|
||||
// for each alignment. This makes each output section simple. In case of
|
||||
// relocatable object generation we do not try to perform merging and treat
|
||||
// SHF_MERGE sections as regular ones, but also create different output
|
||||
// sections for them to allow merging at final linking stage.
|
||||
//
|
||||
// Fortunately, creating symbols in the middle of a merge section is not
|
||||
// supported by bfd or gold, so the SHF_MERGE exception should not cause
|
||||
// problems with most linker scripts.
|
||||
|
||||
typedef typename ELFT::uint uintX_t;
|
||||
uintX_t Flags = C->Flags & (SHF_MERGE | SHF_STRINGS);
|
||||
|
||||
uintX_t Alignment = 0;
|
||||
if (isa<MergeInputSection<ELFT>>(C) ||
|
||||
(Config->Relocatable && (C->Flags & SHF_MERGE)))
|
||||
uintX_t Flags = 0;
|
||||
if (Config->Relocatable && (C->Flags & SHF_MERGE)) {
|
||||
Alignment = std::max<uintX_t>(C->Alignment, C->Entsize);
|
||||
Flags = C->Flags & (SHF_MERGE | SHF_STRINGS);
|
||||
}
|
||||
|
||||
return SectionKey{OutsecName, Flags, Alignment};
|
||||
}
|
||||
|
@ -674,17 +600,11 @@ OutputSectionFactory<ELFT>::create(const SectionKey &Key,
|
|||
}
|
||||
|
||||
uint32_t Type = C->Type;
|
||||
switch (C->kind()) {
|
||||
case InputSectionBase<ELFT>::Regular:
|
||||
case InputSectionBase<ELFT>::Synthetic:
|
||||
Sec = make<OutputSection<ELFT>>(Key.Name, Type, Flags);
|
||||
break;
|
||||
case InputSectionBase<ELFT>::EHFrame:
|
||||
if (C->kind() == InputSectionBase<ELFT>::EHFrame)
|
||||
return {Out<ELFT>::EhFrame, false};
|
||||
case InputSectionBase<ELFT>::Merge:
|
||||
Sec = make<MergeOutputSection<ELFT>>(Key.Name, Type, Flags, Key.Alignment);
|
||||
break;
|
||||
}
|
||||
Sec = make<OutputSection<ELFT>>(Key.Name, Type, Flags);
|
||||
if (Flags & SHF_MERGE)
|
||||
Sec->Entsize = C->Entsize;
|
||||
return {Sec, true};
|
||||
}
|
||||
|
||||
|
@ -724,11 +644,6 @@ template class EhOutputSection<ELF32BE>;
|
|||
template class EhOutputSection<ELF64LE>;
|
||||
template class EhOutputSection<ELF64BE>;
|
||||
|
||||
template class MergeOutputSection<ELF32LE>;
|
||||
template class MergeOutputSection<ELF32BE>;
|
||||
template class MergeOutputSection<ELF64LE>;
|
||||
template class MergeOutputSection<ELF64BE>;
|
||||
|
||||
template class OutputSectionFactory<ELF32LE>;
|
||||
template class OutputSectionFactory<ELF32BE>;
|
||||
template class OutputSectionFactory<ELF64LE>;
|
||||
|
|
|
@ -129,30 +129,6 @@ public:
|
|||
uint8_t *Loc = nullptr;
|
||||
};
|
||||
|
||||
template <class ELFT>
|
||||
class MergeOutputSection final : public OutputSectionBase {
|
||||
typedef typename ELFT::uint uintX_t;
|
||||
|
||||
public:
|
||||
MergeOutputSection(StringRef Name, uint32_t Type, uintX_t Flags,
|
||||
uintX_t Alignment);
|
||||
void addSection(InputSectionData *S) override;
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
void finalize() override;
|
||||
bool shouldTailMerge() const;
|
||||
Kind getKind() const override { return Merge; }
|
||||
static bool classof(const OutputSectionBase *B) {
|
||||
return B->getKind() == Merge;
|
||||
}
|
||||
|
||||
private:
|
||||
void finalizeTailMerge();
|
||||
void finalizeNoTailMerge();
|
||||
|
||||
llvm::StringTableBuilder Builder;
|
||||
std::vector<MergeInputSection<ELFT> *> Sections;
|
||||
};
|
||||
|
||||
struct CieRecord {
|
||||
EhSectionPiece *Piece = nullptr;
|
||||
std::vector<EhSectionPiece *> FdePieces;
|
||||
|
|
|
@ -63,7 +63,8 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
|
|||
Offset += Addend;
|
||||
Addend = 0;
|
||||
}
|
||||
uintX_t VA = (IS->OutSec ? IS->OutSec->Addr : 0) + IS->getOffset(Offset);
|
||||
const OutputSectionBase *OutSec = IS->getOutputSection();
|
||||
uintX_t VA = (OutSec ? OutSec->Addr : 0) + IS->getOffset(Offset);
|
||||
if (D.isTls() && !Config->Relocatable) {
|
||||
if (!Out<ELFT>::TlsPhdr)
|
||||
fatal(toString(D.File) +
|
||||
|
|
|
@ -1152,7 +1152,7 @@ void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) {
|
|||
ESym->st_shndx = SHN_ABS;
|
||||
ESym->st_value = Body.Value;
|
||||
} else {
|
||||
const OutputSectionBase *OutSec = Section->OutSec;
|
||||
const OutputSectionBase *OutSec = Section->getOutputSection();
|
||||
ESym->st_shndx = OutSec->SectionIndex;
|
||||
ESym->st_value = OutSec->Addr + Section->getOffset(Body);
|
||||
}
|
||||
|
@ -1218,7 +1218,7 @@ SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) {
|
|||
case SymbolBody::DefinedRegularKind: {
|
||||
auto &D = cast<DefinedRegular<ELFT>>(*Sym);
|
||||
if (D.Section)
|
||||
return D.Section->OutSec;
|
||||
return D.Section->getOutputSection();
|
||||
break;
|
||||
}
|
||||
case SymbolBody::DefinedCommonKind:
|
||||
|
@ -1871,6 +1871,81 @@ template <class ELFT> bool VersionNeedSection<ELFT>::empty() const {
|
|||
return getNeedNum() == 0;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
MergeSyntheticSection<ELFT>::MergeSyntheticSection(StringRef Name,
|
||||
uint32_t Type, uintX_t Flags,
|
||||
uintX_t Alignment)
|
||||
: SyntheticSection<ELFT>(Flags, Type, Alignment, Name),
|
||||
Builder(StringTableBuilder::RAW, Alignment) {
|
||||
this->Entsize = Alignment;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void MergeSyntheticSection<ELFT>::addSection(MergeInputSection<ELFT> *MS) {
|
||||
assert(!Finalized);
|
||||
MS->MergeSec = this;
|
||||
Sections.push_back(MS);
|
||||
this->Entsize = MS->Entsize;
|
||||
}
|
||||
|
||||
template <class ELFT> void MergeSyntheticSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
Builder.write(Buf);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
bool MergeSyntheticSection<ELFT>::shouldTailMerge() const {
|
||||
return (this->Flags & SHF_STRINGS) && Config->Optimize >= 2;
|
||||
}
|
||||
|
||||
template <class ELFT> void MergeSyntheticSection<ELFT>::finalizeTailMerge() {
|
||||
// Add all string pieces to the string table builder to create section
|
||||
// contents.
|
||||
for (MergeInputSection<ELFT> *Sec : Sections)
|
||||
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
|
||||
if (Sec->Pieces[I].Live)
|
||||
Builder.add(Sec->getData(I));
|
||||
|
||||
// Fix the string table content. After this, the contents will never change.
|
||||
Builder.finalize();
|
||||
|
||||
// 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.
|
||||
for (MergeInputSection<ELFT> *Sec : Sections)
|
||||
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
|
||||
if (Sec->Pieces[I].Live)
|
||||
Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I));
|
||||
}
|
||||
|
||||
template <class ELFT> void MergeSyntheticSection<ELFT>::finalizeNoTailMerge() {
|
||||
// Add all string pieces to the string table builder to create section
|
||||
// contents. Because 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).
|
||||
for (MergeInputSection<ELFT> *Sec : Sections)
|
||||
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
|
||||
if (Sec->Pieces[I].Live)
|
||||
Sec->Pieces[I].OutputOff = Builder.add(Sec->getData(I));
|
||||
|
||||
Builder.finalizeInOrder();
|
||||
}
|
||||
|
||||
template <class ELFT> void MergeSyntheticSection<ELFT>::finalize() {
|
||||
if (Finalized)
|
||||
return;
|
||||
Finalized = true;
|
||||
if (shouldTailMerge())
|
||||
finalizeTailMerge();
|
||||
else
|
||||
finalizeNoTailMerge();
|
||||
}
|
||||
|
||||
template <class ELFT> size_t MergeSyntheticSection<ELFT>::getSize() const {
|
||||
// We should finalize string builder to know the size.
|
||||
const_cast<MergeSyntheticSection<ELFT> *>(this)->finalize();
|
||||
return Builder.getSize();
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
MipsRldMapSection<ELFT>::MipsRldMapSection()
|
||||
: SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
|
||||
|
@ -2064,6 +2139,11 @@ template class elf::VersionDefinitionSection<ELF32BE>;
|
|||
template class elf::VersionDefinitionSection<ELF64LE>;
|
||||
template class elf::VersionDefinitionSection<ELF64BE>;
|
||||
|
||||
template class elf::MergeSyntheticSection<ELF32LE>;
|
||||
template class elf::MergeSyntheticSection<ELF32BE>;
|
||||
template class elf::MergeSyntheticSection<ELF64LE>;
|
||||
template class elf::MergeSyntheticSection<ELF64BE>;
|
||||
|
||||
template class elf::MipsRldMapSection<ELF32LE>;
|
||||
template class elf::MipsRldMapSection<ELF32BE>;
|
||||
template class elf::MipsRldMapSection<ELF64LE>;
|
||||
|
|
|
@ -39,7 +39,7 @@ template <class ELFT> class SyntheticSection : public InputSection<ELFT> {
|
|||
public:
|
||||
SyntheticSection(uintX_t Flags, uint32_t Type, uintX_t Addralign,
|
||||
StringRef Name)
|
||||
: InputSection<ELFT>(Flags, Type, Addralign, ArrayRef<uint8_t>(), Name,
|
||||
: InputSection<ELFT>(Flags, Type, Addralign, {}, Name,
|
||||
InputSectionData::Synthetic) {
|
||||
this->Live = true;
|
||||
}
|
||||
|
@ -629,6 +629,32 @@ public:
|
|||
bool empty() const override;
|
||||
};
|
||||
|
||||
// MergeSyntheticSection is a class that allows us to put mergeable sections
|
||||
// with different attributes in a single output sections. To do that
|
||||
// we put them into MergeSyntheticSection synthetic input sections which are
|
||||
// attached to regular output sections.
|
||||
template <class ELFT>
|
||||
class MergeSyntheticSection final : public SyntheticSection<ELFT> {
|
||||
typedef typename ELFT::uint uintX_t;
|
||||
|
||||
public:
|
||||
MergeSyntheticSection(StringRef Name, uint32_t Type, uintX_t Flags,
|
||||
uintX_t Alignment);
|
||||
void addSection(MergeInputSection<ELFT> *MS);
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
void finalize() override;
|
||||
bool shouldTailMerge() const;
|
||||
size_t getSize() const override;
|
||||
|
||||
private:
|
||||
void finalizeTailMerge();
|
||||
void finalizeNoTailMerge();
|
||||
|
||||
bool Finalized = false;
|
||||
llvm::StringTableBuilder Builder;
|
||||
std::vector<MergeInputSection<ELFT> *> Sections;
|
||||
};
|
||||
|
||||
// .MIPS.abiflags section.
|
||||
template <class ELFT>
|
||||
class MipsAbiFlagsSection final : public SyntheticSection<ELFT> {
|
||||
|
|
|
@ -148,11 +148,60 @@ template <class ELFT> void Writer<ELFT>::removeEmptyPTLoad() {
|
|||
Phdrs.erase(I, Phdrs.end());
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
static typename ELFT::uint getOutFlags(InputSectionBase<ELFT> *S) {
|
||||
return S->Flags & ~(typename ELFT::uint)(SHF_GROUP | SHF_COMPRESSED);
|
||||
}
|
||||
|
||||
// This function scans over the input sections and creates mergeable
|
||||
// synthetic sections. It removes MergeInputSections from array and
|
||||
// adds new synthetic ones. Each synthetic section is added to the
|
||||
// location of the first input section it replaces.
|
||||
template <class ELFT> static void combineMergableSections() {
|
||||
typedef typename ELFT::uint uintX_t;
|
||||
|
||||
std::vector<MergeSyntheticSection<ELFT> *> MergeSections;
|
||||
for (InputSectionBase<ELFT> *&S : Symtab<ELFT>::X->Sections) {
|
||||
MergeInputSection<ELFT> *MS = dyn_cast<MergeInputSection<ELFT>>(S);
|
||||
if (!MS)
|
||||
continue;
|
||||
|
||||
// We do not want to handle sections that are not alive, so just remove
|
||||
// them instead of trying to merge.
|
||||
if (!MS->Live)
|
||||
continue;
|
||||
|
||||
StringRef OutsecName = getOutputSectionName(MS->Name);
|
||||
uintX_t Flags = getOutFlags(MS);
|
||||
uintX_t Alignment = std::max<uintX_t>(MS->Alignment, MS->Entsize);
|
||||
|
||||
auto I =
|
||||
llvm::find_if(MergeSections, [=](MergeSyntheticSection<ELFT> *Sec) {
|
||||
return Sec->Name == OutsecName && Sec->Flags == Flags &&
|
||||
Sec->Alignment == Alignment;
|
||||
});
|
||||
if (I == MergeSections.end()) {
|
||||
MergeSyntheticSection<ELFT> *Syn = make<MergeSyntheticSection<ELFT>>(
|
||||
OutsecName, MS->Type, Flags, Alignment);
|
||||
MergeSections.push_back(Syn);
|
||||
I = std::prev(MergeSections.end());
|
||||
S = Syn;
|
||||
} else {
|
||||
S = nullptr;
|
||||
}
|
||||
(*I)->addSection(MS);
|
||||
}
|
||||
|
||||
std::vector<InputSectionBase<ELFT> *> &V = Symtab<ELFT>::X->Sections;
|
||||
V.erase(std::remove(V.begin(), V.end(), nullptr), V.end());
|
||||
}
|
||||
|
||||
// The main function of the writer.
|
||||
template <class ELFT> void Writer<ELFT>::run() {
|
||||
// Create linker-synthesized sections such as .got or .plt.
|
||||
// Such sections are of type input section.
|
||||
createSyntheticSections();
|
||||
combineMergableSections<ELFT>();
|
||||
|
||||
// We need to create some reserved symbols such as _end. Create them.
|
||||
if (!Config->Relocatable)
|
||||
|
@ -973,8 +1022,9 @@ finalizeSynthetic(const std::vector<SyntheticSection<ELFT> *> &Sections) {
|
|||
// sometimes. This function filters out such unused sections from output.
|
||||
template <class ELFT>
|
||||
static void removeUnusedSyntheticSections(std::vector<OutputSectionBase *> &V) {
|
||||
// Input synthetic sections are placed after all regular ones. We iterate over
|
||||
// them all and exit at first non-synthetic.
|
||||
// All input synthetic sections that can be empty are placed after
|
||||
// all regular ones. We iterate over them all and exit at first
|
||||
// non-synthetic.
|
||||
for (InputSectionBase<ELFT> *S : llvm::reverse(Symtab<ELFT>::X->Sections)) {
|
||||
SyntheticSection<ELFT> *SS = dyn_cast<SyntheticSection<ELFT>>(S);
|
||||
if (!SS)
|
||||
|
|
|
@ -4,25 +4,27 @@
|
|||
# RUN: ld.lld -o %t --script %t.script %t.o -shared
|
||||
# RUN: llvm-readobj -s -section-data %t | FileCheck %s
|
||||
|
||||
# This test shows an oddity in lld. When a linker script alternates among
|
||||
# different types of output section in the same command, the sections are
|
||||
# reordered.
|
||||
# In this test we go from regular, to merge and back to regular. The reason
|
||||
# for the reordering is that we need two create two output sections and
|
||||
# one cannot be in the middle of another.
|
||||
# If this ever becomes a problem, some options would be:
|
||||
# * Adding an extra layer in between input section and output sections (Chunk).
|
||||
# With that this example would have 3 chunks, but only one output section.
|
||||
# This would unfortunately complicate the non-script case too.
|
||||
# * Just create three output sections.
|
||||
# * If having three output sections causes problem, have linkerscript specific
|
||||
# code to write the section table and section indexes. That way we could
|
||||
# keep 3 sections internally but not expose that.
|
||||
|
||||
# CHECK: Name: abc
|
||||
# CHECK: 0000: 01000000 00000000 02000000 00000000 |
|
||||
# CHECK: Name: abc
|
||||
# CHECK: 0000: 61626331 323300 |abc123.|
|
||||
# CHECK: Section {
|
||||
# CHECK: Index:
|
||||
# CHECK: Name: abc
|
||||
# CHECK-NEXT: Type: SHT_PROGBIT
|
||||
# CHECK-NEXT: Flags [
|
||||
# CHECK-NEXT: SHF_ALLOC
|
||||
# CHECK-NEXT: SHF_MERGE
|
||||
# CHECK-NEXT: SHF_STRINGS
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Size:
|
||||
# CHECK-NEXT: Link:
|
||||
# CHECK-NEXT: Info:
|
||||
# CHECK-NEXT: AddressAlignment:
|
||||
# CHECK-NEXT: EntrySize:
|
||||
# CHECK-NEXT: SectionData (
|
||||
# CHECK-NEXT: 0000: 01000000 00000000 61626331 32330002 |........abc123..|
|
||||
# CHECK-NEXT: 0010: 00000000 000000 |.......|
|
||||
# CHECK-NEXT: )
|
||||
# CHECK-NEXT: }
|
||||
|
||||
.section foo, "a"
|
||||
.quad 1
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
# REQUIRES: x86
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
|
||||
|
||||
# RUN: echo "SECTIONS { \
|
||||
# RUN: . = SIZEOF_HEADERS; \
|
||||
# RUN: .rodata : { *(.aaa) *(.bbb) A = .; *(.ccc) B = .; } \
|
||||
# RUN: }" > %t.script
|
||||
# RUN: ld.lld -o %t.so --script %t.script %t.o -shared
|
||||
# RUN: llvm-readobj --dyn-symbols %t.so | FileCheck %s
|
||||
|
||||
# CHECK: DynamicSymbols [
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Name:
|
||||
# CHECK-NEXT: Value:
|
||||
# CHECK-NEXT: Size:
|
||||
# CHECK-NEXT: Binding:
|
||||
# CHECK-NEXT: Type:
|
||||
# CHECK-NEXT: Other:
|
||||
# CHECK-NEXT: Section:
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Name: A
|
||||
# CHECK-NEXT: Value: 0x195
|
||||
# CHECK-NEXT: Size:
|
||||
# CHECK-NEXT: Binding:
|
||||
# CHECK-NEXT: Type:
|
||||
# CHECK-NEXT: Other:
|
||||
# CHECK-NEXT: Section:
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Name: B
|
||||
# CHECK-NEXT: Value: 0x196
|
||||
# CHECK-NEXT: Size:
|
||||
# CHECK-NEXT: Binding:
|
||||
# CHECK-NEXT: Type:
|
||||
# CHECK-NEXT: Other:
|
||||
# CHECK-NEXT: Section:
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
|
||||
|
||||
.section .aaa,"a"
|
||||
.byte 11
|
||||
|
||||
.section .bbb,"aMS",@progbits,1
|
||||
.asciz "foo"
|
||||
|
||||
.section .ccc,"a"
|
||||
.byte 33
|
|
@ -17,61 +17,19 @@
|
|||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address: 0x[[ADDR1:.*]]
|
||||
# CHECK-NEXT: Offset: 0x[[ADDR1]]
|
||||
# CHECK-NEXT: Size: 4
|
||||
# CHECK-NEXT: Link: 0
|
||||
# CHECK-NEXT: Info: 0
|
||||
# CHECK-NEXT: AddressAlignment: 1
|
||||
# CHECK-NEXT: EntrySize: 1
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Section {
|
||||
# CHECK-NEXT: Index:
|
||||
# CHECK-NEXT: Name: .foo
|
||||
# CHECK-NEXT: Type: SHT_PROGBITS
|
||||
# CHECK-NEXT: Flags [
|
||||
# CHECK-NEXT: SHF_ALLOC
|
||||
# CHECK-NEXT: SHF_MERGE
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address: 0x
|
||||
# CHECK-NEXT: Offset: 0x
|
||||
# CHECK-NEXT: Size: 1
|
||||
# CHECK-NEXT: Link: 0
|
||||
# CHECK-NEXT: Info: 0
|
||||
# CHECK-NEXT: AddressAlignment: 1
|
||||
# CHECK-NEXT: EntrySize: 1
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Section {
|
||||
# CHECK-NEXT: Index:
|
||||
# CHECK-NEXT: Name: .foo
|
||||
# CHECK-NEXT: Type: SHT_PROGBITS
|
||||
# CHECK-NEXT: Flags [
|
||||
# CHECK-NEXT: SHF_ALLOC
|
||||
# CHECK-NEXT: SHF_MERGE
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address: 0x
|
||||
# CHECK-NEXT: Offset: 0x
|
||||
# CHECK-NEXT: Size: 2
|
||||
# CHECK-NEXT: Size: 14
|
||||
# CHECK-NEXT: Link: 0
|
||||
# CHECK-NEXT: Info: 0
|
||||
# CHECK-NEXT: AddressAlignment: 2
|
||||
# CHECK-NEXT: EntrySize: 2
|
||||
# CHECK-NEXT: EntrySize: 1
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Section {
|
||||
# CHECK-NEXT: Index:
|
||||
# CHECK-NEXT: Name:
|
||||
# CHECK-NEXT: Type:
|
||||
# CHECK-NEXT: Flags [
|
||||
# CHECK-NEXT: SHF_ALLOC
|
||||
# CHECK-NEXT: SHF_EXECINSTR
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address: 0x[[ADDR2:.*]]
|
||||
# CHECK-NEXT: Offset: 0x[[ADDR2]]
|
||||
|
||||
|
||||
# CHECK: Name: begin
|
||||
# CHECK-NEXT: Value: 0x[[ADDR1]]
|
||||
|
||||
# CHECK: Name: end
|
||||
# CHECK-NEXT: Value: 0x[[ADDR2]]
|
||||
# 0x19E = begin + sizeof(.foo) = 0x190 + 0xE
|
||||
# CHECK-NEXT: Value: 0x19E
|
||||
|
||||
.section .foo.1a,"aMS",@progbits,1
|
||||
.asciz "foo"
|
||||
|
|
|
@ -48,6 +48,7 @@ local:
|
|||
// CHECK-NEXT: 0000000000202000 0000000000000004 16 .bss
|
||||
// CHECK-NEXT: 0000000000202000 0000000000000004 16 COMMON
|
||||
// CHECK-NEXT: 0000000000000000 0000000000000008 1 .comment
|
||||
// CHECK-NEXT: 0000000000000000 0000000000000008 1 .comment
|
||||
// CHECK-NEXT: 0000000000000000 00000000000000f0 8 .symtab
|
||||
// CHECK-NEXT: 0000000000000000 00000000000000f0 8 .symtab
|
||||
// CHECK-NEXT: 0000000000000000 0000000000000039 1 .shstrtab
|
||||
|
|
|
@ -34,10 +34,10 @@
|
|||
// CHECK-NEXT: 0010: 62617200 |bar.|
|
||||
// CHECK-NEXT: )
|
||||
|
||||
.section .rodata.str1.1,"aMS",@progbits,1
|
||||
.section .rodata2,"aMS",@progbits,1
|
||||
.asciz "foo"
|
||||
|
||||
// CHECK: Name: .rodata
|
||||
// CHECK: Name: .rodata2
|
||||
// CHECK-NEXT: Type: SHT_PROGBITS
|
||||
// CHECK-NEXT: Flags [
|
||||
// CHECK-NEXT: SHF_ALLOC
|
||||
|
|
|
@ -2,18 +2,12 @@
|
|||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
|
||||
# RUN: echo "SECTIONS { .data : {*(.data.*)} }" > %t0.script
|
||||
# RUN: ld.lld %t.o -o %t0.out --script %t0.script
|
||||
# RUN: llvm-objdump -s %t0.out | FileCheck %s --check-prefix=OPT
|
||||
# OPT: Contents of section .data:
|
||||
# OPT-NEXT: 0000 01
|
||||
# OPT-NEXT: Contents of section .data:
|
||||
# OPT-NEXT: 0001 6100
|
||||
# OPT-NEXT: Contents of section .data:
|
||||
# OPT-NEXT: 0003 03
|
||||
# RUN: llvm-objdump -s %t0.out | FileCheck %s
|
||||
|
||||
# RUN: ld.lld -O0 %t.o -o %t1.out --script %t0.script
|
||||
# RUN: llvm-objdump -s %t1.out | FileCheck %s --check-prefix=NOOPT
|
||||
# NOOPT: Contents of section .data:
|
||||
# NOOPT-NEXT: 0000 01610003
|
||||
# RUN: llvm-objdump -s %t1.out | FileCheck %s
|
||||
# CHECK: Contents of section .data:
|
||||
# CHECK-NEXT: 0000 01610003
|
||||
|
||||
.section .data.aw,"aw",@progbits
|
||||
.byte 1
|
||||
|
|
Loading…
Reference in New Issue