Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -33,7 +33,19 @@ template class OutputSectionFactory; class InputSectionData; -typedef std::function Expr; +struct Expr { + typedef std::function ExprFn; + + Expr() {} + template Expr(F Fn) : Fn(Fn) {} + template Expr(F Fn, StringRef Sec) : Fn(Fn), Section(Sec) {} + uint64_t operator()(uint64_t V) const { return Fn(V); } + operator bool() const { return Fn != nullptr; } + + ExprFn Fn; + StringRef Section; +}; + // Parses a linker script. Calling this function updates // Config and ScriptConfig. @@ -232,6 +244,7 @@ std::vector *> createInputSectionList(OutputSectionCommand &Cmd); + void assignPendingSymbols(std::vector &Symbols); // "ScriptConfig" is a bit too long, so define a short name for it. ScriptConfiguration &Opt = *ScriptConfig; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -293,7 +293,7 @@ const std::unique_ptr &Base1 = *Iter; if (auto *Cmd = dyn_cast(Base1.get())) { if (shouldDefine(Cmd)) - addRegular(Cmd); + addSymbol(Cmd); continue; } if (auto *Cmd = dyn_cast(Base1.get())) { @@ -566,6 +566,23 @@ return Assign->Name != "."; } +// Assigns synthetic symbols defined outside of section definition. Such symbols +// when ADDR() builtin function is used, i.e: __rela_plt_start = ADDR(.rela.plt) +template +void LinkerScript::assignPendingSymbols( + std::vector &Symbols) { + for (SymbolAssignment *Cmd : Symbols) { + DefinedSynthetic *DS = cast>(Cmd->Sym); + auto Sections = findSections(Cmd->Expression.Section, *OutputSections); + DS->Section = Sections.empty() ? nullptr : Sections.front(); + if (!DS->Section) { + error("undefined section " + Cmd->Expression.Section); + continue; + } + DS->Value = Cmd->Expression(Dot) - DS->Section->getVA(); + } +} + template void LinkerScript::assignAddresses(std::vector> &Phdrs) { // Orphan sections are sections present in the input files which @@ -610,12 +627,18 @@ // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = 0; + // We process synthetic symbols later, so that they can be defined + // before a section they belong to. + std::vector PendingSymbols; + for (const std::unique_ptr &Base : Opt.Commands) { if (auto *Cmd = dyn_cast(Base.get())) { if (Cmd->Name == ".") { Dot = Cmd->Expression(Dot); + } else if (DefinedRegular *DR = dyn_cast_or_null>(Cmd->Sym)) { + DR->Value = Cmd->Expression(Dot); } else if (Cmd->Sym) { - cast>(Cmd->Sym)->Value = Cmd->Expression(Dot); + PendingSymbols.push_back(Cmd); } continue; } @@ -633,6 +656,8 @@ assignOffsets(Cmd); } + assignPendingSymbols(PendingSymbols); + uintX_t MinVA = std::numeric_limits::max(); for (OutputSectionBase *Sec : *OutputSections) { if (Sec->getFlags() & SHF_ALLOC) @@ -920,7 +945,7 @@ unsigned readPhdrType(); SortSectionPolicy readSortKind(); SymbolAssignment *readProvideHidden(bool Provide, bool Hidden); - SymbolAssignment *readProvideOrAssignment(StringRef Tok, bool MakeAbsolute); + SymbolAssignment *readProvideOrAssignment(StringRef Tok, bool OutsideSection); void readSort(); Expr readAssert(); @@ -1396,7 +1421,7 @@ } SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok, - bool MakeAbsolute) { + bool OutsideSection) { SymbolAssignment *Cmd = nullptr; if (peek() == "=" || peek() == "+=") { Cmd = readAssignment(Tok); @@ -1408,8 +1433,8 @@ } else if (Tok == "PROVIDE_HIDDEN") { Cmd = readProvideHidden(true, true); } - if (Cmd && MakeAbsolute) - Cmd->IsAbsolute = true; + if (Cmd && OutsideSection) + Cmd->IsAbsolute = Cmd->Expression.Section.empty(); return Cmd; } @@ -1453,9 +1478,10 @@ }; } if (Op == "+") - return [=](uint64_t Dot) { return L(Dot) + R(Dot); }; + return {[=](uint64_t Dot) { return L(Dot) + R(Dot); }, + L.Section.empty() ? R.Section : L.Section}; if (Op == "-") - return [=](uint64_t Dot) { return L(Dot) - R(Dot); }; + return {[=](uint64_t Dot) { return L(Dot) - R(Dot); }, L.Section}; if (Op == "<<") return [=](uint64_t Dot) { return L(Dot) << R(Dot); }; if (Op == ">>") @@ -1592,8 +1618,9 @@ // https://sourceware.org/binutils/docs/ld/Builtin-Functions.html. if (Tok == "ADDR") { StringRef Name = readParenLiteral(); - return - [=](uint64_t Dot) { return ScriptBase->getOutputSectionAddress(Name); }; + return { + [=](uint64_t Dot) { return ScriptBase->getOutputSectionAddress(Name); }, + Name}; } if (Tok == "LOADADDR") { StringRef Name = readParenLiteral(); Index: test/ELF/linkerscript/symbols-synthetic.s =================================================================== --- test/ELF/linkerscript/symbols-synthetic.s +++ test/ELF/linkerscript/symbols-synthetic.s @@ -42,6 +42,22 @@ # RUN: }" > %t.script # RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t +# Test absolute -> synthetic convertsion, when ADDR() is used. +# RUN: echo "a = ADDR(.text); \ +# RUN: b = 1 + ADDR(.text); \ +# RUN: c = ADDR(.text) - 1; \ +# RUN: d = 1 - ADDR(.text); \ +# RUN: e = 3 * ADDR(.text); \ +# RUN: SECTIONS { \ +# RUN: a1 = ADDR(.text); \ +# RUN: b1 = 1 + ADDR(.text); \ +# RUN: c1 = ADDR(.text) - 1; \ +# RUN: d1 = 1 - ADDR(.text); \ +# RUN: e1 = 3 * ADDR(.text); \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=CONVERT %s + # SIMPLE: 0000000000000128 .foo 00000000 .hidden _end_sec # SIMPLE-NEXT: 0000000000000120 .foo 00000000 _begin_sec # SIMPLE-NEXT: 0000000000000128 *ABS* 00000000 _end_sec_abs @@ -59,6 +75,17 @@ # SIMPLE-NEXT: 0000000000001018 .eh_frame_hdr 00000000 __eh_frame_hdr_end # SIMPLE-NEXT: 0000000000001020 *ABS* 00000000 __eh_frame_hdr_end2 +# CONVERT: 0000000000000000 .text 00000000 a +# CONVERT-NEXT: 0000000000000001 .text 00000000 b +# CONVERT-NEXT: 0000000000000001 .text 00000000 c +# CONVERT-NEXT: 0000000000000001 *ABS* 00000000 d +# CONVERT-NEXT: 0000000000000000 *ABS* 00000000 e +# CONVERT-NEXT: 0000000000000000 .text 00000000 a1 +# CONVERT-NEXT: 0000000000000001 .text 00000000 b1 +# CONVERT-NEXT: 0000000000000001 .text 00000000 c1 +# CONVERT-NEXT: 0000000000000001 *ABS* 00000000 d1 +# CONVERT-NEXT: 0000000000000000 *ABS* 00000000 e1 + .global _start _start: nop