汇编:将1添加到参数

时间:2017-11-06 03:47:51

标签: assembly

  push rbp
  mov rbp, rsp
  mov dword ptr [rbp - 4], edi
  mov edi, dword ptr [rbp - 4]
  add edi, 1
  mov eax, edi
  pop rbp
  ret

您好!我正在学习集会,我无法理解两件事:

  1. 为什么我们使用rbp?我知道这是一个可能不被被调用者修改的寄存器,但我不明白为什么它不能被修改,为什么我们不只是使用rsp。还有,不是rbx而不是rbp吗?
  2. 从第3-4行开始,为什么我们将edi中的元素移动到[rbp-4],然后再将其移回edi?另外,不应该是mov rbp-4,[edi]而不是[rbp-4],edi?

1 个答案:

答案 0 :(得分:1)

对于这两个问题,答案是编译器优化:

原则上,有三种方法可以优化编译:

  1. 产生的代码应尽可能短
  2. 生成的代码应尽快执行
  3. 编制过程应尽可能快
  4. (通常你不会将方法3称为“优化”。)

    默认情况下,C编译器执行第三种方法:始终使用相同的“默认”元素(例如,在函数开头的“push ebp”)始终工作,所以编译器总是执行相同的步骤。这使编译过程更容易。

    有关问题1的详细信息:

    对于16位软件,使用bp寄存器几乎是不可避免的,因为没有指令(当然pushpop除外)能够访问16位代码中sp寄存器的内存。

    在64位代码中,您始终可以使用[rsp - 4]代替[rbp - 4],但在alloca()指令的情况下,这将不再可能。

    为了节省时间(使用优化类型3时),编译器会在之前将push rbpmov rbp, rsp指令写入文件,它知道是否存在{{1是否指示。

    有关问题2的详细信息:

    当使用优化方法1或2时,编译器(我尝试使用Linux下的GNU编译器)将生成如下代码:

    alloca()

    但是要这样做,编译器必须“记住”哪个寄存器当前包含哪个值。编译时会花费时间......

    因此,当使用“优化”方法3时,编译器将执行什么是默认始终在任何情况下都可以工作:

    将所有参数写入堆栈并从堆栈中读取所有局部变量(包括参数)......

      

    另外,不应该是lea eax, [rbp + 1] ret 而不是mov rbp-4, [edi]

    方括号表示:使用内存位置而不是值。

    没有方括号表示不使用内存。

    所以[rbp-4], edi表示:将mov [rbp-4], edi的值写入地址edi的内存位置。

    真正的x86-64 CPU不支持此指令,但我们可以在某些模拟器中运行指令rbp-4。该指令会将值mov [edi], rbp-4写入地址rbp-4的内存位置。

    然而,指令edi意味着:“从地址mov rbp-4, [edi]的内存位置读取值......”(这是可能的)“......并将该值写入{ {1}}“(:”到地址edi的内存中“)。

    CPU必须在一条指令中解决方程式......