[lld] a6db64e - [ELF] Allow sections after a non-SHF_ALLOC section to be covered by PT_LOAD

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 6 08:27:25 PDT 2020


Author: Fangrui Song
Date: 2020-08-06T08:27:15-07:00
New Revision: a6db64ef4a9906c96ef5652739ac15aefaa7827c

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

LOG: [ELF] Allow sections after a non-SHF_ALLOC section to be covered by PT_LOAD

GNU ld allows sections after a non-SHF_ALLOC section to be covered by PT_LOAD
(PR37607) and assigns addresses to non-SHF_ALLOC output sections (similar to
SHF_ALLOC NOBITS sections. The location counter is not advanced).

This patch tries to fix PR37607 (remove a special case in
`Writer<ELFT>::createPhdrs`). To make the created PT_LOAD meaningful, we cannot
reset dot to 0 for a middle non-SHF_ALLOC output section. This results in
removal of two special cases in LinkerScript::assignOffsets. Non-SHF_ALLOC
non-orphan sections can have non-zero addresses like in GNU ld.

The zero address rule for non-SHF_ALLOC sections is weakened to apply to orphan
only. This results in a special case in createSection and findOrphanPos, respectively.

Reviewed By: jhenderson

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

Added: 
    

Modified: 
    lld/ELF/LinkerScript.cpp
    lld/ELF/Writer.cpp
    lld/test/ELF/linkerscript/compress-debug-sections-custom.s
    lld/test/ELF/linkerscript/sections.s
    lld/test/ELF/linkerscript/symbols-non-alloc.test
    lldb/test/Shell/SymbolFile/DWARF/Inputs/debug-line-basic.script

Removed: 
    


