1351282Sdim#if defined(__arm__) && defined(__linux__)
2351282Sdim
3351282Sdim#include "sanitizer_common/sanitizer_asm.h"
4351282Sdim
5351282SdimASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA)
6351282Sdim
7351282Sdim.comm _ZN14__interception10real_vforkE,4,4
8351282Sdim.globl ASM_WRAPPER_NAME(vfork)
9351282SdimASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork))
10351282SdimASM_WRAPPER_NAME(vfork):
11351282Sdim        // Save LR in the off-stack spill area.
12351282Sdim        push    {r4, lr}
13351282Sdim        bl      COMMON_INTERCEPTOR_SPILL_AREA
14351282Sdim        pop     {r4, lr}
15351282Sdim        str     lr, [r0]
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        ldr     r0, .LCPI0_0
20351282Sdim.LPC0_0:
21351282Sdim        ldr     r0, [pc, r0]
22351282Sdim        mov     lr, pc
23351282Sdim        bx      r0
24351282Sdim
25351282Sdim        push    {r0, r4}
26351282Sdim        cmp     r0, #0
27351282Sdim        beq     .L_exit
28351282Sdim
29351282Sdim        // r0 != 0 => parent process. Clear stack shadow.
30351282Sdim        add     r0, sp, #8
31351282Sdim        bl      COMMON_INTERCEPTOR_HANDLE_VFORK
32351282Sdim
33351282Sdim.L_exit:
34351282Sdim        // Restore LR.
35351282Sdim        bl      COMMON_INTERCEPTOR_SPILL_AREA
36351282Sdim        ldr     lr, [r0]
37351282Sdim        pop     {r0, r4}
38351282Sdim
39351282Sdim        mov     pc, lr
40351282Sdim
41351282Sdim.LCPI0_0:
42351282Sdim        .long   _ZN14__interception10real_vforkE - (.LPC0_0+8)
43351282Sdim
44351282SdimASM_SIZE(vfork)
45351282Sdim
46351282Sdim.weak vfork
47351282Sdim.set vfork, ASM_WRAPPER_NAME(vfork)
48351282Sdim
49351282Sdim#endif
50