Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -42,7 +42,8 @@ AssignmentKind, OutputSectionKind, InputSectionKind, - AssertKind + AssertKind, + FillKind }; struct BaseCommand { @@ -109,6 +110,14 @@ Expr Expression; }; +struct FillCommand : BaseCommand { + FillCommand() : BaseCommand(FillKind) {} + static bool classof(const BaseCommand *C); + std::vector Value; + InputSectionData *GoesAfter = nullptr; + uint64_t Offset = 0; +}; + struct PhdrsCommand { StringRef Name; unsigned Type; @@ -151,7 +160,9 @@ std::vector> createPhdrs(); bool ignoreInterpSection(); - ArrayRef getFiller(StringRef Name); + std::vector>> + getFillerMap(StringRef Name); + Expr getLma(StringRef Name); bool shouldKeep(InputSectionBase *S); void assignAddresses(); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -83,6 +83,10 @@ return C->Kind == AssertKind; } +bool FillCommand::classof(const BaseCommand *C) { + return C->Kind == FillKind; +} + template static bool isDiscarded(InputSectionBase *S) { return !S || !S->Live; } @@ -197,6 +201,13 @@ OutCmd->GoesAfter = Ret.empty() ? nullptr : Ret.back(); continue; } + if (auto *OutCmd = dyn_cast(Base.get())) { + OutCmd->GoesAfter = Ret.empty() ? nullptr : Ret.back(); + continue; + } + + if (isa(Base.get())) + continue; auto *Cmd = cast(Base.get()); std::vector *> V = getInputSections(Cmd); @@ -306,6 +317,13 @@ } template +static bool isGoesAfter(BaseCommand *Cmd, InputSectionData *D) { + if (auto *AssignCmd = dyn_cast(Cmd)) + return AssignCmd->GoesAfter == D; + return cast(Cmd)->GoesAfter == D; +} + +template void assignOffsets(OutputSectionCommand *Cmd, OutputSectionBase *Sec) { auto *OutSec = dyn_cast>(Sec); if (!OutSec) { @@ -325,12 +343,18 @@ // is nullptr. auto AssignSuccessors = [&](InputSectionData *D) { for (; ItCmd != Cmd->Commands.end(); ++ItCmd) { - auto *AssignCmd = dyn_cast(ItCmd->get()); - if (!AssignCmd) + BaseCommand *Cmd = ItCmd->get(); + if (!isa(Cmd) && !isa(Cmd)) continue; - if (D != AssignCmd->GoesAfter) + if (!isGoesAfter(Cmd, D)) break; + if (auto *FillCmd = dyn_cast(Cmd)) { + FillCmd->Offset = Off; + continue; + } + + auto *AssignCmd = cast(Cmd); uintX_t Value = AssignCmd->Expression(Sec->getVA() + Off) - Sec->getVA(); if (AssignCmd->Name == ".") { // Update to location counter means update to section size. @@ -503,11 +527,24 @@ } template -ArrayRef LinkerScript::getFiller(StringRef Name) { - for (const std::unique_ptr &Base : Opt.Commands) - if (auto *Cmd = dyn_cast(Base.get())) - if (Cmd->Name == Name) - return Cmd->Filler; +std::vector>> +LinkerScript::getFillerMap(StringRef Name) { + std::vector>> Ret; + for (const std::unique_ptr &Base1 : Opt.Commands) + if (auto *Cmd = dyn_cast(Base1.get())) { + if (Cmd->Name != Name) + continue; + for (const std::unique_ptr &Base2 : Cmd->Commands) + if (auto *Cmd = dyn_cast(Base2.get())) + Ret.push_back({Cmd->Offset, Cmd->Value}); + + if (!Ret.empty()) + return Ret; + if (Cmd->Filler.empty()) + return {}; + return {{0, Cmd->Filler}}; + } + return {}; } @@ -631,7 +668,9 @@ void readVersionScriptCommand(); SymbolAssignment *readAssignment(StringRef Name); + FillCommand *readFill(); OutputSectionCommand *readOutputSectionDescription(StringRef OutSec); + std::vector readSectionFiller(StringRef Tok); std::vector readOutputSectionFiller(); std::vector readOutputSectionPhdrs(); InputSectionDescription *readInputSectionDescription(StringRef Tok); @@ -1015,6 +1054,8 @@ StringRef Tok = next(); if (SymbolAssignment *Assignment = readProvideOrAssignment(Tok)) Cmd->Commands.emplace_back(Assignment); + else if (Tok == "FILL") + Cmd->Commands.emplace_back(readFill()); else if (Tok == "SORT") readSort(); else if (peek() == "(") @@ -1034,19 +1075,21 @@ // hexstrings as blobs of arbitrary sizes, while ld.gold handles them // as 32-bit big-endian values. We will do the same as ld.gold does // because it's simpler than what ld.bfd does. -std::vector ScriptParser::readOutputSectionFiller() { - if (!peek().startswith("=")) - return {}; - - StringRef Tok = next(); +std::vector ScriptParser::readSectionFiller(StringRef Tok) { uint32_t V; - if (Tok.substr(1).getAsInteger(0, V)) { + if (Tok.getAsInteger(0, V)) { setError("invalid filler expression: " + Tok); return {}; } return {uint8_t(V >> 24), uint8_t(V >> 16), uint8_t(V >> 8), uint8_t(V)}; } +std::vector ScriptParser::readOutputSectionFiller() { + if (!peek().startswith("=")) + return {}; + return readSectionFiller(next().drop_front()); +} + SymbolAssignment *ScriptParser::readProvideHidden(bool Provide, bool Hidden) { expect("("); SymbolAssignment *Cmd = readAssignment(next()); @@ -1154,6 +1197,15 @@ return new SymbolAssignment(Name, E); } +FillCommand *ScriptParser::readFill() { + FillCommand *Cmd = new FillCommand(); + expect("("); + Cmd->Value = readSectionFiller(next()); + expect(")"); + expect(";"); + return Cmd; +} + // This is an operator-precedence parser to parse a linker // script expression. Expr ScriptParser::readExpr() { return readExpr1(readPrimary(), 0); } Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -973,10 +973,27 @@ memcpy(Buf + I, A.data(), Size - I); } +static void fillMap(uint8_t *Buf, size_t Size, + ArrayRef>> A) { + for (size_t I = 0, E = A.size(); I < E; ++I) { + size_t Offset = A[I].first; + ArrayRef Filler = A[I].second; + if (I != E - 1) { + size_t NextOffset = A[I + 1].first; + size_t S = NextOffset - Offset; + fill(Buf + Offset, S, Filler); + continue; + } + fill(Buf + Offset, Size - Offset, Filler); + } +} + template void OutputSection::writeTo(uint8_t *Buf) { - ArrayRef Filler = Script::X->getFiller(this->Name); + std::vector>> Filler = + Script::X->getFillerMap(this->Name); if (!Filler.empty()) - fill(Buf, this->getSize(), Filler); + fillMap(Buf, this->getSize(), Filler); + if (Config->Threads) { parallel_for_each(Sections.begin(), Sections.end(), [=](InputSection *C) { C->writeTo(Buf); }); Index: test/ELF/linkerscript/linkerscript-fill.s =================================================================== --- test/ELF/linkerscript/linkerscript-fill.s +++ test/ELF/linkerscript/linkerscript-fill.s @@ -0,0 +1,46 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "SECTIONS { \ +# RUN: .out : { \ +# RUN: FILL(0x11111111); \ +# RUN: *(.aaa) \ +# RUN: . += 4; \ +# RUN: *(.bbb) \ +# RUN: . += 4; \ +# RUN: FILL(0x22222222); \ +# RUN: . += 4; \ +# RUN: } \ +# RUN: }; " > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o +# RUN: llvm-objdump -s %t | FileCheck %s + +# CHECK: Contents of section .out: +# CHECK-NEXT: 0120 aa111111 11bb1111 11112222 2222 + +## If both FILL and ‘=fillexp’ are used then +## that FILL command takes precedence. +# RUN: echo "SECTIONS { \ +# RUN: .out : { \ +# RUN: FILL(0x11111111); \ +# RUN: *(.aaa) \ +# RUN: . += 4; \ +# RUN: *(.bbb) \ +# RUN: . += 4; \ +# RUN: FILL(0x22222222); \ +# RUN: . += 4; \ +# RUN: }=0x99887766 \ +# RUN: }; " > %t2.script +# RUN: ld.lld -o %t2 --script %t2.script %t.o +# RUN: llvm-objdump -s %t2 | FileCheck %s + +.text +.globl _start +_start: + +.section .aaa, "a" +.align 1 +.byte 0xAA + +.section .bbb, "a" +.align 1 +.byte 0xBB Index: test/ELF/linkerscript/linkerscript-sections-padding.s =================================================================== --- test/ELF/linkerscript/linkerscript-sections-padding.s +++ test/ELF/linkerscript/linkerscript-sections-padding.s @@ -29,7 +29,7 @@ # RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x99XX }" > %t.script # RUN: not ld.lld -o %t.out --script %t.script %t 2>&1 \ # RUN: | FileCheck --check-prefix=ERR2 %s -# ERR2: invalid filler expression: =0x99XX +# ERR2: invalid filler expression: 0x99XX .section .mysec.1,"a" .align 16