1 //! Syscall wrappers for 32-bit x86.
2 //!
3 //! This module is similar to the `nr_last` module, except specialized for
4 //! 32-bit x86.
5 //!
6 //! The syscall convention passes all arguments in registers. The closest we
7 //! can easily get to that from Rust is to use the fastcall convention which
8 //! passes the first two arguments in `ecx` and `edx`, which are the second
9 //! and third Linux syscall arguments. To line them up, this function passes
10 //! the second and third syscall argument as the first and second argument to
11 //! the outline assembly, followed by the first syscall argument, and then the
12 //! rest of the syscall arguments. The assembly code still has to do some work,
13 //! but at least we can get up to two arguments into the right place for it.
14
15 #![allow(dead_code, unused_imports)]
16
17 use crate::backend::reg::{ArgReg, RetReg, SyscallNumber, A0, A1, A2, A3, A4, A5, R0};
18 use crate::backend::vdso_wrappers::SyscallType;
19
20 // First we declare the actual assembly routines with `*_nr_last_fastcall`
21 // names and reordered arguments. If the signatures or calling conventions are
22 // ever changed, the symbol names should also be updated accordingly, to avoid
23 // collisions with other versions of this crate.
24 //
25 // We don't define `_readonly` versions of these because we have no way to tell
26 // Rust that calls to our outline assembly are readonly.
27 extern "fastcall" {
rustix_syscall0_nr_last_fastcall(nr: SyscallNumber<'_>) -> RetReg<R0>28 fn rustix_syscall0_nr_last_fastcall(nr: SyscallNumber<'_>) -> RetReg<R0>;
rustix_syscall1_nr_last_fastcall(a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>) -> RetReg<R0>29 fn rustix_syscall1_nr_last_fastcall(a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>) -> RetReg<R0>;
rustix_syscall1_noreturn_nr_last_fastcall(a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>) -> !30 fn rustix_syscall1_noreturn_nr_last_fastcall(a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>) -> !;
rustix_syscall2_nr_last_fastcall( a1: ArgReg<'_, A1>, a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>, ) -> RetReg<R0>31 fn rustix_syscall2_nr_last_fastcall(
32 a1: ArgReg<'_, A1>,
33 a0: ArgReg<'_, A0>,
34 nr: SyscallNumber<'_>,
35 ) -> RetReg<R0>;
rustix_syscall3_nr_last_fastcall( a1: ArgReg<'_, A1>, a2: ArgReg<'_, A2>, a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>, ) -> RetReg<R0>36 fn rustix_syscall3_nr_last_fastcall(
37 a1: ArgReg<'_, A1>,
38 a2: ArgReg<'_, A2>,
39 a0: ArgReg<'_, A0>,
40 nr: SyscallNumber<'_>,
41 ) -> RetReg<R0>;
rustix_syscall4_nr_last_fastcall( a1: ArgReg<'_, A1>, a2: ArgReg<'_, A2>, a0: ArgReg<'_, A0>, a3: ArgReg<'_, A3>, nr: SyscallNumber<'_>, ) -> RetReg<R0>42 fn rustix_syscall4_nr_last_fastcall(
43 a1: ArgReg<'_, A1>,
44 a2: ArgReg<'_, A2>,
45 a0: ArgReg<'_, A0>,
46 a3: ArgReg<'_, A3>,
47 nr: SyscallNumber<'_>,
48 ) -> RetReg<R0>;
rustix_syscall5_nr_last_fastcall( a1: ArgReg<'_, A1>, a2: ArgReg<'_, A2>, a0: ArgReg<'_, A0>, a3: ArgReg<'_, A3>, a4: ArgReg<'_, A4>, nr: SyscallNumber<'_>, ) -> RetReg<R0>49 fn rustix_syscall5_nr_last_fastcall(
50 a1: ArgReg<'_, A1>,
51 a2: ArgReg<'_, A2>,
52 a0: ArgReg<'_, A0>,
53 a3: ArgReg<'_, A3>,
54 a4: ArgReg<'_, A4>,
55 nr: SyscallNumber<'_>,
56 ) -> RetReg<R0>;
rustix_syscall6_nr_last_fastcall( a1: ArgReg<'_, A1>, a2: ArgReg<'_, A2>, a0: ArgReg<'_, A0>, a3: ArgReg<'_, A3>, a4: ArgReg<'_, A4>, a5: ArgReg<'_, A5>, nr: SyscallNumber<'_>, ) -> RetReg<R0>57 fn rustix_syscall6_nr_last_fastcall(
58 a1: ArgReg<'_, A1>,
59 a2: ArgReg<'_, A2>,
60 a0: ArgReg<'_, A0>,
61 a3: ArgReg<'_, A3>,
62 a4: ArgReg<'_, A4>,
63 a5: ArgReg<'_, A5>,
64 nr: SyscallNumber<'_>,
65 ) -> RetReg<R0>;
66 }
67
68 // Then we define inline wrapper functions that do the reordering.
69
70 #[inline]
syscall0(nr: SyscallNumber<'_>) -> RetReg<R0>71 pub(in crate::backend) unsafe fn syscall0(nr: SyscallNumber<'_>) -> RetReg<R0> {
72 rustix_syscall0_nr_last_fastcall(nr)
73 }
74 #[inline]
syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0>75 pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> {
76 rustix_syscall1_nr_last_fastcall(a0, nr)
77 }
78 #[inline]
syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> !79 pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! {
80 rustix_syscall1_noreturn_nr_last_fastcall(a0, nr)
81 }
82 #[inline]
syscall2( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, ) -> RetReg<R0>83 pub(in crate::backend) unsafe fn syscall2(
84 nr: SyscallNumber<'_>,
85 a0: ArgReg<'_, A0>,
86 a1: ArgReg<'_, A1>,
87 ) -> RetReg<R0> {
88 rustix_syscall2_nr_last_fastcall(a1, a0, nr)
89 }
90 #[inline]
syscall3( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, a2: ArgReg<'_, A2>, ) -> RetReg<R0>91 pub(in crate::backend) unsafe fn syscall3(
92 nr: SyscallNumber<'_>,
93 a0: ArgReg<'_, A0>,
94 a1: ArgReg<'_, A1>,
95 a2: ArgReg<'_, A2>,
96 ) -> RetReg<R0> {
97 rustix_syscall3_nr_last_fastcall(a1, a2, a0, nr)
98 }
99 #[inline]
syscall4( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, a2: ArgReg<'_, A2>, a3: ArgReg<'_, A3>, ) -> RetReg<R0>100 pub(in crate::backend) unsafe fn syscall4(
101 nr: SyscallNumber<'_>,
102 a0: ArgReg<'_, A0>,
103 a1: ArgReg<'_, A1>,
104 a2: ArgReg<'_, A2>,
105 a3: ArgReg<'_, A3>,
106 ) -> RetReg<R0> {
107 rustix_syscall4_nr_last_fastcall(a1, a2, a0, a3, nr)
108 }
109 #[inline]
syscall5( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, a2: ArgReg<'_, A2>, a3: ArgReg<'_, A3>, a4: ArgReg<'_, A4>, ) -> RetReg<R0>110 pub(in crate::backend) unsafe fn syscall5(
111 nr: SyscallNumber<'_>,
112 a0: ArgReg<'_, A0>,
113 a1: ArgReg<'_, A1>,
114 a2: ArgReg<'_, A2>,
115 a3: ArgReg<'_, A3>,
116 a4: ArgReg<'_, A4>,
117 ) -> RetReg<R0> {
118 rustix_syscall5_nr_last_fastcall(a1, a2, a0, a3, a4, nr)
119 }
120 #[inline]
syscall6( nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, a2: ArgReg<'_, A2>, a3: ArgReg<'_, A3>, a4: ArgReg<'_, A4>, a5: ArgReg<'_, A5>, ) -> RetReg<R0>121 pub(in crate::backend) unsafe fn syscall6(
122 nr: SyscallNumber<'_>,
123 a0: ArgReg<'_, A0>,
124 a1: ArgReg<'_, A1>,
125 a2: ArgReg<'_, A2>,
126 a3: ArgReg<'_, A3>,
127 a4: ArgReg<'_, A4>,
128 a5: ArgReg<'_, A5>,
129 ) -> RetReg<R0> {
130 rustix_syscall6_nr_last_fastcall(a1, a2, a0, a3, a4, a5, nr)
131 }
132
133 // Then we define the `_readonly` versions of the wrappers. We don't have
134 // separate `_readonly` implementations, so these can just be aliases to
135 // their non-`_readonly` counterparts.
136 pub(in crate::backend) use {
137 syscall0 as syscall0_readonly, syscall1 as syscall1_readonly, syscall2 as syscall2_readonly,
138 syscall3 as syscall3_readonly, syscall4 as syscall4_readonly, syscall5 as syscall5_readonly,
139 syscall6 as syscall6_readonly,
140 };
141
142 // x86 prefers to route all syscalls through the vDSO, though this isn't
143 // always possible, so it also has a special form for doing the dispatch.
144 //
145 // First we declare the actual assembly routines with `*_nr_last_fastcall`
146 // names and reordered arguments. If the signatures or calling conventions are
147 // ever changed, the symbol names should also be updated accordingly, to avoid
148 // collisions with other versions of this crate.
149 extern "fastcall" {
rustix_indirect_syscall0_nr_last_fastcall( nr: SyscallNumber<'_>, callee: SyscallType, ) -> RetReg<R0>150 fn rustix_indirect_syscall0_nr_last_fastcall(
151 nr: SyscallNumber<'_>,
152 callee: SyscallType,
153 ) -> RetReg<R0>;
rustix_indirect_syscall1_nr_last_fastcall( a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>, callee: SyscallType, ) -> RetReg<R0>154 fn rustix_indirect_syscall1_nr_last_fastcall(
155 a0: ArgReg<'_, A0>,
156 nr: SyscallNumber<'_>,
157 callee: SyscallType,
158 ) -> RetReg<R0>;
rustix_indirect_syscall1_noreturn_nr_last_fastcall( a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>, callee: SyscallType, ) -> !159 fn rustix_indirect_syscall1_noreturn_nr_last_fastcall(
160 a0: ArgReg<'_, A0>,
161 nr: SyscallNumber<'_>,
162 callee: SyscallType,
163 ) -> !;
rustix_indirect_syscall2_nr_last_fastcall( a1: ArgReg<'_, A1>, a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>, callee: SyscallType, ) -> RetReg<R0>164 fn rustix_indirect_syscall2_nr_last_fastcall(
165 a1: ArgReg<'_, A1>,
166 a0: ArgReg<'_, A0>,
167 nr: SyscallNumber<'_>,
168 callee: SyscallType,
169 ) -> RetReg<R0>;
rustix_indirect_syscall3_nr_last_fastcall( a1: ArgReg<'_, A1>, a2: ArgReg<'_, A2>, a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>, callee: SyscallType, ) -> RetReg<R0>170 fn rustix_indirect_syscall3_nr_last_fastcall(
171 a1: ArgReg<'_, A1>,
172 a2: ArgReg<'_, A2>,
173 a0: ArgReg<'_, A0>,
174 nr: SyscallNumber<'_>,
175 callee: SyscallType,
176 ) -> RetReg<R0>;
rustix_indirect_syscall4_nr_last_fastcall( a1: ArgReg<'_, A1>, a2: ArgReg<'_, A2>, a0: ArgReg<'_, A0>, a3: ArgReg<'_, A3>, nr: SyscallNumber<'_>, callee: SyscallType, ) -> RetReg<R0>177 fn rustix_indirect_syscall4_nr_last_fastcall(
178 a1: ArgReg<'_, A1>,
179 a2: ArgReg<'_, A2>,
180 a0: ArgReg<'_, A0>,
181 a3: ArgReg<'_, A3>,
182 nr: SyscallNumber<'_>,
183 callee: SyscallType,
184 ) -> RetReg<R0>;
rustix_indirect_syscall5_nr_last_fastcall( a1: ArgReg<'_, A1>, a2: ArgReg<'_, A2>, a0: ArgReg<'_, A0>, a3: ArgReg<'_, A3>, a4: ArgReg<'_, A4>, nr: SyscallNumber<'_>, callee: SyscallType, ) -> RetReg<R0>185 fn rustix_indirect_syscall5_nr_last_fastcall(
186 a1: ArgReg<'_, A1>,
187 a2: ArgReg<'_, A2>,
188 a0: ArgReg<'_, A0>,
189 a3: ArgReg<'_, A3>,
190 a4: ArgReg<'_, A4>,
191 nr: SyscallNumber<'_>,
192 callee: SyscallType,
193 ) -> RetReg<R0>;
rustix_indirect_syscall6_nr_last_fastcall( a1: ArgReg<'_, A1>, a2: ArgReg<'_, A2>, a0: ArgReg<'_, A0>, a3: ArgReg<'_, A3>, a4: ArgReg<'_, A4>, a5: ArgReg<'_, A5>, nr: SyscallNumber<'_>, callee: SyscallType, ) -> RetReg<R0>194 fn rustix_indirect_syscall6_nr_last_fastcall(
195 a1: ArgReg<'_, A1>,
196 a2: ArgReg<'_, A2>,
197 a0: ArgReg<'_, A0>,
198 a3: ArgReg<'_, A3>,
199 a4: ArgReg<'_, A4>,
200 a5: ArgReg<'_, A5>,
201 nr: SyscallNumber<'_>,
202 callee: SyscallType,
203 ) -> RetReg<R0>;
204 }
205
206 // Then we define inline wrapper functions that do the reordering.
207
208 #[inline]
indirect_syscall0( callee: SyscallType, nr: SyscallNumber<'_>, ) -> RetReg<R0>209 pub(in crate::backend) unsafe fn indirect_syscall0(
210 callee: SyscallType,
211 nr: SyscallNumber<'_>,
212 ) -> RetReg<R0> {
213 rustix_indirect_syscall0_nr_last_fastcall(nr, callee)
214 }
215 #[inline]
indirect_syscall1( callee: SyscallType, nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, ) -> RetReg<R0>216 pub(in crate::backend) unsafe fn indirect_syscall1(
217 callee: SyscallType,
218 nr: SyscallNumber<'_>,
219 a0: ArgReg<'_, A0>,
220 ) -> RetReg<R0> {
221 rustix_indirect_syscall1_nr_last_fastcall(a0, nr, callee)
222 }
223 #[inline]
indirect_syscall1_noreturn( callee: SyscallType, nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, ) -> !224 pub(in crate::backend) unsafe fn indirect_syscall1_noreturn(
225 callee: SyscallType,
226 nr: SyscallNumber<'_>,
227 a0: ArgReg<'_, A0>,
228 ) -> ! {
229 rustix_indirect_syscall1_noreturn_nr_last_fastcall(a0, nr, callee)
230 }
231 #[inline]
indirect_syscall2( callee: SyscallType, nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, ) -> RetReg<R0>232 pub(in crate::backend) unsafe fn indirect_syscall2(
233 callee: SyscallType,
234 nr: SyscallNumber<'_>,
235 a0: ArgReg<'_, A0>,
236 a1: ArgReg<'_, A1>,
237 ) -> RetReg<R0> {
238 rustix_indirect_syscall2_nr_last_fastcall(a1, a0, nr, callee)
239 }
240 #[inline]
indirect_syscall3( callee: SyscallType, nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, a2: ArgReg<'_, A2>, ) -> RetReg<R0>241 pub(in crate::backend) unsafe fn indirect_syscall3(
242 callee: SyscallType,
243 nr: SyscallNumber<'_>,
244 a0: ArgReg<'_, A0>,
245 a1: ArgReg<'_, A1>,
246 a2: ArgReg<'_, A2>,
247 ) -> RetReg<R0> {
248 rustix_indirect_syscall3_nr_last_fastcall(a1, a2, a0, nr, callee)
249 }
250 #[inline]
indirect_syscall4( callee: SyscallType, nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, a2: ArgReg<'_, A2>, a3: ArgReg<'_, A3>, ) -> RetReg<R0>251 pub(in crate::backend) unsafe fn indirect_syscall4(
252 callee: SyscallType,
253 nr: SyscallNumber<'_>,
254 a0: ArgReg<'_, A0>,
255 a1: ArgReg<'_, A1>,
256 a2: ArgReg<'_, A2>,
257 a3: ArgReg<'_, A3>,
258 ) -> RetReg<R0> {
259 rustix_indirect_syscall4_nr_last_fastcall(a1, a2, a0, a3, nr, callee)
260 }
261 #[inline]
indirect_syscall5( callee: SyscallType, nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, a2: ArgReg<'_, A2>, a3: ArgReg<'_, A3>, a4: ArgReg<'_, A4>, ) -> RetReg<R0>262 pub(in crate::backend) unsafe fn indirect_syscall5(
263 callee: SyscallType,
264 nr: SyscallNumber<'_>,
265 a0: ArgReg<'_, A0>,
266 a1: ArgReg<'_, A1>,
267 a2: ArgReg<'_, A2>,
268 a3: ArgReg<'_, A3>,
269 a4: ArgReg<'_, A4>,
270 ) -> RetReg<R0> {
271 rustix_indirect_syscall5_nr_last_fastcall(a1, a2, a0, a3, a4, nr, callee)
272 }
273 #[inline]
indirect_syscall6( callee: SyscallType, nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>, a1: ArgReg<'_, A1>, a2: ArgReg<'_, A2>, a3: ArgReg<'_, A3>, a4: ArgReg<'_, A4>, a5: ArgReg<'_, A5>, ) -> RetReg<R0>274 pub(in crate::backend) unsafe fn indirect_syscall6(
275 callee: SyscallType,
276 nr: SyscallNumber<'_>,
277 a0: ArgReg<'_, A0>,
278 a1: ArgReg<'_, A1>,
279 a2: ArgReg<'_, A2>,
280 a3: ArgReg<'_, A3>,
281 a4: ArgReg<'_, A4>,
282 a5: ArgReg<'_, A5>,
283 ) -> RetReg<R0> {
284 rustix_indirect_syscall6_nr_last_fastcall(a1, a2, a0, a3, a4, a5, nr, callee)
285 }
286