diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1896,6 +1896,14 @@ if (!config->relocatable) symtab->scanVersionScript(); + // Initialize usedStartStop. + for (const Symbol *sym : symtab->symbols()) { + StringRef name = sym->getName(); + for (StringRef prefix : {"__start_", "__stop_"}) + if (name.startswith(prefix) && isValidCIdentifier(name)) + symtab->usedStartStop.insert(name.substr(prefix.size())); + } + // Do link-time optimization if given files are LLVM bitcode files. // This compiles bitcode files into real object files. // diff --git a/lld/ELF/LTO.h b/lld/ELF/LTO.h --- a/lld/ELF/LTO.h +++ b/lld/ELF/LTO.h @@ -52,7 +52,6 @@ std::unique_ptr ltoObj; std::vector> buf; std::vector> files; - llvm::DenseSet usedStartStop; std::unique_ptr indexFile; llvm::DenseSet thinIndices; }; diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -152,14 +152,6 @@ ltoObj = std::make_unique(createConfig(), backend, config->ltoPartitions); - - // Initialize usedStartStop. - for (Symbol *sym : symtab->symbols()) { - StringRef s = sym->getName(); - for (StringRef prefix : {"__start_", "__stop_"}) - if (s.startswith(prefix)) - usedStartStop.insert(s.substr(prefix.size())); - } } BitcodeCompiler::~BitcodeCompiler() = default; @@ -194,9 +186,10 @@ // 2) Symbols that are used in regular objects. // 3) C named sections if we have corresponding __start_/__stop_ symbol. // 4) Symbols that are defined in bitcode files and used for dynamic linking. - r.VisibleToRegularObj = config->relocatable || sym->isUsedInRegularObj || - (r.Prevailing && sym->includeInDynsym()) || - usedStartStop.count(objSym.getSectionName()); + r.VisibleToRegularObj = + config->relocatable || sym->isUsedInRegularObj || + (r.Prevailing && sym->includeInDynsym()) || + symtab->usedStartStop.count(objSym.getSectionName()); const auto *dr = dyn_cast(sym); r.FinalDefinitionInLinkageUnit = (isExec || sym->visibility != STV_DEFAULT) && dr && diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -652,11 +652,14 @@ if (sec->partition != isec->partition) continue; - if (config->relocatable && (isec->flags & SHF_LINK_ORDER)) { + if (isec->flags & SHF_LINK_ORDER && + !symtab->usedStartStop.count(isec->name)) { // Merging two SHF_LINK_ORDER sections with different sh_link fields will - // change their semantics, so we only merge them in -r links if they will - // end up being linked to the same output section. The casts are fine - // because everything in the map was created by the orphan placement code. + // change their semantics, so we only merge them if they will end up being + // linked to the same output section. If __start_/__stop_ symbols are + // used, there is an expectation that they delimiter the section contents. + // Don't create multiple OutputSections. The casts are fine because + // everything in the map was created by the orphan placement code. auto *firstIsec = cast( cast(sec->sectionCommands[0]) ->sectionBases[0]); diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp --- a/lld/ELF/MarkLive.cpp +++ b/lld/ELF/MarkLive.cpp @@ -309,13 +309,9 @@ d->section->isLive()) markSymbol(s); - for (InputSectionBase *sec : inputSections) { - if (!sec->isLive() || !isValidCIdentifier(sec->name)) - continue; - if (symtab->find(("__start_" + sec->name).str()) || - symtab->find(("__stop_" + sec->name).str())) + for (InputSectionBase *sec : inputSections) + if (sec->isLive() && symtab->usedStartStop.count(sec->name)) enqueue(sec, 0); - } mark(); } diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h --- a/lld/ELF/SymbolTable.h +++ b/lld/ELF/SymbolTable.h @@ -63,6 +63,9 @@ // is used to uniquify them. llvm::DenseMap comdatGroups; + // C named sections with corresponding __start_/__stop_ symbols. + llvm::DenseSet usedStartStop; + private: std::vector findByVersion(SymbolVersion ver); std::vector findAllByVersion(SymbolVersion ver); diff --git a/lld/test/ELF/linkorder-output-section.s b/lld/test/ELF/linkorder-output-section.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/linkorder-output-section.s @@ -0,0 +1,55 @@ +# REQUIRES: x86 +## Test that SHF_LINK_ORDER sections with different linked-to sections +## are not combined. + +# RUN: llvm-mc -filetype=obj --triple=x86_64 %s -o %t.o + +## Without a SECTIONS command, in a non-relocatable link, foo sections are +## combined as a result of combined .text.* +# RUN: ld.lld %t.o -o %t +# RUN: llvm-readelf -S -x foo %t | FileCheck --check-prefixes=SAME,SAME-EXE %s +# RUN: ld.lld %t.o -o %t.ro -r +# RUN: llvm-readelf -S %t.ro | FileCheck --check-prefix=DIFFERENT %s + +## With a SECTIONS command combining .text.*, foo sections are also combined +## in a relocatable link. +# RUN: echo 'SECTIONS { .text : { *(.text.f1) *(.text.f2) } }' > %t1.lds +# RUN: ld.lld -T %t1.lds %t.o -o %t1 +# RUN: llvm-readelf -S -x foo %t1 | FileCheck --check-prefixes=SAME,SAME-EXE %s +# RUN: ld.lld -T %t1.lds %t.o -o %t1.ro -r +# RUN: llvm-readelf -S -x foo %t1.ro | FileCheck --check-prefixes=SAME,SAME-R %s + +## With a SECTIONS command separating .text.*, foo sections are separate. +# RUN: echo 'SECTIONS { .text.f1 : { *(.text.f1) } .text.f2 : { *(.text.f2) } }' > %t2.lds +# RUN: ld.lld -T %t2.lds %t.o -o %t2 +# RUN: llvm-readelf -S %t2 | FileCheck --check-prefix=DIFFERENT %s +# RUN: ld.lld -T %t2.lds %t.o -o %t2.ro -r +# RUN: llvm-readelf -S %t2.ro | FileCheck --check-prefix=DIFFERENT %s + +# SAME: [Nr] Name {{.*}} Flg Lk +## sh_link(foo) references .text + +## A non-relocatable link places readonly sections before read-executable sections. +# SAME-EXE: [ 1] foo {{.*}} AL 2 +# SAME-EXE: [ 2] .text {{.*}} AX 0 + +# SAME-R: [ 1] .text {{.*}} AX 0 +# SAME-R: [ 2] foo {{.*}} AL 1 + +# SAME-NOT: foo + +# DIFFERENT: foo +# DIFFERENT: foo + +# SAME: Hex dump of section 'foo': +# SAME: 01000000 00000000 02000000 00000000 + +.section .text.f1,"ax",@progbits +ret +.section .text.f2,"ax",@progbits +ret + +.section foo,"ao",@progbits,.text.f2 +.quad 2 +.section foo,"ao",@progbits,.text.f1 +.quad 1 diff --git a/lld/test/ELF/relocatable-linkorder.s b/lld/test/ELF/relocatable-linkorder.s deleted file mode 100644 --- a/lld/test/ELF/relocatable-linkorder.s +++ /dev/null @@ -1,36 +0,0 @@ -// REQUIRES: x86 -// RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux -// RUN: ld.lld %t.o -o %t -r -// RUN: llvm-readelf -S %t | FileCheck --check-prefix=DIFFERENT %s -// RUN: echo 'SECTIONS { .text.f1 : { *(.text.f1) } .text.f2 : { *(.text.f2) } }' > %t.lds -// RUN: ld.lld %t.o -o %t -r %t.lds -// RUN: llvm-readelf -S %t | FileCheck --check-prefix=DIFFERENT %s -// RUN: echo 'SECTIONS { .text : { *(.text.f1) *(.text.f2) } }' > %t.lds -// RUN: ld.lld %t.o -o %t -r %t.lds -// RUN: llvm-readelf -S -x foo %t | FileCheck --check-prefix=SAME %s - -/// Test that SHF_LINK_ORDER sections with different linked sections -/// aren't merged. - -.section .text.f1,"ax",@progbits -.globl f1 -f1: -ret - -.section .text.f2,"ax",@progbits -.globl f2 -f2: -ret - -// SAME: foo -// DIFFERENT: foo -.section foo,"ao",@progbits,.text.f2,unique,2 -.quad 2 - -// SAME-NOT: foo -// DIFFERENT: foo -.section foo,"ao",@progbits,.text.f1,unique,1 -.quad 1 - -// SAME: Hex dump of section 'foo': -// SAME: 01000000 00000000 02000000 00000000