Files
scriptc/packages/runtime/test/test_unwind_frames.S
T
Chris Tate d5ac31f812 Raise through cached unwind plans on x86-64 Linux
scr_unwind_raise walks the stack with plans cached per return address.
The first raise through a return address finds the function's FDE
through the .eh_frame_hdr of the object that contains it, runs the CFI
up to the call, and finds the call site's landing pad in the LSDA; the
plan records the frame's CFA rule, where its callee-saved registers are
saved, and the landing pad. Later raises look the plans up, restore the
registers, and jump to the first landing pad. Plans are inserted under
a lock and read without one.

Landing pads continue the unwind with scr_unwind_resume instead of
`resume`, so the walk goes on from their frame. A frame whose CFI,
pointer encodings or personality the plans do not express, or a return
address without an FDE, leaves the unwind to libgcc's forced unwind
from the frame the walk started at, as before. Other Linux targets keep
libgcc's unwinder; their scr_unwind_resume calls _Unwind_Resume.

bench:runtime gains layered-errors, a workload whose errors are thrown
below small functions that hold references and caught per entry in a
loop, and the corpus gains unwind-landing-pad-chains, which pins landing
pads that continue the unwind, including in frames LLVM inlines into a
caller whose handler takes the exception.
2026-10-28 00:22:04 -05:00

102 lines
2.3 KiB
ArmAsm

/* Frames for test_unwind.c with CFI that compilers emit rarely. Like the
* frames in test_unwind_frames.ll, each takes a chain and calls its first
* function with the rest. */
.text
/* Saves rbx and r12, and leaves through an early epilogue under
* remember_state before its call, so the call's rules come from
* restore_state. */
.globl asm_remember
.type asm_remember,@function
asm_remember:
.cfi_startproc
pushq %rbx
.cfi_def_cfa_offset 16
.cfi_offset %rbx, -16
pushq %r12
.cfi_def_cfa_offset 24
.cfi_offset %r12, -24
subq $8, %rsp
.cfi_def_cfa_offset 32
movq (%rdi), %rax
testq %rax, %rax
jne 1f
.cfi_remember_state
addq $8, %rsp
.cfi_def_cfa_offset 24
popq %r12
.cfi_def_cfa_offset 16
.cfi_restore %r12
popq %rbx
.cfi_def_cfa_offset 8
.cfi_restore %rbx
retq
.cfi_restore_state
1:
movabsq $0x5151515151515151, %rbx
movabsq $0x5252525252525252, %r12
addq $8, %rdi
callq *%rax
addq $8, %rsp
.cfi_def_cfa_offset 24
popq %r12
.cfi_def_cfa_offset 16
popq %rbx
.cfi_def_cfa_offset 8
retq
.cfi_endproc
.size asm_remember, .-asm_remember
/* An rbp frame that saves r13 and r14 below rbp and moves the stack
* pointer by an amount that depends on the chain's address. */
.globl asm_rbp
.type asm_rbp,@function
asm_rbp:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
pushq %r13
pushq %r14
.cfi_offset %r13, -24
.cfi_offset %r14, -32
movq %rdi, %rax
andq $0x70, %rax
subq %rax, %rsp
movabsq $0x5353535353535353, %r13
movabsq $0x5454545454545454, %r14
movq (%rdi), %rax
addq $8, %rdi
callq *%rax
leaq -16(%rbp), %rsp
popq %r14
popq %r13
popq %rbp
.cfi_def_cfa %rsp, 8
retq
.cfi_endproc
.size asm_rbp, .-asm_rbp
/* Defines its CFA with a DWARF expression (rsp + 16), which the plans do
* not express: raises through it go to libgcc's unwinder. */
.globl asm_expr
.type asm_expr,@function
asm_expr:
.cfi_startproc
pushq %rbx
.cfi_escape 0x0f, 0x02, 0x77, 0x10
.cfi_offset %rbx, -16
movabsq $0x5555555555555555, %rbx
movq (%rdi), %rax
addq $8, %rdi
callq *%rax
popq %rbx
.cfi_def_cfa %rsp, 8
retq
.cfi_endproc
.size asm_expr, .-asm_expr
.section .note.GNU-stack,"",@progbits