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())
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<DefinedRegular>(s))
+ if (wasInserted || !isa<DefinedRegular>(s) || s->isWeak)
replaceSymbol<DefinedRegular>(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;
}
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<DefinedRegular *, bool>
addComdat(InputFile *f, StringRef n,
const llvm::object::coff_symbol_generic *s = nullptr);
: 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.");
}
// 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;
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) {
--- /dev/null
+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
+}
--- /dev/null
+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
+}
--- /dev/null
+; 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