Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 29 Jan 2020 16:57:56 +0000 (UTC)
From:      Dimitry Andric <dim@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r357259 - projects/clang1000-import/contrib/llvm-project/lld/ELF
Message-ID:  <202001291657.00TGvuPe029761@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: dim
Date: Wed Jan 29 16:57:55 2020
New Revision: 357259
URL: https://svnweb.freebsd.org/changeset/base/357259

Log:
  Revert upstream lld r371957 (git commit 06bb7dfbd) by Fangrui Song:
  
    [ELF] Map the ELF header at imageBase
  
    If there is no readonly section, we map:
  
    * The ELF header at imageBase+maxPageSize
    * Program headers at imageBase+maxPageSize+sizeof(Ehdr)
    * The first section .text at imageBase+maxPageSize+sizeof(Ehdr)+sizeof(program headers)
  
    Due to the interaction between Writer<ELFT>::fixSectionAlignments and
    LinkerScript::allocateHeaders,
    `alignDown(p_vaddr(R PT_LOAD)) = alignDown(p_vaddr(RX PT_LOAD))`.
    The RX PT_LOAD will override the R PT_LOAD at runtime, which is not ideal:
  
    ```
    // PHDR at 0x401034, should be 0x400034
      PHDR           0x000034 0x00401034 0x00401034 0x000a0 0x000a0 R   0x4
    // R PT_LOAD contains just Ehdr and program headers.
    // At 0x401000, should be 0x400000
      LOAD           0x000000 0x00401000 0x00401000 0x000d4 0x000d4 R   0x1000
      LOAD           0x0000d4 0x004010d4 0x004010d4 0x00001 0x00001 R E 0x1000
    ```
  
    * createPhdrs allocates the headers to the R PT_LOAD.
    * fixSectionAlignments assigns `imageBase+maxPageSize+sizeof(Ehdr)+sizeof(program headers)` (formula: `alignTo(dot, maxPageSize) + dot % config->maxPageSize`) to addrExpr of .text
    * allocateHeaders computes the minimum address among SHF_ALLOC sections, i.e. addr(.text)
    * allocateHeaders sets address of ELF header to `addr(.text)-sizeof(Ehdr)-sizeof(program headers) = imageBase+maxPageSize`
  
    The main observation is that when the SECTIONS command is not used, we
    don't have to call allocateHeaders. This requires an assumption that
    the presence of PT_PHDR and addresses of headers can be decided
    regardless of address information.
  
    This may seem natural because dot is not manipulated by a linker script.
    The other thing is that we have to drop the special rule for -T<section>
    in `getInitialDot`. If -Ttext is smaller than the image base, the headers
    will not be allocated with the old behavior (allocateHeaders is called)
    but always allocated with the new behavior.
  
    The behavior change is not a problem. Whether and where headers are
    allocated can vary among linkers, or ld.bfd across different versions
    (--enable-separate-code or not). It is thus advised to use a linker
    script with the PHDRS command to have a consistent behavior across
    linkers. If PT_PHDR is needed, an explicit --image-base can be a simpler
    alternative.
  
    Differential Revision: https://reviews.llvm.org/D67325
  
    llvm-svn: 371957
  
  This causes "ld: error: output file too large: 18446744073707016908
  bytes" when linking our loader_4th and loader_lua.  Clearly, something
  is wrong when using -Ttext 0x0: I will file an upstream bug report for
  this.

Modified:
  projects/clang1000-import/contrib/llvm-project/lld/ELF/LinkerScript.cpp
  projects/clang1000-import/contrib/llvm-project/lld/ELF/Writer.cpp

Modified: projects/clang1000-import/contrib/llvm-project/lld/ELF/LinkerScript.cpp
==============================================================================
--- projects/clang1000-import/contrib/llvm-project/lld/ELF/LinkerScript.cpp	Wed Jan 29 16:52:12 2020	(r357258)
+++ projects/clang1000-import/contrib/llvm-project/lld/ELF/LinkerScript.cpp	Wed Jan 29 16:57:55 2020	(r357259)
@@ -1020,13 +1020,17 @@ static uint64_t computeBase(uint64_t min, bool allocat
   return alignDown(min, config->maxPageSize);
 }
 
