ARM汇编字符串反转代码触发Segmentation fault问题求助及疑问
ARM汇编字符串反转程序的段错误排查与修复
我编写了一段用于反转输入字符串的ARM汇编代码,运行时在revstr()函数的pa2.s:37行ldrb w10, [x9, 0]处触发Segmentation fault(段错误)。同时不确定打印反转字符串的字符时,是否需要每次将栈指针sp加16,求解答。
代码如下:
.section .data input_prompt : .asciz "Please enter a string: " input_format: .asciz "%[^\n]" output_format: .asciz "%c" new_line_format: .ascii "\n" .section .text .global main main: # set i = 0 add x19, xzr, xzr # print string ldr x0, = input_prompt bl printf sub sp, sp, 16 ldr x0, = input_format mov x1, sp bl scanf mov x0, sp bl revstr add sp, sp, 16 #======================================== revstr: sub sp, sp, 16 str lr, [sp, 0] # get string[i] # i=0 first char i = size last char add x9, x19, x0 ldrb w10, [x9] strb w10, [sp, 8] # print inorder mov w1, w10 ldr x0, =output_format bl printf # if w10 is '\0'(ASCII #10) cbz w10, ret add x19, x19, 1 bl revstr # lr start ldr w1, [sp, 8] ldr x0, =output_format bl printf #======================================== ret: ldr lr, [sp, 0] add sp, sp, 8 br lr # branch to this label on program completion exit: mov x0, 0 mov x8, 93 svc 0 ret
一、段错误的原因
- 递归未保存调用保存寄存器x19:x19是ARM架构中属于「被调用者保存」的寄存器,函数如果要修改它,必须先把原值存在栈里,退出时恢复。你的代码递归调用
revstr时,每次直接修改x19(作为索引i)但未保存状态,导致递归深入后x19持续累加,算出的内存地址超出栈上分配的16字节字符串缓冲区范围,访问非法内存触发段错误。 - 栈平衡异常:
revstr开头用sub sp, sp, 16分配了16字节栈空间,但ret标签处只执行add sp, sp, 8释放8字节,每次递归都会导致栈指针无法正确回退,进一步加剧内存访问异常。 - 注释误导:代码注释写的是判断'\0'(ASCII 10),但实际
cbz w10, ret是判断w10为0(即字符串结束符'\0'),逻辑本身没问题,但注释容易造成混淆。
二、修复方案
针对上述问题,修改后的revstr函数如下:
revstr: sub sp, sp, 32 # 分配32字节栈空间,满足16字节对齐,用于保存lr、x19和当前字符 str lr, [sp, 0] str x19, [sp, 8] # 保存x19的原值到栈 add x9, x19, x0 ldrb w10, [x9] strb w10, [sp, 16] # 存储当前读取的字符 # 打印当前字符(前序遍历) mov w1, w10 ldr x0, =output_format bl printf cbz w10, ret_revstr # 遇到字符串结束符'\0'则跳转返回 add x19, x19, 1 bl revstr # 打印当前字符(后序遍历,实现反转效果) ldr w1, [sp, 16] ldr x0, =output_format bl printf ret_revstr: ldr x19, [sp, 8] # 恢复x19的原值 ldr lr, [sp, 0] add sp, sp, 32 # 释放全部栈空间,维持栈平衡 br lr
额外注意:ARM64调用规范要求栈指针始终保持16字节对齐,所以分配栈空间时必须使用16的倍数。
三、关于栈指针sp的疑问
打印反转字符串的字符时不需要每次将sp加16。栈指针sp仅在以下场景需要调整:
- 需要在栈上临时存储数据、保存寄存器时,用
sub sp分配空间; - 使用完栈上空间后,用
add sp释放,且必须保证分配和释放的字节数一致,维持栈平衡。
调用printf之前,只要栈已经处于16字节对齐状态(修改后的代码已保证),就无需额外调整sp。
内容的提问来源于stack exchange,提问作者user21740627
相关产品推荐
相关产品推荐

