From 04cc6bbeb016d5fa249701f3e9c2c42573b6ba66 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sun, 10 Sep 2023 21:07:20 -0700 Subject: [PATCH] [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, add a padding section .relro_padding like mold, which is contained in the PT_GNU_RELRO segment and the associated PT_LOAD segment. The section also prevents strip from corrupting PT_LOAD program headers. .relro_padding has the largest `sortRank` among RELRO sections. Therefore, it is naturally placed at the end of `PT_GNU_RELRO` segment in the absence of `PHDRS`/`SECTIONS` commands. In the presence of `SECTIONS` commands, we place .relro_padding immediately before a symbol assignment using DATA_SEGMENT_RELRO_END (see also https://reviews.llvm.org/D124656), if present. DATA_SEGMENT_RELRO_END is changed to align to max-page-size instead of common-page-size. Some edge cases worth mentioning: * ppc64-toc-addis-nop.s: when PHDRS is present, do not append .relro_padding * avoid-empty-program-headers.s: when the only RELRO section is .tbss, it is not part of PT_LOAD segment, therefore we do not append .relro_padding. --- 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 runtime_page_size > common-page-size. In my opinion, losing protection for the last page when the runtime 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. Therefore, the end of .relro_padding is padded to a common-page-size boundary. Users who are really anxious can set common-page-size to match their runtime page size. --- 17 tests need updating as there are lots of change detectors. --- lld/ELF/Driver.cpp | 4 +- lld/ELF/LinkerScript.cpp | 18 +++++ lld/ELF/LinkerScript.h | 5 ++ lld/ELF/ScriptParser.cpp | 16 ++-- lld/ELF/SyntheticSections.cpp | 5 ++ lld/ELF/SyntheticSections.h | 11 +++ lld/ELF/Writer.cpp | 39 ++++++--- lld/docs/ELF/linker_script.rst | 15 ++++ lld/docs/ReleaseNotes.rst | 3 +- lld/test/ELF/arm-execute-only.s | 4 +- lld/test/ELF/end-dso-defined.s | 6 +- .../data-segment-relro-ppc64.test | 79 +++++++++++++++++++ .../ELF/linkerscript/data-segment-relro.test | 29 ++++--- 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/ppc64-section-layout.s | 2 + 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 +- 30 files changed, 241 insertions(+), 60 deletions(-) create mode 100644 lld/test/ELF/linkerscript/data-segment-relro-ppc64.test diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 9219314111610..9d167293574fa 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 2b9f28ce68d68..77d13e54de125 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -887,6 +887,10 @@ void LinkerScript::diagnoseOrphanHandling() const { if (config->orphanHandling == OrphanHandlingPolicy::Place) return; for (const InputSectionBase *sec : orphanSections) { + // .relro_padding is inserted before DATA_SEGMENT_RELRO_END, if present, + // automatically. The section is not supposed to be specified by scripts. + if (sec == in.relroPadding.get()) + continue; // Input SHT_REL[A] retained by --emit-relocs are ignored by // computeInputSections(). Don't warn/error. if (isa(sec) && @@ -1079,6 +1083,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 +1169,7 @@ void LinkerScript::adjustOutputSections() { uint64_t flags = SHF_ALLOC; SmallVector defPhdrs; + bool seenRelro = false; for (SectionCommand *&cmd : sectionCommands) { if (!isa(cmd)) continue; @@ -1196,9 +1206,17 @@ void LinkerScript::adjustOutputSections() { if (sec->sectionIndex != UINT32_MAX) maybePropagatePhdrs(*sec, defPhdrs); + // Discard .relro_padding if we have not seen one RELRO section. Note: when + // .tbss is the only RELRO section, there is no associated PT_LOAD segment + // (needsPtLoad), so we don't append .relro_padding in the 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/LinkerScript.h b/lld/ELF/LinkerScript.h index f0a914e65993e..89780bb60f482 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -105,6 +105,9 @@ struct SymbolAssignment : SectionCommand { bool provide = false; bool hidden = false; + // This assignment references DATA_SEGMENT_RELRO_END. + bool dataSegmentRelroEnd = false; + unsigned symOrder; // Holds file name and line number for error reporting. @@ -352,6 +355,8 @@ class LinkerScript final { SmallVector phdrsCommands; bool hasSectionsCommand = false; + bool seenDataAlign = false; + bool seenRelroEnd = false; bool errorOnMissingSection = false; // List of section patterns specified with KEEP commands. They will diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp index 1f8592fbb95de..3fbb49d440c02 100644 --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -136,9 +136,6 @@ 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; }; @@ -600,7 +597,7 @@ void ScriptParser::readSections() { // If DATA_SEGMENT_RELRO_END is absent, for sections after DATA_SEGMENT_ALIGN, // the relro fields should be cleared. - if (!seenRelroEnd) + if (!script->seenRelroEnd) for (SectionCommand *cmd : v) if (auto *osd = dyn_cast(cmd)) osd->osec.relro = false; @@ -916,7 +913,7 @@ OutputDesc *ScriptParser::readOutputSectionDescription(StringRef outSec) { script->createOutputSection(unquote(outSec), getCurrentLocation()); OutputSection *osec = &cmd->osec; // Maybe relro. Will reset to false if DATA_SEGMENT_RELRO_END is absent. - osec->relro = seenDataAlign && !seenRelroEnd; + osec->relro = script->seenDataAlign && !script->seenRelroEnd; size_t symbolsReferenced = script->referencedSymbols.size(); @@ -1051,6 +1048,7 @@ SymbolAssignment *ScriptParser::readAssignment(StringRef tok) { size_t oldPos = pos; SymbolAssignment *cmd = nullptr; + bool savedSeenRelroEnd = script->seenRelroEnd; const StringRef op = peek(); if (op.starts_with("=")) { // Support = followed by an expression without whitespace. @@ -1071,6 +1069,7 @@ SymbolAssignment *ScriptParser::readAssignment(StringRef tok) { } if (cmd) { + cmd->dataSegmentRelroEnd = !savedSeenRelroEnd && script->seenRelroEnd; cmd->commandString = tok.str() + " " + llvm::join(tokens.begin() + oldPos, tokens.begin() + pos, " "); @@ -1439,7 +1438,7 @@ Expr ScriptParser::readPrimary() { expect(","); readExpr(); expect(")"); - seenDataAlign = true; + script->seenDataAlign = true; return [=] { uint64_t align = std::max(uint64_t(1), e().getValue()); return (script->getDot() + align - 1) & -align; @@ -1460,9 +1459,8 @@ Expr ScriptParser::readPrimary() { expect(","); readExpr(); expect(")"); - seenRelroEnd = true; - Expr e = getPageSize(); - return [=] { return alignToPowerOf2(script->getDot(), e().getValue()); }; + script->seenRelroEnd = true; + 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 09090835af4a6..f412efa364802 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 21a3f768ffcf8..3a9f4ba886f6b 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 got; std::unique_ptr gotPlt; std::unique_ptr igotPlt; + std::unique_ptr relroPadding; std::unique_ptr armCmseSGSection; std::unique_ptr ppc64LongBranchTarget; std::unique_ptr mipsAbiFlags; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index d4c667c91ab75..40f7d7981d9d4 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -458,6 +458,13 @@ template void elf::createSyntheticSections() { add(*in.gotPlt); in.igotPlt = std::make_unique(); add(*in.igotPlt); + // Add .relro_padding if DATA_SEGMENT_RELRO_END is used; otherwise, add the + // section in the absence of PHDRS/SECTIONS commands. + if (config->zRelro && ((script->phdrsCommands.empty() && + !script->hasSectionsCommand) || script->seenRelroEnd)) { + in.relroPadding = std::make_unique(); + add(*in.relroPadding); + } if (config->emachine == EM_ARM) { in.armCmseSGSection = std::make_unique(); @@ -818,6 +825,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 +867,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 +930,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. @@ -1140,6 +1152,18 @@ findOrphanPos(SmallVectorImpl::iterator b, SmallVectorImpl::iterator e) { OutputSection *sec = &cast(*e)->osec; + // As a special case, place .relro_padding before the SymbolAssignment using + // DATA_SEGMENT_RELRO_END, if present. + if (in.relroPadding && sec == in.relroPadding->getParent()) { + auto i = std::find_if(b, e, [=](SectionCommand *a) { + if (auto *assign = dyn_cast(a)) + return assign->dataSegmentRelroEnd; + return false; + }); + if (i != e) + return i; + } + // Find the first element that has as close a rank as possible. auto i = std::max_element(b, e, [=](SectionCommand *a, SectionCommand *b) { return getRankProximity(sec, a) < getRankProximity(sec, b); @@ -2334,6 +2358,7 @@ SmallVector Writer::createPhdrs(Partition &part) { relroEnd = sec; } } + relRo->p_align = 1; for (OutputSection *sec : outputSections) { if (!needsPtLoad(sec)) @@ -2677,16 +2702,6 @@ template void Writer::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/ELF/linker_script.rst b/lld/docs/ELF/linker_script.rst index bc2037595e5f5..fbd96abcb44c5 100644 --- a/lld/docs/ELF/linker_script.rst +++ b/lld/docs/ELF/linker_script.rst @@ -172,3 +172,18 @@ description in the ``OVERWRITE_SECTIONS`` command while the insert command still applies (possibly after orphan section placement). It is recommended to leave the brace empty (i.e. ``section : {}``) for the insert command, because its description will be ignored anyway. + +Built-in functions +~~~~~~~~~~~~~~~~~~ + +``DATA_SEGMENT_RELRO_END(offset, exp)`` defines the end of the ``PT_GNU_RELRO`` +segment when ``-z relro`` (default) is in effect. Sections between +``DATA_SEGMENT_ALIGN`` and ``DATA_SEGMENT_RELRO_END`` are considered RELRO. + +The typical use case is ``. = DATA_SEGMENT_RELRO_END(0, .);`` followed by +writable but non-RELRO sections. LLD ignores ``offset`` and ``exp`` and aligns +the current location to a max-page-size boundary, ensuring that the next +``PT_LOAD`` segment will not overlap with the ``PT_GNU_RELRO`` segment. + +LLD will insert ``.relro_padding`` immediately before the symbol assignment +using ``DATA_SEGMENT_RELRO_END``. diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst index 1590879416853..a5e66d98800cc 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 `_) - +* common-page-size can now be larger than the system page-size. + (`#57618 `_) Breaking changes ---------------- diff --git a/lld/test/ELF/arm-execute-only.s b/lld/test/ELF/arm-execute-only.s index 483d33d19fcd4..e938be5e64a4b 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 0b5e977296d10..d0c143c25148e 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-ppc64.test b/lld/test/ELF/linkerscript/data-segment-relro-ppc64.test new file mode 100644 index 0000000000000..502cdd382a55f --- /dev/null +++ b/lld/test/ELF/linkerscript/data-segment-relro-ppc64.test @@ -0,0 +1,79 @@ +# REQUIRES: x86 +# RUN: rm -rf %t && split-file %s %t +# RUN: llvm-mc -filetype=obj -triple=powerpc64le %t/a.s -o %t/a.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64le %p/Inputs/shared.s -o %t/b.o +# RUN: ld.lld -shared -soname=b %t/b.o -o %t/b.so + +# RUN: ld.lld -z max-page-size=65536 -z norelro %t/a.o %t/b.so -T %t/1.t -o %t/a1 +# RN: llvm-readelf -S -l %t/a1 | FileCheck %s --check-prefixes=CHECK1 + +# RUN: ld.lld -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=CHECK2 + +## -z norelro suppresses the .relro_padding section. +# CHECK1: Name Type Address Off Size ES Flg +# CHECK1: .foo PROGBITS +# CHECK1-NEXT: .orphan.rw PROGBITS +# CHECK1-NEXT: .branch_lt PROGBITS +# CHECK1-NEXT: .got PROGBITS +# CHECK1-NEXT: .data PROGBITS +# CHECK1-NEXT: .bss NOBITS + +# CHECK2: Name Type Address Off Size ES Flg +# CHECK2-NEXT: NULL {{.*}} +# CHECK2: .orphan.ro PROGBITS {{.*}} A +# CHECK2: .dynamic DYNAMIC {{.*}} WA +# CHECK2-NEXT: .branch_lt PROGBITS {{.*}} WA +# CHECK2-NEXT: .got PROGBITS {{.*}} WA +# CHECK2-NEXT: .relro_padding NOBITS 00000000000100f0 0100f0 000f10 00 WA +# CHECK2-NEXT: .data PROGBITS {{.*}} WA +# CHECK2-NEXT: .foo PROGBITS {{.*}} WA +# CHECK2-NEXT: .orphan.rw PROGBITS {{.*}} WA +# CHECK2-NEXT: .bss NOBITS {{.*}} WA + +#--- a.s +.global _start +_start: + addis 3, 2, bar2@toc@ha + ld 12, bar2@toc@l(3) + mtctr 12 + bctrl + b bar + nop + +.section .data,"aw" +.quad 0 + +.zero 4 +.section .foo,"aw" +.section .bss,"",@nobits + +.section .orphan.ro,"a",@progbits +.dc.a 0 + +.section .orphan.rw,"aw",@progbits +.dc.a .orphan.rw + +#--- 1.t +SECTIONS { + . = SIZEOF_HEADERS; + + .plt : { *(.plt) } + .text : { *(.text) } + + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + + .dynamic : { *(.dynamic) } + .branch_lt : { *(.branch_lt) } + .got : { *(.got) } + + . = DATA_SEGMENT_RELRO_END (0, .); + + .plt : { *(.plt) } + .data : { *(.data) } + .bss : { *(.bss) } + + . = DATA_SEGMENT_END (.); + + .comment 0 : { *(.comment) } +} diff --git a/lld/test/ELF/linkerscript/data-segment-relro.test b/lld/test/ELF/linkerscript/data-segment-relro.test index 8aba8acb466f6..79bc9156e803f 100644 --- a/lld/test/ELF/linkerscript/data-segment-relro.test +++ b/lld/test/ELF/linkerscript/data-segment-relro.test @@ -7,18 +7,23 @@ ## 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 --orphan-handling=warn \ +# RUN: %t/a.o %t/b.so -T %t/1.t -o %t/a2 2>&1 | FileCheck %s --check-prefix=WARN # RUN: llvm-readelf -S -l %t/a2 | FileCheck %s --check-prefixes=CHECK,CHECK2 +# WARN: warning: :(.dynsym) is being placed in '.dynsym' +# WARN-NOT: (.relro_padding) + # CHECK: Name Type Address Off Size ES Flg # CHECK-NEXT: NULL {{.*}} # CHECK: .orphan.ro PROGBITS {{.*}} A # CHECK: .dynamic DYNAMIC {{.*}} WA # CHECK-NEXT: __libc_atexit PROGBITS {{.*}} WA # CHECK-NEXT: .got PROGBITS {{.*}} WA +# CHECK2-NEXT:.relro_padding NOBITS 0000000000010100 010100 000f00 00 WA # CHECK-NEXT: .got.plt PROGBITS {{.*}} WA # CHECK: .orphan.rw PROGBITS {{.*}} WA @@ -26,18 +31,18 @@ # 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 0x001000 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 0x001000 R 0x1 +# CHECK2-NEXT: GNU_STACK 0x000000 # CHECK2: Section to Segment mapping: -# CHECK2: 06 .dynamic __libc_atexit .got {{$}} +# CHECK2: 06 .dynamic __libc_atexit .got .relro_padding {{$}} # RUN: sed '/DATA_SEGMENT_RELRO_END/d' %t/1.t > %t/2.t # RUN: not ld.lld %t/a.o %t/b.so -T %t/2.t -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR diff --git a/lld/test/ELF/linkerscript/insert-before.test b/lld/test/ELF/linkerscript/insert-before.test index 922e0859106ff..f9611538c013b 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 58c0ce9810480..0297244184508 100644 --- a/lld/test/ELF/map-file-copy.s +++ b/lld/test/ELF/map-file-copy.s @@ -19,7 +19,7 @@ # CHECK-NEXT: :(.bss.rel.ro) ## Ideally this is displayed as copy@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 59931409c7abd..0cb20d5a4164b 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 :(.dynamic) +# CHECK-NEXT: 202530 202530 ad0 1 .relro_padding +# CHECK-NEXT: 202530 202530 0 1 :(.relro_padding) # CHECK-NEXT: 203530 203530 28 8 .got.plt # CHECK-NEXT: 203530 203530 28 8 :(.got.plt) # CHECK-NEXT: 203560 203560 10 16 .bss @@ -100,8 +102,8 @@ labs = 0x1AB5 # CHECK-NEXT: 0 0 8 1 :(.comment) # CHECK-NEXT: 0 0 1b0 8 .symtab # CHECK-NEXT: 0 0 1b0 8 :(.symtab) -# CHECK-NEXT: 0 0 84 1 .shstrtab -# CHECK-NEXT: 0 0 84 1 :(.shstrtab) +# CHECK-NEXT: 0 0 93 1 .shstrtab +# CHECK-NEXT: 0 0 93 1 :(.shstrtab) # CHECK-NEXT: 0 0 71 1 .strtab # CHECK-NEXT: 0 0 71 1 :(.strtab) diff --git a/lld/test/ELF/partition-notes.s b/lld/test/ELF/partition-notes.s index 9bc43f2fbf9ee..c5ade3a47e052 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 2eec08392fe68..d38597856e165 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/ppc64-section-layout.s b/lld/test/ELF/ppc64-section-layout.s index ae5843e1608a1..490f69b82868c 100644 --- a/lld/test/ELF/ppc64-section-layout.s +++ b/lld/test/ELF/ppc64-section-layout.s @@ -13,6 +13,8 @@ # CHECK-NEXT: .dynamic # CHECK-NEXT: .got # CHECK-NEXT: .toc +## The end of .relro_padding is aligned to a common-page-size boundary. +# CHECK-NEXT: .relro_padding NOBITS 0000000010020400 000400 000c00 00 WA 0 0 1 # CHECK-NEXT: .data # CHECK-NEXT: .branch_lt diff --git a/lld/test/ELF/relocation-copy-relro.s b/lld/test/ELF/relocation-copy-relro.s index 91994501a301d..58492509a38b2 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 8fc8167bb51b7..f15aff36872df 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 9a947d898a12a..4745caae86790 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 163e257e2956e..0ab9665443d1f 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 bb9adf5eef054..56ac95d01fdfd 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 fff3fc14f3024..819cd9c14d950 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 d0e4afe7fb668..20501e92b29c9 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 66e32be7c874a..c8e56d0860499 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 21c79eab950d6..56ed2c9ca9bdb 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 9bf38eaac236b..9a1836820ef1f 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 e9ea69afab3b1..37201279fa0a5 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