| 1 | #if defined(__aarch64__) && defined(__linux__) |
| 2 | |
| 3 | #include "sanitizer_common/sanitizer_asm.h" |
| 4 | #include "builtins/assembly.h" |
| 5 | |
| 6 | ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA) |
| 7 | |
| 8 | .comm _ZN14__interception10real_vforkE,8,8 |
| 9 | .globl ASM_WRAPPER_NAME(vfork) |
| 10 | ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork)) |
| 11 | ASM_WRAPPER_NAME(vfork): |
| 12 | // Save x30 in the off-stack spill area. |
| 13 | hint #25 // paciasp |
| 14 | stp xzr, x30, [sp, #-16]! |
| 15 | bl COMMON_INTERCEPTOR_SPILL_AREA |
| 16 | ldp xzr, x30, [sp], 16 |
| 17 | str x30, [x0] |
| 18 | |
| 19 | // Call real vfork. This may return twice. User code that runs between the first and the second return |
| 20 | // may clobber the stack frame of the interceptor; that's why it does not have a frame. |
| 21 | adrp x0, _ZN14__interception10real_vforkE |
| 22 | ldr x0, [x0, :lo12:_ZN14__interception10real_vforkE] |
| 23 | blr x0 |
| 24 | |
| 25 | stp x0, xzr, [sp, #-16]! |
| 26 | cmp x0, #0 |
| 27 | b.eq .L_exit |
| 28 | |
| 29 | // x0 != 0 => parent process. Clear stack shadow. |
| 30 | add x0, sp, #16 |
| 31 | bl COMMON_INTERCEPTOR_HANDLE_VFORK |
| 32 | |
| 33 | .L_exit: |
| 34 | // Restore x30. |
| 35 | bl COMMON_INTERCEPTOR_SPILL_AREA |
| 36 | ldr x30, [x0] |
| 37 | ldp x0, xzr, [sp], 16 |
| 38 | hint #29 // autiasp |
| 39 | |
| 40 | ret |
| 41 | ASM_SIZE(vfork) |
| 42 | |
| 43 | ASM_INTERCEPTOR_TRAMPOLINE(vfork) |
| 44 | ASM_TRAMPOLINE_ALIAS(vfork, vfork) |
| 45 | |
| 46 | GNU_PROPERTY_BTI_PAC |
| 47 | |
| 48 | #endif |
| 49 | |