summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Storsjo <martin@martin.st>2019-04-15 10:57:44 +0000
committerMartin Storsjo <martin@martin.st>2019-04-15 10:57:44 +0000
commitcdf126ebec185d135dfb99cb907cf4f40583e3dc (patch)
tree26c851b7a608cb5063b75169eecd748a988b1820
parent7844031d460403596f151c30068d7fe062d92b37 (diff)
downloadbcm5719-llvm-cdf126ebec185d135dfb99cb907cf4f40583e3dc.tar.gz
bcm5719-llvm-cdf126ebec185d135dfb99cb907cf4f40583e3dc.zip
[COFF] Link crtend.o as the last object file
When faced with command line options such as "crtbegin.o appmain.o -lsomelib crtend.o", GNU ld pulls in all necessary object files from somelib before proceeding to crtend.o. LLD operates differently, only loading object files from any referenced static libraries after processing all input object files. This uses a similar hack as in the ELF linker. Here, it moves crtend.o to the end of the vector of object files. This makes sure that terminator chunks for sections such as .eh_frame gets ordered last, fixing DWARF exception handling for libgcc and gcc's crtend.o. Differential Revision: https://reviews.llvm.org/D60628 llvm-svn: 358394
-rw-r--r--lld/COFF/Driver.cpp33
-rw-r--r--lld/docs/ReleaseNotes.rst4
-rw-r--r--lld/test/COFF/Inputs/eh_frame_terminator-crtend.s3
-rw-r--r--lld/test/COFF/Inputs/eh_frame_terminator-otherfunc.s7
-rw-r--r--lld/test/COFF/eh_frame_terminator.s26
5 files changed, 69 insertions, 4 deletions
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 6acf2774ac0..2d6aeb598fe 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -91,6 +91,16 @@ static std::string getOutputPath(StringRef Path) {
return (S.substr(0, S.rfind('.')) + E).str();
}
+// Returns true if S matches /crtend.?\.o$/.
+static bool isCrtend(StringRef S) {
+ if (!S.endswith(".o"))
+ return false;
+ S = S.drop_back(2);
+ if (S.endswith("crtend"))
+ return true;
+ return !S.empty() && S.drop_back().endswith("crtend");
+}
+
// ErrorOr is not default constructible, so it cannot be used as the type
// parameter of a future.
// FIXME: We could open the file in createFutureForFile and avoid needing to
@@ -1665,11 +1675,28 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
return;
}
- // In MinGW, all symbols are automatically exported if no symbols
- // are chosen to be exported.
- if (Config->MinGW)
+ if (Config->MinGW) {
+ // In MinGW, all symbols are automatically exported if no symbols
+ // are chosen to be exported.
maybeExportMinGWSymbols(Args);
+ // Make sure the crtend.o object is the last object file. This object
+ // file can contain terminating section chunks that need to be placed
+ // last. GNU ld processes files and static libraries explicitly in the
+ // order provided on the command line, while lld will pull in needed
+ // files from static libraries only after the last object file on the
+ // command line.
+ for (auto I = ObjFile::Instances.begin(), E = ObjFile::Instances.end();
+ I != E; I++) {
+ ObjFile *File = *I;
+ if (isCrtend(File->getName())) {
+ ObjFile::Instances.erase(I);
+ ObjFile::Instances.push_back(File);
+ break;
+ }
+ }
+ }
+
// Windows specific -- when we are creating a .dll file, we also
// need to create a .lib file.
if (!Config->Exports.empty() || Config->DLL) {
diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst
index 7b6dbdffbbe..867a3bfee68 100644
--- a/lld/docs/ReleaseNotes.rst
+++ b/lld/docs/ReleaseNotes.rst
@@ -37,7 +37,9 @@ COFF Improvements
MinGW Improvements
------------------
-* ...
+* lld now correctly links crtend.o as the last object file, handling
+ terminators for the sections such as .eh_frame properly, fixing
+ DWARF exception handling with libgcc and gcc's crtend.o.
MachO Improvements
------------------
diff --git a/lld/test/COFF/Inputs/eh_frame_terminator-crtend.s b/lld/test/COFF/Inputs/eh_frame_terminator-crtend.s
new file mode 100644
index 00000000000..5588975efe5
--- /dev/null
+++ b/lld/test/COFF/Inputs/eh_frame_terminator-crtend.s
@@ -0,0 +1,3 @@
+ .section .eh_frame,"dr"
+__FRAME_END__:
+ .byte 3
diff --git a/lld/test/COFF/Inputs/eh_frame_terminator-otherfunc.s b/lld/test/COFF/Inputs/eh_frame_terminator-otherfunc.s
new file mode 100644
index 00000000000..049d2da44f8
--- /dev/null
+++ b/lld/test/COFF/Inputs/eh_frame_terminator-otherfunc.s
@@ -0,0 +1,7 @@
+ .text
+ .globl otherfunc
+otherfunc:
+ ret
+
+ .section .eh_frame,"dr"
+ .byte 2
diff --git a/lld/test/COFF/eh_frame_terminator.s b/lld/test/COFF/eh_frame_terminator.s
new file mode 100644
index 00000000000..001485a92bf
--- /dev/null
+++ b/lld/test/COFF/eh_frame_terminator.s
@@ -0,0 +1,26 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-windows-gnu %s -o %t.main.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-windows-gnu \
+// RUN: %p/Inputs/eh_frame_terminator-otherfunc.s -o %t.otherfunc.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-windows-gnu \
+// RUN: %p/Inputs/eh_frame_terminator-crtend.s -o %t.crtend.o
+// RUN: rm -f %t.otherfunc.lib
+// RUN: llvm-ar rcs %t.otherfunc.lib %t.otherfunc.o
+// RUN: lld-link -lldmingw %t.main.o %t.otherfunc.lib %t.crtend.o -out:%t.exe
+// RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+ .text
+ .globl main
+main:
+ call otherfunc
+ ret
+
+ .globl mainCRTStartup
+mainCRTStartup:
+ call main
+
+ .section .eh_frame,"dr"
+ .byte 1
+
+// CHECK: Contents of section .eh_fram:
+// CHECK-NEXT: 140003000 010203
OpenPOWER on IntegriCloud