Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP raw_dylib: write the import .lib manually. #1414

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
10 changes: 10 additions & 0 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 @@ -18,6 +18,7 @@ target-lexicon = "0.12.0"
gimli = { version = "0.28", default-features = false, features = ["write"]}
object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }

ar_archive_writer = "0.1.5"
indexmap = "2.0.0"
libloading = { version = "0.7.3", optional = true }
smallvec = "1.8.1"
Expand Down
1 change: 1 addition & 0 deletions build_system/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
),
TestCase::build_bin_and_run("aot.float-minmax-pass", "example/float-minmax-pass.rs", &[]),
TestCase::build_bin_and_run("aot.mod_bench", "example/mod_bench.rs", &[]),
TestCase::build_bin_and_run("aot.raw_dylib", "example/raw-dylib.rs", &[]),
TestCase::build_bin_and_run("aot.issue-72793", "example/issue-72793.rs", &[]),
TestCase::build_bin("aot.issue-59326", "example/issue-59326.rs"),
];
Expand Down
1 change: 1 addition & 0 deletions config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ aot.subslice-patterns-const-eval
aot.track-caller-attribute
aot.float-minmax-pass
aot.mod_bench
aot.raw_dylib
aot.issue-72793
aot.issue-59326

Expand Down
42 changes: 42 additions & 0 deletions example/raw-dylib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
fn main() {
#[cfg(all(target_arch = "x86_64", target_os = "windows", target_env = "msvc"))]
x86_64_pc_windows_msvc::test();
}

#[cfg(all(target_arch = "x86_64", target_os = "windows", target_env = "msvc"))]
mod x86_64_pc_windows_msvc {
#![allow(clippy::upper_case_acronyms)]

// Expanded windows_sys, with --cfg windows_raw_dylib, on not(target_arch = "x86").
//
// With target_arch = "x86", #[link] needs import_name_type = "undecorated" for windows APIs for
// windows APIs - and the extern abi depends on the specific API.

// use windows_sys::core::PWSTR;
// use windows_sys::{Win32::Foundation::*, Win32::UI::WindowsAndMessaging::*};
type PWSTR = *mut u16;
type BOOL = i32;
type HWND = isize;
type LPARAM = isize;
type WNDENUMPROC = Option<unsafe extern "system" fn(hwnd: HWND, param: LPARAM) -> BOOL>;

#[link(name = "user32.dll", kind = "raw-dylib", modifiers = "+verbatim")]
extern "system" {
fn EnumWindows(lpenumfunc: WNDENUMPROC, lparam: LPARAM) -> BOOL;

fn GetWindowTextW(hwnd: HWND, buf: PWSTR, buflen: i32) -> i32;
}

pub fn test() {
unsafe { EnumWindows(Some(enum_window), 0) };
}

extern "system" fn enum_window(window: HWND, _: LPARAM) -> BOOL {
let mut text: [u16; 512] = [0; 512];

let len = unsafe { GetWindowTextW(window, text.as_mut_ptr(), text.len() as i32) };
let text = String::from_utf16_lossy(&text[..len as usize]);

1 // TRUE
}
}
91 changes: 85 additions & 6 deletions src/archive.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,104 @@
use std::fs;
use std::path::{Path, PathBuf};

use rustc_codegen_ssa::back::archive::{
get_native_object_symbols, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder,
};
use rustc_session::Session;

struct UnsupportedTargetForRawDyLib;

pub(crate) struct ArArchiveBuilderBuilder;

impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a> {
Box::new(ArArchiveBuilder::new(sess, get_native_object_symbols))
Box::new(ArArchiveBuilder::new(sess, get_import_or_native_object_symbols))
}

fn create_dll_import_lib(
&self,
_sess: &Session,
_lib_name: &str,
_dll_imports: &[rustc_session::cstore::DllImport],
_tmpdir: &Path,
sess: &Session,
lib_name: &str,
dll_imports: &[rustc_session::cstore::DllImport],
tmpdir: &Path,
_is_direct_dependency: bool,
) -> PathBuf {
unimplemented!("creating dll imports is not yet supported");
if sess.target.arch != "x86_64" || !sess.target.is_like_msvc {
sess.span_fatal(
dll_imports.iter().map(|import| import.span).collect::<Vec<_>>(),
"cranelift codegen currently only supports raw_dylib on x86_64 msvc targets.",
)
}

let mut import_lib = crate::dll_import_lib::ImportLibraryBuilder::new(
lib_name,
crate::dll_import_lib::Machine::X86_64,
);

for import in dll_imports {
import_lib.add_import(crate::dll_import_lib::Import {
symbol_name: import.name.to_string(),
ordinal_or_hint: import.ordinal(),
name_type: match import.import_name_type {
Some(rustc_session::cstore::PeImportNameType::Ordinal(_)) => {
crate::dll_import_lib::ImportNameType::Ordinal
}
None | Some(rustc_session::cstore::PeImportNameType::Decorated) => {
crate::dll_import_lib::ImportNameType::Name
}
Some(rustc_session::cstore::PeImportNameType::NoPrefix) => {
crate::dll_import_lib::ImportNameType::NameNoPrefix
}
Some(rustc_session::cstore::PeImportNameType::Undecorated) => {
crate::dll_import_lib::ImportNameType::NameUndecorate
}
},
import_type: crate::dll_import_lib::ImportType::Code,
});
}

let lib_path = tmpdir.join(format!(
"{prefix}{lib_name}_import{suffix}",
prefix = sess.target.staticlib_prefix,
suffix = sess.target.staticlib_suffix,
));

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

// import_lib.write() internally uses BufWriter, so we don't need anything here.
if let Err(error) = import_lib.write(&mut file) {
sess.fatal(format!(
"failed to write import library `{path}`: {error}",
path = lib_path.display(),
));
}

lib_path
}
}

fn get_import_or_native_object_symbols(
buf: &[u8],
f: &mut dyn FnMut(&[u8]) -> std::io::Result<()>,
) -> std::io::Result<bool> {
let sig1 = u16::from_le_bytes([buf[0], buf[1]]);
let sig2 = u16::from_le_bytes([buf[2], buf[3]]);
if sig1 == 0 && sig2 == 0xFFFF {
let data = &buf[20..];
let name_end =
data.iter().position(|&c| c == b'\0').expect("import object missing name terminator");
let name = &data[..name_end];
f(name)?;
Ok(true)
} else {
get_native_object_symbols(buf, f)
}
}