1#if defined(__loongarch_lp64) && defined(__linux__)
2
3#include "sanitizer_common/sanitizer_asm.h"
4
5ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA)
6ASM_HIDDEN(_ZN14__interception10real_vforkE)
7
8.bss
9.type _ZN14__interception10real_vforkE, @object
10.size _ZN14__interception10real_vforkE, 8
11_ZN14__interception10real_vforkE:
12        .zero     8
13
14.text
15.globl ASM_WRAPPER_NAME(vfork)
16ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork))
17ASM_WRAPPER_NAME(vfork):
18        // Save ra in the off-stack spill area.
19        // allocate space on stack
20        addi.d    $sp, $sp, -16
21        // store $ra value
22        st.d      $ra, $sp, 8
23        bl        COMMON_INTERCEPTOR_SPILL_AREA
24        // restore previous values from stack
25        ld.d      $ra, $sp, 8
26        // adjust stack
27        addi.d    $sp, $sp, 16
28        // store $ra by $a0
29        st.d      $ra, $a0, 0
30
31        // Call real vfork. This may return twice. User code that runs between the first and the second return
32        // may clobber the stack frame of the interceptor; that's why it does not have a frame.
33        la.local  $a0, _ZN14__interception10real_vforkE
34        ld.d      $a0, $a0, 0
35        jirl      $ra, $a0, 0
36
37        // adjust stack
38        addi.d    $sp, $sp, -16
39        // store $a0 by adjusted stack
40        st.d      $a0, $sp, 8
41        // jump to exit label if $a0 is 0
42        beqz      $a0, .L_exit
43
44        // $a0 != 0 => parent process. Clear stack shadow.
45        // put old $sp to $a0
46        addi.d    $a0, $sp, 16
47        bl        %plt(COMMON_INTERCEPTOR_HANDLE_VFORK)
48
49.L_exit:
50        // Restore $ra
51        bl        COMMON_INTERCEPTOR_SPILL_AREA
52        ld.d      $ra, $a0, 0
53        // load value by stack
54        ld.d      $a0, $sp, 8
55        // adjust stack
56        addi.d    $sp, $sp, 16
57        jr        $ra
58ASM_SIZE(vfork)
59
60.weak vfork
61.set vfork, ASM_WRAPPER_NAME(vfork)
62
63#endif
64