[lld] r311586 - [ELF] Don't output headers into a segment if there's no space for them

Petr Hosek via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 23 11:44:34 PDT 2017


Author: phosek
Date: Wed Aug 23 11:44:34 2017
New Revision: 311586

URL: http://llvm.org/viewvc/llvm-project?rev=311586&view=rev
Log:
[ELF] Don't output headers into a segment if there's no space for them

Currently, LLD checks whether there's enough space for headers by
checking if headers fit below the address of the first allocated
section. However, that's always thue if the binary doesn't start
at zero which means that LLD always emits a segment for headers,
even if no other sections belong to that segment.

This is a problem in cases when linker script is being used with a
non-zero start address when we don't want to make the headers visible
by not leaving enough space for them. This pattern is common in
embedded programming but doesn't work in LLD.

This patch changes the behavior of LLD in case when linker script
is being to match the behavior of BFD ld and gold, which is to only
place headers into a segment when they're covered by some output
section.

Differential Revision: https://reviews.llvm.org/D36256

Added:
    lld/trunk/test/ELF/linkerscript/segment-headers.s
Modified:
    lld/trunk/ELF/LinkerScript.cpp
    lld/trunk/test/ELF/linkerscript/at-addr.s
    lld/trunk/test/ELF/linkerscript/at.s
    lld/trunk/test/ELF/linkerscript/header-addr.s
    lld/trunk/test/ELF/linkerscript/phdr-check.s

Modified: lld/trunk/ELF/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=311586&r1=311585&r2=311586&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.cpp (original)
+++ lld/trunk/ELF/LinkerScript.cpp Wed Aug 23 11:44:34 2017
@@ -723,6 +723,17 @@ void LinkerScript::adjustSectionsAfterSo
   removeEmptyCommands();
 }
 
