只要遵循 节 7.3 中定义的调用惯例,以及 节 7.2 中定义的寄存器惯例,即可同时使用 C/C++ 与汇编语言函数。C/C++ 代码可访问变量并调用使用汇编语言定义的函数,汇编代码也可访问 C/C++ 变量并调用 C/C++ 函数。
结合使用汇编语言和 C 时,请遵循以下指南:
- 所有函数,无论是以 C/C++ 还是以汇编语言编写,都必须遵循 节 7.2 中罗列的寄存器惯例。
- 必须保留由某函数修改的专用寄存器。专用寄存器包括:
| XAR1 | R4H(仅 FPU) | |
| XAR2 | R5H(仅 FPU) | |
| XAR3 | R6H(仅 FPU) | |
| SP | R7H(仅 FPU) | |
如果通常使用 SP,则无需显式保留。汇编函数可自由使用栈,只要在函数返回前将压入栈的全部内容弹出即可(因此要保留 SP)。
非专用寄存器可自由使用,无需保留。
- 在调用子函数之前,栈指针 (SP) 必须由父函数偶数对齐。如有必要,这是通过将栈指针增加 1 来完成的。如果需要,编码器应在调用之前递增 SP。
- 栈在函数边界对齐。
- 中断例程必须保存所使用的所有寄存器。如需更多信息,请参阅 节 7.7。
- 如果通过汇编语言调用 C/C++ 函数,请加载指定的寄存器与参数,并将其余参数压入栈,如 节 7.3.1 中所述。
在访问从 C/C++ 函数传入的参数时,适用相同的惯例。
- 长整型值和浮点值存储在存储器中,最低有效字位于低位地址。
- 结构也将返回,如 节 7.3.2 中所述。
- 任何汇编模块均不应出于任何目的使用 .cinit 段,除非进行全局变量的自动初始化。C/C++ 启动例程假设 .cinit 段包含完整的 初始化表。将其他信息放入 .cinit 会将表打乱,导致无法预测的结果。
- 编译器会在所有标识符的起始位置加一条下划线 ( _ )。在汇编语言模块中,对于要从 C/C++ 访问的所有对象,都必须使用前缀 _。例如,名为 x 的 C/C++ 对象在汇编语言中需调用 _x。对于只在一个或多个汇编语言模块中使用的标识符,未以下划线开头的任何名称均可安全使用,不会与 C/C++ 标识符产生冲突。
- 编译器会为所有外部对象指定链接名称。因此您在编写汇编语言代码时,使用的链接名称必须与编译器指定的相同。相关详细信息,请参阅节 6.12。
- 在汇编语言中声明、并从 C/C++ 访问或调用的任何对象或函数,必须在汇编语言修饰符中使用 .def 或 .global 指令进行声明。这样可将符号声明为外部引用,并允许链接器解析对它的引用。
同理,若要从汇编语言中访问 C/C++ 函数或对象,应在汇编语言模块中使用 .ref 或 .global 指令来声明 C/C++ 对象。这样可创建未声明的外部引用,并由链接器解析。
- 由于编译代码运行时会复位 PAGE0 模式位,如果您在汇编语言函数中将 PAGE0 位设为 1,则在返回汇编代码前必须将其设回 0。
- 如果您在汇编语言中定义一个结构,并在 C 语言中使用 extern struct 来访问它,则该结构应被阻止。编译器假设会阻止结构定义对 DP 负载进行优化。因此定义应接受此假设。您可以在 .usect 指令中指定阻止标志,以阻止该结构。请参阅《TMS320C28x 汇编语言工具用户指南》,了解有关这些指令的更多信息。