Skip to content

Commit 1977b19

Browse files
committed
add tests for a thumb program calling arm code
and in particular for naked functions in that scenario
1 parent bb779a9 commit 1977b19

5 files changed

Lines changed: 163 additions & 0 deletions

File tree

src/tools/run-make-support/src/external_deps/llvm.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,12 @@ impl LlvmFilecheck {
302302
self.cmd.arg(input_file.as_ref());
303303
self
304304
}
305+
306+
/// Set a single `--check-prefix`.
307+
pub fn check_prefix<S: AsRef<str>>(&mut self, prefix: S) -> &mut Self {
308+
self.cmd.arg(format!("--check-prefix={}", prefix.as_ref()));
309+
self
310+
}
305311
}
306312

307313
impl LlvmObjdump {
@@ -324,6 +330,12 @@ impl LlvmObjdump {
324330
self.cmd.arg("-d");
325331
self
326332
}
333+
334+
/// Demangle symbols.
335+
pub fn demangle(&mut self) -> &mut Self {
336+
self.cmd.arg("--demangle");
337+
self
338+
}
327339
}
328340

329341
impl LlvmAr {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#![feature(no_core)]
2+
#![no_core]
3+
#![no_main]
4+
5+
extern crate minicore;
6+
use minicore::*;
7+
8+
#[unsafe(no_mangle)]
9+
pub fn entry() {
10+
// thumbv5te: blx {{0x[0-9a-f]+}} <a32::normalfn>
11+
// thumbv5te: blx {{0x[0-9a-f]+}} <globalfn>
12+
// thumbv5te: blx {{0x[0-9a-f]+}} <a32::nakedfn>
13+
14+
// thumbv4t: bl {{0x[0-9a-f]+}} <__Thumbv4ABSLongBXThunk__RNvCsdN8C8f0sPJt_3a328normalfn>
15+
// thumbv4t: bl {{0x[0-9a-f]+}} <__Thumbv4ABSLongBXThunk_globalfn>
16+
// thumbv4t: bl {{0x[0-9a-f]+}} <__Thumbv4ABSLongBXThunk__RNvCsdN8C8f0sPJt_3a327nakedfn>
17+
normalfn();
18+
globalfn();
19+
nakedfn();
20+
}
21+
22+
#[instruction_set(arm::a32)]
23+
extern "C" fn normalfn() {
24+
unsafe { asm!("nop") }
25+
}
26+
27+
unsafe extern "C" {
28+
safe fn globalfn();
29+
}
30+
31+
global_asm!(
32+
r#"
33+
.arm
34+
.global globalfn
35+
.type globalfn, %function
36+
globalfn:
37+
nop
38+
bx lr
39+
.size globalfn, . - globalfn
40+
"#
41+
);
42+
43+
#[unsafe(naked)]
44+
#[instruction_set(arm::a32)]
45+
extern "C" fn nakedfn() {
46+
naked_asm!("nop", "bx lr",);
47+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ENTRY(entry);
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//@ needs-rust-lld
2+
use run_make_support::{llvm_filecheck, llvm_objdump, path, rfs, run, rustc, source_root};
3+
4+
// Test a thumb target calling arm functions. Doing so requires switching from thumb mode to arm
5+
// mode, calling the arm code, then switching back to thumb mode. Depending on the thumb version,
6+
// this happens using a special calling instruction, or by calling a generated thunk that performs
7+
// the mode switching.
8+
//
9+
// In particular this tests that naked functions behave like normal functions. Before LLVM 22, a
10+
// bug in LLVM caused thumb mode to be used unconditonally when symbols were .hidden, miscompiling
11+
// calls to arm functions.
12+
//
13+
// - https://github.com/llvm/llvm-project/pull/181156
14+
// - https://github.com/rust-lang/rust/issues/151946
15+
16+
macro_rules! helper {
17+
($prefix:literal, $test:literal) => {
18+
rustc()
19+
.input(source_root().join("tests/auxiliary/minicore.rs"))
20+
.crate_name("minicore")
21+
.crate_type("rlib")
22+
.target(concat!($prefix, "-none-eabi"))
23+
.output("libminicore.rlib")
24+
.run();
25+
let minicore = path("libminicore.rlib");
26+
27+
rustc()
28+
.input(concat!($test, ".rs"))
29+
.panic("abort")
30+
.link_arg("-Tlink.ld")
31+
.arg("--extern")
32+
.arg(format!("minicore={}", minicore.display()))
33+
.target(concat!($prefix, "-none-eabi"))
34+
.output(concat!($prefix, "-", $test))
35+
.run();
36+
37+
let dump =
38+
llvm_objdump().disassemble().demangle().input(path(concat!($prefix, "-", $test))).run();
39+
40+
llvm_filecheck()
41+
.patterns(concat!($test, ".rs"))
42+
.check_prefix($prefix)
43+
.stdin_buf(dump.stdout())
44+
.run();
45+
};
46+
}
47+
48+
fn main() {
49+
// Thumb calling thumb.
50+
helper!("thumbv5te", "t32");
51+
helper!("thumbv4t", "t32");
52+
53+
// Thumb calling arm.
54+
helper!("thumbv5te", "a32");
55+
helper!("thumbv4t", "a32");
56+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#![feature(no_core)]
2+
#![no_core]
3+
#![no_main]
4+
5+
extern crate minicore;
6+
use minicore::*;
7+
8+
#[unsafe(no_mangle)]
9+
pub fn entry() {
10+
// thumbv5te: bl {{0x[0-9a-f]+}} <t32::normalfn>
11+
// thumbv5te: bl {{0x[0-9a-f]+}} <globalfn>
12+
// thumbv5te: bl {{0x[0-9a-f]+}} <t32::nakedfn>
13+
14+
// thumbv4t: bl {{0x[0-9a-f]+}} <t32::normalfn>
15+
// thumbv4t: bl {{0x[0-9a-f]+}} <globalfn>
16+
// thumbv4t: bl {{0x[0-9a-f]+}} <t32::nakedfn>
17+
normalfn();
18+
globalfn();
19+
nakedfn();
20+
}
21+
22+
#[instruction_set(arm::t32)]
23+
extern "C" fn normalfn() {
24+
unsafe { asm!("nop") }
25+
}
26+
27+
unsafe extern "C" {
28+
safe fn globalfn();
29+
}
30+
31+
global_asm!(
32+
r#"
33+
.thumb
34+
.global globalfn
35+
.type globalfn, %function
36+
globalfn:
37+
nop
38+
bx lr
39+
.size globalfn, . - globalfn
40+
"#
41+
);
42+
43+
#[unsafe(naked)]
44+
#[instruction_set(arm::t32)]
45+
extern "C" fn nakedfn() {
46+
naked_asm!("nop", "bx lr",);
47+
}

0 commit comments

Comments
 (0)