ZHCU947E June 2015 – January 2023
在存储器中的一个位置加载代码而在另一个位置运行代码的做法有时会很有用。链接器提供了为一个段指定不同的加载分配和运行分配的功能。实际将代码从加载空间复制到运行空间的重任将留给您完成。
必须先执行复制函数,然后才能在运行空间中执行实际函数。为了方便执行这个复制函数,汇编器提供了 .label 指令,允许您定义加载时地址。然后可以使用这些加载时地址来确定所要复制代码的起始地址和大小。但是,如果代码包含的某个调用需要 trampoline 才能到达其被调用函数,则此机制将不 起作用。这是因为 trampoline 代码是在链接时生成的,即在定义与 .label 指令关联的加载时地址之后。如果链接器在包含 trampoline 调用的输入段中检测到 .label 符号的定义,则会生成警告。
若要解决此问题,可使用 START()、END() 和 SIZE() 运算符(请参阅GUID-FF28563B-D6AD-4B87-8954-50CAED14DB3B.html#GUID-FF28563B-D6AD-4B87-8954-50CAED14DB3B)。通过这些运算符可以定义一些符号来表示链接器命令文件中的加载时起始地址和大小。这些符号可由复制代码引用,并且在分配 trampoline 段之后直到链接时才会解析符号的值。
以下示例说明了如何使用与输出段相关联的 START() 和 SIZE() 运算符来复制 trampoline 代码段以及含有需要 trampoline 的调用的代码:
SECTIONS
{ .foo : load = ROM, run = RAM, start(foo_start), size(foo_size)
{ x.obj(.text) }
.text: {} > ROM
.far : { --library=rts.lib(.text) } > FAR_MEM
}
x.c.obj 中的一个函数包含运行时支持调用。运行时支持库位于 far 存储器中,因此该调用超出范围。链接器会将一个 trampoline 段添加到 .foo 输出段。复制代码可以引用符号 foo_start 和 foo_size 作为整个 .foo 输出段的加载起始地址和大小的参数。因此,复制代码可以将 trampoline 段以及 .text 中的原始 x.c.obj 代码从其加载空间复制到其运行空间。
有关在 C/C++ 代码中引用链接器符号的信息,请参阅GUID-1F98654C-B2F7-475F-A477-551D8A8F35FC.html#GUID-1F98654C-B2F7-475F-A477-551D8A8F35FC。