2 * Copyright (c) 2014 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
7 #ifndef NATIVE_CLIENT_SRC_NONSFI_LINUX_LINUX_SYSCALL_WRAPPERS_H_
8 #define NATIVE_CLIENT_SRC_NONSFI_LINUX_LINUX_SYSCALL_WRAPPERS_H_ 1
11 * Wrappers for calling Linux syscalls directly.
13 * This provides functionality similar to linux_syscall_support.h (from
14 * https://code.google.com/p/linux-syscall-support/), also known as LSS.
15 * We are not reusing LSS here because:
17 * * LSS depends on Linux kernel headers (and glibc headers, to a lesser
18 * extent). We would have to import these into the NaCl build and
19 * resolve conflicts that they have with nacl-newlib's headers.
21 * * We have peculiar requirements such as needing to execute syscalls
22 * from specific program counter addresses in memory, in order to
23 * whitelist these addresses in a seccomp-bpf filter. LSS's
24 * SYS_SYSCALL_ENTRYPOINT is more complex than what we need, and also
25 * won't work with clone().
27 * * LSS lacks a test suite, so even if we got it working with the
28 * nacl-newlib toolchain, this usage might easily be broken by future
37 * Registers used for system call parameters on x86-32:
38 * %eax - system call number and return value
39 * %ebx - argument 1, preserved
40 * %ecx - argument 2, preserved
41 * %edx - argument 3, preserved
42 * %esi - argument 4, preserved
43 * %edi - argument 5, preserved
44 * %ebp - argument 6, preserved
47 static inline uint32_t linux_syscall0(int syscall_number) {
49 __asm__ __volatile__("int $0x80\n"
51 : "a"(syscall_number));
55 static inline uint32_t linux_syscall1(int syscall_number, uint32_t arg1) {
57 __asm__ __volatile__("int $0x80\n"
59 : "a"(syscall_number), "b"(arg1));
63 static inline uint32_t linux_syscall2(int syscall_number,
64 uint32_t arg1, uint32_t arg2) {
66 __asm__ __volatile__("int $0x80\n"
68 : "a"(syscall_number), "b"(arg1), "c"(arg2));
72 static inline uint32_t linux_syscall3(int syscall_number,
73 uint32_t arg1, uint32_t arg2,
76 __asm__ __volatile__("int $0x80\n"
78 : "a"(syscall_number), "b"(arg1), "c"(arg2), "d"(arg3));
82 static inline uint32_t linux_syscall4(int syscall_number,
83 uint32_t arg1, uint32_t arg2,
84 uint32_t arg3, uint32_t arg4) {
86 __asm__ __volatile__("int $0x80\n"
88 : "a"(syscall_number), "b"(arg1), "c"(arg2), "d"(arg3),
93 static inline uint32_t linux_syscall5(int syscall_number,
94 uint32_t arg1, uint32_t arg2,
95 uint32_t arg3, uint32_t arg4,
98 __asm__ __volatile__("int $0x80\n"
100 : "a"(syscall_number), "b"(arg1), "c"(arg2), "d"(arg3),
101 "S"(arg4), "D"(arg5));
105 static inline uint32_t linux_syscall6(int syscall_number,
106 uint32_t arg1, uint32_t arg2,
107 uint32_t arg3, uint32_t arg4,
108 uint32_t arg5, uint32_t arg6) {
110 * Inline assembly doesn't let us use a constraint to set %ebp, which is
111 * the 6th syscall argument on x86-32. To set %ebp, we use the trick of
112 * saving some registers on the stack.
114 * Note, however, that this means unwind info will be incorrect during
117 uint32_t args[2] = { arg1, arg6 };
119 __asm__ __volatile__("push %%ebp\n"
120 "movl 4(%%ebx), %%ebp\n" /* arg6 */
121 "movl 0(%%ebx), %%ebx\n" /* arg1 */
125 : "a"(syscall_number), "b"(&args),
126 "c"(arg2), "d"(arg3), "S"(arg4), "D"(arg5)
131 #elif defined(__arm__)
134 * Registers used for system call parameters on ARM EABI:
135 * r7 - system call number
136 * r0 - argument 1 and return value
137 * r1 - argument 2, preserved
138 * r2 - argument 3, preserved
139 * r3 - argument 4, preserved
140 * r4 - argument 5, preserved
141 * r5 - argument 6, preserved
144 static inline uint32_t linux_syscall0(int syscall_number) {
145 register uint32_t sysno __asm__("r7") = syscall_number;
146 register uint32_t result __asm__("r0");
147 __asm__ __volatile__("svc #0\n"
154 static inline uint32_t linux_syscall1(int syscall_number, uint32_t arg1) {
155 register uint32_t sysno __asm__("r7") = syscall_number;
156 register uint32_t a1 __asm__("r0") = arg1;
157 register uint32_t result __asm__("r0");
158 __asm__ __volatile__("svc #0\n"
160 : "r"(sysno), "r"(a1)
165 static inline uint32_t linux_syscall2(int syscall_number,
166 uint32_t arg1, uint32_t arg2) {
167 register uint32_t sysno __asm__("r7") = syscall_number;
168 register uint32_t a1 __asm__("r0") = arg1;
169 register uint32_t a2 __asm__("r1") = arg2;
170 register uint32_t result __asm__("r0");
171 __asm__ __volatile__("svc #0\n"
173 : "r"(sysno), "r"(a1), "r"(a2)
178 static inline uint32_t linux_syscall3(int syscall_number,
179 uint32_t arg1, uint32_t arg2,
181 register uint32_t sysno __asm__("r7") = syscall_number;
182 register uint32_t a1 __asm__("r0") = arg1;
183 register uint32_t a2 __asm__("r1") = arg2;
184 register uint32_t a3 __asm__("r2") = arg3;
185 register uint32_t result __asm__("r0");
186 __asm__ __volatile__("svc #0\n"
188 : "r"(sysno), "r"(a1), "r"(a2), "r"(a3)
193 static inline uint32_t linux_syscall4(int syscall_number,
194 uint32_t arg1, uint32_t arg2,
195 uint32_t arg3, uint32_t arg4) {
196 register uint32_t sysno __asm__("r7") = syscall_number;
197 register uint32_t a1 __asm__("r0") = arg1;
198 register uint32_t a2 __asm__("r1") = arg2;
199 register uint32_t a3 __asm__("r2") = arg3;
200 register uint32_t a4 __asm__("r3") = arg4;
201 register uint32_t result __asm__("r0");
202 __asm__ __volatile__("svc #0\n"
205 "r"(a1), "r"(a2), "r"(a3), "r"(a4)
210 static inline uint32_t linux_syscall5(int syscall_number,
211 uint32_t arg1, uint32_t arg2,
212 uint32_t arg3, uint32_t arg4,
214 register uint32_t sysno __asm__("r7") = syscall_number;
215 register uint32_t a1 __asm__("r0") = arg1;
216 register uint32_t a2 __asm__("r1") = arg2;
217 register uint32_t a3 __asm__("r2") = arg3;
218 register uint32_t a4 __asm__("r3") = arg4;
219 register uint32_t a5 __asm__("r4") = arg5;
220 register uint32_t result __asm__("r0");
221 __asm__ __volatile__("svc #0\n"
224 "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5)
229 static inline uint32_t linux_syscall6(int syscall_number,
230 uint32_t arg1, uint32_t arg2,
231 uint32_t arg3, uint32_t arg4,
232 uint32_t arg5, uint32_t arg6) {
233 register uint32_t sysno __asm__("r7") = syscall_number;
234 register uint32_t a1 __asm__("r0") = arg1;
235 register uint32_t a2 __asm__("r1") = arg2;
236 register uint32_t a3 __asm__("r2") = arg3;
237 register uint32_t a4 __asm__("r3") = arg4;
238 register uint32_t a5 __asm__("r4") = arg5;
239 register uint32_t a6 __asm__("r5") = arg6;
240 register uint32_t result __asm__("r0");
241 __asm__ __volatile__("svc #0\n"
244 "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(a6)
250 # error Unsupported architecture
253 static inline int linux_is_error_result(uint32_t result) {
255 * -0x1000 is the highest address that mmap() can return as a result.
256 * Linux errno values are less than 0x1000.
258 return result > (uint32_t) -0x1000;