Apple Silicon(aarch64 macOS)汇编中_scanf使用段错误问题排查
问题分析与修复
你的代码存在几个AArch64汇编调用规范和数据类型匹配的核心问题,直接导致了段错误:
错误点1:栈未遵循AArch64对齐要求
AArch64调用约定明确要求,调用外部函数(如_printf、_scanf)时,栈指针SP必须是16字节的整数倍。你的代码进入main后未做栈对齐初始化,调用_scanf时栈状态不符合规范,触发段错误。
错误点2:数据读取类型不匹配
num定义为.word(4字节32位整数),但你用LDR X1, [X10]按64位读取,会从num地址开始读取8字节,越界访问后续内存,引发数据错误或段错误。同时scanf的%d格式符需要32位整数指针,虽然地址传递本身没问题,但后续读取操作的类型不匹配会破坏内存状态。
错误点3:printf参数传递方式错误
AArch64中,printf的前8个整数参数通过X0-X7寄存器传递,你不需要把数字存入栈中,直接将目标值放到X1寄存器即可。
错误点4:退出方式不符合macOS规范
你使用的mov X16, #1加svc 0是Linux的退出方式,在Apple Silicon的macOS上应调用标准_exit函数。
修正后的代码
.global main .align 4 main: // 初始化栈对齐,保存帧指针和链接寄存器,符合AArch64栈帧规范 sub sp, sp, #16 stp x29, x30, [sp] mov x29, sp // 打印提示消息 ADRP X0, message@PAGE ADD X0, X0, message@PAGEOFF BL _printf // 调用键盘输入函数 BL read_from_keyboard // 准备printf参数:X0为格式串,X1为要打印的32位数字(自动零扩展为64位) ADRP X0, output_format@PAGE ADD X0, X0, output_format@PAGEOFF ADRP X10, num@PAGE ADD X10, X10, num@PAGEOFF LDR W1, [X10] BL _printf // 恢复栈并规范退出 ldp x29, x30, [sp] add sp, sp, #16 mov x0, #0 BL _exit read_from_keyboard: // 传递scanf参数:X0为格式串,X1为num的地址 ADRP X0, input_format@PAGE ADD X0, X0, input_format@PAGEOFF ADRP X1, num@PAGE ADD X1, X1, num@PAGEOFF BL _scanf ret .data .balign 4 message: .asciz "What is your favorite number?\n" .balign 4 num: .word 32 .balign 4 input_format: .asciz "%d" .balign 4 output_format: .asciz "Your favorite number is %d \n"
关键修改说明
- 栈对齐初始化:在
main开头调整栈并保存FP(x29)和LR(x30),确保调用外部函数时SP始终保持16字节对齐。 - 正确读取32位整数:用
LDR W1, [X10]读取num的32位值,自动零扩展到X1寄存器,匹配printf的%d格式处理逻辑。 - 简化参数传递:调用
_scanf时直接用X1传递num的地址,符合AArch64调用约定的参数传递规则。 - 规范退出流程:调用
_exit函数退出程序,适配Apple Silicon macOS的系统调用规范。
内容的提问来源于stack exchange,提问作者Jeffrey Shaffer
相关产品推荐
相关产品推荐

