Skip to content

Commit

Permalink
[ELF] Allow SHF_LINK_ORDER and non-SHF_LINK_ORDER to be mixed
Browse files Browse the repository at this point in the history
Currently, `error: incompatible section flags for .rodata` is reported
when we mix SHF_LINK_ORDER and non-SHF_LINK_ORDER sections in an output section.

This is overconstrained. This patch allows mixed flags with the
requirement that SHF_LINK_ORDER sections must be contiguous. Mixing
flags is used by Linux aarch64 (ClangBuiltLinux/linux#953)

  .init.data : { ... KEEP(*(__patchable_function_entries)) ... }

When the integrated assembler is enabled, clang's -fpatchable-function-entry=N[,M]
implementation sets the SHF_LINK_ORDER flag (D72215) to fix a number of
garbage collection issues.

Strictly speaking, the ELF specification does not require contiguous
SHF_LINK_ORDER sections but for many current uses of SHF_LINK_ORDER like
.ARM.exidx/__patchable_function_entries there has been a requirement for
the sections to be contiguous on top of the requirements of the ELF
specification.

This patch also imposes one restriction: SHF_LINK_ORDER sections cannot
be separated by a symbol assignment or a BYTE command. Not allowing BYTE
is a natural extension that a non-SHF_LINK_ORDER cannot be a separator.
Symbol assignments can delimiter the contents of SHF_LINK_ORDER
sections.  Allowing SHF_LINK_ORDER sections across symbol assignments
(especially __start_/__stop_) can make things hard to explain. The
restriction should not be a problem for practical use cases.

Reviewed By: psmith

Differential Revision: https://reviews.llvm.org/D77007
  • Loading branch information
MaskRay committed Mar 30, 2020
1 parent 094b11c commit 673e81e
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 31 deletions.
8 changes: 4 additions & 4 deletions lld/ELF/OutputSections.cpp
Expand Up @@ -114,8 +114,7 @@ void OutputSection::commitSection(InputSection *isec) {
flags = isec->flags;
} else {
// Otherwise, check if new type or flags are compatible with existing ones.
unsigned mask = SHF_TLS | SHF_LINK_ORDER;
if ((flags & mask) != (isec->flags & mask))
if ((flags ^ isec->flags) & SHF_TLS)
error("incompatible section flags for " + name + "\n>>> " + toString(isec) +
": 0x" + utohexstr(isec->flags) + "\n>>> output section " + name +
": 0x" + utohexstr(flags));
Expand Down Expand Up @@ -366,8 +365,9 @@ void OutputSection::finalize() {
// all InputSections in the OutputSection have the same dependency.
if (auto *ex = dyn_cast<ARMExidxSyntheticSection>(first))
link = ex->getLinkOrderDep()->getParent()->sectionIndex;
else if (auto *d = first->getLinkOrderDep())
link = d->getParent()->sectionIndex;
else if (first->flags & SHF_LINK_ORDER)
if (auto *d = first->getLinkOrderDep())
link = d->getParent()->sectionIndex;
}

if (type == SHT_GROUP) {
Expand Down
27 changes: 20 additions & 7 deletions lld/ELF/Writer.cpp
Expand Up @@ -1562,17 +1562,30 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
// but sort must consider them all at once.
std::vector<InputSection **> scriptSections;
std::vector<InputSection *> sections;
bool started = false, stopped = false;
for (BaseCommand *base : sec->sectionCommands) {
if (auto *isd = dyn_cast<InputSectionDescription>(base)) {
for (InputSection *&isec : isd->sections) {
scriptSections.push_back(&isec);
sections.push_back(isec);

InputSection *link = isec->getLinkOrderDep();
if (!link->getParent())
error(toString(isec) + ": sh_link points to discarded section " +
toString(link));
if (!(isec->flags & SHF_LINK_ORDER)) {
if (started)
stopped = true;
} else if (stopped) {
error(toString(isec) + ": SHF_LINK_ORDER sections in " + sec->name +
" are not contiguous");
} else {
started = true;

scriptSections.push_back(&isec);
sections.push_back(isec);

InputSection *link = isec->getLinkOrderDep();
if (!link->getParent())
error(toString(isec) + ": sh_link points to discarded section " +
toString(link));
}
}
} else if (started) {
stopped = true;
}
}

Expand Down
10 changes: 7 additions & 3 deletions lld/test/ELF/linkerscript/linkorder.s
Expand Up @@ -7,6 +7,8 @@
# RUN: ld.lld -T %t.lds %t.o -o %t
# RUN: llvm-readelf -S -x .rodata -x .text %t | FileCheck %s

# CHECK: [ 1] .rodata {{.*}} AL 3
# CHECK: [ 3] .text {{.*}} AX 0
# CHECK: Hex dump of section '.rodata':
# CHECK-NEXT: 00020103
# CHECK: Hex dump of section '.text':
Expand All @@ -17,6 +19,8 @@
# RUN: ld.lld -T %t1.lds %t.o -o %t1
# RUN: llvm-readelf -S -x .rodata -x .text %t1 | FileCheck --check-prefix=CHECK1 %s

# CHECK1: [ 1] .rodata {{.*}} AL 3
# CHECK1: [ 3] .text {{.*}} AX 0
# CHECK1: Hex dump of section '.rodata':
# CHECK1-NEXT: 00010203
# CHECK1: Hex dump of section '.text':
Expand All @@ -35,17 +39,17 @@

## Non-contiguous SHF_LINK_ORDER sections, separated by a BYTE.
# RUN: echo 'SECTIONS { .rodata : {*(.rodata.foo) BYTE(0) *(.rodata.bar)} }' > %terr1.lds
# RUN: ld.lld -T %terr1.lds %t.o -o /dev/null
# RUN: not ld.lld -T %terr1.lds %t.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s

## Non-contiguous SHF_LINK_ORDER sections, separated by a non-SHF_LINK_ORDER section.
# RUN: echo 'SECTIONS { .rodata : {*(.rodata.foo) *(.text) *(.rodata.bar)} }' > %terr2.lds
# RUN: not ld.lld -T %terr2.lds %t.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s

## Non-contiguous SHF_LINK_ORDER sections, separated by a symbol assignment.
# RUN: echo 'SECTIONS { .rodata : {*(.rodata.foo) a = .; *(.rodata.bar)} }' > %terr3.lds
# RUN: ld.lld -T %terr3.lds %t.o -o /dev/null
# RUN: not ld.lld -T %terr3.lds %t.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s

# ERR: error: incompatible section flags for .rodata
# ERR: error: {{.*}}.o:(.rodata.bar): SHF_LINK_ORDER sections in .rodata are not contiguous

.global _start
_start:
Expand Down
17 changes: 0 additions & 17 deletions lld/test/ELF/linkorder-err3.s

This file was deleted.

0 comments on commit 673e81e

Please sign in to comment.