From ba5ff075323a546ac33679561f147d332629ec68 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 25 Jul 2024 19:40:38 +0000 Subject: [PATCH 1/6] Introduce create_dll_import_libs function --- compiler/rustc_codegen_ssa/src/back/link.rs | 75 ++++++++++++--------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 55662bfc2cf..730d1ff73a0 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -390,17 +390,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 +484,27 @@ fn collate_raw_dylibs<'a>( .collect()) } +fn create_dll_import_libs<'a>( + sess: &Session, + archive_builder_builder: &dyn ArchiveBuilderBuilder, + used_libraries: impl IntoIterator, + tmpdir: &Path, + is_direct_dependency: bool, +) -> Result, ErrorGuaranteed> { + Ok(collate_raw_dylibs(sess, used_libraries)? + .into_iter() + .map(|(raw_dylib_name, raw_dylib_imports)| { + archive_builder_builder.create_dll_import_lib( + sess, + &raw_dylib_name, + &raw_dylib_imports, + tmpdir, + is_direct_dependency, + ) + }) + .collect()) +} + /// Create a static archive. /// /// This is essentially the same thing as an rlib, but it also involves adding all of the upstream @@ -2261,16 +2278,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* @@ -2295,16 +2310,14 @@ fn linker_with_args( .flatten() .collect::>(); 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 From ee89db9b172bf32bdf63bdcd841c4b3b8960ce0b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 25 Jul 2024 19:53:17 +0000 Subject: [PATCH 2/6] Move temp file name generation out of the create_dll_import_lib method --- compiler/rustc_codegen_cranelift/src/archive.rs | 7 +++---- compiler/rustc_codegen_gcc/src/archive.rs | 7 +++---- compiler/rustc_codegen_llvm/src/back/archive.rs | 14 ++++---------- compiler/rustc_codegen_ssa/src/back/archive.rs | 5 ++--- compiler/rustc_codegen_ssa/src/back/link.rs | 10 +++++++--- 5 files changed, 19 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index 1935005a08c..73ccf500a51 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -1,4 +1,4 @@ -use std::path::{Path, PathBuf}; +use std::path::Path; use rustc_codegen_ssa::back::archive::{ ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER, @@ -17,9 +17,8 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { sess: &Session, _lib_name: &str, _dll_imports: &[rustc_session::cstore::DllImport], - _tmpdir: &Path, - _is_direct_dependency: bool, - ) -> PathBuf { + _output_path: &Path, + ) { sess.dcx().fatal("raw-dylib is not yet supported by rustc_codegen_cranelift"); } } diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs index 36f5e0f8094..4a54d26daf7 100644 --- a/compiler/rustc_codegen_gcc/src/archive.rs +++ b/compiler/rustc_codegen_gcc/src/archive.rs @@ -1,4 +1,4 @@ -use std::path::{Path, PathBuf}; +use std::path::Path; use rustc_codegen_ssa::back::archive::{ ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER, @@ -18,9 +18,8 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { _sess: &Session, _lib_name: &str, _dll_imports: &[DllImport], - _tmpdir: &Path, - _is_direct_dependency: bool, - ) -> PathBuf { + _output_path: &Path, + ) { unimplemented!("creating dll imports is not yet supported"); } } diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 9a28428cb62..f8c767dea68 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -120,12 +120,8 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { sess: &Session, lib_name: &str, dll_imports: &[DllImport], - tmpdir: &Path, - is_direct_dependency: bool, - ) -> PathBuf { - let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" }; - let output_path = tmpdir.join(format!("{lib_name}{name_suffix}.lib")); - + output_path: &Path, + ) { let target = &sess.target; let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(target); @@ -149,7 +145,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { // that loaded but crashed with an AV upon calling one of the imported // functions. Therefore, use binutils to create the import library instead, // by writing a .DEF file to the temp dir and calling binutils's dlltool. - let def_file_path = tmpdir.join(format!("{lib_name}{name_suffix}.def")); + let def_file_path = output_path.with_extension("def"); let def_file_content = format!( "EXPORTS\n{}", @@ -279,9 +275,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { error: llvm::last_error().unwrap_or("unknown LLVM error".to_string()), }); } - }; - - output_path + } } } diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index fd39ef2649b..b4ee6514b04 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -31,9 +31,8 @@ pub trait ArchiveBuilderBuilder { sess: &Session, lib_name: &str, dll_imports: &[DllImport], - tmpdir: &Path, - is_direct_dependency: bool, - ) -> PathBuf; + output_path: &Path, + ); fn extract_bundled_libs<'a>( &'a self, diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 730d1ff73a0..4bdaeaf2996 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -494,13 +494,17 @@ fn create_dll_import_libs<'a>( 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")); + archive_builder_builder.create_dll_import_lib( sess, &raw_dylib_name, &raw_dylib_imports, - tmpdir, - is_direct_dependency, - ) + &output_path, + ); + + output_path }) .collect()) } From bb764bd406fbfbbd24ac162a1c9d10d349b5e386 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 25 Jul 2024 20:02:56 +0000 Subject: [PATCH 3/6] Move is_mingw_gnu_toolchain and i686_decorated_name to cg_ssa --- .../rustc_codegen_llvm/src/back/archive.rs | 2 +- compiler/rustc_codegen_llvm/src/callee.rs | 5 +- compiler/rustc_codegen_llvm/src/common.rs | 66 +------------------ compiler/rustc_codegen_llvm/src/consts.rs | 5 +- compiler/rustc_codegen_ssa/src/common.rs | 65 ++++++++++++++++++ 5 files changed, 73 insertions(+), 70 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index f8c767dea68..8ef9f8b855d 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -8,11 +8,11 @@ use rustc_codegen_ssa::back::archive::{ try_extract_macho_fat_archive, ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind, DEFAULT_OBJECT_READER, }; +use rustc_codegen_ssa::common; use rustc_session::cstore::DllImport; use rustc_session::Session; use tracing::trace; -use crate::common; use crate::errors::{ DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile, }; diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index c913bdebaaa..9030b3d848f 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -4,13 +4,14 @@ //! and methods are represented as just a fn ptr and not a full //! closure. +use rustc_codegen_ssa::common; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; use rustc_middle::ty::{self, Instance, TypeVisitableExt}; use tracing::debug; use crate::context::CodegenCx; use crate::value::Value; -use crate::{attributes, common, llvm}; +use crate::{attributes, llvm}; /// Codegens a reference to a fn/method item, monomorphizing and /// inlining as it goes. @@ -46,7 +47,7 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> } else { let instance_def_id = instance.def_id(); let llfn = if tcx.sess.target.arch == "x86" - && let Some(dllimport) = common::get_dllimport(tcx, instance_def_id, sym) + && let Some(dllimport) = crate::common::get_dllimport(tcx, instance_def_id, sym) { // Fix for https://github.com/rust-lang/rust/issues/104453 // On x86 Windows, LLVM uses 'L' as the prefix for any private diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 197bbb9ddbf..65f974c5689 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -1,7 +1,5 @@ //! Code that is useful in various codegen modules. -use std::fmt::Write; - use libc::{c_char, c_uint}; use rustc_ast::Mutability; use rustc_codegen_ssa::traits::*; @@ -10,9 +8,8 @@ use rustc_hir::def_id::DefId; use rustc_middle::bug; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; use rustc_middle::ty::TyCtxt; -use rustc_session::cstore::{DllCallingConvention, DllImport, PeImportNameType}; +use rustc_session::cstore::DllImport; use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer}; -use rustc_target::spec::Target; use tracing::debug; use crate::consts::const_alloc_to_llvm; @@ -379,64 +376,3 @@ pub(crate) fn get_dllimport<'tcx>( tcx.native_library(id) .and_then(|lib| lib.dll_imports.iter().find(|di| di.name.as_str() == name)) } - -pub(crate) fn is_mingw_gnu_toolchain(target: &Target) -> bool { - target.vendor == "pc" && target.os == "windows" && target.env == "gnu" && target.abi.is_empty() -} - -pub(crate) 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 { - 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_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index c3ea4a18a71..75b298f14ca 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -1,5 +1,6 @@ use std::ops::Range; +use rustc_codegen_ssa::common; use rustc_codegen_ssa::traits::*; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -18,7 +19,7 @@ use rustc_target::abi::{ }; use tracing::{debug, instrument, trace}; -use crate::common::{self, CodegenCx}; +use crate::common::CodegenCx; use crate::errors::{ InvalidMinimumAlignmentNotPowerOfTwo, InvalidMinimumAlignmentTooLarge, SymbolAlreadyDefined, }; @@ -195,7 +196,7 @@ fn check_and_apply_linkage<'ll, 'tcx>( g2 } } else if cx.tcx.sess.target.arch == "x86" - && let Some(dllimport) = common::get_dllimport(cx.tcx, def_id, sym) + && let Some(dllimport) = crate::common::get_dllimport(cx.tcx, def_id, sym) { cx.declare_global( &common::i686_decorated_name( diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index 741c0f090e9..73ed0471990 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 +} From 3c987cbe0284a954f025546e53b7007ae1cc95f1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 25 Jul 2024 20:08:40 +0000 Subject: [PATCH 4/6] Move computation of decorated names out of the create_dll_import_lib method --- .../rustc_codegen_cranelift/src/archive.rs | 2 +- compiler/rustc_codegen_gcc/src/archive.rs | 3 +-- .../rustc_codegen_llvm/src/back/archive.rs | 21 +++---------------- .../rustc_codegen_ssa/src/back/archive.rs | 3 +-- compiler/rustc_codegen_ssa/src/back/link.rs | 21 +++++++++++++++++-- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index 73ccf500a51..084654af09d 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -16,7 +16,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { &self, sess: &Session, _lib_name: &str, - _dll_imports: &[rustc_session::cstore::DllImport], + _import_name_and_ordinal_vector: Vec<(String, Option)>, _output_path: &Path, ) { sess.dcx().fatal("raw-dylib is not yet supported by rustc_codegen_cranelift"); diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs index 4a54d26daf7..0cee05f1cea 100644 --- a/compiler/rustc_codegen_gcc/src/archive.rs +++ b/compiler/rustc_codegen_gcc/src/archive.rs @@ -3,7 +3,6 @@ use std::path::Path; use rustc_codegen_ssa::back::archive::{ ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER, }; -use rustc_session::cstore::DllImport; use rustc_session::Session; pub(crate) struct ArArchiveBuilderBuilder; @@ -17,7 +16,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { &self, _sess: &Session, _lib_name: &str, - _dll_imports: &[DllImport], + _import_name_and_ordinal_vector: Vec<(String, Option)>, _output_path: &Path, ) { unimplemented!("creating dll imports is not yet supported"); diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 8ef9f8b855d..d6faa26507f 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -9,7 +9,6 @@ use rustc_codegen_ssa::back::archive::{ ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind, DEFAULT_OBJECT_READER, }; use rustc_codegen_ssa::common; -use rustc_session::cstore::DllImport; use rustc_session::Session; use tracing::trace; @@ -119,26 +118,12 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { &self, sess: &Session, lib_name: &str, - dll_imports: &[DllImport], + import_name_and_ordinal_vector: Vec<(String, Option)>, output_path: &Path, ) { let target = &sess.target; let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(target); - let import_name_and_ordinal_vector: Vec<(String, Option)> = dll_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(); - if mingw_gnu_toolchain { // The binutils linker used on -windows-gnu targets cannot read the import // libraries generated by LLVM: in our attempts, the linker produced an .EXE @@ -236,9 +221,9 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { trace!(" output_path {}", output_path.display()); trace!( " import names: {}", - dll_imports + import_name_and_ordinal_vector .iter() - .map(|import| import.name.to_string()) + .map(|(name, _ordinal)| name.clone()) .collect::>() .join(", "), ); diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index b4ee6514b04..0429f11f9ff 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -9,7 +9,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; @@ -30,7 +29,7 @@ pub trait ArchiveBuilderBuilder { &self, sess: &Session, lib_name: &str, - dll_imports: &[DllImport], + import_name_and_ordinal_vector: Vec<(String, Option)>, output_path: &Path, ); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 4bdaeaf2996..e6bd0e3d4f7 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) { @@ -497,10 +498,26 @@ fn create_dll_import_libs<'a>( 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)> = 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, - &raw_dylib_imports, + import_name_and_ordinal_vector, &output_path, ); From 216686bfa5025f2b4cd712c8d933c4d05599816e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 25 Jul 2024 20:17:59 +0000 Subject: [PATCH 5/6] Move mingw dlltool invocation to cg_ssa --- compiler/rustc_codegen_llvm/messages.ftl | 10 -- .../rustc_codegen_llvm/src/back/archive.rs | 138 ++---------------- compiler/rustc_codegen_llvm/src/errors.rs | 23 --- compiler/rustc_codegen_ssa/messages.ftl | 11 ++ .../rustc_codegen_ssa/src/back/archive.rs | 127 ++++++++++++++++ compiler/rustc_codegen_ssa/src/errors.rs | 22 +++ 6 files changed, 172 insertions(+), 159 deletions(-) diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index 1c126e79762..267da9325c3 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -1,23 +1,13 @@ codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err} -codegen_llvm_dlltool_fail_import_library = - Dlltool could not create import library with {$dlltool_path} {$dlltool_args}: - {$stdout} - {$stderr} - codegen_llvm_dynamic_linking_with_lto = cannot prefer dynamic linking when performing LTO .note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO -codegen_llvm_error_calling_dlltool = - Error calling dlltool '{$dlltool_path}': {$error} codegen_llvm_error_creating_import_library = Error creating import library for {$lib_name}: {$error} -codegen_llvm_error_writing_def_file = - Error writing .DEF file: {$error} - codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture codegen_llvm_from_llvm_diag = {$message} diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index d6faa26507f..d3fcbb247b4 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -1,20 +1,19 @@ //! A helper class for dealing with static archives -use std::ffi::{c_char, c_void, CStr, CString, OsString}; +use std::ffi::{c_char, c_void, CStr, CString}; use std::path::{Path, PathBuf}; -use std::{env, io, mem, ptr, str}; +use std::{io, mem, ptr, str}; use rustc_codegen_ssa::back::archive::{ - try_extract_macho_fat_archive, ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder, - ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind, DEFAULT_OBJECT_READER, + create_mingw_dll_import_lib, try_extract_macho_fat_archive, ArArchiveBuilder, + ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind, + DEFAULT_OBJECT_READER, }; use rustc_codegen_ssa::common; use rustc_session::Session; use tracing::trace; -use crate::errors::{ - DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile, -}; +use crate::errors::ErrorCreatingImportLibrary; use crate::llvm::archive_ro::{ArchiveRO, Child}; use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport}; @@ -121,95 +120,18 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { import_name_and_ordinal_vector: Vec<(String, Option)>, output_path: &Path, ) { - let target = &sess.target; - let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(target); - - if mingw_gnu_toolchain { + if common::is_mingw_gnu_toolchain(&sess.target) { // The binutils linker used on -windows-gnu targets cannot read the import // libraries generated by LLVM: in our attempts, the linker produced an .EXE // that loaded but crashed with an AV upon calling one of the imported // functions. Therefore, use binutils to create the import library instead, // by writing a .DEF file to the temp dir and calling binutils's dlltool. - 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::>() - .join("\n") + create_mingw_dll_import_lib( + sess, + lib_name, + import_name_and_ordinal_vector, + output_path, ); - - 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::>() - .join(" "), - stdout: String::from_utf8_lossy(&output.stdout), - stderr: String::from_utf8_lossy(&output.stderr), - }) - } - _ => {} - } } else { // we've checked for \0 characters in the library name already let dll_name_z = CString::new(lib_name).unwrap(); @@ -434,39 +356,3 @@ impl<'a> LlvmArchiveBuilder<'a> { fn string_to_io_error(s: String) -> io::Error { io::Error::new(io::ErrorKind::Other, format!("bad archive: {s}")) } - -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 -} diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index a3957bc52a5..7e53d32ce8c 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -1,4 +1,3 @@ -use std::borrow::Cow; use std::ffi::CString; use std::path::Path; @@ -71,28 +70,6 @@ pub(crate) struct InvalidMinimumAlignmentTooLarge { #[diag(codegen_llvm_sanitizer_memtag_requires_mte)] pub(crate) struct SanitizerMemtagRequiresMte; -#[derive(Diagnostic)] -#[diag(codegen_llvm_error_writing_def_file)] -pub(crate) struct ErrorWritingDEFFile { - pub error: std::io::Error, -} - -#[derive(Diagnostic)] -#[diag(codegen_llvm_error_calling_dlltool)] -pub(crate) struct ErrorCallingDllTool<'a> { - pub dlltool_path: Cow<'a, str>, - pub error: std::io::Error, -} - -#[derive(Diagnostic)] -#[diag(codegen_llvm_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_llvm_dynamic_linking_with_lto)] #[note] diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 000fe2e3ce0..24359f70509 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -25,8 +25,19 @@ codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$e codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error} +codegen_ssa_dlltool_fail_import_library = + Dlltool could not create import library with {$dlltool_path} {$dlltool_args}: + {$stdout} + {$stderr} + +codegen_ssa_error_calling_dlltool = + Error calling dlltool '{$dlltool_path}': {$error} + codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$error} +codegen_ssa_error_writing_def_file = + Error writing .DEF file: {$error} + codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)` codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 0429f11f9ff..df5cc58eca6 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}; @@ -16,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; @@ -70,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)>, + 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::>() + .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::>() + .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/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 46d7cfe87e6..f846e679860 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1024,6 +1024,28 @@ pub struct FailedToGetLayout<'tcx> { pub err: LayoutError<'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 { From f58e737554bebd34ac794d02b6e018bf20857788 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 25 Jul 2024 20:23:12 +0000 Subject: [PATCH 6/6] Update ar_archive_writer to 0.3.3 Version 0.3.1 has added support for writing import libraries. Version 0.3.2 fixed creating archives containing members of import libraries. Version 0.3.3 fixed building on big-endian systems. --- Cargo.lock | 15 +++------------ compiler/rustc_codegen_ssa/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1a7d7e3f5d7..c76ac3b559e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -231,11 +231,11 @@ dependencies = [ [[package]] name = "ar_archive_writer" -version = "0.3.0" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8412a2d690663356cba5a2532f3ed55d1e8090743bc6695b88403b27df67733" +checksum = "3f2bcb7cf51decfbbfc7ef476e28b0775b13e5eb1190f8b7df145cd53d4f4374" dependencies = [ - "object 0.35.0", + "object 0.36.2", ] [[package]] @@ -2573,15 +2573,6 @@ dependencies = [ "ruzstd 0.5.0", ] -[[package]] -name = "object" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" -dependencies = [ - "memchr", -] - [[package]] name = "object" version = "0.36.2" diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 2767ad5ec9c..6e1c323cbd0 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -ar_archive_writer = "0.3.0" +ar_archive_writer = "0.3.3" arrayvec = { version = "0.7", default-features = false } bitflags = "2.4.1" cc = "1.0.90"