[lld] e8a11c0 - [ELF] Allow mixed SHF_LINK_ORDER & non-SHF_LINK_ORDER sections and sort within InputSectionDescription

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 17 11:29:12 PDT 2020


Author: Fangrui Song
Date: 2020-08-17T11:29:05-07:00
New Revision: e8a11c0558af93182ca03c1afcdb857394955767

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

LOG: [ELF] Allow mixed SHF_LINK_ORDER & non-SHF_LINK_ORDER sections and sort within InputSectionDescription

LLD currently does not allow non-contiguous SHF_LINK_ORDER components in an
output section. This makes it infeasible to add SHF_LINK_ORDER to an existing
metadata section if backward compatibility with older object files are
concerned.

We did not allow mixed components (like GNU ld) and D77007 relaxed to allow
non-contiguous SHF_LINK_ORDER components. This patch allows arbitrary mix, with
sorting performed within an InputSectionDescription. For example,
`.rodata : {*(.rodata.foo) *(.rodata.bar)}`, has two InputSectionDescription's.
If there is at least one SHF_LINK_ORDER and at least one non-SHF_LINK_ORDER in
.rodata.foo, they are ordered within `*(.rodata.foo)`: we arbitrarily place
SHF_LINK_ORDER components before non-SHF_LINK_ORDER components (like Solaris ld).

`*(.rodata.bar)` is ordered similarly, but the two InputSectionDescription's
don't interact.  It can be argued that this is more reasonable than the previous
behavior where written order was not respected.

It would be nice if the two different semantics (ordering requirement & garbage
collection) were not overloaded on one section flag, however, it is probably
difficult to obtain a generic flag at this point
(https://groups.google.com/forum/#!topic/generic-abi/hgx_m1aXqUo
"SHF_LINK_ORDER's original semantics make upgrade difficult").

(Actually, without the GC semantics, SHF_LINK_ORDER would still have the
sh_link!=0 & sh_link=0 issue. It is just that people find the GC semantics more
useful and tend to use the feature more often.)

GNU ld feature request: https://sourceware.org/bugzilla/show_bug.cgi?id=16833

Differential Revision: https://reviews.llvm.org/D84001

Added: 
    

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

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 2cb508cc43da..cffdce0d6c31 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1618,9 +1618,10 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
 }
 
 static bool compareByFilePosition(InputSection *a, InputSection *b) {
-  InputSection *la = a->getLinkOrderDep();
-  InputSection *lb = b->getLinkOrderDep();
-  // SHF_LINK_ORDER sections with non-zero sh_link are ordered before others.
+  InputSection *la = a->flags & SHF_LINK_ORDER ? a->getLinkOrderDep() : nullptr;
+  InputSection *lb = b->flags & SHF_LINK_ORDER ? b->getLinkOrderDep() : nullptr;
+  // SHF_LINK_ORDER sections with non-zero sh_link are ordered before
+  // non-SHF_LINK_ORDER sections and SHF_LINK_ORDER sections with zero sh_link.
   if (!la || !lb)
     return la && !lb;
   OutputSection *aOut = la->getParent();
@@ -1642,44 +1643,34 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
         sec->type == SHT_ARM_EXIDX)
       continue;
 
-    // Link order may be distributed across several InputSectionDescriptions
-    // but sort must consider them all at once.
+    // Link order may be distributed across several InputSectionDescriptions.
+    // Sorting is performed separately.
     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) {
-          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 && !link->getParent())
-              error(toString(isec) + ": sh_link points to discarded section " +
-                    toString(link));
-          }
+      auto *isd = dyn_cast<InputSectionDescription>(base);
+      if (!isd)
+        continue;
+      bool hasLinkOrder = false;
+      scriptSections.clear();
+      sections.clear();
+      for (InputSection *&isec : isd->sections) {
+        if (isec->flags & SHF_LINK_ORDER) {
+          InputSection *link = isec->getLinkOrderDep();
+          if (link && !link->getParent())
+            error(toString(isec) + ": sh_link points to discarded section " +
+                  toString(link));
+          hasLinkOrder = true;
         }
-      } else if (started) {
-        stopped = true;
+        scriptSections.push_back(&isec);
+        sections.push_back(isec);
+      }
+      if (hasLinkOrder && errorCount() == 0) {
+        llvm::stable_sort(sections, compareByFilePosition);
+        for (int i = 0, n = sections.size(); i != n; ++i)
+          *scriptSections[i] = sections[i];
       }
     }
