| From 7e0768329ca347e37c7bdb0da16b51cb3e7b7d8b Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st> |
| Date: Sun, 9 May 2021 23:27:35 +0300 |
| Subject: [PATCH] [LLD] [COFF] Fix including the personality function for DWARF |
| EH when linking with --gc-sections |
| |
| Since c579a5b1d92a9bc2046d00ee2d427832e0f5ddec we don't traverse |
| .eh_frame when doing GC. But the exception handling personality |
| function needs to be included, and is only referenced from within |
| .eh_frame. |
| |
| Differential Revision: https://reviews.llvm.org/D102138 |
| --- |
| COFF/Driver.cpp | 19 ++++++++++++++++++- |
| test/COFF/gc-dwarf-eh.s | 36 ++++++++++++++++++++++++++++++++++++ |
| 2 files changed, 54 insertions(+), 1 deletion(-) |
| create mode 100644 test/COFF/gc-dwarf-eh.s |
| |
| diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp |
| index e2374b52b4f9f..029148c4722bb 100644 |
| --- a/COFF/Driver.cpp |
| +++ b/COFF/Driver.cpp |
| @@ -2226,8 +2226,25 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) { |
| config->printSymbolOrder = arg->getValue(); |
| |
| // Identify unreferenced COMDAT sections. |
| - if (config->doGC) |
| + if (config->doGC) { |
| + if (config->mingw) { |
| + // markLive doesn't traverse .eh_frame, but the personality function is |
| + // only reached that way. The proper solution would be to parse and |
| + // traverse the .eh_frame section, like the ELF linker does. |
| + // For now, just manually try to retain the known possible personality |
| + // functions. This doesn't bring in more object files, but only marks |
| + // functions that already have been included to be retained. |
| + for (const char *n : {"__gxx_personality_v0", "__gcc_personality_v0"}) { |
| + Defined *d = dyn_cast_or_null<Defined>(symtab->findUnderscore(n)); |
| + if (d && !d->isGCRoot) { |
| + d->isGCRoot = true; |
| + config->gcroot.push_back(d); |
| + } |
| + } |
| + } |
| + |
| markLive(symtab->getChunks()); |
| + } |
| |
| // Needs to happen after the last call to addFile(). |
| convertResources(); |
| diff --git a/test/COFF/gc-dwarf-eh.s b/test/COFF/gc-dwarf-eh.s |
| new file mode 100644 |
| index 0000000000000..757aa671c7693 |
| --- /dev/null |
| +++ b/test/COFF/gc-dwarf-eh.s |
| @@ -0,0 +1,36 @@ |
| +# REQUIRES: x86 |
| + |
| +# RUN: llvm-mc -triple=i686-windows-gnu %s -filetype=obj -o %t.obj |
| +# RUN: lld-link -lldmingw -lldmap:%t.map -out:%t.exe -opt:ref -entry:main %t.obj -verbose 2>&1 | FileCheck %s |
| +# RUN: FileCheck %s --check-prefix=MAP --input-file=%t.map |
| + |
| +# CHECK: Discarded _unused |
| + |
| +# MAP: In Symbol |
| +# MAP: gc-dwarf-eh.s.tmp.obj:(.text) |
| +# MAP: {{ ___gxx_personality_v0$}} |
| + |
| + .def _main; .scl 2; .type 32; .endef |
| + .section .text,"xr",one_only,_main |
| + .globl _main |
| + .cfi_startproc |
| + .cfi_personality 0, ___gxx_personality_v0 |
| +_main: |
| + xorl %eax, %eax |
| + ret |
| + .cfi_endproc |
| + |
| + .def ___gxx_personality_v0; .scl 2; .type 32; .endef |
| + .section .text,"xr",one_only,___gxx_personality_v0 |
| + .globl ___gxx_personality_v0 |
| +___gxx_personality_v0: |
| + ret |
| + |
| + .def _unused; .scl 2; .type 32; .endef |
| + .section .text,"xr",one_only,_unused |
| + .globl _unused |
| + .cfi_startproc |
| + .cfi_personality 0, ___gxx_personality_v0 |
| +_unused: |
| + ret |
| + .cfi_endproc |