ARM GCC中内联汇编语法

ARM嵌入式开发中的GCC内联汇编简介

嵌入式开发交流群280352802,欢迎加入!

在针对ARM体系结构的编程中,一般很难直接使用C语言产生操作协处理器的相关代码,因此使用汇编语言来实现就成为了唯一的选择。但如果完全通过汇编代码实现,又会过于复杂、难以调试。因此,C语言内嵌汇编的方式倒是一个不错的选择。然而,使用内联汇编的一个主要问题是,内联汇编的语法格式与使用的编译器直接相关,也就是说,使用不同的C编译器内联汇编代码时,它们的写法是各不相同的。下面介绍在ARM体系结构下GCC的内联汇编。GCC内联汇编的一般格式:

[plain]  view plain copy print ?
  1. asm(    
  2.   
  3.   
  4.      代码列表    
  5.      : 输出运算符列表    
  6.      : 输入运算符列表    
  7.      : 被更改资源列表    
  8. );  

在C代码中嵌入汇编需要使用asm关键字,在asm的修饰下,代码列表、输出运算符列表、输入运算符列表和被更改的资源列表这4个部分被3个“:”分隔。下面,我们看一个例子:

[plain]  view plain copy print ?
  1. void test(void)  
  2. {    
  3.     ……    
  4.     asm(    
  5.         "mov r1,#1\n"    
  6.         :    
  7.         :    
  8.         :"r1"    
  9.     );    
  10.     ……    
  11. }   

注:换行符和制表符的使用可以使得指令列表看起来变得美观。你第一次看起来可能有点怪异,但是当C编译器编译C语句的是候,它就是按照上面(换行和制表)生成汇编的。

函数test中内嵌了一条汇编指令实现将立即数1赋值给寄存器R1的操作。由于没有任何形式的输出和输入,因此输出和输入列表的位置上什么都没有填写。但是,在汇编代码执行过程中R1寄存器会被修改,因此为了通知编译器,在被更改资源列表中,需要写上寄存器R1。

寄存器被修改这种现象发生的频率还是比较高的。例如,在调用某段汇编程序之前,寄存器R1可能已经保存了某个重要数据,当汇编指令被调用之后,R1寄存器被赋予了新的值,原来的值就会被修改,所以,需要将会被修改的寄存器放入到被更改资源列表中,这样编译器会自动帮助我们解决这个问题。也可以说,出现在被更改资源列表中的资源会在调用汇编代码一开始就首先保存起来,然后在汇编代码结束时释放出去。所以,上面的代码与如下代码从语义上来说是等价的。

[plain]  view plain copy print ?
  1. void test(void)  
  2. {    
  3.     ……    
  4.     asm(    
  5.         "stmfd sp!,{r1}\n"  
  6.         "mov r1,#1\n"    
  7.         "ldmfd sp!,{r1}\n"    
  8.     );    
  9.     ……    
  10. }   

这段代码中的内联汇编既无输出又无输入,也没有资源被更改,只留下了汇编代码的部分。由于程序在修改R1之前已经将寄存器R1的值压入了堆栈,在使用完之后,又将R1的值从堆栈中弹出,所以,通过被更改资源列表来临时保存R1的值就没什么必要了。

在以上两段代码中,汇编指令都是独立运行的。但更多的时候,C和内联汇编之间会存在一种交互。C程序需要把某些值传递给内联汇编运算,内联汇编也会把运算结果输出给C代码。此时就可以通过将适当的值列在输入运算符列表和输出运算符列表中来实现这一要求。请看下面的例子:

[plain]  view plain copy print ?
  1. void test(void)  
  2. {    
  3.     int tmp=5;    
  4.     asm(    
  5.         "mov r4,%0\n"    
  6.         :    
  7.         :"r"(tmp)    
  8.         :"r4"    
  9.     );    
  10. }   

