summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/Writer.cpp117
-rw-r--r--lld/test/ELF/edata-etext.s2
-rw-r--r--lld/test/ELF/linkerscript/symbol-reserved.s6
3 files changed, 88 insertions, 37 deletions
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 0a316391c4f..68e14ce539d 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -54,6 +54,7 @@ private:
void sortSections();
void finalizeSections();
void addPredefinedSections();
+ void addPredefinedSymbols();
std::vector<PhdrEntry *> createPhdrs();
void removeEmptyPTLoad();
@@ -200,6 +201,12 @@ template <class ELFT> void Writer<ELFT>::run() {
parallelForEach(OutputSections,
[](OutputSection *Sec) { Sec->maybeCompress<ELFT>(); });
+ // Generate assignments for predefined symbols (e.g. _end or _etext)
+ // before assigning addresses. These symbols may be referred to from
+ // the linker script and we need to ensure they have the correct value
+ // prior evaluating any expressions using these symbols.
+ addPredefinedSymbols();
+
Script->assignAddresses();
Script->allocateHeaders(Phdrs);
@@ -920,6 +927,80 @@ template <class ELFT> void Writer<ELFT>::createSections() {
sortCtorsDtors(findSection(".dtors"));
}
+// This function generates assignments for predefined symbols (e.g. _end or
+// _etext) and inserts them into the commands sequence to be processed at the
+// appropriate time. This ensures that the value is going to be correct by the
+// time any references to these symbols are processed and is equivalent to
+// defining these symbols explicitly in the linker script.
+template <class ELFT> void Writer<ELFT>::addPredefinedSymbols() {
+ PhdrEntry *Last = nullptr;
+ PhdrEntry *LastRO = nullptr;
+ PhdrEntry *LastRW = nullptr;
+ for (PhdrEntry *P : Phdrs) {
+ if (P->p_type != PT_LOAD)
+ continue;
+ Last = P;
+ if (P->p_flags & PF_W)
+ LastRW = P;
+ else
+ LastRO = P;
+ }
+
+ auto Make = [](DefinedRegular *S) {
+ auto *Cmd = make<SymbolAssignment>(
+ S->getName(), [=] { return Script->getSymbolValue("", "."); }, "");
+ Cmd->Sym = S;
+ return Cmd;
+ };
+
+ auto IsSection = [](OutputSection *Sec) {
+ return [=](BaseCommand *Base) { return Base == Sec; };
+ };
+
+ auto IsNoBits = [](BaseCommand *Base) {
+ if (auto *Sec = dyn_cast<OutputSection>(Base))
+ return Sec->Type == SHT_NOBITS;
+ return false;
+ };
+
+ if (Last) {
+ // _end is the first location after the uninitialized data region.
+ auto E = Script->Opt.Commands.end();
+ auto I = Script->Opt.Commands.begin();
+ I = std::find_if(I, E, IsSection(Last->Last));
+ if (I != E) {
+ if (ElfSym::End1)
+ Script->Opt.Commands.insert(++I, Make(ElfSym::End1));
+ if (ElfSym::End2)
+ Script->Opt.Commands.insert(++I, Make(ElfSym::End2));
+ }
+ }
+ if (LastRO) {
+ // _etext is the first location after the last read-only loadable segment.
+ auto E = Script->Opt.Commands.end();
+ auto I = Script->Opt.Commands.begin();
+ I = std::find_if(I, E, IsSection(LastRO->Last));
+ if (I != E) {
+ if (ElfSym::Etext1)
+ Script->Opt.Commands.insert(++I, Make(ElfSym::Etext1));
+ if (ElfSym::Etext2)
+ Script->Opt.Commands.insert(++I, Make(ElfSym::Etext2));
+ }
+ }
+ if (LastRW) {
+ // _edata points to the end of the last non SHT_NOBITS section.
+ auto E = Script->Opt.Commands.end();
+ auto I = Script->Opt.Commands.begin();
+ I = std::find_if(std::find_if(I, E, IsSection(LastRW->First)), E, IsNoBits);
+ if (I != E) {
+ if (ElfSym::Edata2)
+ I = Script->Opt.Commands.insert(I, Make(ElfSym::Edata2));
+ if (ElfSym::Edata1)
+ I = Script->Opt.Commands.insert(I, Make(ElfSym::Edata1));
+ }
+ }
+}
+
// We want to find how similar two ranks are.
// The more branches in getSectionRank that match, the more similar they are.
// Since each branch corresponds to a bit flag, we can just use
@@ -1718,42 +1799,6 @@ static uint16_t getELFType() {
// to each section. This function fixes some predefined
// symbol values that depend on section address and size.
template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() {
- // _etext is the first location after the last read-only loadable segment.
- // _edata is the first location after the last read-write loadable segment.
- // _end is the first location after the uninitialized data region.
- PhdrEntry *Last = nullptr;
- PhdrEntry *LastRO = nullptr;
- PhdrEntry *LastRW = nullptr;
- for (PhdrEntry *P : Phdrs) {
- if (P->p_type != PT_LOAD)
- continue;
- Last = P;
- if (P->p_flags & PF_W)
- LastRW = P;
- else
- LastRO = P;
- }
-
- auto Set = [](DefinedRegular *S, OutputSection *Cmd, uint64_t Value) {
- if (S) {
- S->Section = Cmd;
- S->Value = Value;
- }
- };
-
- if (Last) {
- Set(ElfSym::End1, Last->First, Last->p_memsz);
- Set(ElfSym::End2, Last->First, Last->p_memsz);
- }
- if (LastRO) {
- Set(ElfSym::Etext1, LastRO->First, LastRO->p_filesz);
- Set(ElfSym::Etext2, LastRO->First, LastRO->p_filesz);
- }
- if (LastRW) {
- Set(ElfSym::Edata1, LastRW->First, LastRW->p_filesz);
- Set(ElfSym::Edata2, LastRW->First, LastRW->p_filesz);
- }
-
if (ElfSym::Bss)
ElfSym::Bss->Section = findSection(".bss");
diff --git a/lld/test/ELF/edata-etext.s b/lld/test/ELF/edata-etext.s
index 3b0ba49ad1a..2358399857d 100644
--- a/lld/test/ELF/edata-etext.s
+++ b/lld/test/ELF/edata-etext.s
@@ -19,7 +19,7 @@
# CHECK: SYMBOL TABLE:
# CHECK-NEXT: 0000000000000000 *UND* 00000000
# CHECK-NEXT: 0000000000202002 .data 00000000 _edata
-# CHECK-NEXT: 000000000020200a .data 00000000 _end
+# CHECK-NEXT: 000000000020200a .bss 00000000 _end
# CHECK-NEXT: 0000000000201001 .text 00000000 _etext
# CHECK-NEXT: 0000000000201000 .text 00000000 _start
diff --git a/lld/test/ELF/linkerscript/symbol-reserved.s b/lld/test/ELF/linkerscript/symbol-reserved.s
index 23f164e94d0..8ae9d0cd661 100644
--- a/lld/test/ELF/linkerscript/symbol-reserved.s
+++ b/lld/test/ELF/linkerscript/symbol-reserved.s
@@ -28,6 +28,12 @@
# ALIGN-SUB: 0000000000000006 *ABS* 00000000 .hidden newsym
# RUN: echo "PROVIDE_HIDDEN(newsym = ALIGN(_end, CONSTANT(MAXPAGESIZE)) + 5);" > %t.script
+# RUN: ld.lld -o %t1 %t %t.script
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=RELATIVE %s
+# RELATIVE: 0000000000202005 .text 00000000 .hidden newsym
+# RELATIVE: 0000000000201007 .text 00000000 _end
+
+# RUN: echo "PROVIDE_HIDDEN(newsym = ALIGN(_end, CONSTANT(MAXPAGESIZE)) + 5);" > %t.script
# RUN: ld.lld -o %t1 --script %p/Inputs/symbol-reserved.script %t %t.script
# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=RELATIVE-ADD %s
# RELATIVE-ADD: 0000000000001005 .text 00000000 .hidden newsym
OpenPOWER on IntegriCloud