Skip to content
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
15 changes: 14 additions & 1 deletion compiler/rustc_codegen_llvm/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,20 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
let llfn = if tcx.sess.target.arch == "x86" &&
let Some(dllimport) = common::get_dllimport(tcx, instance_def_id, sym)
{
cx.declare_fn(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&tcx.sess.target), true), fn_abi)
// Fix for https://github.com/rust-lang/rust/issues/104453
// On x86 Windows, LLVM uses 'L' as the prefix for any private
// global symbols, so when we create an undecorated function symbol
// that begins with an 'L' LLVM misinterprets that as a private
// global symbol that it created and so fails the compilation at a
// later stage since such a symbol must have a definition.
//
// To avoid this, we set the Storage Class to "DllImport" so that
// LLVM will prefix the name with `__imp_`. Ideally, we'd like the
// existing logic below to set the Storage Class, but it has an
// exemption for MinGW for backwards compatability.
let llfn = cx.declare_fn(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&tcx.sess.target), true), fn_abi);
unsafe { llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); }
llfn
} else {
cx.declare_fn(sym, fn_abi)
};
Expand Down
8 changes: 8 additions & 0 deletions src/test/run-make/raw-dylib-import-name-type/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#[link(name = "extern", kind = "raw-dylib", import_name_type = "undecorated")]
extern "C" {
fn LooksLikeAPrivateGlobal(i: i32);
fn cdecl_fn_undecorated(i: i32);
#[link_name = "cdecl_fn_undecorated2"]
fn cdecl_fn_undecorated_renamed(i: i32);
Expand Down Expand Up @@ -84,6 +85,13 @@ extern {

pub fn main() {
unsafe {
// Regression test for #104453
// On x86 LLVM uses 'L' as the prefix for private globals (PrivateGlobalPrefix), which
// causes it to believe that undecorated functions starting with 'L' are actually temporary
// symbols that it generated, which causes a later check to fail as the symbols we are
// creating don't have definitions (whereas all temporary symbols do).
LooksLikeAPrivateGlobal(13);

cdecl_fn_undecorated(1);
cdecl_fn_undecorated_renamed(10);
cdecl_fn_noprefix(2);
Expand Down
5 changes: 5 additions & 0 deletions src/test/run-make/raw-dylib-import-name-type/extern.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#include <stdio.h>
#include <stdint.h>

void _cdecl LooksLikeAPrivateGlobal(int i) {
printf("LooksLikeAPrivateGlobal(%d)\n", i);
fflush(stdout);
}

void _cdecl cdecl_fn_undecorated(int i) {
printf("cdecl_fn_undecorated(%d)\n", i);
fflush(stdout);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
LIBRARY extern
EXPORTS
LooksLikeAPrivateGlobal
cdecl_fn_undecorated
cdecl_fn_undecorated2
cdecl_fn_noprefix
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
LIBRARY extern
EXPORTS
LooksLikeAPrivateGlobal
cdecl_fn_undecorated
cdecl_fn_undecorated2
cdecl_fn_noprefix
Expand Down
1 change: 1 addition & 0 deletions src/test/run-make/raw-dylib-import-name-type/output.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
LooksLikeAPrivateGlobal(13)
cdecl_fn_undecorated(1)
cdecl_fn_undecorated2(10)
cdecl_fn_noprefix(2)
Expand Down