ARM体系结构与编程-第四章
第4章 ARM汇编语言程序设计
4.1 伪操作
ARM汇编语言源程序中语句由指令、伪操作和宏指令组成。
4.1.1 符号定义伪操作
符号定义伪操作用于定义ARM汇编程序中的变量,对变量进行赋值以及定义寄存器名称。包括以下伪操作:
-
GBLA,GBLL及GBLS
声明一个ARM程序中的全局变量,并将其初始化。
-
A声明全局算术变量,初始化为0
-
L声明全局逻辑变量,初始化为
-
S声明全局的串变量,初始化为空串“”
全局变量的作用范围为包含该变量的源程序
variable -
-
LCLA,LCLL及LCLS
声明局部变量,并将其初始化
-
A声明局部算术变量,将其初始化为0
-
L声明局部逻辑变量,将其初始化为
-
S声明局部串变量,初始化为空串
局部变量的作用范围为包含该局部变量的宏代码的一个实例
variable -
-
SETA,SETL及SETS
给对应类型的变量赋值
variable
expr -
RLIST
为通用寄存器列表定义名称,定义的名称可以在LDM/STM指令中使用。
在LDM/STM指令中,寄存器列表中的寄存器的访问次序总是先访问编号较低的寄存器,再访问编号较高的寄存器,而不管寄存器列表中各寄存器的排列顺序。
name RLIST {list-of-registers}
-
CN 为协处理器的寄存器定义名称
name CN expr (expr为协处理器的寄存器编号,数值范围0~15)
-
CP 为协处理器定义名称
name CP expr (expr为协处理器的编号,数值范围0~15)
-
DN及SN
DN 为双精度的VFP寄存器定义名称
SN 为单精度的VFP寄存器定义名称
name DN expr
name SN expr
-
FN 为FPA的浮点寄存器定义名称
name FN expr
4.1.2 数据定义伪操作
包括:
-
LTORG 声明一个数据缓冲池的开始
LTORG
-
MAP 定义一个结构化的内存表的首地址,同义词^
MAP expr { base-register}
-
FIELD 定义结构化的内存表中的一个数据域,同义词#
{label} MAP expr
-
SPACE 分配一块内存单元,并用0初始化,同义词%
{label} SPACE expr
-
DCB 分配一段字节的内存单元,并用指定数据初始化,同义词=
{label} DCB expr {expr}...
-
DCD 及 DCDU 分配一段字的内存单元,并用指定的数据初始化,DCD同义词&
{label} DCD expr {expr}...
DCD可能在分配到第一个内存单元前插入填补字节以保证分配的内存是对齐的,DCDU不需要字对齐
-
DCDO 分配一段字的内存单元,并将单元的内容初始化成该单元相对于静态基址寄存器R9的偏移量
{label} DCD0 expr {,expr}...
-
DCFD 及 DCFDU 分配一段双字的内存单元,并用双精度的浮点数据初始化。每个双精度的浮点数占据两个字单元
{label} DCFD{U} fpliteral {,fpliteral}...
DCFD可能在分配到鹅第一个内存单元前插入填补字节保证分配的内存是字对齐的,DCFDU不需要字对齐
-
DCFS 及 DCFSU 分配一段字的内存单元,并用单精度的浮点数据初始化
{label} DCFS{U} fpliteral {,fpliteral}...
-
DCI 分配一段字节的内存单元,用指定的数据初始化,指定内存单元中存放的是代码,而不是数据
在ARM代码中,DCI分配一段字内存单元(分配的内存都是自对齐的),并用expr初始化
在Thumb代码中,DCI分配一段半字内存单元(分配的内存都是自对齐的),并用expr初始化
{label} DCI expr {,expr}...
-
DCQ 及DCQU 分配一段8个字节(双字)的内存单元,并用64位的整数数据初始化,后者不字对齐
{label} DCQ{U} {-}literal {,literal}...
-
DCW 及 DCWU 分配一段半字的内存单元,并用指定的数据初始化,后者不半字对齐
{label} DCW expr {,expr}...
-
DATA 在代码段中使用数据。
4.1.3 汇编控制伪操作
包括:
-
IF,ELSE和ENDIF
能够根据条件把一段源代码包括汇编语言程序内或者将其排除在程序之外。[是IF伪操作的同义词,|是ELSE伪操作的同义词,]是ENDIF伪操作的同义词。
例:
IF Version = "1.0" ;指令 ;伪指令 ELSE ;指令 ;伪指令 ENDIF
-
WHILE及WEND
例:
count SETA 1 WHILE count <= 4 count SETA count+1 ;code WEND
-
MACRO及WEND
MACRO伪指令标识宏定义的开始,MEND标识宏定义的结束。用MACRO定义一段代码,称为宏定义体,这样在程序中就可以通过宏指令多次调用该行代码段。
语法:
MACRO {$label} macroname {$parameter {,$parameter}...} ;code ... ;code MEND
-
MEXIT
从宏中跳转出去
4.1.4 栈中数据帧描述伪操作
4.1.5 信息报告伪操作
-
ASSERT
在汇编编译器对汇编程序的第二遍扫描中,如果其中ASSERTION中条件不成立,ASSERT伪操作将报告该错误信息。
ASSERT logical expression
-
INFO
支持在汇编处理过程的第一遍扫描或者第二遍扫描时报告诊断信息。
INFO numeric-expression,string-expression
-
OPT设置列表选项
OPT n
-
TTL及SUBT
TTL伪操作在列表文件的每一页的开头插入一个标题,该TTL伪操作将作用在其后的每一页,直到遇到新的TTL伪操作
SUBT伪操作在列表文件的每一页的开头插入一个子标题,该SUBT伪操作将作用在其后的每一页,直到遇到新的SUBT伪操作
TTL title
SUB subtitle
4.1.6 其他的伪操作
-
ALIGN
通过添加补丁字节使当前位置满足一定的对齐方式
ALIGN {expr{, offset}}
-
AREA
用于定义一个代码段或者数据段
AREA sectionname {attr} {attr}...
attr 属性包括:
-
ALIGN=expression
-
ASSOC=section
-
CODE 定义代码段
-
COMDEF 定义一个通用的段,可以包含代码或数据
-
COMMON定义一个通用的段,不包含代码或数据
-
DATA 定义数据段
-
NOINIT 指明本数据段仅仅保留内存单元,而没有将初始化值写入内存单元
-
READONLY 本段只读
-
READWRITE 本段可读可写
-
-
CODE16及CODE32
CODE16告诉汇编编译器后面的指令序列为16位的Thumb指令
CODE32告诉汇编编译器后面的指令序列为32位的ARM指令
-
END
告诉编译器已经到了源程序结尾
-
ENTRY
指定指定程序的入口点
一个程序(可以包含多个源文件)至少要有一个ENTRY,但是一个源文件最多只能有一个ENTRY
-
EQU
EQU伪操作位数字常量、基于寄存器的值和程序中的标号定义一个字符名称。*是EQU的同义词
name EQU expr{type}
type取值:
-
CODE16
-
CODE32
-
DATA
-
-
EXPORT 或 GLOBAL
声明一个符号可以被其他文件引用,相当于声明了一个全局变量。
EXPORT symbol {[WEAK]}
-
EXTERN
告诉编译器当前符号不是在本源文件中定义的,而是在其他源文件中定义的,在本源文件中可能引用该符号.如果本源文件没有实际引用该符号,该符号将不会被加入到本源文件的符号表中。
EXTERN symbol {[WEAK]}
-
GET 或 INCLUDE
将一个源文件包含到当前源文件中,并将被包含的文件在其当前位置进行汇编处理。INCLUDE是GET的同义词。
GET filename
-
IMPORT
告诉编译器当前符号不是在本源文件中定义的,而是在其他源文件中定义的,在本源文件中可能引用该符号,而且不论本源文件是否实际引用该符号,该符号都将被加入到本源文件的符号表中。
IMPORT symbol {[WEAK]}
-
INCBIN
将一个文件包含到当前源文件中,被包含的文件不进行汇编处理
INCBIN filename
-
KEEP
告诉编译器将局部符号包含在目标文件的符号表中。
KEEP {symbol}
-
NOFP
禁止源程序中包含浮点运算指令。
-
REQUIRE
指定段之间的相互依赖关系
REQUIRE lable
-
REQUIRE8 及 PRESERVE8
前者指示当前代码中要求数据栈8字节对齐
后者指示当前代码中数字栈是8字节对齐的
-
RN
为一个特定的寄存器定义名称。
name RN expr
-
ROUT
用于定义局部变量的有效范围
{name} ROUT
4.2 ARM汇编语言伪指令
-
ADR(小范围的地址读取伪指令)
-
ADRL(中等范围的地址读取伪指令)
-
LDR(大范围的地址读取伪指令)
-
NOP空操作伪指令
4.3 ARM汇编语言语句格式
{ symbol } { instruction | directive | pseudo - instruction} {; comment}
instruction: 指令
pseudo-instruction: 伪指令
symbol: 符号
comment: 语句注释
4.3.1 ARM汇编语言中的符号
在ARM汇编语言中,符号可以代表地址、变量和数字常量。当符号地址时又称为标号。
-
变量
变量的值在汇编处理过程中可能发生变化。在ARM汇编语言中变量有:数字变量、逻辑变量和串变量
-
数字变量
在ARM汇编中,使用EQU定义数字常量
-
汇编时的变量替换
如果在串变量前面有一个$字符,在汇编时编译器将用该串变量的数值取代该串变量。
-
标号
标号是表示程序的指令或者数据地址的符号。根据标号的生成方式可以有3种:
-
基于PC的标号
-
基于寄存器的标号
-
绝对地址
-
-
局部标号
主要在局部范围使用。
4.3.2 ARM 汇编语言中的表达式
表达式是有符号、数值、单目或多目操作符以及括号组成的。优先级如下:
-
括号内的表达式优先级最高
-
各种操作符有一定的优先级
-
相邻的单目操作符的执行顺序为由左到右,单目运算符优先级高于其他操作符
-
优先级相同的双目运算符执行顺序为由左到右。
表达式的各元素:
-
字符串表达式
字符串表达式由字符串、字符串变量、操作符以及括号组成。
-
数字表示式
数字表示式由数字常量、数字变量、操作符和括号组成。
-
基于寄存器和基于PC的表达式
基于寄存器的表达式表示了某个寄存器的值加上(或减去)一个数字表达式
基于PC的表达式表示了PC寄存器的值加上(或减去)一个数字表达式
-
逻辑表达式
逻辑表达式由逻辑量、逻辑操作符、关系运算符以及括号组成。取值范围为{FALSE}和
-
其他一些操作符
4.4 ARM汇编语言程序格式
4.4.1 汇编语言程序格式
ARM汇编语言以段为单位组织源文件。段是相对独立的、具有特定名称的、不可分割的指令或者数字序列。段又可以分为代码段和数据段,代码段存放代码,数据段存放代码运行时需要用到的数据。
ARM汇编语言经过编译后生成一个可执行的映像文件,该可执行的映像文件包括:
-
一个或多个代码段,代码段通常是只读的
-
零个或多个包含初始值的数据段。这些数据段通常是可读写的
-
零个或多个不包含初始值的数据段。这些数据段被初始化为0,通常是可读写的
连接器根据一定的规则将各个段的安排到内存相应的位置。源程序中段之间的相邻关系与可执行的映像文件中段之间的相邻关系并不一定相同。
4.4.2 汇编语言子程序调用
在ARM汇编语言中,子程序调用是通过BL指令完成的。
BL指令完成两个操作:将子程序的返回地址放在LR寄存器中,同时将PC寄存器值设置成目标子程序的第一条指令地址。
在子程序返回时可以通过将LR寄存器的值传送到PC寄存器中来实现。
子程序调用时通常使用寄存器R0~R3来传递参数和返回结果。
4.5 ARM汇编编译器的使用
ARM汇编编译器ARMASM