从编译器到汇编器
From Compiler to assembler
我有一个关于汇编程序的问题。我在想把多个参数作为实参的C函数是如何转化成汇编的。那么我的问题是,汇编中有没有把arguments作为参数来运行的子程序?
代码可能如下所示:
调用标签 1,R16。
其中R16为子程序输入参数。
如果不是这种情况,则意味着每次调用 C 函数时,它都会被组装到一个子例程中,并在其中自动替换与特定调用相关的参数。这基本上意味着无论何时调用 C 函数,编译器都会将其转换为内联函数,但肯定不是这种情况:D
那么哪个是对的?
非常感谢! :)
在某些指令集中可能会有一些最小的选项,但通常情况并非如此。
有些汇编程序虽然有宏,但可以模拟过程调用(通常只有几个可注册的基类型)。
不,只有在内联函数的情况下,才会生成一个新函数,其中参数化后的参数被替换。
编译器不会通过参数的文本替换为过程生成代码,而是通过将所有相关参数放入寄存器或堆栈中称为 "calling convention" 的固定机制中。
每次调用都会生成计算和加载参数(在寄存器或堆栈中)的代码,procedure/function 保持不变并从它知道可以找到它们的地方加载参数
编译器使用 "calling convention",它可以特定于该目标架构(x86、arm、mips、pdp-11 等)的编译器。对于具有 "plenty" 个通用寄存器的架构,调用约定通常从在寄存器中传递参数开始,然后使用堆栈,对于寄存器不多的架构,堆栈主要用于参数传递和return。
调用约定是一套规则,如果每个人都遵守这些规则,你就可以将函数编译成对象,然后 link 它们与其他对象一起调用,它们将能够相互调用函数或调用自己.
所以它有点混合了您的假设。为该函数构建的代码在某些方面是该函数的自定义代码,因为参数的数量和类型决定了哪些寄存器或多少堆栈被消耗以及如何消耗。同时,所有函数都遵循相同的公式,因此它们看起来相似多于不同。
例如,在一个 arm 上,您可能将三个整数传递给一个函数,对于我见过的所有 arm 调用约定,它们都是如此(通常您会发现,即使它可能因编译器而异,但通常不会或在在 arm 和 mips 以及其他一些情况下,他们试图为每个人规定约定,而不是编译器人员试图这样做)C 函数中的第一个参数将进入 r0,第二个进入 r1,第三个进入 r2。如果第一个参数是 64 位整数,那么 r0 和 r1 用于第一个参数,r2 获取第二个参数,r3 获取第三个参数,在使用堆栈的 r3 之后,堆栈上的参数顺序也由约定决定。因此,当使用相同的 C 原型编译调用者或被调用者的代码时,双方都确切知道在哪里可以找到参数并构建汇编语言来执行此操作。
我有一个关于汇编程序的问题。我在想把多个参数作为实参的C函数是如何转化成汇编的。那么我的问题是,汇编中有没有把arguments作为参数来运行的子程序? 代码可能如下所示:
调用标签 1,R16。 其中R16为子程序输入参数。
如果不是这种情况,则意味着每次调用 C 函数时,它都会被组装到一个子例程中,并在其中自动替换与特定调用相关的参数。这基本上意味着无论何时调用 C 函数,编译器都会将其转换为内联函数,但肯定不是这种情况:D
那么哪个是对的? 非常感谢! :)
在某些指令集中可能会有一些最小的选项,但通常情况并非如此。
有些汇编程序虽然有宏,但可以模拟过程调用(通常只有几个可注册的基类型)。
不,只有在内联函数的情况下,才会生成一个新函数,其中参数化后的参数被替换。
编译器不会通过参数的文本替换为过程生成代码,而是通过将所有相关参数放入寄存器或堆栈中称为 "calling convention" 的固定机制中。
每次调用都会生成计算和加载参数(在寄存器或堆栈中)的代码,procedure/function 保持不变并从它知道可以找到它们的地方加载参数
编译器使用 "calling convention",它可以特定于该目标架构(x86、arm、mips、pdp-11 等)的编译器。对于具有 "plenty" 个通用寄存器的架构,调用约定通常从在寄存器中传递参数开始,然后使用堆栈,对于寄存器不多的架构,堆栈主要用于参数传递和return。
调用约定是一套规则,如果每个人都遵守这些规则,你就可以将函数编译成对象,然后 link 它们与其他对象一起调用,它们将能够相互调用函数或调用自己.
所以它有点混合了您的假设。为该函数构建的代码在某些方面是该函数的自定义代码,因为参数的数量和类型决定了哪些寄存器或多少堆栈被消耗以及如何消耗。同时,所有函数都遵循相同的公式,因此它们看起来相似多于不同。
例如,在一个 arm 上,您可能将三个整数传递给一个函数,对于我见过的所有 arm 调用约定,它们都是如此(通常您会发现,即使它可能因编译器而异,但通常不会或在在 arm 和 mips 以及其他一些情况下,他们试图为每个人规定约定,而不是编译器人员试图这样做)C 函数中的第一个参数将进入 r0,第二个进入 r1,第三个进入 r2。如果第一个参数是 64 位整数,那么 r0 和 r1 用于第一个参数,r2 获取第二个参数,r3 获取第三个参数,在使用堆栈的 r3 之后,堆栈上的参数顺序也由约定决定。因此,当使用相同的 C 原型编译调用者或被调用者的代码时,双方都确切知道在哪里可以找到参数并构建汇编语言来执行此操作。