Tweak orphan section placement.
authorRafael Espindola <rafael.espindola@gmail.com>
Tue, 19 Sep 2017 17:29:58 +0000 (17:29 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Tue, 19 Sep 2017 17:29:58 +0000 (17:29 +0000)
Given a linker script that ends 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.

llvm-svn: 313646

lld/ELF/Writer.cpp
lld/test/ELF/linkerscript/orphan-end.s [new file with mode: 0644]

index 9f1cea5..6dd3d9f 100644 (file)
@@ -1044,6 +1044,17 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B,
       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;
diff --git a/lld/test/ELF/linkerscript/orphan-end.s b/lld/test/ELF/linkerscript/orphan-end.s
new file mode 100644 (file)
index 0000000..5f56d8f
--- /dev/null
@@ -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