Skip to content

Commit f847388

Browse files
committed
Implementation of import_name_type
1 parent a8a33cf commit f847388

31 files changed

+614
-46
lines changed

compiler/rustc_codegen_llvm/src/back/archive.rs

+10-24
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ use std::path::{Path, PathBuf};
88
use std::ptr;
99
use std::str;
1010

11+
use crate::common;
1112
use crate::llvm::archive_ro::{ArchiveRO, Child};
1213
use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
1314
use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
14-
use rustc_session::cstore::{DllCallingConvention, DllImport};
15+
use rustc_session::cstore::DllImport;
1516
use rustc_session::Session;
1617

1718
/// Helper for adding many files to an archive.
@@ -111,21 +112,18 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
111112
};
112113

113114
let target = &sess.target;
114-
let mingw_gnu_toolchain = target.vendor == "pc"
115-
&& target.os == "windows"
116-
&& target.env == "gnu"
117-
&& target.abi.is_empty();
115+
let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(target);
118116

119117
let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = dll_imports
120118
.iter()
121119
.map(|import: &DllImport| {
122120
if sess.target.arch == "x86" {
123121
(
124-
LlvmArchiveBuilder::i686_decorated_name(import, mingw_gnu_toolchain),
125-
import.ordinal,
122+
common::i686_decorated_name(import, mingw_gnu_toolchain, false),
123+
import.ordinal(),
126124
)
127125
} else {
128-
(import.name.to_string(), import.ordinal)
126+
(import.name.to_string(), import.ordinal())
129127
}
130128
})
131129
.collect();
@@ -159,6 +157,9 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
159157
}
160158
};
161159

160+
// --no-leading-underscore: For the `import_name_type` feature to work, we need to be
161+
// able to control the *exact* spelling of each of the symbols that are being imported:
162+
// hence we don't want `dlltool` adding leading underscores automatically.
162163
let dlltool = find_binutils_dlltool(sess);
163164
let result = std::process::Command::new(dlltool)
164165
.args([
@@ -168,6 +169,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
168169
lib_name,
169170
"-l",
170171
output_path.to_str().unwrap(),
172+
"--no-leading-underscore",
171173
])
172174
.output();
173175

@@ -322,22 +324,6 @@ impl<'a> LlvmArchiveBuilder<'a> {
322324
ret
323325
}
324326
}
325-
326-
fn i686_decorated_name(import: &DllImport, mingw: bool) -> String {
327-
let name = import.name;
328-
let prefix = if mingw { "" } else { "_" };
329-
330-
match import.calling_convention {
331-
DllCallingConvention::C => format!("{}{}", prefix, name),
332-
DllCallingConvention::Stdcall(arg_list_size) => {
333-
format!("{}{}@{}", prefix, name, arg_list_size)
334-
}
335-
DllCallingConvention::Fastcall(arg_list_size) => format!("@{}@{}", name, arg_list_size),
336-
DllCallingConvention::Vectorcall(arg_list_size) => {
337-
format!("{}@@{}", name, arg_list_size)
338-
}
339-
}
340-
}
341327
}
342328

343329
fn string_to_io_error(s: String) -> io::Error {

compiler/rustc_codegen_llvm/src/callee.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
77
use crate::abi::FnAbiLlvmExt;
88
use crate::attributes;
9+
use crate::common;
910
use crate::context::CodegenCx;
1011
use crate::llvm;
1112
use crate::value::Value;
@@ -79,13 +80,18 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
7980
llfn
8081
}
8182
} else {
82-
let llfn = cx.declare_fn(sym, fn_abi);
83+
let instance_def_id = instance.def_id();
84+
let llfn = if tcx.sess.target.arch == "x86" &&
85+
let Some(dllimport) = common::get_dllimport(tcx, instance_def_id, sym)
86+
{
87+
cx.declare_fn(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&tcx.sess.target), true), fn_abi)
88+
} else {
89+
cx.declare_fn(sym, fn_abi)
90+
};
8391
debug!("get_fn: not casting pointer!");
8492

