c语言汇编混合编程 gcc,C\C++以及汇编语言的混合编程

C\C++以及汇编语言的混合编程

在应用系统设计中,如果所有程序都用汇编语言实现,虽然提高了执行效率,但工作量大而且不易于移植和升级;如果全部用C语言来编写,一些对硬件的操作,例如允许和禁止中断就无法实现。因此,通常在实际系统设计中采用汇编和C语言混合编程的方式。ARM体系结构支持汇编和C语言的混合编程。一般在ARM实际编程应用中,程序的初始化部分用汇编语言来实现,然后用C/C++语言完成其他任务。

²

C和汇编之间的函数调用

n

(温故知新)C语言程序中的调用

n

C程序调用汇编程序函数

n

汇编程序调用c程序函数

n

汇编程序访问c程序变量

n

ATPCS标准(ARM-Thumb Procedure Call Standard)

²

C程序嵌入汇编指令

n

内联汇编

n

嵌入式汇编

l

C和汇编之间的函数调用

ARM工程中,C程序调用汇编函数和汇编程序调用C函数时经常的事情,遵守ARM-Thumb过程调用标准ATPCS(ARM-Thumb Procedure Call

Standard)。

ATPCS标准——ARM编译器使用的函数调用规则(详见下面)

Ø

(温故知新)C语言程序中的调用

int main()

{

printf("1234+5678=%d\n",sum(1234,5678));

return 0;

}

请编写sum函数,实现两个数的相加。

int

sum(int x,int y)

{

int

s;

s=x+y;

return

s

}

Ø

C程序调用汇编程序函数

要点:

1.

在汇编语言中,用该函数名作为汇编代码段的标识,定义函数代码,最后用MOV

PC,LR返回

2.

在汇编语言中用EXPORT导出函数名,使得该函数可以被其他的程序调用。

3.

在C语言中用extern关键词声明函数原型。

4.

函数调用时参数传递规则:寄存器组中的{R0-R3}作为参数传递和结果返回寄存器,如果参数数目超过4个,则使用堆栈进行传递。

;工程exp10_1_2,实现字符串的复制

;汇编函数文件strcopy.s

;把R1指向的数据块复制到R0指向的存储块。

AREA StrCopy,CODE,READONLY

EXPORT strcopy

strcopy

LDRB R2,[R1],#1

STRB R2,[R0],#1

CMP R2,#0

BNE strcopy

MOV PC,LR

END

;C文件main.c

;调用strcopy函数

extern void StrCopy(char *d,const char

*s); //声明strcopy为外部引用符号

int main(void)

{

const char *src=”Source”;

char dest[12]=”Destination”;

strcopy(dest,src); //调用汇编函数strcopy

printf(“After copying:\n”);

printf(“%s\n%s\n”,src,dest);

return(0);

}

根据ATPCS的C语言程序调用汇编函数规则,参数由左向右依次传递给寄存器R0~R3,可知汇编函数strcopy在C程序中的原型应该为:

void strcopy(char *d,const char *s);

其中,参数d对应R0,参数s对应R1。函数没有返回值,类型为void。函数名称与汇编函数标号名称一致。

Ø

汇编程序调用c程序函数

在汇编程序中调用C程序函数的步骤如下:

在C程序中,无需任何关键字导出或者声明被调用的C语言函数。

在汇编程序中,在调用其他文件的C语言函数前,先用IMPORT伪操作声明该函数。

在汇编程序中,通常使用BL指令来调用其他程序文件中的C语言函数,并保证调用时参数正确传递。参数的传递规则与C程序调用汇编语言函数的规则相同。

;工程Exp10_1_3,累加

C函数

int g(int a,int b,int c,int d,int e)

{

return a+b+c+d+e;

}

汇编函数f中调用C函数g(),以实现下面的功能:

int f(int i)

{

return g(i, 2*i, 3*i, 4*i, 5*i );

}

整个汇编函数f的代码如下:

EXPORT f

AREA f,CODE,READONLY

IMPORT g