-
-    if (errorCount())
-      continue;
-
-    llvm::stable_sort(sections, compareByFilePosition);
-
-    for (int i = 0, n = sections.size(); i < n; ++i)
-      *scriptSections[i] = sections[i];
   }
 }
 

diff  --git a/lld/test/ELF/linkerscript/linkorder.s b/lld/test/ELF/linkerscript/linkorder.s
index 1eb93ecd3218..d4bbfc06392d 100644
--- a/lld/test/ELF/linkerscript/linkorder.s
+++ b/lld/test/ELF/linkerscript/linkorder.s
@@ -2,7 +2,7 @@
 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
 
 ## Contiguous SHF_LINK_ORDER sections.
-# RUN: echo 'SECTIONS { .rodata : {BYTE(0) *(.rodata*) BYTE(3)} \
+# RUN: echo 'SECTIONS { .rodata : {BYTE(0) *(.rodata*) BYTE(4)} \
 # RUN:   .text : {*(.text.bar) *(.text.foo)} }' > %t.lds
 # RUN: ld.lld -T %t.lds %t.o -o %t
 # RUN: llvm-readelf -S -x .rodata -x .text %t | FileCheck %s
@@ -10,11 +10,11 @@
 # CHECK:      [ 1] .rodata   {{.*}} AL 3
 # CHECK:      [ 3] .text     {{.*}} AX 0
 # CHECK:      Hex dump of section '.rodata':
-# CHECK-NEXT: 00020103
+# CHECK-NEXT: 00030102 04
 # CHECK:      Hex dump of section '.text':
 # CHECK-NEXT: 0201
 
-# RUN: echo 'SECTIONS { .rodata : {BYTE(0) *(.rodata*) BYTE(3)} \
+# RUN: echo 'SECTIONS { .rodata : {BYTE(0) *(.rodata*) BYTE(4)} \
 # RUN:  .text : {*(.text.foo) *(.text.bar)} }' > %t1.lds
 # RUN: ld.lld -T %t1.lds %t.o -o %t1
 # RUN: llvm-readelf -S -x .rodata -x .text %t1 | FileCheck --check-prefix=CHECK1 %s
@@ -22,34 +22,46 @@
 # CHECK1:      [ 1] .rodata   {{.*}} AL 3
 # CHECK1:      [ 3] .text     {{.*}} AX 0
 # CHECK1:      Hex dump of section '.rodata':
-# CHECK1-NEXT: 00010203
+# CHECK1-NEXT: 00010302 04
 # CHECK1:      Hex dump of section '.text':
 # CHECK1-NEXT: 0102
 
 ## Adjacent input sections descriptions are contiguous.
-## Orphan section .text.bar precedes .text.foo, so swap the order of .rodata.*
+## Orphan section .text.bar precedes .text.foo. However, don't swap the order of .rodata.*
+## because they are in 
diff erent InputSectionDescriptions.
 # RUN: echo 'SECTIONS { .rodata : {*(.rodata.foo) *(.rodata.bar)} }' > %t2.lds
 # RUN: ld.lld -T %t2.lds %t.o -o %t2
 # RUN: llvm-readelf -S -x .rodata %t2 | FileCheck --check-prefix=CHECK2 %s
 
-# CHECK2:      [ 1] .rodata   {{.*}} AL 4
+# CHECK2:      [ 1] .rodata   {{.*}} AL 5
 # CHECK2:      [ 4] .text.bar {{.*}} AX 0
+# CHECK2-NEXT: [ 5] .text.foo {{.*}} AX 0
 # CHECK2:      Hex dump of section '.rodata':
-# CHECK2-NEXT: 0201
+# CHECK2-NEXT: 010302
 
 ## Non-contiguous SHF_LINK_ORDER sections, separated by a BYTE.