8593
attributes::from_fn_attrs(cx, llfn, instance);
8694

87-
let instance_def_id = instance.def_id();
88-
8995
// Apply an appropriate linkage/visibility value to our item that we
9096
// just declared.
9197
//

compiler/rustc_codegen_llvm/src/common.rs

+76
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,17 @@ use crate::value::Value;
1010
use rustc_ast::Mutability;
1111
use rustc_codegen_ssa::mir::place::PlaceRef;
1212
use rustc_codegen_ssa::traits::*;
13+
use rustc_hir::def_id::DefId;
1314
use rustc_middle::bug;
1415
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
1516
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
17+
use rustc_middle::ty::TyCtxt;
18+
use rustc_session::cstore::{DllCallingConvention, DllImport, PeImportNameType};
1619
use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer, Size};
20+
use rustc_target::spec::Target;
1721

1822
use libc::{c_char, c_uint};
23+
use std::fmt::Write;
1924
use tracing::debug;
2025

2126
/*
@@ -357,3 +362,74 @@ fn hi_lo_to_u128(lo: u64, hi: u64) -> u128 {
357362
fn try_as_const_integral(v: &Value) -> Option<&ConstantInt> {
358363
unsafe { llvm::LLVMIsAConstantInt(v) }
359364
}
365+
366+
pub(crate) fn get_dllimport<'tcx>(
367+
tcx: TyCtxt<'tcx>,
368+
id: DefId,
369+
name: &str,
370+
) -> Option<&'tcx DllImport> {
371+
tcx.native_library(id)
372+
.map(|lib| lib.dll_imports.iter().find(|di| di.name.as_str() == name))
373+
.flatten()
374+
}
375+
376+
pub(crate) fn is_mingw_gnu_toolchain(target: &Target) -> bool {
377+
target.vendor == "pc" && target.os == "windows" && target.env == "gnu" && target.abi.is_empty()
378+
}
379+
380+
pub(crate) fn i686_decorated_name(
381+
dll_import: &DllImport,
382+
mingw: bool,
383+
disable_name_mangling: bool,
384+
) -> String {
385+
let name = dll_import.name.as_str();
386+
387+
let (add_prefix, add_suffix) = match dll_import.import_name_type {
388+
Some(PeImportNameType::NoPrefix) => (false, true),
389+
Some(PeImportNameType::Undecorated) => (false, false),
390+
_ => (true, true),
391+
};
392+
393+
// Worst case: +1 for disable name mangling, +1 for prefix, +4 for suffix (@@__).
394+
let mut decorated_name = String::with_capacity(name.len() + 6);
395+
396+
if disable_name_mangling {
397+
// LLVM uses a binary 1 ('\x01') prefix to a name to indicate that mangling needs to be disabled.
398+
decorated_name.push('\x01');
399+
}
400+
401+
let prefix = if add_prefix && dll_import.is_fn {
402+
match dll_import.calling_convention {
403+
DllCallingConvention::C | DllCallingConvention::Vectorcall(_) => None,
404+
DllCallingConvention::Stdcall(_) => (!mingw
405+
|| dll_import.import_name_type == Some(PeImportNameType::Decorated))
406+
.then_some('_'),
407+
DllCallingConvention::Fastcall(_) => Some('@'),
408+
}
409+
} else if !dll_import.is_fn && !mingw {
410+
// For static variables, prefix with '_' on MSVC.
411+
Some('_')
412+
} else {
413+
None
414+
};
415+
if let Some(prefix) = prefix {
416+
decorated_name.push(prefix);
417+
}
418+
419+
decorated_name.push_str(name);
420+
421+
if add_suffix && dll_import.is_fn {
422+
match dll_import.calling_convention {
423+
DllCallingConvention::C => {}
424+
DllCallingConvention::Stdcall(arg_list_size)
425+
| DllCallingConvention::Fastcall(arg_list_size) => {
426+
write!(&mut decorated_name, "@{}", arg_list_size).unwrap();
427+
}
428+
DllCallingConvention::Vectorcall(arg_list_size) => {
429+
write!(&mut decorated_name, "@@{}", arg_list_size).unwrap();
430+
}
431+
}
432+
}
433+
434+
decorated_name
435+
}

compiler/rustc_codegen_llvm/src/consts.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::base;
2-
use crate::common::CodegenCx;
2+
use crate::common::{self, CodegenCx};
33
use crate::debuginfo;
44
use crate::llvm::{self, True};
55
use crate::llvm_util;
@@ -160,7 +160,7 @@ fn check_and_apply_linkage<'ll, 'tcx>(
160160
attrs: &CodegenFnAttrs,
161161
ty: Ty<'tcx>,
162162
sym: &str,
163-
span_def_id: DefId,
163+
def_id: DefId,
164164
) -> &'ll Value {
165165
let llty = cx.layout_of(ty).llvm_type(cx);
166166
if let Some(linkage) = attrs.linkage {
@@ -175,7 +175,7 @@ fn check_and_apply_linkage<'ll, 'tcx>(
175175
cx.layout_of(mt.ty).llvm_type(cx)
176176
} else {
177177
cx.sess().span_fatal(
178-
cx.tcx.def_span(span_def_id),
178+
cx.tcx.def_span(def_id),
179179
"must have type `*const T` or `*mut T` due to `#[linkage]` attribute",
180180
)
181181
};
@@ -194,14 +194,18 @@ fn check_and_apply_linkage<'ll, 'tcx>(
194194
real_name.push_str(sym);
195195
let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| {
196196
cx.sess().span_fatal(
197-
cx.tcx.def_span(span_def_id),
197+
cx.tcx.def_span(def_id),
198198
&format!("symbol `{}` is already defined", &sym),
199199
)
200200
});
201201
llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
202202
llvm::LLVMSetInitializer(g2, g1);
203203
g2
204204
}
205+
} else if cx.tcx.sess.target.arch == "x86" &&
206+
let Some(dllimport) = common::get_dllimport(cx.tcx, def_id, sym)
207+
{
208+
cx.declare_global(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&cx.tcx.sess.target), true), llty)
205209
} else {
206210
// Generate an external declaration.
207211
// FIXME(nagisa): investigate whether it can be changed into define_global

compiler/rustc_feature/src/builtin_attrs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
335335
// ABI, linking, symbols, and FFI
336336
ungated!(
337337
link, Normal,
338-
template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...""#),
338+
template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated""#),
339339
DuplicatesOk,
340340
),
341341
ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),

compiler/rustc_metadata/src/native_libs.rs

+74-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_errors::struct_span_err;
55
use rustc_hir as hir;
66
use rustc_hir::def::DefKind;
77
use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
8-
use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib};
8+
use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib, PeImportNameType};
99
use rustc_session::parse::feature_err;
1010
use rustc_session::utils::NativeLibKind;
1111
use rustc_session::Session;
@@ -61,6 +61,7 @@ impl<'tcx> Collector<'tcx> {
6161
let mut modifiers = None;
6262
let mut cfg = None;
6363
let mut wasm_import_module = None;
64+
let mut import_name_type = None;
6465
for item in items.iter() {
6566
match item.name_or_empty() {
6667
sym::name => {
@@ -199,9 +200,51 @@ impl<'tcx> Collector<'tcx> {
199200
};
200201
wasm_import_module = Some((link_wasm_import_module, item.span()));
201202
}
203+
sym::import_name_type => {
204+
if import_name_type.is_some() {
205+
let msg = "multiple `import_name_type` arguments in a single `#[link]` attribute";
206+
sess.span_err(item.span(), msg);
207+
continue;
208+
}
209+
let Some(link_import_name_type) = item.value_str() else {
210+
let msg = "import name type must be of the form `import_name_type = \"string\"`";
211+
sess.span_err(item.span(), msg);
212+
continue;
213+
};
214+
if self.tcx.sess.target.arch != "x86" {
215+
let msg = "import name type is only supported on x86";
216+
sess.span_err(item.span(), msg);
217+
continue;
218+
}
219+
220+
let link_import_name_type = match link_import_name_type.as_str() {
221+
"decorated" => PeImportNameType::Decorated,
222+
"noprefix" => PeImportNameType::NoPrefix,
223+
"undecorated" => PeImportNameType::Undecorated,
224+
import_name_type => {
225+
let msg = format!(
226+
"unknown import name type `{import_name_type}`, expected one of: \
227+
decorated, noprefix, undecorated"
228+
);
229+
sess.span_err(item.span(), msg);
230+
continue;
231+
}
232+
};
233+
if !features.raw_dylib {
234+
let span = item.name_value_literal_span().unwrap();
235+
feature_err(
236+
&sess.parse_sess,
237+
sym::raw_dylib,
238+
span,
239+
"import name type is unstable",
240+
)
241+
.emit();
242+
}
243+
import_name_type = Some((link_import_name_type, item.span()));
244+
}
202245
_ => {
203246
let msg = "unexpected `#[link]` argument, expected one of: \
204-
name, kind, modifiers, cfg, wasm_import_module";
247+
name, kind, modifiers, cfg, wasm_import_module, import_name_type";
205248
sess.span_err(item.span(), msg);
206249
}
207250
}
@@ -315,6 +358,14 @@ impl<'tcx> Collector<'tcx> {
315358
.emit();
316359
}
317360

361+
// Do this outside of the loop so that `import_name_type` can be specified before `kind`.
362+
if let Some((_, span)) = import_name_type {
363+
if kind != Some(NativeLibKind::RawDylib) {
364+
let msg = "import name type can only be used with link kind `raw-dylib`";
365+
sess.span_err(span, msg);
366+
}
367+
}
368+
318369
let dll_imports = match kind {
319370
Some(NativeLibKind::RawDylib) => {
320371
if let Some((name, span)) = name && name.as_str().contains('\0') {
@@ -325,7 +376,13 @@ impl<'tcx> Collector<'tcx> {
325376
}
326377
foreign_mod_items
327378
.iter()
328-
.map(|child_item| self.build_dll_import(abi, child_item))
379+
.map(|child_item| {
380+
self.build_dll_import(
381+
abi,
382+
import_name_type.map(|(import_name_type, _)| import_name_type),
383+
child_item,
384+
)
385+
})
329386
.collect()
330387
}
331388
_ => {
@@ -486,7 +543,12 @@ impl<'tcx> Collector<'tcx> {
486543
.sum()
487544
}
488545

489-
fn build_dll_import(&self, abi: Abi, item: &hir::ForeignItemRef) -> DllImport {
546+
fn build_dll_import(
547+
&self,
548+
abi: Abi,
549+
import_name_type: Option<PeImportNameType>,
550+
item: &hir::ForeignItemRef,
551+
) -> DllImport {
490552
let calling_convention = if self.tcx.sess.target.arch == "x86" {
491553
match abi {
492554
Abi::C { .. } | Abi::Cdecl { .. } => DllCallingConvention::C,
@@ -518,11 +580,18 @@ impl<'tcx> Collector<'tcx> {
518580
}
519581
};
520582

583+
let import_name_type = self
584+
.tcx
585+
.codegen_fn_attrs(item.id.def_id)
586+
.link_ordinal
587+
.map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord)));
588+
521589
DllImport {
522590
name: item.ident.name,
523-
ordinal: self.tcx.codegen_fn_attrs(item.id.def_id).link_ordinal,
591+
import_name_type,
524592
calling_convention,
525593
span: item.span,
594+
is_fn: self.tcx.def_kind(item.id.def_id).is_fn_like(),
526595
}
527596
}
528597
}

0 commit comments

Comments
 (0)