AArch64(Apple M1)汇编调用nanosleep触发SIGSYS错误解决
问题现象
在Apple M1(对应AArch64架构)平台编写汇编代码调用nanosleep系统调用时,进程被异常终止,触发SIGSYS信号,报错信息如下:
terminated by signal SIGSYS (Bad system call)
复现逻辑为:尝试将可正常运行的C代码中bl nanosleep的调用逻辑替换为直接系统调用实现,参考公开的32位ARM系统调用表,认为0x65是nanosleep对应的系统调用号,编写的完整汇编逻辑如下:
mov x0, 2 str x0, [sp, 56] str xzr, [sp, 48] ldr x0, [sp, 56] str x0, [sp, 24] ldr x0, [sp, 48] str x0, [sp, 32] add x0, sp, 24 mov x1, 0 mov x16, 0x65 svc 0x80
问题产生原因
触发SIGSYS错误的核心原因是系统调用的参考依据和平台约定完全不匹配,具体有两点:
- 参考的系统调用表对应错误:查阅的是32位ARM EABI架构、ChromeOS系统的系统调用表,和Apple M1运行的macOS(Darwin内核)AArch64环境的系统调用号定义完全不兼容,
0x65在macOS AArch64下根本不是nanosleep的有效调用号,内核识别到非法调用号就会发送SIGSYS终止进程。 - 系统调用的触发规则不符合macOS平台要求:
- macOS AArch64的系统调用号按类型加固定偏移,BSD类系统调用需要在基础调用号上加
0x2000000的类偏移,nanosleep属于BSD类系统调用,基础调用号是0x57,实际传入x16寄存器的正确值应该是0x2000057。 - 系统调用触发指令的约定不匹配:
svc 0x80是32位类Unix平台的旧触发约定,macOS AArch64下触发系统调用只需要使用svc #0即可。
- macOS AArch64的系统调用号按类型加固定偏移,BSD类系统调用需要在基础调用号上加
正确调用方法
直接触发原始系统调用的正确汇编片段
; 栈上分配16字节空间存放timespec结构体 sub sp, sp, #16 ; 给timespec赋值:tv_sec=2(睡眠2秒),tv_nsec=0(0纳秒) mov x9, #2 str x9, [sp] str xzr, [sp, #8] ; 配置系统调用参数:x0指向timespec结构体,x1传0表示不需要存储剩余睡眠时长 mov x0, sp mov x1, #0 ; 写入正确的nanosleep系统调用号 mov x16, #0x2000057 ; 触发系统调用 svc #0 ; 回收栈空间 add sp, sp, #16
兼容性更好的实现方案
不推荐在用户态汇编代码里直接硬编码系统调用号,优先选择链接系统libc,直接通过bl _nanosleep调用libc封装好的nanosleep函数即可,这种方式不需要关心不同系统版本的调用号、调用约定变动,兼容性更强。
额外注意:macOS平台用户态直接发起原始系统调用时,需要严格遵守Darwin平台的调用约定,包括进入系统调用前的栈16字节对齐、参数寄存器的正确使用、返回值的错误码处理规则,否则即使调用号正确,也可能出现未知运行时错误。
内容的提问来源于stack exchange,提问作者jevoso5871
相关产品推荐
相关产品推荐

