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

Windows: Add -dllimport CLI option for more selective implicit dllimports #3763

Merged
merged 7 commits into from
Jun 18, 2021
Merged
12 changes: 10 additions & 2 deletions dmd/globals.d
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,14 @@ enum FeatureState : byte
enabled = 1 /// Specified as `-preview=`
}

version (IN_LLVM)
enum DLLImport : byte
{
none,
defaultLibsOnly, // only symbols from druntime/Phobos
all
}

// Put command line switches in here
extern (C++) struct Param
{
Expand Down Expand Up @@ -304,8 +312,8 @@ version (IN_LLVM)
bool linkonceTemplates; // -linkonce-templates

// Windows-specific:
bool dllexport; // dllexport ~all defined symbols?
bool dllimport; // dllimport data symbols not defined in any root module?
bool dllexport; // dllexport ~all defined symbols?
DLLImport dllimport; // dllimport data symbols not defined in any root module?
} // IN_LLVM
}

Expand Down
13 changes: 11 additions & 2 deletions dmd/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,15 @@ enum class FeatureState : signed char
enabled = 1 /// Specified as `-preview=`
};

#if IN_LLVM
enum class DLLImport : char
{
none,
defaultLibsOnly, // only symbols from druntime/Phobos
all
};
#endif

// Put command line switches in here
struct Param
{
Expand Down Expand Up @@ -279,8 +288,8 @@ struct Param
bool linkonceTemplates; // -linkonce-templates

// Windows-specific:
bool dllexport; // dllexport ~all defined symbols?
bool dllimport; // dllimport data symbols not defined in any root module?
bool dllexport; // dllexport ~all defined symbols?
DLLImport dllimport; // dllimport data symbols not defined in any root module?
#endif
};

Expand Down
3 changes: 3 additions & 0 deletions dmd/id.d
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,9 @@ immutable Msgtable[] msgtable =
{ "dcPointer", "Pointer" },
{ "dcReflect", "__dcompute_reflect" },
{ "RTInfoImpl" },

// IN_LLVM
{ "io" },
];


Expand Down
4 changes: 4 additions & 0 deletions dmd/id.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ struct Id
static Identifier *dcompute;
static Identifier *dcPointer;
static Identifier *object;
static Identifier *core;
static Identifier *etc;
static Identifier *std;
static Identifier *ensure;
static Identifier *require;
static Identifier *xopEquals;
Expand Down Expand Up @@ -90,5 +93,6 @@ struct Id
static Identifier *udaDynamicCompile;
static Identifier *udaDynamicCompileConst;
static Identifier *udaDynamicCompileEmit;
static Identifier *io;
#endif
};
16 changes: 16 additions & 0 deletions driver/cl_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,22 @@ cl::opt<SymbolVisibility> symbolVisibility(
"Only export symbols marked with 'export'"),
clEnumValN(SymbolVisibility::public_, "public", "Export all symbols")));

cl::opt<DLLImport, true> dllimport(
"dllimport", cl::ZeroOrMore, cl::location(global.params.dllimport),
cl::desc("Windows only: which extern(D) global variables to dllimport "
"implicitly if not defined in a root module"),
cl::values(
clEnumValN(DLLImport::none, "none",
"None (default with -link-defaultlib-shared=false)"),
clEnumValN(DLLImport::defaultLibsOnly, "defaultLibsOnly",
"Only druntime/Phobos symbols (default with "
"-link-defaultlib-shared and -fvisibility=hidden). May "
"likely need to be coupled with -linkonce-templates to "
"overcome linker errors wrt. instantiated symbols."),
clEnumValN(DLLImport::all, "all",
"All (default with -link-defaultlib-shared and "
"-fvisibility=public)")));

static cl::opt<bool, true> verbose("v", cl::desc("Verbose"), cl::ZeroOrMore,
cl::location(global.params.verbose));

Expand Down
1 change: 1 addition & 0 deletions driver/cl_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ extern FloatABI::Type floatABI;
extern cl::opt<bool> disableLinkerStripDead;
enum class SymbolVisibility { default_, hidden, public_ };
extern cl::opt<SymbolVisibility> symbolVisibility;
extern cl::opt<DLLImport, true> dllimport;
extern cl::opt<bool> noPLT;
extern cl::opt<bool> useDIP25;

