三.ARM指令集
1.指令格式
ARM采用三地址指令格式:
<opcode> {<cond>} {S} <Rd>,<Rn>{,<operand2>}
其中<>内容为必须的,{}为可选的。
<opcode>:操作码,代表指令执行的操作类型,如加法(ADD)、减法(SUB)、移动(MOV)等。
{<cond>}:条件码,是可选的,用于指定指令执行的条件,如等于(EQ)、不等于(NE)、无符号大于(HI)等。条件码允许指令在满足特定条件时才执行。
{S}:标志位,是可选的,如果存在,表示指令执行后会影响CPSR(当前程序状态寄存器)的条件标志位(如N、Z、C、V)。
<Rd>:目标寄存器,指令执行结果的存放位置。
<Rn>:第一个操作数寄存器,通常包含源操作数。
{,<operand2>}:第二个操作数,是可选的,可以是立即数(一个常数)、寄存器或者寄存器加上一个偏移量。如果存在,它必须用逗号与<Rn>隔开。
提示:汇编中的注释符为';'。
2.寻址方式
即处理器根据指令信息找到操作数的方式:
1、立即数寻址( 操作数直接在指令中 mov R1,#3:将3放到R0)
立即数被表示为#immed_8,即常数表达式。
2、寄存器寻址
mov R0,R1:将R0的值放到R1中
操作数即为寄存器的数值。
3、寄存器间接寻址
mov R0,[R2]:将R2中的值为地址指向内存中的数放到R0中
操作数在寄存器值为地址指向的内存中
4、寄存器位移寻址
mov R0,R1,lsl#3:将R1中值左移3位放到R0中
当第二个数为位移方式时、将寄存器的值先位移处理得到操作数
5、寄存器基址寻址(也叫基址变址寻址)
LDR R0, [R1, #4]:先将R1中的值加4 然后以结果为地址 对应的内存操作数放到R0
由间接寻址发展而来,先对寄存器中的值进行计算,再以结果为地址,取其指向内存值为操作数。
6、多寄存器寻址
STMIA R0!,{R2-R7,R12}:将 R2 到 R7 和 R12 放到 R0 指向的地址中
一条指令传送多个(最多16个)寄存器值
7、相对寻址
BL NEXT:跳转到NEXT标签处
以程序计数器 PC 的当前值为基地址,指令中的地址标号作为偏移量,将两者相加之后得到操作数的有效地址
8、拷贝寻址。将连续的寄存器值进行操作。
STMIA R0! ,{R1-R7}:将R1~R7的数据保存到R0指向的地址中
9、堆栈寻址。将栈用于操作数保存或者导出的操作。
STMFD SP!,{R1-R7,LR}:将R1~R7,LR入栈,SP更新。满递减堆栈
3.伪指令
汇编器定义了一些特殊的指令助记符,即伪指令(也叫做伪操作),它们就类似于C语言中的预处理命令,是为了方便对汇编程序做各种处理而生的。伪指令用于指导汇编器在汇编过程中执行特定的任务,如数据定义、内存分配、段定义等,它们在汇编程序转换成机器代码的过程中被处理,但在生成的机器代码中并不直接体现。
/******************** 基础伪操作 ********************/
ALIGN ;地址对齐
AREA ;用来定义一个代码段或数据段,常用的段属性为CODE/DATA
ENTRY ;指定汇编程序的执行入口
END ;用来告诉编译器源程序已到了结尾,停止编译
EQU ;赋值伪指令,类似宏,给常量定义一个符号名
CODE16/CODE32 ;指示编译器后面的指令为THUMB/ARM 指令
EXPORT/GLOBAL ;声明一个全局符号,可以被其他文件引用
IMPORT/EXTERN ;引用其他文件的全局符号前,要先IMPORT
GET/INCLUDE ;包含文件,并将该文件当前位置进行编译,一般包含的是程序文件
INCBIN ;包含文件,但不编译,一般包含的是数据、配置文件等
/******************** 变量定义 ********************/
//全局变量定义
GBLA a ;定义一个全局算术变量a,并初始化为0
a SETA 10 ;给算术变量a赋值为10
GBLL b ;定义一个全局逻辑变量b,并初始化为false
b SETL 20 ;给逻辑变量b赋值为20
GBLS STR ;定义一个全局字符串变量STR,并初始化为0
STR SETS "123" ;给变量STR赋值为"123"
//局部变量定义
LCLA a ;定义一个局部算术变量a,并初始化为0
LCLL b ;定义一个局部逻辑变量b,并初始化为false
LCLS name ;定义一个局部字符串变量name,并初始化为0
name SETS "123" ;给局部字符串变量赋值
/******************** 数据定义 ********************/
DATA1 DCB 10,20,30,40 ;分配一片连续的字节存储单元名为DATA1,并初始化
STR DCB "123" ;给字符串STR分配一片连续的存储单元并初始化
DATA2 DCD 10,20,30,40 ;分配一片连续的字存储单元名为DATA2,并初始化
BUF SPACE 100 ;给BUF分配100字节的存储单元并初始化为0
DATA 10,20,30,40 ;定义了一个包含四个整数的数据集合
举例,下面我们实现了一个汇编子程序SUM_ASM,使用EXPORT伪操作将其声明为一个全局符号(这样其他汇编程序或C程序就可以直接调用它了),SUM_ASM自身又调用了其他子程序sum(这个sum子程序可以是一个汇编子程序,也可以是一个使用C语言定义的函数),在调用之前我们要先使用IMPORT伪操作把sum子程序导入进来,然后就可以直接使用BL指令跳转过去运行了。
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 ;返回主程序,继续运行