ARM汇编中atoi函数使用异常:命令行参数校验触发段错误
问题分析与修复
你的段错误根源在于违反ARM64调用约定,同时存在一处参数传递错误,具体如下:
1. 被调用者保存寄存器未做栈保存
ARM64调用规范中,x19-x29属于被调用者保存寄存器——你的代码若要使用这些寄存器,必须先把它们的值保存到栈上,调用外部函数(如atoi、printf)后再恢复。你直接使用w19、w20、w21却未做栈保存,导致外部函数调用时这些寄存器被覆盖,后续访问argv_r(x21)或i_r(w19)时拿到非法地址/值,触发段错误。
2. top段中atoi的参数传递错误
top段里调用atoi时,你错误地将参数加载到x1,但atoi要求输入参数放在x0寄存器中,这会导致atoi读取垃圾值,进一步触发段错误。
修复后的代码
define(i_r, w19) define(argc_r, w20) define(argv_r, x21) fmt: .string "%d " err: .string "usage: a5b mm dd\n" .balign 4 .global main main: // 扩展栈空间,保存被调用者寄存器x19-x21 stp x29, x30, [sp, -32]! stp x19, x20, [sp, 16] str x21, [sp, 24] mov x29, sp mov argc_r, w0 // 保存argc mov argv_r, x1 // 保存argv mov i_r, 1 // 从第二个参数开始处理 cmp argc_r, 3 // 检查参数数量是否为3 b.ne error // 参数数量不对则跳转到错误处理 ldr x0, [argv_r, i_r, SXTW 3] // 加载第二个参数字符串 bl atoi // 转换为整数 cmp w0, 12 // 检查月份是否大于12 bgt error // 超出范围则报错 cmp w0, 0 // 检查月份是否小于0 blt error // 超出范围则报错 mov w1, w0 // 把转换后的整数传给printf的参数w1 adrp x0, fmt // 加载格式化字符串 add x0, x0, :lo12:fmt bl printf // 打印月份 add i_r, i_r, 1 // 切换到第三个参数 top: ldr x0, [argv_r, i_r, SXTW 3] // 加载当前参数字符串到x0(atoi的参数) bl atoi // 转换为整数 mov w1, w0 // 把转换后的整数传给printf的参数w1 adrp x0, fmt // 加载格式化字符串 add x0, x0, :lo12:fmt bl printf // 打印当前参数 add i_r, i_r, 1 // 切换到下一个参数 cmp i_r, argc_r // 检查是否处理完所有参数 b.lt top // 未处理完则继续循环 end: // 恢复被调用者寄存器 ldp x19, x20, [sp, 16] ldr x21, [sp, 24] ldp x29, x30, [sp], 32 ret error: adrp x0, err add x0, x0, :lo12:err bl printf b end
内容的提问来源于stack exchange,提问作者Jarvis
相关产品推荐
相关产品推荐

