[PATCH] D95198: [ELF] Fix program header alloc when first PT_LOAD is not at lowest VMA

Patrick Oppenlander via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 21 19:03:03 PST 2021


pattop created this revision.
Herald added subscribers: arichardson, emaste.
Herald added a reviewer: MaskRay.
pattop requested review of this revision.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Program headers must be allocated in the first PT_LOAD segment, however
this is not necessarily at the lowest VMA in the program image.

Previously lld would find the lowest VMA in all allocated sections and
allocate the program headers below that.

This patch changes to searching the first PT_LOAD segment first and
falls back to the old behaviour if that fails.

The new offset-headers.s test case previously failed with:

ld.lld: error: could not allocate headers


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D95198

Files:
  lld/ELF/LinkerScript.cpp
  lld/test/ELF/linkerscript/offset-headers.s


Index: lld/test/ELF/linkerscript/offset-headers.s
===================================================================
--- /dev/null
+++ lld/test/ELF/linkerscript/offset-headers.s
@@ -0,0 +1,53 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "PHDRS { \
+# RUN:           ph1 PT_LOAD FILEHDR PHDRS; \
+# RUN:           ph2 PT_LOAD; } \
+# RUN:       MEMORY { \
+# RUN:           mem1 : ORIGIN = 0x1000000000000000, LENGTH = 64K \
+# RUN:           mem2 : ORIGIN = 0, LENGTH = 128K } \
+# RUN:       SECTIONS { \
+# RUN:           .data : {*(.data*)} >mem2 :ph2 \
+# RUN:           .text ORIGIN(mem1) + SIZEOF_HEADERS : {*(.text*)} >mem1 :ph1 }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -l %t1 | FileCheck %s
+
+# CHECK:     ProgramHeaders [
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_LOAD (0x1)
+# CHECK-NEXT:    Offset: 0x0
+# CHECK-NEXT:    VirtualAddress: 0x1000000000000000
+# CHECK-NEXT:    PhysicalAddress: 0x1000000000000000
+# CHECK-NEXT:    FileSize: 8368
+# CHECK-NEXT:    MemSize: 8368
+# CHECK-NEXT:    Flags [ (0x5)
+# CHECK-NEXT:      PF_R (0x4)
+# CHECK-NEXT:      PF_X (0x1)
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 4096
+# CHECK-NEXT:  }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_LOAD (0x1)
+# CHECK-NEXT:    Offset: 0x3000
+# CHECK-NEXT:    VirtualAddress: 0x0
+# CHECK-NEXT:    PhysicalAddress: 0x0
+# CHECK-NEXT:    FileSize: 32768
+# CHECK-NEXT:    MemSize: 32768
+# CHECK-NEXT:    Flags [ (0x6)
+# CHECK-NEXT:      PF_R (0x4)
+# CHECK-NEXT:      PF_W (0x2)
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 4096
+# CHECK-NEXT:  }
+# CHECK-NEXT: ]
+
+.global _start
+_start:
+ .rept 0x2000
+ nop
+ .endr
+
+.data
+ .rept 0x2000
+ .long 0
+ .endr
Index: lld/ELF/LinkerScript.cpp
===================================================================
--- lld/ELF/LinkerScript.cpp
+++ lld/ELF/LinkerScript.cpp
@@ -1148,17 +1148,25 @@
 // 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)
-    if (sec->flags & SHF_ALLOC)
-      min = std::min<uint64_t>(min, sec->addr);
-
   auto it = llvm::find_if(
       phdrs, [](const PhdrEntry *e) { return e->p_type == PT_LOAD; });
   if (it == phdrs.end())
     return;
   PhdrEntry *firstPTLoad = *it;
 
+  uint64_t min = std::numeric_limits<uint64_t>::max();
+
+  // Try to find first section address in first PT_LOAD segment
+  for (OutputSection *sec : outputSections)
+    if (sec->ptLoad == firstPTLoad)
+      min = std::min<uint64_t>(min, sec->addr);
+
+  // If not found, use first allocated section address
+  if (min == std::numeric_limits<uint64_t>::max())
+    for (OutputSection *sec : outputSections)
+      if (sec->flags & SHF_ALLOC)
+        min = std::min<uint64_t>(min, sec->addr);
+
   bool hasExplicitHeaders =
       llvm::any_of(phdrsCommands, [](const PhdrsCommand &cmd) {
         return cmd.hasPhdrs || cmd.hasFilehdr;


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D95198.318393.patch
Type: text/x-patch
Size: 3175 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20210122/24d0f65f/attachment.bin>


More information about the llvm-commits mailing list