}
template <class ELFT> static void addSynthetic(SymbolAssignment *Cmd) {
+ // If we have SECTIONS block then output sections haven't been created yet.
+ const OutputSectionBase *Sec =
+ ScriptConfig->HasSections ? nullptr : Cmd->Expression.Section();
Symbol *Sym = Symtab<ELFT>::X->addSynthetic(
- Cmd->Name, nullptr, 0, Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT);
+ Cmd->Name, Sec, 0, Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT);
Cmd->Sym = Sym->body();
+
+ // If we already know section then we can calculate symbol value immediately.
+ if (Sec)
+ cast<DefinedSynthetic<ELFT>>(Cmd->Sym)->Value =
+ Cmd->Expression(0) - Sec->Addr;
}
template <class ELFT> static void addSymbol(SymbolAssignment *Cmd) {
// is an offset from beginning of section and regular
// symbols whose value is absolute.
template <class ELFT>
-static void assignSectionSymbol(SymbolAssignment *Cmd, OutputSectionBase *Sec,
+static void assignSectionSymbol(SymbolAssignment *Cmd,
typename ELFT::uint Value) {
if (!Cmd->Sym)
return;
if (auto *Body = dyn_cast<DefinedSynthetic<ELFT>>(Cmd->Sym)) {
- Body->Section = Sec;
- Body->Value = Cmd->Expression(Value) - Sec->Addr;
+ Body->Section = Cmd->Expression.Section();
+ Body->Value = Cmd->Expression(Value) - Body->Section->Addr;
return;
}
auto *Body = cast<DefinedRegular<ELFT>>(Cmd->Sym);
CurOutSec->Size = Dot - CurOutSec->Addr;
return;
}
- assignSectionSymbol<ELFT>(AssignCmd, CurOutSec, Dot);
+ assignSectionSymbol<ELFT>(AssignCmd, Dot);
return;
}
if (Cmd->Name == ".") {
Dot = Cmd->Expression(Dot);
} else if (Cmd->Sym) {
- assignSectionSymbol<ELFT>(
- Cmd, CurOutSec ? CurOutSec : (*OutputSections)[0], Dot);
+ assignSectionSymbol<ELFT>(Cmd, Dot);
}
continue;
}
}
template <class ELFT>
-uint64_t LinkerScript<ELFT>::getOutputSectionAddress(StringRef Name) {
- for (OutputSectionBase *Sec : *OutputSections)
- if (Sec->getName() == Name)
- return Sec->Addr;
- error("undefined section " + Name);
- return 0;
-}
-
-template <class ELFT>
-uint64_t LinkerScript<ELFT>::getOutputSectionLMA(StringRef Name) {
- for (OutputSectionBase *Sec : *OutputSections)
- if (Sec->getName() == Name)
- return Sec->getLMA();
- error("undefined section " + Name);
- return 0;
-}
-
-template <class ELFT>
-uint64_t LinkerScript<ELFT>::getOutputSectionSize(StringRef Name) {
- for (OutputSectionBase *Sec : *OutputSections)
- if (Sec->getName() == Name)
- return Sec->Size;
- error("undefined section " + Name);
- return 0;
-}
+const OutputSectionBase *LinkerScript<ELFT>::getOutputSection(StringRef Name) {
+ static OutputSectionBase FakeSec("", 0, 0);
-template <class ELFT>
-uint64_t LinkerScript<ELFT>::getOutputSectionAlign(StringRef Name) {
for (OutputSectionBase *Sec : *OutputSections)
if (Sec->getName() == Name)
- return Sec->Addralign;
+ return Sec;
error("undefined section " + Name);
- return 0;
+ return &FakeSec;
}
template <class ELFT> uint64_t LinkerScript<ELFT>::getHeaderSize() {
return DR && !DR->Section;
}
+// Gets section symbol belongs to. Symbol "." doesn't belong to any
+// specific section but isn't absolute at the same time, so we try
+// to find suitable section for it as well.
+template <class ELFT>
+const OutputSectionBase *LinkerScript<ELFT>::getSymbolSection(StringRef S) {
+ SymbolBody *Sym = Symtab<ELFT>::X->find(S);
+ if (!Sym) {
+ if (OutputSections->empty())
+ return nullptr;
+ return CurOutSec ? CurOutSec : (*OutputSections)[0];
+ }
+
+ if (auto *DR = dyn_cast_or_null<DefinedRegular<ELFT>>(Sym))
+ return DR->Section ? DR->Section->OutSec : nullptr;
+ if (auto *DS = dyn_cast_or_null<DefinedSynthetic<ELFT>>(Sym))
+ return DS->Section;
+
+ return nullptr;
+}
+
// Returns indices of ELF headers containing specific section, identified
// by Name. Each index is a zero based number of ELF header listed within
// PHDRS {} script block.
}
if (Op == "+")
return {[=](uint64_t Dot) { return L(Dot) + R(Dot); },
- [=]() { return L.IsAbsolute() && R.IsAbsolute(); }};
+ [=]() { return L.IsAbsolute() && R.IsAbsolute(); },
+ [=]() {
+ const OutputSectionBase *S = L.Section();
+ return S ? S : R.Section();
+ }};
if (Op == "-")
return [=](uint64_t Dot) { return L(Dot) - R(Dot); };
if (Op == "<<")
// 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->getOutputSection(Name)->Addr; },
+ [=]() { return false; },
+ [=]() { return ScriptBase->getOutputSection(Name); }};
}
if (Tok == "LOADADDR") {
StringRef Name = readParenLiteral();
- return [=](uint64_t Dot) { return ScriptBase->getOutputSectionLMA(Name); };
+ return [=](uint64_t Dot) {
+ return ScriptBase->getOutputSection(Name)->getLMA();
+ };
}
if (Tok == "ASSERT")
return readAssert();
}
if (Tok == "SIZEOF") {
StringRef Name = readParenLiteral();
- return [=](uint64_t Dot) { return ScriptBase->getOutputSectionSize(Name); };
+ return
+ [=](uint64_t Dot) { return ScriptBase->getOutputSection(Name)->Size; };
}
if (Tok == "ALIGNOF") {
StringRef Name = readParenLiteral();
- return
- [=](uint64_t Dot) { return ScriptBase->getOutputSectionAlign(Name); };
+ return [=](uint64_t Dot) {
+ return ScriptBase->getOutputSection(Name)->Addralign;
+ };
}
if (Tok == "SIZEOF_HEADERS")
return [=](uint64_t Dot) { return ScriptBase->getHeaderSize(); };
if (Tok != "." && !isValidCIdentifier(Tok))
setError("malformed number: " + Tok);
return {[=](uint64_t Dot) { return getSymbolValue(Tok, Dot); },
- [=]() { return isAbsolute(Tok); }};
+ [=]() { return isAbsolute(Tok); },
+ [=]() { return ScriptBase->getSymbolSection(Tok); }};
}
Expr ScriptParser::readTernary(Expr Cond) {
struct Expr {
std::function<uint64_t(uint64_t)> Val;
std::function<bool()> IsAbsolute;
+
+ // If expression is section-relative the function below is used
+ // to get the output section pointer.
+ std::function<const OutputSectionBase *()> Section;
+
uint64_t operator()(uint64_t Dot) const { return Val(Dot); }
operator bool() const { return (bool)Val; }
- Expr(std::function<uint64_t(uint64_t)> Val, std::function<bool()> IsAbsolute)
- : Val(Val), IsAbsolute(IsAbsolute) {}
- template <typename T> Expr(T V) : Expr(V, []() { return true; }) {}
+ Expr(std::function<uint64_t(uint64_t)> Val, std::function<bool()> IsAbsolute,
+ std::function<const OutputSectionBase *()> Section)
+ : Val(Val), IsAbsolute(IsAbsolute), Section(Section) {}
+ template <typename T>
+ Expr(T V) : Expr(V, []() { return true; }, []() { return nullptr; }) {}
Expr() : Expr(nullptr) {}
};
~LinkerScriptBase() = default;
public:
- virtual uint64_t getOutputSectionAddress(StringRef Name) = 0;
- virtual uint64_t getOutputSectionSize(StringRef Name) = 0;
- virtual uint64_t getOutputSectionAlign(StringRef Name) = 0;
- virtual uint64_t getOutputSectionLMA(StringRef Name) = 0;
virtual uint64_t getHeaderSize() = 0;
virtual uint64_t getSymbolValue(StringRef S) = 0;
virtual bool isDefined(StringRef S) = 0;
virtual bool isAbsolute(StringRef S) = 0;
+ virtual const OutputSectionBase *getSymbolSection(StringRef S) = 0;
+ virtual const OutputSectionBase *getOutputSection(StringRef S) = 0;
};
// ScriptConfiguration holds linker script parse results.
void placeOrphanSections();
void assignAddresses(std::vector<PhdrEntry<ELFT>> &Phdrs);
bool hasPhdrsCommands();
- uint64_t getOutputSectionAddress(StringRef Name) override;
- uint64_t getOutputSectionSize(StringRef Name) override;
- uint64_t getOutputSectionAlign(StringRef Name) override;
- uint64_t getOutputSectionLMA(StringRef Name) override;
uint64_t getHeaderSize() override;
uint64_t getSymbolValue(StringRef S) override;
bool isDefined(StringRef S) override;
bool isAbsolute(StringRef S) override;
+ const OutputSectionBase *getSymbolSection(StringRef S) override;
+ const OutputSectionBase *getOutputSection(StringRef S) override;
std::vector<OutputSectionBase *> *OutputSections;
# RUN: }" > %t.script
# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
+# Check that we can specify synthetic symbols without defining SECTIONS.
+# RUN: echo "PROVIDE_HIDDEN(_begin_sec = _start); \
+# RUN: PROVIDE_HIDDEN(_end_sec = ADDR(.text) + SIZEOF(.text));" > %t.script
+# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=NO-SEC %s
+
+# Check that we can do the same as above inside SECTIONS block.
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x11000; \
+# RUN: .text : { *(.text) } \
+# RUN: PROVIDE_HIDDEN(_begin_sec = ADDR(.text)); \
+# RUN: PROVIDE_HIDDEN(_end_sec = ADDR(.text) + SIZEOF(.text)); }" > %t.script
+# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=IN-SEC %s
+
# SIMPLE: 0000000000000128 .foo 00000000 .hidden _end_sec
# SIMPLE-NEXT: 0000000000000120 .foo 00000000 _begin_sec
# SIMPLE-NEXT: 0000000000000128 *ABS* 00000000 _end_sec_abs
# SIMPLE-NEXT: 0000000000001018 .eh_frame_hdr 00000000 __eh_frame_hdr_end
# SIMPLE-NEXT: 0000000000001020 *ABS* 00000000 __eh_frame_hdr_end2
+# NO-SEC: 0000000000011000 .text 00000000 .hidden _begin_sec
+# NO-SEC-NEXT: 0000000000011001 .text 00000000 .hidden _end_sec
+
+# IN-SEC: 0000000000011000 .text 00000000 .hidden _begin_sec
+# IN-SEC-NEXT: 0000000000011001 .text 00000000 .hidden _end_sec
+
.global _start
_start:
nop