Skip to content

Commit

Permalink
[clang] [MinGW] Add the option -fno-auto-import
Browse files Browse the repository at this point in the history
In GCC, the .refptr stubs are only generated for x86_64, and only
for code models medium and larger (and medium is the default for
x86_64 since this was introduced). They can be omitted for
projects that are conscious about performance and size, and don't
need automatically importing dll data members, by passing -mcmodel=small.

In Clang/LLVM, such .refptr stubs are generated for any potentially
symbol reference that might end up autoimported. The .refptr stubs
are emitted for three separate reasons:
- Without .refptr stubs, undefined symbols are mostly referenced
  with 32 bit wide relocations. If the symbol ends up autoimported
  from a different DLL, a 32 bit relative offset might not be
  enough to reference data in a different DLL, depending on runtime
  loader layout.
- Without .refptr stubs, the runtime pseudo relocation mechanism
  will need to temporarily make sections read-write-executable
  if there are such relocations in the text section
- On ARM and AArch64, the immediate addressing encoded into
  instructions isn't in the form of a plain 32 bit relative offset,
  but is expressed with various bits scattered throughout two
  instructions - the mingw runtime pseudo relocation mechanism
  doesn't support updating offsets in that form.

If autoimporting is known not to be needed, the user can now
compile with -fno-auto-import, avoiding the extra overhead of
the .refptr stubs.

However, omitting them is potentially fragile as the code
might still rely on automatically importing some symbol without
the developer knowing. If this happens, linking still usually
will succeed, but users may encounter issues at runtime.

Therefore, if the new option -fno-auto-import is passed to the compiler
when driving linking, it passes the flag --disable-auto-import to
the linker, making sure that no symbols actually are autoimported
when the generated code doesn't expect it.

Differential Revision: https://reviews.llvm.org/D61670
  • Loading branch information
mstorsjo committed Sep 1, 2023
1 parent 898bf53 commit f9f2fdc
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 5 deletions.
8 changes: 8 additions & 0 deletions clang/docs/ReleaseNotes.rst
Expand Up @@ -300,6 +300,14 @@ Windows Support
``MSInheritanceAttr`` attributes to class template instantiations created
for explicit template instantiation declarations.

- The ``-fno-auto-import`` option was added for MinGW targets. The option both
affects code generation (inhibiting generating indirection via ``.refptr``
stubs for potentially auto imported symbols, generating smaller and more
efficient code) and linking (making the linker error out on such cases).
If the option only is used during code generation but not when linking,
linking may succeed but the resulting executables may expose issues at
runtime.

LoongArch Support
^^^^^^^^^^^^^^^^^

Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/CodeGenOptions.def
Expand Up @@ -38,6 +38,7 @@ CODEGENOPT(PreserveAsmComments, 1, 1) ///< -dA, -fno-preserve-as-comments.
CODEGENOPT(AssumeSaneOperatorNew , 1, 1) ///< implicit __attribute__((malloc)) operator new
CODEGENOPT(AssumeUniqueVTables , 1, 1) ///< Assume a class has only one vtable.
CODEGENOPT(Autolink , 1, 1) ///< -fno-autolink
CODEGENOPT(AutoImport , 1, 1) ///< -fno-auto-import
CODEGENOPT(ObjCAutoRefCountExceptions , 1, 0) ///< Whether ARC should be EH-safe.
CODEGENOPT(Backchain , 1, 0) ///< -mbackchain
CODEGENOPT(ControlFlowGuardNoChecks , 1, 0) ///< -cfguard-no-checks
Expand Down
11 changes: 11 additions & 0 deletions clang/include/clang/Driver/Options.td
Expand Up @@ -1469,6 +1469,17 @@ defm autolink : BoolFOption<"autolink",
"Disable generation of linker directives for automatic library linking">,
PosFlag<SetTrue>>;

let Flags = [TargetSpecific] in {
defm auto_import : BoolFOption<"auto-import",
CodeGenOpts<"AutoImport">, DefaultTrue,
NegFlag<SetFalse, [], [ClangOption, CC1Option],
"MinGW specific. Disable support for automatic dllimport in code generation "
"and linking">,
PosFlag<SetTrue, [], [], "MinGW specific. Enable code generation support for "
"automatic dllimport, and enable support for it in the linker. "
"Enabled by default.">>;
} // let Flags = [TargetSpecific]

