Skip to content

Commit 2d8ceee

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 2d8ceee

File tree

4 files changed

+183
-0
lines changed

4 files changed

+183
-0
lines changed

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: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ENTRY(entry);
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#![feature(no_core)]
2+
#![no_core]
3+
#![no_main]
4+
5+
extern crate minicore;
6+
use minicore::*;
7+
8+
#[unsafe(no_mangle)]
9+
fn entry() {
10+
arm();
11+
thumb();
12+
}
13+
14+
#[unsafe(no_mangle)]
15+
pub fn arm() {
16+
// thumbv5te-LABEL: <arm>:
17+
// thumbv5te: blx {{0x[0-9a-f]+}} <main::arm_normalfn>
18+
// thumbv5te: blx {{0x[0-9a-f]+}} <arm_globalfn>
19+
// thumbv5te: blx {{0x[0-9a-f]+}} <main::arm_nakedfn>
20+
21+
// thumbv4t-LABEL: <arm>:
22+
// thumbv4t: bl {{0x[0-9a-f]+}} <__Thumbv4ABSLongBXThunk__{{.*}}arm_normalfn>
23+
// thumbv4t: bl {{0x[0-9a-f]+}} <__Thumbv4ABSLongBXThunk_arm_globalfn>
24+
// thumbv4t: bl {{0x[0-9a-f]+}} <__Thumbv4ABSLongBXThunk__{{.*}}arm_nakedfn>
25+
26+
// armv5te-LABEL: <arm>:
27+
// armv5te: bl {{0x[0-9a-f]+}} <main::arm_normalfn>
28+
// armv5te: bl {{0x[0-9a-f]+}} <arm_globalfn>
29+
// armv5te: bl {{0x[0-9a-f]+}} <main::arm_nakedfn>
30+
31+
// armv4t-LABEL: <arm>:
32+
// armv4t: bl {{0x[0-9a-f]+}} <main::arm_normalfn>
33+
// armv4t: bl {{0x[0-9a-f]+}} <arm_globalfn>
34+
// armv4t: bl {{0x[0-9a-f]+}} <main::arm_nakedfn>
35+
arm_normalfn();
36+
arm_globalfn();
37+
arm_nakedfn();
38+
}
39+
40+
#[unsafe(no_mangle)]
41+
pub fn thumb() {
42+
// thumbv5te-LABEL: <thumb>:
43+
// thumbv5te: bl {{0x[0-9a-f]+}} <main::thumb_normalfn>
44+
// thumbv5te: bl {{0x[0-9a-f]+}} <thumb_globalfn>
45+
// thumbv5te: bl {{0x[0-9a-f]+}} <main::thumb_nakedfn>
46+
47+
// thumbv4t-LABEL: <thumb>:
48+
// thumbv4t: bl {{0x[0-9a-f]+}} <main::thumb_normalfn>
49+
// thumbv4t: bl {{0x[0-9a-f]+}} <thumb_globalfn>
50+
// thumbv4t: bl {{0x[0-9a-f]+}} <main::thumb_nakedfn>
51+
52+
// armv5te-LABEL: <thumb>:
53+
// armv5te: blx {{0x[0-9a-f]+}} <main::thumb_normalfn>
54+
// armv5te: blx {{0x[0-9a-f]+}} <thumb_globalfn>
55+
// armv5te: blx {{0x[0-9a-f]+}} <main::thumb_nakedfn>
56+
57+
// armv4t-LABEL: <thumb>:
58+
// armv4t: bl {{0x[0-9a-f]+}} <__ARMv4ABSLongBXThunk__{{.*}}thumb_normalfn>
59+
// armv4t: bl {{0x[0-9a-f]+}} <__ARMv4ABSLongBXThunk_thumb_globalfn>
60+
// armv4t: bl {{0x[0-9a-f]+}} <__ARMv4ABSLongBXThunk__{{.*}}thumb_nakedfn>
61+
thumb_normalfn();
62+
thumb_globalfn();
63+
thumb_nakedfn();
64+
}
65+
66+
#[instruction_set(arm::t32)]
67+
extern "C" fn thumb_normalfn() {
68+
unsafe { asm!("nop") }
69+
}
70+
71+
unsafe extern "C" {
72+
safe fn thumb_globalfn();
73+
}
74+
75+
global_asm!(
76+
r#"
77+
.thumb
78+
.global thumb_globalfn
79+
.type thumb_globalfn, %function
80+
thumb_globalfn:
81+
nop
82+
bx lr
83+
.size thumb_globalfn, . - thumb_globalfn
84+
"#
85+
);
86+
87+
#[unsafe(naked)]
88+
#[instruction_set(arm::t32)]
89+
extern "C" fn thumb_nakedfn() {
90+
naked_asm!("nop", "bx lr",);
91+
}
92+
93+
#[instruction_set(arm::a32)]
94+
extern "C" fn arm_normalfn() {
95+
unsafe { asm!("nop") }
96+
}
97+
98+
unsafe extern "C" {
99+
safe fn arm_globalfn();
100+
}
101+
102+
global_asm!(
103+
r#"
104+
.arm
105+
.global arm_globalfn
106+
.type arm_globalfn, %function
107+
arm_globalfn:
108+
nop
109+
bx lr
110+
.size arm_globalfn, . - arm_globalfn
111+
"#
112+
);
113+
114+
#[unsafe(naked)]
115+
#[instruction_set(arm::a32)]
116+
extern "C" fn arm_nakedfn() {
117+
naked_asm!("nop", "bx lr",);
118+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//@ needs-llvm-components: arm
2+
//@ needs-rust-lld
3+
use run_make_support::{llvm_filecheck, llvm_objdump, path, rfs, run, rustc, source_root};
4+
5+
// Test a thumb target calling arm functions. Doing so requires switching from thumb mode to arm
6+
// mode, calling the arm code, then switching back to thumb mode. Depending on the thumb version,
7+
// this happens using a special calling instruction, or by calling a generated thunk that performs
8+
// the mode switching.
9+
//
10+
// In particular this tests that naked functions behave like normal functions. Before LLVM 22, a
11+
// bug in LLVM caused thumb mode to be used unconditonally when symbols were .hidden, miscompiling
12+
// calls to arm functions.
13+
//
14+
// - https://github.com/llvm/llvm-project/pull/181156
15+
// - https://github.com/rust-lang/rust/issues/151946
16+
17+
fn main() {
18+
// Thumb calling thumb and arm.
19+
helper("thumbv5te", "thumbv5te-none-eabi");
20+
helper("thumbv4t", "thumbv4t-none-eabi");
21+
22+
// Arm calling thumb and arm.
23+
helper("armv5te", "armv5te-none-eabi");
24+
helper("armv4t", "armv4t-none-eabi");
25+
}
26+
27+
fn helper(prefix: &str, target: &str) {
28+
rustc()
29+
.input(source_root().join("tests/auxiliary/minicore.rs"))
30+
.crate_name("minicore")
31+
.crate_type("rlib")
32+
.target(target)
33+
.output("libminicore.rlib")
34+
.run();
35+
let minicore = path("libminicore.rlib");
36+
37+
rustc()
38+
.input("main.rs")
39+
.panic("abort")
40+
.link_arg("-Tlink.ld")
41+
.arg("--extern")
42+
.arg(format!("minicore={}", minicore.display()))
43+
.target(target)
44+
.output(prefix)
45+
.run();
46+
47+
let dump = llvm_objdump().disassemble().demangle().input(path(prefix)).run();
48+
49+
eprintln!("{}", str::from_utf8(&dump.stdout()).unwrap());
50+
51+
llvm_filecheck().patterns("main.rs").check_prefix(prefix).stdin_buf(dump.stdout()).run();
52+
}

0 commit comments

Comments
 (0)