循环中能否用非常量值计算有效地址?NASM汇编报错求助
问题分析与解决方案
核心问题拆解
- 寻址模式不合法:x86-64架构不支持
[rbp - rdx]这种直接用两个寄存器相减的内存寻址方式,仅允许基址寄存器 + 索引寄存器×比例 + 位移量的组合(位移量可正可负,但不能是两个寄存器直接相减)。 - 指令语法错误:NASM中64位环境的整数乘法指令应为
imul,而非mult(后者是32位模式下的无符号乘法指令,不符合64位语法要求)。 - 逻辑偏差:你原本希望每次将乘数加1(使偏移量递增8),但当前代码在计算出偏移量后直接对偏移量自增,导致下次的乘数被错误设置为偏移量,完全偏离了“每次偏移量+8”的预期。
修正后的代码
filter: push rbp mov rbp, rsp sub rsp, 128 mov dword [rbp], 1 ; 初始乘数设为1,用dword确保32位整数写入,自动零扩展为64位 save: ; 计算正确地址并保存RSI push rdx ; 提前保存RDX寄存器 mov edx, [rbp] ; 取出当前乘数(用32位寄存器足够,避免高位干扰) ; 计算偏移量:乘数×8,用左移3位替代乘法,效率更高 shl rdx, 3 ; 此时rdx = 乘数×8 ; 计算目标地址:先通过寄存器运算得到合法地址 mov rax, rbp sub rax, rdx ; rax = rbp - 偏移量,这是合法的寄存器操作 mov [rax], rsi ; 将RSI保存到目标地址 ; 更新乘数:取出原始乘数自增后存回 mov edx, [rbp] inc edx mov [rbp], edx pop rdx ; 恢复RDX寄存器 ret
关键修正说明
- 寻址问题解决:先通过寄存器运算
mov rax, rbp+sub rax, rdx得到合法的目标地址,再通过[rax]访问内存,规避了不合法的直接寄存器相减寻址。 - 指令修正:用
shl rdx,3替代错误的mult rdx,8,既符合64位NASM语法,又比乘法指令更高效;若偏好乘法,也可改为imul rdx, 8。 - 逻辑修正:更新乘数时,重新取出原始乘数进行自增,确保每次偏移量递增8,避免覆盖之前保存的RSI值。
内容的提问来源于stack exchange,提问作者Faraz Khanafari
相关产品推荐
相关产品推荐

