这只是一个蹦床。交互工作更容易演示,在这里使用 gnu,但这意味着 Kiel 也有一个解决方案。
.globl even_more
.type eve_more,%function
even_more:
bx lr
.thumb
.globl more_fun
.thumb_func
more_fun:
bx lr
extern unsigned int more_fun ( unsigned int x );
extern unsigned int even_more ( unsigned int x );
unsigned int fun ( unsigned int a )
{
return(more_fun(a)+even_more(a));
}
Unlinked object:
Disassembly of section .text:
00000000 <fun>:
0: e92d4070 push {r4, r5, r6, lr}
4: e1a05000 mov r5, r0
8: ebfffffe bl 0 <more_fun>
c: e1a04000 mov r4, r0
10: e1a00005 mov r0, r5
14: ebfffffe bl 0 <even_more>
18: e0840000 add r0, r4, r0
1c: e8bd4070 pop {r4, r5, r6, lr}
20: e12fff1e bx lr
Linked binary (yes completely unusable, but demonstrates what the tool does)
Disassembly of section .text:
00001000 <fun>:
1000: e92d4070 push {r4, r5, r6, lr}
1004: e1a05000 mov r5, r0
1008: eb000008 bl 1030 <__more_fun_from_arm>
100c: e1a04000 mov r4, r0
1010: e1a00005 mov r0, r5
1014: eb000002 bl 1024 <even_more>
1018: e0840000 add r0, r4, r0
101c: e8bd4070 pop {r4, r5, r6, lr}
1020: e12fff1e bx lr
00001024 <even_more>:
1024: e12fff1e bx lr
00001028 <more_fun>:
1028: 4770 bx lr
102a: 46c0 nop ; (mov r8, r8)
102c: 0000 movs r0, r0
...
00001030 <__more_fun_from_arm>:
1030: e59fc000 ldr r12, [pc] ; 1038 <__more_fun_from_arm+0x8>
1034: e12fff1c bx r12
1038: 00001029 .word 0x00001029
103c: 00000000 .word 0x00000000
您不能使用 bl 在 arm 和 thumb 之间切换模式,因此链接器添加了一个蹦床,正如我所说的那样,或者听到它叫你跳上跳下到达目的地。在这种情况下,本质上是将 bl 的分支部分转换为 bx,他们利用的链接部分仅使用 bl。您可以看到拇指到手臂或手臂到拇指的情况。
even_more 函数处于相同模式 (ARM),因此不需要蹦床/单板。
有关 bl lemme 的距离限制,请参阅。哇,这很容易,gnu 也称它为 veneer:
.globl more_fun
.type more_fun,%function
more_fun:
bx lr
extern unsigned int more_fun ( unsigned int x );
unsigned int fun ( unsigned int a )
{
return(more_fun(a)+1);
}
MEMORY
{
bob : ORIGIN = 0x00000000, LENGTH = 0x1000
ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.some : { so.o(.text*) } > bob
.more : { more.o(.text*) } > ted
}
Disassembly of section .some:
00000000 <fun>:
0: e92d4010 push {r4, lr}
4: eb000003 bl 18 <__more_fun_veneer>
8: e8bd4010 pop {r4, lr}
c: e2800001 add r0, r0, #1
10: e12fff1e bx lr
14: 00000000 andeq r0, r0, r0
00000018 <__more_fun_veneer>:
18: e51ff004 ldr pc, [pc, #-4] ; 1c <__more_fun_veneer+0x4>
1c: 20000000 .word 0x20000000
Disassembly of section .more:
20000000 <more_fun>:
20000000: e12fff1e bx lr
保持相同的模式不需要 bx。
另一种方法是在编译时用更复杂的解决方案替换每条 bl 指令,以防万一需要进行远调用。或者由于 bl 偏移量/立即数是在链接时计算的,您可以在链接时将蹦床/单板放入以更改模式或覆盖距离。
您应该可以使用 Kiel 工具自己重复此操作,您需要做的就是在外部函数调用上切换模式或超出 bl 指令的范围。
编辑
了解工具链各不相同,甚至在工具链中,gcc 3.xx 是第一个支持 thumb 的,我不知道我当时看到了这个。请注意,链接器是 binutils 的一部分,它与 gcc 是分开开发的。你提到“arm linker”,arm有自己的工具链,然后他们买了Kiel,也许用他们自己的替换了Kiel的。然后是 gnu 和 clang/llvm 等。因此,这不是“arm链接器”这样做或那样的情况,而是工具链链接器这样做或那样的情况,并且每个工具链首先可以自由使用他们想要的任何调用约定,没有强制要求他们必须使用ARM 的建议,其次他们可以选择实现或不实现,或者只是给你一个警告,你必须处理它(可能用汇编语言或通过函数指针)。
ARM 不需要解释它,或者说,它在架构参考手册中有明确的解释(查看 bl 指令,bx 指令查找单词 interworking 等。所有解释都非常清楚)针对特定架构。所以没有理由再解释一遍。尤其是对于 bl 的范围各不相同且每种架构具有不同的互通特性的通用声明,它可能是一长串的段落或一小章来解释已经清楚记录的内容。
任何实现编译器和链接器的人都会事先精通指令集,并了解指令集的 bl 和条件分支以及其他限制。一些指令集提供近跳转和远跳转,其中一些近和远的汇编语言可能是相同的助记符,因此汇编器通常会决定是否在同一文件中看不到标签来实现远跳转/调用而不是而不是一个近的,以便可以链接对象。
无论如何,在链接之前,您必须编译和组装,工具链人员将完全理解架构的规则。ARM在这里并不特别。