ZHCUAU3J January 2018 – March 2024
C7000 器件具有PC 相关的调用指令和PC 相关的分支指令,其范围小于整个地址空间。使用这些指令时,目标地址必须足够靠近指令,以便调用和目标之间的差异适应可用的编码位。如果被调用函数离调用函数太远,链接器会生成错误或生成 trampoline,具体取决于 --trampolines 选项的设置(on 还是 off)。
PC 相关调用的替代项是绝对调用,通常作为间接调用来实现:将被调用地址加载到寄存器中,然后调用该寄存器。这通常不是想要的结果,因为它需要更多的指令(依速度和大小)并且需要一个额外的寄存器来保存地址。
默认情况下,如果目标太远,编译器会生成可能需要 trampoline 的调用。在某些架构中,这种类型的调用被称为“near 调用”。
--trampolines 选项使用户能够控制 trampoline 的生成。当设置为“on”时,此选项会使链接器为其调用目标范围外链接的每个调用生成一个 trampoline 代码段。trampoline 代码段包含一个指令序列,该序列会执行到达原始调用地址的透明长分支。每个超出被调用函数范围的调用指令都会重定向到 trampoline。
此选项的语法为:
--trampolines[=on|off]
默认设置为 on。对于 C7000,默认启用 trampoline。
例如,在一段 C 代码中,bar 函数调用 foo 函数。编译器为函数生成以下代码:
bar:
...
CALL .B1 foo ; call the function "foo"
...
如果 foo 函数置于 bar 内部对 foo 的调用范围之外,那么使用 --trampolines 时,链接器会将原来对 foo 的调用更改为对 foo_trampoline 的调用,如下所示:
bar:
...
CALL .B1 $Tramp$L$PI$$myfunc ; call a trampoline for foo
...
上面的代码会生成一个名为 foo_trampoline 的 trampoline 代码段,其中包含执行到达原始调用函数 foo 的长分支的代码。例如:
$Tramp$L$PI$$myfunc:
BE .B1 foo ; long branch to foo (with constant extension)
可在对同一被调用函数的调用之间共享 trampoline。唯一的要求是对被调用函数的所有调用都在被调用函数的 trampoline 附近进行链接。
当链接器生成一个映射文件(--map_file 选项)并且已生成一个或多个 trampoline 时,该映射文件将包含有关已生成的 trampoline 以及所到达的函数的统计信息。映射文件中还会提供每个 trampoline 的调用列表。
汇编语言程序员必须知道链接器假定 D15 包含栈指针。链接器必须在由其生成的 trampoline 代码中保存和恢复栈上的值。如果用户不使用 D15 作为栈指针,则应使用禁用 trampoline 的链接器选项 --trampolines=off 。否则,trampoline 可能会破坏存储器并覆盖寄存器值。