上面的代码中有一条mov指令,该指令将%0赋值给R4。这里,符号%0代表出现在输入运算符列表和输出运算符列表中的第一个值。如果%1存在的话,那么它就代表出现在列表中的第二个值,依此类推。所以,在该段代码中,%0代表的就是“r”(tmp)这个表达式的值了。
那么这个新的表达式又该怎样解释呢?原来,在“r”(tmp)这个表达式中,tmp代表的正是C语言向内联汇编输入的变量,操作符“r”则代表tmp的值会通过某一个寄存器来传递。在GCC4中与之相类似的操作符还包括“m”、“I”,等等,其含义见下表:


与输入运算符列表的应用方法一致,当C语言需要利用内联汇编输出结果时,可以使用输出运算符列表来实现,其格式应该是下面这样的。

[plain]  view plain copy print ?
  1. void test(void)  
  2. {    
  3.     int tmp;    
  4.     asm(    
  5.         "mov %0,#1\n"    
  6.         :"=r"(tmp)    
  7.         :    
  8.     );    
  9. }   

在上面的代码中,原本应出现在输入运算符列表中的运算符,现在出现在了输出运算符列表中,同时变量tmp将会存储内联汇编的输出结果。这里有一点可能已经引起大家的注意了,上面的代码中操作符r的前面多了一个“=”。这个等号被称为约束修饰符,其作用是对内联汇编的操作符进行修饰。几种修饰符的含义如下表所示:

当一个操作符没有修饰符对其进行修饰时,代表这个操作符是只读的。当我们需要将内联汇编的结果输出出来,那么至少要保证该操作符是可写的。因此,“=”或者“+”也就必不可少了。










4.1.1  访问CP15寄存器的指令

访问CP15寄存器指令的编码格式及语法说明如下:

31  28

27  24

23  21

20

19  16

15  12

11  8

7  5

4

3  0

cond

1 1 1 0

opcode_1

L

cr n

rd

1 1 1 1

opcode_2

1

crm

说明:

:协处理器行为操作码,对于CP15来说,永远为0b000,否则结果未知。

:不能是r15/pc,否则,结果未知。

:作为目标寄存器的协处理器寄存器,编号为C0~C15。

:附加的目标寄存器或源操作数寄存器,如果不需要设置附加信息,将crm设置为c0,否则结果未知。

:提供附加信息比如寄存器的版本号或者访问类型,用于区分同一个编号的不同物理寄存器,可以省略或者将其设置为0,否则结果未知。

指    令

说    明

语法格式

mcr

将ARM处理器的寄存器中的数据写到CP15中的寄存器中

mcr{}   p15, , , , , {}

mrc

将CP15中的寄存器中的数据读到ARM处理器的寄存器中

mcr{}   p15, , , , , {}

4.1.2  CP15寄存器介绍

CP15的寄存器列表如表4-1所示。

表4-1  ARM处理器中CP15协处理器的寄存器

寄存器编号

基本作用

在MMU中的作用

在PU中的作用

0

ID编码(只读)

ID编码和cache类型

 

1

控制位(可读写)

各种控制位

 

2

存储保护和控制

地址转换表基地址

Cachability的控制位

3

存储保护和控制

域访问控制位

Bufferablity控制位

4

存储保护和控制

保留

保留

5

存储保护和控制

内存失效状态

访问权限控制位

6

存储保护和控制

内存失效地址

保护区域控制

7

高速缓存和写缓存

高速缓存和写缓存控制

 

8

存储保护和控制

TLB控制

保留

9

高速缓存和写缓存

高速缓存锁定

 

10

存储保护和控制

TLB锁定

保留

11

保留

 

 

12

保留

 

 

13

进程标识符

进程标识符

 

14

保留

 

 

15

因不同设计而异

因不同设计而异

因不同设计而异

  • CP15的寄存器C0

CP15中寄存器C0对应两个标识符寄存器,由访问CP15中的寄存器指令中的指定要访问哪个具体物理寄存器,与两个标识符寄存器的对应关系如下所示:

 

opcode_2编码

对应的标识符号寄存器

0b000

主标识符寄存器

0b001

cache类型标识符寄存器

其他

保留

1)主标识符寄存器

访问主标识符寄存器的指令格式如下所示:

mrc p15, 0, r0, c0, c0, 0       ;将主标识符寄存器C0,0的值读到r0中

