ARM汇编笔记

本文是对老师上课笔记的整理汇总,请勿转载

ARM汇编指令:

condition:
EQ Z=1 相等
NE Z=0 不相等
CS/HS C=1 无符号数大于或等于
CC/LO C=0 无符号数小于
MI N=1 负数
PL N=0 正数或零
VS V=1 溢出
VC V=0 未溢出
HI C=1且Z=0 无符号数大于
LS C=0且Z=1 无符号数小于或等于
GE N=1且V=1或N=0且V=0 带符号数大于或等于
LT N=1且V=0或N=0且V=1 带符号数小于

后缀:
S,指令执行后程序状态寄存器的条件标志位将刷新。(有的指令不使用 S 后缀,也要刷新条件标志位,如CMP、CMN、TST等指令。)
!,在指令的地址表达式中含有 !后缀时,指令执行后,基地址寄存器中的地址将会发生变化(回写)。
B,指令所涉及的数据是一个字节,不是一个字或半字。
T,指令在特权模式下对存储器的访问,将被存储器看作是用户模式的访问。

前变址和自动变址模式都会回写,后变址模式不会回写

ASR #n;算数右移n位(1≤ n ≤32)
LSL #n;逻辑左移n位(0≤ n ≤31)
LSR #n;逻辑右移n位(1≤ n ≤32)
ROR #n;循环右移n位(1≤ n ≤31)

LDM{<cond>} {mode} <Rd>{!},<reglist>{^}
STM{<cond>} {mode} <Rd>{!},<reglist>{^}
IA 先传送数据,后基地址加4 (Rn) 增加
IB 先基地址加4,后传送数据 (Rn)+4 增加
DA 先传送数据,后基地址减4 (Rn) 减少
DB 先基地址减4,后传送数据 (Rn)-4 减少
LDMIA R0,{R2、R3、R4、R5} //[R0]->R2 [R0+4]->R3 [R0+8]->R4 [R0+12]->R5

FA 递增满堆栈 LDMFA STMFA
FD 递减满堆栈 LDMFD STMFD
EA 递增空堆栈 LDMEA STMEA
ED 递减空堆栈 LDMED STMED
STMXX SP!,{R1-R7,LR} XX:FD ED FA EA
LDMXX SP!,{R1-R7,LR} XX:FD ED FA EA

LDR{<cond>} <Rd>, <address_mode>
LDR{cond}H <Rd>, <address_mode> //半字,高16位清零
LDR{cond}B <Rd>, <address_mode> //字节,高24位清零
STR{cond} <Rd>, <address_mode>
STR{cond}H <Rd>, <address_mode>
STR{cond}B <Rd>, <address_mode>

注意:
LDR LDM中L都是Load,第一参数都是寄存器,第二参数都是存储器地址,前者是加载到寄存器,后者是加载到存储器。
同理,STR STM中L都是Store,第一参数都是寄存器,第二参数都是存储器地址,前者是store寄存器(到存储器),后者是store存储器(到寄存器)。

B{<cond>} <target>
BL{<cond>} <target>
BX{<cond>} Rm
BLX <target> //ARM -> Thumb PC -> LR
BLX{<cond>} Rm //Rm[0] -> T

ADD{<cond>}{S} <Rd>, <Rn>, <operand2>
SUB{<cond>}{S} <Rd>, <Rn>, <operand2>
ADC{<cond>}{S} <Rd>, <Rn>, <operand2>
SBC{<cond>}{S} <Rd>, <Rn>, <operand2>
RSB{<cond>}{S} <Rd>, <Rn>, <operand2>
RSC{<cond>}{S} <Rd>, <Rn>, <operand2>

AND{<cond>}{S} <Rd>, <Rn>, <operand2>
ORR{<cond>}{S} <Rd>, <Rn>, <operand2>
EOR{<cond>}{S} <Rd>, <Rn>, <operand2>
BIC{<cond>}{S} <Rd>, <Rn>, <operand2>

MOV{<cond>}{S} <Rd>, <operand2>
MVN{<cond>}{S} <Rd>, <operand2> //operand按位取反

CMP{<cond>} <Rd>, <operand2> //减
CMN{<cond>} <Rd>, <operand2> //operand2取反,不存储结果
TST{<cond>} <Rd>, <operand2> //与
TEQ{<cond>} <Rd>, <operand2> //异或