-# RUN: echo 'SECTIONS { .rodata : {*(.rodata.foo) BYTE(0) *(.rodata.bar)} }' > %terr1.lds
-# RUN: not ld.lld -T %terr1.lds %t.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s
+# RUN: echo 'SECTIONS { .rodata : {*(.rodata.foo) BYTE(0) *(.rodata.bar)} }' > %t3.lds
+# RUN: ld.lld -T %t3.lds %t.o -o %t3
+# RUN: llvm-readelf -S -x .rodata %t3 | FileCheck --check-prefix=CHECK3 %s
+
+# CHECK3:      [ 1] .rodata   {{.*}} AL 5
+# CHECK3:      [ 4] .text.bar {{.*}} AX 0
+# CHECK3:      [ 5] .text.foo {{.*}} AX 0
+# CHECK3:      Hex dump of section '.rodata':
+# CHECK3-NEXT: 01000302
 
 ## 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
+# RUN: echo 'SECTIONS { .rodata : {*(.rodata.foo) *(.text) *(.rodata.bar)} }' > %t4.lds
+# RUN: ld.lld -T %t4.lds %t.o -o %t4
+# RUN: llvm-readelf -x .rodata %t4 | FileCheck --check-prefix=CHECK4 %s
 
-## Non-contiguous SHF_LINK_ORDER sections, separated by a symbol assignment.
-# RUN: echo 'SECTIONS { .rodata : {*(.rodata.foo) a = .; *(.rodata.bar)} }' > %terr3.lds
-# RUN: not ld.lld -T %terr3.lds %t.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s
+# CHECK4:      Hex dump of section '.rodata':
+# CHECK4-NEXT: 01cccccc 0302
 
-# ERR: error: {{.*}}.o:(.rodata.bar): SHF_LINK_ORDER sections in .rodata are not contiguous
+## Non-contiguous SHF_LINK_ORDER sections, separated by a symbol assignment.
+# RUN: echo 'SECTIONS { .rodata : {*(.rodata.foo) a = .; *(.rodata.bar)} }' > %t5.lds
+# RUN: ld.lld -T %t5.lds %t.o -o %t5
+# RUN: llvm-readelf -S -x .rodata %t5 | FileCheck --check-prefix=CHECK2 %s
 
 .global _start
 _start:
@@ -63,5 +75,9 @@ _start:
 .byte 1
 .section .rodata.foo,"ao", at progbits,.text.foo
 .byte 1
-.section .rodata.bar,"ao", at progbits,.text.bar
+## If the two .rodata.bar sections are in the same InputSectionDescription,
+## 03 (sh_link!=0) will be ordered before 02 (sh_link=0).
+.section .rodata.bar,"a", at progbits
 .byte 2
+.section .rodata.bar,"ao", at progbits,.text.bar
+.byte 3

diff  --git a/lld/test/ELF/linkorder-mixed.s b/lld/test/ELF/linkorder-mixed.s
index 829853422dba..57b3616e92f9 100644
--- a/lld/test/ELF/linkorder-mixed.s
+++ b/lld/test/ELF/linkorder-mixed.s
@@ -14,9 +14,17 @@
 # CHECK:      Hex dump of section '.linkorder':
 # CHECK-NEXT:   [[#%x,ADDR:]] 01020003
 
-## TODO Allow non-contiguous SHF_LINK_ORDER sections in an output section.
 # RUN: llvm-mc --filetype=obj -triple=x86_64 --defsym EXTRA=1 %s -o %t.o
-# RUN: not ld.lld %t.o -o /dev/null
+# RUN: ld.lld %t.o -o %t1
+# RUN: llvm-readelf -S -x .linkorder %t1 | FileCheck %s --check-prefix=CHECK1
+
+# CHECK1:      [Nr] Name       {{.*}} Size   ES Flg Lk Inf
+# CHECK1-NEXT: [ 0]            {{.*}}
+# CHECK1-NEXT: [ 1] .linkorder {{.*}} 000005 00  AL  2   0
+# CHECK1-NEXT: [ 2] .text      {{.*}}
+
+# CHECK1:      Hex dump of section '.linkorder':
+# CHECK1-NEXT:   [[#%x,ADDR:]] 01020004 03
 
 .section .text,"ax", at progbits,unique,0
 .Ltext0:


        


More information about the llvm-commits mailing list