ARM不同版本体系处理器中主标识符寄存器的编码格式说明如下。

ARM7之后处理器的主标识符寄存器编码格式如下所示:

31             24      23            20      19              16    15              4     3               0

由生产商确定

产品子编号

ARM体系版本号

产品主编号

处理器版本号

 

说    明

位[3: 0]

生产商定义的处理器版本号

位[15: 4]

生产商定义的产品主编号,其中最高4位即位[15:12]可能的取值为0~7但不能是0或7

位[19: 16]

ARM体系的版本号,可能的取值如下:

0x1   ARM体系版本4

0x2   ARM体系版本4T

0x3   ARM体系版本5

0x4   ARM体系版本5T

0x5   ARM体系版本5TE

其他  由ARM公司保留将来使用

位[23: 20]

生产商定义的产品子编号,当产品主编号相同时,使用子编号来区分不同的产品子类,如产品中不同的高速缓存的大小等

位[31: 24]

生产厂商的编号,现在已经定义的有以下值:

0x41  =A  ARM公司

0x44  =D  Digital Equipment公司

0x69  =I   intel公司

ARM7处理器的主标识符寄存器编码格式如下所示:

31             24     23     22                        16           15          4         3          0

由生产商确定

A

产品子编号

产品主编号

处理器版本号

 

说    明

位[3: 0]

生产商定义的处理器版本号

位[15: 4]

生产商定义的产品主编号,其中最高4位即位[15:12]的值为0x7

位[22: 16]

生产商定义的产品子编号,当产品主编号相同时,使用子编号来区分不同的产品子类,如产品中不同的高速缓存的大小等

续表 

说    明

位[23]

ARM7支持下面两种ARM体系的版本号:

0x0   ARM体系版本3

0x1   ARM体系版本4T

位[31: 24]

生产厂商的编号,现在已经定义的有以下值:

0x41  =A  ARM公司

0x44  =D  Digital Equipment公司

0x69  =I   Intel公司

ARM7之前处理器的主标识符寄存器编码格式如下所示:

31           24       23       22                    16            15          4         3           0

由生产商确定

A

产品子编号

产品主编号

处理器版本号

 

说    明

位[3: 0]

生产商定义的处理器版本号

位[15: 4]

生产商定义的产品主编号,其中最高4位即为[15:12]的值为0x7

位[22: 16]

生产商定义的产品子编号,当产品主编号相同时,使用子编号来区分不同的产品子类,如产品中不同的高速缓存的大小等

位[23]

ARM7支持下面两种ARM体系的版本号:

0x0   ARM体系版本3

0x1   ARM体系版本4T

位[31: 24]

生产厂商的编号,现在已经定义的有以下值:

0x41  =A  ARM公司

0x44  =D  Digital Equipment公司

0x69  =I   intel公司

2)cache类型标识符寄存器

访问cache类型标识符寄存器的指令格式如下所示:

mrc p15, 0, r0, c0, c0, 1       ;将cache类型标识符寄存器C0,1的值读到r0中

ARM处理器中cache类型标识符寄存器的编码格式如下所示:

31             29     28           25    24       23             12               11            0

0   0   0

属性字段

S

数据cache相关属性

指令cache相关属性

 

说明

位[28: 25]

指定控制字段位[24: 0]指定的属性之外的cache的其他属性,详见表4-2

位[24]

定义系统中的数据cache和指令cache是分开的还是统一的:

0   系统的数据cache和指令cache是统一的;

1   系统的数据cache和指令cache是分开的

位[23: 12]

定义数据cache的相关属性,如果位[24]为0,本字段定义整个cache的属性

位[31: 24]

定义指令cache的相关属性,如果位[24]为0,本字段定义整个cache的属性

其中控制字段位[28:25]的含义说明如下:

表4-2  cache类型标识符寄存器的控制字段位[28:25]

编    码

cache类型

cache内容清除方法

cache内容锁定方法

0b0000

写通类型

不需要内容清除

不支持内容锁定

0b0001

写回类型

数据块读取

不支持内容锁定

0b0010

写回类型

由寄存器C7定义

不支持内容锁定

0b0110

写回类型

由寄存器C7定义

