Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lld: Fix exception handling in static libraries #5546

Merged
merged 1 commit into from
Jun 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
366 changes: 366 additions & 0 deletions mingw-w64-clang/0306-lld-fix-static-lib.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,366 @@
Index: lld/trunk/COFF/Driver.h
===================================================================
--- lld/trunk/COFF/Driver.h
+++ lld/trunk/COFF/Driver.h
@@ -96,6 +96,8 @@
// Library search path. The first element is always "" (current directory).
std::vector<StringRef> SearchPaths;

+ void maybeExportMinGWSymbols(const llvm::opt::InputArgList &Args);
+
// We don't want to add the same file more than once.
// Files are uniquified by their filesystem and file number.
std::set<llvm::sys::fs::UniqueID> VisitedFiles;
Index: lld/trunk/COFF/Driver.cpp
===================================================================
--- lld/trunk/COFF/Driver.cpp
+++ lld/trunk/COFF/Driver.cpp
@@ -90,6 +90,16 @@
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
@@ -898,6 +908,44 @@
Config->PDBAltPath = Buf;
}

+// In MinGW, if no symbols are chosen to be exported, then all symbols are
+// automatically exported by default. This behavior can be forced by the
+// -export-all-symbols option, so that it happens even when exports are
+// explicitly specified. The automatic behavior can be disabled using the
+// -exclude-all-symbols option, so that lld-link behaves like link.exe rather
+// than MinGW in the case that nothing is explicitly exported.
+void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &Args) {
+ if (!Config->DLL)
+ return;
+
+ if (!Args.hasArg(OPT_export_all_symbols)) {
+ if (!Config->Exports.empty())
+ return;
+ if (Args.hasArg(OPT_exclude_all_symbols))
+ return;
+ }
+
+ AutoExporter Exporter;
+
+ for (auto *Arg : Args.filtered(OPT_wholearchive_file))
+ if (Optional<StringRef> Path = doFindFile(Arg->getValue()))
+ Exporter.addWholeArchive(*Path);
+
+ Symtab->forEachSymbol([&](Symbol *S) {
+ auto *Def = dyn_cast<Defined>(S);
+ if (!Exporter.shouldExport(Def))
+ return;
+
+ Export E;
+ E.Name = Def->getName();
+ E.Sym = Def;
+ if (Chunk *C = Def->getChunk())
+ if (!(C->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
+ E.Data = true;
+ Config->Exports.push_back(E);
+ });
+}
+
void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// If the first command line argument is "/lib", link.exe acts like lib.exe.
// We call our own implementation of lib.exe that understands bitcode files.
@@ -1326,14 +1374,10 @@
return;

std::set<sys::fs::UniqueID> WholeArchives;
- AutoExporter Exporter;
- for (auto *Arg : Args.filtered(OPT_wholearchive_file)) {
- if (Optional<StringRef> Path = doFindFile(Arg->getValue())) {
+ for (auto *Arg : Args.filtered(OPT_wholearchive_file))
+ if (Optional<StringRef> Path = doFindFile(Arg->getValue()))
if (Optional<sys::fs::UniqueID> ID = getUniqueID(*Path))
WholeArchives.insert(*ID);
- Exporter.addWholeArchive(*Path);
- }
- }

// A predicate returning true if a given path is an argument for
// /wholearchive:, or /wholearchive is enabled globally.
@@ -1603,24 +1647,26 @@
return;
}

- // In MinGW, all symbols are automatically exported if no symbols
- // are chosen to be exported.
- if (Config->DLL && ((Config->MinGW && Config->Exports.empty()) ||
- Args.hasArg(OPT_export_all_symbols))) {
- Exporter.initSymbolExcludes();
-
- Symtab->forEachSymbol([=](Symbol *S) {
- auto *Def = dyn_cast<Defined>(S);
- if (!Exporter.shouldExport(Def))
- return;
- Export E;
- E.Name = Def->getName();
- E.Sym = Def;
- if (Def->getChunk() &&
- !(Def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
- E.Data = true;
- Config->Exports.push_back(E);
- });
+ 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
Index: lld/trunk/COFF/MinGW.h
===================================================================
--- lld/trunk/COFF/MinGW.h
+++ lld/trunk/COFF/MinGW.h
@@ -22,8 +22,6 @@
public:
AutoExporter();

- void initSymbolExcludes();
-
void addWholeArchive(StringRef Path);

llvm::StringSet<> ExcludeSymbols;
Index: lld/trunk/COFF/MinGW.cpp
===================================================================
--- lld/trunk/COFF/MinGW.cpp
+++ lld/trunk/COFF/MinGW.cpp
@@ -18,7 +18,34 @@
using namespace llvm;
using namespace llvm::COFF;

-void AutoExporter::initSymbolExcludes() {
+AutoExporter::AutoExporter() {
+ ExcludeLibs = {
+ "libgcc",
+ "libgcc_s",
+ "libstdc++",
+ "libmingw32",
+ "libmingwex",
+ "libg2c",
+ "libsupc++",
+ "libobjc",
+ "libgcj",
+ "libclang_rt.builtins",
+ "libclang_rt.builtins-aarch64",
+ "libclang_rt.builtins-arm",
+ "libclang_rt.builtins-i386",
+ "libclang_rt.builtins-x86_64",
+ "libc++",
+ "libc++abi",
+ "libunwind",
+ "libmsvcrt",
+ "libucrtbase",
+ };
+
+ ExcludeObjects = {
+ "crt0.o", "crt1.o", "crt1u.o", "crt2.o", "crt2u.o", "dllcrt1.o",
+ "dllcrt2.o", "gcrt0.o", "gcrt1.o", "gcrt2.o", "crtbegin.o", "crtend.o",
+ };
+
ExcludeSymbolPrefixes = {
// Import symbols
"__imp_",
@@ -31,10 +58,12 @@
// Artifical symbols such as .refptr
".",
};
+
ExcludeSymbolSuffixes = {
"_iname",
"_NULL_THUNK_DATA",
};
+
if (Config->Machine == I386) {
ExcludeSymbols = {
"__NULL_IMPORT_DESCRIPTOR",
@@ -72,44 +101,6 @@
}
}

-AutoExporter::AutoExporter() {
- ExcludeLibs = {
- "libgcc",
- "libgcc_s",
- "libstdc++",
- "libmingw32",
- "libmingwex",
- "libg2c",
- "libsupc++",
- "libobjc",
- "libgcj",
- "libclang_rt.builtins",
- "libclang_rt.builtins-aarch64",
- "libclang_rt.builtins-arm",
- "libclang_rt.builtins-i386",
- "libclang_rt.builtins-x86_64",
- "libc++",
- "libc++abi",
- "libunwind",
- "libmsvcrt",
- "libucrtbase",
- };
- ExcludeObjects = {
- "crt0.o",
- "crt1.o",
- "crt1u.o",
- "crt2.o",
- "crt2u.o",
- "dllcrt1.o",
- "dllcrt2.o",
- "gcrt0.o",
- "gcrt1.o",
- "gcrt2.o",
- "crtbegin.o",
- "crtend.o",
- };
-}
-
void AutoExporter::addWholeArchive(StringRef Path) {
StringRef LibName = sys::path::filename(Path);
// Drop the file extension, to match the processing below.
Index: lld/trunk/COFF/Options.td
===================================================================
--- lld/trunk/COFF/Options.td
+++ lld/trunk/COFF/Options.td
@@ -150,6 +150,7 @@
def help_q : Flag<["/?", "-?"], "">, Alias<help>;

// LLD extensions
+def exclude_all_symbols : F<"exclude-all-symbols">;
def export_all_symbols : F<"export-all-symbols">;
def kill_at : F<"kill-at">;
def lldmingw : F<"lldmingw">;
Index: lld/trunk/docs/ReleaseNotes.rst
===================================================================
--- lld/trunk/docs/ReleaseNotes.rst
+++ lld/trunk/docs/ReleaseNotes.rst
@@ -112,6 +112,10 @@
Previously, the ``--build-id`` option did not actually generate a build id
unless ``--pdb`` was specified.

+* 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.
+
WebAssembly Improvements
------------------------

Index: lld/trunk/test/COFF/Inputs/eh_frame_terminator-crtend.s
===================================================================
--- lld/trunk/test/COFF/Inputs/eh_frame_terminator-crtend.s
+++ lld/trunk/test/COFF/Inputs/eh_frame_terminator-crtend.s
@@ -0,0 +1,3 @@
+ .section .eh_frame,"dr"
+__FRAME_END__:
+ .byte 3
Index: lld/trunk/test/COFF/Inputs/eh_frame_terminator-otherfunc.s
===================================================================
--- lld/trunk/test/COFF/Inputs/eh_frame_terminator-otherfunc.s
+++ lld/trunk/test/COFF/Inputs/eh_frame_terminator-otherfunc.s
@@ -0,0 +1,7 @@
+ .text
+ .globl otherfunc
+otherfunc:
+ ret
+
+ .section .eh_frame,"dr"
+ .byte 2
Index: lld/trunk/test/COFF/eh_frame_terminator.s
===================================================================
--- lld/trunk/test/COFF/eh_frame_terminator.s
+++ lld/trunk/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
Index: lld/trunk/test/COFF/exclude-all.s
===================================================================
--- lld/trunk/test/COFF/exclude-all.s
+++ lld/trunk/test/COFF/exclude-all.s
@@ -0,0 +1,31 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -triple=i686-windows-gnu %s -filetype=obj -o %t.obj
+
+# RUN: lld-link -lldmingw -exclude-all-symbols -dll -out:%t.dll -entry:DllMainCRTStartup@12 %t.obj
+# RUN: llvm-readobj -coff-exports %t.dll | FileCheck %s -check-prefix=NO-EXPORTS
+
+# NO-EXPORTS-NOT: Name:
+
+.global _foobar
+.global _DllMainCRTStartup@12
+.global _dataSym
+.text
+_DllMainCRTStartup@12:
+ ret
+_foobar:
+ ret
+.data
+_dataSym:
+ .int 4
+
+# Test specifying -exclude-all-symbols, on an object file that contains
+# dllexport directive for some of the symbols. In this case, the dllexported
+# symbols are still exported.
+
+# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
+#
+# RUN: lld-link -out:%t.dll -dll %t.obj -lldmingw -exclude-all-symbols -output-def:%t.def
+# RUN: llvm-readobj -coff-exports %t.dll | FileCheck -check-prefix=DLLEXPORT %s
+
+# DLLEXPORT: Name: exportfn3
5 changes: 4 additions & 1 deletion mingw-w64-clang/PKGBUILD
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pkgname=("${MINGW_PACKAGE_PREFIX}-${_realname}"
"${MINGW_PACKAGE_PREFIX}-llvm"
"${MINGW_PACKAGE_PREFIX}-polly")
pkgver=8.0.0
pkgrel=9
pkgrel=10
pkgdesc="C language family frontend for LLVM (mingw-w64)"
arch=('any')
url="https://llvm.org/"
Expand Down Expand Up @@ -84,6 +84,7 @@ source=(https://releases.llvm.org/${pkgver}/llvm-${pkgver}.src.tar.xz{,.sig}
"0303-lld-response-file.patch"
"0304-lld-version-flags.patch"
"0305-lld-exception-handling.patch"
"0306-lld-fix-static-lib.patch"
"0401-disable-visibility-annotations.patch"
"0405-fix-conflict-win32-posix-threads.patch"
"0406-fix-static_asserts-and-unique_ptr-for-libcxx.patch"
Expand Down Expand Up @@ -152,6 +153,7 @@ sha256sums=('8872be1b12c61450cacc82b3d153eab02be2546ef34fa3580ed14137bb26224c'
'63ffa972420d32befdb0812dc8f7da06433a3c16cc93f2daedad6d72d0714e69'
'cd8417499aa2d49e21847eec24e0fe33ec77376639f0fc011e1077e21456525c'
'b99dd4f250706a75c076797f2b2e0a9848187869df822ab78633c3acc805f799'
'526264f75e9ad32391cbb0c2ac8c946f282378e99a931c375981aeae110b56ed'
'219eca2ad015ababb05d81ed97b4b40cf13ea189ee93cf57aa814cca7cf40001'
'2f8f3c819837e4a16a364ed6e2a0a879cd10f924169ed7d89c27c1ed64edfe95'
'a219798d0199e0b34c90fcdacada7e0f6d179fa4349a26bce8f714173046ecc7'
Expand Down Expand Up @@ -217,6 +219,7 @@ prepare() {
patch -p2 -i "${srcdir}/0303-lld-response-file.patch"
patch -p2 -i "${srcdir}/0304-lld-version-flags.patch"
patch -p2 -i "${srcdir}/0305-lld-exception-handling.patch"
patch -p2 -i "${srcdir}/0306-lld-fix-static-lib.patch"

cd "${srcdir}/libcxx-${pkgver}.src"
patch -p1 -i "${srcdir}/0401-disable-visibility-annotations.patch"
Expand Down