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

Fix #3916 - undefined symbols with -dllimport=all on Windows #3923

Merged
merged 1 commit into from
Feb 28, 2022
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 25 additions & 16 deletions gen/llvmhelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1607,7 +1607,7 @@ DValue *DtoSymbolAddress(const Loc &loc, Type *type, Declaration *decl) {
if (SymbolDeclaration *sdecl = decl->isSymbolDeclaration()) {
// this is the static initialiser (init symbol) for aggregates
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);
auto sd = ad->isStructDeclaration();

Expand Down Expand Up @@ -1733,24 +1733,33 @@ static bool isDefaultLibSymbol(Dsymbol *sym) {
(md->packages.length > 1 && md->packages.ptr[1] == Id::io)));
}

bool defineOnDeclare(Dsymbol* sym, bool isFunction) {
if (global.params.linkonceTemplates)
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 defineOnDeclare(Dsymbol* sym, bool) {
return global.params.linkonceTemplates && sym->isInstantiated();
}

bool dllimportDataSymbol(Dsymbol *sym) {
return sym->isExport() || global.params.dllimport == DLLImport::all ||
(global.params.dllimport == DLLImport::defaultLibsOnly &&
// exclude instantiated symbols from druntime/Phobos templates (see
// `defineOnDeclare()`)
!sym->isInstantiated() && isDefaultLibSymbol(sym));
if (!global.params.targetTriple->isOSWindows())
return false;

if (sym->isExport() || global.params.dllimport == DLLImport::all ||
(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,
Expand Down
3 changes: 1 addition & 2 deletions gen/llvmhelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,7 @@ llvm::Constant *buildStringLiteralConstant(StringExp *se, bool zeroTerm);
/// primarily for -linkonce-templates.
bool defineOnDeclare(Dsymbol *sym, bool isFunction);

/// Indicates whether the specified data symbol is a general dllimport
/// candidate.
/// Indicates whether the specified data symbol is to be declared as dllimport.
bool dllimportDataSymbol(Dsymbol *sym);

/// Tries to declare an LLVM global. If a variable with the same mangled name
Expand Down
8 changes: 6 additions & 2 deletions gen/tollvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,12 @@ void setVisibility(Dsymbol *sym, llvm::GlobalObject *obj) {

if (triple.isOSWindows()) {
bool isExported = sym->isExport();
// also export with -fvisibility=public without @hidden
if (!isExported && global.params.dllexport && !hasHiddenUDA) {
// Also export (non-linkonce_odr) symbols
// * 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);
}
// reset default visibility & DSO locality - on Windows, the DLL storage
Expand Down
12 changes: 1 addition & 11 deletions ir/iraggr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,7 @@ bool IrAggr::suppressTypeInfo() const {
//////////////////////////////////////////////////////////////////////////////

bool IrAggr::useDLLImport() const {
if (!global.params.targetTriple->isOSWindows())
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;
return dllimportDataSymbol(aggrdecl);
}

//////////////////////////////////////////////////////////////////////////////
Expand Down
8 changes: 2 additions & 6 deletions ir/irvar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,8 @@ void IrGlobal::declare() {
// dllimport isn't supported for thread-local globals (MSVC++ neither)
if (!V->isThreadlocal()) {
// implicitly include extern(D) globals with -dllimport
if (V->isExport() || (V->linkage == LINK::d && dllimportDataSymbol(V))) {
const bool isDefinedInRootModule =
!(V->storage_class & STCextern) && !V->inNonRoot();
if (!isDefinedInRootModule)
useDLLImport = true;
}
useDLLImport =
(V->isExport() || V->linkage == LINK::d) && dllimportDataSymbol(V);
}
}

Expand Down
12 changes: 12 additions & 0 deletions tests/codegen/dllimport_gh3916.d
Original file line number Diff line number Diff line change
@@ -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);
}