Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -220,7 +220,7 @@ std::vector getPhdrIndices(OutputSection *Sec); - MemoryRegion *findMemoryRegion(OutputSection *Sec); + MemoryRegion *findMemoryRegion(OutputSection *Sec, llvm::StringRef Name); void switchTo(OutputSection *Sec); uint64_t advance(uint64_t Size, unsigned Align); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -620,14 +620,15 @@ // This function searches for a memory region to place the given output // section in. If found, a pointer to the appropriate memory region is // returned. Otherwise, a nullptr is returned. -MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *Sec) { +MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *Sec, + llvm::StringRef Name) { // If a memory region name was specified in the output section command, // then try to find that region first. - if (!Sec->MemoryRegionName.empty()) { - auto It = MemoryRegions.find(Sec->MemoryRegionName); + if (!Name.empty()) { + auto It = MemoryRegions.find(Name); if (It != MemoryRegions.end()) return It->second; - error("memory region '" + Sec->MemoryRegionName + "' not declared"); + error("memory region '" + Name + "' not declared"); return nullptr; } @@ -666,6 +667,10 @@ uint64_t D = Dot; Ctx->LMAOffset = [=] { return Sec->LMAExpr().getValue() - D; }; } + if (Sec->LMARegion) { + uint64_t D = Dot; + Ctx->LMAOffset = [=] { return Sec->LMARegion->Origin - D; }; + } switchTo(Sec); @@ -791,7 +796,11 @@ if (auto *Sec = dyn_cast(Base)) { if (!Sec->Live) continue; - Sec->MemRegion = findMemoryRegion(Sec); + + Sec->MemRegion = findMemoryRegion(Sec, Sec->MemoryRegionName); + if (!Sec->LMARegionName.empty()) + Sec->LMARegion = findMemoryRegion(Sec, Sec->LMARegionName); + // Handle align (e.g. ".foo : ALIGN(16) { ... }"). if (Sec->AlignExpr) Sec->Alignment = Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -89,6 +89,7 @@ // The following members are normally only used in linker scripts. MemoryRegion *MemRegion = nullptr; + MemoryRegion *LMARegion = nullptr; Expr AddrExpr; Expr AlignExpr; Expr LMAExpr; @@ -99,6 +100,7 @@ ConstraintKind Constraint = ConstraintKind::NoConstraint; std::string Location; std::string MemoryRegionName; + std::string LMARegionName; bool Noload = false; template void finalize(); Index: ELF/ScriptParser.cpp =================================================================== --- ELF/ScriptParser.cpp +++ ELF/ScriptParser.cpp @@ -708,6 +708,24 @@ else if (peek().startswith(">")) Cmd->MemoryRegionName = next().drop_front(); + if (consume("AT")) { + if (!peek().startswith(">")) { + setError("unknown command " + peek()); + } else if (peek() == ">") { + skip(); + Cmd->LMARegionName = next(); + } else { + Cmd->LMARegionName = next().drop_front(); + } + } else if (consume("AT>")) { + Cmd->LMARegionName = next(); + } else if (peek().startswith("AT>")) { + Cmd->LMARegionName = next().drop_front(3); + } + + if (Cmd->LMAExpr && !Cmd->LMARegionName.empty()) + error("section can't have both LMA and a load region"); + Cmd->Phdrs = readOutputSectionPhdrs(); if (consume("=")) Index: test/ELF/linkerscript/at2.s =================================================================== --- test/ELF/linkerscript/at2.s +++ test/ELF/linkerscript/at2.s @@ -0,0 +1,68 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "MEMORY { \ +# RUN: FLASH (ax) : ORIGIN = 0x2000, LENGTH = 0x100 \ +# RUN: RAM (aw) : ORIGIN = 0x5000, LENGTH = 0x100 } \ +# RUN: SECTIONS { \ +# RUN: .foo1 : { *(.foo1) } > FLASH AT>FLASH \ +# RUN: .foo2 : { *(.foo2) } > FLASH \ +# RUN: .bar1 : { *(.bar1) } > RAM AT> RAM \ +# RUN: .bar2 : { *(.bar2) } > RAM AT > RAM \ +# RUN: .bar3 : { *(.bar3) } > RAM AT >RAM \ +# RUN: }" > %t.script +# RUN: ld.lld %t --script %t.script -o %t2 +# RUN: llvm-readobj -program-headers %t2 | FileCheck %s + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "MEMORY { \ +# RUN: FLASH (ax) : ORIGIN = 0x2000, LENGTH = 0x100 \ +# RUN: RAM (aw) : ORIGIN = 0x5000, LENGTH = 0x100 } \ +# RUN: SECTIONS { \ +# RUN: .foo1 : AT(0x500) { *(.foo1) } > FLASH AT>FLASH \ +# RUN: }" > %t2.script +# RUN: not ld.lld %t --script %t2.script -o %t2 2>&1 | \ +# RUN: FileCheck %s --check-prefix=ERR +# ERR: error: section can't have both LMA and a load region + +# CHECK: ProgramHeaders [ +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: VirtualAddress: 0x2000 +# CHECK-NEXT: PhysicalAddress: 0x2000 +# CHECK-NEXT: FileSize: +# CHECK-NEXT: MemSize: +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: PF_X +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD +# CHECK-NEXT: Offset: 0x2000 +# CHECK-NEXT: VirtualAddress: 0x5000 +# CHECK-NEXT: PhysicalAddress: 0x5000 +# CHECK-NEXT: FileSize: +# CHECK-NEXT: MemSize: +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: PF_W +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } + +.section .foo1, "ax" +.quad 0 + +.section .foo2, "ax" +.quad 0 + +.section .bar1, "aw" +.quad 0 + +.section .bar2, "aw" +.quad 0 + +.section .bar3, "aw" +.quad 0