既然我们必须把所有的形参都存入栈,为什么编译器在调用函数的时候不把它们压入栈,而是把前4个形参存入R 0 ~R3呢?enter image description here我试着去理解它,但是我就是不能理解它,所以你能给予我一些帮助吗?
rwqw0loc1#
传统上,编译器通过传递堆栈上的所有参数来工作。当优化被禁用时,ARM等平台的编译器(其文档调用约定被指定为在寄存器中传递参数)可以在函数入口时将寄存器存储在堆栈帧上,以便它们可以处理函数的剩余部分,就好像参数已经在堆栈上传递一样。请注意,如果编译器生成的代码永远不会与其他工具生成的代码链接,那么它可以简单地传递堆栈上的所有参数。但是,这样做会使生成的代码与其他编译器生成的代码不兼容。接受寄存器中的东西,但立即将它们存储到堆栈上,允许编译器与其他编译器生成的代码兼容,同时仍然使用与“传统”参数传递机制相关的代码生成逻辑。
vql8enpb2#
为什么?因为这是32位ARM的标准,以便生成可以链接在一起的兼容二进制文件。引用ARM ABI本身的话:
3范围
AAPCS定义子程序如何单独编写、单独编译和单独组装以一起工作。它描述了调用例程和被调用例程之间的契约,定义:
...ABI指出:
6.1.1核心寄存器
Arm和Thumb指令集有16个32位核心(整数)寄存器。这些标记为r 0-r15或R 0-R15。......前四个寄存器r 0-r3(a1-a4)用于将参数值传递到子例程中,并从函数返回结果值。...以不符合ABI标准的方式编译的代码将无法与符合ABI标准的代码链接。关于“由于我们必须将所有形式参数存储到堆栈中”.不,我们不必这样做。将值从寄存器压入堆栈只是为了让被调用的例程将该值放回寄存器是没有意义的。在寄存器中传递参数要比强制它们进入内存快几个数量级,因为被调用的例程所做的第一件事就是从内存中读回参数,即使该值在缓存中是“热”的。堆栈传递仅在没有足够寄存器时才需要。
2条答案
按热度按时间rwqw0loc1#
传统上,编译器通过传递堆栈上的所有参数来工作。当优化被禁用时,ARM等平台的编译器(其文档调用约定被指定为在寄存器中传递参数)可以在函数入口时将寄存器存储在堆栈帧上,以便它们可以处理函数的剩余部分,就好像参数已经在堆栈上传递一样。
请注意,如果编译器生成的代码永远不会与其他工具生成的代码链接,那么它可以简单地传递堆栈上的所有参数。但是,这样做会使生成的代码与其他编译器生成的代码不兼容。接受寄存器中的东西,但立即将它们存储到堆栈上,允许编译器与其他编译器生成的代码兼容,同时仍然使用与“传统”参数传递机制相关的代码生成逻辑。
vql8enpb2#
为什么?因为这是32位ARM的标准,以便生成可以链接在一起的兼容二进制文件。
引用ARM ABI本身的话:
3范围
AAPCS定义子程序如何单独编写、单独编译和单独组装以一起工作。它描述了调用例程和被调用例程之间的契约,定义:
...
ABI指出:
6.1.1核心寄存器
Arm和Thumb指令集有16个32位核心(整数)寄存器。这些标记为r 0-r15或R 0-R15。...
...
前四个寄存器r 0-r3(a1-a4)用于将参数值传递到子例程中,并从函数返回结果值。...
以不符合ABI标准的方式编译的代码将无法与符合ABI标准的代码链接。
关于“由于我们必须将所有形式参数存储到堆栈中”.
不,我们不必这样做。
将值从寄存器压入堆栈只是为了让被调用的例程将该值放回寄存器是没有意义的。在寄存器中传递参数要比强制它们进入内存快几个数量级,因为被调用的例程所做的第一件事就是从内存中读回参数,即使该值在缓存中是“热”的。
堆栈传递仅在没有足够寄存器时才需要。