Skip to content

Commit 60e8ab6

Browse files
Rollup merge of #130586 - dpaoliello:fixrawdylib, r=wesleywiser
Set "symbol name" in raw-dylib import libraries to the decorated name `windows-rs` received a bug report that mixing raw-dylib generated and the Windows SDK import libraries was causing linker failures: <microsoft/windows-rs#3285> The root cause turned out to be #124958, that is we are not including the decorated name in the import library and so the import name type is also not being correctly set. This change modifies the generation of import libraries to set the "symbol name" to the fully decorated name and correctly marks the import as being data vs function. Note that this also required some changes to how the symbol is named within Rust: for MSVC we now need to use the decorated name but for MinGW we still need to use partially decorated (or undecorated) name. Fixes#124958 Passing i686 MSVC and MinGW build: <https://github.com/rust-lang/rust/actions/runs/11000433888?pr=130586> r? `@ChrisDenton`
2 parents b91a3a0 + b2fd8a0 commit 60e8ab6

7 files changed

Lines changed: 95 additions & 55 deletions

File tree

‎compiler/rustc_codegen_gcc/src/archive.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::path::Path;
22

33
use rustc_codegen_ssa::back::archive::{
44
ArArchiveBuilder,ArchiveBuilder,ArchiveBuilderBuilder,DEFAULT_OBJECT_READER,
5+
ImportLibraryItem,
56
};
67
use rustc_session::Session;
78

