Skip to content

Commit

Permalink
add test that tracks that functions defined in extern blocks are not …
Browse files Browse the repository at this point in the history
…exported

this maybe should change, but now at least it won't be changed unintentionally
  • Loading branch information
folkertdev committed Aug 3, 2024
1 parent 9061915 commit 940a109
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 32 deletions.
13 changes: 13 additions & 0 deletions tests/run-make/naked-symbol-visibility/a_rust_dylib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,16 @@ extern "C" fn naked_weak_linkage() -> u32 {
extern "C" fn naked_external_linkage() -> u32 {
unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
}

// functions that are declared in an `extern "C"` block are currently not exported
// this maybe should change in the future, this is just tracking the current behavior
// reported in https://github.com/rust-lang/rust/issues/128071
std::arch::global_asm! {
".globl function_defined_in_global_asm",
"function_defined_in_global_asm:",
"ret",
}

extern "C" {
pub fn function_defined_in_global_asm();
}
81 changes: 49 additions & 32 deletions tests/run-make/naked-symbol-visibility/rmake.rs
Original file line number Diff line number Diff line change
@@ -1,63 +1,80 @@
// @only-x86_64
use run_make_support::{dynamic_lib_name, llvm_readobj, regex, rustc};
use run_make_support::object::read::{File, Object, Symbol};
use run_make_support::object::ObjectSymbol;
use run_make_support::{dynamic_lib_name, rfs, rustc};

fn main() {
let rdylib_name = dynamic_lib_name("a_rust_dylib");
rustc().arg("-Zshare-generics=no").input("a_rust_dylib.rs").run();

let binary_data = rfs::read(&rdylib_name);
let rdylib = File::parse(&*binary_data).unwrap();

// check vanilla symbols
not_exported(&rdylib_name, "private_vanilla_rust_function_from_rust_dylib");
global_function(&rdylib_name, "public_vanilla_rust_function_from_rust_dylib");
not_exported(&rdylib_name, "public_vanilla_generic_function_from_rust_dylib");
not_exported(&rdylib, "private_vanilla_rust_function_from_rust_dylib");
global_function(&rdylib, "public_vanilla_rust_function_from_rust_dylib");
not_exported(&rdylib, "public_vanilla_generic_function_from_rust_dylib");

weak_function(&rdylib_name, "vanilla_weak_linkage");
global_function(&rdylib_name, "vanilla_external_linkage");
weak_function(&rdylib, "vanilla_weak_linkage");
global_function(&rdylib, "vanilla_external_linkage");

// naked should mirror vanilla
not_exported(&rdylib_name, "private_naked_rust_function_from_rust_dylib");
global_function(&rdylib_name, "public_naked_rust_function_from_rust_dylib");
not_exported(&rdylib_name, "public_naked_generic_function_from_rust_dylib");
not_exported(&rdylib, "private_naked_rust_function_from_rust_dylib");
global_function(&rdylib, "public_naked_rust_function_from_rust_dylib");
not_exported(&rdylib, "public_naked_generic_function_from_rust_dylib");

weak_function(&rdylib, "naked_weak_linkage");
global_function(&rdylib, "naked_external_linkage");

weak_function(&rdylib_name, "naked_weak_linkage");
global_function(&rdylib_name, "naked_external_linkage");
// functions that are declared in an `extern "C"` block are currently not exported
// this maybe should change in the future, this is just tracking the current behavior
// reported in https://github.com/rust-lang/rust/issues/128071
not_exported(&rdylib, "function_defined_in_global_asm");

// share generics should expose the generic functions
rustc().arg("-Zshare-generics=yes").input("a_rust_dylib.rs").run();
global_function(&rdylib_name, "public_vanilla_generic_function_from_rust_dylib");
global_function(&rdylib_name, "public_naked_generic_function_from_rust_dylib");
let binary_data = rfs::read(&rdylib_name);
let rdylib = File::parse(&*binary_data).unwrap();

global_function(&rdylib, "public_vanilla_generic_function_from_rust_dylib");
global_function(&rdylib, "public_naked_generic_function_from_rust_dylib");
}

#[track_caller]
fn global_function(path: &str, symbol_name: &str) {
let lines = find_dynamic_symbol(path, symbol_name);
let [line] = lines.as_slice() else {
panic!("symbol {symbol_name} occurs {} times", lines.len())
fn global_function(file: &File, symbol_name: &str) {
let symbols = find_dynamic_symbol(file, symbol_name);
let [symbol] = symbols.as_slice() else {
panic!("symbol {symbol_name} occurs {} times", symbols.len())
};

assert!(line.contains("FUNC"), "`{symbol_name}` is not a function");
assert!(line.contains("GLOBAL"), "`{symbol_name}` is not marked as global");
assert!(symbol.is_definition(), "`{symbol_name}` is not a function");
assert!(symbol.is_global(), "`{symbol_name}` is not marked as global");
}

#[track_caller]
fn weak_function(path: &str, symbol_name: &str) {
let lines = find_dynamic_symbol(path, symbol_name);
let [line] = lines.as_slice() else {
panic!("symbol {symbol_name} occurs {} times", lines.len())
fn weak_function(file: &File, symbol_name: &str) {
let symbols = find_dynamic_symbol(file, symbol_name);
let [symbol] = symbols.as_slice() else {
panic!("symbol {symbol_name} occurs {} times", symbols.len())
};

assert!(line.contains("FUNC"), "`{symbol_name}` is not a function");
assert!(line.contains("WEAK"), "`{symbol_name}` is not marked as weak");
assert!(symbol.is_definition(), "`{symbol_name}` is not a function");
assert!(symbol.is_weak(), "`{symbol_name}` is not marked as weak");
}

#[track_caller]
fn not_exported(path: &str, symbol_name: &str) {
assert_eq!(find_dynamic_symbol(path, symbol_name).len(), 0)
fn not_exported(file: &File, symbol_name: &str) {
assert_eq!(find_dynamic_symbol(file, symbol_name).len(), 0)
}

fn find_dynamic_symbol<'a>(path: &str, symbol_name: &str) -> Vec<String> {
let out = llvm_readobj().arg("--dyn-symbols").input(path).run().stdout_utf8();
out.lines()
.filter(|&line| !line.contains("__imp_") && line.contains(symbol_name))
.map(|line| line.to_string())
fn find_dynamic_symbol<'file, 'data>(
file: &'file File<'data>,
expected: &str,
) -> Vec<Symbol<'data, 'file>> {
file.dynamic_symbols()
.filter(|symbol| {
let name = symbol.name().unwrap();
!name.contains("__imp_") && name.contains(expected)
})
.collect()
}

0 comments on commit 940a109

Please sign in to comment.