MUL{<cond>}{S} <Rd>, <Rm>, <Rs>
MLA{<cond>}{S} <Rd>, <Rm>, <Rs>, <Rn> //RmXRs+Rn -> Rd

SMULL{<cond>}{S}<RdLo>, <RdHi>, <Rm>, <Rs>//Rm*Rs [0-31]->RdLo [32-63]->RdHi
SMLAL{<cond>}{S}<RdLo>, <RdHi>, <Rm>, <Rs>//Rm*Rs [0-31]+RdLo->RdLo [32-63]+RdHi->RdHi
UMULL{<cond>}{S}<RdLo>, <RdHi>, <Rm>, <Rs>//无符号数
UMLAL{<cond>}{S}<RdLo>, <RdHi>, <Rm>, <Rs>//无符号数

MRS {<cond>} <Rd>, CPSR //CPSR -> Rd
MRS {<cond>} <Rd>,SPSR

MSR{<cond>} CPSR_<fields>,<operand2> //fields:f s x c operand2->fields
MSR{<cond>} SPSR_<fields>,<operand2>
f [31:24] 条件标志域
s [23:16] 状态位域
x [15:8] 扩展位域
c [7:0] 控制位域

SWP 字交换 Tmp=mem32[Rn]
Mem32[Rn]=Rm
Rd=tmp
SWP{<cond>} <Rd>, <Rm>, {<Rn>}

SWPB 字节交换 Tmp=mem8[Rn]
Mem8[Rn]=Rm
Rd=tmp
SWPB{<cond>} <Rd>, <Rm>, {<Rn>}

特殊情况的总结

除专用指令外会修改cpsr的指令

1.16-bit体系下(thumb),所有对pc进行修改并带s的指令,都会造成spsr->cpsr
2.ldm的寄存器列表中含pc,也会造成spsr->cpsr

伪代码(顶格书写):

宏:
MACRO 和 MEND 宏指令可以为一个程序段定义一个名称。
MACRO
参数1, $参数2,…..
程序段(宏定义体)
MEND

MEXIT 用于从宏定义中跳转出去。

宏指令:
ADR{cond} <reg>, <expr> //近地址读取宏指令 expr通常是地址标号。
ADRL{cond} <reg>, <expr> //远地址读取宏指令 Expr 为表达式,必须是 64KB 以内非字对齐地址,256KB 以内的字对齐地址。
LDR{cond} <reg>, ={expr | label - expr} //全范围地址读取宏指令

声明全局变量伪指令 GBLA、GBLL和GBLS,GBLA、GBLL 和 GBLS 伪指令用于定义一个 ARM 程序中的 全局变量,并将其初始化。
GBLA 定义一个 全局数字变量,其默认初值为 0 ;
GBLL 定义一个 全局逻辑变量 ,其默认初值为 FALSE(假);
GBLS 定义一个 全局字符串变量,其默认初值为 空 ;

声明 局部变量 伪指令 LCLA、LCLL和LCLS,LCLA、LCLL和LCLS 伪指令用于定义一个 ARM 程序中的 局部变量,并将其初始化。
LCLA 定义一个 局部数字变量,其默认初值为 0;
LCLL 定义一个 局部逻辑变量,其默认初值为 FALSE(假);
LCLS 定义一个 局部字符串变量,其默认初值为 空。

变量赋值伪指令 SETA、SETL和SETS
伪指令 SETA、SETL和SETS 用于给一个 已经定义 的 全局变量 或 局部变量 进行赋值。

指令 LDM/STM 需要使用一个比较长的寄存器列表,使用伪指令 RLIST 可对一个列表定义一个统一的名称。
<name> RLIST <{list}>

数据定义伪指令 LTORG
伪指令 LTORG 用来说明某个存储区域为一个用来暂存数据的数据缓冲区,也叫文字池 或 数据缓冲池。

 AREA example, CODE, READONLY
 Start  BL  Func1
             …
 Func1  LDR R1,=0x800
        MOV PC,LR
 LTORG  ;定义数据缓冲池的开始位置
 Date   SPACE  40 ;数据缓冲池有40个被初始化为0的字节
        END

