[PATCH] D37998: Tweak orphan section placement

Rafael Ávila de Espíndola via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 18 14:15:36 PDT 2017


rafael created this revision.
Herald added a subscriber: emaste.

Filipe noticed that given a linker script that ended in

.some_sec { ...} ;
__stack_start = .;
. = . + 0x2000;
__stack_end = .;

lld would put orphan sections like .comment before __stack_end, corrupting the intended meaning.

The reason we don't normally move orphans past assignments to . is to avoid breaking

rx_sec : { *(rx_sec) }                                                                                                                                                      
 . = ALIGN(0x1000);                                                                                                                                                          
 /* The RW PT_LOAD starts here*/

but in this case, there is nothing after and it seems safer to put the orphan section last. This seems to match bfd's behavior and is convenient for writing linker scripts that care about the layout of SHF_ALLOC sections, but not of any non SHF_ALLOC sections.


https://reviews.llvm.org/D37998

Files:
  ELF/Writer.cpp
  test/ELF/linkerscript/orphan-end.s


Index: test/ELF/linkerscript/orphan-end.s
===================================================================
--- /dev/null
+++ test/ELF/linkerscript/orphan-end.s
@@ -0,0 +1,57 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# Test that .orphan_rx is placed after __stack_end. This matches bfd's
+# behavior when the orphan section is the last one.
+
+# RUN: echo "SECTIONS {             \
+# RUN:        __start_text = .;     \
+# RUN:        .text : { *(.text*) } \
+# RUN:        __end_text = .;       \
+# RUN:        __stack_start = .;    \
+# RUN:        . = . + 0x1000;       \
+# RUN:        __stack_end = .;      \
+# RUN:      }" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-readelf -S --symbols %t | FileCheck %s
+
+# CHECK-DAG: .text             PROGBITS        0000000000000000
+# CHECK-DAG: .orphan_rx        PROGBITS        0000000000001004
+
+# CHECK-DAG: 0000000000000000 {{.*}} __start_text
+# CHECK-DAG: 0000000000000004 {{.*}} __end_text
+# CHECK-DAG: 0000000000000004 {{.*}} __stack_start
+# CHECK-DAG: 0000000000001004 {{.*}} __stack_end
+
+# Test that .orphan_rx is now placed before __stack_end. This matches bfd's
+# behavior when the orphan section is not the last one.
+
+# RUN: echo "SECTIONS {             \
+# RUN:        __start_text = .;     \
+# RUN:        .text : { *(.text*) } \
+# RUN:        __end_text = .;       \
+# RUN:        __stack_start = .;    \
+# RUN:        . = . + 0x1000;       \
+# RUN:        __stack_end = .;      \
+# RUN:        .orphan_rw : { *(.orphan_rw*) } \
+# RUN:      }" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-readelf -S --symbols %t | FileCheck --check-prefix=MIDDLE %s
+
+# MIDDLE-DAG: .text             PROGBITS        0000000000000000
+# MIDDLE-DAG: .orphan_rx        PROGBITS        0000000000000004
+
+# MIDDLE-DAG: 0000000000000000 {{.*}} __start_text
+# MIDDLE-DAG: 0000000000000004 {{.*}} __end_text
+# MIDDLE-DAG: 0000000000000004 {{.*}} __stack_start
+# MIDDLE-DAG: 0000000000001008 {{.*}} __stack_end
+
+        .global _start
+_start:
+        .zero 4
+
+        .section .orphan_rx,"ax"
+        .zero 4
+
+        .section .orphan_rw,"aw"
+        .zero 4
Index: ELF/Writer.cpp
===================================================================
--- ELF/Writer.cpp
+++ ELF/Writer.cpp
@@ -1043,6 +1043,17 @@
       llvm::make_reverse_iterator(I), llvm::make_reverse_iterator(B),
       [](BaseCommand *Cmd) { return isa<OutputSection>(Cmd); });
   I = J.base();
+
+  // As a special case, if the orphan section is the last section, put
+  // it at the very end, past any other commands.
+  // This matches bfd's behavior and is convenient when the linker script fully
+  // specifies the start of the file, but doesn't care about the end (the non
+  // alloc sections for example).
+  auto NextSec = std::find_if(
+      I, E, [](BaseCommand *Cmd) { return isa<OutputSection>(Cmd); });
+  if (NextSec == E)
+    return E;
+
   while (I != E && shouldSkip(*I))
     ++I;
   return I;


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D37998.115715.patch
Type: text/x-patch
Size: 3058 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20170918/9b54106e/attachment.bin>


More information about the llvm-commits mailing list