当我使用64位局部变量时,为什么堆栈指针不会减少?

时间:2018-11-30 03:25:06

标签: c assembly arm

这是从C编译的反汇编代码:

grid()

子例程调用(799d6e:4798 blx r3)的目标采用64位整数指针参数并返回64位整数。而且该例程是一个库函数,因此我无法对其进行任何修改。 此操作可以覆盖存储lr和r6值的堆栈吗?

1 个答案:

答案 0 :(得分:4)

您说分支目标“采用64位整数指针参数并返回64位整数”,但事实并非如此。它使用一个指向64位整数的指针作为唯一参数(并且该指针的长度为32位,除非您使用的是aarch64,我怀疑其余代码是否存在);而且它什么也不会返回,只会覆盖您传入的参数所指向的64位值。我确定这就是您的意思,但是请谨慎使用术语,因为这两者之间的区别很重要!特别是,您调用的函数中都没有传递给我们的64位参数。

问题本身。了解编译器在此处执行的操作的关键是从第一行开始:

push    {r0, r1, r4, r5, r6, lr}

ARM calling convention不需要r0r1进行呼叫保留,那么它们在列表中做什么?答案是,编译器添加了这些“虚拟”推送以在堆栈上创建一些空间。上面的push操作基本上等同于

push    {r4, r5, r6, lr}
sub     sp, sp, #0x08

除了保存指令外。当然,结果并不完全相同,因为r0r1中的内容最终都被写入了这些位置。但是鉴于无法事先知道其中的内容,而且堆积的值无论如何都将被覆盖,因此没有任何影响。因此,我们有一个堆栈框架

      lr
      r6
      r5
      r4
      (r1)
sp -> (r0)

,其中堆栈指针指向由r0r1的虚拟推送创建的空间。现在我们有

mov   r0, sp

将堆栈指针复制到r0用作要调用的函数的指针参数,然后它将覆盖此位置的两个单词,从而导致堆栈帧为

      lr
      r6
      r5
      r4
      (64-bit value, high word)
sp -> (64-bit value, low word)

除了blx r3之外,您没有显示任何代码,因此无法确切说明函数末尾堆栈发生了什么。但是,如果此函数不返回任何参数,我希望看到一个匹配的

pop     {r0, r1, r4, r5, r6, pc}

,这当然会导致您的64位结果保留在r0r1中。但是,根据调用约定,这些寄存器都经过调用处理,所以没有问题。