+// Try to find an address for the file and program headers output sections,
+// which were unconditionally added to the first PT_LOAD segment earlier.
+//
+// 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)
@@ -736,14 +747,17 @@ void LinkerScript::allocateHeaders(std::
   PhdrEntry *FirstPTLoad = *It;
 
   uint64_t HeaderSize = getHeaderSize();
-  if (HeaderSize <= Min || Script->hasPhdrsCommands()) {
-    Min = alignDown(Min - HeaderSize, Config->MaxPageSize);
+  // When linker script with SECTIONS is being used, don't output headers
+  // unless there's a space for them.
+  uint64_t Base = Opt.HasSections ? alignDown(Min, Config->MaxPageSize) : 0;
+  if (HeaderSize <= Min - Base || Script->hasPhdrsCommands()) {
+    Min = Opt.HasSections ? Base
+                          : alignDown(Min - HeaderSize, Config->MaxPageSize);
     Out::ElfHeader->Addr = Min;
     Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size;
     return;
   }
 
-  assert(FirstPTLoad->First == Out::ElfHeader);
   OutputSection *ActualFirst = nullptr;
   for (OutputSection *Sec : OutputSections) {
     if (Sec->FirstInPtLoad == Out::ElfHeader) {

Modified: lld/trunk/test/ELF/linkerscript/at-addr.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/at-addr.s?rev=311586&r1=311585&r2=311586&view=diff
==============================================================================
--- lld/trunk/test/ELF/linkerscript/at-addr.s (original)
+++ lld/trunk/test/ELF/linkerscript/at-addr.s Wed Aug 23 11:44:34 2017
@@ -9,10 +9,6 @@
 # RUN: llvm-readobj -program-headers %t2 | FileCheck %s
 
 # CHECK:      Type: PT_LOAD
-# CHECK-NEXT:   Offset: 0x0
-# CHECK-NEXT:   VirtualAddress: 0x0
-# CHECK-NEXT:   PhysicalAddress: 0x0
-# CHECK:      Type: PT_LOAD
 # CHECK-NEXT:   Offset: 0x1000
 # CHECK-NEXT:   VirtualAddress: 0x1000
 # CHECK-NEXT:   PhysicalAddress: 0xB00

Modified: lld/trunk/test/ELF/linkerscript/at.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/at.s?rev=311586&r1=311585&r2=311586&view=diff
==============================================================================
--- lld/trunk/test/ELF/linkerscript/at.s (original)
+++ lld/trunk/test/ELF/linkerscript/at.s Wed Aug 23 11:44:34 2017
@@ -13,31 +13,6 @@
 
 # CHECK:      ProgramHeaders [
 # CHECK-NEXT:   ProgramHeader {
-# CHECK-NEXT:     Type: PT_PHDR
-# CHECK-NEXT:     Offset: 0x40
-# CHECK-NEXT:     VirtualAddress: 0x40
-# CHECK-NEXT:     PhysicalAddress: 0x40
-# CHECK-NEXT:     FileSize:
-# CHECK-NEXT:     MemSize:
-# CHECK-NEXT:     Flags [
-# CHECK-NEXT:       PF_R
-# CHECK-NEXT:     ]
-# CHECK-NEXT:     Alignment: 8
-# CHECK-NEXT:   }
-# CHECK-NEXT:   ProgramHeader {
-# CHECK-NEXT:     Type: PT_LOAD
-# CHECK-NEXT:     Offset: 0x0
-# CHECK-NEXT:     VirtualAddress: 0x0
-# CHECK-NEXT:     PhysicalAddress: 0x0
-# CHECK-NEXT:     FileSize:
-# CHECK-NEXT:     MemSize:
-# CHECK-NEXT:     Flags [
-# CHECK-NEXT:       PF_R
-# CHECK-NEXT:       PF_X
-# CHECK-NEXT:     ]
-# CHECK-NEXT:     Alignment:
-# CHECK-NEXT:   }
-# CHECK-NEXT:   ProgramHeader {
 # CHECK-NEXT:     Type: PT_LOAD
 # CHECK-NEXT:     Offset: 0x1000
 # CHECK-NEXT:     VirtualAddress: 0x1000

Modified: lld/trunk/test/ELF/linkerscript/header-addr.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/header-addr.s?rev=311586&r1=311585&r2=311586&view=diff
==============================================================================
--- lld/trunk/test/ELF/linkerscript/header-addr.s (original)
+++ lld/trunk/test/ELF/linkerscript/header-addr.s Wed Aug 23 11:44:34 2017
@@ -2,7 +2,7 @@
 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
 # RUN: echo "PHDRS {all PT_LOAD PHDRS;} \
 # RUN:       SECTIONS { \
-# RUN:       . = 0x2000; \
+# RUN:       . = 0x2000 + SIZEOF_HEADERS; \
 # RUN:       .text : {*(.text)} :all \
 # RUN:     }" > %t.script
 # RUN: ld.lld -o %t.so --script %t.script %t.o -shared
@@ -12,10 +12,10 @@
 # CHECK-NEXT:   ProgramHeader {
 # CHECK-NEXT:     Type: PT_LOAD
 # CHECK-NEXT:     Offset: 0x40
-# CHECK-NEXT:     VirtualAddress: 0x1040
-# CHECK-NEXT:     PhysicalAddress: 0x1040
-# CHECK-NEXT:     FileSize: 4176
-# CHECK-NEXT:     MemSize: 4176
+# CHECK-NEXT:     VirtualAddress: 0x2040
+# CHECK-NEXT:     PhysicalAddress: 0x2040
+# CHECK-NEXT:     FileSize: 200
+# CHECK-NEXT:     MemSize: 200
 # CHECK-NEXT:     Flags [
 # CHECK-NEXT:       PF_R (0x4)
 # CHECK-NEXT:       PF_W (0x2)
@@ -33,10 +33,10 @@
 # MAXPAGE-NEXT:   ProgramHeader {
 # MAXPAGE-NEXT:     Type: PT_LOAD
 # MAXPAGE-NEXT:     Offset: 0x40
-# MAXPAGE-NEXT:     VirtualAddress: 0x40
-# MAXPAGE-NEXT:     PhysicalAddress: 0x40
-# MAXPAGE-NEXT:     FileSize: 8272
-# MAXPAGE-NEXT:     MemSize: 8272
+# MAXPAGE-NEXT:     VirtualAddress: 0x2040
+# MAXPAGE-NEXT:     PhysicalAddress: 0x2040
+# MAXPAGE-NEXT:     FileSize: 200
+# MAXPAGE-NEXT:     MemSize: 200
 # MAXPAGE-NEXT:     Flags [
 # MAXPAGE-NEXT:       PF_R
 # MAXPAGE-NEXT:       PF_W

Modified: lld/trunk/test/ELF/linkerscript/phdr-check.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/phdr-check.s?rev=311586&r1=311585&r2=311586&view=diff
==============================================================================
--- lld/trunk/test/ELF/linkerscript/phdr-check.s (original)
+++ lld/trunk/test/ELF/linkerscript/phdr-check.s Wed Aug 23 11:44:34 2017
@@ -1,14 +1,14 @@
 # REQUIRES: x86
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
 
-# RUN: echo "SECTIONS { . = 0x10000000; .text : {*(.text.*)} }" > %t.script
+# RUN: echo "SECTIONS { . = 0x10000000 + SIZEOF_HEADERS; .text : {*(.text.*)} }" > %t.script
 # RUN: ld.lld -o %t1 --script %t.script %t
 # RUN: llvm-readobj -program-headers %t1 | FileCheck %s
 # CHECK:      ProgramHeaders [
 # CHECK-NEXT:  ProgramHeader {
 # CHECK-NEXT:    Type: PT_PHDR (0x6)
 # CHECK-NEXT:    Offset: 0x40
-# CHECK-NEXT:    VirtualAddress: 0xFFFF040
+# CHECK-NEXT:    VirtualAddress: 0x10000040
 
 .global _start
 _start:

Added: lld/trunk/test/ELF/linkerscript/segment-headers.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/segment-headers.s?rev=311586&view=auto
==============================================================================
--- lld/trunk/test/ELF/linkerscript/segment-headers.s (added)
+++ lld/trunk/test/ELF/linkerscript/segment-headers.s Wed Aug 23 11:44:34 2017
@@ -0,0 +1,26 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { . = 0x2000; .text : AT(0x100000) { *(.text) } }" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-readobj -l %t | FileCheck %s
+
+# CHECK: ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x1000
+# CHECK-NEXT:     VirtualAddress: 0x2000
+# CHECK-NEXT:     PhysicalAddress: 0x100000
+# CHECK-NEXT:     FileSize: 1
+# CHECK-NEXT:     MemSize: 1
+# CHECK-NEXT:     Flags [ (0x5)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:       PF_X (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4096
+# CHECK-NEXT:   }
+
+.section .text
+.global _start
+
+_start:
+  ret




More information about the llvm-commits mailing list