1351282Sdim#if defined(__aarch64__) && defined(__linux__)
2351282Sdim
3351282Sdim#include "sanitizer_common/sanitizer_asm.h"
4351282Sdim
5351282SdimASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA)
6351282Sdim
7351282Sdim.comm _ZN14__interception10real_vforkE,8,8
8351282Sdim.globl ASM_WRAPPER_NAME(vfork)
9351282SdimASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork))
10351282SdimASM_WRAPPER_NAME(vfork):
11351282Sdim        // Save x30 in the off-stack spill area.
12351282Sdim        stp     xzr, x30, [sp, #-16]!
13351282Sdim        bl      COMMON_INTERCEPTOR_SPILL_AREA
14351282Sdim        ldp     xzr, x30, [sp], 16
15351282Sdim        str     x30, [x0]
16351282Sdim
17351282Sdim        // Call real vfork. This may return twice. User code that runs between the first and the second return
18351282Sdim        // may clobber the stack frame of the interceptor; that's why it does not have a frame.
19351282Sdim        adrp    x0, _ZN14__interception10real_vforkE
20351282Sdim        ldr     x0, [x0, :lo12:_ZN14__interception10real_vforkE]
21351282Sdim        blr     x0
22351282Sdim
23351282Sdim        stp     x0, xzr, [sp, #-16]!
24351282Sdim        cmp     x0, #0
25351282Sdim        b.eq   .L_exit
26351282Sdim
27351282Sdim        // x0 != 0 => parent process. Clear stack shadow.
28351282Sdim        add    x0, sp, #16
29351282Sdim        bl     COMMON_INTERCEPTOR_HANDLE_VFORK
30351282Sdim
31351282Sdim.L_exit:
32351282Sdim        // Restore x30.
33351282Sdim        bl     COMMON_INTERCEPTOR_SPILL_AREA
34351282Sdim        ldr    x30, [x0]
35351282Sdim        ldp    x0, xzr, [sp], 16
36351282Sdim
37351282Sdim        ret
38351282SdimASM_SIZE(vfork)
39351282Sdim
40351282Sdim.weak vfork
41351282Sdim.set vfork, ASM_WRAPPER_NAME(vfork)
42351282Sdim
43351282Sdim#endif
44