-// When the SECTIONS command is used, try to find an address for the file and
-// program headers output sections, which can be added to the first PT_LOAD
-// segment when program headers are created.
+// Try to find an address for the file and program headers output sections,
+// which were unconditionally added to the first PT_LOAD segment earlier.
 //
-// We check if the headers fit below the first allocated section. If there isn't
-// enough space for these sections, we'll remove them from the PT_LOAD segment,
-// and we'll also remove the PT_PHDR segment.
+// When using the default layout, we check if the headers fit below the first
+// allocated section. When using a linker script, we also check if the headers
+// are covered by the output section. This allows omitting the headers by not
+// leaving enough space for them in the linker script; this pattern is common
+// in embedded systems.
+//
+// If there isn't enough space for these sections, we'll remove them from the
+// PT_LOAD segment, and we'll also remove the PT_PHDR segment.
 void LinkerScript::allocateHeaders(std::vector<PhdrEntry *> &phdrs) {
   uint64_t min = std::numeric_limits<uint64_t>::max();
   for (OutputSection *sec : outputSections)
@@ -1072,23 +1076,28 @@ LinkerScript::AddressState::AddressState() {
   }
 }
 
+static uint64_t getInitialDot() {
+  // By default linker scripts use an initial value of 0 for '.',
+  // but prefer -image-base if set.
+  if (script->hasSectionsCommand)
+    return config->imageBase ? *config->imageBase : 0;
+
+  uint64_t startAddr = UINT64_MAX;
+  // The sections with -T<section> have been sorted in order of ascending
+  // address. We must lower startAddr if the lowest -T<section address> as
+  // calls to setDot() must be monotonically increasing.
+  for (auto &kv : config->sectionStartMap)
+    startAddr = std::min(startAddr, kv.second);
+  return std::min(startAddr, target->getImageBase() + elf::getHeaderSize());
+}
+
 // Here we assign addresses as instructed by linker script SECTIONS
 // sub-commands. Doing that allows us to use final VA values, so here
 // we also handle rest commands like symbol assignments and ASSERTs.
 // Returns a symbol that has changed its section or value, or nullptr if no
 // symbol has changed.
 const Defined *LinkerScript::assignAddresses() {
-  if (script->hasSectionsCommand) {
-    // With a linker script, assignment of addresses to headers is covered by
-    // allocateHeaders().
-    dot = config->imageBase.getValueOr(0);
-  } else {
-    // Assign addresses to headers right now.
-    dot = target->getImageBase();
-    Out::elfHeader->addr = dot;
-    Out::programHeaders->addr = dot + Out::elfHeader->size;
-    dot += getHeaderSize();
-  }
+  dot = getInitialDot();
 
   auto deleter = std::make_unique<AddressState>();
   ctx = deleter.get();

Modified: projects/clang1000-import/contrib/llvm-project/lld/ELF/Writer.cpp
==============================================================================
--- projects/clang1000-import/contrib/llvm-project/lld/ELF/Writer.cpp	Wed Jan 29 16:52:12 2020	(r357258)
+++ projects/clang1000-import/contrib/llvm-project/lld/ELF/Writer.cpp	Wed Jan 29 16:57:55 2020	(r357259)
@@ -569,8 +569,7 @@ template <class ELFT> void Writer<ELFT>::run() {
   for (OutputSection *sec : outputSections)
     sec->maybeCompress<ELFT>();
 
-  if (script->hasSectionsCommand)
-    script->allocateHeaders(mainPart->phdrs);
+  script->allocateHeaders(mainPart->phdrs);
 
   // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
   // 0 sized region. This has to be done late since only after assignAddresses



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202001291657.00TGvuPe029761>