3.6 C语言和汇编语言混合编程 “每日读书”

小明 2025-05-05 06:39:21 7

在一些嵌入式场合,���们经常看到C程序和汇编程序相互调用,混合编程,如在ARM启动代码中,系统上电首先运行的是汇编代码,等初始化好内存堆栈环境之后,才会跳到C程序中执行,对嵌入式软件进行优化时,在一些性能要求比较高的场合,通常会在C语言中内嵌一些汇编代码,作为一名嵌入式工程师,掌握C语言和汇编的混合编程还是有必要的。

3.6.1 ATPCS规则

无论是在汇编程序中调用C程序,还是在C程序中调用汇编,往往都要涉及子程序调用,子程序的返回,参数传递这些问题。从指令集层面看C语言和汇编语言,两种其实无差别。最终都会被翻译成二进制机器指令,在学习C语言和ARM汇编语言混合编程之前,我们需要先了解一下ATPCS规则。

ATPCS的全称是ARM-thumb procedure call standard, 其核心内容就是定义了ARM子程序调用的基本规则以及堆栈的使用约定等,如ATPCS规定了ARM程序要使用满递减堆栈,入栈/出栈操作要使用STMFD/LDMFD指令,只要所有的程序都遵循这个约定,ARM程序的格式也就统一了。我们编写的ARM程序也就可以在各种各样的ARM处理器上运行了。

ATPCS最重要的内容就是定义了子程序调用的具体规则,无论是程序员编写程序,还是编译器开发商开发编译器工具,一般都要遵循它,规则的主要内容如下。

1 子程序间要通过寄存器R0-R3 传递参数,当参数大于4个时,剩余的参数使用堆栈来传递。

2 子程序通过r0-r1返回结果

3 子程序使用r4-r11来保存局部变量

4 r12作为调用过程中的临时寄存器,一般用来保存函数的栈帧基址,记作FP。

5 r13作为堆栈指针寄存器,一般记作SP

6 R14作为链接寄存器,用来保存函数调用者的返回地址,记作LR。

7 R15作为程序计数器,总是指向当前正在运行的指令,记作PC。

在ARM平台下,无论是C程序,还是汇编程序,只要大家遵守ARM子程序之间的参数传递和调用规则,就可以很方便的在C程序中调用汇编子程序,或者在一个汇编程序中调用C程序。

    我们在main.c 中定义了main函数和sum函数,在一个汇编文件SUM.S中定义了一个汇编子程序SUM_ASM。  在main() 函数中,我们直接调用了汇编子程序SUM._ASM 而在SUM_ASM的汇编代码实现中,又调用了在C源文件中定义的sum 函数,使用较差编译器arm-linux-gcc编译这两个源文件运行。

IMPORT sum;

AREA SUM_ASM,CODE,READONLY

EXPORT SUM_ASM

SUM_ASM

STR LR.[SP, #-4] ;去栈变量

LDR R0,=0x3

LDR R1, =0x4

BL sum

LDR PC,[SP],#4

END

int sum(int a, int b)

{

int result = a + b;

return result;

}

int main(void)

{

SUM_ASM();

return 0;

}

3.6.2 在C程序中内嵌汇编代码

为了能在C程序中内嵌汇编代码,ARM编译器在ANSI C标准的基础上,扩展了一个关键字__asm, 通过这个关键字,我们就可以在C程序中内嵌AMR汇编代码,在C程序中内嵌汇编代码的格式如下。

__asm

{

指令

  [指令]

}

这里有个细节需要注意下,想再内嵌的汇编代码中添加注释,记得要使用C语言的注释符号,而不是汇编语言的注释。接下来我们通过一个数据块复制的例子。

int src[10] = {1,2,3,4,5,6,7,8,9};

int dst[10] = {0};

//数据块复制的C语言实现

int data_copy_c(void)

{

for (int i = 0; i 

The End
微信