Skip to content

Commit

Permalink
Support raw-dylib functions being used inside inlined functions
Browse files Browse the repository at this point in the history
  • Loading branch information
dpaoliello committed Oct 24, 2022
1 parent 758f196 commit 3a1ef50
Show file tree
Hide file tree
Showing 12 changed files with 146 additions and 7 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_codegen_cranelift/src/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
_lib_name: &str,
_dll_imports: &[rustc_session::cstore::DllImport],
_tmpdir: &Path,
_is_direct_dependency: bool,
) -> PathBuf {
bug!("creating dll imports is not supported");
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_gcc/src/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
_lib_name: &str,
_dll_imports: &[DllImport],
_tmpdir: &Path,
_is_direct_dependency: bool,
) -> PathBuf {
unimplemented!();
}
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_codegen_llvm/src/back/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,12 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
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 = {
let mut output_path: PathBuf = tmpdir.to_path_buf();
output_path.push(format!("{}_imports", lib_name));
output_path.push(format!("{}{}", lib_name, name_suffix));
output_path.with_extension("lib")
};

Expand All @@ -195,7 +197,8 @@ 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!("{}_imports", lib_name)).with_extension("def");
let def_file_path =
tmpdir.join(format!("{}{}", lib_name, name_suffix)).with_extension("def");

let def_file_content = format!(
"EXPORTS\n{}",
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_ssa/src/back/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub trait ArchiveBuilderBuilder {
lib_name: &str,
dll_imports: &[DllImport],
tmpdir: &Path,
is_direct_dependency: bool,
) -> PathBuf;

fn extract_bundled_libs(
Expand Down
41 changes: 36 additions & 5 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,13 +391,14 @@ fn link_rlib<'a>(
}

for (raw_dylib_name, raw_dylib_imports) in
collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)?
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,
);

ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| {
Expand Down Expand Up @@ -449,9 +450,9 @@ fn link_rlib<'a>(
/// then the CodegenResults value contains one NativeLib instance for each block. However, the
/// linker appears to expect only a single import library for each library used, so we need to
/// collate the symbols together by library name before generating the import libraries.
fn collate_raw_dylibs(
sess: &Session,
used_libraries: &[NativeLib],
fn collate_raw_dylibs<'a, 'b>(
sess: &'a Session,
used_libraries: impl IntoIterator<Item = &'b NativeLib>,
) -> Result<Vec<(String, Vec<DllImport>)>, ErrorGuaranteed> {
// Use index maps to preserve original order of imports and libraries.
let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default();
Expand Down Expand Up @@ -2068,13 +2069,43 @@ fn linker_with_args<'a>(

// 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)?
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,
));
}
// 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*
// handling the raw-dylib symbols in the current crate to make sure that those are chosen first
// by the linker.
let (_, dependency_linkage) = codegen_results
.crate_info
.dependency_formats
.iter()
.find(|(ty, _)| *ty == crate_type)
.expect("failed to find crate type in dependency format list");
let native_libraries_from_nonstatics = codegen_results
.crate_info
.native_libraries
.iter()
.filter_map(|(cnum, libraries)| {
(dependency_linkage[cnum.as_usize() - 1] != Linkage::Static).then(|| libraries)
})
.flatten();
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,
));
}

Expand Down
31 changes: 31 additions & 0 deletions src/test/run-make/raw-dylib-inline-cross-dylib/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Regression test for calling an inline function that uses a raw-dylib function.

# only-windows

include ../../run-make-fulldeps/tools.mk

all:
$(RUSTC) --crate-type dylib --crate-name raw_dylib_test lib.rs -C prefer-dynamic
$(RUSTC) --crate-type dylib --crate-name raw_dylib_test_wrapper lib_wrapper.rs -C prefer-dynamic
$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" -C prefer-dynamic
# Make sure we don't find an import to the functions we expect to be inlined.
"$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function"
"$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function_calls_inline"
# Make sure we do find an import to the functions we expect to be imported.
"$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -e "library_function"
$(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
$(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
ifdef IS_MSVC
$(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll -noimplib
$(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll -noimplib
else
$(CC) "$(TMPDIR)"/extern_1.obj -shared -o "$(TMPDIR)"/extern_1.dll
$(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll
endif
$(call RUN,driver) > "$(TMPDIR)"/output.txt

ifdef RUSTC_BLESS_TEST
cp "$(TMPDIR)"/output.txt output.txt
else
$(DIFF) output.txt "$(TMPDIR)"/output.txt
endif
21 changes: 21 additions & 0 deletions src/test/run-make/raw-dylib-inline-cross-dylib/driver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#![feature(raw_dylib)]

extern crate raw_dylib_test;
extern crate raw_dylib_test_wrapper;

#[link(name = "extern_2", kind = "raw-dylib")]
extern {
fn extern_fn_2();
}

fn main() {
// NOTE: The inlined call to `extern_fn_2` links against the function in extern_2.dll instead
// of extern_1.dll since raw-dylib symbols from the current crate are passed to the linker
// first, so any ambiguous names will prefer the current crate's definition.
raw_dylib_test::inline_library_function();
raw_dylib_test::library_function();
raw_dylib_test_wrapper::inline_library_function_calls_inline();
unsafe {
extern_fn_2();
}
}
11 changes: 11 additions & 0 deletions src/test/run-make/raw-dylib-inline-cross-dylib/extern_1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include <stdio.h>

__declspec(dllexport) void extern_fn_1() {
printf("extern_fn_1\n");
fflush(stdout);
}

__declspec(dllexport) void extern_fn_2() {
printf("extern_fn_2 in extern_1\n");
fflush(stdout);
}
6 changes: 6 additions & 0 deletions src/test/run-make/raw-dylib-inline-cross-dylib/extern_2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <stdio.h>

__declspec(dllexport) void extern_fn_2() {
printf("extern_fn_2 in extern_2\n");
fflush(stdout);
}
21 changes: 21 additions & 0 deletions src/test/run-make/raw-dylib-inline-cross-dylib/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#![feature(raw_dylib)]

#[link(name = "extern_1", kind = "raw-dylib")]
extern {
fn extern_fn_1();
fn extern_fn_2();
}

#[inline]
pub fn inline_library_function() {
unsafe {
extern_fn_1();
extern_fn_2();
}
}

pub fn library_function() {
unsafe {
extern_fn_2();
}
}
6 changes: 6 additions & 0 deletions src/test/run-make/raw-dylib-inline-cross-dylib/lib_wrapper.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
extern crate raw_dylib_test;

#[inline]
pub fn inline_library_function_calls_inline() {
raw_dylib_test::inline_library_function();
}
6 changes: 6 additions & 0 deletions src/test/run-make/raw-dylib-inline-cross-dylib/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
extern_fn_1
extern_fn_2 in extern_2
extern_fn_2 in extern_1
extern_fn_1
extern_fn_2 in extern_2
extern_fn_2 in extern_2

0 comments on commit 3a1ef50

Please sign in to comment.