调用指令:编译成机器码

Posted

技术标签:

【中文标题】调用指令:编译成机器码【英文标题】:Call Instruction: Compilation into machine code 【发布时间】:2019-12-22 19:25:10 【问题描述】:

汇编调用指令是如何编译成机器码的? 标签会发生什么? 标签不存在时,机器码调用指令如何引用特定函数?

我知道编译后的代码中的标签被函数的地址替换了。

但是,函数的指令只有在程序运行后才会加载到 RAM 内存中。 那么里面的机器码是如何在编译之前通过标签的方式来表示一个特定的函数呢?

请用简单易懂的方式回答我,最好是一个实际的例子。

【问题讨论】:

“标签被函数的地址替换”就是它的全部内容。汇编器在发出机器代码指令时为它们分配顺序地址,因此它确切地知道任何给定函数在运行时将位于内存中的什么位置。现代计算机上的虚拟内存硬件允许所有程序驻留在相同的起始内存地址,即使有多个程序正在运行,因为每个程序都有自己的私有内存空间。 你为什么repost你之前的问题? 【参考方案1】:

汇编语言标签是一种编译时汇编时和链接时结构——在汇编和/或链接期间,这些标签被赋予一个内存地址,有时是绝对地址,但通常是从一开始就作为相对地址标签所在的部分。

机器代码中省略了标签(以及从符号/标签名称到地址或偏移量的映射) - 今天的处理器不知道或看到机器代码中的汇编标签。

在汇编语言中,调用指令以及 if-then、while 等的分支指令都有一个分支目标作为它们的操作数之一。对于这些指令中的大多数,在机器代码中,操作数被编码为 pc 相对偏移量,存储在立即字段中作为机器代码指令的操作数。

见pc-relative addressing mode。

立即数中的相对于 pc 的偏移量由硬件恢复为绝对地址,使用类似于指令地址 + 立即数的公式:

pcnext-cycle := pccurrent-branch-instruction + immediate * Scale + Bias.

 CPU   Scale    Bias
 -------------------
 x86      1       0
 MIPS     4       4
 RISC V   2       0

然后,汇编器/链接器使用相同的公式,虽然解决了即时,有效地反转了这个计算:

offset = (labeltarget - pccurrent-branch-instruction - Bias) / Scale

然后这个偏移量被编码在分支或调用指令的立即域中。


例如,在 MIPS 处理器上,分支指令具有 16 位立即数字段,用于保存此类偏移量。立即数 -1 将跳转到自身,立即数 -5 将向后分支 4 条指令,立即数 +5 将向前分支 6 条指令。

MIPS 调用指令使用绝对地址而不是 pc 相对地址,因此它们被编码为具有 26 位长度的文本段相对偏移量的大立即数。 (计算不会对 pc 的低 26 位求和,因此实际上并不认为是 pc 相对寻址。)

在 RISC V 和 x86 上,分支和调用指令都可以使用 pc 相对寻址来完成,但在 x86 上也可以使用绝对寻址和其他寻址模式。

【讨论】:

以上是关于调用指令:编译成机器码的主要内容,如果未能解决你的问题,请参考以下文章

软件管理

关于Java的编译执行与解释执行

关于Java的编译执行与解释执行

第四章

inline内联函数

Java代码是怎么运行的