"feature detected");
}
- // This adds a .comment section containing a version string. We have to add it
- // before mergeSections because the .comment section is a mergeable section.
+ // This adds a .comment section containing a version string.
if (!config->relocatable)
inputSections.push_back(createCommentSection());
splitSections<ELFT>();
markLive<ELFT>();
demoteSharedSymbols();
- mergeSections();
// Make copies of any input sections that need to be copied into each
// partition.
// they are assigned to output sections by the default rule. Process that.
script->addOrphanSections();
+ // Migrate InputSectionDescription::sectionBases to sections. This includes
+ // merging MergeInputSections into a single MergeSyntheticSection. From this
+ // point onwards InputSectionDescription::sections should be used instead of
+ // sectionBases.
+ for (BaseCommand *base : script->sectionCommands)
+ if (auto *sec = dyn_cast<OutputSection>(base))
+ sec->finalizeInputSections();
+ llvm::erase_if(inputSections,
+ [](InputSectionBase *s) { return isa<MergeInputSection>(s); });
+
// Two input sections with different output sections should not be folded.
// ICF runs after processSectionCommands() so that we know the output sections.
if (config->icf != ICFLevel::None) {
}
// A helper function for the SORT() command.
-static bool matchConstraints(ArrayRef<InputSection *> sections,
+static bool matchConstraints(ArrayRef<InputSectionBase *> sections,
ConstraintKind kind) {
if (kind == ConstraintKind::NoConstraint)
return true;
bool isRW = llvm::any_of(
- sections, [](InputSection *sec) { return sec->flags & SHF_WRITE; });
+ sections, [](InputSectionBase *sec) { return sec->flags & SHF_WRITE; });
return (isRW && kind == ConstraintKind::ReadWrite) ||
(!isRW && kind == ConstraintKind::ReadOnly);
}
-static void sortSections(MutableArrayRef<InputSection *> vec,
+static void sortSections(MutableArrayRef<InputSectionBase *> vec,
SortSectionPolicy k) {
auto alignmentComparator = [](InputSectionBase *a, InputSectionBase *b) {
// ">" is not a mistake. Sections with larger alignments are placed
// --sort-section is handled as an inner SORT command.
// 3. If one SORT command is given, and if it is SORT_NONE, don't sort.
// 4. If no SORT command is given, sort according to --sort-section.
-static void sortInputSections(MutableArrayRef<InputSection *> vec,
+static void sortInputSections(MutableArrayRef<InputSectionBase *> vec,
const SectionPattern &pat) {
if (pat.sortOuter == SortSectionPolicy::None)
return;
}
// Compute and remember which sections the InputSectionDescription matches.
-std::vector<InputSection *>
+std::vector<InputSectionBase *>
LinkerScript::computeInputSections(const InputSectionDescription *cmd) {
- std::vector<InputSection *> ret;
+ std::vector<InputSectionBase *> ret;
// Collects all sections that satisfy constraints of Cmd.
for (const SectionPattern &pat : cmd->sectionPatterns) {
// which are common because they are in the default bfd script.
// We do not ignore SHT_REL[A] linker-synthesized sections here because
// want to support scripts that do custom layout for them.
- //
- // It is safe to assume that Sec is an InputSection because mergeable or
- // EH input sections have already been handled and eliminated.
- if (cast<InputSection>(sec)->getRelocatedSection())
+ if (isa<InputSection>(sec) &&
+ cast<InputSection>(sec)->getRelocatedSection())
continue;
std::string filename = getFilename(sec->file);
!pat.sectionPat.match(sec->name))
continue;
- ret.push_back(cast<InputSection>(sec));
+ ret.push_back(sec);
sec->assigned = true;
}
- sortInputSections(MutableArrayRef<InputSection *>(ret).slice(sizeBefore),
- pat);
+ sortInputSections(
+ MutableArrayRef<InputSectionBase *>(ret).slice(sizeBefore), pat);
}
return ret;
}
-void LinkerScript::discard(ArrayRef<InputSection *> v) {
- for (InputSection *s : v) {
- if (s == in.shStrTab || s == mainPart->relaDyn || s == mainPart->relrDyn)
- error("discarding " + s->name + " section is not allowed");
-
- // You can discard .hash and .gnu.hash sections by linker scripts. Since
- // they are synthesized sections, we need to handle them differently than
- // other regular sections.
- if (s == mainPart->gnuHashTab)
- mainPart->gnuHashTab = nullptr;
- if (s == mainPart->hashTab)
- mainPart->hashTab = nullptr;
-
- s->markDead();
- discard(s->dependentSections);
- }
+void LinkerScript::discard(InputSectionBase *s) {
+ if (s == in.shStrTab || s == mainPart->relaDyn || s == mainPart->relrDyn)
+ error("discarding " + s->name + " section is not allowed");
+
+ // You can discard .hash and .gnu.hash sections by linker scripts. Since
+ // they are synthesized sections, we need to handle them differently than
+ // other regular sections.
+ if (s == mainPart->gnuHashTab)
+ mainPart->gnuHashTab = nullptr;
+ if (s == mainPart->hashTab)
+ mainPart->hashTab = nullptr;
+
+ s->markDead();
+ for (InputSection *ds : s->dependentSections)
+ discard(ds);
}
-std::vector<InputSection *>
+std::vector<InputSectionBase *>
LinkerScript::createInputSectionList(OutputSection &outCmd) {
- std::vector<InputSection *> ret;
+ std::vector<InputSectionBase *> ret;
for (BaseCommand *base : outCmd.sectionCommands) {
if (auto *cmd = dyn_cast<InputSectionDescription>(base)) {
- cmd->sections = computeInputSections(cmd);
- ret.insert(ret.end(), cmd->sections.begin(), cmd->sections.end());
+ cmd->sectionBases = computeInputSections(cmd);
+ ret.insert(ret.end(), cmd->sectionBases.begin(), cmd->sectionBases.end());
}
}
return ret;
size_t i = 0;
for (BaseCommand *base : sectionCommands) {
if (auto *sec = dyn_cast<OutputSection>(base)) {
- std::vector<InputSection *> v = createInputSectionList(*sec);
+ std::vector<InputSectionBase *> v = createInputSectionList(*sec);
// The output section name `/DISCARD/' is special.
// Any input section assigned to it is discarded.
if (sec->name == "/DISCARD/") {
- discard(v);
+ for (InputSectionBase *s : v)
+ discard(s);
sec->sectionCommands.clear();
continue;
}
s->alignment = subalign;
}
- // Some input sections may be removed from the list after ICF.
- for (InputSection *s : v)
- sec->addSection(s);
-
sec->sectionIndex = i++;
- if (sec->noload)
- sec->type = SHT_NOBITS;
- if (sec->nonAlloc)
- sec->flags &= ~(uint64_t)SHF_ALLOC;
+ for (InputSectionBase *s : v)
+ s->parent = sec;
}
}
}
static OutputSection *createSection(InputSectionBase *isec,
StringRef outsecName) {
OutputSection *sec = script->createOutputSection(outsecName, "<internal>");
- sec->addSection(cast<InputSection>(isec));
+ sec->recordSection(isec);
return sec;
}
OutputSection *out = sec->getRelocatedSection()->getOutputSection();
if (out->relocationSection) {
- out->relocationSection->addSection(sec);
+ out->relocationSection->recordSection(sec);
return nullptr;
}
return out->relocationSection;
}
- // When control reaches here, mergeable sections have already been merged into
- // synthetic sections. For relocatable case we want to create one output
- // section per syntetic section so that they have a valid sh_entsize.
- if (config->relocatable && (isec->flags & SHF_MERGE))
- return createSection(isec, outsecName);
-
// The ELF spec just says
// ----------------------------------------------------------------
// In the first phase, input sections that match in name, type and
for (OutputSection *sec : v) {
if (sec->partition != isec->partition)
continue;
- sec->addSection(cast<InputSection>(isec));
+ sec->recordSection(isec);
return nullptr;
}
warn(toString(s) + " is being placed in '" + name + "'");
if (OutputSection *sec = findByName(sectionCommands, name)) {
- sec->addSection(cast<InputSection>(s));
+ sec->recordSection(s);
return;
}
if (OutputSection *os = addInputSec(map, s, name))
v.push_back(os);
- assert(s->getOutputSection()->sectionIndex == UINT32_MAX);
+ assert(isa<MergeInputSection>(s) ||
+ s->getOutputSection()->sectionIndex == UINT32_MAX);
};
// For futher --emit-reloc handling code we need target output section
// will be associated with this InputSectionDescription.
std::vector<SectionPattern> sectionPatterns;
+ // Includes InputSections and MergeInputSections. Used temporarily during
+ // assignment of input sections to output sections.
+ std::vector<InputSectionBase *> sectionBases;
+
+ // Used after the finalizeInputSections() pass. MergeInputSections have been
+ // merged into MergeSyntheticSections.
std::vector<InputSection *> sections;
// Temporary record of synthetic ThunkSection instances and the pass that
void expandOutputSection(uint64_t size);
void expandMemoryRegions(uint64_t size);
- std::vector<InputSection *>
+ std::vector<InputSectionBase *>
computeInputSections(const InputSectionDescription *);
- std::vector<InputSection *> createInputSectionList(OutputSection &cmd);
+ std::vector<InputSectionBase *> createInputSectionList(OutputSection &cmd);
std::vector<size_t> getPhdrIndices(OutputSection *sec);
bool hasPhdrsCommands() { return !phdrsCommands.empty(); }
uint64_t getDot() { return dot; }
- void discard(ArrayRef<InputSection *> v);
+ void discard(InputSectionBase *s);
ExprValue getSymbolValue(StringRef name, const Twine &loc);
type == SHT_NOTE;
}
-void OutputSection::addSection(InputSection *isec) {
+// Record that isec will be placed in the OutputSection. isec does not become
+// permanent until finalizeInputSections() is called. The function should not be
+// used after finalizeInputSections() is called. If you need to add an
+// InputSection post finalizeInputSections(), then you must do the following:
+//
+// 1. Find or create an InputSectionDescription to hold InputSection.
+// 2. Add the InputSection to the InputSectionDesciption::sections.
+// 3. Call commitSection(isec).
+void OutputSection::recordSection(InputSectionBase *isec) {
+ partition = isec->partition;
+ isec->parent = this;
+ if (sectionCommands.empty() ||
+ !isa<InputSectionDescription>(sectionCommands.back()))
+ sectionCommands.push_back(make<InputSectionDescription>(""));
+ auto *isd = cast<InputSectionDescription>(sectionCommands.back());
+ isd->sectionBases.push_back(isec);
+}
+
+// Update fields (type, flags, alignment, etc) according to the InputSection
+// isec. Also check whether the InputSection flags and type are consistent with
+// other InputSections.
+void OutputSection::commitSection(InputSection *isec) {
if (!hasInputSections) {
// If IS is the first section to be added to this section,
- // initialize Partition, Type, Entsize and flags from IS.
+ // initialize type, entsize and flags from isec.
hasInputSections = true;
- partition = isec->partition;
type = isec->type;
entsize = isec->entsize;
flags = isec->flags;
type = SHT_PROGBITS;
}
}
+ if (noload)
+ type = SHT_NOBITS;
isec->parent = this;
uint64_t andMask =
uint64_t andFlags = (flags & isec->flags) & andMask;
uint64_t orFlags = (flags | isec->flags) & orMask;
flags = andFlags | orFlags;
+ if (nonAlloc)
+ flags &= ~(uint64_t)SHF_ALLOC;
alignment = std::max(alignment, isec->alignment);
// set sh_entsize to 0.
if (entsize != isec->entsize)
entsize = 0;
+}
+
+// This function scans over the InputSectionBase list sectionBases to create
+// InputSectionDescription::sections.
+//
+// It removes MergeInputSections from the input section array and adds
+// new synthetic sections at the location of the first input section
+// that it replaces. It then finalizes each synthetic section in order
+// to compute an output offset for each piece of each input section.
+void OutputSection::finalizeInputSections() {
+ std::vector<MergeSyntheticSection *> mergeSections;
+ for (BaseCommand *base : sectionCommands) {
+ auto *cmd = dyn_cast<InputSectionDescription>(base);
+ if (!cmd)
+ continue;
+ cmd->sections.reserve(cmd->sectionBases.size());
+ for (InputSectionBase *s : cmd->sectionBases) {
+ MergeInputSection *ms = dyn_cast<MergeInputSection>(s);
+ if (!ms) {
+ cmd->sections.push_back(cast<InputSection>(s));
+ continue;
+ }
+
+ // We do not want to handle sections that are not alive, so just remove
+ // them instead of trying to merge.
+ if (!ms->isLive())
+ continue;
+
+ auto i = llvm::find_if(mergeSections, [=](MergeSyntheticSection *sec) {
+ // While we could create a single synthetic section for two different
+ // values of Entsize, it is better to take Entsize into consideration.
+ //
+ // With a single synthetic section no two pieces with different Entsize
+ // could be equal, so we may as well have two sections.
+ //
+ // Using Entsize in here also allows us to propagate it to the synthetic
+ // section.
+ //
+ // SHF_STRINGS section with different alignments should not be merged.
+ return sec->flags == ms->flags && sec->entsize == ms->entsize &&
+ (sec->alignment == ms->alignment || !(sec->flags & SHF_STRINGS));
+ });
+ if (i == mergeSections.end()) {
+ MergeSyntheticSection *syn =
+ createMergeSynthetic(name, ms->type, ms->flags, ms->alignment);
+ mergeSections.push_back(syn);
+ i = std::prev(mergeSections.end());
+ syn->entsize = ms->entsize;
+ cmd->sections.push_back(syn);
+ }
+ (*i)->addSection(ms);
+ }
+
+ // sectionBases should not be used from this point onwards. Clear it to
+ // catch misuses.
+ cmd->sectionBases.clear();
- if (!isec->assigned) {
- isec->assigned = true;
- if (sectionCommands.empty() ||
- !isa<InputSectionDescription>(sectionCommands.back()))
- sectionCommands.push_back(make<InputSectionDescription>(""));
- auto *isd = cast<InputSectionDescription>(sectionCommands.back());
- isd->sections.push_back(isec);
+ // Some input sections may be removed from the list after ICF.
+ for (InputSection *s : cmd->sections)
+ commitSection(s);
}
+ for (auto *ms : mergeSections)
+ ms->finalizeContents();
}
static void sortByOrder(MutableArrayRef<InputSection *> in,
uint64_t addr = 0;
uint32_t shName = 0;
- void addSection(InputSection *isec);
+ void recordSection(InputSectionBase *isec);
+ void commitSection(InputSection *isec);
+ void finalizeInputSections();
// The following members are normally only used in linker scripts.
MemoryRegion *memRegion = nullptr;
bool isRO = isReadOnly<ELFT>(ss);
BssSection *sec =
make<BssSection>(isRO ? ".bss.rel.ro" : ".bss", symSize, ss.alignment);
- if (isRO)
- in.bssRelRo->getParent()->addSection(sec);
- else
- in.bss->getParent()->addSection(sec);
+ OutputSection *osec = (isRO ? in.bssRelRo : in.bss)->getParent();
+
+ // At this point, sectionBases has been migrated to sections. Append sec to
+ // sections.
+ if (osec->sectionCommands.empty() ||
+ !isa<InputSectionDescription>(osec->sectionCommands.back()))
+ osec->sectionCommands.push_back(make<InputSectionDescription>(""));
+ auto *isd = cast<InputSectionDescription>(osec->sectionCommands.back());
+ isd->sections.push_back(sec);
+ osec->commitSection(sec);
// Look through the DSO's dynamic symbol table for aliases and create a
// dynamic symbol for each one. This causes the copy relocation to correctly
});
}
-static MergeSyntheticSection *createMergeSynthetic(StringRef name,
- uint32_t type,
- uint64_t flags,
- uint32_t alignment) {
+MergeSyntheticSection *elf::createMergeSynthetic(StringRef name, uint32_t type,
+ uint64_t flags,
+ uint32_t alignment) {
bool shouldTailMerge = (flags & SHF_STRINGS) && config->optimize >= 2;
if (shouldTailMerge)
return make<MergeTailSection>(name, type, flags, alignment);
});
}
-// This function scans over the inputsections to create mergeable
-// synthetic sections.
-//
-// It removes MergeInputSections from the input section array and adds
-// new synthetic sections at the location of the first input section
-// that it replaces. It then finalizes each synthetic section in order
-// to compute an output offset for each piece of each input section.
-void elf::mergeSections() {
- std::vector<MergeSyntheticSection *> mergeSections;
- for (InputSectionBase *&s : inputSections) {
- MergeInputSection *ms = dyn_cast<MergeInputSection>(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->isLive()) {
- s = nullptr;
- continue;
- }
-
- StringRef outsecName = getOutputSectionName(ms);
-
- auto i = llvm::find_if(mergeSections, [=](MergeSyntheticSection *sec) {
- // While we could create a single synthetic section for two different
- // values of Entsize, it is better to take Entsize into consideration.
- //
- // With a single synthetic section no two pieces with different Entsize
- // could be equal, so we may as well have two sections.
- //
- // Using Entsize in here also allows us to propagate it to the synthetic
- // section.
- //
- // SHF_STRINGS section with different alignments should not be merged.
- return sec->name == outsecName && sec->flags == ms->flags &&
- sec->entsize == ms->entsize &&
- (sec->alignment == ms->alignment || !(sec->flags & SHF_STRINGS));
- });
- if (i == mergeSections.end()) {
- MergeSyntheticSection *syn =
- createMergeSynthetic(outsecName, ms->type, ms->flags, ms->alignment);
- mergeSections.push_back(syn);
- i = std::prev(mergeSections.end());
- s = syn;
- syn->entsize = ms->entsize;
- } else {
- s = nullptr;
- }
- (*i)->addSection(ms);
- }
- for (auto *ms : mergeSections)
- ms->finalizeContents();
-
- std::vector<InputSectionBase *> &v = inputSections;
- v.erase(std::remove(v.begin(), v.end(), nullptr), v.end());
-}
-
MipsRldMapSection::MipsRldMapSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, config->wordsize,
".rld_map") {}
InputSection *createInterpSection();
MergeInputSection *createCommentSection();
+MergeSyntheticSection *createMergeSynthetic(StringRef name, uint32_t type,
+ uint64_t flags, uint32_t alignment);
template <class ELFT> void splitSections();
-void mergeSections();
template <typename ELFT> void writeEhdr(uint8_t *buf, Partition &part);
template <typename ELFT> void writePhdrs(uint8_t *buf, Partition &part);
});
if (i == sec->sectionCommands.end())
continue;
- InputSection *isec = cast<InputSectionDescription>(*i)->sections[0];
+ InputSectionBase *isec = cast<InputSectionDescription>(*i)->sections[0];
// Relocations are not using REL[A] section symbols.
if (isec->type == SHT_REL || isec->type == SHT_RELA)
--- /dev/null
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+
+## SHF_MERGE sections within the same output section can be freely merged.
+# RUN: echo 'SECTIONS { .rodata : { *(.rodata.*) }}' > %t.script
+# RUN: ld.lld %t.o -T %t.script -o %t
+# RUN: llvm-readelf -x .rodata %t | FileCheck --check-prefix=SAME %s --implicit-check-not=section
+
+# SAME: section '.rodata':
+# SAME-NEXT: 0x00000000 01000200 0300
+
+## SHF_MERGE sections with different output sections cannot be merged.
+# RUN: echo 'SECTIONS { \
+# RUN: .rodata.foo : { *(.rodata.foo) } \
+# RUN: .rodata.bar : { *(.rodata.bar) } \
+# RUN: }' > %t2.script
+# RUN: ld.lld %t.o -T %t2.script -o %t2
+# RUN: llvm-readelf -x .rodata.foo -x .rodata.bar %t2 | FileCheck --check-prefix=DIFF %s --implicit-check-not=section
+
+# DIFF: section '.rodata.foo':
+# DIFF-NEXT: 0x00000000 01000200 0300
+# DIFF: section '.rodata.bar':
+# DIFF-NEXT: 0x00000006 0100
+
+.section .rodata.foo,"aM",@progbits,2,unique,0
+.short 1
+.short 2
+.section .rodata.foo,"aM",@progbits,2,unique,1
+.short 1
+.short 3
+
+.section .rodata.bar,"aM",@progbits,2,unique,0
+.short 1
+.section .rodata.bar,"aM",@progbits,2,unique,1
+.short 1
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x[[ADDR1:.*]]
# CHECK-NEXT: Offset: 0x[[ADDR1]]
-# CHECK-NEXT: Size: 14
+# CHECK-NEXT: Size: 8
# CHECK-NEXT: Link: 0
# CHECK-NEXT: Info: 0
# CHECK-NEXT: AddressAlignment: 2
# CHECK-NEXT: Value: 0x[[ADDR1]]
# CHECK: Name: end
-# CHECK-NEXT: Value: 0x236
+# CHECK-NEXT: Value: 0x230
# Check that we don't crash with --gc-sections
# RUN: ld.lld --gc-sections -o %t2 --script %t.script %t -shared
# RUN: llvm-readelf -x .cst %t | FileCheck --check-prefix=HEX %s
# RUN: ld.lld -O0 -r %t.o -o %t1.o
-# RUN: llvm-readelf -S %t1.o | FileCheck --check-prefix=SEC-R %s
-# RUN: llvm-readelf -x .cst %t1.o | FileCheck --check-prefix=HEX-R %s
+# RUN: llvm-readelf -S %t1.o | FileCheck --check-prefix=SEC %s
+# RUN: llvm-readelf -x .cst %t1.o | FileCheck --check-prefix=HEX %s
## Check that SHF_MERGE sections with the same name, sh_flags and sh_entsize
## are grouped together and can be merged within the group.
# SEC: Name Type {{.*}} Size ES Flg Lk Inf Al
# SEC: .cst PROGBITS {{.*}} 000020 00 AM 0 0 8
-## .cst 0 and .cst 1 are merged, but emitted as a separate output section.
-# SEC-R: .cst PROGBITS {{.*}} 00000c 04 AM 0 0 4
-# SEC-R: .cst PROGBITS {{.*}} 000010 08 AM 0 0 8
-
# HEX: Hex dump of section '.cst':
# HEX-NEXT: 0x{{[0-9a-f]+}} 01000000 00000000 02000000 00000000
# HEX-NEXT: 0x{{[0-9a-f]+}} 01000000 00000000 03000000 00000000
-# HEX-R: Hex dump of section '.cst':
-# HEX-R-NEXT: 0x00000000 01000000 00000000 02000000
-# HEX-R-EMPTY:
-# HEX-R-NEXT: Hex dump of section '.cst':
-# HEX-R-NEXT: 0x00000000 01000000 00000000 03000000 00000000
-
.section .cst,"aM",@progbits,4,unique,0
.align 2
.long 1