Skip to content

Commit

Permalink
Add support for raw-dylib
Browse files Browse the repository at this point in the history
  • Loading branch information
dpaoliello committed Aug 2, 2024
1 parent 395181c commit 92d6d33
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 91 deletions.
14 changes: 12 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ cranelift-object = { version = "0.110.1" }
target-lexicon = "0.12.0"
gimli = { version = "0.28", default-features = false, features = ["write"]}
object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
ar_archive_writer = "0.3.2"

indexmap = "2.0.0"
libloading = { version = "0.8.0", optional = true }
Expand Down
1 change: 1 addition & 0 deletions build_system/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
]);
runner.run_out_command("gen_block_iterate", &[]);
}),
TestCase::build_bin_and_run("aot.raw-dylib", "example/raw-dylib.rs", &[]),
];

pub(crate) static RAND_REPO: GitRepo = GitRepo::github(
Expand Down
1 change: 1 addition & 0 deletions config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ aot.issue-59326
aot.polymorphize_coroutine
aot.neon
aot.gen_block_iterate
aot.raw-dylib

testsuite.extended_sysroot
test.rust-random/rand
Expand Down
24 changes: 24 additions & 0 deletions example/raw-dylib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Tests the raw-dylib feature for Windows.
// https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute

fn main() {
#[cfg(windows)]
{
#[link(name = "kernel32", kind = "raw-dylib")]
extern "C" {
fn GetModuleFileNameA(module: *mut std::ffi::c_void, filename: *mut u8, size: u32) -> u32;
}

// Get the filename of the current executable....
let mut buffer = [0u8; 1024];
let size = unsafe { GetModuleFileNameA(core::ptr::null_mut(), buffer.as_mut_ptr(), buffer.len() as u32) };
if size == 0 {
eprintln!("failed to get module file name: {}", std::io::Error::last_os_error());
return;
} else {
// ...and make sure that it matches the test name.
let filename = std::ffi::CStr::from_bytes_with_nul(&buffer[..size as usize + 1]).unwrap();
assert!(filename.to_str().unwrap().ends_with("raw-dylib.exe"));
}
}
}
47 changes: 0 additions & 47 deletions patches/0029-stdlib-rawdylib-processprng.patch

This file was deleted.

This file was deleted.

125 changes: 120 additions & 5 deletions src/archive.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
use std::borrow::Borrow;
use std::fmt::Write;
use std::fs;
use std::path::{Path, PathBuf};

use ar_archive_writer::{COFFShortExport, MachineTypes};
use rustc_codegen_ssa::back::archive::{
ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
};
use rustc_session::cstore::{DllCallingConvention, DllImport, PeImportNameType};
use rustc_session::Session;

pub(crate) struct ArArchiveBuilderBuilder;
Expand All @@ -15,11 +20,121 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
fn create_dll_import_lib(
&self,
sess: &Session,
_lib_name: &str,
_dll_imports: &[rustc_session::cstore::DllImport],
_tmpdir: &Path,
_is_direct_dependency: bool,
lib_name: &str,
dll_imports: &[DllImport],
tmpdir: &Path,
is_direct_dependency: bool,
) -> PathBuf {
sess.dcx().fatal("raw-dylib is not yet supported by rustc_codegen_cranelift");
let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" };
let output_path = tmpdir.join(format!("{lib_name}{name_suffix}.lib"));

let mut file = match fs::OpenOptions::new().write(true).create_new(true).open(&output_path)
{
Ok(file) => file,
Err(error) => {
sess.dcx().fatal(format!(
"failed to create import library file `{path}`: {error}",
path = output_path.display(),
));
}
};

let machine = match sess.target.arch.borrow() {
"x86" => MachineTypes::I386,
"x86_64" => MachineTypes::AMD64,
"arm" => MachineTypes::ARMNT,
"aarch64" => MachineTypes::ARM64,
_ => {
sess.dcx().fatal(format!(
"unsupported target architecture `{arch}`",
arch = sess.target.arch,
));
}
};

let exports = dll_imports
.iter()
.map(|import| {
let name = if machine == MachineTypes::I386 {
i686_decorated_name(import, !sess.target.is_like_msvc)
} else {
import.name.to_string()
};
COFFShortExport {
name,
ext_name: None,
symbol_name: None,
alias_target: None,
ordinal: import.ordinal().unwrap_or(0),
noname: import.ordinal().is_some(),
data: false,
private: false,
constant: false,
}
})
.collect::<Vec<_>>();

if let Err(error) = ar_archive_writer::write_import_library(
&mut file,
lib_name,
&exports,
machine,
!sess.target.is_like_msvc,
) {
sess.dcx().fatal(format!(
"failed to create import library `{path}`: `{error}`",
path = output_path.display(),
));
}

output_path
}
}

fn i686_decorated_name(dll_import: &DllImport, mingw: 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 prefix, +4 for suffix (@@__).
let mut decorated_name = String::with_capacity(name.len() + 5);

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
}

0 comments on commit 92d6d33

Please sign in to comment.