blob: 05192485d597170615a06fcb41d967134c92b060 [file] [log] [blame]
#if defined(__loongarch_lp64) && defined(__linux__)
#include "sanitizer_common/sanitizer_asm.h"
ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA)
ASM_HIDDEN(_ZN14__interception10real_vforkE)
.bss
.type _ZN14__interception10real_vforkE, @object
.size _ZN14__interception10real_vforkE, 8
_ZN14__interception10real_vforkE:
.zero 8
.text
.globl ASM_WRAPPER_NAME(vfork)
ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork))
ASM_WRAPPER_NAME(vfork):
// Save ra in the off-stack spill area.
// allocate space on stack
addi.d $sp, $sp, -16
// store $ra value
st.d $ra, $sp, 8
bl COMMON_INTERCEPTOR_SPILL_AREA
// restore previous values from stack
ld.d $ra, $sp, 8
// adjust stack
addi.d $sp, $sp, 16
// store $ra by $a0
st.d $ra, $a0, 0
// Call real vfork. This may return twice. User code that runs between the first and the second return
// may clobber the stack frame of the interceptor; that's why it does not have a frame.
la.local $a0, _ZN14__interception10real_vforkE
ld.d $a0, $a0, 0
jirl $ra, $a0, 0
// adjust stack
addi.d $sp, $sp, -16
// store $a0 by adjusted stack
st.d $a0, $sp, 8
// jump to exit label if $a0 is 0
beqz $a0, .L_exit
// $a0 != 0 => parent process. Clear stack shadow.
// put old $sp to $a0
addi.d $a0, $sp, 16
bl %plt(COMMON_INTERCEPTOR_HANDLE_VFORK)
.L_exit:
// Restore $ra
bl COMMON_INTERCEPTOR_SPILL_AREA
ld.d $ra, $a0, 0
// load value by stack
ld.d $a0, $sp, 8
// adjust stack
addi.d $sp, $sp, 16
jr $ra
ASM_SIZE(vfork)
.weak vfork
.set vfork, ASM_WRAPPER_NAME(vfork)
#endif