Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -26,7 +26,8 @@ template class OutputSectionFactory; template class DefinedCommon; -typedef std::function Expr; +typedef std::function DotExpr; +typedef std::function Expr; // Parses a linker script. Calling this function updates // Config and ScriptConfig. @@ -81,6 +82,7 @@ StringRef Name; Expr AddrExpr; Expr AlignExpr; + Expr SubAlignExpr; std::vector> Commands; std::vector Phdrs; std::vector Filler; @@ -135,6 +137,8 @@ createPhdrs(ArrayRef *> S); ArrayRef getFiller(StringRef Name); + uintX_t getSubAlign(StringRef Name); + bool shouldKeep(InputSectionBase *S); void assignAddresses(ArrayRef *> S); int compareSections(StringRef A, StringRef B); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -220,12 +220,14 @@ uintX_t MinVA = std::numeric_limits::max(); uintX_t ThreadBssOffset = 0; + auto LocationCounter = [=]() { return Dot; }; for (const std::unique_ptr &Base : Opt.Commands) { if (auto *Cmd = dyn_cast(Base.get())) { if (Cmd->Name == ".") { - Dot = Cmd->Expression(Dot); + Dot = Cmd->Expression(LocationCounter); } else if (Cmd->Sym) { - cast>(Cmd->Sym)->Value = Cmd->Expression(Dot); + cast>(Cmd->Sym)->Value = + Cmd->Expression(LocationCounter); } continue; } @@ -239,10 +241,10 @@ continue; if (Cmd->AddrExpr) - Dot = Cmd->AddrExpr(Dot); + Dot = Cmd->AddrExpr(LocationCounter); if (Cmd->AlignExpr) - Sec->updateAlignment(Cmd->AlignExpr(Dot)); + Sec->updateAlignment(Cmd->AlignExpr(LocationCounter)); if ((Sec->getFlags() & SHF_TLS) && Sec->getType() == SHT_NOBITS) { uintX_t TVA = Dot + ThreadBssOffset; @@ -342,6 +344,19 @@ return {}; } +template +typename ELFT::uint LinkerScript::getSubAlign(StringRef Name) { + auto LocationCounter = [=]() { + error("access to location counter not supported for SUBALIGN"); + return 1; + }; + for (const std::unique_ptr &Base : Opt.Commands) + if (auto *Cmd = dyn_cast(Base.get())) + if (Cmd->SubAlignExpr && Cmd->Name == Name) + return Cmd->SubAlignExpr(LocationCounter); + return (uintX_t)(-1); +} + // Returns the index of the given section name in linker script // SECTIONS commands. Sections are laid out as the same order as they // were in the script. If a given name did not appear in the script, @@ -467,6 +482,7 @@ unsigned readPhdrType(); void readProvide(bool Hidden); void readAlign(OutputSectionCommand *Cmd); + void readSubAlign(OutputSectionCommand *Cmd); void readSort(); Expr readExpr(); @@ -747,6 +763,12 @@ expect(")"); } +void ScriptParser::readSubAlign(OutputSectionCommand *Cmd) { + expect("("); + Cmd->SubAlignExpr = readExpr(); + expect(")"); +} + void ScriptParser::readSort() { expect("("); expect("CONSTRUCTORS"); @@ -766,6 +788,8 @@ if (skip("ALIGN")) readAlign(Cmd); + if (skip("SUBALIGN")) + readSubAlign(Cmd); // Parse constraints. if (skip("ONLY_IF_RO")) @@ -872,7 +896,7 @@ assert(Op == "=" || Op == "+="); Expr E = readExpr(); if (Op == "+=") - E = [=](uint64_t Dot) { return getSymbolValue(Name, Dot) + E(Dot); }; + E = [=](DotExpr Dot) { return getSymbolValue(Name, Dot()) + E(Dot); }; auto *Cmd = new SymbolAssignment(Name, E); Opt.Commands.emplace_back(Cmd); return Cmd; @@ -933,13 +957,13 @@ expect("("); Expr E = readExpr(); expect(")"); - return [=](uint64_t Dot) { return alignTo(Dot, E(Dot)); }; + return [=](DotExpr Dot) { return alignTo(Dot(), E(Dot)); }; } if (Tok == "CONSTANT") { expect("("); StringRef Tok = next(); expect(")"); - return [=](uint64_t Dot) { return getConstant(Tok); }; + return [=](DotExpr Dot) { return getConstant(Tok); }; } if (Tok == "SEGMENT_START") { expect("("); @@ -948,7 +972,7 @@ uint64_t Val; next().getAsInteger(0, Val); expect(")"); - return [=](uint64_t Dot) { return Val; }; + return [=](DotExpr Dot) { return Val; }; } if (Tok == "DATA_SEGMENT_ALIGN") { expect("("); @@ -956,13 +980,13 @@ expect(","); readExpr(); expect(")"); - return [=](uint64_t Dot) { return alignTo(Dot, E(Dot)); }; + return [=](DotExpr Dot) { return alignTo(Dot(), E(Dot)); }; } if (Tok == "DATA_SEGMENT_END") { expect("("); expect("."); expect(")"); - return [](uint64_t Dot) { return Dot; }; + return [](DotExpr Dot) { return Dot(); }; } // GNU linkers implements more complicated logic to handle // DATA_SEGMENT_RELRO_END. We instead ignore the arguments and just align to @@ -973,13 +997,13 @@ expect(","); readExpr(); expect(")"); - return [](uint64_t Dot) { return alignTo(Dot, Target->PageSize); }; + return [](DotExpr Dot) { return alignTo(Dot(), Target->PageSize); }; } if (Tok == "SIZEOF") { expect("("); StringRef Name = next(); expect(")"); - return [=](uint64_t Dot) { return getSectionSize(Name); }; + return [=](DotExpr Dot) { return getSectionSize(Name); }; } // Parse a symbol name or a number literal. @@ -987,9 +1011,9 @@ if (Tok.getAsInteger(0, V)) { if (Tok != "." && !isValidCIdentifier(Tok)) setError("malformed number: " + Tok); - return [=](uint64_t Dot) { return getSymbolValue(Tok, Dot); }; + return [=](DotExpr Dot) { return getSymbolValue(Tok, Dot()); }; } - return [=](uint64_t Dot) { return V; }; + return [=](DotExpr Dot) { return V; }; } Expr ScriptParser::readTernary(Expr Cond) { @@ -997,14 +1021,14 @@ Expr L = readExpr(); expect(":"); Expr R = readExpr(); - return [=](uint64_t Dot) { return Cond(Dot) ? L(Dot) : R(Dot); }; + return [=](DotExpr Dot) { return Cond(Dot) ? L(Dot) : R(Dot); }; } Expr ScriptParser::combine(StringRef Op, Expr L, Expr R) { if (Op == "*") - return [=](uint64_t Dot) { return L(Dot) * R(Dot); }; + return [=](DotExpr Dot) { return L(Dot) * R(Dot); }; if (Op == "/") { - return [=](uint64_t Dot) -> uint64_t { + return [=](DotExpr Dot) -> uint64_t { uint64_t RHS = R(Dot); if (RHS == 0) { error("division by zero"); @@ -1014,23 +1038,23 @@ }; } if (Op == "+") - return [=](uint64_t Dot) { return L(Dot) + R(Dot); }; + return [=](DotExpr Dot) { return L(Dot) + R(Dot); }; if (Op == "-") - return [=](uint64_t Dot) { return L(Dot) - R(Dot); }; + return [=](DotExpr Dot) { return L(Dot) - R(Dot); }; if (Op == "<") - return [=](uint64_t Dot) { return L(Dot) < R(Dot); }; + return [=](DotExpr Dot) { return L(Dot) < R(Dot); }; if (Op == ">") - return [=](uint64_t Dot) { return L(Dot) > R(Dot); }; + return [=](DotExpr Dot) { return L(Dot) > R(Dot); }; if (Op == ">=") - return [=](uint64_t Dot) { return L(Dot) >= R(Dot); }; + return [=](DotExpr Dot) { return L(Dot) >= R(Dot); }; if (Op == "<=") - return [=](uint64_t Dot) { return L(Dot) <= R(Dot); }; + return [=](DotExpr Dot) { return L(Dot) <= R(Dot); }; if (Op == "==") - return [=](uint64_t Dot) { return L(Dot) == R(Dot); }; + return [=](DotExpr Dot) { return L(Dot) == R(Dot); }; if (Op == "!=") - return [=](uint64_t Dot) { return L(Dot) != R(Dot); }; + return [=](DotExpr Dot) { return L(Dot) != R(Dot); }; if (Op == "&") - return [=](uint64_t Dot) { return L(Dot) & R(Dot); }; + return [=](DotExpr Dot) { return L(Dot) & R(Dot); }; llvm_unreachable("invalid operator"); } Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -860,9 +860,15 @@ // This function is called after we sort input sections // and scan relocations to setup sections' offsets. template void OutputSection::assignOffsets() { + uintX_t SubAlign = ScriptConfig->HasContents + ? Script::X->getSubAlign(this->getName()) + : (uintX_t)-1; uintX_t Off = this->Header.sh_size; for (InputSection *S : Sections) { - Off = alignTo(Off, S->Alignment); + if (SubAlign != (uintX_t)-1) + Off = alignTo(Off, SubAlign); + else + Off = alignTo(Off, S->Alignment); S->OutSecOff = Off; Off += S->getSize(); } Index: test/ELF/linkerscript/linkerscript-subalign.s =================================================================== --- test/ELF/linkerscript/linkerscript-subalign.s +++ test/ELF/linkerscript/linkerscript-subalign.s @@ -0,0 +1,47 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o + +# RUN: echo "SECTIONS { .aaa : { *(.aaa.*) } }" > %t1.script +# RUN: ld.lld -o %t1 --script %t1.script %t1.o +# RUN: llvm-objdump -s %t1 | FileCheck -check-prefix=NOALIGN %s +# NOALIGN: Contents of section .aaa: +# NOALIGN-NEXT: 0180 01000000 00000000 00000000 00000000 +# NOALIGN-NEXT: 0190 00000000 00000000 00000000 00000000 +# NOALIGN-NEXT: 01a0 02000000 00000000 00000000 00000000 +# NOALIGN-NEXT: 01b0 00000000 00000000 00000000 00000000 +# NOALIGN-NEXT: 01c0 03000000 00000000 00000000 00000000 +# NOALIGN-NEXT: 01d0 00000000 00000000 00000000 00000000 +# NOALIGN-NEXT: 01e0 00000000 00000000 00000000 00000000 +# NOALIGN-NEXT: 01f0 00000000 00000000 00000000 00000000 +# NOALIGN-NEXT: 0200 04000000 00000000 + +# RUN: echo "SECTIONS { .aaa : SUBALIGN(1) { *(.aaa.*) } }" > %t2.script +# RUN: ld.lld -o %t2 --script %t2.script %t1.o +# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=SUBALIGN %s +# SUBALIGN: Contents of section .aaa: +# SUBALIGN: 0180 01000000 00000000 02000000 00000000 +# SUBALIGN: 0190 03000000 00000000 04000000 00000000 + +# RUN: echo "SECTIONS { .aaa : SUBALIGN(.) { *(.aaa.*) } }" > %t3.script +# RUN: not ld.lld -o %t3 --script %t3.script %t1.o 2>&1 | FileCheck -check-prefix=ERR %s +# ERR: access to location counter not supported for SUBALIGN + +.global _start +_start: + nop + +.section .aaa.1, "a" +.align 16 +.quad 1 + +.section .aaa.2, "a" +.align 32 +.quad 2 + +.section .aaa.3, "a" +.align 64 +.quad 3 + +.section .aaa.4, "a" +.align 128 +.quad 4