rustix/backend/linux_raw/arch/
mod.rs

1//! Architecture-specific syscall code.
2//!
3//! This module also has a `choose` submodule which chooses a scheme and is
4//! what most of the `rustix` syscalls use.
5//!
6//! Compilers should really have intrinsics for making system calls. They're
7//! much like regular calls, with custom calling conventions, and calling
8//! conventions are otherwise the compiler's job. But for now, use inline asm.
9//!
10//! The calling conventions for Linux syscalls are [documented here].
11//!
12//! [documented here]: https://man7.org/linux/man-pages/man2/syscall.2.html
13//!
14//! # Safety
15//!
16//! This contains the inline `asm` statements performing the syscall
17//! instructions.
18
19#![allow(unsafe_code)]
20#![cfg_attr(not(feature = "all-apis"), allow(unused_imports))]
21// We'll use as many arguments as syscalls need.
22#![allow(clippy::too_many_arguments)]
23
24// These functions always use the machine's syscall instruction, even when it
25// isn't the fastest option available.
26#[cfg_attr(target_arch = "aarch64", path = "aarch64.rs")]
27#[cfg_attr(all(target_arch = "arm", not(thumb_mode)), path = "arm.rs")]
28#[cfg_attr(all(target_arch = "arm", thumb_mode), path = "thumb.rs")]
29#[cfg_attr(target_arch = "mips", path = "mips.rs")]
30#[cfg_attr(target_arch = "mips32r6", path = "mips32r6.rs")]
31#[cfg_attr(target_arch = "mips64", path = "mips64.rs")]
32#[cfg_attr(target_arch = "mips64r6", path = "mips64r6.rs")]
33#[cfg_attr(target_arch = "powerpc64", path = "powerpc64.rs")]
34#[cfg_attr(target_arch = "riscv64", path = "riscv64.rs")]
35#[cfg_attr(target_arch = "x86", path = "x86.rs")]
36#[cfg_attr(target_arch = "x86_64", path = "x86_64.rs")]
37pub(in crate::backend) mod asm;
38
39// On most architectures, the architecture syscall instruction is fast, so use
40// it directly.
41#[cfg(any(
42    target_arch = "arm",
43    target_arch = "aarch64",
44    target_arch = "mips",
45    target_arch = "mips32r6",
46    target_arch = "mips64",
47    target_arch = "mips64r6",
48    target_arch = "powerpc64",
49    target_arch = "riscv64",
50    target_arch = "x86_64",
51))]
52pub(in crate::backend) use self::asm as choose;
53
54// On 32-bit x86, use vDSO wrappers for all syscalls. We could use the
55// architecture syscall instruction (`int 0x80`), but the vDSO kernel_vsyscall
56// mechanism is much faster.
57#[cfg(target_arch = "x86")]
58pub(in crate::backend) use super::vdso_wrappers::x86_via_vdso as choose;
59
60// This would be the code for always using `int 0x80` on 32-bit x86.
61//#[cfg(target_arch = "x86")]
62//pub(in crate::backend) use self::asm as choose;
63
64// Macros for invoking system calls.
65//
66// These factor out:
67//  - Calling `nr` on the syscall number to convert it into `SyscallNumber`.
68//  - Calling `.into()` on each of the arguments to convert them into `ArgReg`.
69//  - Qualifying the `syscall*` and `__NR_*` identifiers.
70//  - Counting the number of arguments.
71macro_rules! syscall {
72    ($nr:ident) => {
73        $crate::backend::arch::choose::syscall0($crate::backend::reg::nr(
74            linux_raw_sys::general::$nr,
75        ))
76    };
77
78    ($nr:ident, $a0:expr) => {
79        $crate::backend::arch::choose::syscall1(
80            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
81            $a0.into(),
82        )
83    };
84
85    ($nr:ident, $a0:expr, $a1:expr) => {
86        $crate::backend::arch::choose::syscall2(
87            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
88            $a0.into(),
89            $a1.into(),
90        )
91    };
92
93    ($nr:ident, $a0:expr, $a1:expr, $a2:expr) => {
94        $crate::backend::arch::choose::syscall3(
95            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
96            $a0.into(),
97            $a1.into(),
98            $a2.into(),
99        )
100    };
101
102    ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr) => {
103        $crate::backend::arch::choose::syscall4(
104            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
105            $a0.into(),
106            $a1.into(),
107            $a2.into(),
108            $a3.into(),
109        )
110    };
111
112    ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => {
113        $crate::backend::arch::choose::syscall5(
114            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
115            $a0.into(),
116            $a1.into(),
117            $a2.into(),
118            $a3.into(),
119            $a4.into(),
120        )
121    };
122
123    ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr) => {
124        $crate::backend::arch::choose::syscall6(
125            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
126            $a0.into(),
127            $a1.into(),
128            $a2.into(),
129            $a3.into(),
130            $a4.into(),
131            $a5.into(),
132        )
133    };
134
135    ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr) => {
136        $crate::backend::arch::choose::syscall7(
137            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
138            $a0.into(),
139            $a1.into(),
140            $a2.into(),
141            $a3.into(),
142            $a4.into(),
143            $a5.into(),
144            $a6.into(),
145        )
146    };
147}
148
149// Macro to invoke a syscall that always uses direct assembly, rather than the
150// vDSO. Useful when still finding the vDSO.
151#[allow(unused_macros)]
152macro_rules! syscall_always_asm {
153    ($nr:ident) => {
154        $crate::backend::arch::asm::syscall0($crate::backend::reg::nr(linux_raw_sys::general::$nr))
155    };
156
157    ($nr:ident, $a0:expr) => {
158        $crate::backend::arch::asm::syscall1(
159            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
160            $a0.into(),
161        )
162    };
163
164    ($nr:ident, $a0:expr, $a1:expr) => {
165        $crate::backend::arch::asm::syscall2(
166            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
167            $a0.into(),
168            $a1.into(),
169        )
170    };
171
172    ($nr:ident, $a0:expr, $a1:expr, $a2:expr) => {
173        $crate::backend::arch::asm::syscall3(
174            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
175            $a0.into(),
176            $a1.into(),
177            $a2.into(),
178        )
179    };
180
181    ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr) => {
182        $crate::backend::arch::asm::syscall4(
183            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
184            $a0.into(),
185            $a1.into(),
186            $a2.into(),
187            $a3.into(),
188        )
189    };
190
191    ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => {
192        $crate::backend::arch::asm::syscall5(
193            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
194            $a0.into(),
195            $a1.into(),
196            $a2.into(),
197            $a3.into(),
198            $a4.into(),
199        )
200    };
201
202    ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr) => {
203        $crate::backend::arch::asm::syscall6(
204            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
205            $a0.into(),
206            $a1.into(),
207            $a2.into(),
208            $a3.into(),
209            $a4.into(),
210            $a5.into(),
211        )
212    };
213
214    ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr) => {
215        $crate::backend::arch::asm::syscall7(
216            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
217            $a0.into(),
218            $a1.into(),
219            $a2.into(),
220            $a3.into(),
221            $a4.into(),
222            $a5.into(),
223            $a6.into(),
224        )
225    };
226}
227
228/// Like `syscall`, but adds the `readonly` attribute to the inline asm, which
229/// indicates that the syscall does not mutate any memory.
230macro_rules! syscall_readonly {
231    ($nr:ident) => {
232        $crate::backend::arch::choose::syscall0_readonly($crate::backend::reg::nr(
233            linux_raw_sys::general::$nr,
234        ))
235    };
236
237    ($nr:ident, $a0:expr) => {
238        $crate::backend::arch::choose::syscall1_readonly(
239            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
240            $a0.into(),
241        )
242    };
243
244    ($nr:ident, $a0:expr, $a1:expr) => {
245        $crate::backend::arch::choose::syscall2_readonly(
246            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
247            $a0.into(),
248            $a1.into(),
249        )
250    };
251
252    ($nr:ident, $a0:expr, $a1:expr, $a2:expr) => {
253        $crate::backend::arch::choose::syscall3_readonly(
254            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
255            $a0.into(),
256            $a1.into(),
257            $a2.into(),
258        )
259    };
260
261    ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr) => {
262        $crate::backend::arch::choose::syscall4_readonly(
263            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
264            $a0.into(),
265            $a1.into(),
266            $a2.into(),
267            $a3.into(),
268        )
269    };
270
271    ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => {
272        $crate::backend::arch::choose::syscall5_readonly(
273            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
274            $a0.into(),
275            $a1.into(),
276            $a2.into(),
277            $a3.into(),
278            $a4.into(),
279        )
280    };
281
282    ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr) => {
283        $crate::backend::arch::choose::syscall6_readonly(
284            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
285            $a0.into(),
286            $a1.into(),
287            $a2.into(),
288            $a3.into(),
289            $a4.into(),
290            $a5.into(),
291        )
292    };
293
294    ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr) => {
295        $crate::backend::arch::choose::syscall7_readonly(
296            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
297            $a0.into(),
298            $a1.into(),
299            $a2.into(),
300            $a3.into(),
301            $a4.into(),
302            $a5.into(),
303            $a6.into(),
304        )
305    };
306}
307
308/// Like `syscall`, but indicates that the syscall does not return.
309#[cfg(feature = "runtime")]
310macro_rules! syscall_noreturn {
311    ($nr:ident, $a0:expr) => {
312        $crate::backend::arch::choose::syscall1_noreturn(
313            $crate::backend::reg::nr(linux_raw_sys::general::$nr),
314            $a0.into(),
315        )
316    };
317}