Index: lld/trunk/ELF/LinkerScript.h =================================================================== --- lld/trunk/ELF/LinkerScript.h +++ lld/trunk/ELF/LinkerScript.h @@ -54,8 +54,9 @@ }; struct SymbolAssignment : BaseCommand { - SymbolAssignment(StringRef Name, Expr E) - : BaseCommand(AssignmentKind), Name(Name), Expression(E) {} + SymbolAssignment(StringRef Name, Expr E, bool IsAbsolute) + : BaseCommand(AssignmentKind), Name(Name), Expression(E), + IsAbsolute(IsAbsolute) {} static bool classof(const BaseCommand *C); // The LHS of an expression. Name is either a symbol name or ".". @@ -68,6 +69,7 @@ // Command attributes for PROVIDE, HIDDEN and PROVIDE_HIDDEN. bool Provide = false; bool Hidden = false; + bool IsAbsolute; InputSectionData *GoesAfter = nullptr; }; Index: lld/trunk/ELF/LinkerScript.cpp =================================================================== --- lld/trunk/ELF/LinkerScript.cpp +++ lld/trunk/ELF/LinkerScript.cpp @@ -56,6 +56,12 @@ Cmd->Sym = Sym->body(); } +template static void addSymbol(SymbolAssignment *Cmd) { + if (Cmd->IsAbsolute) + addRegular(Cmd); + else + addSynthetic(Cmd); +} // If a symbol was in PROVIDE(), we need to define it only when // it is an undefined symbol. template static bool shouldDefine(SymbolAssignment *Cmd) { @@ -184,7 +190,7 @@ for (const std::unique_ptr &Base : OutCmd.Commands) { if (auto *OutCmd = dyn_cast(Base.get())) { if (shouldDefine(OutCmd)) - addSynthetic(OutCmd); + addSymbol(OutCmd); OutCmd->GoesAfter = Ret.empty() ? nullptr : Ret.back(); continue; } @@ -267,6 +273,26 @@ } } +// Sets value of a section-defined symbol. Two kinds of +// symbols are processed: synthetic symbols, whose value +// is an offset from beginning of section and regular +// symbols whose value is absolute. +template +static void assignSectionSymbol(SymbolAssignment *Cmd, + OutputSectionBase *Sec, + typename ELFT::uint Off) { + if (!Cmd->Sym) + return; + + if (auto *Body = dyn_cast>(Cmd->Sym)) { + Body->Section = Sec; + Body->Value = Cmd->Expression(Sec->getVA() + Off) - Sec->getVA(); + return; + } + auto *Body = cast>(Cmd->Sym); + Body->Value = Cmd->Expression(Sec->getVA() + Off); +} + // Linker script may define start and end symbols for special section types, // like .got, .eh_frame_hdr, .eh_frame and others. Those sections are not a list // of regular input input sections, therefore our way of defining symbols for @@ -280,12 +306,7 @@ for (std::unique_ptr &Base : Cmd->Commands) { if (auto *AssignCmd = dyn_cast(Base.get())) { - if (auto *Sym = cast_or_null>(AssignCmd->Sym)) { - Sym->Section = Sec; - Sym->Value = - AssignCmd->Expression(Sec->getVA() + (Start ? 0 : Sec->getSize())) - - Sec->getVA(); - } + assignSectionSymbol(AssignCmd, Sec, Start ? 0 : Sec->getSize()); } else { if (!Start && isa(PrevCmd)) error("section '" + Sec->getName() + @@ -322,19 +343,13 @@ if (D != AssignCmd->GoesAfter) break; - uintX_t Value = AssignCmd->Expression(Sec->getVA() + Off) - Sec->getVA(); if (AssignCmd->Name == ".") { // Update to location counter means update to section size. - Off = Value; + Off = AssignCmd->Expression(Sec->getVA() + Off) - Sec->getVA(); Sec->setSize(Off); continue; } - - if (DefinedSynthetic *Sym = - cast_or_null>(AssignCmd->Sym)) { - Sym->Section = OutSec; - Sym->Value = Value; - } + assignSectionSymbol(AssignCmd, Sec, Off); } }; @@ -631,7 +646,7 @@ unsigned readPhdrType(); SortKind readSortKind(); SymbolAssignment *readProvideHidden(bool Provide, bool Hidden); - SymbolAssignment *readProvideOrAssignment(StringRef Tok); + SymbolAssignment *readProvideOrAssignment(StringRef Tok, bool MakeAbsolute); void readSort(); Expr readAssert(); @@ -710,7 +725,7 @@ readSections(); } else if (Tok == "VERSION") { readVersion(); - } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok)) { + } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok, true)) { if (Opt.HasContents) Opt.Commands.emplace_back(Cmd); else @@ -872,7 +887,7 @@ expect("{"); while (!Error && !skip("}")) { StringRef Tok = next(); - BaseCommand *Cmd = readProvideOrAssignment(Tok); + BaseCommand *Cmd = readProvideOrAssignment(Tok, true); if (!Cmd) { if (Tok == "ASSERT") Cmd = new AssertCommand(readAssert()); @@ -1020,7 +1035,7 @@ while (!Error && !skip("}")) { StringRef Tok = next(); - if (SymbolAssignment *Assignment = readProvideOrAssignment(Tok)) + if (SymbolAssignment *Assignment = readProvideOrAssignment(Tok, false)) Cmd->Commands.emplace_back(Assignment); else if (Tok == "FILL") Cmd->Filler = readFill(); @@ -1063,7 +1078,8 @@ return Cmd; } -SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) { +SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok, + bool MakeAbsolute) { SymbolAssignment *Cmd = nullptr; if (peek() == "=" || peek() == "+=") { Cmd = readAssignment(Tok); @@ -1075,6 +1091,8 @@ } else if (Tok == "PROVIDE_HIDDEN") { Cmd = readProvideHidden(true, true); } + if (Cmd && MakeAbsolute) + Cmd->IsAbsolute = true; return Cmd; } @@ -1153,11 +1171,18 @@ SymbolAssignment *ScriptParser::readAssignment(StringRef Name) { StringRef Op = next(); + bool IsAbsolute = false; + Expr E; assert(Op == "=" || Op == "+="); - Expr E = readExpr(); + if (skip("ABSOLUTE")) { + E = readParenExpr(); + IsAbsolute = true; + } else { + E = readExpr(); + } if (Op == "+=") E = [=](uint64_t Dot) { return getSymbolValue(Name, Dot) + E(Dot); }; - return new SymbolAssignment(Name, E); + return new SymbolAssignment(Name, E, IsAbsolute); } // This is an operator-precedence parser to parse a linker Index: lld/trunk/test/ELF/linkerscript/symbols-synthetic.s =================================================================== --- lld/trunk/test/ELF/linkerscript/symbols-synthetic.s +++ lld/trunk/test/ELF/linkerscript/symbols-synthetic.s @@ -10,7 +10,9 @@ # RUN: *(.foo) \ # RUN: end_foo = .; \ # RUN: PROVIDE_HIDDEN(_end_sec = .); \ +# RUN: PROVIDE(_end_sec_abs = ABSOLUTE(.)); \ # RUN: size_foo_1 = SIZEOF(.foo); \ +# RUN: size_foo_1_abs = ABSOLUTE(SIZEOF(.foo)); \ # RUN: . = ALIGN(0x1000); \ # RUN: begin_bar = .; \ # RUN: *(.bar) \ @@ -19,10 +21,10 @@ # RUN: size_foo_3 = SIZEOF(.foo); \ # RUN: .eh_frame_hdr : { \ # RUN: __eh_frame_hdr_start = .; \ -# RUN: __eh_frame_hdr_start2 = ALIGN(0x10); \ +# RUN: __eh_frame_hdr_start2 = ABSOLUTE(ALIGN(0x10)); \ # RUN: *(.eh_frame_hdr) \ # RUN: __eh_frame_hdr_end = .; \ -# RUN: __eh_frame_hdr_end2 = ALIGN(0x10); } \ +# RUN: __eh_frame_hdr_end2 = ABSOLUTE(ALIGN(0x10)); } \ # RUN: }" > %t.script # RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t # RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=SIMPLE %s @@ -34,7 +36,7 @@ # RUN: PROVIDE_HIDDEN(_begin_sec = .); \ # RUN: __eh_frame_hdr_start = .; \ # RUN: *(.eh_frame_hdr) \ -# RUN: __eh_frame_hdr_end = .; \ +# RUN: PROVIDE_HIDDEN(_end_sec_abs = ABSOLUTE(.)); \ # RUN: *(.eh_frame_hdr) } \ # RUN: PROVIDE_HIDDEN(_end_sec = .); \ # RUN: }" > %t.script @@ -46,23 +48,26 @@ # RUN: PROVIDE_HIDDEN(_begin_sec = .); \ # RUN: *(.eh_frame_hdr) \ # RUN: *(.eh_frame_hdr) \ +# RUN: PROVIDE_HIDDEN(_end_sec_abs = ABSOLUTE(.)); \ # RUN: PROVIDE_HIDDEN(_end_sec = .); } \ # RUN: }" > %t.script # RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t # SIMPLE: 0000000000000160 .foo 00000000 .hidden _end_sec # SIMPLE: 0000000000000158 .foo 00000000 _begin_sec +# SIMPLE-NEXT: 0000000000000160 *ABS* 00000000 _end_sec_abs # SIMPLE-NEXT: 0000000000000158 .foo 00000000 begin_foo # SIMPLE-NEXT: 0000000000000160 .foo 00000000 end_foo # SIMPLE-NEXT: 0000000000000008 .foo 00000000 size_foo_1 +# SIMPLE-NEXT: 0000000000000008 *ABS* 00000000 size_foo_1_abs # SIMPLE-NEXT: 0000000000001000 .foo 00000000 begin_bar # SIMPLE-NEXT: 0000000000001004 .foo 00000000 end_bar # SIMPLE-NEXT: 0000000000000eac .foo 00000000 size_foo_2 # SIMPLE-NEXT: 0000000000000eac *ABS* 00000000 size_foo_3 # SIMPLE-NEXT: 0000000000001004 .eh_frame_hdr 00000000 __eh_frame_hdr_start -# SIMPLE-NEXT: 0000000000001010 .eh_frame_hdr 00000000 __eh_frame_hdr_start2 +# SIMPLE-NEXT: 0000000000001010 *ABS* 00000000 __eh_frame_hdr_start2 # SIMPLE-NEXT: 0000000000001018 .eh_frame_hdr 00000000 __eh_frame_hdr_end -# SIMPLE-NEXT: 0000000000001020 .eh_frame_hdr 00000000 __eh_frame_hdr_end2 +# SIMPLE-NEXT: 0000000000001020 *ABS* 00000000 __eh_frame_hdr_end2 # ERROR: section '.eh_frame_hdr' supports only start and end symbols .global _start @@ -80,4 +85,4 @@ nop .cfi_endproc -.global _begin_sec, _end_sec +.global _begin_sec, _end_sec, _end_sec_abs