ARM64汇编中limit变量为何被意外重置为0?
64位ARM汇编素数判断中变量被意外覆盖的问题分析与修复
问题根源
核心问题是数据类型宽度不匹配导致的内存越界覆盖:
- 你在
.data段用.word定义了testvalue、factor、limit,这是32位(4字节)的存储单元,且在内存中连续排列:testvalue→factor→limit。 - 但代码中使用了64位寄存器(X0、X1等)的
STR指令,这类指令会一次性写入8字节数据。
当执行第47行STR X1, [X0]时,X1的值是2(64位表示为0x0000000000000002),写入factor的4字节地址后,会额外覆盖后面4字节的内存——而这部分正好是limit的存储位置,limit被写入64位值的高4字节(全0),因此最终变为0。
从GDB调试时序看,第47行执行后GDB可能未立即刷新内存读取,直到步进至第49行时才显示出limit被覆盖后的0值。
解决方案
有两种可行的修复方式:
方式一:改用64位数据类型定义变量
将.data段中的.word替换为.dword(64位双字),让每个变量占用8字节,确保64位STR指令写入时不会越界覆盖相邻变量:
.data testvalue: .dword 0 // 64位存储单元 factor: .dword 0 // 64位存储单元 limit: .dword 0 // 64位存储单元
注意同步修改scanf和printf的格式符,将%d改为%ld以适配64位整数。
方式二:使用32位寄存器与指令
如果坚持使用32位.word变量,需改用32位寄存器(W0、W1等)和对应32位存储指令STR Wx, [Xy],确保只写入4字节:
- 第43行修改为:
STR W0, [X1](写入limit时只用32位寄存器的内容) - 第47行修改为:
STR W1, [X0](写入factor时只用32位寄存器的内容) - 所有读取变量的操作,也改用
LDR Wx, [Xy]读取32位值,例如第34行LDR W0, [X0]、第40行LDR W0, [X0]等。
额外优化建议
- 素数判断无需循环到
testvalue-1,只需循环到sqrt(testvalue)即可大幅减少循环次数。 - 可先判断输入是否为偶数,再从3开始以步进2的方式循环,进一步提升效率。
内容的提问来源于stack exchange,提问作者Andrew H
相关产品推荐
相关产品推荐

