56章 汇编语言程序设计final.docx
《56章 汇编语言程序设计final.docx》由会员分享,可在线阅读,更多相关《56章 汇编语言程序设计final.docx(34页珍藏版)》请在冰豆网上搜索。
56章汇编语言程序设计final
第5章ARM汇编语言程序设计
5.1ARM汇编语言伪指令
伪指令并不是真正的arm指令或者thumb指令,编译时伪指令会被处理成对应的arm或thumb指令序列。
不同的编译器提供的伪指令不同,这里主要介绍ARM编译器常用的伪指令。
5.1.1符号定义伪指令
1全局变量声明
GBLA声明一个全局算术变量,并将其初始化为0。
GBLL声明一个全局逻辑变量,并将其初始化为{FALSE}。
GBLS声明一个全局字符串变量,并将其初始化为NULL。
语法格式:
GBLAvariable
GBLLvariable
GBLSvariable
例:
GBLAnum1
GBLLlogic_x
GBLSstring_y
2局部变量声明
LCLA声明一个局部算术变量,并将其初始化为0。
LCLL声明一个局部逻辑变量,并将其初始化为{FALSE}。
LCLS声明一个局部字符串变量,并将其初始化为NULL。
语法格式:
LCLAvariable
LCLLvariable
LCLSvariable
例:
LCLAnum1
LCLLlogic_x
LCLSstring_y
3变量赋值
SETA给一个算术变量赋值。
SETL给一个逻辑变量赋值。
SETS给一个字符串变量赋值。
语法格式:
variableSETAexpr
variableSETLexpr
variableSETSexpr
例:
num1SETA0xff
logic_xSETL{TRUE}
string_ySETS“stringtest”
4RLIST
为通用寄存器列表定义名称,定义的名称可以在LDM/STM指令中使用。
列表中的寄存器以逗号分隔,连续编号的寄存器可以用“-”包括,例如:
r7-r9表示寄存器r7、r8、r9。
语法格式:
nameRLIST{listofregisters}
例:
reg_listRLIST{r0-r4,r6,r7-r9}
STMFDsp!
reg_list;将r0-r4,r6,r7-r9的内容压入满降序栈中保存
5RN
为寄存器定义名称。
语法格式:
nameRNexpr
例:
spRNr13
6CN、CP
CN为协处理器的寄存器定义名称。
CP为协处理器定义名称。
语法格式:
nameCNexpr
nameCPexpr
例:
powerCN6
dmuCP6
7DN、SN、FN
DN为一个双精度的VFP寄存器定义名称。
SN为一个单精度的VFP寄存器定义名称。
FN为一个FPA浮点寄存器定义名称。
语法格式:
nameDNexpr
nameSNexpr
nameFNexpr
例:
heightDN6
widthSN16
lowerFN6
8EQU
为数字常量、标号或寄存器定义一个字符名称。
语法格式:
nameEQUexpr{,type}
当expr表示绝对地址时,可以使用type选项,type可以为:
CODE16(表示Thumb指令地址)、CODE32(表示ARM指令地址)或DATA(表示数据区地址)。
例如:
addr_aEQU0x20,CODE32;将绝对地址0x20赋值给addr_a,并标记为32位地址。
5.1.2空间分配伪指令
9SPACE
SPACE伪指令常常用来分配一块内存区域供程序使用,并且将这个内存区域初始化为0。
该伪指令可以用“%”代替。
语法格式:
{label}SPACEexpr;其中label为可选项
例:
dataroomSPACE256;以dataroom为起始地址,分配256个字节的内存单元,并初始化为0
10DCB
DCB用于定义并初始化一个或多个字节的内存区域。
该伪指令可以用“=”代替。
语法格式:
{label}DCBexpr{,expr,…}
例:
data1DCB1,3,5
stringDCB“hello!
”,0;构造一个以NULL结尾的字符串,字符串的起始地址为string
注意,当DCB后面紧跟一个指令时,为了使指令保持字对齐,需要用到ALIGN伪指令,ALIGN伪指令将在下面讲到。
11DCD、DCDU
DCD和DCDU用于定义并初始化一个或多个字的内存区域,其中DCD可以用“&”代替。
DCD和DCDU的区别在于DCD可以保证分配的内存单元是严格的字对齐的,而DCDU不能保证。
语法格式:
{label}DCDexpr{,expr,…}
例:
data1DCD0,2,4,6
data2DCDU1,3,5
12DCDO
DCDO用于定义并初始化一个或多个字的内存区域,且保证分配的内存单元是字对齐的。
语法格式:
{label1}DCDOlabel2
DCDO与DCD的区别在于DCDO将内存单元label1初始化为DCDO后面的标号label2相对于静态基址寄存器R9(sb)的偏移量。
例:
IMPORTexternlabel
data1DCDOexternlabel;将地址为data1的字单元初始化为标号externlabel相对于R9的偏移量
13DCFD、DCFDU、DCFS、DCFSU
DCFD用于为双精度的浮点数分配字对齐的内存单元,每个双精度浮点数占据两个字单元。
语法格式:
{label}DCFDfpliteral{,fpliteral,…}
DCFDU与DCFD的不同之处在于DCFDU分配的内存单元并不是严格字对齐的。
DCFS用于为单精度的浮点数分配字对齐的内存单元,每个单精度浮点数占据1个字单元。
DCFSU与DCFS的不同之处在于DCFSU分配的内存单元并不是严格字对齐的。
例:
data1DCFD2.1E204,-3E-100
data2DCFDU236,-.5,3E25
data3DCFS2.1E2,-3E-10
14DCI
DCI用于分配并初始化一段内存单元,且认为内存单元中的数值为指令数据。
当DCI位于ARM代码中的时候,分配的内存是严格字对齐的;当DCI位于Thumb代码中的时候,分配的内存是半字对齐的。
语法格式:
{label}DCIexpr{,expr,…}
15DCQ、DCQU以及DCW、DCWU
DCQ和DCQU用于分配双字(8个字节)的内存单元,其中DCQ是严格字对齐的,DCQU不能保证严格字对齐。
DCW和DCWU用于分配半字(2个字节)的内存单元,其中DCW是严格字对齐的,DCWU不能保证严格字对齐。
语法格式:
{label}DCQexpr{,expr,…}
16LTORG
LTORG用于声明一个数据缓冲池(literalpool)的开始。
通常放在无条件跳转指令之后,或者子程序返回指令之后,以免处理器错误的将数据缓冲池中的数据作为指令来执行。
例:
func1
:
;代码
MOVPC,lr
LTORG
dataSPACE256;从data标号开始预留256个字节的内存单元
END
17MAP、FIELD
MAP和FIELD用于描述结构化的内存表。
其中MAP用于定义结构化内存表的首地址,MAP也可以用“^”来表示;FIELD用于定义结构化内存表中的数据域,FIELD可以用“#”来表示。
语法格式:
MAPexpr{,base-register};内存表的起始地址为expr+base-register,其中base-register为可选项,若没有此项,则内存表的起始地址为expr。
例:
MAP4000;内存表的起始地址为4000
IntegerFIELD4;从4000开始为Integer分配4个字节
StringFIELD64;从4004开始为String分配64个字节
DoubleaFIEDL8;从4068开始为Doublea分配8个字节
5.1.3汇编控制伪指令
18IF、ELSE和ENDIF
IF、ELSE和ENDIF用于控制汇编器是否将一段汇编指令的源代码包含在汇编语言程序内。
例:
IFFLAG=1
:
;如果条件满足,则包含此段代码
ELSE
:
;如果条件不满足,则包含此段代码
ENDIF
19WHILE、WEND
WHILE和WEND用来控制编译器根据条件重复汇编一段源代码。
例:
WHILEFLAG=1
:
;如果条件满足,则重复汇编此段代码
WEND
20MACRO、MEND、MEXIT
MACRO和MEND用来定义一段宏体。
所谓宏实际上是一段汇编语言指令序列,将多条指令定义成一条宏语句,编译时宏语句被展开。
例:
MACRO
$labelsubmac$sum,$num1,$num2
$labelCMP$num1,$num2
$label.1SUBGE$sum,$num1,$num2
$label.2SUB$sum,$num2,$num1
MEND
在这个例子中定义了一个名为“submac”的宏,其中$label、$label.1、$label.2为宏中语句的标号,$label并不是必需的,只有当宏中的其他语句需要标号时,$label才是必需的。
其他语句的标号可以根据需要设置成其他的名字,如$label.1、$label.2可以定义成$label.sub、$label.ressub等。
$sum、$num1、$num2是宏的参数,宏中所有的变量都是以“$”开头的。
若在程序中引用宏submac:
submacr0,r1,r2
则编译后展开为下面的语句:
CMPr1,r2
SUBGEr0,r1,r2
SUBr0,r2,r1
使用宏时应注意,宏操作中不遵循APCS原则,寄存器也不会受到保护。
MEXIT为从宏中跳出的伪指令。
5.1.4格式控制伪指令
21ALIGN
通过填充0将当前的位置以某种形式对齐。
语法格式:
ALIGN{expr{,offset}}
expr通常为2的整数次幂,表示对齐的方式。
例如,当expr为4时,表示其后的指令对齐到下一个字的边界处;offset表示在上述对齐方式下的偏移量。
若ALIGN后不带任何参数,则表示把当前位置对齐到下一个字的起始位置。
例如:
ALIGN4,1
表示其后的指令以字(4个字节)为起始位置,且偏移量为1。
若下一个字地址为0xC0004,则下面指令的起始地址为0xC0005。
22CODE16、CODE32
CODE16表示其后的指令为16位的THUMB指令。
CODE32表示其后的指令为32位的ARM指令。
语法格式:
CODE16
CODE32
23AREA
定义一个代码段或数据段及其属性。
语法格式:
AREAsectionname{,attr}{,attr}…
sectionname为代码段或数据段的名称。
若该名称以数字开头,则必须用“|”括起来,如“|2_name|”。
还有一些代码段有约定的名称,如|.text|表示C语言编译器产生的代码段或者是C语言库相关的代码段。
attr表示代码段的属性,各属性间用逗号分隔