[lld] 673e81e - [ELF] Allow SHF_LINK_ORDER and non-SHF_LINK_ORDER to be mixed

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 30 10:04:08 PDT 2020


Author: Fangrui Song
Date: 2020-03-30T10:03:55-07:00
New Revision: 673e81eee4fa3ffa38736f1063e6c4fa2d9278b0

URL: https://github.com/llvm/llvm-project/commit/673e81eee4fa3ffa38736f1063e6c4fa2d9278b0
DIFF: https://github.com/llvm/llvm-project/commit/673e81eee4fa3ffa38736f1063e6c4fa2d9278b0.diff

LOG: [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

Added: 
    

Modified: 
    lld/ELF/OutputSections.cpp
    lld/ELF/Writer.cpp
    lld/test/ELF/linkerscript/linkorder.s

Removed: 
    lld/test/ELF/linkorder-err3.s


################################################################################
diff  --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index e5360c1ce23a..c38d4f0b6750 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<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) {

diff  --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 15b04d6fe332..5dcffa560e1e 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -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;
       }
     }
 

diff  --git a/lld/test/ELF/linkerscript/linkorder.s b/lld/test/ELF/linkerscript/linkorder.s
index 060b82900a18..1eb93ecd3218 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 2e36ab457677..000000000000
--- 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", at progbits
-.quad 0
-
-.section .bar,"ao", at progbits,.foo,unique,1
-.quad 0
-
-.section .bar,"a", at progbits,unique,2
-.quad 1


        


More information about the llvm-commits mailing list