diff options
| author | Martin Storsjo <martin@martin.st> | 2019-04-15 10:57:44 +0000 |
|---|---|---|
| committer | Martin Storsjo <martin@martin.st> | 2019-04-15 10:57:44 +0000 |
| commit | cdf126ebec185d135dfb99cb907cf4f40583e3dc (patch) | |
| tree | 26c851b7a608cb5063b75169eecd748a988b1820 | |
| parent | 7844031d460403596f151c30068d7fe062d92b37 (diff) | |
| download | bcm5719-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.cpp | 33 | ||||
| -rw-r--r-- | lld/docs/ReleaseNotes.rst | 4 | ||||
| -rw-r--r-- | lld/test/COFF/Inputs/eh_frame_terminator-crtend.s | 3 | ||||
| -rw-r--r-- | lld/test/COFF/Inputs/eh_frame_terminator-otherfunc.s | 7 | ||||
| -rw-r--r-- | lld/test/COFF/eh_frame_terminator.s | 26 |
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 |

