调用例程的职责

当汇编语言程序调用另一程序时,调用者不应将被调用程序的命令,函数或过程的名称用作全局汇编语言符号。 为了避免混淆,请在创建符号名称时遵循被调用程序的语言的命名约定。 例如,如果要调用 C 语言程序,请确保使用该语言的命名约定。

被调用例程具有两个与其关联的符号: 函数描述符 (Name) 和入口点 ()。名称)。 对例程进行调用时,编译器将直接分支到入口点。

对函数的调用由编译器展开,以在每个分支和链接指令之后包含 NOP 指令。 如果需要,链接编辑器将修改此额外指令,以在从模块外调用返回时恢复 TOC 寄存器 (寄存器 2) 的内容。

编译器生成的指令序列为:
bl .foo           #Branch to foo
nop               
注: 汇编程序为 nop 助记符生成 ori 0,0,0 (0x60000000) 指令。 为了向后兼容,链接编辑器还接受 cror 15,15,15 (0x4def7b82) 和 cror 31,31,31 (0x4ffffb82) 作为有效的 NOP 指令。

当链接编辑器看到 bl 指令 (在先前的指令序列中,在调用 foo 函数时) 时,它将执行以下两项操作之一:

  • 如果导入 foo 函数 (不在同一可执行模块中) ,那么链接编辑器:
    • bl .foo 指令更改为 bl .glink_of_foo (全局链接例程)。
    • .glink 代码序列插入 (/usr/lib/glink.o 文件) 模块中。
    • 将 NOP 指令替换为用于复原 TOC 寄存器的 lwz (load) 指令。
    bl .foo 指令序列更改为:
    bl .glink_of_foo  #Branch to global linkage routine for foo
    lwz 2,20(1)       #Restore TOC register instruction 0x80410014
  • 如果 foo 函数随后与其调用者绑定在同一可执行模块中,那么链接编辑器:
    • bl .glink_of_foo 序列 (全局链接例程) 更改为 bl .foo
    • 将复原 TOC 注册指令替换为 NOP 指令。
    bl .glink_of_foo 指令序列更改为:
    bl .foo         #Branch to foo
    nop
注: 对于任何导出,链接编辑器都会将过程的描述符插入到模块中。