MAP <expr>{,<baseregister>}
<label> FIEL <expr>
MAP 通常和 FIELD 伪指令相配合来定义一个结构化的内存表。
MAP 用于定义一个结构化的内存表的首地址。
FIELD 伪指令用于定义一个结构化内存表中的数据域。

 MAP 0X100 ;定义结构化内存表首地址为 0X100
 A FIELD 16 ;定义A的长度为16字节,位置为 0X100
 B FIELD 32 ;定义B的长度为32字节,位置为 0X110
 S FIELD 256 ;定义S的长度为256字节,位置为 0X130

SPACE 伪指令用于分配一片连续的存储区域并初始化为 0。
<label> SPACE <expr> //表达式为要分配的 字节数,SPACE 也可用“%” 代替。

DCB 伪指令用于分配一片连续的 以字节为单位 的存储区域,并用指定的表达式对其进行初始化。
{<label>} DCB <expr> //Expr 为表达式,为从标号开始存放的数据。该表达式可以为 0~255 的数字或字符串。DCB 也可用“=” 代替

DCD(或DCDU)伪指令用于分配一片连续的 字 存储单元,并用伪指令中指定的表达式初始化。
<label> DCD(或DCDU) <expr> //表达式可以为 程序标号 或 数字表达式。用 DCD 分配的字存储单元是字对齐的,而用 DCDU 分配的字存储单元并不严格要求字对齐。DCD 也可用“&” 代替。

DCDO 用来为字分配一段字对准的内存单元,并用一个地址偏移量初始化,这个偏移量是 DCDO 定义的标号地址到 R9 指定的地址之间的差值。
{<label>} DCDO 用来初始化的数值或标号

DCFD(或DCFDU)伪指令用于为双精度的浮点数分配一片连续的字存储单元,并用伪指令中指定的表达式初始化。每个双精度的浮点数占据 两个字单元。
<label> DCFD(或DCFDU) <expr> //用 DCFD 分配的字存储单元是字对齐的而用 DCFDU 分配的字存储单元并不严格字对齐。

DCFS(或DCFSU)伪指令用于为 单精度的浮点数 分配一片连续的字存储单元,并用伪指令中指定的表达式初始化。每个单精度浮点数占据 一个字单元。
<label> DCFS(或DCFSU) <expr> //用 DCFS 分配的字存储单元是字对齐的;而用 DCFSU 分配的字存储单元并不严格字对齐。

DCQ(或DCQU)伪指令用于分配一片以 8字节 为单位的连续存储区域,并用伪指令中指定的表达式初始化。
<label> DCQ(或DCQU) <expr> //用 DCQ 分配的存储单元是字对齐的,而用 DCQU 分配的字存储单元并不严格字对齐。

DCW(或DCWU)伪指令用于为数据分配一片连续的 半字 存储单元,并用表达式对其进行初始化。
<label> DCW(或DCWU) <expr> //用 DCW 分配的半字存储单元是严格按半字对齐的,而用 DCWU 分配的半字存储单元并不严格按半字对齐。

IF、ELSE 和 ENDIF伪指令能根据条件的成立与否决定是否执行某个程序段。

IF 逻辑表达式
  程序段1
ELSE
  程序段2
ENDIF

WHILE 和 WEND 伪指令根据条件的成立与否决定是否重复汇编一个程序段。

WHILE  逻辑表达式
   程序段
WEND

定义对齐方式伪指令 ALIGN
ALIGN=表达式 //对齐方式为2表达式的值。 使用 ALIGN 伪指令可用添加填充字节的方式,使当前位置实现某种对齐方式。在开发环境中看不到。

AREA Init, CODE, READONLY, ALIGN=3
  代码段
END

段定义伪指令
AREA <sectionname>,{<attr>}{,<attr>}… //sectionname:段名,若段名以数字开头,则必须用符号“|”扩起来,如|1_test|。
attr:属性字段,多个属性字段用逗号分隔。
CODE 代码段 默认读/写属性为READONLY
DATA 数据段 默认读/写属性为READWRITE
READONLY 本段为只读
READWRITE 本段为可读可写
ALIGN表达式 ELF 的代码段和数据段为字对齐
COMMON 多源文件共享段

CODE16 和 CODE32
CODE16 用来表明其后的指令均为 16位Thumb 指令;CODE32 伪指令则表明其后面的指令均为 32位ARM 指令。

