我们都知道ARM处理器有两种工作状态:ARM状态和Thumb状态。处理器可以在两种状态下随意切换。
处于ARM状态时,执行32位字对齐的ARM指令。
处于Thumb状态时,执行16位对齐的Thumb指令。
ARM 和 Thumb 指令集的动态切换,是通过 BX 指令使用一个寄存器名作为参数来完成。
程序控制权被转交给该寄存器中存储的地址 ( LSB 位被屏蔽 )。
如果 LSB=1, 则进入 Thumb 指令处理模式; 如果 LSB=0, 则进入 ARM 指令处理模式。
通俗点讲其实就是BX 跳转的地址最低位为1还是0来判断是进入Thumb指令处理模式还是进人ARM指令处理模式。
一、针对 C 和 C++ 文件代码交织的显式支持
缺省情况下,如果一个文件没有使用任何特殊的编译命令行参数,编译生成的代码将不支持代码交织。
如果一个程序完全通过目标文件和库文件以要么全部是 ARM 指令,要么全部是 Thumb 指令的方式编译链接,
将能生成一个可工作的可执行文件。
如果尝试去链接的目标文件和库文件中,既包括 ARM 指令, 也包括 Thumb 指令, 链接器将产生警告信息并且
生成的可执行文件不能正常工作。
为了产生支持代码交织( interworking ) 的代码,需要使用如下编译参数:
- -mthumb-interwork
如果一个程序所需要的所有目标文件和库文件都使用了该编译参数, 即使该程序的不同部分分别使用了
ARM 指令和 Thumb 指令,链接生成的可执行文件也可以正确工作。 且链接器不会给出警告信息。
但是,需要注意的是,使用了 -mthumb-interworking 参数后,生成的代码大小将略微增大,执行效率略微降低。
这就是为什么代码交织支持必须使能一个特定编译开关的原因。
二、针对 arm 汇编文件代码交织的显式支持
如果汇编文件将被包括进一个支持代码交织的程序中,必须遵循如下规则:
- 任何外部可见函数必须使用 BX 指令返回
- 普通的函数调用可以使用 BL 指令。链接器将自动插入代码以便进行 ARM 和 Thumb 指令切换
- 如果函数指针调用来自 ARM 代码, 应该使用 BX 指令。
然而,下述指令不能在 Thumb 模式工作,因为 MOV 指令没有正确设置 LR 寄存器的 LSB 位。
- .code 32
- mov lr, pc
- bx rX
其中, rX 表示包含有该函数地址的寄存器名称。
- .code 16
- bl _call_via_rX
- 所有在 Thumb 模式运行的外部可见函数, 必须在函数入口前使用 .thumb_func 伪指令。
- .code 16
- .global function
- .thumb_func
- unction:
- ...start of function....
- 所有汇编文件必须使用 -mthumb-interwork 参数进行编译。
(如果使用gcc 编译,如果该汇编文件被指定为第一个文件, gcc 将自动传入 -mthumb-interwork 参数)
三、支持古老的且无法区别 代码交织的代码
如果要链接相对古老的代码, 或者通过不支持代码交织的编译器生成的代码,或者通过新编译器产生
但是没有使用 -mthumb-interwork 参数生成的代码,有两种编译参数可以处理这种情况。
- 编译开关: -mcaller-super-interworking
该参数允许在 Thumb 模式的函数指针调用正常工作,而无须考虑该函数指针是否指向老的,无法区别代码交织的代码。
使用该开关将产生执行较慢的代码。
注意:
没有编译开关用于允许 ARM 模式的函数指针调用被特别处理。
对于借助于函数指针的调用,如果从支持代码交织的 ARM 代码调用不支持代码交织的 ARM 代码,该调用能正常工作而
无须编译器考虑有任何考虑。
对于借助于函数指针的调用,如果从支持代码交织的 ARM 代码调用不支持代码交织的 Thumb 代码,该调用不能正常工作。
(实际上对于某些特定情况,也能工作; 但是无法保证一定能工作) 这是因为只有新编译器可以产生 Thumb 代码,
并且该编译器已经使用编译开关来产生支持代码交织的代码。
- 编译开关: -mcallee-super-interworking
该参数允许无法区别 ARM 和 Thumb 的代码调用 Thumb 函数,无论是直接调用或借助于函数指针的调用。
使用此参数将产生略大且执行稍慢的代码。
注意:
没有编译开关可以用于允许无法区别代码交织的 ARM 或者 Thumb 代码调用 ARM 函数。
对于从无法区别代码交织的 ARM 代码调用支持代码交织的 ARM 函数,没有必要进行任何特殊处理。
对于从不支持代码交织的 Thumb 代码调 ARM 函数,将不能正常工作。
这种情况没有其他选择,除非能够重新编译成支持代码交织的 Thumb 代码。
作为编译参数 -mcallee-super-interworking (因为它影响同一个文件中所有的外部可见函数) 的替换选择,
可以对单个函数指定一个属性或者 declspec 符号。通过此方式来表示该特定函数可以支持从无法区别代码交织的代码里被调用。
示例如下:
- int function __attribute__((interfacearm))
- {
- ... body of function ...
- }
- or
- int function __declspec(interfacearm)