gpt4 book ai didi

assembly - 返回地址寄存器如何在不将返回地址存储在堆栈上的处理器架构中工作?

转载 作者:行者123 更新时间:2023-12-03 18:44:09 25 4
gpt4 key购买 nike

我试图弄清楚将调用的返回地址存储在寄存器 (RR) 中的架构如何工作(而不是在堆栈上推送和弹出返回地址)。

每次进行嵌套调用时,是否都不会覆盖返回地址寄存器(因此在一次返回后无法返回)?阅读我的作业问题,我应该修改一个汇编程序以使用一个 RR 寄存器来存储调用的返回地址,而不是将它插入和弹出堆栈。我已经搜索了它是如何工作的,但要么那里什么都没有,信息隐藏得很好,要么我的谷歌搜索技能不是那么好。

我不是要求解决问题,但我想知道如何将返回地址存储在一个寄存器中是可行的,在程序中多次调用而不随后将寄存器值存储在堆栈上(这会破坏练习)。

谢谢你的帮助。

最佳答案

是的,在使用“链接寄存器”传递返回地址的 ISA 上,非叶函数必须保存/恢复它们的返回地址,非常类似于他们保存想要在函数内部使用的调用保留寄存器的方式.即通常在调用堆栈上。

许多 RISC ISA 没有 push/pop 指令,但可以用多条指令完成相同的操作。例如从堆栈指针中减去以腾出空间,然后在函数入口处保存包括 LR 在内的一些寄存器。然后在返回之前,重新加载寄存器并添加到堆栈指针以恢复调用者的 SP 和任何其他寄存器的值。

叶函数(不进行任何函数调用)可以只保留该寄存器,以便返回地址在它们ret 时仍然存在。 (或任何调用的返回指令,例如 MIPS jr $ra - 跳转寄存器到返回地址寄存器)。

例如,查看编译器输出:

void external();

void foo(int *p) {
external();
*p = 0; // defeat tail-call optimization
}

GCC 5.4 为 MIPS 编译 -O2 -fno-delayed-branch on the Godbolt compiler explorer
foo(int*):
addiu $sp,$sp,-32 # reserve 32 bytes of stack space (MIPS calling convention I think guarantees some "shadow space" for callees)
sw $31,28($sp) # $31 is MIPS's $ra return address reg
sw $16,24($sp) # $16 is a call-preserved register
move $16,$4 # save p for later use
jal external
nop # branch-delay slot

lw $31,28($sp) # reload return address
sw $0,0($16) # *p = 0
lw $16,24($sp) # restore caller's $16
addiu $sp,$sp,32 # restore stack
j $31 # jump to return address
nop # branch delay slot

函数通常不需要返回它之前所在的同一寄存器中的返回地址,这取决于 ISA 使用的返回指令类型。不过,这是典型的,并且可能有助于对某些微体系结构进行分支预测。

32 位 ARM 很有趣,并且有微码 push/ pop使用寄存器位域来推送和弹出的指令。所以这是典型的 push {r4, lr}关于函数入口和 pop {r4, pc}作为返回指令。 (ARM 将程序计数器作为 16 个架构通用寄存器之一。写入它是一个跳转。)推送 r4连同链接寄存器 lr保持堆栈对齐,并为您提供一个保留调用的寄存器。

关于assembly - 返回地址寄存器如何在不将返回地址存储在堆栈上的处理器架构中工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61334346/

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