为什么使用由堆栈指针、基指针寄存器操作的堆栈是处理函数帧的正确解决方案?

问题描述 投票:0回答:1

任何人都可以从技术和历史的角度启发我们为什么计算机使用由堆栈指针和基指针操作的堆栈,并遵循特定的过程,例如保存返回地址,推送基指针的旧值等..

有关处理函数调用堆栈的过程的更多信息,请检查以下内容:

https://www.learnvulnerabilityresearch.com/stack-frame-function-prologue

我的问题是为什么它是正确的解决方案?

function assembly memory-management callstack
1个回答
0
投票

几十年来,架构从内存密集型发展到寄存器密集型。

最初,可能有一个数据寄存器、一个累加器,程序员和设计者自然地想到在主存中定位和存储变量、参数、返回地址等——他们还会去哪里?

许多架构甚至是在普遍认识到调用堆栈的必要性之前创建的。

随着架构的发展,引入了调用堆栈以及附加寄存器,但系统架构仍然强烈倾向于使用内存来存储参数、局部变量和返回地址。

随着快速寄存器和优秀编译器的可用性增加,体系结构开始选择使用寄存器而不是内存。例如,MIPS & RISC V & ARM 的指令集架构将返回地址存储在链接寄存器中,如果要将其放入堆栈,则必须为此编写代码。

有了大量可用的快速寄存器,很明显,在过程/函数/方法之间共享寄存器是一个真正的问题——即使有很多寄存器,它们实际上也是全局资源,并且在数千个函数之间共享它们需要一些架构。

因此,硬件寄存器按照软件约定进行划分,用于两种非常基本但不同的场景——短期和长期使用。对于短期使用,我们不想支付任何开销,只需不受惩罚地使用寄存器即可。对于长期使用,我们愿意在函数入口/出口处支付一些开销,以便这些值能够正确保存更长的时间。这就是称为 call-clobbered 与 call-preserved 的寄存器集的动机(也通过误导性术语 caller-saves 与 callee-saves)。

您通过该引用看到的是此演变中的中间快照 - 当参数和返回地址被推入堆栈时,帧指针用于帮助组织和访问堆栈和堆栈帧。

从那时起,时代已经进步,因此大多数架构现在主要使用寄存器来传递参数而不是推送(尽管 x86/64 仍然使用内存作为返回地址),以及替代(静态,即低动态开销)方法来堆栈展开(例如静态表)被用于帧指针的动态管理。

© www.soinside.com 2019 - 2024. All rights reserved.