[lld] r312305 - [ELF] Generate symbol assignments for predefined symbols

Petr Hosek via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 31 19:23:31 PDT 2017


Author: phosek
Date: Thu Aug 31 19:23:31 2017
New Revision: 312305

URL: http://llvm.org/viewvc/llvm-project?rev=312305&view=rev
Log:
[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

Modified:
    lld/trunk/ELF/Writer.cpp
    lld/trunk/test/ELF/edata-etext.s
    lld/trunk/test/ELF/linkerscript/symbol-reserved.s

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=312305&r1=312304&r2=312305&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Thu Aug 31 19:23:31 2017
@@ -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>:
   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>:
   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");
 

Modified: lld/trunk/test/ELF/edata-etext.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/edata-etext.s?rev=312305&r1=312304&r2=312305&view=diff
==============================================================================
--- lld/trunk/test/ELF/edata-etext.s (original)
+++ lld/trunk/test/ELF/edata-etext.s Thu Aug 31 19:23:31 2017
@@ -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
 

Modified: lld/trunk/test/ELF/linkerscript/symbol-reserved.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/symbol-reserved.s?rev=312305&r1=312304&r2=312305&view=diff
==============================================================================
--- lld/trunk/test/ELF/linkerscript/symbol-reserved.s (original)
+++ lld/trunk/test/ELF/linkerscript/symbol-reserved.s Thu Aug 31 19:23:31 2017
@@ -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




More information about the llvm-commits mailing list