]>
Commit | Line | Data |
---|---|---|
353b0b11 FG |
1 | //! Syscall wrappers for platforms which pass the syscall number specially. |
2 | //! | |
3 | //! Rustix aims to minimize the amount of assembly code it needs. To that end, | |
4 | //! this code reorders syscall arguments as close as feasible to the actual | |
5 | //! syscall convention before calling the assembly functions. | |
6 | //! | |
7 | //! Many architectures use a convention where the syscall number is passed in a | |
8 | //! special register, with the regular syscall arguments passed in either the | |
9 | //! same or similar registers as the platform C convention. This code | |
10 | //! approximates that order by passing the regular syscall arguments first, and | |
11 | //! the syscall number last. That way, the outline assembly code typically just | |
12 | //! needs to move the syscall number to its special register, and leave the | |
13 | //! other arguments mostly as they are. | |
14 | ||
15 | #[cfg(target_arch = "mips")] | |
16 | use crate::backend::reg::A6; | |
17 | use crate::backend::reg::{ArgReg, RetReg, SyscallNumber, A0, A1, A2, A3, A4, A5, R0}; | |
18 | ||
19 | // First we declare the actual assembly routines with `*_nr_last` names and | |
20 | // reordered arguments. If the signatures or calling conventions are ever | |
21 | // changed, the symbol names should also be updated accordingly, to avoid | |
22 | // collisions with other versions of this crate. | |
23 | // | |
24 | // We don't define `_readonly` versions of these because we have no way to tell | |
25 | // Rust that calls to our outline assembly are readonly. | |
26 | extern "C" { | |
27 | fn rustix_syscall0_nr_last(nr: SyscallNumber<'_>) -> RetReg<R0>; | |
28 | fn rustix_syscall1_nr_last(a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>) -> RetReg<R0>; | |
29 | fn rustix_syscall1_noreturn_nr_last(a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>) -> !; | |
30 | fn rustix_syscall2_nr_last( | |
31 | a0: ArgReg<'_, A0>, | |
32 | a1: ArgReg<'_, A1>, | |
33 | nr: SyscallNumber<'_>, | |
34 | ) -> RetReg<R0>; | |
35 | fn rustix_syscall3_nr_last( | |
36 | a0: ArgReg<'_, A0>, | |
37 | a1: ArgReg<'_, A1>, | |
38 | a2: ArgReg<'_, A2>, | |
39 | nr: SyscallNumber<'_>, | |
40 | ) -> RetReg<R0>; | |
41 | fn rustix_syscall4_nr_last( | |
42 | a0: ArgReg<'_, A0>, | |
43 | a1: ArgReg<'_, A1>, | |
44 | a2: ArgReg<'_, A2>, | |
45 | a3: ArgReg<'_, A3>, | |
46 | nr: SyscallNumber<'_>, | |
47 | ) -> RetReg<R0>; | |
48 | fn rustix_syscall5_nr_last( | |
49 | a0: ArgReg<'_, A0>, | |
50 | a1: ArgReg<'_, A1>, | |
51 | a2: ArgReg<'_, A2>, | |
52 | a3: ArgReg<'_, A3>, | |
53 | a4: ArgReg<'_, A4>, | |
54 | nr: SyscallNumber<'_>, | |
55 | ) -> RetReg<R0>; | |
56 | fn rustix_syscall6_nr_last( | |
57 | a0: ArgReg<'_, A0>, | |
58 | a1: ArgReg<'_, A1>, | |
59 | a2: ArgReg<'_, A2>, | |
60 | a3: ArgReg<'_, A3>, | |
61 | a4: ArgReg<'_, A4>, | |
62 | a5: ArgReg<'_, A5>, | |
63 | nr: SyscallNumber<'_>, | |
64 | ) -> RetReg<R0>; | |
65 | #[cfg(target_arch = "mips")] | |
66 | fn rustix_syscall7_nr_last( | |
67 | a0: ArgReg<'_, A0>, | |
68 | a1: ArgReg<'_, A1>, | |
69 | a2: ArgReg<'_, A2>, | |
70 | a3: ArgReg<'_, A3>, | |
71 | a4: ArgReg<'_, A4>, | |
72 | a5: ArgReg<'_, A5>, | |
73 | a6: ArgReg<'_, A6>, | |
74 | nr: SyscallNumber<'_>, | |
75 | ) -> RetReg<R0>; | |
76 | } | |
77 | ||
78 | // Then we define inline wrapper functions that do the reordering. | |
79 | ||
80 | #[inline] | |
81 | pub(in crate::backend) unsafe fn syscall0(nr: SyscallNumber<'_>) -> RetReg<R0> { | |
82 | rustix_syscall0_nr_last(nr) | |
83 | } | |
84 | #[inline] | |
85 | pub(in crate::backend) unsafe fn syscall1(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> RetReg<R0> { | |
86 | rustix_syscall1_nr_last(a0, nr) | |
87 | } | |
88 | #[inline] | |
89 | pub(in crate::backend) unsafe fn syscall1_noreturn(nr: SyscallNumber<'_>, a0: ArgReg<'_, A0>) -> ! { | |
90 | rustix_syscall1_noreturn_nr_last(a0, nr) | |
91 | } | |
92 | #[inline] | |
93 | pub(in crate::backend) unsafe fn syscall2( | |
94 | nr: SyscallNumber<'_>, | |
95 | a0: ArgReg<'_, A0>, | |
96 | a1: ArgReg<'_, A1>, | |
97 | ) -> RetReg<R0> { | |
98 | rustix_syscall2_nr_last(a0, a1, nr) | |
99 | } | |
100 | #[inline] | |
101 | pub(in crate::backend) unsafe fn syscall3( | |
102 | nr: SyscallNumber<'_>, | |
103 | a0: ArgReg<'_, A0>, | |
104 | a1: ArgReg<'_, A1>, | |
105 | a2: ArgReg<'_, A2>, | |
106 | ) -> RetReg<R0> { | |
107 | rustix_syscall3_nr_last(a0, a1, a2, nr) | |
108 | } | |
109 | #[inline] | |
110 | pub(in crate::backend) unsafe fn syscall4( | |
111 | nr: SyscallNumber<'_>, | |
112 | a0: ArgReg<'_, A0>, | |
113 | a1: ArgReg<'_, A1>, | |
114 | a2: ArgReg<'_, A2>, | |
115 | a3: ArgReg<'_, A3>, | |
116 | ) -> RetReg<R0> { | |
117 | rustix_syscall4_nr_last(a0, a1, a2, a3, nr) | |
118 | } | |
119 | #[inline] | |
120 | pub(in crate::backend) unsafe fn syscall5( | |
121 | nr: SyscallNumber<'_>, | |
122 | a0: ArgReg<'_, A0>, | |
123 | a1: ArgReg<'_, A1>, | |
124 | a2: ArgReg<'_, A2>, | |
125 | a3: ArgReg<'_, A3>, | |
126 | a4: ArgReg<'_, A4>, | |
127 | ) -> RetReg<R0> { | |
128 | rustix_syscall5_nr_last(a0, a1, a2, a3, a4, nr) | |
129 | } | |
130 | #[inline] | |
131 | pub(in crate::backend) unsafe fn syscall6( | |
132 | nr: SyscallNumber<'_>, | |
133 | a0: ArgReg<'_, A0>, | |
134 | a1: ArgReg<'_, A1>, | |
135 | a2: ArgReg<'_, A2>, | |
136 | a3: ArgReg<'_, A3>, | |
137 | a4: ArgReg<'_, A4>, | |
138 | a5: ArgReg<'_, A5>, | |
139 | ) -> RetReg<R0> { | |
140 | rustix_syscall6_nr_last(a0, a1, a2, a3, a4, a5, nr) | |
141 | } | |
142 | #[cfg(target_arch = "mips")] | |
143 | #[inline] | |
144 | pub(in crate::backend) unsafe fn syscall7( | |
145 | nr: SyscallNumber<'_>, | |
146 | a0: ArgReg<'_, A0>, | |
147 | a1: ArgReg<'_, A1>, | |
148 | a2: ArgReg<'_, A2>, | |
149 | a3: ArgReg<'_, A3>, | |
150 | a4: ArgReg<'_, A4>, | |
151 | a5: ArgReg<'_, A5>, | |
152 | a6: ArgReg<'_, A6>, | |
153 | ) -> RetReg<R0> { | |
154 | rustix_syscall7_nr_last(a0, a1, a2, a3, a4, a5, a6, nr) | |
155 | } | |
156 | ||
157 | // Then we define the `_readonly` versions of the wrappers. We don't have | |
158 | // separate `_readonly` implementations, so these can just be aliases to | |
159 | // their non-`_readonly` counterparts. | |
160 | #[cfg(target_arch = "mips")] | |
161 | pub(in crate::backend) use syscall7 as syscall7_readonly; | |
162 | pub(in crate::backend) use { | |
163 | syscall0 as syscall0_readonly, syscall1 as syscall1_readonly, syscall2 as syscall2_readonly, | |
164 | syscall3 as syscall3_readonly, syscall4 as syscall4_readonly, syscall5 as syscall5_readonly, | |
165 | syscall6 as syscall6_readonly, | |
166 | }; |