Skip to content

Commit 249482e

Browse files
committed
add test for symbol visibility of #[naked] functions
1 parent 3954398 commit 249482e

File tree

2 files changed

+137
-0
lines changed

2 files changed

+137
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#![feature(naked_functions, asm_const, linkage)]
2+
#![crate_type = "dylib"]
3+
4+
use std::arch::asm;
5+
6+
pub trait TraitWithConst {
7+
const COUNT: u32;
8+
}
9+
10+
struct Test;
11+
12+
impl TraitWithConst for Test {
13+
const COUNT: u32 = 1;
14+
}
15+
16+
#[no_mangle]
17+
fn entry() {
18+
private_vanilla_rust_function_from_rust_dylib();
19+
private_naked_rust_function_from_rust_dylib();
20+
21+
public_vanilla_generic_function_from_rust_dylib::<Test>();
22+
public_naked_generic_function_from_rust_dylib::<Test>();
23+
}
24+
25+
extern "C" fn private_vanilla_rust_function_from_rust_dylib() -> u32 {
26+
42
27+
}
28+
29+
#[no_mangle]
30+
pub extern "C" fn public_vanilla_rust_function_from_rust_dylib() -> u32 {
31+
42
32+
}
33+
34+
pub extern "C" fn public_vanilla_generic_function_from_rust_dylib<T: TraitWithConst>() -> u32 {
35+
T::COUNT
36+
}
37+
38+
#[linkage = "weak"]
39+
extern "C" fn vanilla_weak_linkage() -> u32 {
40+
42
41+
}
42+
43+
#[linkage = "external"]
44+
extern "C" fn vanilla_external_linkage() -> u32 {
45+
42
46+
}
47+
48+
#[naked]
49+
extern "C" fn private_naked_rust_function_from_rust_dylib() -> u32 {
50+
unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
51+
}
52+
53+
#[naked]
54+
#[no_mangle]
55+
pub extern "C" fn public_naked_rust_function_from_rust_dylib() -> u32 {
56+
unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
57+
}
58+
59+
#[naked]
60+
pub extern "C" fn public_naked_generic_function_from_rust_dylib<T: TraitWithConst>() -> u32 {
61+
unsafe { asm!("mov rax, {}", "ret", const T::COUNT, options(noreturn)) }
62+
}
63+
64+
#[naked]
65+
#[linkage = "weak"]
66+
extern "C" fn naked_weak_linkage() -> u32 {
67+
unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
68+
}
69+
70+
#[naked]
71+
#[linkage = "external"]
72+
extern "C" fn naked_external_linkage() -> u32 {
73+
unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
74+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// @only-x86_64
2+
use run_make_support::{dynamic_lib_name, llvm_readobj, regex, rustc};
3+
4+
fn main() {
5+
let rdylib_name = dynamic_lib_name("a_rust_dylib");
6+
rustc().arg("-Zshare-generics=no").input("a_rust_dylib.rs").run();
7+
8+
// check vanilla symbols
9+
not_exported(&rdylib_name, "private_vanilla_rust_function_from_rust_dylib");
10+
global_function(&rdylib_name, "public_vanilla_rust_function_from_rust_dylib");
11+
not_exported(&rdylib_name, "public_vanilla_generic_function_from_rust_dylib");
12+
13+
weak_function(&rdylib_name, "vanilla_weak_linkage");
14+
global_function(&rdylib_name, "vanilla_external_linkage");
15+
16+
// naked should mirror vanilla
17+
not_exported(&rdylib_name, "private_naked_rust_function_from_rust_dylib");
18+
global_function(&rdylib_name, "public_naked_rust_function_from_rust_dylib");
19+
not_exported(&rdylib_name, "public_naked_generic_function_from_rust_dylib");
20+
21+
weak_function(&rdylib_name, "naked_weak_linkage");
22+
global_function(&rdylib_name, "naked_external_linkage");
23+
24+
// share generics should expose the generic functions
25+
rustc().arg("-Zshare-generics=yes").input("a_rust_dylib.rs").run();
26+
global_function(&rdylib_name, "public_vanilla_generic_function_from_rust_dylib");
27+
global_function(&rdylib_name, "public_naked_generic_function_from_rust_dylib");
28+
}
29+
30+
#[track_caller]
31+
fn global_function(path: &str, symbol_name: &str) {
32+
let lines = find_dynamic_symbol(path, symbol_name);
33+
let [line] = lines.as_slice() else {
34+
panic!("symbol {symbol_name} occurs {} times", lines.len())
35+
};
36+
37+
assert!(line.contains("FUNC"), "`{symbol_name}` is not a function");
38+
assert!(line.contains("GLOBAL"), "`{symbol_name}` is not marked as global");
39+
}
40+
41+
#[track_caller]
42+
fn weak_function(path: &str, symbol_name: &str) {
43+
let lines = find_dynamic_symbol(path, symbol_name);
44+
let [line] = lines.as_slice() else {
45+
panic!("symbol {symbol_name} occurs {} times", lines.len())
46+
};
47+
48+
assert!(line.contains("FUNC"), "`{symbol_name}` is not a function");
49+
assert!(line.contains("WEAK"), "`{symbol_name}` is not marked as weak");
50+
}
51+
52+
#[track_caller]
53+
fn not_exported(path: &str, symbol_name: &str) {
54+
assert_eq!(find_dynamic_symbol(path, symbol_name).len(), 0)
55+
}
56+
57+
fn find_dynamic_symbol<'a>(path: &str, symbol_name: &str) -> Vec<String> {
58+
let out = llvm_readobj().arg("--dyn-symbols").input(path).run().stdout_utf8();
59+
out.lines()
60+
.filter(|&line| !line.contains("__imp_") && line.contains(symbol_name))
61+
.map(|line| line.to_string())
62+
.collect()
63+
}

0 commit comments

Comments
 (0)