Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/llvm/llvm-project.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lld
diff options
context:
space:
mode:
authorFangrui Song <i@maskray.me>2022-05-04 11:10:45 +0300
committerFangrui Song <i@maskray.me>2022-05-04 11:10:46 +0300
commit5a44980f0a8bb2c7dafe9a9f5e5a17699e65cc3d (patch)
tree294b93d09fed1ab21f0d669f0e7bff15b999092f /lld
parent37a147352457c690a6130a5d20ef381037fc3548 (diff)
[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
Diffstat (limited to 'lld')
-rw-r--r--lld/ELF/OutputSections.h4
-rw-r--r--lld/ELF/ScriptParser.cpp15
-rw-r--r--lld/ELF/Writer.cpp2
-rw-r--r--lld/test/ELF/linkerscript/data-segment-relro.test25
4 files changed, 39 insertions, 7 deletions
diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h
index 9179d14aef07..020eeaec368e 100644
--- a/lld/ELF/OutputSections.h
+++ b/lld/ELF/OutputSections.h
@@ -100,6 +100,10 @@ public:
// 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 c58309b12e57..51792da64b82 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -135,6 +135,9 @@ private:
// 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 125d7189a447..649958b74798 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 bc24ad48d932..8aba8acb466f 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",@progbits
.dc.a __libc_atexit
+.section .orphan.ro,"a",@progbits
+.dc.a 0
+
+.section .orphan.rw,"aw",@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) }