Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -69,6 +69,7 @@ : BaseCommand(OutputSectionKind), Name(Name) {} static bool classof(const BaseCommand *C); StringRef Name; + std::vector AlignExpr; std::vector> Commands; std::vector Phdrs; std::vector Filler; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -267,12 +267,14 @@ // 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, - ConstraintKind Constraint) { + ConstraintKind Constraint, uintX_t Align) { OutputSectionBase *Sec; bool IsNew; std::tie(Sec, IsNew) = Factory.create(C, Name); - if (IsNew) + if (IsNew) { Result.push_back(Sec); + Sec->updateAlignment(Align); + } if ((!(C->getSectionHdr()->sh_flags & SHF_WRITE)) && Constraint == ReadWrite) { Removed.insert(Sec); @@ -293,6 +295,8 @@ if (!OutCmd) continue; + uint64_t Align = + OutCmd->AlignExpr.empty() ? 0 : evalExpr(OutCmd->AlignExpr, Dot); for (const std::unique_ptr &Cmd : OutCmd->Commands) { auto *InCmd = dyn_cast(Cmd.get()); if (!InCmd) @@ -307,7 +311,7 @@ if (OutCmd->Name == "/DISCARD/") S->Live = false; else - AddInputSec(S, OutCmd->Name, OutCmd->Constraint); + AddInputSec(S, OutCmd->Name, OutCmd->Constraint, Align); } } } @@ -319,7 +323,7 @@ for (InputSectionBase *S : F->getSections()) { if (!isDiscarded(S)) { if (!S->OutSec) - AddInputSec(S, getOutputSectionName(S), NoConstraint); + AddInputSec(S, getOutputSectionName(S), NoConstraint, 0); } else reportDiscarded(S, F); } @@ -604,6 +608,7 @@ void readProvide(bool Hidden); SymbolAssignment *readSymbolAssignment(StringRef Name); std::vector readSectionsCommandExpr(); + void readAlign(OutputSectionCommand *Cmd); const static StringMap Cmd; ScriptConfiguration &Opt = *ScriptConfig; @@ -820,11 +825,21 @@ Opt.Commands.push_back(llvm::make_unique(".", Expr)); } +void ScriptParser::readAlign(OutputSectionCommand *Cmd) { + expect("ALIGN"); + expect("("); + Cmd->AlignExpr = readSectionsCommandExpr(); + expect(")"); +} + void ScriptParser::readOutputSectionDescription(StringRef OutSec) { OutputSectionCommand *Cmd = new OutputSectionCommand(OutSec); Opt.Commands.emplace_back(Cmd); expect(":"); + if (peek() == "ALIGN") + readAlign(Cmd); + // Parse constraints. if (skip("ONLY_IF_RO")) Cmd->Constraint = ReadOnly; Index: test/ELF/linkerscript-align.s =================================================================== --- test/ELF/linkerscript-align.s +++ test/ELF/linkerscript-align.s @@ -1,6 +1,7 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +## Check that ALIGN command workable using location counter # RUN: echo "SECTIONS { \ # RUN: . = 0x10000; \ # RUN: .aaa : \ @@ -27,6 +28,25 @@ # CHECK-NEXT: 2 .bbb 00000008 0000000000011000 DATA # CHECK-NEXT: 3 .ccc 00000008 0000000000014000 DATA +## Check output sections ALIGN modificator +# RUN: echo "SECTIONS { \ +# RUN: . = 0x10000; \ +# RUN: .aaa : \ +# RUN: { \ +# RUN: *(.aaa) \ +# RUN: } \ +# RUN: .bbb : ALIGN(4096) \ +# RUN: { \ +# RUN: *(.bbb) \ +# RUN: } \ +# RUN: .ccc : ALIGN(4096 * 4) \ +# RUN: { \ +# RUN: *(.ccc) \ +# RUN: } \ +# RUN: }" > %t2.script +# RUN: ld.lld -o %t2 --script %t2.script %t +# RUN: llvm-objdump -section-headers %t1 | FileCheck %s + .global _start _start: nop