diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -100,6 +100,10 @@ // 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 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 --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -135,6 +135,9 @@ // 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 @@ 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(cmd)) + osd->osec.relro = false; + script->sectionCommands.insert(script->sectionCommands.end(), v.begin(), v.end()); @@ -887,6 +898,8 @@ 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 @@ expect(","); readExpr(); expect(")"); + seenDataAlign = true; return [=] { return alignTo(script->getDot(), std::max((uint64_t)1, e().getValue())); }; @@ -1377,6 +1391,7 @@ 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 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -761,6 +761,8 @@ 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 --- 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 @@ .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 @@ . = 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) }