[lld] [ELF] Align the end of PT_GNU_RELRO associated PT_LOAD to a common-page-size boundary (PR #66042)

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 13 15:15:04 PDT 2023


https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/66042:

>From 2b7373cbf7ee8abbfaec33bea5a7673f31afea7f Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sun, 10 Sep 2023 21:07:20 -0700
Subject: [PATCH 1/2] [ELF] Align the end of PT_GNU_RELRO associated PT_LOAD to
 a common-page-size boundary

Close #57618: currently we align the end of PT_GNU_RELRO to a common-page-size
boundary, but do not align the end of the associated PT_LOAD. This is benign
when runtime_page_size >= common-page-size.

However, when runtime_page_size < common-page-size, it is possible that
`alignUp(end(PT_LOAD), page_size) < alignDown(end(PT_GNU_RELRO), page_size)`.
In this case, rtld's mprotect call for PT_GNU_RELRO will apply to unmapped
regions and lead to an error, e.g.

```
error while loading shared libraries: cannot apply additional memory protection after relocation: Cannot allocate memory
```

To fix the issue, apply two changes:

* in the presence of SECTIONS: change DATA_SEGMENT_RELRO_END (see also https://reviews.llvm.org/D124656) to use max-page-size instead of common-page-size
* in the absence of PHDRS/SECTIONS: ensure the end of the PT_LOAD program loader associated with the PT_GNU_RELRO segment is aligned to a common-page-size boundary.

To prevent strip from corrupting PT_LOAD program headers, add a padding section
.relro_padding like mold.

In the presence of PHDRS/SECTIONS commands, we don't add .relro_padding or align
the end of PT_GNU_RELRO. This is different from the previous behavior where we
unconditionally aligned the end of PT_GNU_RELRO to a common-page-size. I think
this change is acceptable. Most SECTIONS users don't use RELRO anyway.

---

Close #65002: GNU ld from 2.39 onwards aligns the end of PT_GNU_RELRO to a
max-page-size boundary (https://sourceware.org/PR28824) so that the last page is
protected even if system-page-size > common-page-size.

In my opinion, losing protection for the last page when the system page size is
larger than common-page-size is not really an issue. Double mapping a page of up
to max-common-page for the protection could cause undesired VM waste. Internally
we had users complaining about 2MiB max-page-size applying to shared objects.

Our two RW PT_LOAD design gives more flexibility.
I believe we should keep common-page-size as the RELRO alignment boundary,
otherwise the setting is just useless. Users who are really anxious can set
common-page-size to match their system page size.

---

17 tests need updating as there are lots of change detectors.

* avoid-empty-program-headers.s: test that if the only RELRO section is .tbss, we don't need .relro_padding
* ppc64-toc-addis-nop.s: that that when PHDRS is used, we should not need .relro_padding
---
 lld/ELF/Driver.cpp                            |  4 +--
 lld/ELF/LinkerScript.cpp                      | 15 +++++++++++
 lld/ELF/ScriptParser.cpp                      |  3 +--
 lld/ELF/SyntheticSections.cpp                 |  5 ++++
 lld/ELF/SyntheticSections.h                   | 11 ++++++++
 lld/ELF/Writer.cpp                            | 26 ++++++++++---------
 lld/docs/ReleaseNotes.rst                     |  3 ++-
 lld/test/ELF/arm-execute-only.s               |  4 +--
 lld/test/ELF/end-dso-defined.s                |  6 ++---
 .../ELF/linkerscript/data-segment-relro.test  | 23 ++++++++--------
 lld/test/ELF/linkerscript/insert-before.test  |  2 +-
 lld/test/ELF/map-file-copy.s                  |  2 +-
 lld/test/ELF/map-file.s                       |  6 +++--
 lld/test/ELF/partition-notes.s                |  2 +-
 lld/test/ELF/partition-synthetic-sections.s   |  1 +
 lld/test/ELF/relocation-copy-relro.s          | 19 ++++++++++++++
 lld/test/ELF/relro-bss.s                      |  3 ++-
 lld/test/ELF/relro-copyrel-bss-script.s       |  2 +-
 lld/test/ELF/relro.s                          |  4 +--
 lld/test/ELF/riscv-section-layout.s           |  2 ++
 lld/test/ELF/section-name.s                   |  3 ++-
 lld/test/ELF/separate-segments.s              |  6 ++---
 lld/test/ELF/shuffle-sections-init-fini.s     |  4 +--
 lld/test/ELF/shuffle-sections.s               |  4 +--
 lld/test/ELF/sort-norosegment.s               |  2 +-
 lld/test/ELF/x86-64-section-layout.s          |  3 ++-
 26 files changed, 113 insertions(+), 52 deletions(-)

diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 9219314111610d1..9d167293574fa64 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1586,8 +1586,8 @@ static void readConfigs(opt::InputArgList &args) {
 
   // Page alignment can be disabled by the -n (--nmagic) and -N (--omagic).
   // As PT_GNU_RELRO relies on Paging, do not create it when we have disabled
-  // it.
-  if (config->nmagic || config->omagic)
+  // it. Also disable RELRO for -r.
+  if (config->nmagic || config->omagic || config->relocatable)
     config->zRelro = false;
 
   std::tie(config->buildId, config->buildIdVector) = getBuildId(args);
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index 2b9f28ce68d685d..e82230a38bf6318 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -1079,6 +1079,11 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
     }
   }
 
+  // If .relro_padding is present, round up the end to a common-page-size
+  // boundary to protect the last page.
+  if (in.relroPadding && sec == in.relroPadding->getParent())
+    expandOutputSection(alignToPowerOf2(dot, config->commonPageSize) - dot);
+
   // Non-SHF_ALLOC sections do not affect the addresses of other OutputSections
   // as they are not part of the process image.
   if (!(sec->flags & SHF_ALLOC)) {
@@ -1160,6 +1165,7 @@ void LinkerScript::adjustOutputSections() {
   uint64_t flags = SHF_ALLOC;
 
   SmallVector<StringRef, 0> defPhdrs;
+  bool seenRelro = false;
   for (SectionCommand *&cmd : sectionCommands) {
     if (!isa<OutputDesc>(cmd))
       continue;
@@ -1196,9 +1202,18 @@ void LinkerScript::adjustOutputSections() {
     if (sec->sectionIndex != UINT32_MAX)
       maybePropagatePhdrs(*sec, defPhdrs);
 
+    // Discard .relro_padding if we have not seen one non-NOBITS RELRO section.
+    // Note: when .tbss is the only RELRO section, it's difficult to pick a
+    // suitable padding size (see computeFilOffset). For simplicity, don't
+    // retain .relro_padding in this case.
+    if (in.relroPadding && in.relroPadding->getParent() == sec && !seenRelro)
+      discardable = true;
     if (discardable) {
       sec->markDead();
       cmd = nullptr;
+    } else {
+      seenRelro |=
+          sec->relro && !(sec->type == SHT_NOBITS && (sec->flags & SHF_TLS));
     }
   }
 
diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp
index 1f8592fbb95deda..7c5f15011f3953d 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -1461,8 +1461,7 @@ Expr ScriptParser::readPrimary() {
     readExpr();
     expect(")");
     seenRelroEnd = true;
-    Expr e = getPageSize();
-    return [=] { return alignToPowerOf2(script->getDot(), e().getValue()); };
+    return [=] { return alignToPowerOf2(script->getDot(), config->maxPageSize); };
   }
   if (tok == "DEFINED") {
     StringRef name = unquote(readParenLiteral());
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 09090835af4a621..f412efa36480284 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -2688,6 +2688,10 @@ size_t IBTPltSection::getSize() const {
 
 bool IBTPltSection::isNeeded() const { return in.plt->getNumEntries() > 0; }
 
+RelroPaddingSection::RelroPaddingSection()
+    : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, 1, ".relro_padding") {
+}
+
 // The string hash function for .gdb_index.
 static uint32_t computeGdbHash(StringRef s) {
   uint32_t h = 0;
@@ -3839,6 +3843,7 @@ void InStruct::reset() {
   got.reset();
   gotPlt.reset();
   igotPlt.reset();
+  relroPadding.reset();
   armCmseSGSection.reset();
   ppc64LongBranchTarget.reset();
   mipsAbiFlags.reset();
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 21a3f768ffcf8e1..3a9f4ba886f6bbb 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -778,6 +778,16 @@ class IBTPltSection : public SyntheticSection {
   size_t getSize() const override;
 };
 
+// Used to align the end of the PT_GNU_RELRO segment and the associated PT_LOAD
+// segment to a common-page-size boundary. This padding section ensures that all
+// pages in the PT_LOAD segment is covered by at least one section.
+class RelroPaddingSection final : public SyntheticSection {
+public:
+  RelroPaddingSection();
+  size_t getSize() const override { return 0; }
+  void writeTo(uint8_t *buf) override {}
+};
+
 class GdbIndexSection final : public SyntheticSection {
 public:
   struct AddressEntry {
@@ -1333,6 +1343,7 @@ struct InStruct {
   std::unique_ptr<GotSection> got;
   std::unique_ptr<GotPltSection> gotPlt;
   std::unique_ptr<IgotPltSection> igotPlt;
+  std::unique_ptr<RelroPaddingSection> relroPadding;
   std::unique_ptr<SyntheticSection> armCmseSGSection;
   std::unique_ptr<PPC64LongBranchTargetSection> ppc64LongBranchTarget;
   std::unique_ptr<SyntheticSection> mipsAbiFlags;
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 255f8c334b969bc..f4f81539fe9f2cc 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -458,6 +458,12 @@ template <class ELFT> void elf::createSyntheticSections() {
   add(*in.gotPlt);
   in.igotPlt = std::make_unique<IgotPltSection>();
   add(*in.igotPlt);
+  // In the absence of PHDRS/SECTIONS commands. add .relro_padding.
+  if (config->zRelro && script->phdrsCommands.empty() &&
+      !script->hasSectionsCommand) {
+    in.relroPadding = std::make_unique<RelroPaddingSection>();
+    add(*in.relroPadding);
+  }
 
   if (config->emachine == EM_ARM) {
     in.armCmseSGSection = std::make_unique<ArmCmseSGSection>();
@@ -818,6 +824,9 @@ static bool isRelroSection(const OutputSection *sec) {
   if (sec == in.gotPlt->getParent())
     return config->zNow;
 
+  if (in.relroPadding && sec == in.relroPadding->getParent())
+    return true;
+
   // .dynamic section contains data for the dynamic linker, and
   // there's no need to write to it at runtime, so it's better to put
   // it into RELRO.
@@ -857,7 +866,7 @@ enum RankFlags {
   RF_BSS = 1 << 7,
 };
 
-static unsigned getSectionRank(const OutputSection &osec) {
+static unsigned getSectionRank(OutputSection &osec) {
   unsigned rank = osec.partition * RF_PARTITION;
 
   // We want to put section specified by -T option first, so we
@@ -920,7 +929,9 @@ static unsigned getSectionRank(const OutputSection &osec) {
     // TLS sections directly before the other RELRO sections.
     if (!(osec.flags & SHF_TLS))
       rank |= RF_NOT_TLS;
-    if (!isRelroSection(&osec))
+    if (isRelroSection(&osec))
+      osec.relro = true;
+    else
       rank |= RF_NOT_RELRO;
     // Place .ldata and .lbss after .bss. Making .bss closer to .text alleviates
     // relocation overflow pressure.
@@ -2336,6 +2347,7 @@ SmallVector<PhdrEntry *, 0> Writer<ELFT>::createPhdrs(Partition &part) {
       relroEnd = sec;
     }
   }
+  relRo->p_align = 1;
 
   for (OutputSection *sec : outputSections) {
     if (!needsPtLoad(sec))
@@ -2679,16 +2691,6 @@ template <class ELFT> void Writer<ELFT>::setPhdrs(Partition &part) {
       if (!p->hasLMA)
         p->p_paddr = first->getLMA();
     }
-
-    if (p->p_type == PT_GNU_RELRO) {
-      p->p_align = 1;
-      // musl/glibc ld.so rounds the size down, so we need to round up
-      // to protect the last page. This is a no-op on FreeBSD which always
-      // rounds up.
-      p->p_memsz =
-          alignToPowerOf2(p->p_offset + p->p_memsz, config->commonPageSize) -
-          p->p_offset;
-    }
   }
 }
 
diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst
index 1590879416853e0..a5e66d98800cc6e 100644
--- a/lld/docs/ReleaseNotes.rst
+++ b/lld/docs/ReleaseNotes.rst
@@ -29,7 +29,8 @@ ELF Improvements
 * ``--fat-lto-objects`` option is added to support LLVM FatLTO.
   Without ``--fat-lto-objects``, LLD will link LLVM FatLTO objects using the
   relocatable object file. (`D146778 <https://reviews.llvm.org/D146778>`_)
-
+* common-page-size can now be larger than the system page-size.
+ (`#57618 <https://github.com/llvm/llvm-project/issues/57618>`_)
 
 Breaking changes
 ----------------
diff --git a/lld/test/ELF/arm-execute-only.s b/lld/test/ELF/arm-execute-only.s
index 483d33d19fcd4a6..e938be5e64a4b65 100644
--- a/lld/test/ELF/arm-execute-only.s
+++ b/lld/test/ELF/arm-execute-only.s
@@ -13,7 +13,7 @@
 // CHECK:      LOAD           0x000000 0x00000000 0x00000000 0x0016d 0x0016d  R 0x10000
 // CHECK:      LOAD           0x000170 0x00010170 0x00010170 0x{{.*}} 0x{{.*}} R E 0x10000
 // CHECK:      LOAD           0x000174 0x00020174 0x00020174 0x{{.*}} 0x{{.*}}   E 0x10000
-// CHECK:      LOAD           0x000178 0x00030178 0x00030178 0x00038  0x00038  RW  0x10000
+// CHECK:      LOAD           0x000178 0x00030178 0x00030178 0x00038  0x00e88  RW  0x10000
 
 // CHECK: 01     .dynsym .gnu.hash .hash .dynstr
 // CHECK: 02     .text
@@ -22,7 +22,7 @@
 
 // DIFF:      LOAD           0x000000 0x00000000 0x00000000 0x0014d 0x0014d R   0x10000
 // DIFF:      LOAD           0x000150 0x00010150 0x00010150 0x0000c 0x0000c R E 0x10000
-// DIFF:      LOAD           0x00015c 0x0002015c 0x0002015c 0x00038 0x00038 RW  0x10000
+// DIFF:      LOAD           0x00015c 0x0002015c 0x0002015c 0x00038 0x00ea4 RW  0x10000
 
 // DIFF: 01     .dynsym .gnu.hash .hash .dynstr
 // DIFF: 02     .text .foo
diff --git a/lld/test/ELF/end-dso-defined.s b/lld/test/ELF/end-dso-defined.s
index 0b5e977296d1042..d0c143c25148e25 100644
--- a/lld/test/ELF/end-dso-defined.s
+++ b/lld/test/ELF/end-dso-defined.s
@@ -21,16 +21,16 @@
 # CHECK-NEXT: AddressAlignment:
 # CHECK-NEXT: EntrySize:
 # CHECK-NEXT: SectionData (
-# CHECK-NEXT:   0000: 08232000 00000000 08232000 00000000
+# CHECK-NEXT:   0000: 00302000 00000000 00302000 00000000
 # CHECK-NEXT: )
 
 # CHECK:      Symbol {
 # CHECK:        Name: _end
-# CHECK-NEXT:   Value: 0x202308
+# CHECK-NEXT:   Value: 0x203000
 
 # CHECK:      Symbol {
 # CHECK:        Name: end
-# CHECK-NEXT:   Value: 0x202308
+# CHECK-NEXT:   Value: 0x203000
 
 .global _start
 _start:
diff --git a/lld/test/ELF/linkerscript/data-segment-relro.test b/lld/test/ELF/linkerscript/data-segment-relro.test
index 8aba8acb466f6eb..1043c69120d4679 100644
--- a/lld/test/ELF/linkerscript/data-segment-relro.test
+++ b/lld/test/ELF/linkerscript/data-segment-relro.test
@@ -7,10 +7,10 @@
 ## With relro or without DATA_SEGMENT_RELRO_END just aligns to
 ## page boundary.
 
-# RUN: ld.lld --hash-style=sysv -z norelro %t/a.o %t/b.so -T %t/1.t -o %t/a1
+# RUN: ld.lld --hash-style=sysv -z max-page-size=65536 -z norelro %t/a.o %t/b.so -T %t/1.t -o %t/a1
 # RUN: llvm-readelf -S -l %t/a1 | FileCheck %s --check-prefixes=CHECK,CHECK1
 
-# RUN: ld.lld --hash-style=sysv -z relro %t/a.o %t/b.so -T %t/1.t -o %t/a2
+# RUN: ld.lld --hash-style=sysv -z max-page-size=65536 -z relro %t/a.o %t/b.so -T %t/1.t -o %t/a2
 # RUN: llvm-readelf -S -l %t/a2 | FileCheck %s --check-prefixes=CHECK,CHECK2
 
 # CHECK:      Name           Type     Address          Off      Size ES Flg
@@ -26,15 +26,16 @@
 # CHECK1-NOT:  GNU_RELRO
 
 # CHECK2:      Program Headers:
-# CHECK2-NEXT:   Type
-# CHECK2-NEXT:   PHDR
-# CHECK2-NEXT:   LOAD
-# CHECK2-NEXT:   LOAD
-# CHECK2-NEXT:   LOAD
-# CHECK2-NEXT:   LOAD
-# CHECK2-NEXT:   DYNAMIC
-# CHECK2-NEXT:   GNU_RELRO
-# CHECK2-NEXT:   GNU_STACK
+# CHECK2-NEXT:   Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
+# CHECK2-NEXT:   PHDR           0x000040
+# CHECK2-NEXT:   LOAD           0x000000
+# CHECK2-NEXT:   LOAD           0x0002b0
+# CHECK2-NEXT:   LOAD           0x010000 0x0000000000010000 0x0000000000010000 0x000100 0x000100 RW  0x10000
+# CHECK2-NEXT:   LOAD           0x020000 0x0000000000020000 0x0000000000020000 0x000034 0x000034 RW  0x10000
+# CHECK2-NEXT:   DYNAMIC        0x010000 0x0000000000010000 0x0000000000010000 0x0000f0 0x0000f0 RW  0x8
+# CHECK2-NEXT:   GNU_RELRO      0x010000 0x0000000000010000 0x0000000000010000 0x000100 0x000100 R   0x1
+# CHECK2-NEXT:   GNU_STACK      0x000000
+
 
 # CHECK2:      Section to Segment mapping:
 # CHECK2:        06     .dynamic __libc_atexit .got {{$}}
diff --git a/lld/test/ELF/linkerscript/insert-before.test b/lld/test/ELF/linkerscript/insert-before.test
index 922e0859106ff1e..f9611538c013b2b 100644
--- a/lld/test/ELF/linkerscript/insert-before.test
+++ b/lld/test/ELF/linkerscript/insert-before.test
@@ -29,7 +29,7 @@
 # CHECK2-NEXT:           NULL
 # CHECK2-NEXT: .foo.text PROGBITS 000000000020{{.*}} [[#%x,]] 000008 00  AX
 # CHECK2-NEXT: .text     PROGBITS [[#%x,]]           [[#%x,]] 000008 00  AX
-# CHECK2-NEXT: .byte     PROGBITS [[#%x,]]           [[#%x,]] 000001 00  AX
+# CHECK2-NEXT: .byte     PROGBITS [[#%x,]]           [[#%x,]] 000001 00  WA
 # CHECK2-NEXT: .foo.data PROGBITS [[#%x,]]           [[#%x,]] 000008 00  WA
 # CHECK2-NEXT: .data     PROGBITS [[#%x,]]           [[#%x,]] 000008 00  WA
 # CHECK2:      Type      {{.*}} Flg Align
diff --git a/lld/test/ELF/map-file-copy.s b/lld/test/ELF/map-file-copy.s
index 58c0ce981048093..029724418450889 100644
--- a/lld/test/ELF/map-file-copy.s
+++ b/lld/test/ELF/map-file-copy.s
@@ -19,7 +19,7 @@
 # CHECK-NEXT:         <internal>:(.bss.rel.ro)
 ## Ideally this is displayed as copy at v2.
 # CHECK-NEXT:                 copy{{$}}
-# CHECK-NEXT: .got.plt
+# CHECK-NEXT: .relro_padding
 
 #--- 1.s
 .global _start
diff --git a/lld/test/ELF/map-file.s b/lld/test/ELF/map-file.s
index 59931409c7abdb3..0cb20d5a4164bcb 100644
--- a/lld/test/ELF/map-file.s
+++ b/lld/test/ELF/map-file.s
@@ -87,6 +87,8 @@ labs = 0x1AB5
 # CHECK-NEXT:          201420           201420        0     1                 sharedFunc2
 # CHECK-NEXT:          202430           202430      100     8 .dynamic
 # CHECK-NEXT:          202430           202430      100     8         <internal>:(.dynamic)
+# CHECK-NEXT:          202530           202530      ad0     1 .relro_padding
+# CHECK-NEXT:          202530           202530        0     1         <internal>:(.relro_padding)
 # CHECK-NEXT:          203530           203530       28     8 .got.plt
 # CHECK-NEXT:          203530           203530       28     8         <internal>:(.got.plt)
 # CHECK-NEXT:          203560           203560       10    16 .bss
@@ -100,8 +102,8 @@ labs = 0x1AB5
 # CHECK-NEXT:               0                0        8     1         <internal>:(.comment)
 # CHECK-NEXT:               0                0      1b0     8 .symtab
 # CHECK-NEXT:               0                0      1b0     8         <internal>:(.symtab)
-# CHECK-NEXT:               0                0       84     1 .shstrtab
-# CHECK-NEXT:               0                0       84     1         <internal>:(.shstrtab)
+# CHECK-NEXT:               0                0       93     1 .shstrtab
+# CHECK-NEXT:               0                0       93     1         <internal>:(.shstrtab)
 # CHECK-NEXT:               0                0       71     1 .strtab
 # CHECK-NEXT:               0                0       71     1         <internal>:(.strtab)
 
diff --git a/lld/test/ELF/partition-notes.s b/lld/test/ELF/partition-notes.s
index 9bc43f2fbf9ee4c..c5ade3a47e05282 100644
--- a/lld/test/ELF/partition-notes.s
+++ b/lld/test/ELF/partition-notes.s
@@ -37,7 +37,7 @@
 // CHECK-NEXT:       Owner: GNU
 // CHECK-NEXT:       Data size:
 // CHECK-NEXT:       Type: NT_GNU_BUILD_ID (unique build ID bitstring)
-// CHECK-NEXT:       Build ID: ab81108a3d85b729980356331fddc2bfc4c10177{{$}}
+// CHECK-NEXT:       Build ID: d5101cb9d03b7e836ba9b64f5768a0b31980920f{{$}}
 // CHECK-NEXT:     }
 // CHECK-NEXT:   }
 // CHECK-NEXT: ]
diff --git a/lld/test/ELF/partition-synthetic-sections.s b/lld/test/ELF/partition-synthetic-sections.s
index 2eec08392fe68d3..d38597856e165ef 100644
--- a/lld/test/ELF/partition-synthetic-sections.s
+++ b/lld/test/ELF/partition-synthetic-sections.s
@@ -41,6 +41,7 @@
 // PART0-NEXT: .plt              PROGBITS
 // PART0-NEXT: .init_array       INIT_ARRAY      {{0*}}[[INIT_ARRAY_ADDR:[^ ]*]]
 // CHECK-NEXT: .dynamic          DYNAMIC         {{0*}}[[DYNAMIC_ADDR:[^ ]*]]
+// PART0-NEXT: .relro_padding    NOBITS
 // PART0-NEXT: .data             PROGBITS        000000000000[[DATA_SEGMENT:.]]178
 // PART1-NEXT: .data             PROGBITS        000000000000[[DATA_SEGMENT:.]]130
 // PART0-NEXT: .got.plt          PROGBITS        {{0*}}[[GOT_PLT_ADDR:[^ ]*]]
diff --git a/lld/test/ELF/relocation-copy-relro.s b/lld/test/ELF/relocation-copy-relro.s
index 91994501a301dbd..58492509a38b2b7 100644
--- a/lld/test/ELF/relocation-copy-relro.s
+++ b/lld/test/ELF/relocation-copy-relro.s
@@ -8,6 +8,11 @@
 // RUN: ld.lld %t.o %t.so -o %t3
 // RUN: llvm-readobj -S -l -r %t3 | FileCheck %s
 
+/// Due to -z rodynamic, The only RELRO section is .bss.rel.ro. Test that we
+/// still append the .relro_padding section.
+// RUN: ld.lld -z rodynamic %t.o %t.so -o %t4
+// RUN: llvm-readelf -S -l %t4 | FileCheck %s --check-prefix=CHECK2
+
 // CHECK:        Name: .bss.rel.ro
 // CHECK-NEXT:   Type: SHT_NOBITS (0x8)
 // CHECK-NEXT:   Flags [ (0x3)
@@ -28,6 +33,20 @@
 // CHECK: 0x202368 R_X86_64_COPY a 0x0
 // CHECK: 0x20236C R_X86_64_COPY b 0x0
 
+// CHECK2:      LOAD           0x000356 0x0000000000202356 0x0000000000202356 0x000000 0x000caa RW  0x1000
+// CHECK2:      DYNAMIC        0x000258 0x0000000000200258 0x0000000000200258 0x0000b0 0x0000b0 R   0x8
+// CHECK2:      GNU_RELRO      0x000356 0x0000000000202356 0x0000000000202356 0x000000 0x000caa R   0x1
+
+// CHECK2:      Section to Segment mapping:
+// CHECK2-NEXT:  Segment Sections...
+// CHECK2-NEXT:   00
+// CHECK2-NEXT:   01     .dynsym .gnu.hash .hash .dynamic .dynstr .rela.dyn
+// CHECK2-NEXT:   02     .text
+// CHECK2-NEXT:   03     .bss.rel.ro .relro_padding
+// CHECK2-NEXT:   04     .dynamic
+// CHECK2-NEXT:   05     .bss.rel.ro .relro_padding
+// CHECK2-NEXT:   06
+
 .text
 .global _start
 _start:
diff --git a/lld/test/ELF/relro-bss.s b/lld/test/ELF/relro-bss.s
index 8fc8167bb51b7dc..f15aff36872df5c 100644
--- a/lld/test/ELF/relro-bss.s
+++ b/lld/test/ELF/relro-bss.s
@@ -10,7 +10,7 @@
 
 #           Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
 # SEG:      LOAD           0x0001c8 0x00000000002011c8 0x00000000002011c8 0x000001 0x000001 R E 0x1000
-# SEG-NEXT: LOAD           0x0001c9 0x00000000002021c9 0x00000000002021c9 0x000001 0x002001 RW  0x1000
+# SEG-NEXT: LOAD           0x0001c9 0x00000000002021c9 0x00000000002021c9 0x000001 0x002e37 RW  0x1000
 # SEG-NEXT: LOAD           0x0001ca 0x00000000002051ca 0x00000000002051ca 0x000001 0x000002 RW  0x1000
 # SEG-NEXT: GNU_RELRO      0x0001c9 0x00000000002021c9 0x00000000002021c9 0x000001 0x002e37 R   0x1
 # SEG-NEXT: GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x0
@@ -24,6 +24,7 @@
 #        [Nr] Name              Type            Address          Off    Size
 # CHECK:      .data.rel.ro      PROGBITS        00000000002021c9 0001c9 000001
 # CHECK-NEXT: .bss.rel.ro       NOBITS          00000000002021ca 0001ca 002000
+# CHECK-NEXT: .relro_padding    NOBITS          00000000002041ca 0001ca 000e36
 # CHECK-NEXT: .data             PROGBITS        00000000002051ca 0001ca 000001
 # CHECK-NEXT: .bss              NOBITS          00000000002051cb 0001cb 000001
 
diff --git a/lld/test/ELF/relro-copyrel-bss-script.s b/lld/test/ELF/relro-copyrel-bss-script.s
index 9a947d898a12a1d..4745caae8679039 100644
--- a/lld/test/ELF/relro-copyrel-bss-script.s
+++ b/lld/test/ELF/relro-copyrel-bss-script.s
@@ -28,4 +28,4 @@ _start:
         .space 0x2000
 
 // CHECK: Type      Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
-// CHECK: GNU_RELRO 0x002150 0x0000000000000150 0x0000000000000150 0x000100 0x000eb0 R   0x1
+// CHECK: GNU_RELRO 0x002150 0x0000000000000150 0x0000000000000150 0x000100 0x000100 R   0x1
diff --git a/lld/test/ELF/relro.s b/lld/test/ELF/relro.s
index 163e257e2956e0a..0ab9665443d1fb3 100644
--- a/lld/test/ELF/relro.s
+++ b/lld/test/ELF/relro.s
@@ -24,8 +24,8 @@
 // CHECK-NEXT: GNU_RELRO
 // CHECK: Section to Segment mapping:
 
-// FULLRELRO:  03     .openbsd.randomdata .dynamic .got .got.plt {{$}}
-// PARTRELRO:  03     .openbsd.randomdata .dynamic .got {{$}}
+// FULLRELRO:  03     .openbsd.randomdata .dynamic .got .got.plt .relro_padding {{$}}
+// PARTRELRO:  03     .openbsd.randomdata .dynamic .got .relro_padding {{$}}
 
 
 // NORELRO-NOT: GNU_RELRO
diff --git a/lld/test/ELF/riscv-section-layout.s b/lld/test/ELF/riscv-section-layout.s
index bb9adf5eef0545b..56ac95d01fdfd61 100644
--- a/lld/test/ELF/riscv-section-layout.s
+++ b/lld/test/ELF/riscv-section-layout.s
@@ -20,6 +20,7 @@
 # NOSDATA-NEXT: .tbss
 # NOSDATA-NEXT: .dynamic
 # NOSDATA-NEXT: .got
+# NOSDATA-NEXT: .relro_padding
 # NOSDATA-NEXT: .data    PROGBITS [[#%x,DATA:]]
 # NOSDATA-NEXT: .bss     NOBITS   [[#%x,BSS:]]
 
@@ -36,6 +37,7 @@
 # CHECK-NEXT: .tbss
 # CHECK-NEXT: .dynamic
 # CHECK-NEXT: .got
+# CHECK-NEXT: .relro_padding
 # CHECK-NEXT: .data
 # CHECK-NEXT: .sdata     PROGBITS [[#%x,SDATA:]]
 # CHECK-NEXT: .sbss      NOBITS   [[#%x,SBSS:]]
diff --git a/lld/test/ELF/section-name.s b/lld/test/ELF/section-name.s
index fff3fc14f30246f..819cd9c14d95001 100644
--- a/lld/test/ELF/section-name.s
+++ b/lld/test/ELF/section-name.s
@@ -48,11 +48,12 @@ _start:
 // CHECK-NEXT: .tdata            00000001
 // CHECK-NEXT: .tbss             00000001
 // CHECK-NEXT: .data.rel.ro      00000004
+// CHECK-NEXT: .relro_padding    00000df5
 // CHECK-NEXT: .data             00000002
 // CHECK-NEXT: .foo.a            00000001
 // CHECK-NEXT: .foo              00000001
 // CHECK-NEXT: .bss              00000002
 // CHECK-NEXT: .comment          00000008
 // CHECK-NEXT: .symtab           00000030
-// CHECK-NEXT: .shstrtab         00000075
+// CHECK-NEXT: .shstrtab         00000084
 // CHECK-NEXT: .strtab           00000008
diff --git a/lld/test/ELF/separate-segments.s b/lld/test/ELF/separate-segments.s
index d0e4afe7fb66858..20501e92b29c97e 100644
--- a/lld/test/ELF/separate-segments.s
+++ b/lld/test/ELF/separate-segments.s
@@ -7,7 +7,7 @@
 # RUN: llvm-readelf -l %t | FileCheck --check-prefix=NONE %s
 # NONE:      LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000245 0x000245 R   0x1000
 # NONE-NEXT: LOAD 0x000248 0x0000000000001248 0x0000000000001248 0x000001 0x000001 R E 0x1000
-# NONE-NEXT: LOAD 0x000250 0x0000000000002250 0x0000000000002250 0x000090 0x000090 RW  0x1000
+# NONE-NEXT: LOAD 0x000250 0x0000000000002250 0x0000000000002250 0x000090 0x000db0 RW  0x1000
 # NONE-NEXT: LOAD 0x0002e0 0x00000000000032e0 0x00000000000032e0 0x000001 0x000001 RW  0x1000
 
 ## -z separate-code makes text segment (RX) separate.
@@ -16,7 +16,7 @@
 # RUN: llvm-readelf -l %t | FileCheck --check-prefix=CODE %s
 # CODE:      LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000245 0x000245 R   0x1000
 # CODE-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000001 0x000001 R E 0x1000
-# CODE-NEXT: LOAD 0x002000 0x0000000000002000 0x0000000000002000 0x000090 0x000090 RW  0x1000
+# CODE-NEXT: LOAD 0x002000 0x0000000000002000 0x0000000000002000 0x000090 0x001000 RW  0x1000
 # CODE-NEXT: LOAD 0x002090 0x0000000000003090 0x0000000000003090 0x000001 0x000001 RW  0x1000
 
 ## -z separate-loadable-segments makes all segments separate.
@@ -24,7 +24,7 @@
 # RUN: llvm-readelf -l %t | FileCheck --check-prefix=ALL %s
 # ALL:       LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000245 0x000245 R   0x1000
 # ALL-NEXT:  LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000001 0x000001 R E 0x1000
-# ALL-NEXT:  LOAD 0x002000 0x0000000000002000 0x0000000000002000 0x000090 0x000090 RW  0x1000
+# ALL-NEXT:  LOAD 0x002000 0x0000000000002000 0x0000000000002000 0x000090 0x001000 RW  0x1000
 # ALL-NEXT:  LOAD 0x003000 0x0000000000003000 0x0000000000003000 0x000001 0x000001 RW  0x1000
 
 nop
diff --git a/lld/test/ELF/shuffle-sections-init-fini.s b/lld/test/ELF/shuffle-sections-init-fini.s
index 66e32be7c874add..c8e56d0860499d5 100644
--- a/lld/test/ELF/shuffle-sections-init-fini.s
+++ b/lld/test/ELF/shuffle-sections-init-fini.s
@@ -1,11 +1,11 @@
 # REQUIRES: x86
 # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
 
-# RUN: ld.lld %t.o -o %t
+# RUN: ld.lld -z norelro %t.o -o %t
 # RUN: llvm-readelf -x .init -x .fini -x .init_array -x .fini_array %t | \
 # RUN:   FileCheck --check-prefixes=CHECK,ORDERED %s
 
-# RUN: ld.lld %t.o --shuffle-sections '*=1' -o %t1
+# RUN: ld.lld -z norelro %t.o --shuffle-sections '*=1' -o %t1
 # RUN: llvm-readelf -x .init -x .fini -x .init_array -x .fini_array %t1 | \
 # RUN:   FileCheck --check-prefixes=CHECK,SHUFFLED %s
 
diff --git a/lld/test/ELF/shuffle-sections.s b/lld/test/ELF/shuffle-sections.s
index 21c79eab950d671..56ed2c9ca9bdb09 100644
--- a/lld/test/ELF/shuffle-sections.s
+++ b/lld/test/ELF/shuffle-sections.s
@@ -10,7 +10,7 @@
 # RUN: ld.lld --shuffle-sections='*=1' %t.o -o %t1.out
 # RUN: llvm-readelf -x .text %t1.out | FileCheck %s --check-prefix=SHUFFLE1
 # SHUFFLE1: Hex dump of section '.text':
-# SHUFFLE1-NEXT: 01020403
+# SHUFFLE1-NEXT: 030402cc 01
 
 ## Test that --shuffle-sections= can be used with --symbol-ordering-file
 # RUN: echo "foo" > %t_order.txt
@@ -21,7 +21,7 @@
 # SHUFFLE2: Hex dump of section '.text':
 # SHUFFLE2-NEXT: 02cccccc 010304
 
-# RUN: ld.lld --symbol-ordering-file %t_order.txt --shuffle-sections='*=3' %t.o -o %t3.out
+# RUN: ld.lld -z norelro --symbol-ordering-file %t_order.txt --shuffle-sections='*=3' %t.o -o %t3.out
 # RUN: llvm-readelf -x .text %t3.out | FileCheck %s --check-prefix=SHUFFLE3
 # SHUFFLE3: Hex dump of section '.text':
 # SHUFFLE3-NEXT: 02cccccc 010403
diff --git a/lld/test/ELF/sort-norosegment.s b/lld/test/ELF/sort-norosegment.s
index 9bf38eaac236bc2..9a1836820ef1fa7 100644
--- a/lld/test/ELF/sort-norosegment.s
+++ b/lld/test/ELF/sort-norosegment.s
@@ -9,7 +9,7 @@
 # CHECK-NEXT: .dynstr  {{.*}}   A
 # CHECK-NEXT: .text    {{.*}}   AX
 # CHECK-NEXT: .dynamic {{.*}}  WA
-# CHECK-NEXT: foo      {{.*}}  WA
+# CHECK:      foo      {{.*}}  WA
 
 .section foo, "aw"
 .byte 0
diff --git a/lld/test/ELF/x86-64-section-layout.s b/lld/test/ELF/x86-64-section-layout.s
index e9ea69afab3b106..37201279fa0a5d0 100644
--- a/lld/test/ELF/x86-64-section-layout.s
+++ b/lld/test/ELF/x86-64-section-layout.s
@@ -23,6 +23,7 @@
 # CHECK-NEXT:  .text      PROGBITS        0000000000201304 000304 000001 00  AX  0   0  4
 # CHECK-NEXT:  .tdata     PROGBITS        0000000000202305 000305 000001 00 WAT  0   0  1
 # CHECK-NEXT:  .tbss      NOBITS          0000000000202306 000306 000002 00 WAT  0   0  1
+# CHECK-NEXT:  .relro_padding NOBITS      0000000000202306 000306 000cfa 00  WA  0   0  1
 # CHECK-NEXT:  .data      PROGBITS        0000000000203306 000306 000001 00  WA  0   0  1
 # CHECK-NEXT:  .bss       NOBITS          0000000000203307 000307 001800 00  WA  0   0  1
 ## We spend size(.bss) % MAXPAGESIZE bytes for .bss.
@@ -36,7 +37,7 @@
 # CHECK-NEXT:    PHDR  0x000040 0x0000000000200040 0x0000000000200040 {{.*}}   {{.*}}   R   0x8
 # CHECK-NEXT:    LOAD  0x000000 0x0000000000200000 0x0000000000200000 0x000304 0x000304 R   0x1000
 # CHECK-NEXT:    LOAD  0x000304 0x0000000000201304 0x0000000000201304 0x000001 0x000001 R E 0x1000
-# CHECK-NEXT:    LOAD  0x000305 0x0000000000202305 0x0000000000202305 0x000001 0x000001 RW  0x1000
+# CHECK-NEXT:    LOAD  0x000305 0x0000000000202305 0x0000000000202305 0x000001 0x000cfb RW  0x1000
 # CHECK-NEXT:    LOAD  0x000306 0x0000000000203306 0x0000000000203306 0x000001 0x001801 RW  0x1000
 # CHECK-NEXT:    LOAD  0x000b07 0x0000000000205b07 0x0000000000205b07 0x000003 0x000005 RW  0x1000
 

>From ab1ee9a5e5c0f5d3cf0c6aa0b950600d50e37e58 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Wed, 13 Sep 2023 15:13:58 -0700
Subject: [PATCH 2/2] append .relro_padding if .bss.rel.ro is the only RELRO
 section. Add new test to relocation-copy-relro.s

---
 lld/ELF/LinkerScript.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index e82230a38bf6318..9819c26ce779660 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -1202,10 +1202,10 @@ void LinkerScript::adjustOutputSections() {
     if (sec->sectionIndex != UINT32_MAX)
       maybePropagatePhdrs(*sec, defPhdrs);
 
-    // Discard .relro_padding if we have not seen one non-NOBITS RELRO section.
-    // Note: when .tbss is the only RELRO section, it's difficult to pick a
-    // suitable padding size (see computeFilOffset). For simplicity, don't
-    // retain .relro_padding in this case.
+    // Discard .relro_padding if we have not seen one RELRO section. Note: when
+    // .tbss is the only RELRO section, it's difficult to pick a suitable
+    // padding size (see computeFileOffset). For simplicity, don't retain
+    // .relro_padding in this case.
     if (in.relroPadding && in.relroPadding->getParent() == sec && !seenRelro)
       discardable = true;
     if (discardable) {



More information about the llvm-commits mailing list