summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Hosek <phosek@chromium.org>2017-09-01 02:23:31 +0000
committerPetr Hosek <phosek@chromium.org>2017-09-01 02:23:31 +0000
commit18821b60b0847f97f16d915c66b34b0aed66efc7 (patch)
tree19796b163db7559b3fa39e46879d00dc84a1f88a
parent04567fd4806ef359bf537463012427b69912e944 (diff)
downloadbcm5719-llvm-18821b60b0847f97f16d915c66b34b0aed66efc7.tar.gz
bcm5719-llvm-18821b60b0847f97f16d915c66b34b0aed66efc7.zip
[ELF] Generate symbol assignments for predefined symbols
The problem with symbol assignments in implicit linker scripts is that they can refer synthetic symbols such as _end, _etext or _edata. The value of these symbols is currently fixed only after all linker script commands are processed, so these assignments will be using non-final and hence invalid value. Rather than fixing the symbol values after all command processing have finished, we instead change the logic to generate symbol assignment commands that set the value of these symbols while processing the commands, this ensures that the value is going to be correct by the time any reference to these symbol is processed and is equivalent to defining these symbols explicitly in linker script as BFD ld does. Differential Revision: https://reviews.llvm.org/D36986 llvm-svn: 312305
-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