@@ -16,7 +17,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
1617
&self,
1718
_sess:&Session,
1819
_lib_name:&str,
19-
_import_name_and_ordinal_vector:Vec<(String,Option<u16>)>,
20+
_items:Vec<ImportLibraryItem>,
2021
_output_path:&Path,
2122
){
2223
unimplemented!("creating dll imports is not yet supported");

‎compiler/rustc_codegen_llvm/src/callee.rs‎

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,22 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
4444
let llfn = if tcx.sess.target.arch == "x86"
4545
&& letSome(dllimport) = crate::common::get_dllimport(tcx, instance_def_id, sym)
4646
{
47+
// When calling functions in generated import libraries, MSVC needs
48+
// the fully decorated name (as would have been in the declaring
49+
// object file), but MinGW wants the name as exported (as would be
50+
// in the def file) which may be missing decorations.
51+
let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(&tcx.sess.target);
52+
let llfn = cx.declare_fn(
53+
&common::i686_decorated_name(
54+
dllimport,
55+
mingw_gnu_toolchain,
56+
true,
57+
!mingw_gnu_toolchain,
58+
),
59+
fn_abi,
60+
Some(instance),
61+
);
62+
4763
// Fix for https://github.com/rust-lang/rust/issues/104453
4864
// On x86 Windows, LLVM uses 'L' as the prefix for any private
4965
// global symbols, so when we create an undecorated function symbol
@@ -55,15 +71,6 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
5571
// LLVM will prefix the name with `__imp_`. Ideally, we'd like the
5672
// existing logic below to set the Storage Class, but it has an
5773
// exemption for MinGW for backwards compatibility.
58-
let llfn = cx.declare_fn(
59-
&common::i686_decorated_name(
60-
dllimport,
61-
common::is_mingw_gnu_toolchain(&tcx.sess.target),
62-
true,
63-
),
64-
fn_abi,
65-
Some(instance),
66-
);
6774
unsafe{
6875
llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
6976
}

‎compiler/rustc_codegen_llvm/src/consts.rs‎

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -194,16 +194,10 @@ fn check_and_apply_linkage<'ll, 'tcx>(
194194
unsafe{ llvm::LLVMSetInitializer(g2, g1)};
195195
g2
196196
}elseif cx.tcx.sess.target.arch == "x86"
197+
&& common::is_mingw_gnu_toolchain(&cx.tcx.sess.target)
197198
&& letSome(dllimport) = crate::common::get_dllimport(cx.tcx, def_id, sym)
198199
{
199-
cx.declare_global(
200-
&common::i686_decorated_name(
201-
dllimport,
202-
common::is_mingw_gnu_toolchain(&cx.tcx.sess.target),
203-
true,
204-
),
205-
llty,
206-
)
200+
cx.declare_global(&common::i686_decorated_name(dllimport,true,true,false), llty)
207201
}else{
208202
// Generate an external declaration.
209203
// FIXME(nagisa): investigate whether it can be changed into define_global

‎compiler/rustc_codegen_ssa/src/back/archive.rs‎

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,35 @@ use crate::errors::{
2626
DlltoolFailImportLibrary,ErrorCallingDllTool,ErrorCreatingImportLibrary,ErrorWritingDEFFile,
2727
};
2828

29+
/// An item to be included in an import library.
30+
/// This is a slimmed down version of `COFFShortExport` from `ar-archive-writer`.
31+
pubstructImportLibraryItem{
32+
/// The name to be exported.
33+
pubname:String,
34+
/// The ordinal to be exported, if any.
35+
pubordinal:Option<u16>,
36+
/// The original, decorated name if `name` is not decorated.
37+
pubsymbol_name:Option<String>,
38+
/// True if this is a data export, false if it is a function export.
39+
pubis_data:bool,
40+
}
41+
42+
implFrom<ImportLibraryItem>forCOFFShortExport{
43+
fnfrom(item:ImportLibraryItem) -> Self{
44+
COFFShortExport{
45+
name: item.name,
46+
ext_name:None,
47+
symbol_name: item.symbol_name,
48+
alias_target:None,
49+
ordinal: item.ordinal.unwrap_or(0),
50+
noname: item.ordinal.is_some(),
51+
data: item.is_data,
52+
private:false,
53+
constant:false,
54+
}
55+
}
56+
}
57+
2958
pubtraitArchiveBuilderBuilder{
3059
fnnew_archive_builder<'a>(&self,sess:&'aSession) -> Box<dynArchiveBuilder + 'a>;
3160

@@ -38,7 +67,7 @@ pub trait ArchiveBuilderBuilder {
3867
&self,
3968
sess:&Session,
4069
lib_name:&str,
41-
import_name_and_ordinal_vector:Vec<(String,Option<u16>)>,
70+
items:Vec<ImportLibraryItem>,
4271
output_path:&Path,
4372
){
4473
if common::is_mingw_gnu_toolchain(&sess.target){
@@ -47,21 +76,16 @@ pub trait ArchiveBuilderBuilder {
4776
// that loaded but crashed with an AV upon calling one of the imported
4877
// functions. Therefore, use binutils to create the import library instead,
4978
// by writing a .DEF file to the temp dir and calling binutils's dlltool.
50-
create_mingw_dll_import_lib(
51-
sess,
52-
lib_name,
53-
import_name_and_ordinal_vector,
54-
output_path,
55-
);
79+
create_mingw_dll_import_lib(sess, lib_name, items, output_path);
5680
}else{
5781
trace!("creating import library");
5882
trace!(" dll_name {:#?}", lib_name);
5983
trace!(" output_path {}", output_path.display());
6084
trace!(
6185
" import names: {}",
62-
import_name_and_ordinal_vector
86+
items
6387
.iter()
64-
.map(|(name,_ordinal)| name.clone())
88+
.map(|ImportLibraryItem{name,.. }| name.clone())
6589
.collect::<Vec<_>>()
6690
.join(", "),
6791
);
@@ -79,20 +103,7 @@ pub trait ArchiveBuilderBuilder {
79103
.emit_fatal(ErrorCreatingImportLibrary{ lib_name,error: error.to_string()}),
80104
};
81105

82-
let exports = import_name_and_ordinal_vector
83-
.iter()
84-
.map(|(name, ordinal)| COFFShortExport{
85-
name: name.to_string(),
86-
ext_name:None,
87-
symbol_name:None,
88-
alias_target:None,
89-
ordinal: ordinal.unwrap_or(0),
90-
noname: ordinal.is_some(),
91-
data:false,
92-
private:false,
93-
constant:false,
94-
})
95-
.collect::<Vec<_>>();
106+
let exports = items.into_iter().map(Into::into).collect::<Vec<_>>();
96107
let machine = match&*sess.target.arch{
97108
"x86_64" => MachineTypes::AMD64,
98109
"x86" => MachineTypes::I386,
@@ -160,16 +171,16 @@ pub trait ArchiveBuilderBuilder {
160171
fncreate_mingw_dll_import_lib(
161172
sess:&Session,
162173
lib_name:&str,
163-
import_name_and_ordinal_vector:Vec<(String,Option<u16>)>,
174+
items:Vec<ImportLibraryItem>,
164175
output_path:&Path,
165176
){
166177
let def_file_path = output_path.with_extension("def");
167178

168179
let def_file_content = format!(
169180
"EXPORTS\n{}",
170-
import_name_and_ordinal_vector
181+
items
171182
.into_iter()
172-
.map(|(name, ordinal)| {
183+
.map(|ImportLibraryItem{name, ordinal, .. }| {
173184
match ordinal {
174185
Some(n) => format!("{name} @{n} NONAME"),
175186
None => name,

‎compiler/rustc_codegen_ssa/src/back/link.rs‎

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use rustc_target::spec::{
4545
use tempfile::BuilderasTempFileBuilder;
4646
use tracing::{debug, info, warn};
4747

48-
usesuper::archive::{ArchiveBuilder,ArchiveBuilderBuilder};
48+
usesuper::archive::{ArchiveBuilder,ArchiveBuilderBuilder,ImportLibraryItem};
4949
usesuper::command::Command;
5050
usesuper::linker::{self,Linker};
5151
usesuper::metadata::{MetadataPosition, create_wrapper_file};
@@ -495,24 +495,43 @@ fn create_dll_import_libs<'a>(
495495

496496
let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(&sess.target);
497497

498-
letimport_name_and_ordinal_vector:Vec<(String,Option<u16>)> = raw_dylib_imports
498+
letitems:Vec<ImportLibraryItem> = raw_dylib_imports
499499
.iter()
500500
.map(|import:&DllImport| {
501501
if sess.target.arch == "x86"{
502-
(
503-
common::i686_decorated_name(import, mingw_gnu_toolchain,false),
504-
import.ordinal(),
505-
)
502+
ImportLibraryItem{
503+
name: common::i686_decorated_name(
504+
import,
505+
mingw_gnu_toolchain,
506+
false,
507+
false,
508+
),
509+
ordinal: import.ordinal(),
510+
symbol_name: import.is_missing_decorations().then(|| {
511+
common::i686_decorated_name(
512+
import,
513+
mingw_gnu_toolchain,
514+
false,
515+
true,
516+
)
517+
}),
518+
is_data: !import.is_fn,
519+
}
506520
}else{
507-
(import.name.to_string(), import.ordinal())
521+
ImportLibraryItem{
522+
name: import.name.to_string(),
523+
ordinal: import.ordinal(),
524+
symbol_name:None,
525+
is_data: !import.is_fn,
526+
}
508527
}
509528
})
510529
.collect();
511530

512531
archive_builder_builder.create_dll_import_lib(
513532
sess,
514533
&raw_dylib_name,
515-
import_name_and_ordinal_vector,
534+
items,
516535
&output_path,
517536
);
518537

‎compiler/rustc_codegen_ssa/src/common.rs‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,15 @@ pub fn i686_decorated_name(
187187
dll_import:&DllImport,
188188
mingw:bool,
189189
disable_name_mangling:bool,
190+
force_fully_decorated:bool,
190191
) -> String{
191192
let name = dll_import.name.as_str();
192193

193-
let(add_prefix, add_suffix) = match dll_import.import_name_type{
194-
Some(PeImportNameType::NoPrefix) => (false,true),
195-
Some(PeImportNameType::Undecorated) => (false,false),
194+
let(add_prefix, add_suffix) = match(force_fully_decorated, dll_import.import_name_type){
195+
// No prefix is a bit weird, in that LLVM/ar_archive_writer won't emit it, so we will
196+
// ignore `force_fully_decorated` and always partially decorate it.
197+
(_,Some(PeImportNameType::NoPrefix)) => (false,true),
198+
(false,Some(PeImportNameType::Undecorated)) => (false,false),
196199
_ => (true,true),
197200
};
198201

‎compiler/rustc_session/src/cstore.rs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ impl DllImport {
130130
None
131131
}
132132
}
133+
134+
pubfnis_missing_decorations(&self) -> bool{
135+
self.import_name_type == Some(PeImportNameType::Undecorated)
136+
|| self.import_name_type == Some(PeImportNameType::NoPrefix)
137+
}
133138
}
134139

135140
/// Calling convention for a function defined in an external library.

0 commit comments

Comments
 (0)