2 /*--------------------------------------------------------------------*/
3 /*--- Support for doing system calls. syscall-amd64-linux.S ---*/
4 /*--------------------------------------------------------------------*/
7 This file is part of Valgrind, a dynamic binary instrumentation
10 Copyright (C) 2000-2017 Julian Seward
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, see <http://www.gnu.org/licenses/>.
26 The GNU General Public License is contained in the file COPYING.
29 #include "pub_core_basics_asm.h"
31 #if defined(VGP_amd64_linux)
33 #include "pub_core_vkiscnums_asm.h"
34 #include "libvex_guest_offsets.h"
37 /*----------------------------------------------------------------*/
39 Perform a syscall for the client. This will run a syscall
40 with the client's specific per-thread signal mask.
42 The structure of this function is such that, if the syscall is
43 interrupted by a signal, we can determine exactly what
44 execution state we were in with respect to the execution of
45 the syscall by examining the value of %eip in the signal
46 handler. This means that we can always do the appropriate
47 thing to precisely emulate the kernel's signal/syscall
50 The syscall number is taken from the argument, even though it
51 should also be in guest_state->guest_RAX. The syscall result
52 is written back to guest_state->guest_RAX on completion.
54 Returns 0 if the syscall was successfully called (even if the
55 syscall itself failed), or a -ve error code if one of the
56 sigprocmasks failed (there's no way to determine which one
59 VG_(fixup_guest_state_after_syscall_interrupted) does the
60 thread state fixup in the case where we were interrupted by a
65 Int ML_(do_syscall_for_client_WRK(
67 void* guest_state, // rsi
68 const vki_sigset_t *sysmask, // rdx
69 const vki_sigset_t *postmask, // rcx
75 #define VKI_SIG_SETMASK 2
77 .globl ML_(do_syscall_for_client_WRK)
78 ML_(do_syscall_for_client_WRK):
80 /* save callee-saved regs */
82 .cfi_adjust_cfa_offset 8
85 .cfi_adjust_cfa_offset 8
88 .cfi_adjust_cfa_offset 8
91 .cfi_adjust_cfa_offset 8
94 .cfi_adjust_cfa_offset 8
97 .cfi_adjust_cfa_offset 8
100 #define FSZ ((4+1)*4) /* 4 args + ret addr */
102 #define PUSH_di_si_dx_cx_8 \
104 .cfi_adjust_cfa_offset 8 ; \
106 .cfi_adjust_cfa_offset 8 ; \
108 .cfi_adjust_cfa_offset 8 ; \
110 .cfi_adjust_cfa_offset 8 ; \
112 .cfi_adjust_cfa_offset 8
114 #define POP_di_si_dx_cx_8 \
116 .cfi_adjust_cfa_offset -8 ; \
118 .cfi_adjust_cfa_offset -8 ; \
120 .cfi_adjust_cfa_offset -8 ; \
122 .cfi_adjust_cfa_offset -8 ; \
124 .cfi_adjust_cfa_offset -8
126 1: /* Even though we can't take a signal until the sigprocmask completes,
127 start the range early.
128 If eip is in the range [1,2), the syscall hasn't been started yet */
130 /* Set the signal mask which should be current during the syscall. */
131 /* Save and restore all 5 arg regs round the call. This is easier
132 than figuring out the minimal set to save/restore. */
136 movq $__NR_rt_sigprocmask, %rax // syscall #
137 movq $VKI_SIG_SETMASK, %rdi // how
138 movq %rdx, %rsi // sysmask
139 movq %rcx, %rdx // postmask
140 movq %r8, %r10 // sigsetSzB
146 js 7f /* sigprocmask failed */
148 /* OK, that worked. Now do the syscall proper. */
152 movq %rsi, %rax /* rax --> VexGuestAMD64State * */
153 pushq %rdi /* syscallno -> stack */
154 .cfi_adjust_cfa_offset 8
155 movq OFFSET_amd64_RDI(%rax), %rdi
156 movq OFFSET_amd64_RSI(%rax), %rsi
157 movq OFFSET_amd64_RDX(%rax), %rdx
158 movq OFFSET_amd64_R10(%rax), %r10
159 movq OFFSET_amd64_R8(%rax), %r8
160 movq OFFSET_amd64_R9(%rax), %r9
161 popq %rax /* syscallno -> %rax */
162 .cfi_adjust_cfa_offset -8
164 /* If rip==2, then the syscall was either just about
165 to start, or was interrupted and the kernel was
168 3: /* In the range [3, 4), the syscall result is in %rax,
169 but hasn't been committed to RAX. */
173 movq %rax, OFFSET_amd64_RAX(%rsi) /* save back to RAX */
175 4: /* Re-block signals. If eip is in [4,5), then the syscall
176 is complete and we needn't worry about it. */
180 movq $__NR_rt_sigprocmask, %rax // syscall #
181 movq $VKI_SIG_SETMASK, %rdi // how
182 movq %rcx, %rsi // postmask
183 xorq %rdx, %rdx // NULL
184 movq %r8, %r10 // sigsetSzB
190 js 7f /* sigprocmask failed */
192 5: /* now safe from signals */
193 movq $0, %rax /* SUCCESS */
195 .cfi_adjust_cfa_offset -8
197 .cfi_adjust_cfa_offset -8
199 .cfi_adjust_cfa_offset -8
201 .cfi_adjust_cfa_offset -8
203 .cfi_adjust_cfa_offset -8
205 .cfi_adjust_cfa_offset -8
207 .cfi_adjust_cfa_offset 6*8
209 7: /* failure: return 0x8000 | error code */
214 .cfi_adjust_cfa_offset -8
216 .cfi_adjust_cfa_offset -8
218 .cfi_adjust_cfa_offset -8
220 .cfi_adjust_cfa_offset -8
222 .cfi_adjust_cfa_offset -8
224 .cfi_adjust_cfa_offset -8
230 /* export the ranges so that
231 VG_(fixup_guest_state_after_syscall_interrupted) can do the
234 .globl ML_(blksys_setup)
235 .globl ML_(blksys_restart)
236 .globl ML_(blksys_complete)
237 .globl ML_(blksys_committed)
238 .globl ML_(blksys_finished)
239 ML_(blksys_setup): .quad 1b
240 ML_(blksys_restart): .quad 2b
241 ML_(blksys_complete): .quad 3b
242 ML_(blksys_committed): .quad 4b
243 ML_(blksys_finished): .quad 5b
246 #endif // defined(VGP_amd64_linux)
248 /* Let the linker know we don't need an executable stack */
251 /*--------------------------------------------------------------------*/
253 /*--------------------------------------------------------------------*/