################################################################################
diff  --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index 72e2ebff9b8c..a187aa1eb05a 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -586,6 +586,8 @@ static OutputSection *findByName(ArrayRef<BaseCommand *> vec,
 static OutputSection *createSection(InputSectionBase *isec,
                                     StringRef outsecName) {
   OutputSection *sec = script->createOutputSection(outsecName, "<internal>");
+  if (!(isec->flags & SHF_ALLOC))
+    sec->addrExpr = [] { return 0; };
   sec->recordSection(isec);
   return sec;
 }
@@ -848,9 +850,6 @@ static OutputSection *findFirstSection(PhdrEntry *load) {
 // This function assigns offsets to input sections and an output section
 // for a single sections command (e.g. ".text { *(.text); }").
 void LinkerScript::assignOffsets(OutputSection *sec) {
-  if (!(sec->flags & SHF_ALLOC))
-    dot = 0;
-
   const bool sameMemRegion = ctx->memRegion == sec->memRegion;
   const bool prevLMARegionIsDefault = ctx->lmaRegion == nullptr;
   ctx->memRegion = sec->memRegion;
@@ -858,7 +857,7 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
   if (ctx->memRegion)
     dot = ctx->memRegion->curPos;
 
-  if ((sec->flags & SHF_ALLOC) && sec->addrExpr)
+  if (sec->addrExpr)
     setDot(sec->addrExpr, sec->location, false);
 
   // If the address of the section has been moved forward by an explicit

diff  --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index c1469e123336..1bd6fb61e2e4 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1234,7 +1234,13 @@ static bool shouldSkip(BaseCommand *cmd) {
 static std::vector<BaseCommand *>::iterator
 findOrphanPos(std::vector<BaseCommand *>::iterator b,
               std::vector<BaseCommand *>::iterator e) {
+  // OutputSections without the SHF_ALLOC flag are not part of the memory image
+  // and their addresses usually don't matter. Place any orphan sections without
+  // the SHF_ALLOC flag at the end so that these do not affect the address
+  // assignment of OutputSections with the SHF_ALLOC flag.
   OutputSection *sec = cast<OutputSection>(*e);
+  if (!(sec->flags & SHF_ALLOC))
+    return e;
 
   // Find the first element that has as close a rank as possible.
   auto i = std::max_element(b, e, [=](BaseCommand *a, BaseCommand *b) {
@@ -2329,8 +2335,6 @@ std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs(Partition &part) {
   }
 
   for (OutputSection *sec : outputSections) {
-    if (!(sec->flags & SHF_ALLOC))
-      break;
     if (!needsPtLoad(sec))
       continue;
 

diff  --git a/lld/test/ELF/linkerscript/compress-debug-sections-custom.s b/lld/test/ELF/linkerscript/compress-debug-sections-custom.s
index f61d6398b1f0..7b9a8d091bf5 100644
--- a/lld/test/ELF/linkerscript/compress-debug-sections-custom.s
+++ b/lld/test/ELF/linkerscript/compress-debug-sections-custom.s
@@ -1,9 +1,10 @@
 # REQUIRES: x86, zlib
 
+## NOTE GNU ld makes .debug_str and .debug_info SHF_ALLOC due to `. += 10`.
 # RUN: echo "SECTIONS { \
 # RUN:          .text : { . += 0x10; *(.text) } \
-# RUN:          .debug_str : { . += 0x10; *(.debug_str) } \
-# RUN:          .debug_info : { . += 0x10; *(.debug_info) } \
+# RUN:          .debug_str 0 : { . += 0x10; *(.debug_str) } \
+# RUN:          .debug_info 0 : { . += 0x10; *(.debug_info) } \
 # RUN:          }" > %t.script
 
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o

diff  --git a/lld/test/ELF/linkerscript/sections.s b/lld/test/ELF/linkerscript/sections.s
index 14a9ac5ab75b..fa346406b743 100644
--- a/lld/test/ELF/linkerscript/sections.s
+++ b/lld/test/ELF/linkerscript/sections.s
@@ -25,8 +25,10 @@
 # SEC-DEFAULT: 7 .shstrtab     0000003b {{[0-9a-f]*}}
 # SEC-DEFAULT: 8 .strtab       00000008 {{[0-9a-f]*}}
 
-# Sections are put in order specified in linker script, other than alloc
-# sections going first.
+## Sections are placed in the order specified by the linker script. .data has
+## a PT_LOAD segment, even if it is preceded by a non-alloc section. To
+## allow this, place non-alloc orphan sections at the end and advance
+## location counters for non-alloc non-orphan sections.
 # RUN: echo "SECTIONS { \
 # RUN:          .bss : { *(.bss) } \
 # RUN:          other : { *(other) } \
@@ -34,20 +36,27 @@
 # RUN:          .symtab : { *(.symtab) } \
 # RUN:          .strtab : { *(.strtab) } \
 # RUN:          .data : { *(.data) } \
-# RUN:          .text : { *(.text) } }" > %t.script
-# RUN: ld.lld -o %t3 --script %t.script %t
-# RUN: llvm-objdump --section-headers %t3 | \
-# RUN:   FileCheck -check-prefix=SEC-ORDER %s
+# RUN:          .text : { *(.text) } }" > %t3.lds
+# RUN: ld.lld -o %t3a -T %t3.lds %t
+# RUN: llvm-readelf -S -l %t3a | FileCheck --check-prefix=SEC-ORDER %s
+# RUN: ld.lld -o %t3b -T %t3.lds --unique %t
+# RUN: llvm-readelf -S -l %t3b | FileCheck --check-prefix=SEC-ORDER %s
 
-#           Idx Name          Size
-# SEC-ORDER: 1 .bss          00000002 {{[0-9a-f]*}} BSS
-# SEC-ORDER: 2 other         00000003 {{[0-9a-f]*}} DATA
-# SEC-ORDER: 3 .shstrtab     0000003b {{[0-9a-f]*}}
-# SEC-ORDER: 4 .symtab       00000030 {{[0-9a-f]*}}
-# SEC-ORDER: 5 .strtab       00000008 {{[0-9a-f]*}}
-# SEC-ORDER: 6 .comment      00000008 {{[0-9a-f]*}}
-# SEC-ORDER: 7 .data         00000020 {{[0-9a-f]*}} DATA
-# SEC-ORDER: 8 .text         0000000e {{[0-9a-f]*}} TEXT
+# SEC-ORDER:       [Nr] Name      Type     Address          Off    Size   ES Flg
+# SEC-ORDER:       [ 0]           NULL     0000000000000000 000000 000000 00
+# SEC-ORDER-NEXT:  [ 1] .bss      NOBITS   0000000000000000 001000 000002 00  WA
+# SEC-ORDER-NEXT:  [ 2] other     PROGBITS 0000000000000002 001002 000003 00  WA
+# SEC-ORDER-NEXT:  [ 3] .shstrtab STRTAB   0000000000000005 001005 00003b 00
+# SEC-ORDER-NEXT:  [ 4] .symtab   SYMTAB   0000000000000040 001040 000030 18
+# SEC-ORDER-NEXT:  [ 5] .strtab   STRTAB   0000000000000070 001070 000008 00
+# SEC-ORDER-NEXT:  [ 6] .data     PROGBITS 0000000000000078 001078 000020 00  WA
+# SEC-ORDER-NEXT:  [ 7] .text     PROGBITS 0000000000000098 001098 00000e 00  AX
+# SEC-ORDER-NEXT:  [ 8] .comment  PROGBITS 0000000000000000 0010a6 000008 01  MS
+
+# SEC-ORDER:        Type      Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
+# SEC-ORDER-NEXT:   LOAD      0x001000 0x0000000000000000 0x0000000000000000 0x000098 0x000098 RW  0x1000
+# SEC-ORDER-NEXT:   LOAD      0x001098 0x0000000000000098 0x0000000000000098 0x00000e 0x00000e R E 0x1000
+# SEC-ORDER-NEXT:   GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0
 
 # .text and .data have swapped names but proper sizes and types.
 # RUN: echo "SECTIONS { \
@@ -89,6 +98,28 @@
 # SEC-MULTI-NEXT:   .shstrtab     00000035 {{[0-9a-f]*}}
 # SEC-MULTI-NEXT:   .strtab       00000008 {{[0-9a-f]*}}
 
+## other is placed in a PT_LOAD segment even if it is preceded by a non-alloc section.
+## The current implementation places .data, .bss, .comment and other in the same PT_LOAD.
+# RUN: echo 'SECTIONS { \
+# RUN:          .text : { *(.text) } \
+# RUN:          .data : { *(.data) } \
+# RUN:          .comment : { *(.comment) } \
+# RUN:          other : { *(other) } }' > %t5.lds
+# RUN: ld.lld -o %t5 -T %t5.lds %t
+# RUN: llvm-readelf -S -l %t5 | FileCheck --check-prefix=SEP-BY-NONALLOC %s
+
+# SEP-BY-NONALLOC:      [Nr] Name      Type     Address          Off    Size   ES Flg
+# SEP-BY-NONALLOC:      [ 1] .text     PROGBITS 0000000000000000 001000 00000e 00  AX
+# SEP-BY-NONALLOC-NEXT: [ 2] .data     PROGBITS 000000000000000e 00100e 000020 00  WA
+# SEP-BY-NONALLOC-NEXT: [ 3] .bss      NOBITS   000000000000002e 00102e 000002 00  WA
+# SEP-BY-NONALLOC-NEXT: [ 4] .comment  PROGBITS 0000000000000030 00102e 000008 01  MS
+# SEP-BY-NONALLOC-NEXT: [ 5] other     PROGBITS 0000000000000038 001038 000003 00  WA
+
+# SEP-BY-NONALLOC:      Type      Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
+# SEP-BY-NONALLOC-NEXT: LOAD      0x001000 0x0000000000000000 0x0000000000000000 0x00000e 0x00000e R E 0x1000
+# SEP-BY-NONALLOC-NEXT: LOAD      0x00100e 0x000000000000000e 0x000000000000000e 0x00002d 0x00002d RW  0x1000
+# SEP-BY-NONALLOC-NEXT: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0
+
 # Input section pattern contains additional semicolon.
 # Case found in linux kernel script. Check we are able to parse it.
 # RUN: echo "SECTIONS { .text : { ;;*(.text);;S = 0;; } }" > %t.script

diff  --git a/lld/test/ELF/linkerscript/symbols-non-alloc.test b/lld/test/ELF/linkerscript/symbols-non-alloc.test
index 920cff96a3a2..2bd6fc84df46 100644
--- a/lld/test/ELF/linkerscript/symbols-non-alloc.test
+++ b/lld/test/ELF/linkerscript/symbols-non-alloc.test
@@ -1,14 +1,17 @@
 # REQUIRES: x86
+## The address of a symbol assignment after a non-SHF_ALLOC section equals the
+## end address of the section.
+
 # RUN: echo '.section .nonalloc,""; .quad 0' \
 # RUN:   | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t
 # RUN: ld.lld -o %t2 --script %s %t
 # RUN: llvm-objdump --section-headers -t %t2 | FileCheck %s
 
 # CHECK: Sections:
-# CHECK:  .nonalloc     00000008 0000000000000000
+# CHECK:  .nonalloc     00000008 0000000000000120
 
 # CHECK: SYMBOL TABLE:
-# CHECK:  0000000000000008 g .nonalloc 0000000000000000 Sym
+# CHECK:  0000000000000128 g .nonalloc 0000000000000000 Sym
 
 SECTIONS {
   . = SIZEOF_HEADERS;

diff  --git a/lldb/test/Shell/SymbolFile/DWARF/Inputs/debug-line-basic.script b/lldb/test/Shell/SymbolFile/DWARF/Inputs/debug-line-basic.script
index 7f3a1b9c2ff9..f5f89d137813 100644
--- a/lldb/test/Shell/SymbolFile/DWARF/Inputs/debug-line-basic.script
+++ b/lldb/test/Shell/SymbolFile/DWARF/Inputs/debug-line-basic.script
@@ -2,11 +2,11 @@ PHDRS {
   text PT_LOAD;
 }
 SECTIONS {
-  .shstrtab     : { *(.shstrtab    ) }
-  .debug_info   : { *(.debug_info  ) }
-  .debug_line   : { *(.debug_line  ) }
-  .debug_str    : { *(.debug_str   ) }
-  .debug_abbrev : { *(.debug_abbrev) }
+  .shstrtab     0 : { *(.shstrtab    ) }
+  .debug_info   0 : { *(.debug_info  ) }
+  .debug_line   0 : { *(.debug_line  ) }
+  .debug_str    0 : { *(.debug_str   ) }
+  .debug_abbrev 0 : { *(.debug_abbrev) }
 
   . = 0x201000;
   .text : { *(.text .text.f) } :text


        


More information about the llvm-commits mailing list