支持格式A

0b0111

写回类型

由寄存器C7定义

支持格式B

控制字段位[23:12]和控制字段位[11:0]的编码格式相同,含义如下所示:

11      9         8             6         5          3                2            1               0

0    0    0

cache容量

cache相联特性

M

块大小

cache容量字段bits[8: 6]的含义如下所示:

编    码

M=0时含义(单位KB)

M=1时含义(单位KB)

0b000

0.5

0.75

0b001

1

1.5

0b010

2

3

0b011

4

6

0b100

8

12

0b101

16

24

0b110

32

48

0b111

64

96

cache相联特性字段bits[5: 3]的含义如下所示:

编    码

M=0时含义

M=1时含义

0b000

1路相联(直接映射)

没有cache

0b001

2路相联

3路相联

0b010

4路相联

6路相联

0b011

8路相联

12路相联

0b100

16路相联

24路相联

0b101

32路相联

48路相联

0b110

64路相联

96路相联

0b111

128路相联

192路相联

cache块大小字段bits[1: 0]的含义如下所示:

编    码

cache块大小

0b00

2个字(8字节)

0b01

4个字(16字节)

0b10

8个字(32字节)

0b11

16个字(64字节)

  • CP15的寄存器C1

访问主标识符寄存器的指令格式如下所示:

mrc p15, 0, r0, c1, c0{, 0}     ;将CP15的寄存器C1的值读到r0中

mcr p15, 0, r0, c1, c0{, 0}     ;将r0的值写到CP15的寄存器C1中

CP15中的寄存器C1的编码格式及含义说明如下:

31 16

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

附加

L4

RR

V

I

Z

F

R

S

B

L

D

P

W

C

A

M

 

说    明

M

0:禁止MMU或者PU;1:使能MMU或者PU

A

0:禁止地址对齐检查;1:使能地址对齐检查

C

0:禁止数据/整个cache;1:使能数据/整个cache

W

0:禁止写缓冲;1:使能写缓冲

P

0:异常中断处理程序进入32位地址模式;1:异常中断处理程序进入26位地址模式

D

0:禁止26位地址异常检查;1:使能26位地址异常检查

L

0:选择早期中止模型;1:选择后期中止模型

B

0:little endian;1:big endian

S

在基于MMU的存储系统中,本位用作系统保护

R

在基于MMU的存储系统中,本位用作ROM保护

F

0:由生产商定义

Z

0:禁止跳转预测功能;1:使能跳转预测指令

I

0:禁止指令cache;1:使能指令cache

V

0:选择低端异常中断向量0x0~0x1c;1:选择高端异常中断向量0xffff0000~ 0xffff001c

RR

0:常规的cache淘汰算法,如随机淘汰;1:预测性淘汰算法,如round-robin淘汰算法

L4

0:保持ARMv5以上版本的正常功能;1:将ARMv5以上版本与以前版本处理器兼容,不根据跳转地址的bit[0]进行ARM指令和Thumb状态切换:bit[0]等于0表示ARM指令,等于1表示Thumb指令

附加:

 

  • CP15的寄存器C2

CP15中的寄存器C2保存的是页表的基地址,即一级映射描述符表的基地址。其编码格如下所示:

31                                                                                                     0

一级映射描述符表的基地址(物理地址)

  • CP15的寄存器C3

CP15中的寄存器C3定义了ARM处理器的16个域的访问权限。

31                                                                                                     0

D15

D14

D13

D12

D11

D10

D9

D8

D7

D6

D5

D4

D3

D2

D1

D0

  • CP15的寄存器C5

CP15中的寄存器C5是失效状态寄存器,编码格式如下所示:

31                                                           9        8    7       4     3        0

UNP/SBZP

0

域标识

状态标识

其中,域标识bit[7:4]表示存放引起存储访问失效的存储访问所属的域。

状态标识bit[3:0]表示放引起存储访问失效的存储访问类型,该字段含义如表4-3所示(优先级由上到下递减)。

表4-3  状态标识字段含义

引起访问失效的原因

状态标识

域标识

C6

终端异常(Terminal Exception)

0b0010

无效

