Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit cf5c3b8

Browse files
dpaolielloMark-Simulacrum
authored andcommitted
Support raw-dylib functions being used inside inlined functions
1 parent 4b7c6cb commit cf5c3b8

File tree

12 files changed

+146
-7
lines changed

12 files changed

+146
-7
lines changed

compiler/rustc_codegen_cranelift/src/archive.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
3838
_lib_name: &str,
3939
_dll_imports: &[rustc_session::cstore::DllImport],
4040
_tmpdir: &Path,
41+
_is_direct_dependency: bool,
4142
) -> PathBuf {
4243
bug!("creating dll imports is not supported");
4344
}

compiler/rustc_codegen_gcc/src/archive.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
4545
_lib_name: &str,
4646
_dll_imports: &[DllImport],
4747
_tmpdir: &Path,
48+
_is_direct_dependency: bool,
4849
) -> PathBuf {
4950
unimplemented!();
5051
}

compiler/rustc_codegen_llvm/src/back/archive.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,12 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
104104
lib_name: &str,
105105
dll_imports: &[DllImport],
106106
tmpdir: &Path,
107+
is_direct_dependency: bool,
107108
) -> PathBuf {
109+
let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" };
108110
let output_path = {
109111
let mut output_path: PathBuf = tmpdir.to_path_buf();
110-
output_path.push(format!("{}_imports", lib_name));
112+
output_path.push(format!("{}{}", lib_name, name_suffix));
111113
output_path.with_extension("lib")
112114
};
113115

@@ -134,7 +136,8 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
134136
// that loaded but crashed with an AV upon calling one of the imported
135137
// functions. Therefore, use binutils to create the import library instead,
136138
// by writing a .DEF file to the temp dir and calling binutils's dlltool.
137-
let def_file_path = tmpdir.join(format!("{}_imports", lib_name)).with_extension("def");
139+
let def_file_path =
140+
tmpdir.join(format!("{}{}", lib_name, name_suffix)).with_extension("def");
138141

139142
let def_file_content = format!(
140143
"EXPORTS\n{}",

compiler/rustc_codegen_ssa/src/back/archive.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub trait ArchiveBuilderBuilder {
2525
lib_name: &str,
2626
dll_imports: &[DllImport],
2727
tmpdir: &Path,
28+
is_direct_dependency: bool,
2829
) -> PathBuf;
2930

3031
fn extract_bundled_libs(

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -376,13 +376,14 @@ fn link_rlib<'a>(
376376
}
377377

378378
for (raw_dylib_name, raw_dylib_imports) in
379-
collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)?
379+
collate_raw_dylibs(sess, codegen_results.crate_info.used_libraries.iter())?
380380
{
381381
let output_path = archive_builder_builder.create_dll_import_lib(
382382
sess,
383383
&raw_dylib_name,
384384
&raw_dylib_imports,
385385
tmpdir.as_ref(),
386+
true,
386387
);
387388

388389
ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|e| {
@@ -434,9 +435,9 @@ fn link_rlib<'a>(
434435
/// then the CodegenResults value contains one NativeLib instance for each block. However, the
435436
/// linker appears to expect only a single import library for each library used, so we need to
436437
/// collate the symbols together by library name before generating the import libraries.
437-
fn collate_raw_dylibs(
438-
sess: &Session,
439-
used_libraries: &[NativeLib],
438+
fn collate_raw_dylibs<'a, 'b>(
439+
sess: &'a Session,
440+
used_libraries: impl IntoIterator<Item = &'b NativeLib>,
440441
) -> Result<Vec<(String, Vec<DllImport>)>, ErrorGuaranteed> {
441442
// Use index maps to preserve original order of imports and libraries.
442443
let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default();
@@ -2028,13 +2029,43 @@ fn linker_with_args<'a>(
20282029

20292030
// Link with the import library generated for any raw-dylib functions.
20302031
for (raw_dylib_name, raw_dylib_imports) in
2031-
collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)?
2032+
collate_raw_dylibs(sess, codegen_results.crate_info.used_libraries.iter())?
2033+
{
2034+
cmd.add_object(&archive_builder_builder.create_dll_import_lib(
2035+
sess,
2036+
&raw_dylib_name,
2037+
&raw_dylib_imports,
2038+
tmpdir,
2039+
true,
2040+
));
2041+
}
2042+
// As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case
2043+
// they are used within inlined functions or instantiated generic functions. We do this *after*
2044+
// handling the raw-dylib symbols in the current crate to make sure that those are chosen first
2045+
// by the linker.
2046+
let (_, dependency_linkage) = codegen_results
2047+
.crate_info
2048+
.dependency_formats
2049+
.iter()
2050+
.find(|(ty, _)| *ty == crate_type)
2051+
.expect("failed to find crate type in dependency format list");
2052+
let native_libraries_from_nonstatics = codegen_results
2053+
.crate_info
2054+
.native_libraries
2055+
.iter()
2056+
.filter_map(|(cnum, libraries)| {
2057+
(dependency_linkage[cnum.as_usize() - 1] != Linkage::Static).then(|| libraries)
2058+
})
2059+
.flatten();
2060+
for (raw_dylib_name, raw_dylib_imports) in
2061+
collate_raw_dylibs(sess, native_libraries_from_nonstatics)?
20322062
{
20332063
cmd.add_object(&archive_builder_builder.create_dll_import_lib(
20342064
sess,
20352065
&raw_dylib_name,
20362066
&raw_dylib_imports,
20372067
tmpdir,
2068+
false,
20382069
));
20392070
}
20402071

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Regression test for calling an inline function that uses a raw-dylib function.
2+
3+
# only-windows
4+
5+
include ../../run-make-fulldeps/tools.mk
6+
7+
all:
8+
$(RUSTC) --crate-type dylib --crate-name raw_dylib_test lib.rs -C prefer-dynamic
9+
$(RUSTC) --crate-type dylib --crate-name raw_dylib_test_wrapper lib_wrapper.rs -C prefer-dynamic
10+
$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" -C prefer-dynamic
11+
# Make sure we don't find an import to the functions we expect to be inlined.
12+
"$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function"
13+
"$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function_calls_inline"
14+
# Make sure we do find an import to the functions we expect to be imported.
15+
"$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -e "library_function"
16+
$(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
17+
$(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
18+
ifdef IS_MSVC
19+
$(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll -noimplib
20+
$(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll -noimplib
21+
else
22+
$(CC) "$(TMPDIR)"/extern_1.obj -shared -o "$(TMPDIR)"/extern_1.dll
23+
$(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll
24+
endif
25+
$(call RUN,driver) > "$(TMPDIR)"/output.txt
26+
27+
ifdef RUSTC_BLESS_TEST
28+
cp "$(TMPDIR)"/output.txt output.txt
29+
else
30+
$(DIFF) output.txt "$(TMPDIR)"/output.txt
31+
endif
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#![feature(raw_dylib)]
2+
3+
extern crate raw_dylib_test;
4+
extern crate raw_dylib_test_wrapper;
5+
6+
#[link(name = "extern_2", kind = "raw-dylib")]
7+
extern {
8+
fn extern_fn_2();
9+
}
10+
11+
fn main() {
12+
// NOTE: The inlined call to `extern_fn_2` links against the function in extern_2.dll instead
13+
// of extern_1.dll since raw-dylib symbols from the current crate are passed to the linker
14+
// first, so any ambiguous names will prefer the current crate's definition.
15+
raw_dylib_test::inline_library_function();
16+
raw_dylib_test::library_function();
17+
raw_dylib_test_wrapper::inline_library_function_calls_inline();
18+
unsafe {
19+
extern_fn_2();
20+
}
21+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include <stdio.h>
2+
3+
__declspec(dllexport) void extern_fn_1() {
4+
printf("extern_fn_1\n");
5+
fflush(stdout);
6+
}
7+
8+
__declspec(dllexport) void extern_fn_2() {
9+
printf("extern_fn_2 in extern_1\n");
10+
fflush(stdout);
11+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include <stdio.h>
2+
3+
__declspec(dllexport) void extern_fn_2() {
4+
printf("extern_fn_2 in extern_2\n");
5+
fflush(stdout);
6+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#![feature(raw_dylib)]
2+
3+
#[link(name = "extern_1", kind = "raw-dylib")]
4+
extern {
5+
fn extern_fn_1();
6+
fn extern_fn_2();
7+
}
8+
9+
#[inline]
10+
pub fn inline_library_function() {
11+
unsafe {
12+
extern_fn_1();
13+
extern_fn_2();
14+
}
15+
}
16+
17+
pub fn library_function() {
18+
unsafe {
19+
extern_fn_2();
20+
}
21+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
extern crate raw_dylib_test;
2+
3+
#[inline]
4+
pub fn inline_library_function_calls_inline() {
5+
raw_dylib_test::inline_library_function();
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
extern_fn_1
2+
extern_fn_2 in extern_2
3+
extern_fn_2 in extern_1
4+
extern_fn_1
5+
extern_fn_2 in extern_2
6+
extern_fn_2 in extern_2

0 commit comments

Comments
 (0)