Skip to content

Commit ebf562f

Browse files
authored
Fix linux-raw inline asm for thumb-mode. (#416)
* Fix linux-raw inline asm for thumb-mode. In thumb-mode, r7 is reserved as the frame pointer and isn't permitted as an inline asm operand. It's still the syscall-number operand in syscalls though, so pass the syscall-number operand in in a separate register, copy it into r7 inside the inline asm, and then restore the value of r7 when we're done. * Add a thumbv7neon-unknown-linux-gnueabihf line to CI.
1 parent 08773a6 commit ebf562f

File tree

3 files changed

+332
-1
lines changed

3 files changed

+332
-1
lines changed

.github/workflows/main.yml

+2
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,10 @@ jobs:
163163
rustup target add
164164
x86_64-unknown-redox
165165
wasm32-wasi
166+
thumbv7neon-unknown-linux-gnueabihf
166167
- run: cargo check --workspace --release -vv --target=x86_64-unknown-redox --features=all-apis
167168
- run: cargo check --workspace --release -vv --target=wasm32-wasi --features=all-apis
169+
- run: cargo check --workspace --release -vv --target=thumbv7neon-unknown-linux-gnueabihf --features=all-apis
168170

169171
check_tier3:
170172
name: Check selected Tier 3 platforms

src/backend/linux_raw/arch/inline/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@
55
//! conventions are otherwise the compiler's job. But for now, use inline asm.
66
77
#[cfg_attr(target_arch = "aarch64", path = "aarch64.rs")]
8-
#[cfg_attr(target_arch = "arm", path = "arm.rs")]
8+
#[cfg_attr(
9+
all(target_arch = "arm", not(target_feature = "thumb-mode")),
10+
path = "arm.rs"
11+
)]
12+
#[cfg_attr(
13+
all(target_arch = "arm", target_feature = "thumb-mode"),
14+
path = "thumb.rs"
15+
)]
916
#[cfg_attr(target_arch = "mips", path = "mips.rs")]
1017
#[cfg_attr(target_arch = "mips64", path = "mips64.rs")]
1118
#[cfg_attr(target_arch = "powerpc64", path = "powerpc64.rs")]
+322
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
//! arm Linux system calls, using thumb-mode.
2+
//!
3+
//! In thumb-mode, r7 is the frame pointer and is not permitted to be used in
4+
//! an inline asm operand, so we have to use a different register and copy it
5+
//! into r7 inside the inline asm.
6+
7+
use crate::backend::reg::{
8+
ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0,
9+
};
10+
use core::arch::asm;
11+
12+
#[inline]
13+
pub(in crate::backend) unsafe fn syscall0_readonly(nr: SyscallNumber<'_>) -> RetReg<R0> {
14+
let r0;
15+
asm!(
16+
"mov {tmp}, r7",
17+
"mov r7, {nr}",
18+
"svc 0",
19+
"mov r7, {tmp}",
20+
nr = in(reg) nr.to_asm(),
21+
tmp = out(reg) _,
22+
lateout("r0") r0,
23+
options(nostack, preserves_flags, readonly)
24+
);
25+
FromAsm::from_asm(r0)
26+
}
27+
28+
#[inline]
29+
pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> {
30+
let r0;
31+
asm!(
32+
"mov {tmp}, r7",
33+
"mov r7, {nr}",
34+
"svc 0",
35+
"mov r7, {tmp}",
36+
nr = in(reg) nr.to_asm(),
37+
tmp = out(reg) _,
38+
inlateout("r0") a0.to_asm() => r0,
39+
options(nostack, preserves_flags)
40+
);
41+
FromAsm::from_asm(r0)
42+
}
43+
44+
#[inline]
45+
pub(in crate::backend) unsafe fn syscall1_readonly(
46+
nr: SyscallNumber<'_>,
47+
a0: ArgReg<'_, A0>,
48+
) -> RetReg<R0> {
49+
let r0;
50+
asm!(
51+
"mov {tmp}, r7",
52+
"mov r7, {nr}",
53+
"svc 0",
54+
"mov r7, {tmp}",
55+
nr = in(reg) nr.to_asm(),
56+
tmp = out(reg) _,
57+
inlateout("r0") a0.to_asm() => r0,
58+
options(nostack, preserves_flags, readonly)
59+
);
60+
FromAsm::from_asm(r0)
61+
}
62+
63+
#[inline]
64+
pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! {
65+
asm!(
66+
"mov r7, {nr}",
67+
"svc 0",
68+
nr = in(reg) nr.to_asm(),
69+
in("r0") a0.to_asm(),
70+
options(noreturn)
71+
)
72+
}
73+
74+
#[inline]
75+
pub(in crate::backend) unsafe fn syscall2(
76+
nr: SyscallNumber<'_>,
77+
a0: ArgReg<'_, A0>,
78+
a1: ArgReg<'_, A1>,
79+
) -> RetReg<R0> {
80+
let r0;
81+
asm!(
82+
"mov {tmp}, r7",
83+
"mov r7, {nr}",
84+
"svc 0",
85+
"mov r7, {tmp}",
86+
nr = in(reg) nr.to_asm(),
87+
tmp = out(reg) _,
88+
inlateout("r0") a0.to_asm() => r0,
89+
in("r1") a1.to_asm(),
90+
options(nostack, preserves_flags)
91+
);
92+
FromAsm::from_asm(r0)
93+
}
94+
95+
#[inline]
96+
pub(in crate::backend) unsafe fn syscall2_readonly(
97+
nr: SyscallNumber<'_>,
98+
a0: ArgReg<'_, A0>,
99+
a1: ArgReg<'_, A1>,
100+
) -> RetReg<R0> {
101+
let r0;
102+
asm!(
103+
"mov {tmp}, r7",
104+
"mov r7, {nr}",
105+
"svc 0",
106+
"mov r7, {tmp}",
107+
nr = in(reg) nr.to_asm(),
108+
tmp = out(reg) _,
109+
inlateout("r0") a0.to_asm() => r0,
110+
in("r1") a1.to_asm(),
111+
options(nostack, preserves_flags, readonly)
112+
);
113+
FromAsm::from_asm(r0)
114+
}
115+
116+
#[inline]
117+
pub(in crate::backend) unsafe fn syscall3(
118+
nr: SyscallNumber<'_>,
119+
a0: ArgReg<'_, A0>,
120+
a1: ArgReg<'_, A1>,
121+
a2: ArgReg<'_, A2>,
122+
) -> RetReg<R0> {
123+
let r0;
124+
asm!(
125+
"mov {tmp}, r7",
126+
"mov r7, {nr}",
127+
"svc 0",
128+
"mov r7, {tmp}",
129+
nr = in(reg) nr.to_asm(),
130+
tmp = out(reg) _,
131+
inlateout("r0") a0.to_asm() => r0,
132+
in("r1") a1.to_asm(),
133+
in("r2") a2.to_asm(),
134+
options(nostack, preserves_flags)
135+
);
136+
FromAsm::from_asm(r0)
137+
}
138+
139+
#[inline]
140+
pub(in crate::backend) unsafe fn syscall3_readonly(
141+
nr: SyscallNumber<'_>,
142+
a0: ArgReg<'_, A0>,
143+
a1: ArgReg<'_, A1>,
144+
a2: ArgReg<'_, A2>,
145+
) -> RetReg<R0> {
146+
let r0;
147+
asm!(
148+
"mov {tmp}, r7",
149+
"mov r7, {nr}",
150+
"svc 0",
151+
"mov r7, {tmp}",
152+
nr = in(reg) nr.to_asm(),
153+
tmp = out(reg) _,
154+
inlateout("r0") a0.to_asm() => r0,
155+
in("r1") a1.to_asm(),
156+
in("r2") a2.to_asm(),
157+
options(nostack, preserves_flags, readonly)
158+
);
159+
FromAsm::from_asm(r0)
160+
}
161+
162+
#[inline]
163+
pub(in crate::backend) unsafe fn syscall4(
164+
nr: SyscallNumber<'_>,
165+
a0: ArgReg<'_, A0>,
166+
a1: ArgReg<'_, A1>,
167+
a2: ArgReg<'_, A2>,
168+
a3: ArgReg<'_, A3>,
169+
) -> RetReg<R0> {
170+
let r0;
171+
asm!(
172+
"mov {tmp}, r7",
173+
"mov r7, {nr}",
174+
"svc 0",
175+
"mov r7, {tmp}",
176+
nr = in(reg) nr.to_asm(),
177+
tmp = out(reg) _,
178+
inlateout("r0") a0.to_asm() => r0,
179+
in("r1") a1.to_asm(),
180+
in("r2") a2.to_asm(),
181+
in("r3") a3.to_asm(),
182+
options(nostack, preserves_flags)
183+
);
184+
FromAsm::from_asm(r0)
185+
}
186+
187+
#[inline]
188+
pub(in crate::backend) unsafe fn syscall4_readonly(
189+
nr: SyscallNumber<'_>,
190+
a0: ArgReg<'_, A0>,
191+
a1: ArgReg<'_, A1>,
192+
a2: ArgReg<'_, A2>,
193+
a3: ArgReg<'_, A3>,
194+
) -> RetReg<R0> {
195+
let r0;
196+
asm!(
197+
"mov {tmp}, r7",
198+
"mov r7, {nr}",
199+
"svc 0",
200+
"mov r7, {tmp}",
201+
nr = in(reg) nr.to_asm(),
202+
tmp = out(reg) _,
203+
inlateout("r0") a0.to_asm() => r0,
204+
in("r1") a1.to_asm(),
205+
in("r2") a2.to_asm(),
206+
in("r3") a3.to_asm(),
207+
options(nostack, preserves_flags, readonly)
208+
);
209+
FromAsm::from_asm(r0)
210+
}
211+
212+
#[inline]
213+
pub(in crate::backend) unsafe fn syscall5(
214+
nr: SyscallNumber<'_>,
215+
a0: ArgReg<'_, A0>,
216+
a1: ArgReg<'_, A1>,
217+
a2: ArgReg<'_, A2>,
218+
a3: ArgReg<'_, A3>,
219+
a4: ArgReg<'_, A4>,
220+
) -> RetReg<R0> {
221+
let r0;
222+
asm!(
223+
"mov {tmp}, r7",
224+
"mov r7, {nr}",
225+
"svc 0",
226+
"mov r7, {tmp}",
227+
nr = in(reg) nr.to_asm(),
228+
tmp = out(reg) _,
229+
inlateout("r0") a0.to_asm() => r0,
230+
in("r1") a1.to_asm(),
231+
in("r2") a2.to_asm(),
232+
in("r3") a3.to_asm(),
233+
in("r4") a4.to_asm(),
234+
options(nostack, preserves_flags)
235+
);
236+
FromAsm::from_asm(r0)
237+
}
238+
239+
#[inline]
240+
pub(in crate::backend) unsafe fn syscall5_readonly(
241+
nr: SyscallNumber<'_>,
242+
a0: ArgReg<'_, A0>,
243+
a1: ArgReg<'_, A1>,
244+
a2: ArgReg<'_, A2>,
245+
a3: ArgReg<'_, A3>,
246+
a4: ArgReg<'_, A4>,
247+
) -> RetReg<R0> {
248+
let r0;
249+
asm!(
250+
"mov {tmp}, r7",
251+
"mov r7, {nr}",
252+
"svc 0",
253+
"mov r7, {tmp}",
254+
nr = in(reg) nr.to_asm(),
255+
tmp = out(reg) _,
256+
inlateout("r0") a0.to_asm() => r0,
257+
in("r1") a1.to_asm(),
258+
in("r2") a2.to_asm(),
259+
in("r3") a3.to_asm(),
260+
in("r4") a4.to_asm(),
261+
options(nostack, preserves_flags, readonly)
262+
);
263+
FromAsm::from_asm(r0)
264+
}
265+
266+
#[inline]
267+
pub(in crate::backend) unsafe fn syscall6(
268+
nr: SyscallNumber<'_>,
269+
a0: ArgReg<'_, A0>,
270+
a1: ArgReg<'_, A1>,
271+
a2: ArgReg<'_, A2>,
272+
a3: ArgReg<'_, A3>,
273+
a4: ArgReg<'_, A4>,
274+
a5: ArgReg<'_, A5>,
275+
) -> RetReg<R0> {
276+
let r0;
277+
asm!(
278+
"mov {tmp}, r7",
279+
"mov r7, {nr}",
280+
"svc 0",
281+
"mov r7, {tmp}",
282+
nr = in(reg) nr.to_asm(),
283+
tmp = out(reg) _,
284+
inlateout("r0") a0.to_asm() => r0,
285+
in("r1") a1.to_asm(),
286+
in("r2") a2.to_asm(),
287+
in("r3") a3.to_asm(),
288+
in("r4") a4.to_asm(),
289+
in("r5") a5.to_asm(),
290+
options(nostack, preserves_flags)
291+
);
292+
FromAsm::from_asm(r0)
293+
}
294+
295+
#[inline]
296+
pub(in crate::backend) unsafe fn syscall6_readonly(
297+
nr: SyscallNumber<'_>,
298+
a0: ArgReg<'_, A0>,
299+
a1: ArgReg<'_, A1>,
300+
a2: ArgReg<'_, A2>,
301+
a3: ArgReg<'_, A3>,
302+
a4: ArgReg<'_, A4>,
303+
a5: ArgReg<'_, A5>,
304+
) -> RetReg<R0> {
305+
let r0;
306+
asm!(
307+
"mov {tmp}, r7",
308+
"mov r7, {nr}",
309+
"svc 0",
310+
"mov r7, {tmp}",
311+
nr = in(reg) nr.to_asm(),
312+
tmp = out(reg) _,
313+
inlateout("r0") a0.to_asm() => r0,
314+
in("r1") a1.to_asm(),
315+
in("r2") a2.to_asm(),
316+
in("r3") a3.to_asm(),
317+
in("r4") a4.to_asm(),
318+
in("r5") a5.to_asm(),
319+
options(nostack, preserves_flags, readonly)
320+
);
321+
FromAsm::from_asm(r0)
322+
}

0 commit comments

Comments
 (0)