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_fastcallnull28 fn rustix_syscall0_nr_last_fastcall(nr: SyscallNumber<'_>) -> RetReg<R0>; 29 fn rustix_syscall1_nr_last_fastcall(a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>) -> RetReg<R0>; rustix_syscall1_noreturn_nr_last_fastcallnull30 fn rustix_syscall1_noreturn_nr_last_fastcall(a0: ArgReg<'_, A0>, nr: SyscallNumber<'_>) -> !; rustix_syscall2_nr_last_fastcallnull31 fn rustix_syscall2_nr_last_fastcall( 32 a1: ArgReg<'_, A1>, 33 a0: ArgReg<'_, A0>, 34 nr: SyscallNumber<'_>, 35 ) -> RetReg<R0>; rustix_syscall3_nr_last_fastcallnull36 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_fastcallnull42 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_fastcallnull49 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_fastcallnull57 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] 71 pub(in crate::backend) unsafe fn syscall0(nr: SyscallNumber<'_>) -> RetReg<R0> { 72 rustix_syscall0_nr_last_fastcall(nr) 73 } 74 #[inline] 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] 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] 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] 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] 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] 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] 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_fastcallnull150 fn rustix_indirect_syscall0_nr_last_fastcall( 151 nr: SyscallNumber<'_>, 152 callee: SyscallType, 153 ) -> RetReg<R0>; rustix_indirect_syscall1_nr_last_fastcallnull154 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_fastcallnull159 fn rustix_indirect_syscall1_noreturn_nr_last_fastcall( 160 a0: ArgReg<'_, A0>, 161 nr: SyscallNumber<'_>, 162 callee: SyscallType, 163 ) -> !; rustix_indirect_syscall2_nr_last_fastcallnull164 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_fastcallnull170 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_fastcallnull177 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_fastcallnull185 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_fastcallnull194 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] 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] 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] 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] 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] 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] 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] 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] 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