【问题标题】:Can't understand the error: invalid effective address on mov rax , qword [ rbp-24 - rbx * 8]无法理解错误:mov rax, qword [rbp-24 - rbx * 8] 上的有效地址无效
【发布时间】:2021-02-10 06:49:27
【问题描述】:

我想学习 asm,来自 C
一本书建议尝试实现这个算法,这是一个非常简单的排序算法

begin
for i = 0 to len-1
    small = arr(i)
    index = i
        for j = i to len-1
            if ( arr(j) < small ) then
                small = arr(j)
                index = j
            end_if
        end_for
    arr(index) = arr(i)
    arr(i) = small
end_for
end_begin

我的代码的开头是(如果需要可以提供其余部分)

section .bss


section .data

len dq 5
array dq 1 , 3 ,  6 , 8 ,  2


section .text


        global _start

_start:
        mov rdi , [len]
        mov rsi , array
        call sort
        exit





sort:
        push rbp
        mov rbp,rsp
        push qword 0 ; i_counter = rbp-8
        push rdi ; len = rbp-16
        push rsi ; *array = rbp -24
        push  qword 0 ; j = rbp - 32
        dec qword [rbp-16]
i_loop:
        mov r8 , [rbp-16]
        cmp [rbp-8], r8 ; if counter = len - 1 (decreased above)
        je end_i_loop
        mov rbx , [rbp-8]
        mov rax , qword [  rbp-24 - rbx * 8] ; small = array(i) and line 38
        mov rcx , [rbp-8] ; index = i
        mov [rbp - 32 ] , rcx ; j = i

在第 38 行我得到了错误 错误:无效的有效地址

起初我认为这是一个对齐错误(因此是排序函数开头的推四字)
然后我尝试使用 movq 指令(由于其他原因显然不起作用,我已经阅读了指令手册)
向内存地址移动似乎有效,即使被寄存器引用(至少 mov [rax] , qword [ rbp-24 - rbx * 8] 编译),但我几乎看不到这样做的任何意义) 我可以用 lea 修复它,它可以编译,但我想要这个值,不 mov rax,, qword [ rbp-24 - rbx * 8] 给出 rbp-24-rbx*8 指向的值?

由于我在代码中的四个不同点(第 38 行之后)有同样的问题,我完全陷入困境,不知道现在该尝试什么
有人可以解释为什么这不能编译,如果可能的话给出一个解决方案(或至少提示)

【问题讨论】:

  • 您可能会在godbolt.org 编译器资源管理器中找到很大的好处!

标签: linux 64-bit nasm


【解决方案1】:
mov rax , qword [  rbp-24 - rbx * 8]

这从表面上看是非法的,因为 SIB 寻址模式只能添加缩放索引寄存器(此处为rbx * 8);它不能减去它。但是如果你想要array(i),那么无论如何你都想添加它,因为这里的rbx对应于i

但是,您似乎正在尝试使用存储在rbp-24 的指针作为基地址,这也不支持;基地址必须来自寄存器。方便的是,array 的地址已经在寄存器rdi 中了,所以我想你想要的很简单

mov rax, qword [rdi + rbx * 8]

只是在改进代码时的一般提示:使用汇编语言的主要原因是速度,而实现速度的最重要方法是最大限度地减少内存访问。您真的不希望将局部变量保留在堆栈中并在每次触摸它们时访问内存。机器有很多寄存器,所以只需为每个变量选择一个寄存器并将其保留在那里。

如果您一直试图通过阅读未优化的编译器汇编输出来学习,您可能会养成过度使用内存的习惯;非优化编译器会将所有内容保留在堆栈中,以便在需要时具有一致的位置和一致的地址。但是尝试启用优化,你会发现这一切都神奇地消失了,一切都尽可能地使用寄存器完成。这才是你应该努力争取的。

【讨论】:

  • 很好,谢谢!这些提示也会被记住;)是否有可能知道为什么减去索引是不可能的?是因为 ISA 不允许(这将是一个简单的原因)还是有其他更复杂的原因
  • @rcmb:是的,这不是 ISA 设计人员选择包含的功能。除了它会增加有效地址 ALU 的复杂性之外,您还需要在地址字节或其他地方指定一个位来指示加法或减法,而这些位对于不太可能被大量使用的东西来说是一种极其珍贵的商品。您多久在高级语言中使用负数或减数数组索引?最明显的用例 - 向后迭代数组 - 也可以通过让数组索引从最后一个元素开始并倒计时来处理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-05
  • 1970-01-01
  • 2014-01-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多