1 | //! Architecture-specific syscall code. |
2 | //! |
3 | //! `rustix` has inline assembly sequences using `asm!`, but that requires |
4 | //! Rust 1.59, so it also has out-of-line ("outline") assembly sequences in .s |
5 | //! files. And 32-bit x86 is special (see comments below). |
6 | //! |
7 | //! This module also has a `choose` submodule which chooses a scheme and is |
8 | //! what most of the `rustix` syscalls use. |
9 | //! |
10 | //! # Safety |
11 | //! |
12 | //! This contains the inline `asm` statements performing the syscall |
13 | //! instructions and FFI declarations declaring the out-of-line ("outline") |
14 | //! syscall instructions. |
15 | |
16 | #![allow (unsafe_code)] |
17 | #![cfg_attr (not(feature = "all-apis" ), allow(unused_imports))] |
18 | // We'll use as many arguments as syscalls need. |
19 | #![allow (clippy::too_many_arguments)] |
20 | |
21 | // When inline asm is available, use it. Otherwise, use out-of-line asm. These |
22 | // functions always use the machine's syscall instruction, even when it isn't |
23 | // the fastest option available. |
24 | #[cfg_attr (asm, path = "inline/mod.rs" )] |
25 | #[cfg_attr (not(asm), path = "outline/mod.rs" )] |
26 | pub(in crate::backend) mod asm; |
27 | |
28 | // On most architectures, the architecture syscall instruction is fast, so use |
29 | // it directly. |
30 | #[cfg (any( |
31 | target_arch = "arm" , |
32 | target_arch = "aarch64" , |
33 | target_arch = "mips" , |
34 | target_arch = "mips64" , |
35 | target_arch = "powerpc64" , |
36 | target_arch = "riscv64" , |
37 | target_arch = "x86_64" , |
38 | ))] |
39 | pub(in crate::backend) use self::asm as choose; |
40 | |
41 | // On 32-bit x86, use vDSO wrappers for all syscalls. We could use the |
42 | // architecture syscall instruction (`int 0x80`), but the vDSO kernel_vsyscall |
43 | // mechanism is much faster. |
44 | #[cfg (target_arch = "x86" )] |
45 | pub(in crate::backend) use super::vdso_wrappers::x86_via_vdso as choose; |
46 | |
47 | // This would be the code for always using `int 0x80` on 32-bit x86. |
48 | //#[cfg(target_arch = "x86")] |
49 | //pub(in crate::backend) use self::asm as choose; |
50 | |
51 | // Macros for invoking system calls. |
52 | // |
53 | // These factor out: |
54 | // - Calling `nr` on the syscall number to convert it into `SyscallNumber`. |
55 | // - Calling `.into()` on each of the arguments to convert them into `ArgReg`. |
56 | // - Qualifying the `syscall*` and `__NR_*` identifiers. |
57 | // - Counting the number of arguments. |
58 | macro_rules! syscall { |
59 | ($nr:ident) => { |
60 | $crate::backend::arch::choose::syscall0($crate::backend::reg::nr( |
61 | linux_raw_sys::general::$nr, |
62 | )) |
63 | }; |
64 | |
65 | ($nr:ident, $a0:expr) => { |
66 | $crate::backend::arch::choose::syscall1( |
67 | $crate::backend::reg::nr(linux_raw_sys::general::$nr), |
68 | $a0.into(), |
69 | ) |
70 | }; |
71 | |
72 | ($nr:ident, $a0:expr, $a1:expr) => { |
73 | $crate::backend::arch::choose::syscall2( |
74 | $crate::backend::reg::nr(linux_raw_sys::general::$nr), |
75 | $a0.into(), |
76 | $a1.into(), |
77 | ) |
78 | }; |
79 | |
80 | ($nr:ident, $a0:expr, $a1:expr, $a2:expr) => { |
81 | $crate::backend::arch::choose::syscall3( |
82 | $crate::backend::reg::nr(linux_raw_sys::general::$nr), |
83 | $a0.into(), |
84 | $a1.into(), |
85 | $a2.into(), |
86 | ) |
87 | }; |
88 | |
89 | ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr) => { |
90 | $crate::backend::arch::choose::syscall4( |
91 | $crate::backend::reg::nr(linux_raw_sys::general::$nr), |
92 | $a0.into(), |
93 | $a1.into(), |
94 | $a2.into(), |
95 | $a3.into(), |
96 | ) |
97 | }; |
98 | |
99 | ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => { |
100 | $crate::backend::arch::choose::syscall5( |
101 | $crate::backend::reg::nr(linux_raw_sys::general::$nr), |
102 | $a0.into(), |
103 | $a1.into(), |
104 | $a2.into(), |
105 | $a3.into(), |
106 | $a4.into(), |
107 | ) |
108 | }; |
109 | |
110 | ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr) => { |
111 | $crate::backend::arch::choose::syscall6( |
112 | $crate::backend::reg::nr(linux_raw_sys::general::$nr), |
113 | $a0.into(), |
114 | $a1.into(), |
115 | $a2.into(), |
116 | $a3.into(), |
117 | $a4.into(), |
118 | $a5.into(), |
119 | ) |
120 | }; |
121 | |
122 | ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr) => { |
123 | $crate::backend::arch::choose::syscall7( |
124 | $crate::backend::reg::nr(linux_raw_sys::general::$nr), |
125 | $a0.into(), |
126 | $a1.into(), |
127 | $a2.into(), |
128 | $a3.into(), |
129 | $a4.into(), |
130 | $a5.into(), |
131 | $a6.into(), |
132 | ) |
133 | }; |
134 | } |
135 | |
136 | /// Like `syscall`, but adds the `readonly` attribute to the inline asm, which |
137 | /// indicates that the syscall does not mutate any memory. |
138 | macro_rules! syscall_readonly { |
139 | ($nr:ident) => { |
140 | $crate::backend::arch::choose::syscall0_readonly($crate::backend::reg::nr( |
141 | linux_raw_sys::general::$nr, |
142 | )) |
143 | }; |
144 | |
145 | ($nr:ident, $a0:expr) => { |
146 | $crate::backend::arch::choose::syscall1_readonly( |
147 | $crate::backend::reg::nr(linux_raw_sys::general::$nr), |
148 | $a0.into(), |
149 | ) |
150 | }; |
151 | |
152 | ($nr:ident, $a0:expr, $a1:expr) => { |
153 | $crate::backend::arch::choose::syscall2_readonly( |
154 | $crate::backend::reg::nr(linux_raw_sys::general::$nr), |
155 | $a0.into(), |
156 | $a1.into(), |
157 | ) |
158 | }; |
159 | |
160 | ($nr:ident, $a0:expr, $a1:expr, $a2:expr) => { |
161 | $crate::backend::arch::choose::syscall3_readonly( |
162 | $crate::backend::reg::nr(linux_raw_sys::general::$nr), |
163 | $a0.into(), |
164 | $a1.into(), |
165 | $a2.into(), |
166 | ) |
167 | }; |
168 | |
169 | ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr) => { |
170 | $crate::backend::arch::choose::syscall4_readonly( |
171 | $crate::backend::reg::nr(linux_raw_sys::general::$nr), |
172 | $a0.into(), |
173 | $a1.into(), |
174 | $a2.into(), |
175 | $a3.into(), |
176 | ) |
177 | }; |
178 | |
179 | ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => { |
180 | $crate::backend::arch::choose::syscall5_readonly( |
181 | $crate::backend::reg::nr(linux_raw_sys::general::$nr), |
182 | $a0.into(), |
183 | $a1.into(), |
184 | $a2.into(), |
185 | $a3.into(), |
186 | $a4.into(), |
187 | ) |
188 | }; |
189 | |
190 | ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr) => { |
191 | $crate::backend::arch::choose::syscall6_readonly( |
192 | $crate::backend::reg::nr(linux_raw_sys::general::$nr), |
193 | $a0.into(), |
194 | $a1.into(), |
195 | $a2.into(), |
196 | $a3.into(), |
197 | $a4.into(), |
198 | $a5.into(), |
199 | ) |
200 | }; |
201 | |
202 | ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr) => { |
203 | $crate::backend::arch::choose::syscall7_readonly( |
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 | $a6.into(), |
212 | ) |
213 | }; |
214 | } |
215 | |
216 | /// Like `syscall`, but indicates that the syscall does not return. |
217 | #[cfg (feature = "runtime" )] |
218 | macro_rules! syscall_noreturn { |
219 | ($nr:ident, $a0:expr) => { |
220 | $crate::backend::arch::choose::syscall1_noreturn( |
221 | $crate::backend::reg::nr(linux_raw_sys::general::$nr), |
222 | $a0.into(), |
223 | ) |
224 | }; |
225 | } |
226 | |