gpt4 book ai didi

c - 为什么当我使用 64 位局部变量时堆栈指针没有减少?

转载 作者:太空宇宙 更新时间:2023-11-04 06:12:28 24 4
gpt4 key购买 nike

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

00799d60 <sub_799d60>:
799d60: b573 push {r0, r1, r4, r5, r6, lr}
799d62: 0004 movs r4, r0
799d64: f000 e854 blx 799e10 <jmp_sub_100C54>
799d68: 4b15 ldr r3, [pc, #84] ; (799dc0 <sub_799d60+0x60>)
799d6a: 0005 movs r5, r0
799d6c: 4668 mov r0, sp
799d6e: 4798 blx r3

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

最佳答案

您说分支目标“接受一个 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 中。但是这些寄存器根据调用约定进行了调用破坏,所以没有问题。

关于c - 为什么当我使用 64 位局部变量时堆栈指针没有减少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53550790/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com