[lld] 5a44980 - [ELF] Support custom sections between DATA_SEGMENT_ALIGN and DATA_SEGMENT_RELRO_END

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Wed May 4 01:10:53 PDT 2022


Author: Fangrui Song
Date: 2022-05-04T01:10:46-07:00
New Revision: 5a44980f0a8bb2c7dafe9a9f5e5a17699e65cc3d

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

LOG: [ELF] Support custom sections between DATA_SEGMENT_ALIGN and DATA_SEGMENT_RELRO_END

We currently hard code RELRO sections. When a custom section is between
DATA_SEGMENT_ALIGN and DATA_SEGMENT_RELRO_END, we may report a spurious
`error: section: ... is not contiguous with other relro sections`. GNU ld
makes such sections RELRO.

glibc recently switched to default --with-default-link=no. This configuration
places `__libc_atexit` and others between DATA_SEGMENT_ALIGN and
DATA_SEGMENT_RELRO_END. This patch allows such a ld.bfd --verbose
linker script to be fed into lld.

Reviewed By: peter.smith

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

Added: 
    

Modified: 
    lld/ELF/OutputSections.h
    lld/ELF/ScriptParser.cpp
    lld/ELF/Writer.cpp
    lld/test/ELF/linkerscript/data-segment-relro.test

Removed: 
    


################################################################################
diff  --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h
index 9179d14aef07a..020eeaec368ee 100644
--- a/lld/ELF/OutputSections.h
+++ b/lld/ELF/OutputSections.h
@@ -100,6 +100,10 @@ class OutputSection final : public SectionBase {
   // that wasn't needed). This is needed for orphan placement.
   bool hasInputSections = false;
 
+  // The output section description is specified between DATA_SEGMENT_ALIGN and
+  // DATA_RELRO_END.
+  bool relro = false;
+
   void finalize();
   template <class ELFT> void writeTo(uint8_t *buf);
   // Check that the addends for dynamic relocations were written correctly.

diff  --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp
index c58309b12e576..51792da64b82e 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -135,6 +135,9 @@ class ScriptParser final : ScriptLexer {
   // True if a script being read is in the --sysroot directory.
   bool isUnderSysroot = false;
 
+  bool seenDataAlign = false;
+  bool seenRelroEnd = false;
+
   // A set to detect an INCLUDE() cycle.
   StringSet<> seen;
 };
@@ -583,6 +586,14 @@ void ScriptParser::readSections() {
     else
       v.push_back(readOutputSectionDescription(tok));
   }
+
+  // If DATA_SEGMENT_RELRO_END is absent, for sections after DATA_SEGMENT_ALIGN,
+  // the relro fields should be cleared.
+  if (!seenRelroEnd)
+    for (SectionCommand *cmd : v)
+      if (auto *osd = dyn_cast<OutputDesc>(cmd))
+        osd->osec.relro = false;
+
   script->sectionCommands.insert(script->sectionCommands.end(), v.begin(),
                                  v.end());
 
@@ -887,6 +898,8 @@ OutputDesc *ScriptParser::readOverlaySectionDescription() {
 OutputDesc *ScriptParser::readOutputSectionDescription(StringRef outSec) {
   OutputDesc *cmd = script->createOutputSection(outSec, getCurrentLocation());
   OutputSection *osec = &cmd->osec;
+  // Maybe relro. Will reset to false if DATA_SEGMENT_RELRO_END is absent.
+  osec->relro = seenDataAlign && !seenRelroEnd;
 
   size_t symbolsReferenced = script->referencedSymbols.size();
 
@@ -1358,6 +1371,7 @@ Expr ScriptParser::readPrimary() {
     expect(",");
     readExpr();
     expect(")");
+    seenDataAlign = true;
     return [=] {
       return alignTo(script->getDot(), std::max((uint64_t)1, e().getValue()));
     };
@@ -1377,6 +1391,7 @@ Expr ScriptParser::readPrimary() {
     expect(",");
     readExpr();
     expect(")");
+    seenRelroEnd = true;
     Expr e = getPageSize();
     return [=] { return alignTo(script->getDot(), e().getValue()); };
   }

diff  --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 125d7189a4477..649958b747986 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -761,6 +761,8 @@ template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
 static bool isRelroSection(const OutputSection *sec) {
   if (!config->zRelro)
     return false;
+  if (sec->relro)
+    return true;
 
   uint64_t flags = sec->flags;
 

diff  --git a/lld/test/ELF/linkerscript/data-segment-relro.test b/lld/test/ELF/linkerscript/data-segment-relro.test
index bc24ad48d932e..8aba8acb466f6 100644
--- a/lld/test/ELF/linkerscript/data-segment-relro.test
+++ b/lld/test/ELF/linkerscript/data-segment-relro.test
@@ -15,10 +15,12 @@
 
 # CHECK:      Name           Type     Address          Off      Size ES Flg
 # CHECK-NEXT:                NULL     {{.*}}
-# CHECK:      .dynamic       DYNAMIC  0000000000001000 001000 0000f0 10  WA
-# CHECK-NEXT: .got           PROGBITS 00000000000010f0 0010f0 000008 00  WA
-# CHECK-NEXT: __libc_atexit  PROGBITS 0000000000002000 002000 000008 00  WA
-# CHECK-NEXT: .got.plt       PROGBITS 0000000000002008 002008 000020 00  WA
+# CHECK:      .orphan.ro     PROGBITS {{.*}}                              A
+# CHECK:      .dynamic       DYNAMIC  {{.*}}                             WA
+# CHECK-NEXT: __libc_atexit  PROGBITS {{.*}}                             WA
+# CHECK-NEXT: .got           PROGBITS {{.*}}                             WA
+# CHECK-NEXT: .got.plt       PROGBITS {{.*}}                             WA
+# CHECK:      .orphan.rw     PROGBITS {{.*}}                             WA
 
 # CHECK1:      Program Headers:
 # CHECK1-NOT:  GNU_RELRO
@@ -35,10 +37,12 @@
 # CHECK2-NEXT:   GNU_STACK
 
 # CHECK2:      Section to Segment mapping:
-# CHECK2:        06     .dynamic .got {{$}}
+# CHECK2:        06     .dynamic __libc_atexit .got {{$}}
 
 # RUN: sed '/DATA_SEGMENT_RELRO_END/d' %t/1.t > %t/2.t
-# RUN: ld.lld %t/a.o %t/b.so -T %t/2.t -o /dev/null
+# RUN: not ld.lld %t/a.o %t/b.so -T %t/2.t -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR
+
+# ERR: error: section: .got is not contiguous with other relro sections
 
 #--- a.s
 .global _start
@@ -56,6 +60,12 @@ _start:
 .section __libc_atexit,"aw", at progbits
 .dc.a __libc_atexit
 
+.section .orphan.ro,"a", at progbits
+.dc.a 0
+
+.section .orphan.rw,"aw", at progbits
+.dc.a .orphan.rw
+
 #--- 1.t
 SECTIONS {
   . = SIZEOF_HEADERS;
@@ -66,11 +76,12 @@ SECTIONS {
   . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
 
   .dynamic : { *(.dynamic) }
+  ## The custom section __libc_atexit is made relro.
+  __libc_atexit : { *(__libc_atexit) }
   .got : { *(.got) }
 
   . = DATA_SEGMENT_RELRO_END (1 ? 24 : 0, .);
 
-  __libc_atexit : { *(__libc_atexit) }
   .got.plt : { *(.got.plt) }
   .data : { *(.data) }
   .bss : { *(.bss) }


        


More information about the llvm-commits mailing list