diff options
| author | bors <bors@rust-lang.org> | 2024-08-07 14:10:46 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-08-07 14:10:46 +0000 |
| commit | 8d0066922b14cee3175e8c141e5e909fa6d9a6eb (patch) | |
| tree | 30c9da0e9f2be154bbce28f6c9dc50f3d2cdcdbd /compiler/rustc_codegen_ssa/src | |
| parent | 9bad7ba324099d124c77c5b06aebf68e11763f7b (diff) | |
| parent | 920cb642a4708e52e6b92f39f224cb5c855b8cec (diff) | |
| download | rust-8d0066922b14cee3175e8c141e5e909fa6d9a6eb.tar.gz rust-8d0066922b14cee3175e8c141e5e909fa6d9a6eb.zip | |
Auto merge of #128783 - GuillaumeGomez:rollup-2kvpg7s, r=GuillaumeGomez
Rollup of 9 pull requests Successful merges: - #128206 (Make create_dll_import_lib easier to implement) - #128424 (minor `effects` cleanups) - #128527 (More information for fully-qualified suggestion when there are multiple impls) - #128656 (Enable msvc for run-make/rust-lld) - #128683 (bootstrap: clear miri's ui test deps when rustc changes) - #128700 (Migrate `simd-ffi` `run-make` test to rmake) - #128753 (Don't arbitrarily choose one upper bound for hidden captured region error message) - #128757 (Migrate `pgo-gen-lto` `run-make` test to rmake) - #128758 (Specify a minimum supported version for VxWorks) Failed merges: - #128679 (codegen: better centralize function declaration attribute computation) r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'compiler/rustc_codegen_ssa/src')
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/archive.rs | 135 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/link.rs | 98 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/common.rs | 65 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/errors.rs | 22 |
4 files changed, 283 insertions, 37 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 4f93b7b23c6..ce55d99f506 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -1,4 +1,6 @@ +use std::env; use std::error::Error; +use std::ffi::OsString; use std::fs::{self, File}; use std::io::{self, Write}; use std::path::{Path, PathBuf}; @@ -9,7 +11,6 @@ use object::read::archive::ArchiveFile; use object::read::macho::FatArch; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::memmap::Mmap; -use rustc_session::cstore::DllImport; use rustc_session::Session; use rustc_span::symbol::Symbol; use tempfile::Builder as TempFileBuilder; @@ -17,6 +18,7 @@ use tempfile::Builder as TempFileBuilder; use super::metadata::search_for_section; // Re-exporting for rustc_codegen_llvm::back::archive pub use crate::errors::{ArchiveBuildFailure, ExtractBundledLibsError, UnknownArchiveKind}; +use crate::errors::{DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorWritingDEFFile}; pub trait ArchiveBuilderBuilder { fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a>; @@ -30,10 +32,9 @@ pub trait ArchiveBuilderBuilder { &self, sess: &Session, lib_name: &str, - dll_imports: &[DllImport], - tmpdir: &Path, - is_direct_dependency: bool, - ) -> PathBuf; + import_name_and_ordinal_vector: Vec<(String, Option<u16>)>, + output_path: &Path, + ); fn extract_bundled_libs<'a>( &'a self, @@ -72,6 +73,130 @@ pub trait ArchiveBuilderBuilder { } } +pub fn create_mingw_dll_import_lib( + sess: &Session, + lib_name: &str, + import_name_and_ordinal_vector: Vec<(String, Option<u16>)>, + output_path: &Path, +) { + let def_file_path = output_path.with_extension("def"); + + let def_file_content = format!( + "EXPORTS\n{}", + import_name_and_ordinal_vector + .into_iter() + .map(|(name, ordinal)| { + match ordinal { + Some(n) => format!("{name} @{n} NONAME"), + None => name, + } + }) + .collect::<Vec<String>>() + .join("\n") + ); + + match std::fs::write(&def_file_path, def_file_content) { + Ok(_) => {} + Err(e) => { + sess.dcx().emit_fatal(ErrorWritingDEFFile { error: e }); + } + }; + + // --no-leading-underscore: For the `import_name_type` feature to work, we need to be + // able to control the *exact* spelling of each of the symbols that are being imported: + // hence we don't want `dlltool` adding leading underscores automatically. + let dlltool = find_binutils_dlltool(sess); + let temp_prefix = { + let mut path = PathBuf::from(&output_path); + path.pop(); + path.push(lib_name); + path + }; + // dlltool target architecture args from: + // https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69 + let (dlltool_target_arch, dlltool_target_bitness) = match sess.target.arch.as_ref() { + "x86_64" => ("i386:x86-64", "--64"), + "x86" => ("i386", "--32"), + "aarch64" => ("arm64", "--64"), + "arm" => ("arm", "--32"), + _ => panic!("unsupported arch {}", sess.target.arch), + }; + let mut dlltool_cmd = std::process::Command::new(&dlltool); + dlltool_cmd + .arg("-d") + .arg(def_file_path) + .arg("-D") + .arg(lib_name) + .arg("-l") + .arg(&output_path) + .arg("-m") + .arg(dlltool_target_arch) + .arg("-f") + .arg(dlltool_target_bitness) + .arg("--no-leading-underscore") + .arg("--temp-prefix") + .arg(temp_prefix); + + match dlltool_cmd.output() { + Err(e) => { + sess.dcx().emit_fatal(ErrorCallingDllTool { + dlltool_path: dlltool.to_string_lossy(), + error: e, + }); + } + // dlltool returns '0' on failure, so check for error output instead. + Ok(output) if !output.stderr.is_empty() => { + sess.dcx().emit_fatal(DlltoolFailImportLibrary { + dlltool_path: dlltool.to_string_lossy(), + dlltool_args: dlltool_cmd + .get_args() + .map(|arg| arg.to_string_lossy()) + .collect::<Vec<_>>() + .join(" "), + stdout: String::from_utf8_lossy(&output.stdout), + stderr: String::from_utf8_lossy(&output.stderr), + }) + } + _ => {} + } +} + +fn find_binutils_dlltool(sess: &Session) -> OsString { + assert!(sess.target.options.is_like_windows && !sess.target.options.is_like_msvc); + if let Some(dlltool_path) = &sess.opts.cg.dlltool { + return dlltool_path.clone().into_os_string(); + } + + let tool_name: OsString = if sess.host.options.is_like_windows { + // If we're compiling on Windows, always use "dlltool.exe". + "dlltool.exe" + } else { + // On other platforms, use the architecture-specific name. + match sess.target.arch.as_ref() { + "x86_64" => "x86_64-w64-mingw32-dlltool", + "x86" => "i686-w64-mingw32-dlltool", + "aarch64" => "aarch64-w64-mingw32-dlltool", + + // For non-standard architectures (e.g., aarch32) fallback to "dlltool". + _ => "dlltool", + } + } + .into(); + + // NOTE: it's not clear how useful it is to explicitly search PATH. + for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) { + let full_path = dir.join(&tool_name); + if full_path.is_file() { + return full_path.into_os_string(); + } + } + + // The user didn't specify the location of the dlltool binary, and we weren't able + // to find the appropriate one on the PATH. Just return the name of the tool + // and let the invocation fail with a hopefully useful error message. + tool_name +} + pub trait ArchiveBuilder { fn add_file(&mut self, path: &Path); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 653895380be..45a92fd03d5 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -51,7 +51,8 @@ use super::linker::{self, Linker}; use super::metadata::{create_wrapper_file, MetadataPosition}; use super::rpath::{self, RPathConfig}; use crate::{ - errors, looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib, + common, errors, looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, + NativeLib, }; pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) { @@ -390,17 +391,13 @@ fn link_rlib<'a>( } } - for (raw_dylib_name, raw_dylib_imports) in - collate_raw_dylibs(sess, codegen_results.crate_info.used_libraries.iter())? - { - let output_path = archive_builder_builder.create_dll_import_lib( - sess, - &raw_dylib_name, - &raw_dylib_imports, - tmpdir.as_ref(), - true, - ); - + for output_path in create_dll_import_libs( + sess, + archive_builder_builder, + codegen_results.crate_info.used_libraries.iter(), + tmpdir.as_ref(), + true, + )? { ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| { sess.dcx().emit_fatal(errors::AddNativeLibrary { library_path: output_path, error }); }); @@ -488,6 +485,47 @@ fn collate_raw_dylibs<'a>( .collect()) } +fn create_dll_import_libs<'a>( + sess: &Session, + archive_builder_builder: &dyn ArchiveBuilderBuilder, + used_libraries: impl IntoIterator<Item = &'a NativeLib>, + tmpdir: &Path, + is_direct_dependency: bool, +) -> Result<Vec<PathBuf>, ErrorGuaranteed> { + Ok(collate_raw_dylibs(sess, used_libraries)? + .into_iter() + .map(|(raw_dylib_name, raw_dylib_imports)| { + let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" }; + let output_path = tmpdir.join(format!("{raw_dylib_name}{name_suffix}.lib")); + + let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(&sess.target); + + let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = raw_dylib_imports + .iter() + .map(|import: &DllImport| { + if sess.target.arch == "x86" { + ( + common::i686_decorated_name(import, mingw_gnu_toolchain, false), + import.ordinal(), + ) + } else { + (import.name.to_string(), import.ordinal()) + } + }) + .collect(); + + archive_builder_builder.create_dll_import_lib( + sess, + &raw_dylib_name, + import_name_and_ordinal_vector, + &output_path, + ); + + output_path + }) + .collect()) +} + /// Create a static archive. /// /// This is essentially the same thing as an rlib, but it also involves adding all of the upstream @@ -2305,16 +2343,14 @@ fn linker_with_args( ); // Link with the import library generated for any raw-dylib functions. - for (raw_dylib_name, raw_dylib_imports) in - collate_raw_dylibs(sess, codegen_results.crate_info.used_libraries.iter())? - { - cmd.add_object(&archive_builder_builder.create_dll_import_lib( - sess, - &raw_dylib_name, - &raw_dylib_imports, - tmpdir, - true, - )); + for output_path in create_dll_import_libs( + sess, + archive_builder_builder, + codegen_results.crate_info.used_libraries.iter(), + tmpdir, + true, + )? { + cmd.add_object(&output_path); } // As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case // they are used within inlined functions or instantiated generic functions. We do this *after* @@ -2339,16 +2375,14 @@ fn linker_with_args( .flatten() .collect::<Vec<_>>(); native_libraries_from_nonstatics.sort_unstable_by(|a, b| a.name.as_str().cmp(b.name.as_str())); - for (raw_dylib_name, raw_dylib_imports) in - collate_raw_dylibs(sess, native_libraries_from_nonstatics)? - { - cmd.add_object(&archive_builder_builder.create_dll_import_lib( - sess, - &raw_dylib_name, - &raw_dylib_imports, - tmpdir, - false, - )); + for output_path in create_dll_import_libs( + sess, + archive_builder_builder, + native_libraries_from_nonstatics, + tmpdir, + false, + )? { + cmd.add_object(&output_path); } // Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index a972c0cd99d..bfb1d217eae 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -4,7 +4,9 @@ use rustc_hir::LangItem; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, Instance, TyCtxt}; use rustc_middle::{bug, mir, span_bug}; +use rustc_session::cstore::{DllCallingConvention, DllImport, PeImportNameType}; use rustc_span::Span; +use rustc_target::spec::Target; use crate::traits::*; @@ -176,3 +178,66 @@ pub fn asm_const_to_str<'tcx>( _ => span_bug!(sp, "asm const has bad type {}", ty_and_layout.ty), } } + +pub fn is_mingw_gnu_toolchain(target: &Target) -> bool { + target.vendor == "pc" && target.os == "windows" && target.env == "gnu" && target.abi.is_empty() +} + +pub fn i686_decorated_name( + dll_import: &DllImport, + mingw: bool, + disable_name_mangling: bool, +) -> String { + let name = dll_import.name.as_str(); + + let (add_prefix, add_suffix) = match dll_import.import_name_type { + Some(PeImportNameType::NoPrefix) => (false, true), + Some(PeImportNameType::Undecorated) => (false, false), + _ => (true, true), + }; + + // Worst case: +1 for disable name mangling, +1 for prefix, +4 for suffix (@@__). + let mut decorated_name = String::with_capacity(name.len() + 6); + + if disable_name_mangling { + // LLVM uses a binary 1 ('\x01') prefix to a name to indicate that mangling needs to be disabled. + decorated_name.push('\x01'); + } + + let prefix = if add_prefix && dll_import.is_fn { + match dll_import.calling_convention { + DllCallingConvention::C | DllCallingConvention::Vectorcall(_) => None, + DllCallingConvention::Stdcall(_) => (!mingw + || dll_import.import_name_type == Some(PeImportNameType::Decorated)) + .then_some('_'), + DllCallingConvention::Fastcall(_) => Some('@'), + } + } else if !dll_import.is_fn && !mingw { + // For static variables, prefix with '_' on MSVC. + Some('_') + } else { + None + }; + if let Some(prefix) = prefix { + decorated_name.push(prefix); + } + + decorated_name.push_str(name); + + if add_suffix && dll_import.is_fn { + use std::fmt::Write; + + match dll_import.calling_convention { + DllCallingConvention::C => {} + DllCallingConvention::Stdcall(arg_list_size) + | DllCallingConvention::Fastcall(arg_list_size) => { + write!(&mut decorated_name, "@{arg_list_size}").unwrap(); + } + DllCallingConvention::Vectorcall(arg_list_size) => { + write!(&mut decorated_name, "@@{arg_list_size}").unwrap(); + } + } + } + + decorated_name +} diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 2d1eae630cf..94bf0ab34e2 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1027,6 +1027,28 @@ pub struct FailedToGetLayout<'tcx> { } #[derive(Diagnostic)] +#[diag(codegen_ssa_dlltool_fail_import_library)] +pub(crate) struct DlltoolFailImportLibrary<'a> { + pub dlltool_path: Cow<'a, str>, + pub dlltool_args: String, + pub stdout: Cow<'a, str>, + pub stderr: Cow<'a, str>, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_error_writing_def_file)] +pub(crate) struct ErrorWritingDEFFile { + pub error: std::io::Error, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_error_calling_dlltool)] +pub(crate) struct ErrorCallingDllTool<'a> { + pub dlltool_path: Cow<'a, str>, + pub error: std::io::Error, +} + +#[derive(Diagnostic)] #[diag(codegen_ssa_error_creating_remark_dir)] pub struct ErrorCreatingRemarkDir { pub error: std::io::Error, |
