Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -53,6 +53,12 @@ std::vector Expr; }; +// Linker scripts allow additional constraints to be put on ouput sections. +// An output section will only be created if all of its input sections are read-only +// or all of its input sections are read-write by using the keyword ONLY_IF_RO +// and ONLY_IF_RW respectively. +enum ConstraintKind { NoConstraint, ReadOnly, ReadWrite }; + struct OutputSectionCommand : BaseCommand { OutputSectionCommand(StringRef Name) : BaseCommand(OutputSectionKind), Name(Name) {} @@ -61,6 +67,7 @@ std::vector> Commands; std::vector Phdrs; std::vector Filler; + ConstraintKind Constraint = NoConstraint; }; struct InputSectionDescription : BaseCommand { Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -265,12 +265,23 @@ // Add input section to output section. If there is no output section yet, // then create it and add to output section list. - auto AddInputSec = [&](InputSectionBase *C, StringRef Name) { + auto AddInputSec = [&](InputSectionBase *C, StringRef Name, + ConstraintKind Constraint) { OutputSectionBase *Sec; bool IsNew; std::tie(Sec, IsNew) = Factory.create(C, Name); if (IsNew) Result.push_back(Sec); + if ((!(C->getSectionHdr()->sh_flags & SHF_WRITE)) && + Constraint == ReadWrite) { + Sec->DiscardFromOutput = true; + return; + } + if ((C->getSectionHdr()->sh_flags & SHF_WRITE) && + Constraint == ReadOnly) { + Sec->DiscardFromOutput = true; + return; + } Sec->addSection(C); }; @@ -296,7 +307,7 @@ if (OutCmd->Name == "/DISCARD/") S->Live = false; else - AddInputSec(S, OutCmd->Name); + AddInputSec(S, OutCmd->Name, OutCmd->Constraint); } } } @@ -308,11 +319,17 @@ for (InputSectionBase *S : F->getSections()) { if (!isDiscarded(S)) { if (!S->OutSec) - AddInputSec(S, getOutputSectionName(S)); + AddInputSec(S, getOutputSectionName(S), NoConstraint); } else reportDiscarded(S, F); } + // Remove from the output all the sections which did not met the constraints. + Result.erase(std::remove_if(Result.begin(), Result.end(), + [](OutputSectionBase *Sec) { + return Sec->DiscardFromOutput; + }), + Result.end()); return Result; } @@ -793,10 +810,17 @@ OutputSectionCommand *Cmd = new OutputSectionCommand(OutSec); Opt.Commands.emplace_back(Cmd); expect(":"); + + // Parse constraints. + StringRef Tok = peek(); + if (skip("ONLY_IF_RO")) + Cmd->Constraint = ReadOnly; + if (skip("ONLY_IF_RW")) + Cmd->Constraint = ReadWrite; expect("{"); while (!Error && !skip("}")) { - StringRef Tok = next(); + Tok = next(); if (Tok == "*") { auto *InCmd = new InputSectionDescription(); Cmd->Commands.emplace_back(InCmd); @@ -820,7 +844,7 @@ } Cmd->Phdrs = readOutputSectionPhdrs(); - StringRef Tok = peek(); + Tok = peek(); if (Tok.startswith("=")) { if (!Tok.startswith("=0x")) { setError("filler should be a hexadecimal value"); Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -78,6 +78,9 @@ // Typically the first section of each PT_LOAD segment has this flag. bool PageAlign = false; + // If true, this section will be not included in the final binary. + bool DiscardFromOutput = false; + virtual void finalize() {} virtual void finalizePieces() {} virtual void assignOffsets() {} Index: test/ELF/linkerscript-sections-constraint.s =================================================================== --- test/ELF/linkerscript-sections-constraint.s +++ test/ELF/linkerscript-sections-constraint.s @@ -8,9 +8,9 @@ # RUN: FileCheck -check-prefix=BASE %s # BASE: Sections: # BASE-NEXT: Idx Name Size Address Type -# BASE-NEXT: 0 00000000 0000000000000000 -# BASE-NEXT: 1 .writable 00000004 0000000000000190 DATA -# BASE-NEXT: 2 .readable 00000004 0000000000000194 DATA +# BASE-NEXT: 0 00000000 0000000000000000 +# BASE-NEXT: 1 .writable 00000004 0000000000000190 DATA +# BASE-NEXT: 2 .readable 00000004 0000000000000194 DATA # RUN: echo "SECTIONS { \ # RUN: .writable : ONLY_IF_RO { *(.writable) } \