Expand Down
13 changes: 9 additions & 4 deletions driver/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1090,10 +1090,15 @@ int cppmain() {
v == opts::SymbolVisibility::public_ ||
// default with -shared
(v == opts::SymbolVisibility::default_ && global.params.dll);
global.params.dllimport =
v == opts::SymbolVisibility::public_ ||
// enforced when linking against shared default libs
linkAgainstSharedDefaultLibs();
if (opts::dllimport.getNumOccurrences() == 0) {
global.params.dllimport =
!linkAgainstSharedDefaultLibs() ? DLLImport::none
: global.params.dllexport ? DLLImport::all
: DLLImport::defaultLibsOnly;
}
} else {
global.params.dllexport = false;
global.params.dllimport = DLLImport::none;
}

// allocate the target abi
Expand Down
32 changes: 32 additions & 0 deletions gen/llvmhelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1670,6 +1670,38 @@ std::string llvmTypeToString(llvm::Type *type) {
return result;
}

// Is the specified symbol defined in the druntime/Phobos libs?
// Note: fuzzy semantics for instantiated symbols, except with
// -linkonce-templates.
static bool isDefaultLibSymbol(Dsymbol *sym) {
if (defineOnDeclare(sym))
return false;

auto mod = sym->getModule();
if (!mod)
return false;

auto md = mod->md;
if (!md)
return false;

if (md->packages.length == 0)
return md->id == Id::object || md->id == Id::std;

auto p = md->packages.ptr[0];
return p == Id::core || p == Id::etc || p == Id::ldc ||
(p == Id::std &&
// 3rd-party package: std.io (https://github.com/MartinNowak/io/)
!((md->packages.length == 1 && md->id == Id::io) ||
(md->packages.length > 1 && md->packages.ptr[1] == Id::io)));
}

bool dllimportSymbol(Dsymbol *sym) {
return sym->isExport() || global.params.dllimport == DLLImport::all ||
(global.params.dllimport == DLLImport::defaultLibsOnly &&
isDefaultLibSymbol(sym));
}

