Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -155,6 +155,7 @@ virtual uint64_t getOutputSectionAddress(StringRef Name) = 0; virtual uint64_t getOutputSectionSize(StringRef Name) = 0; virtual uint64_t getOutputSectionAlign(StringRef Name) = 0; + virtual uint64_t getOutputSectionLoadAddress(StringRef Name) = 0; virtual uint64_t getHeaderSize() = 0; virtual uint64_t getSymbolValue(StringRef S) = 0; virtual bool isDefined(StringRef S) = 0; @@ -202,6 +203,7 @@ uint64_t getOutputSectionAddress(StringRef Name) override; uint64_t getOutputSectionSize(StringRef Name) override; uint64_t getOutputSectionAlign(StringRef Name) override; + uint64_t getOutputSectionLoadAddress(StringRef Name) override; uint64_t getHeaderSize() override; uint64_t getSymbolValue(StringRef S) override; bool isDefined(StringRef S) override; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -728,6 +728,14 @@ } template +uint64_t LinkerScript::getOutputSectionLoadAddress(StringRef Name) { + uint64_t VA = getOutputSectionAddress(Name); + if (Expr LmaExpr = getLma(Name)) + return LmaExpr(VA); + return VA; +} + +template uint64_t LinkerScript::getOutputSectionSize(StringRef Name) { for (OutputSectionBase *Sec : *OutputSections) if (Sec->getName() == Name) @@ -1539,6 +1547,14 @@ expect(")"); return [](uint64_t Dot) { return alignTo(Dot, Target->PageSize); }; } + if (Tok == "LOADADDR") { + expect("("); + StringRef Name = next(); + expect(")"); + return [=](uint64_t Dot) { + return ScriptBase->getOutputSectionLoadAddress(Name); + }; + } if (Tok == "SIZEOF") { expect("("); StringRef Name = next(); Index: test/ELF/linkerscript/loadaddr.s =================================================================== --- test/ELF/linkerscript/loadaddr.s +++ test/ELF/linkerscript/loadaddr.s @@ -0,0 +1,45 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +# RUN: echo "SECTIONS { \ +# RUN: . = 0x10000; \ +# RUN: .foo : AT(0x15000) { *(.foo*) } \ +# RUN: .bar LOADADDR(.foo) : { *(.bar*) } \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-objdump -section-headers %t1 | FileCheck %s +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address Type +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK-NEXT: 1 .foo 00000008 0000000000010000 DATA +# CHECK-NEXT: 2 .bar 00000008 0000000000015000 DATA + +# RUN: echo "SECTIONS { \ +# RUN: . = 0x10000; \ +# RUN: .foo : { *(.foo*) } \ +# RUN: .bar LOADADDR(.foo) + 0x100 : { *(.bar*) } \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t2 --script %t.script %t +# RUN: llvm-objdump -section-headers %t2 | FileCheck %s --check-prefix=NO-AT +# NO-AT: Sections: +# NO-AT-NEXT: Idx Name Size Address Type +# NO-AT-NEXT: 0 00000000 0000000000000000 +# NO-AT-NEXT: 1 .foo 00000008 0000000000010000 DATA +# NO-AT-NEXT: 2 .bar 00000008 0000000000010100 DATA + +## Check that we error out if trying to get load address of +## section that does not exist. +# RUN: echo "SECTIONS { .bar LOADADDR(.zed) : { *(.bar*) } }" > %t.script +# RUN: not ld.lld -o %t1 --script %t.script %t 2>&1 \ +# RUN: | FileCheck -check-prefix=ERR %s +# ERR: undefined section .zed + +.global _start +_start: + nop + +.section .foo,"a" +.quad 1 + +.section .bar,"a" +.quad 1