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