定义程序入口点伪指令 ENTRY

  AREA Init, CODE, READONLY
  ENTRY;
  …..

汇编结束伪指令 END
END 伪指令用于通知编译器汇编工作到此结束,不再往下汇编了。

外部可引用符号声明伪指令 EXPORT(或GLOBAL)
用伪指令 EXPORT 可以声明一个其他源文件可引用的符号,这种符号也叫做外部可引用符号。
EXPORT 符号 {[WEAK]} //EXPORT 可用 GLOBAL 代替。[WEAK]选项声明其他的同名符号优先于该符号被引用。

等效伪指令 EQU
EQU 伪指令用于为程序中的常量、标号等定义一个等效的字符名字,其作用类似于 C语言 中的 #define。
名称 EQU 表达式 {,类型} //由 EQU 伪指令定义的字符名称,当其表达式为 32位 常量时,可以指定表达式的数据类型,有以下三种类型:CODE16、CODE32 和 DATA。EQU 也可用“*” 代替。

IMPORT
当在一个源文件中需要使用另外一个源文件的外部可引用符号时,在被引用的符号前面必须使用伪指令 IMPORT 对其进行声明。
IMPORT 符号 {[WEAK]} //[WEAK] 选项表示当前所有的源文件都没有定义这样一个符号时,编译器也不报错,并在多数情况下将该符号置为 0 。但该符号被 B 或 BL 指令所引用时,则将 B 或 BL 指令置为 NOP 操作。

EXTERN
EXTERN 伪指令与 IMPORT 伪指令的功能基本相同,但如果当前源文件中的程序实际并未使用该指令,则该符号不会加入到当前源文件的符号表中。其它与 IMPORT 相同。

GET(INCLUDE)
GET 伪指令用于将一个源文件包含到当前的源文件中,并将被包含的源文件在当前位置进行汇编。
GET 文件名 //GET 伪指令只能用于包含 源文件,包含目标文件则需要使用 INCBIN 伪指令。可以使用 INCLUDE 代替 GET。

INCBIN
INCBIN 伪指令用于将一个 目标文件 或 数据文件 包含到当前的源文件中,被包含的文件不做任何变动地存放在当前文件中,编译器从其后开始继续处理。
INCBIN 文件名

  AREA Init, CODE, READONLY
  INCBIN a1.dat
  INCBIN c:\a2.txt
  …
  END

RN
RN 伪指令用于给一个寄存器定义一个别名,以提高程序的可读性。
名称 RN 表达式 //名称为给寄存器定义的别名,表达式为寄存器的编码。

ROUT
ROUT 伪指令用于给一个局部变量定义作用范围。
名称 ROUT //在程序中未使用该伪指令时,局部变量的作用范围为所在的 AREA ;而使用 ROUT 后,局部变量的作用范围为当前 ROUT 和下一个 ROUT 之间。

ARM编程:

符号

在ARM汇编语言中,符号 可以代表 地址、变量 和 数字常量。
符号命名规则如下:
第一:符号由大小写字母、数字以及下画线组成;
第二:局部标号以数字开头,其他的符号都不能以数字开头;
第三:符号是区分大小写的;
第四:符号中的所有字符都是有意义的;
第五:符号在其作用范围内必须唯一;
第六:程序中的符号不能与指令助记符、伪指令、宏指令同名。

汇编语言的表达式和运算符

运算次序遵循如下的优先级:
(1)优先级相同的双目运算符运算顺序为 从左到右;
(2)相邻的 单目运算符 的运算顺序为从右到左,且 单目运算符 的优先级高于其他运算符;
(3)括号运算符的优先级最高。

汇编调用C函数 //汇编import,BL

C调用汇编函数 //汇编export C用extern

内联汇编

 _ _asm     //声名内联汇编代码
{
    MRS  tmp, CPSR
    BIC  tmp, tmp, #0x80
    MSR  CPSR_c, tmp
}

嵌入式汇编 //像C函数一样被调用

 _ _asm int add(int i, int j)
       {
          ADD  R0, R0, R1
          MOV  PC, LR
       }

猜你喜欢

转载自blog.csdn.net/the_k_is_on_the_way/article/details/79885459