llvm::GlobalVariable *declareGlobal(const Loc &loc, llvm::Module &module,
llvm::Type *type,
llvm::StringRef mangledName,
Expand Down
3 changes: 3 additions & 0 deletions gen/llvmhelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,9 @@ LLConstant *toConstantArray(LLType *ct, LLArrayType *at, T *str, size_t len,

llvm::Constant *buildStringLiteralConstant(StringExp *se, bool zeroTerm);

/// Indicates whether the specified symbol is a general dllimport candidate.
bool dllimportSymbol(Dsymbol *sym);

/// Tries to declare an LLVM global. If a variable with the same mangled name
/// already exists, checks if the types match and returns it instead.
///
Expand Down
5 changes: 3 additions & 2 deletions gen/modules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,9 @@ LLFunction *build_module_reference_and_ctor(const char *moduleMangle,
LLConstant *mref = gIR->module.getNamedGlobal(mrefIRMangle);
LLType *modulerefPtrTy = getPtrToType(modulerefTy);
if (!mref) {
mref = declareGlobal(Loc(), gIR->module, modulerefPtrTy, mrefIRMangle,
false, false, global.params.dllimport);
mref =
declareGlobal(Loc(), gIR->module, modulerefPtrTy, mrefIRMangle, false,
false, global.params.dllimport != DLLImport::none);
}
mref = DtoBitCast(mref, getPtrToType(modulerefPtrTy));

Expand Down
2 changes: 1 addition & 1 deletion gen/optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ bool ldc_optimize_module(llvm::Module *M) {

addOptimizationPasses(mpm, fpm, optLevel(), sizeLevel());

if (global.params.dllimport) {
if (global.params.dllimport != DLLImport::none) {
mpm.add(createDLLImportRelocationPass());
}

Expand Down
3 changes: 1 addition & 2 deletions gen/typinf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -439,8 +439,7 @@ void buildTypeInfo(TypeInfoDeclaration *decl) {
// immutable on the D side, and e.g. synchronized() can be used on the
// implicit monitor.
const bool isConstant = false;
// TODO: no dllimport when compiling druntime itself
const bool useDLLImport = isBuiltin && global.params.dllimport;
bool useDLLImport = isBuiltin && global.params.dllimport != DLLImport::none;
gvar = declareGlobal(decl->loc, gIR->module, type, irMangle, isConstant,
false, useDLLImport);
}
Expand Down
2 changes: 1 addition & 1 deletion ir/iraggr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ bool IrAggr::useDLLImport() const {
if (!global.params.targetTriple->isOSWindows())
return false;

if (global.params.dllimport || aggrdecl->isExport()) {
if (dllimportSymbol(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).
Expand Down
2 changes: 1 addition & 1 deletion ir/irmodule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ llvm::GlobalVariable *IrModule::moduleInfoSymbol() {

const auto irMangle = getIRMangledModuleInfoSymbolName(M);

const bool useDLLImport = global.params.dllimport && !M->isRoot();
const bool useDLLImport = !M->isRoot() && dllimportSymbol(M);

moduleInfoVar = declareGlobal(Loc(), gIR->module,
llvm::StructType::create(gIR->context()),
Expand Down
5 changes: 2 additions & 3 deletions ir/irvar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,8 @@ void IrGlobal::declare() {
if (global.params.targetTriple->isOSWindows()) {
// dllimport isn't supported for thread-local globals (MSVC++ neither)
if (!V->isThreadlocal()) {
// with -fvisibility=public / -link-defaultlib-shared, also include all
// extern(D) globals
if (V->isExport() || (global.params.dllimport && V->linkage == LINK::d)) {
// implicitly include extern(D) globals with -dllimport
if (V->isExport() || (V->linkage == LINK::d && dllimportSymbol(V))) {
const bool isDefinedInRootModule =
!(V->storage_class & STCextern) && !V->inNonRoot();
if (!isDefinedInRootModule)
Expand Down
6 changes: 3 additions & 3 deletions runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ macro(build_runtime_variant d_flags c_flags ld_flags lib_suffix path_suffix emit
AND NOT ${all_d_files_at_once})
set(phobos2_o "")
set(phobos2_bc "")
compile_phobos2("${phobos2_d_flags};-relocation-model=pic;-fvisibility=public"
compile_phobos2("${phobos2_d_flags};-relocation-model=pic;-fvisibility=public;-dllimport=all"
"${lib_suffix}${SHARED_LIB_SUFFIX}" "${path_suffix}"
"${emit_bc}" "${all_d_files_at_once}" "OFF" phobos2_o phobos2_bc)

Expand Down Expand Up @@ -753,15 +753,15 @@ macro(build_runtime_variant d_flags c_flags ld_flags lib_suffix path_suffix emit
# compile druntime with public visibility and extra `version (Shared)`
set(druntime_o "")
set(druntime_bc "")
compile_druntime("${druntime_d_flags};-relocation-model=pic;-fvisibility=public;-d-version=Shared"
compile_druntime("${druntime_d_flags};-relocation-model=pic;-fvisibility=public;-dllimport=none;-d-version=Shared"
"${lib_suffix}${SHARED_LIB_SUFFIX}" "${path_suffix}"
"OFF" "${all_d_files_at_once}" "OFF" druntime_o druntime_bc)

# compile Phobos with public visibility (and preferably to a single object file)
if(phobos2_common STREQUAL "")
set(phobos2_o "")
set(phobos2_bc "")
compile_phobos2("${phobos2_d_flags};-relocation-model=pic;-fvisibility=public"
compile_phobos2("${phobos2_d_flags};-relocation-model=pic;-fvisibility=public;-dllimport=all"
"${lib_suffix}${SHARED_LIB_SUFFIX}" "${path_suffix}"
"OFF" "${all_d_files_at_once}" "${all_d_files_at_once}" phobos2_o phobos2_bc)
endif()
Expand Down
2 changes: 1 addition & 1 deletion runtime/druntime
Submodule druntime updated 1 files
+5 −2 test/shared/Makefile
2 changes: 1 addition & 1 deletion runtime/phobos
Submodule phobos updated 1 files
+55 −29 std/getopt.d
6 changes: 3 additions & 3 deletions tests/codegen/fvisibility_dll.d
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

// REQUIRES: Windows

// generate DLL and import lib
// generate DLL and import lib (public visibility by default)
// RUN: %ldc %S/inputs/fvisibility_dll_lib.d -betterC -shared -of=%t_lib.dll

// compile, link and run the app; -link-defaultlib-shared for importing data symbols as dllimport
// RUN: %ldc %s -I%S/inputs -betterC -link-defaultlib-shared %t_lib.lib -of=%t.exe
// compile, link and run the app; `-dllimport=all` for dllimporting data symbols
// RUN: %ldc %s -I%S/inputs -betterC -dllimport=all %t_lib.lib -of=%t.exe
// RUN: %t.exe

import fvisibility_dll_lib;
Expand Down