diff options
| author | Richard Cobbe <ricobbe@microsoft.com> | 2021-03-08 12:42:54 -0800 |
|---|---|---|
| committer | Richard Cobbe <ricobbe@microsoft.com> | 2021-06-04 18:01:35 -0700 |
| commit | 6aa45b71b11823a3140736536a93c5eac11ceecb (patch) | |
| tree | 05e4c4665f34ac3bd0713239586d1e9341e4dda6 /compiler/rustc_codegen_llvm/src | |
| parent | c79419af0721c614d050f09b95f076da09d37b0d (diff) | |
| download | rust-6aa45b71b11823a3140736536a93c5eac11ceecb.tar.gz rust-6aa45b71b11823a3140736536a93c5eac11ceecb.zip | |
Add first cut of functionality for #58713: support for #[link(kind = "raw-dylib")].
This does not yet support #[link_name] attributes on functions, the #[link_ordinal] attribute, #[link(kind = "raw-dylib")] on extern blocks in bin crates, or stdcall functions on 32-bit x86.
Diffstat (limited to 'compiler/rustc_codegen_llvm/src')
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/back/archive.rs | 83 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 34 |
2 files changed, 116 insertions, 1 deletions
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 261affe2c42..64416bced31 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -8,9 +8,11 @@ use std::ptr; use std::str; use crate::llvm::archive_ro::{ArchiveRO, Child}; -use crate::llvm::{self, ArchiveKind}; +use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport}; use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder}; use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME}; +use rustc_data_structures::temp_dir::MaybeTempDir; +use rustc_middle::middle::cstore::DllImport; use rustc_session::Session; use rustc_span::symbol::Symbol; @@ -61,6 +63,17 @@ fn archive_config<'a>(sess: &'a Session, output: &Path, input: Option<&Path>) -> } } +/// Map machine type strings to values of LLVM's MachineTypes enum. +fn llvm_machine_type(cpu: &str) -> LLVMMachineType { + match cpu { + "x86_64" => LLVMMachineType::AMD64, + "x86" => LLVMMachineType::I386, + "aarch64" => LLVMMachineType::ARM64, + "arm" => LLVMMachineType::ARM, + _ => panic!("unsupported cpu type {}", cpu), + } +} + impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { /// Creates a new static archive, ready for modifying the archive specified /// by `config`. @@ -175,6 +188,74 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { self.config.sess.fatal(&format!("failed to build archive: {}", e)); } } + + fn inject_dll_import_lib( + &mut self, + lib_name: &str, + dll_imports: &[DllImport], + tmpdir: &MaybeTempDir, + ) { + let output_path = { + let mut output_path: PathBuf = tmpdir.as_ref().to_path_buf(); + output_path.push(format!("{}_imports", lib_name)); + output_path.with_extension("lib") + }; + + // we've checked for \0 characters in the library name already + let dll_name_z = CString::new(lib_name).unwrap(); + // All import names are Rust identifiers and therefore cannot contain \0 characters. + // FIXME: when support for #[link_name] implemented, ensure that import.name values don't + // have any \0 characters + let import_name_vector: Vec<CString> = dll_imports + .iter() + .map(if self.config.sess.target.arch == "x86" { + |import: &DllImport| CString::new(format!("_{}", import.name.to_string())).unwrap() + } else { + |import: &DllImport| CString::new(import.name.to_string()).unwrap() + }) + .collect(); + + let output_path_z = rustc_fs_util::path_to_c_string(&output_path); + + tracing::trace!("invoking LLVMRustWriteImportLibrary"); + tracing::trace!(" dll_name {:#?}", dll_name_z); + tracing::trace!(" output_path {}", output_path.display()); + tracing::trace!( + " import names: {}", + dll_imports.iter().map(|import| import.name.to_string()).collect::<Vec<_>>().join(", "), + ); + + let ffi_exports: Vec<LLVMRustCOFFShortExport> = import_name_vector + .iter() + .map(|name_z| LLVMRustCOFFShortExport::from_name(name_z.as_ptr())) + .collect(); + let result = unsafe { + crate::llvm::LLVMRustWriteImportLibrary( + dll_name_z.as_ptr(), + output_path_z.as_ptr(), + ffi_exports.as_ptr(), + ffi_exports.len(), + llvm_machine_type(&self.config.sess.target.arch) as u16, + !self.config.sess.target.is_like_msvc, + ) + }; + + if result == crate::llvm::LLVMRustResult::Failure { + self.config.sess.fatal(&format!( + "Error creating import library for {}: {}", + lib_name, + llvm::last_error().unwrap_or("unknown LLVM error".to_string()) + )); + } + + self.add_archive(&output_path, |_| false).unwrap_or_else(|e| { + self.config.sess.fatal(&format!( + "failed to add native library {}: {}", + output_path.display(), + e + )); + }); + } } impl<'a> LlvmArchiveBuilder<'a> { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 115aa74dcc4..91923251018 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -29,6 +29,31 @@ pub enum LLVMRustResult { Success, Failure, } + +// Rust version of the C struct with the same name in rustc_llvm/llvm-wrapper/RustWrapper.cpp. +#[repr(C)] +pub struct LLVMRustCOFFShortExport { + pub name: *const c_char, +} + +impl LLVMRustCOFFShortExport { + pub fn from_name(name: *const c_char) -> LLVMRustCOFFShortExport { + LLVMRustCOFFShortExport { name } + } +} + +/// Translation of LLVM's MachineTypes enum, defined in llvm\include\llvm\BinaryFormat\COFF.h. +/// +/// We include only architectures supported on Windows. +#[derive(Copy, Clone, PartialEq)] +#[repr(C)] +pub enum LLVMMachineType { + AMD64 = 0x8664, + I386 = 0x14c, + ARM64 = 0xaa64, + ARM = 0x01c0, +} + // Consts for the LLVM CallConv type, pre-cast to usize. /// LLVM CallingConv::ID. Should we wrap this? @@ -2265,6 +2290,15 @@ extern "C" { ) -> &'a mut RustArchiveMember<'a>; pub fn LLVMRustArchiveMemberFree(Member: &'a mut RustArchiveMember<'a>); + pub fn LLVMRustWriteImportLibrary( + ImportName: *const c_char, + Path: *const c_char, + Exports: *const LLVMRustCOFFShortExport, + NumExports: usize, + Machine: u16, + MinGW: bool, + ) -> LLVMRustResult; + pub fn LLVMRustSetDataLayoutFromTargetMachine(M: &'a Module, TM: &'a TargetMachine); pub fn LLVMRustBuildOperandBundleDef( |