STR LR,[SP,#-4]

ADD R1,R0,R0

ADD R2,R1,R0

ADD R3,R1,R2

STR R3,[SP,#-4]

ADD R3,R1,R1

BL g

ADD SP,SP,#4

RSB R0,R0,#0

LDR PC,[SP],#4

END

;由于函数g()有5个参数,所以该函数用寄存器R0~R3来传递a~d,而用堆栈来传递第5个参数e。

Ø

汇编程序访问c程序变量

变量定义是混合编程的基本问题。汇编程序访问C程序中的变量的步骤类似于汇编程序调用C程序中的函数的步骤,具体操作如下:

²

在C程序中,无需任何关键字导出或声明被调用的C程序变量。

²

在汇编程序中,在访问其他文件的C程序变量前,先用IMPORT伪操作声明该变量。

在汇编程序中,通常根据该数据的数据类型使用相应的LDR指令读取这个全局变量的地址和值,然后在此基础上,可以使用其他数据处理指令(如ADD、SUB或STR指令等)对这个全局变量进行进一步操作。

实际上是引用不同文件定义的变量:

IMPORT:声明符号为外部引用符号

EXPORT:声明符号为导出符号

例子:

AREA

globals,CODE,READONLY

EXPORT

asmsubroutine ;声明可导出符号,以供外程序调用

IMPORT

globvar ;声明引用外部符号

asmsubroutine

LDR R1,= globvar

LDR R0,[R1]

ADD R0,R0,#2

STR R0,[R1]

MOV PC,LR

END

Ø

ATPCS标准(ARM-Thumb Procedure Call Standard)

ARM编译器使用的函数调用规则。

1.

寄存器的使用规则

R0 ~R3用来传递参数;

R4~R11用来保存局部变量;

R12用做子程序内部调用的scratch寄存器

R13堆栈指针,保存当前处理器模式的堆栈的栈顶

R14链接寄存器

R15程序计数器

进入函数时,必须保存R4~R11中被函数破坏的寄存器。

2.

堆栈的使用规则

FD类型。

3.

参数的传递规则

<4个:R0~R3

>4个:堆栈

4.

函数返回值

R0,R1

l

C程序嵌入汇编指令

内联汇编inline assemble

嵌入式汇编embedded assemble

有时候,必须在C/C++语言程序中嵌入汇编指令:

C/C++语言程序中需要对协处理器进行操作。

C/C++语言程序中完成对程序状态寄存器CPSR的操作。

C/C++语言程序中内嵌汇编指令由两种方法,分别是内联汇编和嵌入式汇编,他们都是包含在C/C++编译器中的汇编器,可以实现一些高级语言没有的功能。不仅如此,在C/C++语言程序中灵活使用内联汇编和嵌入式汇编,还有助于提高程序的执行效率。

Ø

内联汇编

在c函数定义中插入汇编语句。

使用关键字__asm来定义一个内联汇编程序段,当ARM编译器遇到这个关键字时,就会启动内联汇编器对关键字下面的程序进行汇编工作。语法格式与编译器相关,不同版本的ARM编译器对内联汇编的语法要求不一样,例如armcc和gcc的汇编格式就不一样。

用法特点:

u

如果同一行包含多条指令,则用分号隔开。

u

如果一条指令不能在同一行中完成,则用反斜杠连接。

u

内联汇编中出现的寄存器使用前必须先声明,且不一定与同名物理寄存器相对应。

u

内联汇编中的寄存器(除CPSR和SPSR外),在读取前必须先赋值。

由于内联汇编嵌入在C/C++语言程序中,所以可以在内联汇编代码中执行的操作有某些限制:

u

不支持Thumb指令集;

u

不支持带转移的跳转指令

u

不支持对寄存器执行装载/存储操作,而使用MOV指令对寄存器赋值

u

不支持标号变量

u

不能直接向PC赋值

u

十六进制数前使用0x,不能使用前缀&

语法格式

__asm

{

汇编语句段

}

内嵌内联汇编的两个整型数相加的C语言程序。(工程exp10_1,文件exp10_exa1.c)

#include

int sum(int i,int j)

{

int total;

__asm

{

ADD total,i,j

}

return total;

}

int main()

{

printf("1234+5678=%d\n",sum(1234,5678));

return 0;

}

Ø

嵌入式汇编

在形式上表现为独立定义的函数。嵌入式汇编具有真实汇编的所有特性,同时支持ARM和Thumb指令集。

嵌入式汇编程序时一个编写在C程序外的单独汇编程序段,可以像函数那样被C程序调用。可以有参数和返回值。定义嵌入式汇编函数的语法格式为:

__asm return-type

function-name(parameter-list)

{

汇编程序段

}

使用嵌入式汇编有以下限制:

²

嵌入式汇编中不能直接引用C/C++的变量定义。

²

编译程序不为_asm函数生成返回指令

例子:

__asm int add(int i, int j)

{

ADD R0,R0,R1

MOV PC,LR

}

注意参数名只允许在参数列表中,不能用在嵌入式汇编函数体内。

在C中调用嵌入式汇编程序的方法与调用C函数的方法相同。

void main()

{

printf(”%d”,add(123,456));

}

BDHN

内嵌嵌入式汇编的两个整型数相加的C语言程序。(工程exp10_1,文件exp10_exa2.c)

#include

_asm int add(int i,int j)

{

ADD R0,R0,R1

MOV PC,LR

}

void

main( )

{

printf("1234+5678=%d\n",add(1234,5678));

return

0;

}

内联汇编和嵌入式汇编的主要区别

功能

内联汇编

嵌入式汇编

指令集

仅支持ARM

支持ARM和Thumb

ARM汇编伪操作

不支持

支持

C/C++表达式

完全支持

只支持常量表达式

汇编代码优化

完全优化

无优化

能否被内联

有可能

不可能

寄存器访问

使用虚拟寄存器不能使用PC、LR和SP

使用指定的物理寄存器可以使用PC、LR和SP

是否自动产生返回指令

指定产生

手工添加返回指令

课堂补充实验:

实验目的

Ø

掌握C程序中内嵌汇编指令的使用方法。

Ø

掌握C程序调用汇编程序函数的方法。

Ø

掌握汇编程序调用C程序函数和变量的方法。

实验一 允许和禁止中断程序(ARM7)

本实验使用内联汇编完成允许和禁止中断程序设计,采用ARMulator方式调试,选用ARM7作为目标处理器。

;工程exp10_1,文件exp10_1_1.c

#include

__inline

void enable_IRQ(void)

{

int tmp;

__asm

{

MRS

tmp,CPSR //read

CPSR

BIC

tmp,tmp,#0x80 //bit[7]=0,IRQ alowed

MSR

CPSR_c,tmp //write CPSR

}

}

__inline void

disable_IRQ(void)

{

int tmp;

__asm

{

MRS

tmp,CPSR //read CPSR

ORR

tmp,tmp,#0x80 //bit[7]=1,IRQ forbitten

MSR

CPSR_c,tmp //write CPSR

}

}

int

main(void)

{

enable_IRQ();

disable_IRQ();

return 0;

}

单步调试程序,观察C程序的执行过程,将寄存器的变化情况记录在下表中。

序号

执行指令

指令执行后的变化情况

寄存器

R0

R1

R2

R3

R4

R5

R12

SP

LR

PC

CPSR

0

---------------

1

MRS tmp,CPSR

2

BIC tmp,tmp,#0x80

3

MSR CPSR_c,tmp

4

MRS tmp,CPSR

5

ORR tmp,tmp,#0x80

6

MSR CPSR_c,tmp

实验二 伪随机数程序(ARM7)

本实验使用C程序调用汇编函数的方法设计伪随机数程序。本实验中的伪随机数并不是真正的随机数,而只是足够分散的一系列数据,因为它足够分散,所以看起来是随机的。真正的随机数,需要由物理方式来产生。本实验通过移位操作和“异或”运算来产生伪随机数,并采用ARMulator方式调试,选用ARM7作为目标处理器。

(工程exp10_2.mcp)

实验三 验证汇编程序调用C程序函数和访问C程序变量的执行过程(ARM9)

本实验在汇编程序中调用C程序函数和访问C程序变量,采用ARMualtor方式调试,选用ARM9作为目标处理器。(工程Exp10_3.mcp)

序号

执行指令

指令执行后的变化情况

寄存器

存储空间

变量

R0

R1

R2

R3

R4

SP

LR

PC

0x9FFC

0x9FF8

sum

0

-----------

1

2

3

4

5

思考:

1.

分别概述C程序调用汇编函数和汇编程序调用C函数的步骤。

2.

在C程序中内嵌汇编指令有哪几种方法?适用于哪些情况。

你可能感兴趣的:(c语言汇编混合编程,gcc)