生产商定义

中断向量访问异常(Vector Exception)

0b0000

无效

有效

地址对齐

0b00x1

无效

有效

一级页表访问失效

0b1100

无效

有效

二级页表访问失效

0b1110

有效

有效

基于段的地址变换失效

0b0101

无效

有效

基于页的地址变换失效

0b0111

有效

有效

基于段的存储访问中域控制失效

0b1001

有效

有效

基于页的存储访问中域控制失效

0b1101

有效

有效

基于段的存储访问中访问权限控制失效

0b1111

有效

有效

基于页的存储访问中访问权限控制失效

0b0100

有效

有效

基于段的cache预取时外部存储系统失效

0b0110

有效

有效

基于页的cache预取时外部存储系统失效

0b1000

有效

有效

基于段的非cache预取时外部存储系统失效

0b1010

有效

有效

  • CP15中的寄存器C6

CP15中的寄存器C5是失效地址寄存器,编码格式如下所示:

31                                                                                                     0

失效地址(虚拟地址)

  • CP15中的寄存器C7

CP15的C7寄存器用来控制cache和写缓存,它是一个只写寄存器,读操作将产生不可预知的后果。

访问CP15的C7寄存器的指令格式如下所示:

mcr p15, 0, , , crm, 的不同取值组合    实现不同功能

  • CP15中的寄存器C8

CP15的C8寄存器用来控制清除TLB的内容,是只写寄存器,读操作将产生不可预知的后果。

访问CP15的C8寄存器的指令格式如下所示:

mcr p15, 0, , , crm, 的不同取值组合实现不同功能,见第4.2节

  • CP15中的寄存器C9

CP15的C9寄存器用于控制cache内容锁定。

访问CP15的C9寄存器的指令格式如下所示:

mcr p15, 0, , , c0,

mrc p15, 0, , , c0,

如果系统中包含独立的指令cache和数据cache,那么对应于数据cache和指令cache分别有一个独立的cache内容锁定寄存器,用来选择其中的某个寄存器:

=1选择指令cache的内容锁定寄存器;

=0选择数据cache的内容锁定寄存器。

CP15的C9寄存器有A、B两种编码格式。编码格式A如下所示:

31                                       32-W 31-W                                         0

cache组内块序号index

0

其中index表示当下一次发生cache未命中时,将预取的存储块存入cache中该块对应的组中序号为index的cache块中。此时序号为0~index-1的cache块被锁定,当发生cache替换时,从序号为index到ASSOCIATIVITY的块中选择被替换的块。

编码格式B如下所示:

31    30                                          W      W-1                                     0

L

0

cache组内块序号index

 

 

说    明

L=0

当发生cache未命中时,将预取的存储块存入cache中该块对应的组中序号为index的cache块中

续表 

说    明

L=1

如果本次写操作之前L=0,并且index值小于本次写入的index,本次写操作执行的结果不可预知;否则,这时被锁定的cache块包括序号为0~index-1的块,当发生cache替换时,从序号为index到ASSOCIATIVITY的块中选择被替换的块

  • CP15的寄存器C10

CP15的C10寄存器用于控制TLB内容锁定。

访问CP15的C10寄存器的指令格式如下所示:

mcr p15, 0, , , c0,

mrc p15, 0, , , c0,

如果系统中包含独立的指令TLB和数据TLB,那么对应于数据TLB和指令TLB分别有一个独立的TLB内容锁定寄存器,用来选择其中的某个寄存器:

=1选择指令TLB的内容锁定寄存器;

=0选择数据TLB的内容锁定寄存器。

C10寄存器的编码格式如下:

31 30                         32-W       31-W                            32-2W    31-2W     1    0

可被替换的条目起始地址的base

下一个将被替换的条目地址victim

0

P

 

说    明

victim

指定下一次TLB没有命中(所需的地址变换条目没有包含在TLB中)时,从内存页表中读取所需的地址变换条目,并把该地址变换条目保存在TLB中地址victim处

base

指定TLB替换时,所使用的地址范围,从(base)到(TLB中条目数-1);字段victim的值应该包含在该范围内

P

