From b34006dd0a5126a7b3c2c5ba4d575456ab8a4894 Mon Sep 17 00:00:00 2001 From: Alan Zhao Date: Wed, 31 Aug 2022 16:45:40 -0400 Subject: [PATCH] [lld][COFF] Add support for overriding weak symbols in LLVM bitcode input LLVM bitcode contains support for weak symbols, so we can add support for overriding weak symbols in the output COFF even though COFF doesn't have inherent support for weak symbols. The motivation for this patch is that Chromium is trying to use libc++'s assertion handler mechanism, which relies on weak symbols [0], but we're unable to perform a ThinLTO build on Windows due to this problem [1]. [0]: https://reviews.llvm.org/D121478 [1]: https://crrev.com/c/3863576 Reviewed By: rnk Differential Revision: https://reviews.llvm.org/D133165 --- lld/COFF/InputFiles.cpp | 3 ++- lld/COFF/SymbolTable.cpp | 8 ++++---- lld/COFF/SymbolTable.h | 3 ++- lld/COFF/Symbols.h | 11 +++++++++-- lld/test/COFF/Inputs/strong-def.ll | 6 ++++++ lld/test/COFF/Inputs/weak-def.ll | 6 ++++++ lld/test/COFF/weak-override.ll | 30 ++++++++++++++++++++++++++++++ 7 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 lld/test/COFF/Inputs/strong-def.ll create mode 100644 lld/test/COFF/Inputs/weak-def.ll create mode 100644 lld/test/COFF/weak-override.ll diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp index 0f3f5e0..9c1b269 100644 --- a/lld/COFF/InputFiles.cpp +++ b/lld/COFF/InputFiles.cpp @@ -1070,7 +1070,8 @@ void BitcodeFile::parse() { sym = ctx.symtab.addUndefined(symName, this, false); } } else { - sym = ctx.symtab.addRegular(this, symName, nullptr, fakeSC); + sym = ctx.symtab.addRegular(this, symName, nullptr, fakeSC, 0, + objSym.isWeak()); } symbols.push_back(sym); if (objSym.isUsed()) diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp index 9e5edb6..95f7b4e 100644 --- a/lld/COFF/SymbolTable.cpp +++ b/lld/COFF/SymbolTable.cpp @@ -698,12 +698,12 @@ Symbol *SymbolTable::addSynthetic(StringRef n, Chunk *c) { Symbol *SymbolTable::addRegular(InputFile *f, StringRef n, const coff_symbol_generic *sym, SectionChunk *c, - uint32_t sectionOffset) { + uint32_t sectionOffset, bool isWeak) { auto [s, wasInserted] = insert(n, f); - if (wasInserted || !isa(s)) + if (wasInserted || !isa(s) || s->isWeak) replaceSymbol(s, f, n, /*IsCOMDAT*/ false, - /*IsExternal*/ true, sym, c); - else + /*IsExternal*/ true, sym, c, isWeak); + else if (!isWeak) reportDuplicate(s, f, c, sectionOffset); return s; } diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h index 167377e..15cb533 100644 --- a/lld/COFF/SymbolTable.h +++ b/lld/COFF/SymbolTable.h @@ -95,7 +95,8 @@ public: Symbol *addAbsolute(StringRef n, COFFSymbolRef s); Symbol *addRegular(InputFile *f, StringRef n, const llvm::object::coff_symbol_generic *s = nullptr, - SectionChunk *c = nullptr, uint32_t sectionOffset = 0); + SectionChunk *c = nullptr, uint32_t sectionOffset = 0, + bool isWeak = false); std::pair addComdat(InputFile *f, StringRef n, const llvm::object::coff_symbol_generic *s = nullptr); diff --git a/lld/COFF/Symbols.h b/lld/COFF/Symbols.h index a4c6f89..7e99b02 100644 --- a/lld/COFF/Symbols.h +++ b/lld/COFF/Symbols.h @@ -106,7 +106,8 @@ protected: : symbolKind(k), isExternal(true), isCOMDAT(false), writtenToSymtab(false), pendingArchiveLoad(false), isGCRoot(false), isRuntimePseudoReloc(false), deferUndefined(false), canInline(true), - nameSize(n.size()), nameData(n.empty() ? nullptr : n.data()) { + isWeak(false), nameSize(n.size()), + nameData(n.empty() ? nullptr : n.data()) { assert((!n.empty() || k <= LastDefinedCOFFKind) && "If the name is empty, the Symbol must be a DefinedCOFF."); } @@ -145,6 +146,11 @@ public: // doesn't know the final contents of the symbol. unsigned canInline : 1; + // True if the symbol is weak. This is only tracked for bitcode/LTO symbols. + // This information isn't written to the output; rather, it's used for + // managing weak symbol overrides. + unsigned isWeak : 1; + protected: // Symbol name length. Assume symbol lengths fit in a 32-bit integer. uint32_t nameSize; @@ -200,10 +206,11 @@ public: DefinedRegular(InputFile *f, StringRef n, bool isCOMDAT, bool isExternal = false, const coff_symbol_generic *s = nullptr, - SectionChunk *c = nullptr) + SectionChunk *c = nullptr, bool isWeak = false) : DefinedCOFF(DefinedRegularKind, f, n, s), data(c ? &c->repl : nullptr) { this->isExternal = isExternal; this->isCOMDAT = isCOMDAT; + this->isWeak = isWeak; } static bool classof(const Symbol *s) { diff --git a/lld/test/COFF/Inputs/strong-def.ll b/lld/test/COFF/Inputs/strong-def.ll new file mode 100644 index 0000000..ea5d78c --- /dev/null +++ b/lld/test/COFF/Inputs/strong-def.ll @@ -0,0 +1,6 @@ +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc" + +define dso_local noundef i32 @foo() local_unnamed_addr { + ret i32 5678 +} diff --git a/lld/test/COFF/Inputs/weak-def.ll b/lld/test/COFF/Inputs/weak-def.ll new file mode 100644 index 0000000..9e1315a --- /dev/null +++ b/lld/test/COFF/Inputs/weak-def.ll @@ -0,0 +1,6 @@ +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc" + +define weak dso_local noundef i32 @foo() local_unnamed_addr { + ret i32 1234 +} diff --git a/lld/test/COFF/weak-override.ll b/lld/test/COFF/weak-override.ll new file mode 100644 index 0000000..93f2d8e --- /dev/null +++ b/lld/test/COFF/weak-override.ll @@ -0,0 +1,30 @@ +; REQUIRES: x86 +; RUN: llvm-as -o %t-weak.obj %S/Inputs/weak-def.ll +; RUN: llvm-as -o %t-strong.obj %S/Inputs/strong-def.ll +; RUN: llvm-as -o %t.obj %s +; RUN: lld-link /dll /out:%t-weak-first.dll %t.obj %t-weak.obj %t-strong.obj +; RUN: lld-link /dll /out:%t-strong-first.dll %t.obj %t-strong.obj %t-weak.obj +; RUN: lld-link /dll /out:%t-weak-only.dll %t.obj %t-weak.obj +; RUN: llvm-objdump -d %t-weak-first.dll | FileCheck --check-prefix=CHECK-STRONG %s +; RUN: llvm-objdump -d %t-strong-first.dll | FileCheck --check-prefix=CHECK-STRONG %s +; RUN: llvm-objdump -d %t-weak-only.dll | FileCheck --check-prefix=CHECK-WEAK %s + +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc" + +declare noundef i32 @foo() local_unnamed_addr + +define dllexport i32 @bar() local_unnamed_addr { + %1 = tail call noundef i32 @foo() + ret i32 %1 +} + +define void @_DllMainCRTStartup() { +entry: + ret void +} + +; CHECK-STRONG: movl $5678, %eax +; CHECK-STRONG-NOT: movl $1234, %eax +; CHECK-WEAK: movl $1234, %eax +; CHECK-WEAK-NOT: movl $5678, %eax -- 2.7.4