// In the future this option will be supported by other offloading
// languages and accept other values such as CPU/GPU architectures,
// offload kinds and target aliases.
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/CodeGen/CodeGenModule.cpp
Expand Up @@ -1419,6 +1419,7 @@ static bool shouldAssumeDSOLocal(const CodeGenModule &CGM,
return false;

const llvm::Triple &TT = CGM.getTriple();
const auto &CGOpts = CGM.getCodeGenOpts();
if (TT.isWindowsGNUEnvironment()) {
// In MinGW, variables without DLLImport can still be automatically
// imported from a DLL by the linker; don't mark variables that
Expand All @@ -1429,7 +1430,8 @@ static bool shouldAssumeDSOLocal(const CodeGenModule &CGM,
// such variables can't be marked as DSO local. (Native TLS variables
// can't be dllimported at all, though.)
if (GV->isDeclarationForLinker() && isa<llvm::GlobalVariable>(GV) &&
(!GV->isThreadLocal() || CGM.getCodeGenOpts().EmulatedTLS))
(!GV->isThreadLocal() || CGM.getCodeGenOpts().EmulatedTLS) &&
CGOpts.AutoImport)
return false;
}

Expand All @@ -1452,7 +1454,6 @@ static bool shouldAssumeDSOLocal(const CodeGenModule &CGM,
return false;

// If this is not an executable, don't assume anything is local.
const auto &CGOpts = CGM.getCodeGenOpts();
llvm::Reloc::Model RM = CGOpts.RelocationModel;
const auto &LOpts = CGM.getLangOpts();
if (RM != llvm::Reloc::Static && !LOpts.PIE) {
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Expand Up @@ -5623,6 +5623,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-mms-bitfields");
}

if (Triple.isWindowsGNUEnvironment()) {
Args.addOptOutFlag(CmdArgs, options::OPT_fauto_import,
options::OPT_fno_auto_import);
}

// Non-PIC code defaults to -fdirect-access-external-data while PIC code
// defaults to -fno-direct-access-external-data. Pass the option if different
// from the default.
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Driver/ToolChains/MinGW.cpp
Expand Up @@ -169,6 +169,10 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
CmdArgs.push_back("--no-demangle");

if (!Args.hasFlag(options::OPT_fauto_import, options::OPT_fno_auto_import,
true))
CmdArgs.push_back("--disable-auto-import");

if (Arg *A = Args.getLastArg(options::OPT_mguard_EQ)) {
StringRef GuardArgs = A->getValue();
if (GuardArgs == "none")
Expand Down
8 changes: 5 additions & 3 deletions clang/test/CodeGen/dso-local-executable.c
Expand Up @@ -9,12 +9,14 @@
// COFF-DAG: define dso_local ptr @zed()
// COFF-DAG: declare dllimport void @import_func()

// RUN: %clang_cc1 -triple x86_64-w64-mingw32 -emit-llvm %s -o - | FileCheck --check-prefixes=MINGW,MINGW-NATIVE_TLS %s
// RUN: %clang_cc1 -triple x86_64-w64-mingw32 -emit-llvm %s -o - -femulated-tls | FileCheck --check-prefixes=MINGW,MINGW-EMUTLS %s
// RUN: %clang_cc1 -triple x86_64-w64-mingw32 -emit-llvm %s -o - | FileCheck --check-prefixes=MINGW,MINGW-NATIVE_TLS,MINGW-AUTO-IMPORT %s
// RUN: %clang_cc1 -triple x86_64-w64-mingw32 -emit-llvm %s -o - -fno-auto-import | FileCheck --check-prefixes=MINGW,MINGW-NATIVE_TLS,MINGW-NO-AUTO-IMPORT %s
// RUN: %clang_cc1 -triple x86_64-w64-mingw32 -emit-llvm %s -o - -femulated-tls | FileCheck --check-prefixes=MINGW,MINGW-EMUTLS,MINGW-AUTO-IMPORT %s
// MINGW: @baz = dso_local global i32 42
// MINGW-NEXT: @import_var = external dllimport global i32
// MINGW-NEXT: @weak_bar = extern_weak global i32
// MINGW-NEXT: @bar = external global i32
// MINGW-AUTO-IMPORT-NEXT: @bar = external global i32
// MINGW-NO-AUTO-IMPORT-NEXT: @bar = external dso_local global i32
// MINGW-NEXT: @local_thread_var = dso_local thread_local global i32 42
// MINGW-NATIVE_TLS-NEXT: @thread_var = external dso_local thread_local global i32
// MINGW-EMUTLS-NEXT: @thread_var = external thread_local global i32
Expand Down
15 changes: 15 additions & 0 deletions clang/test/Driver/mingw-auto-import.c
@@ -0,0 +1,15 @@
// By default, we don't pass any -fauto-import to -cc1, as that's the default.
//
// RUN: %clang --target=x86_64-w64-windows-gnu -### %s 2>&1 | FileCheck --check-prefixes=DEFAULT %s
// RUN: %clang --target=x86_64-w64-windows-gnu -fno-auto-import -fauto-import -### %s 2>&1 | FileCheck --check-prefixes=DEFAULT %s
// DEFAULT: "-cc1"
// DEFAULT-NOT: no-auto-import
// DEFAULT-NOT: --disable-auto-import

// When compiling with -fno-auto-import, we pass -fno-auto-import to -cc1
// and --disable-auto-import to the linker.
//
// RUN: %clang --target=x86_64-w64-windows-gnu -fauto-import -fno-auto-import -### %s 2>&1 | FileCheck --check-prefixes=NO_AUTOIMPORT %s
// NO_AUTOIMPORT: "-cc1"
// NO_AUTOIMPORT: "-fno-auto-import"
// NO_AUTOIMPORT: "--disable-auto-import"

0 comments on commit f9f2fdc

Please sign in to comment.