Merge pull request #3923 from kinke/fix3916

Fix #3916 - undefined symbols with `-dllimport=all` on Windows
This commit is contained in:
Martin Kinkelin 2022-02-28 22:19:02 +01:00 committed by GitHub
parent d07df5d166
commit f2a6fefb7b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 47 additions and 37 deletions

View file

@ -1607,7 +1607,7 @@ DValue *DtoSymbolAddress(const Loc &loc, Type *type, Declaration *decl) {
if (SymbolDeclaration *sdecl = decl->isSymbolDeclaration()) { if (SymbolDeclaration *sdecl = decl->isSymbolDeclaration()) {
// this is the static initialiser (init symbol) for aggregates // this is the static initialiser (init symbol) for aggregates
AggregateDeclaration *ad = sdecl->dsym; AggregateDeclaration *ad = sdecl->dsym;
IF_LOG Logger::print("Sym: ad=%s\n", ad->toChars()); IF_LOG Logger::print("init symbol of %s\n", ad->toChars());
DtoResolveDsymbol(ad); DtoResolveDsymbol(ad);
auto sd = ad->isStructDeclaration(); auto sd = ad->isStructDeclaration();
@ -1733,24 +1733,33 @@ static bool isDefaultLibSymbol(Dsymbol *sym) {
(md->packages.length > 1 && md->packages.ptr[1] == Id::io))); (md->packages.length > 1 && md->packages.ptr[1] == Id::io)));
} }
bool defineOnDeclare(Dsymbol* sym, bool isFunction) { bool defineOnDeclare(Dsymbol* sym, bool) {
if (global.params.linkonceTemplates) return global.params.linkonceTemplates && sym->isInstantiated();
return sym->isInstantiated();
// With -dllimport=defaultLibsOnly, an instantiated data symbol from a
// druntime/Phobos template may be assigned to an arbitrary binary (and culled
// from others via `needsCodegen()`). Define it in each referencing CU and
// never dllimport.
return !isFunction && global.params.dllimport == DLLImport::defaultLibsOnly &&
sym->isInstantiated() && isDefaultLibSymbol(sym);
} }
bool dllimportDataSymbol(Dsymbol *sym) { bool dllimportDataSymbol(Dsymbol *sym) {
return sym->isExport() || global.params.dllimport == DLLImport::all || if (!global.params.targetTriple->isOSWindows())
(global.params.dllimport == DLLImport::defaultLibsOnly && return false;
// exclude instantiated symbols from druntime/Phobos templates (see
// `defineOnDeclare()`) if (sym->isExport() || global.params.dllimport == DLLImport::all ||
!sym->isInstantiated() && isDefaultLibSymbol(sym)); (global.params.dllimport == DLLImport::defaultLibsOnly &&
isDefaultLibSymbol(sym))) {
// Okay, this symbol is a candidate. Use dllimport unless we have a
// guaranteed-codegen'd definition in a root module.
if (auto mod = sym->isModule()) {
return !mod->isRoot(); // non-root ModuleInfo symbol
} else if (sym->inNonRoot()) {
return true; // not instantiated, and defined in non-root
} else if (!global.params.linkonceTemplates &&
sym->isInstantiated()) {
return true; // instantiated but potentially culled (needsCodegen())
} else if (auto vd = sym->isVarDeclaration()) {
if (vd->storage_class & STCextern)
return true; // externally defined global variable
}
}
return false;
} }
llvm::GlobalVariable *declareGlobal(const Loc &loc, llvm::Module &module, llvm::GlobalVariable *declareGlobal(const Loc &loc, llvm::Module &module,

View file

@ -247,8 +247,7 @@ llvm::Constant *buildStringLiteralConstant(StringExp *se, bool zeroTerm);
/// primarily for -linkonce-templates. /// primarily for -linkonce-templates.
bool defineOnDeclare(Dsymbol *sym, bool isFunction); bool defineOnDeclare(Dsymbol *sym, bool isFunction);
/// Indicates whether the specified data symbol is a general dllimport /// Indicates whether the specified data symbol is to be declared as dllimport.
/// candidate.
bool dllimportDataSymbol(Dsymbol *sym); bool dllimportDataSymbol(Dsymbol *sym);
/// Tries to declare an LLVM global. If a variable with the same mangled name /// Tries to declare an LLVM global. If a variable with the same mangled name

View file

@ -290,8 +290,12 @@ void setVisibility(Dsymbol *sym, llvm::GlobalObject *obj) {
if (triple.isOSWindows()) { if (triple.isOSWindows()) {
bool isExported = sym->isExport(); bool isExported = sym->isExport();
// also export with -fvisibility=public without @hidden // Also export (non-linkonce_odr) symbols
if (!isExported && global.params.dllexport && !hasHiddenUDA) { // * with -fvisibility=public without @hidden, or
// * if declared with dllimport (so potentially imported from other object
// files / DLLs).
if (!isExported && ((global.params.dllexport && !hasHiddenUDA) ||
obj->hasDLLImportStorageClass())) {
isExported = hasExportedLinkage(obj); isExported = hasExportedLinkage(obj);
} }
// reset default visibility & DSO locality - on Windows, the DLL storage // reset default visibility & DSO locality - on Windows, the DLL storage

View file

@ -53,17 +53,7 @@ bool IrAggr::suppressTypeInfo() const {
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
bool IrAggr::useDLLImport() const { bool IrAggr::useDLLImport() const {
if (!global.params.targetTriple->isOSWindows()) return dllimportDataSymbol(aggrdecl);
return false;
if (dllimportDataSymbol(aggrdecl)) {
// dllimport, unless defined in a root module (=> no extra indirection for
// other root modules, assuming *all* root modules will be linked together
// to one or more binaries).
return aggrdecl->inNonRoot();
}
return false;
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////

View file

@ -86,12 +86,8 @@ void IrGlobal::declare() {
// dllimport isn't supported for thread-local globals (MSVC++ neither) // dllimport isn't supported for thread-local globals (MSVC++ neither)
if (!V->isThreadlocal()) { if (!V->isThreadlocal()) {
// implicitly include extern(D) globals with -dllimport // implicitly include extern(D) globals with -dllimport
if (V->isExport() || (V->linkage == LINK::d && dllimportDataSymbol(V))) { useDLLImport =
const bool isDefinedInRootModule = (V->isExport() || V->linkage == LINK::d) && dllimportDataSymbol(V);
!(V->storage_class & STCextern) && !V->inNonRoot();
if (!isDefinedInRootModule)
useDLLImport = true;
}
} }
} }

View file

@ -0,0 +1,12 @@
// REQUIRES: Windows
// RUN: %ldc -output-ll -dllimport=all -of=%t_all.ll %s && FileCheck %s < %t_all.ll
// RUN: %ldc -output-ll -dllimport=defaultLibsOnly -of=%t_dlo.ll %s && FileCheck %s < %t_dlo.ll
import std.random : Xorshift; // pre-instantiated template
void foo()
{
// CHECK: _D3std6random__T14XorshiftEngine{{.*}}6__initZ = external dllimport
const i = __traits(initSymbol, Xorshift);
}