1:写入TLB的地址变换条目不会受使整个TLB无效操作的影响,一直保持有效;0:写入TLB的地址变换条目将会受到使整个TLB无效操作的影响

  • CP15的寄存器C13

C13寄存器用于快速上下文切换FCSE。

访问CP15的C13寄存器的指令格式如下所示:

mcr p15, 0, , , c0, 0

mrc p15, 0, , , c0, 0

C13寄存器的编码格式如下所示:

31                25       24                                                                     0

PID

0

其中,PID表示当前进程的所在的进程空间块的编号,即当前进程的进程标识符,取值为0~127。

0:MVA(变换后的虚拟地址)= VA(虚拟地址),禁止FCSE(快速上下文切换技术),系统复位后PID=0;

非0:使能FCSE。


















MCR指令将ARM处理器的寄存器中的数据传送到协处理器的寄存器中。如果协处理器不能成功地执行该操作,将产生未定义的指令异常中断。

指令的语法格式:

MCR{} p15, 0, , , {,}

MCR2 p15, 0, , , {,}

其中,为指令执行的条件码。当忽略时指令为无条件执行。MCR2中,为Ob1111,指令为无条件执行指令。

 为协处理器将执行的操作的操作码。对于CP15协处理器来说, 永远为0b000,当不为0b000时,该指令操作结果不可预知。

 作为元寄存器的ARM寄存器,其值被传送到得协处理器寄存器中。

 不能为PC,当其为PC时,指令操作结果不可预知。

 作为目标寄存器的协处理器寄存器,其编号可能为C0,C1....C15。 附加的目标寄存器或者原操作数寄存器,用于区分同一个编号的不同物理寄存器。当指令中不需要提供附加信息时,将C0指定为,否则指令操作结果不可预知。  提供附加信息,用于区别同一个编号的不同物理寄存器。当指令中指定附加信息时,省略或者将其指定为0,否则指令操作结果不可预知。

MRC指令将协处理器的寄存器中数值传送到ARM处理器的寄存器中。如果协处理器不能成功地执行该操作,将产生未定义的指令异常中断。

指令的语法格式:

MRC{} p15, 0, , , {,}

MRC2 p15, 0, , , {,}



MVN指令

MVN指令的格式为:

MVN{条件}{S} 目的寄存器,源操作数

MVN指令可完成从另一个寄存器、被移位的寄存器、或将一个立即数加载到目的寄存器。与MOV指令不同之处是在传送之前按位被取反了,即把一个被取反的值传送到目的寄存器中。其中S决定指令的操作是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。
4(00000100b) 取反为 11111011,这个是数是-5的补码,所以r0=-5

1111011高位为1,为负数,故减一取反为5,加上符号就为-5



BIC 位清0指令

Rd,  Rn, Oprand2

BIC(位清除)指令对 Rn 中的值 和 Operand2 值的反码按位进行逻辑“与”运算。 (注意:ARM官方网站有误, 写的是补码)
BIC 是 逻辑”与非” 指令, 实现的 Bit Clear的功能

举例:
BIC     R0,   R0  , #0xF0000000


ORR 逻辑或指令



5.         位操作指令 AND,ORR, TST,BIC

n         AND位与指令

AND R0,R1,R2; R0=R1 & R2

AND R0,R1,#0xFF ;R0=R1 & 0xFF

n         ORR位或指令

ORR R0,R1,R2; R0=R1 | R2

ORR R0,R1,#0xFF ;R0=R1 | 0xFF

n         TST测试某一位是否为1,并把结果写入CPSR,供下一句使用

TST R1,#0xffe;   等同于if(R1 & 0xffe)

TST R1,#%1;测试最低位是否为1,%表示二进制

n         BIC清位操作

BIC   R0,R0,#0xF           等同于 R0 &=~(0xF)

BIC   R0,R0,#%1011   ; 该指令清除 R0 中的位 0 1  3,其余的位保持;   %表示是二进制,0x表示十六进制

 

6.         比较指令 CMP

n         CMP比较两个操作数,并把结果存入CPSR供下一句语句使用



你可能感兴趣的:(ARM GCC中内联汇编语法)