| commit 97e251e05a46f5b90af5a0bebebdda98e7fd98ab |
| Author: Peter Collingbourne <peter@pcc.me.uk> |
| Date: Mon Sep 30 20:23:00 2019 +0000 |
| |
| ELF: Don't merge SHF_LINK_ORDER sections for different output sections in relocatable links. |
| |
| Merging SHF_LINK_ORDER sections can affect semantics if the sh_link |
| fields point to different sections. |
| |
| Specifically, for SHF_LINK_ORDER sections, the sh_link field acts as a reverse |
| dependency from the linked section, causing the SHF_LINK_ORDER section to |
| be included if the linked section is included. Merging sections with different |
| sh_link fields will cause the entire contents of the SHF_LINK_ORDER section |
| to be associated with a single (arbitrarily chosen) output section, whereas the |
| correct semantics are for the individual pieces of the SHF_LINK_ORDER section |
| to be associated with their linked output sections. As a result we can end up |
| incorrectly dropping SHF_LINK_ORDER section contents or including the wrong |
| section contents, depending on which linked sections were chosen. |
| |
| Differential Revision: https://reviews.llvm.org/D68094 |
| |
| llvm-svn: 373255 |
| |
| diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp |
| index 533f2f6ad73..70efc22829c 100644 |
| --- a/lld/ELF/LinkerScript.cpp |
| +++ b/lld/ELF/LinkerScript.cpp |
| @@ -645,6 +645,20 @@ addInputSec(StringMap<TinyPtrVector<OutputSection *>> &map, |
| for (OutputSection *sec : v) { |
| if (sec->partition != isec->partition) |
| continue; |
| + |
| + if (config->relocatable && (isec->flags & SHF_LINK_ORDER)) { |
| + // 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. |
| + auto *firstIsec = cast<InputSectionBase>( |
| + cast<InputSectionDescription>(sec->sectionCommands[0]) |
| + ->sectionBases[0]); |
| + if (firstIsec->getLinkOrderDep()->getOutputSection() != |
| + isec->getLinkOrderDep()->getOutputSection()) |
| + continue; |
| + } |
| + |
| sec->recordSection(isec); |
| return nullptr; |
| } |
| @@ -659,26 +673,30 @@ void LinkerScript::addOrphanSections() { |
| StringMap<TinyPtrVector<OutputSection *>> map; |
| std::vector<OutputSection *> v; |
| |
| - auto add = [&](InputSectionBase *s) { |
| - if (!s->isLive() || s->parent) |
| - return; |
| - |
| - StringRef name = getOutputSectionName(s); |
| - |
| - if (config->orphanHandling == OrphanHandlingPolicy::Error) |
| - error(toString(s) + " is being placed in '" + name + "'"); |
| - else if (config->orphanHandling == OrphanHandlingPolicy::Warn) |
| - warn(toString(s) + " is being placed in '" + name + "'"); |
| - |
| - if (OutputSection *sec = findByName(sectionCommands, name)) { |
| - sec->recordSection(s); |
| - return; |
| + std::function<void(InputSectionBase *)> add; |
| + add = [&](InputSectionBase *s) { |
| + if (s->isLive() && !s->parent) { |
| + StringRef name = getOutputSectionName(s); |
| + |
| + if (config->orphanHandling == OrphanHandlingPolicy::Error) |
| + error(toString(s) + " is being placed in '" + name + "'"); |
| + else if (config->orphanHandling == OrphanHandlingPolicy::Warn) |
| + warn(toString(s) + " is being placed in '" + name + "'"); |
| + |
| + if (OutputSection *sec = findByName(sectionCommands, name)) { |
| + sec->recordSection(s); |
| + } else { |
| + if (OutputSection *os = addInputSec(map, s, name)) |
| + v.push_back(os); |
| + assert(isa<MergeInputSection>(s) || |
| + s->getOutputSection()->sectionIndex == UINT32_MAX); |
| + } |
| } |
| |
| - if (OutputSection *os = addInputSec(map, s, name)) |
| - v.push_back(os); |
| - assert(isa<MergeInputSection>(s) || |
| - s->getOutputSection()->sectionIndex == UINT32_MAX); |
| + if (config->relocatable) |
| + for (InputSectionBase *depSec : s->dependentSections) |
| + if (depSec->flags & SHF_LINK_ORDER) |
| + add(depSec); |
| }; |
| |
| // For futher --emit-reloc handling code we need target output section |
| @@ -686,6 +704,12 @@ void LinkerScript::addOrphanSections() { |
| // to create target sections first. We do not want priority handling |
| // for synthetic sections because them are special. |
| for (InputSectionBase *isec : inputSections) { |
| + // In -r links, SHF_LINK_ORDER sections are added while adding their parent |
| + // sections because we need to know the parent's output section before we |
| + // can select an output section for the SHF_LINK_ORDER section. |
| + if (config->relocatable && (isec->flags & SHF_LINK_ORDER)) |
| + continue; |
| + |
| if (auto *sec = dyn_cast<InputSection>(isec)) |
| if (InputSectionBase *rel = sec->getRelocatedSection()) |
| if (auto *relIS = dyn_cast_or_null<InputSectionBase>(rel->parent)) |
| diff --git a/lld/test/ELF/relocatable-linkorder.s b/lld/test/ELF/relocatable-linkorder.s |
| new file mode 100644 |
| index 00000000000..0a7dfc6c12a |
| --- /dev/null |
| +++ b/lld/test/ELF/relocatable-linkorder.s |
| @@ -0,0 +1,36 @@ |
| +// 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 |