From 673e81eee4fa3ffa38736f1063e6c4fa2d9278b0 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sat, 28 Mar 2020 23:12:04 -0700 Subject: [PATCH] [ELF] Allow SHF_LINK_ORDER and non-SHF_LINK_ORDER to be mixed 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 (https://github.com/ClangBuiltLinux/linux/issues/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 --- lld/ELF/OutputSections.cpp | 8 ++++---- lld/ELF/Writer.cpp | 27 ++++++++++++++++++++------- lld/test/ELF/linkerscript/linkorder.s | 10 +++++++--- lld/test/ELF/linkorder-err3.s | 17 ----------------- 4 files changed, 31 insertions(+), 31 deletions(-) delete mode 100644 lld/test/ELF/linkorder-err3.s diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index e5360c1ce23ac..c38d4f0b67508 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -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)); @@ -366,8 +365,9 @@ void OutputSection::finalize() { // all InputSections in the OutputSection have the same dependency. if (auto *ex = dyn_cast(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) { diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 15b04d6fe332b..5dcffa560e1e6 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1562,17 +1562,30 @@ template void Writer::resolveShfLinkOrder() { // but sort must consider them all at once. std::vector scriptSections; std::vector sections; + bool started = false, stopped = false; for (BaseCommand *base : sec->sectionCommands) { if (auto *isd = dyn_cast(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; } } diff --git a/lld/test/ELF/linkerscript/linkorder.s b/lld/test/ELF/linkerscript/linkorder.s index 060b82900a180..1eb93ecd3218a 100644 --- a/lld/test/ELF/linkerscript/linkorder.s +++ b/lld/test/ELF/linkerscript/linkorder.s @@ -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': @@ -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': @@ -35,7 +39,7 @@ ## 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 @@ -43,9 +47,9 @@ ## 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: diff --git a/lld/test/ELF/linkorder-err3.s b/lld/test/ELF/linkorder-err3.s deleted file mode 100644 index 2e36ab457677c..0000000000000 --- a/lld/test/ELF/linkorder-err3.s +++ /dev/null @@ -1,17 +0,0 @@ -# REQUIRES: x86 - -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s - -# CHECK: error: incompatible section flags for .bar -# CHECK-NEXT: >>> {{.*}}.o:(.bar): 0x2 -# CHECK-NEXT: >>> output section .bar: 0x82 - -.section .foo,"a",@progbits -.quad 0 - -.section .bar,"ao",@progbits,.foo,unique,1 -.quad 0 - -.section .bar,"a",@progbits,unique,2 -.quad 1