Apple M1汇编:如何正确处理SIGINT并返回指定退出码?
Apple M1 ARM64汇编实现SIGINT捕获并以123退出
问题分析
1. 使用signal系统调用(0x8c)的问题
你遇到的退出码130(128 + 2,2是SIGINT的编号),本质是信号处理函数未正确执行,转而触发了默认的信号处理流程。原因有两点:
- 调用约定违反:ARM64信号处理函数需要遵守调用约定,必须保存
x29(帧指针)、x30(链接寄存器)等被调用者保存寄存器,否则会导致上下文混乱,内核转而执行默认处理。 signal的特性:signal注册的处理函数在执行一次后会自动恢复为默认处理逻辑,若处理函数未直接退出,后续信号会触发默认行为。
2. 使用sigaction系统调用(46)的段错误问题
段错误的核心是你定义的__sigaction结构体大小和布局不符合macOS ARM64的要求:
- macOS ARM64的
__sigaction结构体实际大小为32字节(而非你定义的24字节),字段布局包含sa_handler(8字节)、sa_mask(8字节)、sa_flags(4字节)、填充(4字节)、sa_restorer(8字节)。 - 结构体布局错误会导致
sigaction系统调用读取非法内存,触发段错误。
正确实现代码
.global _start .align 4 .text _start: // 注册SIGINT信号处理函数 mov x0, #2 // 信号编号:SIGINT adrp x1, nsa@PAGE add x1, x1, nsa@PAGEOFF // 指向__sigaction结构体的指针 mov x2, #0 // 不保存旧的信号处理结构(NULL) mov x16, #46 // sigaction系统调用号 svc #0x80 loop: // 无限循环 b loop // SIGINT处理函数 sigint_handler: // 建立栈帧,保存被调用者寄存器 stp x29, x30, [sp, #-16]! mov x29, sp // 以状态码123退出程序 mov x0, #123 mov x16, #1 // exit系统调用号 svc #0x80 // exit不会返回,此处仅为符合函数结构 ldp x29, x30, [sp], #16 ret .data .align 4 // __sigaction结构体(macOS ARM64布局) nsa: .quad sigint_handler // sa_handler:信号处理函数指针 .quad 0 // sa_mask:信号掩码,设为0 .word 0 // sa_flags:标志位,设为0 .word 0 // 填充4字节,保证8字节对齐 .quad 0 // sa_restorer:恢复函数,设为0即可
编译与运行
使用as和ld编译:
as -o sigint.o sigint.s ld -o sigint sigint.o
运行后按下Ctrl+C,执行echo $?即可看到退出码为123。
关键细节说明
- 栈帧的必要性:信号处理函数属于内核调用的函数,必须遵守ARM64调用约定,保存
x29和x30到栈中,否则会破坏进程上下文,导致不可预期的错误。 __sigaction结构体:macOS ARM64的结构体必须严格按照8字节对齐的要求定义,缺失填充字段或大小错误会导致系统调用读取非法内存。- 系统调用号:macOS ARM64的系统调用号与Linux不同,
exit是1,sigaction是46,需确保使用正确的编号。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

