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: <https://github.com/microsoft/windows-rs/issues/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`
This commit is contained in:
commit
60e8ab6ba8
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use rustc_codegen_ssa::back::archive::{
|
use rustc_codegen_ssa::back::archive::{
|
||||||
ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
|
ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
|
||||||
|
ImportLibraryItem,
|
||||||
};
|
};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
|
|
||||||
@ -16,7 +17,7 @@ fn create_dll_import_lib(
|
|||||||
&self,
|
&self,
|
||||||
_sess: &Session,
|
_sess: &Session,
|
||||||
_lib_name: &str,
|
_lib_name: &str,
|
||||||
_import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
|
_items: Vec<ImportLibraryItem>,
|
||||||
_output_path: &Path,
|
_output_path: &Path,
|
||||||
) {
|
) {
|
||||||
unimplemented!("creating dll imports is not yet supported");
|
unimplemented!("creating dll imports is not yet supported");
|
||||||
|
@ -44,6 +44,22 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
|
|||||||
let llfn = if tcx.sess.target.arch == "x86"
|
let llfn = if tcx.sess.target.arch == "x86"
|
||||||
&& let Some(dllimport) = crate::common::get_dllimport(tcx, instance_def_id, sym)
|
&& let Some(dllimport) = crate::common::get_dllimport(tcx, instance_def_id, sym)
|
||||||
{
|
{
|
||||||
|
// When calling functions in generated import libraries, MSVC needs
|
||||||
|
// the fully decorated name (as would have been in the declaring
|
||||||
|
// object file), but MinGW wants the name as exported (as would be
|
||||||
|
// in the def file) which may be missing decorations.
|
||||||
|
let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(&tcx.sess.target);
|
||||||
|
let llfn = cx.declare_fn(
|
||||||
|
&common::i686_decorated_name(
|
||||||
|
dllimport,
|
||||||
|
mingw_gnu_toolchain,
|
||||||
|
true,
|
||||||
|
!mingw_gnu_toolchain,
|
||||||
|
),
|
||||||
|
fn_abi,
|
||||||
|
Some(instance),
|
||||||
|
);
|
||||||
|
|
||||||
// Fix for https://github.com/rust-lang/rust/issues/104453
|
// Fix for https://github.com/rust-lang/rust/issues/104453
|
||||||
// On x86 Windows, LLVM uses 'L' as the prefix for any private
|
// On x86 Windows, LLVM uses 'L' as the prefix for any private
|
||||||
// global symbols, so when we create an undecorated function symbol
|
// 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
|
|||||||
// LLVM will prefix the name with `__imp_`. Ideally, we'd like the
|
// LLVM will prefix the name with `__imp_`. Ideally, we'd like the
|
||||||
// existing logic below to set the Storage Class, but it has an
|
// existing logic below to set the Storage Class, but it has an
|
||||||
// exemption for MinGW for backwards compatibility.
|
// exemption for MinGW for backwards compatibility.
|
||||||
let llfn = cx.declare_fn(
|
|
||||||
&common::i686_decorated_name(
|
|
||||||
dllimport,
|
|
||||||
common::is_mingw_gnu_toolchain(&tcx.sess.target),
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
fn_abi,
|
|
||||||
Some(instance),
|
|
||||||
);
|
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
|
llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
|
||||||
}
|
}
|
||||||
|
@ -194,16 +194,10 @@ fn check_and_apply_linkage<'ll, 'tcx>(
|
|||||||
unsafe { llvm::LLVMSetInitializer(g2, g1) };
|
unsafe { llvm::LLVMSetInitializer(g2, g1) };
|
||||||
g2
|
g2
|
||||||
} else if cx.tcx.sess.target.arch == "x86"
|
} else if cx.tcx.sess.target.arch == "x86"
|
||||||
|
&& common::is_mingw_gnu_toolchain(&cx.tcx.sess.target)
|
||||||
&& let Some(dllimport) = crate::common::get_dllimport(cx.tcx, def_id, sym)
|
&& let Some(dllimport) = crate::common::get_dllimport(cx.tcx, def_id, sym)
|
||||||
{
|
{
|
||||||
cx.declare_global(
|
cx.declare_global(&common::i686_decorated_name(dllimport, true, true, false), llty)
|
||||||
&common::i686_decorated_name(
|
|
||||||
dllimport,
|
|
||||||
common::is_mingw_gnu_toolchain(&cx.tcx.sess.target),
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
llty,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
// Generate an external declaration.
|
// Generate an external declaration.
|
||||||
// FIXME(nagisa): investigate whether it can be changed into define_global
|
// FIXME(nagisa): investigate whether it can be changed into define_global
|
||||||
|
@ -26,6 +26,35 @@
|
|||||||
DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile,
|
DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// An item to be included in an import library.
|
||||||
|
/// This is a slimmed down version of `COFFShortExport` from `ar-archive-writer`.
|
||||||
|
pub struct ImportLibraryItem {
|
||||||
|
/// The name to be exported.
|
||||||
|
pub name: String,
|
||||||
|
/// The ordinal to be exported, if any.
|
||||||
|
pub ordinal: Option<u16>,
|
||||||
|
/// The original, decorated name if `name` is not decorated.
|
||||||
|
pub symbol_name: Option<String>,
|
||||||
|
/// True if this is a data export, false if it is a function export.
|
||||||
|
pub is_data: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ImportLibraryItem> for COFFShortExport {
|
||||||
|
fn from(item: ImportLibraryItem) -> Self {
|
||||||
|
COFFShortExport {
|
||||||
|
name: item.name,
|
||||||
|
ext_name: None,
|
||||||
|
symbol_name: item.symbol_name,
|
||||||
|
alias_target: None,
|
||||||
|
ordinal: item.ordinal.unwrap_or(0),
|
||||||
|
noname: item.ordinal.is_some(),
|
||||||
|
data: item.is_data,
|
||||||
|
private: false,
|
||||||
|
constant: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ArchiveBuilderBuilder {
|
pub trait ArchiveBuilderBuilder {
|
||||||
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a>;
|
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a>;
|
||||||
|
|
||||||
@ -38,7 +67,7 @@ fn create_dll_import_lib(
|
|||||||
&self,
|
&self,
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
lib_name: &str,
|
lib_name: &str,
|
||||||
import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
|
items: Vec<ImportLibraryItem>,
|
||||||
output_path: &Path,
|
output_path: &Path,
|
||||||
) {
|
) {
|
||||||
if common::is_mingw_gnu_toolchain(&sess.target) {
|
if common::is_mingw_gnu_toolchain(&sess.target) {
|
||||||
@ -47,21 +76,16 @@ fn create_dll_import_lib(
|
|||||||
// that loaded but crashed with an AV upon calling one of the imported
|
// that loaded but crashed with an AV upon calling one of the imported
|
||||||
// functions. Therefore, use binutils to create the import library instead,
|
// functions. Therefore, use binutils to create the import library instead,
|
||||||
// by writing a .DEF file to the temp dir and calling binutils's dlltool.
|
// by writing a .DEF file to the temp dir and calling binutils's dlltool.
|
||||||
create_mingw_dll_import_lib(
|
create_mingw_dll_import_lib(sess, lib_name, items, output_path);
|
||||||
sess,
|
|
||||||
lib_name,
|
|
||||||
import_name_and_ordinal_vector,
|
|
||||||
output_path,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
trace!("creating import library");
|
trace!("creating import library");
|
||||||
trace!(" dll_name {:#?}", lib_name);
|
trace!(" dll_name {:#?}", lib_name);
|
||||||
trace!(" output_path {}", output_path.display());
|
trace!(" output_path {}", output_path.display());
|
||||||
trace!(
|
trace!(
|
||||||
" import names: {}",
|
" import names: {}",
|
||||||
import_name_and_ordinal_vector
|
items
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(name, _ordinal)| name.clone())
|
.map(|ImportLibraryItem { name, .. }| name.clone())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(", "),
|
.join(", "),
|
||||||
);
|
);
|
||||||
@ -79,20 +103,7 @@ fn create_dll_import_lib(
|
|||||||
.emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() }),
|
.emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() }),
|
||||||
};
|
};
|
||||||
|
|
||||||
let exports = import_name_and_ordinal_vector
|
let exports = items.into_iter().map(Into::into).collect::<Vec<_>>();
|
||||||
.iter()
|
|
||||||
.map(|(name, ordinal)| COFFShortExport {
|
|
||||||
name: name.to_string(),
|
|
||||||
ext_name: None,
|
|
||||||
symbol_name: None,
|
|
||||||
alias_target: None,
|
|
||||||
ordinal: ordinal.unwrap_or(0),
|
|
||||||
noname: ordinal.is_some(),
|
|
||||||
data: false,
|
|
||||||
private: false,
|
|
||||||
constant: false,
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let machine = match &*sess.target.arch {
|
let machine = match &*sess.target.arch {
|
||||||
"x86_64" => MachineTypes::AMD64,
|
"x86_64" => MachineTypes::AMD64,
|
||||||
"x86" => MachineTypes::I386,
|
"x86" => MachineTypes::I386,
|
||||||
@ -160,16 +171,16 @@ fn extract_bundled_libs<'a>(
|
|||||||
fn create_mingw_dll_import_lib(
|
fn create_mingw_dll_import_lib(
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
lib_name: &str,
|
lib_name: &str,
|
||||||
import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
|
items: Vec<ImportLibraryItem>,
|
||||||
output_path: &Path,
|
output_path: &Path,
|
||||||
) {
|
) {
|
||||||
let def_file_path = output_path.with_extension("def");
|
let def_file_path = output_path.with_extension("def");
|
||||||
|
|
||||||
let def_file_content = format!(
|
let def_file_content = format!(
|
||||||
"EXPORTS\n{}",
|
"EXPORTS\n{}",
|
||||||
import_name_and_ordinal_vector
|
items
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(name, ordinal)| {
|
.map(|ImportLibraryItem { name, ordinal, .. }| {
|
||||||
match ordinal {
|
match ordinal {
|
||||||
Some(n) => format!("{name} @{n} NONAME"),
|
Some(n) => format!("{name} @{n} NONAME"),
|
||||||
None => name,
|
None => name,
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
use tempfile::Builder as TempFileBuilder;
|
use tempfile::Builder as TempFileBuilder;
|
||||||
use tracing::{debug, info, warn};
|
use tracing::{debug, info, warn};
|
||||||
|
|
||||||
use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
|
use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder, ImportLibraryItem};
|
||||||
use super::command::Command;
|
use super::command::Command;
|
||||||
use super::linker::{self, Linker};
|
use super::linker::{self, Linker};
|
||||||
use super::metadata::{MetadataPosition, create_wrapper_file};
|
use super::metadata::{MetadataPosition, create_wrapper_file};
|
||||||
@ -495,16 +495,35 @@ fn create_dll_import_libs<'a>(
|
|||||||
|
|
||||||
let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(&sess.target);
|
let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(&sess.target);
|
||||||
|
|
||||||
let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = raw_dylib_imports
|
let items: Vec<ImportLibraryItem> = raw_dylib_imports
|
||||||
.iter()
|
.iter()
|
||||||
.map(|import: &DllImport| {
|
.map(|import: &DllImport| {
|
||||||
if sess.target.arch == "x86" {
|
if sess.target.arch == "x86" {
|
||||||
(
|
ImportLibraryItem {
|
||||||
common::i686_decorated_name(import, mingw_gnu_toolchain, false),
|
name: common::i686_decorated_name(
|
||||||
import.ordinal(),
|
import,
|
||||||
|
mingw_gnu_toolchain,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
ordinal: import.ordinal(),
|
||||||
|
symbol_name: import.is_missing_decorations().then(|| {
|
||||||
|
common::i686_decorated_name(
|
||||||
|
import,
|
||||||
|
mingw_gnu_toolchain,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
|
}),
|
||||||
|
is_data: !import.is_fn,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
(import.name.to_string(), import.ordinal())
|
ImportLibraryItem {
|
||||||
|
name: import.name.to_string(),
|
||||||
|
ordinal: import.ordinal(),
|
||||||
|
symbol_name: None,
|
||||||
|
is_data: !import.is_fn,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
@ -512,7 +531,7 @@ fn create_dll_import_libs<'a>(
|
|||||||
archive_builder_builder.create_dll_import_lib(
|
archive_builder_builder.create_dll_import_lib(
|
||||||
sess,
|
sess,
|
||||||
&raw_dylib_name,
|
&raw_dylib_name,
|
||||||
import_name_and_ordinal_vector,
|
items,
|
||||||
&output_path,
|
&output_path,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -187,12 +187,15 @@ pub fn i686_decorated_name(
|
|||||||
dll_import: &DllImport,
|
dll_import: &DllImport,
|
||||||
mingw: bool,
|
mingw: bool,
|
||||||
disable_name_mangling: bool,
|
disable_name_mangling: bool,
|
||||||
|
force_fully_decorated: bool,
|
||||||
) -> String {
|
) -> String {
|
||||||
let name = dll_import.name.as_str();
|
let name = dll_import.name.as_str();
|
||||||
|
|
||||||
let (add_prefix, add_suffix) = match dll_import.import_name_type {
|
let (add_prefix, add_suffix) = match (force_fully_decorated, dll_import.import_name_type) {
|
||||||
Some(PeImportNameType::NoPrefix) => (false, true),
|
// No prefix is a bit weird, in that LLVM/ar_archive_writer won't emit it, so we will
|
||||||
Some(PeImportNameType::Undecorated) => (false, false),
|
// ignore `force_fully_decorated` and always partially decorate it.
|
||||||
|
(_, Some(PeImportNameType::NoPrefix)) => (false, true),
|
||||||
|
(false, Some(PeImportNameType::Undecorated)) => (false, false),
|
||||||
_ => (true, true),
|
_ => (true, true),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -130,6 +130,11 @@ pub fn ordinal(&self) -> Option<u16> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_missing_decorations(&self) -> bool {
|
||||||
|
self.import_name_type == Some(PeImportNameType::Undecorated)
|
||||||
|
|| self.import_name_type == Some(PeImportNameType::NoPrefix)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calling convention for a function defined in an external library.
|
/// Calling convention for a function defined in an external library.
|
||||||
|
Loading…
Reference in New Issue
Block a user