ARM编译器一般都支撑汇编言语的程序设计和C/C++言语的程序设计,以及两者的混合编程。本章介绍ARM程序设计的一些根本概念,如ARM汇编言语的伪指令、汇编言语的查办格局和汇编言语的程序结构等,一起介绍C/C++和汇编言语的混合编程等问题。
本章的首要内容:
- ARM编译器所支撑的伪指令
- 汇编言语的查办格局
- 汇编言语的程序结构
- 相关的程序示例
4.1 ARM汇编器所支撑的伪指令
在ARM汇编言语程序里,有一些特别指令助记符,这些助记符与指令体系的助记符不同,没有相对应的操作码,一般称这些特别指令助记符为伪指令,他们所完结的操作称为伪操作。伪指令在源程序中的效果是为完结汇编程序作各种准备作业的,这些伪指令仅在汇编进程中起效果,一旦汇编完毕,伪指令的使命就完结。
在ARM的汇编程序中,有如下几种伪指令:符号界说伪指令、数据界说伪指令、汇编操控伪指令、宏指令以及其他伪指令。
4.1.1符号界说(Symbol Definition)伪指令
符号界说伪指令用于界说ARM汇编程序中的变量、对变量赋值以及界说寄存器的别号等操作。常见的符号界说伪指令有如下几种:
— 用于界说大局变量的GBLA、GBLL和GBLS。
— 用于界说部分变量的LCLA、LCLL和LCLS。
— 用于对变量赋值的SETA、SETL、SETS。
— 为通用寄存器列表界说称号的RLIST。
1、 GBLA、GBLL和GBLS
语法格局:
GBLA(GBLL或GBLS) 大局变量名
GBLA、GBLL和GBLS伪指令用于界说一个ARM程序中的大局变量,并将其初始化。其间:
GBLA伪指令用于界说一个大局的数字变量,并初始化为0;
GBLL伪指令用于界说一个大局的逻辑变量,并初始化为F(假);
GBLS伪指令用于界说一个大局的字符串变量,并初始化为空;
我们以上三条伪指令用于界说大局变量,因而在整个程序规模内变量名有必要仅有。
运用示例:
GBLA Test1 ;界说一个大局的数字变量,变量名为Test1
Test1 SETA 0xaa ;将该变量赋值为0xaa
GBLL Test2 ;界说一个大局的逻辑变量,变量名为Test2
Test2 SETL {TRUE} ;将该变量赋值为真
GBLS Test3 ;界说一个大局的字符串变量,变量名为Test3
Test3 SETS “Testing” ;将该变量赋值为“Testing”
2、 LCLA、LCLL和LCLS
语法格局:
LCLA(LCLL或LCLS) 部分变量名
LCLA、LCLL和LCLS伪指令用于界说一个ARM程序中的部分变量,并将其初始化。其间:
LCLA伪指令用于界说一个部分的数字变量,并初始化为0;
LCLL伪指令用于界说一个部分的逻辑变量,并初始化为F(假);
LCLS伪指令用于界说一个部分的字符串变量,并初始化为空;
以上三条伪指令用于声明部分变量,在其效果规模内变量名有必要仅有。
运用示例:
LCLA Test4 ;声明一个部分的数字变量,变量名为Test4
Test3 SETA 0xaa ;将该变量赋值为0xaa
LCLL Test5 ;声明一个部分的逻辑变量,变量名为Test5
Test4 SETL {TRUE} ;将该变量赋值为真
LCLS Test6 ;界说一个部分的字符串变量,变量名为Test6
Test6 SETS “Testing” ;将该变量赋值为“Testing”
3、 SETA、SETL和SETS
语法格局:
变量名 SETA(SETL或SETS) 表达式
伪指令SETA、SETL、SETS用于给一个现已界说的大局变量或部分变量赋值。
SETA伪指令用于给一个数学变量赋值;
SETL伪指令用于给一个逻辑变量赋值;
SETS伪指令用于给一个字符串变量赋值;
其间,变量名为现已界说过的大局变量或部分变量,表达式为酿制赋给变量的值。
运用示例:
LCLA Test3 ;声明一个部分的数字变量,变量名为Test3
Test3 SETA 0xaa ;将该变量赋值为0xaa
LCLL Test4 ;声明一个部分的逻辑变量,变量名为Test4
Test4 SETL {TRUE} ;将该变量赋值为真
4、 RLIST
语法格局:
称号 RLIST {寄存器列表}
RLIST伪指令可用于对一个通用寄存器列表界说称号,运用该伪指令界说的称号可在ARM指令LDM/STM中运用。在LDM/STM指令中,列表中的寄存器拜访次第为依据寄存器的编号由低到高,而与列表中的寄存器摆放次第无关。
运用示例:
RegList RLIST {R0-R5,R8,R10} ;将寄存器列表称号界说为RegList,可在ARM指令LDM/STM中经过该称号拜访寄存器列表。
4.1.2数据界说(Data Definition)伪指令
数据界说伪指令一般用于为特定的数据分配存储单元,一起可完结已分配存储单元的初始化。常见的数据界说伪指令有如下几种:
— DCB 用于分配一片接连的字节存储单元并用指定的数据初始化。
— DCW(DCWU) 用于分配一片接连的半字存储单元并用指定的数据初始化。
— DCD(DCDU) 用于分配一片接连的字存储单元并用指定的数据初始化。
— DCFD(DCFDU)用于为双精度的浮点数分配一片接连的字存储单元并用指定的数据初始化。
— DCFS(DCFSU) 用于为单精度的浮点数分配一片接连的字存储单元并用指定的数据初始化。
— DCQ(DCQU) 用于分配一片以8字节为单位的连 续的存储单元并用指定的数据初始化。
— SPACE 用于分配一片接连的存储单元
— MAP 用于界说一个结构化的内存表首地址
— FIELD 用于界说一个结构化的内存表的数据域
1、 DCB
语法格局:
标号 DCB 表达式
DCB伪指令用于分配一片接连的字节存储单元并用伪指令中指定的表达式初始化。其间,表达式能够为0~255的数字或字符串。DCB也可用“=”替代。
运用示例:
Str DCB “This is a test!” ;分配一片接连的字节存储单元并初始化。
2、 DCW(或DCWU)
语法格局:
标号 DCW(或DCWU) 表达式
DCW(或DCWU)伪指令用于分配一片接连的半字存储单元并用伪指令中指定的表达式初始化。其间,表达式能够为程序标号或数字表达式。。
用DCW分配的字存储单元是半字对齐的,而用DCWU分配的字存储单元并不严厉半字对齐。
运用示例:
DataTest DCW 1,2,3 ;分配一片接连的半字存储单元并初始化。
3、 DCD(或DCDU)
语法格局:
标号 DCD(或DCDU) 表达式
DCD(或DCDU)伪指令用于分配一片接连的字存储单元并用伪指令中指定的表达式初始化。其间,表达式能够为程序标号或数字表达式。DCD也可用“&”替代。
用DCD分配的字存储单元是字对齐的,而用DCDU分配的字存储单元并不严厉字对齐。
运用示例:
DataTest DCD 4,5,6 ;分配一片接连的字存储单元并初始化。
4、 DCFD(或DCFDU)
语法格局:
标号 DCFD(或DCFDU) 表达式
DCFD(或DCFDU)伪指令用于为双精度的浮点数分配一片接连的字存储单元并用伪指令中指定的表达式初始化。每个双精度的浮点数占有两个字单元。
用DCFD分配的字存储单元是字对齐的,而用DCFDU分配的字存储单元并不严厉字对齐。
运用示例:
FDataTest DCFD 2E115,-5E7 ;分配一片接连的字存储单元并初始化为指定的双精度数。
5、 DCFS(或DCFSU)
语法格局:
标号 DCFS(或DCFSU) 表达式
DCFS(或DCFSU)伪指令用于为单精度的浮点数分配一片接连的字存储单元并用伪指令中指定的表达式初始化。每个单精度的浮点数占有一个字单元。
用DCFS分配的字存储单元是字对齐的,而用DCFSU分配的字存储单元并不严厉字对齐。
运用示例:
FDataTest DCFS 2E5,-5E-7 ;分配一片接连的字存储单元并初始化为指定的单精度数。
6、 DCQ(或DCQU)
语法格局:
标号 DCQ(或DCQU) 表达式
DCQ(或DCQU)伪指令用于分配一片以8个字节为单位的接连存储区域并用伪指令中指定的表达式初始化。
用DCQ分配的存储单元是字对齐的,而用DCQU分配的存储单元并不严厉字对齐。
运用示例:
DataTest DCQ 100 ;分配一片接连的存储单元并初始化为指定的值。
7、 SPACE
语法格局:
标号 SPACE 表达式
SPACE伪指令用于分配一片接连的存储区域并初始化为0。其间,表达式为要分配的字节数。SPACE也可用“%”替代。
运用示例:
DataSpace SPACE 100 ;分配接连100字节的存储单元并初始化为0。
8、 MAP
语法格局:
MAP 表达式{,基址寄存器}
MAP伪指令用于界说一个结构化的内存表的首地址。MAP也可用“^”替代。
表达式能够为程序中的标号或数学表达式,基址寄存器为可选项,当基址寄存器选项不存在时,表达式的值即为内存表的首地址,当该选项存在时,内存表的首地址为表达式的值与基址寄存器的和。
MAP伪指令一般与FIELD伪指令合作运用来界说结构化的内存表。
运用示例:
MAP 0x100,R0 ;界说结构化内存表首地址的值为0x100+R0。
9、 FILED
语法格局:
标号 FIELD 表达式
FIELD伪指令用于界说一个结构化内存表中的数据域。FILED也可用“#”替代。
表达式的值为当时数据域在内存表中所占的字节数。
FIELD伪指令常与MAP伪指令合作运用来界说结构化的内存表。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
4.1.3汇编操控(Assembly Control)伪指令
汇编操控伪指令用于操控汇编程序的碑文流程,常用的汇编操控伪指令包括以下几条:
— IF、ELSE、ENDIF
— WHILE、WEND
— MACRO、MEND
— MEXIT
1、 IF、ELSE、ENDIF
语法格局:
IF 逻辑表达式
指令序列1
ELSE
指令序列2
ENDIF
IF、ELSE、ENDIF伪指令能依据条件的建立与否决议是否碑文某个指令序列。当IF后边的逻辑表达式为真,则碑文指令序列1,不然碑文指令序列2。其间,ELSE及指令序列2能够没有,此刻,当IF后边的逻辑表达式为真,则碑文指令序列1,不然持续碑文后边的指令。
IF、ELSE、ENDIF伪指令能够嵌套运用。
运用示例:
GBLL Test ;声明一个大局的逻辑变量,变量名为Test
……
IF Test = TRUE
指令序列1
ELSE
指令序列2
ENDIF
2、 WHILE、WEND
语法格局:
WHILE 逻辑表达式
指令序列
WEND
WHILE、WEND伪指令能依据条件的建立与否决议是否循环碑文某个指令序列。当WHILE后边的逻辑表达式为真,则碑文指令序列,该指令序列碑文完毕后,再判别逻辑表达式的值,若为真则持续碑文,一直到逻辑表达式的值为假。
WHILE、WEND伪指令能够嵌套运用。
运用示例:
GBLA Counter ;声明一个大局的数学变量,变量名为Counter
Counter SETA 3 ;由变量Counter操控循环次数
……
WHILE Counter < 10
指令序列
WEND
3、 MACRO、MEND
语法格局:
$标号 宏名 $参数1,$参数2,……
指令序列
MEND
MACRO、MEND伪指令能够将一段代码界说为一个全体,称为宏指令,然后就能够在程序中经过宏指令屡次调用该段代码。其间,$标号在宏指令被打开时,标号会被替换为用户界说的符号,
宏指令能够运用一个或多个参数,当宏指令被打开时,这些参数被相应的值替换。
宏指令的运用办法和功用与子程序有些类似,子程序能够供给模块化的程序设计、节约存储空间并进步运转速度。但在运用子程序结构时需求维护现场,然后添加了体系的开支,因而,在代码较短且需求传递的参数较多时,能够运用宏指令替代子程序。
包括在MACRO和MEND之间的指令序列称为宏界说体,在宏界说体的榜首行应声明宏的原型(包括宏名、所需的参数),然后就能够在汇编程序中经过宏名来调用该指令序列。在源程序被编译时,汇编器将宏调用打开,用宏界说中的指令序列替代程序中的宏调用,并将实践参数的值传递给宏界说中的形式参数。
MACRO、MEND伪指令能够嵌套运用。
4、 MEXIT
语法格局:
MEXIT
MEXIT用于从宏界说中跳转出去。
4.1.4其他常用的伪指令
还有一些其他的伪指令,在汇编程序中常常会被运用,包括以下几条:
— AREA
— ALIGN
— CODE16、CODE32
— ENTRY
— END
— EQU
— EXPORT(或GLOBAL)
— IMPORT
— EXTERN
— GET(或INCLUDE)
— INCBIN
— RN
— ROUT
1、 AREA
语法格局:
AREA 段名 特点1,特点2,……
AREA伪指令用于界说一个代码段或数据段。其间,段名若以数字最初,则该段名需用“|”括起来,如|1_test|。
特点字段一共该代码段(或数据段)的相关特点,多个特点用逗号分隔。常用的特点如下:
— CODE特点:用于界说代码段,默以为READONLY。
— DATA特点:用于界说数据段,默以为READWRITE。
— READONLY特点:指定本段为只读,代码段默以为READONLY。
— READWRITE特点:指定本段为可读可写,数据段的默许特点为READWRITE。
— ALIGN特点:运用办法为ALIGN 表达式。在默许时,ELF(可碑文衔接文件)的代码段和数据段是按字对齐的,表达式的取值规模为0~31,相应的对齐办法为2表达式次方。
— COMMON特点:该特点界说一个通用的段,不包括任何的用户代码和数据。各源文件中同名的COMMON段同享同一段存储单元。
一个汇编言语程序至少要包括一个段,当程序太长时,也能够将程序分为多个代码段和数据段。
运用示例:
AREA Init,CODE,READONLY
指令序列
;该伪指令界说了一个代码段,段名为Init,特点为只读
2、 ALIGN
语法格局:
ALIGN {表达式{,偏移量}}
ALIGN伪指令可经过添加填充字节的办法,使当时方位分量必定的对其办法|。其间,表达式的值用于指定对齐办法,或许的取值为2的幂,如1、2、4、8、16等。若未指定表达式,则将当时方位对齐到下一个字的方位。偏移量也为一个数字表达式,若运用该字段,则当时方位的对齐办法为:2的表达式次幂+偏移量。
运用示例:
AREA Init,CODE,READONLY,ALIEN=3 ;指定后边的指令为8字节对齐。
指令序列
END
3、 CODE16、CODE32
语法格局:
CODE16(或CODE32)
CODE16伪指令告知编译器,这以后的指令序列为16位的Thumb指令。
CODE32伪指令告知编译器,这以后的指令序列为32位的ARM指令。
若在汇编源程序中一起包括ARM指令和Thumb指令时,可用CODE16伪指令告知编译器这以后的指令序列为16位的Thumb指令,CODE32伪指令告知编译器这以后的指令序列为32位的ARM指令。因而,在运用ARM指令和Thumb指令混合编程的代码里,可用这两条伪指令进行切换,但留意他们只告知编译器这以后指令的类型,并不能对处理器进行状况的切换。
运用示例:
AREA Init,CODE,READONLY
……
CODE32 ;告知编译器这以后的指令为32位的ARM指令
LDR R0,=NEXT+1 ;将跳转地址放入寄存器R0
BX R0 ;程序跳转到新的方位碑文,并将处理器切换到Thumb作业状况
……
CODE16 ;告知编译器这以后的指令为16位的Thumb指令
NEXT LDR R3,=0x3FF
……
END ;程序完毕
4、 ENTRY
语法格局:
ENTRY
ENTRY伪指令用于指定汇编程序的进口点。在一个完好的汇编程序中至少要有一个ENTRY(也能够有多个,当有多个ENTRY时,程序的真实进口点由链接器指定),但在一个源文件里最多只能有一个ENTRY(能够没有)。
运用示例:
AREA Init,CODE,READONLY
ENTRY ;指定运用程序的进口点
……
5、 END
语法格局:
END
END伪指令用于告知编译器现已到了源程序的完毕。
运用示例:
AREA Init,CODE,READONLY
……
END ;指定运用程序的完毕
6、 EQU
语法格局:
称号 EQU 表达式{,类型}
EQU伪指令用于为程序中的常量、标号等界说一个等效的字符称号,类似于C言语中的#define。其间EQU可用“*”替代。
称号为EQU伪指令界说的字符称号,当表达式为32位的常量时,能够指定表达式的数据类型,能够有以下三种类型:
CODE16、CODE32和DATA
运用示例:
Test EQU 50 ;界说标号Test的值为50
Addr EQU 0x55,CODE32 ;界说Addr的值为0x55,且该处为32位的ARM指令。
7、 EXPORT(或GLOBAL)
语法格局:
EXPORT 标号{[WEAK]}
EXPORT伪指令用于在程序中声明一个大局的标号,该标号可在其他的文件中引证。EXPORT可用GLOBAL替代。标号在程序中委任巨细写,[WEAK]选项声明其他的同名标号优先于该标号被引证。
运用示例:
AREA Init,CODE,READONLY
EXPORT Stest ;声明一个可大局引证的标号Stest
……
END
8、 IMPORT
语法格局:
IMPORT 标号{[WEAK]}
IMPORT伪指令用于告知编译器要运用的标号在其他的源文件中界说,但要在当时源文件中引证,并且不管当时源文件是否引证该标号,该标号均会被加入到当时源文件的符号表中。
标号在程序中委任巨细写,[WEAK]选项一共当一切的源文件都没有界说这样一个标号时,编译器也不给出错误信息,在大都状况下将该标号置为0,若该标号为B或BL指令引证,则将B或BL指令置为NOP操作。
运用示例:
AREA Init,CODE,READONLY
IMPORT Main ;告知编译器当时文件要引证标号Main,但Main在其他源文件中界说
……
END
9、 EXTERN
语法格局:
EXTERN 标号{[WEAK]}
EXTERN伪指令用于告知编译器要运用的标号在其他的源文件中界说,但要在当时源文件中引证,假如当时源文件实践并未引证该标号,该标号就不会被加入到当时源文件的符号表中。
标号在程序中委任巨细写,[WEAK]选项一共当一切的源文件都没有界说这样一个标号时,编译器也不给出错误信息,在大都状况下将该标号置为0,若该标号为B或BL指令引证,则将B或BL指令置为NOP操作。
运用示例:
AREA Init,CODE,READONLY
EXTERN Main ;告知编译器当时文件要引证标号Main,但Main在其他源文件中界说
……
END
10、 GET(或INCLUDE)
语法格局:
GET 文件名
GET伪指令用于将一个源文件包括到当时的源文件中,并将被包括的源文件在当时方位进行汇编处理。能够运用INCLUDE替代GET。
汇编程序中常用的办法是在某源文件中界说一些宏指令,用EQU界说常量的符号称号,用MAP和FIELD界说结构化的数据类型,然后用GET伪指令将这个源文件包括到其他的源文件中。运用办法与C言语中的“include”类似。
GET伪指令只能用于包括源文件,包括方针文件需求运用INCBIN伪指令
运用示例:
AREA Init,CODE,READONLY
GET a1.s ;告知编译器当时源文件包括源文件a1.s
GE T C:/a2.s ;告知编译器当时源文件包括源文件C:/ a2.s
……
END
11、 INCBIN
语法格局:
INCBIN 文件名
INCBIN伪指令用于将一个方针文件或数据文件包括到当时的源文件中,被包括的文件不作任何变化的寄存在当时文件中,编译器从这以后开端持续处理。
运用示例:
AREA Init,CODE,READONLY
INCBIN a1.dat ;告知编译器当时源文件包括文件a1.dat
INCBIN C:/a2.txt ;告知编译器当时源文件包括文件C:/a2.txt
……
END
12、 RN
语法格局:
称号 RN 表达式
RN伪指令用于给一个寄存器界说一个别号。选用这种办法能够便利程序员伤心该寄存器的功用。其间,称号为给寄存器界说的别号,表达式为寄存器的编码。
运用示例:
Temp RN R0 ;将R0界说一个别号Temp
13、 ROUT
语法格局:
{称号} ROUT
ROUT伪指令用于给一个部分变量界说效果规模。在程序中未运用该伪指令时,部分变量的效果规模为地点的AREA,而运用ROUT后,部分变量的作为规模为当时ROUT和下一个ROUT之间。
4.2汇编言语的查办格局
ARM(Thumb)汇编言语的查办格局为:
{标号} {指令或伪指令} {;注释}
在汇编言语程序设计中,每一条指令的助记符能够悉数用大写、或悉数用小写,但不必许在一条指令中大、小写混用。
一起,假如一条查办太长,可将该长查办分为若干行来书写,内行的结尾用“/”一共下一行与本行为同一条查办。
4.2.1在汇编言语程序中常用的符号
在汇编言语程序设计中,常常运用各种符号替代地址、变量和常量等,以添加程序的可读性。虽然符号的命名由编程者决议,但并不是恣意的,有必要遵从以下的约好:
— 符号委任巨细写,同名的大、小写符号会被编译器以为是两个不同的符号。
— 符号在其效果规模内有必要仅有。
— 自界说的符号名不能与体系的保留字相同。
— 符号名不该与指令或伪指令同名。
1、 程序中的变量
程序中的变量是指其值在程序的运转进程中能够改动的量。ARM(Thumb)汇编程序所支撑的变量稀有字变量、逻辑变量和字符串变量。
数字变量用于在程序的运转中保存数字值,但留意数字值的巨细不该超出数字变量所能一共的规模。
逻辑变量用于在程序的运转中保存逻辑值,逻辑值只要两种取值状况:真或假。
字符串变量用于在程序的运转中保存一个字符串,但留意字符串的长度不该超出字符串变量所能一共的规模。
在ARM(Thumb)汇编言语程序设计中,可运用GBLA、GBLL、GBLS伪指令声明大局变量,运用LCLA、LCLL、LCLS伪指令声明部分变量,并可运用SETA、SETL和SETS对其进行初始化。
2、 程序中的常量
程序中的常量是指其值在程序的运转进程中不能被改动的量。ARM(Thumb)汇编程序所支撑的常量稀有字常量、逻辑常量和字符串常量。
数字常量一般为32位的整数,当作为无符号数时,其取值规模为0~232-1,当作为有符号数时,其取值规模为-231~231-1。
逻辑常量只要两种取值状况:真或假。
字符串常量为一个固定的字符串,一般用于程序运转时的信息提示。
3、 程序中的变量代换
程序中的变量可经过代换操作获得一个常量。代换操作符为“$”。
假如在数字变量前面有一个代换操作符“$”,编译器会将该数字变量的值转换为十六进制的字符串,并将该十六进制的字符串代换“$”后的数字变量。
假如在逻辑变量前面有一个代换操作符“$”,编译器会将该逻辑变量代换为它的取值(真或假)。
假如在字符串变量前面有一个代换操作符“$”,编译器会将该字符串变量的值代换“$”后的字符串变量。
运用示例:
LCLS S1 ;界说部分字符串变量S1和S2
LCLS S2
S1 SETS “Test!”
S2 SETS “This is a $S1” ;字符串变量S2的值为“This is a Test!”
4.2.2汇编言语程序中的表达式和运算符
在汇编言语程序设计中,也常常运用各种表达式,表达式一般由变量、常量、运算符和括号构成。常用的表达式稀有字表达式、逻辑表达式和字符串表达式,其运算次第遵从如下的优先级:
— 优先级相同的双目运算符的运算次序为从左到右。
— 相邻的单目运算符的运算次序为从右到左,且单目运算符的优先级高于其他运算符。
— 括号运算符的优先级最高。
1、 数字表达式及运算符
数字表达式一般由数字常量、数字变量、数字运算符和括号构成。与数字表达式相关的运算符如下:
— “+”、“-”、“×”、“/” 及“MOD”算术运算符
以上的算术运算符别离代表加、减、乘、除和取余数运算。例如,以X和Y一共两个数字表达式,则:
X+Y 一共X与Y的和。
X-Y 一共X与Y的差。
X×Y 一共X与Y的乘积。
X/Y 一共X除以Y的商。
X:MOD:Y 一共X除以Y的余数。
— “ROL”、“ROR”、“SHL”及“SHR”移位运算符
以X和Y一共两个数字表达式,以上的移位运算符代表的运算如下:
X:ROL:Y 一共将X循环左移Y位。
X:ROR:Y 一共将X循环右移Y位。
X:SHL:Y 一共将X左移Y位。
X:SHR:Y 一共将X右移Y位。
— “AND”、“OR”、“NOT”及“EOR”按位逻辑运算符
以X和Y一共两个数字表达式,以上的按位逻辑运算符代表的运算如下:
X:AND:Y 一共将X和Y按位作逻辑与的操作。
X:OR:Y 一共将X和Y按位作逻辑或的操作。
:NOT:Y 一共将Y按位作逻辑非的操作。
X:EOR:Y 一共将X和Y按位作逻辑异或的操作。
2、 逻辑表达式及运算符
逻辑表达式一般由逻辑量、逻辑运算符和括号构成,其表达式的运算成果为真或假。与逻辑表达式相关的运算符如下:
— “=”、“>”、“<”、“>=”、“<= ”、“/=”、“ <>” 运算符
以X和Y一共两个逻辑表达式,以上的运算符代表的运算如下:
X = Y 一共X等于Y。
X > Y 一共X大于Y。
X < Y 一共X小于Y。
X >= Y 一共X大于等于Y。
X <= Y 一共X小于等于Y。
X /= Y 一共X不等于Y。
X <> Y 一共X不等于Y。
— “LAND”、“LOR”、“LNOT”及“LEOR”运算符
以X和Y一共两个逻辑表达式,以上的逻辑运算符代表的运算如下:
X:LAND:Y 一共将X和Y 作逻辑与的操作。
X:LOR:Y 一共将X和Y作逻辑或的操作。
:LNOT:Y 一共将Y作逻辑非的操作。
X:LEOR:Y 一共将X和Y作逻辑异或的操作。
3、 字符串表达式及运算符
字符串表达式一般由字符串常量、字符串变量、运算符和括号构成。编译器所支撑的字符串最大长度为512字节。常用的与字符串表达式相关的运算符如下:
— LEN运算符
LEN运算符回来字符串的长度(字符数),以X一共字符串表达式,其语法格局如下:
:LEN:X
— CHR运算符
CHR运算符将0~255之间的整数转换为一个字符,以M一共某一个整数,其语法格局如下:
:CHR:M
— STR运算符
STR运算符将将一个数字表达式或逻辑表达式转换为一个字符串。关于数字表达式,STR运算符将其转换为一个以十六进制组成的字符串;关于逻辑表达式,STR运算符将其转换为字符串T或F,其语法格局如下:
:STR:X
其间,X为一个数字表达式或逻辑表达式。
— LEFT运算符
LEFT运算符回来某个字符串左端的一个子串,其语法格局如下:
X:LEFT:Y
其间:X为源字符串,Y为一个整数,一共要回来的字符个数。
— RIGHT运算符
与LEFT运算符相对应,RIGHT运算符回来某个字符串右端的一个子串,其语法格局如下:
X:RIGHT:Y
其间:X为源字符串,Y为一个整数,一共要回来的字符个数。
— CC运算符
CC运算符用于将两个字符串衔接成一个字符串,其语法格局如下:
X:CC:Y
其间:X为源字符串1,Y为源字符串2,CC运算符将Y衔接到X的后边。
4、 与寄存器和程序计数器(PC)相关的表达式及运算符
常用的与寄存器和程序计数器(PC)相关的表达式及运算符如下:
— BASE运算符
BASE运算符回来依据寄存器的表达式中寄存器的编号,其语法格局如下:
:BASE:X
其间,X为与寄存器相关的表达式。
— INDEX运算符
INDEX运算符回来依据寄存器的表达式中相关于其基址寄存器的偏移量,其语法格局如下:
:INDEX:X
其间,X为与寄存器相关的表达式。
5、 其他常用运算符
—?运算符
?运算符回来某代码行所生成的可碑文代码的长度,例如:
?X
回来界说符号X的代码行所生成的可碑文代码的字节数。
— DEF运算符
DEF运算符判别是否界说某个符号,例如:
:DEF:X
假如符号X现已界说,则成果为真,不然为假。
4.3汇编言语的程序结构
4.3.1汇编言语的程序结构
4.3.1汇编言语的程序结构
在ARM(Thumb)汇编言语程序中,以程序段为单位安排代码。段是相对独立的指令或数据序列,具有特定的称号。段能够分为代码段和数据段,代码段的内容为碑文代码,数据段寄存代码运转时需求用到的数据。一个汇编程序至少应该有一个代码段,当程序较长时,能够分割为多个代码段和数据段,多个段在程序编译链接时终究构成一个可碑文的映象文件。
可碑文映象文件一般由以下几部分构成:
—一个或多个代码段,代码段的特点为只读。
— 零个或多个包括初始化数据的数据段,数据段的特点为可读写。
—零个或多个不包括初始化数据的数据段,数据段的特点为可读写。
链接器依据体系默许或用户设定的规矩,将各个段安排在存储器中的相应方位。因而源程序中段之间的相对方位与可碑文的映象文件中段的相对方位一般不会相同。
以下是一个汇编言语源程序的根本结构:
AREA Init,CODE,READONLY
ENTRY
Start
LDR R0,=0x3FF5000
LDR R1,0xFF
STR R1,[R0]
LDR R0,=0x3FF5008
LDR R1,0x01
STR R1,[R0]
┉┉
END
在汇编言语程序中,用AREA伪指令界说一个段,并阐明所界说段的相关特点,本例界说一个名为Init的代码段,特点为只读。ENTRY伪指令标识程序的进口点,接下来为指令序列,程序的结尾为END伪指令,该伪指令告知编译器源文件的完毕,每一个汇编程序段都有必要有一条END伪指令,指示代码段的完毕。
4.3.2汇编言语的子程序调用
在ARM汇编言语程序中,子程序的调用一般是经过BL指令来完结的。在程序中,运用指令:BL子程序名
即可完结子程序的调用。
该指令在碑文时完结如下操作:将子程序的回来地址寄存在衔接寄存器LR中,一起将程序计数器PC指向子程序的进口点,当子程序碑文完毕需求回来调用途时,只需求将寄存在LR中的回来地址从头劳动给程序计数器PC即可。在调用子程序的一起,也能够完结参数的传递和从子程序回来运算的成果,一般能够运用寄存器R0~R3完结。
以下是运用BL指令调用子程序的汇编言语源程序的根本结构:
AREA Init,CODE,READONLY
ENTRY
Start
LDR R0,=0x3FF5000
LDR R1,0xFF
STR R1,[R0]
LDR R0,=0x3FF5008
LDR R1,0x01
STR R1,[R0]
BL PRINT_TEXT
┉┉
PRINT_TEXT
┉┉
MOV PC,BL
┉┉
END
4.3.3汇编言语程序示例
以下是一个依据S3C4510B的串行通讯程序,关于S3C4510B的串行通讯的作业原理,能够参阅第六章的相关内容,在此仅向读者阐明一个完好汇编言语程序的根本结构:
;
; Institute of Automation,Chinese Academy of Sciences
;Description: This example shows the UART communication!
;Author: JuGuang,Lee
;Date:
;
UARTLCON0 EQU 0x3FFD000
UARTCONT0 EQU 0x3FFD004
UARTSTAT0 EQU 0x3FFD008
UTXBUF0 EQU 0x3FFD00C
UARTBRD0 EQU 0x3FFD014
AREA Init,CODE,READONLY
ENTRY
;
;LED Display
;
LDR R1,=0x3FF5000
LDR R0,=&ff
STR R0,[R1]
LDR R1,=0x3FF5008
LDR R0,=&ff
STR R0,[R1]
;*
;UART0 line control register
;*
LDR R1,=UARTLCON0
LDR R0,=0x03
STR R0,[R1]
;
;UART0 control regiser
;
LDR R1,=UARTCONT0
LDR R0,=0x9
STR R0,[R1]
;
;UART0 baud rate divisor regiser
;Baudrate=19200,对应于50MHz的体系作业频率
;*
LDR R1,=UARTBRD0
LDR R0,=0x500
STR R0,[R1]
;*
;Print the messages!
;*
LOOP
LDR R0,=Line1
BL PrintLine
LDR R0,=Line2
BL PrintLine
LDR R0,=Line3
BL PrintLine
LDR R0,=Line4
BL PrintLine
LDR R1,=0x7FFFFF
LOOP1
SUBS R1,R1,#1
BNE LOOP1
B LOOP
;*
;Print line
;*
PrintLine
MOV R4,LR
MOV R5,R0
Line
LDRB R1,[R5],#1
AND R0,R1,#&FF
TST R0,#&FF
MOVEQ PC,R4
BL PutByte
B Line
PutByte
LDR R3,=UARTSTAT0
LDR R2,[R3]
TST R2,#&40
BEQ PutByte
LDR R3,=UTXBUF0
STR R0,[R3]
MOV PC,LR
Line1 DCB &A,&D,””,0
Line2 DCB &A,&D,”Chinese Academy of Sciences,Institute of Automation,Complex System Lab.”,0
Line3 DCB &A,&D,” ARM Development Board Based on Samsung ARM S3C4510B.”,0
Line4 DCB &A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,0
END
4.3.4汇编言语与C/C++的混合编程
在运用体系的程序设计中,若一切的编程使命均用汇编言语来完结,其作业量是可想而知的,一起,不利于体系升级或运用软件移植,事实上,ARM体系结构支撑C/C+以及与汇编言语的混合编程,在一个完好的程序设计的中,除了初始化部分用汇编言语完结以外,其首要的编程使命一般都用C/C++ 完结。
汇编言语与C/C++的混合编程一般有以下几种办法:
- 在C/C++代码中嵌入汇编指令。
- 在汇编程序和C/C++的程序之间进行变量的互访。
- 汇编程序、C/C++程序间的彼此调用。
在以上的几种混合编程技术中,有必要恪守必定的调用规矩,如物理寄存器的运用、参数的传递等,这关于初学者来说,无疑显得过于烦琐。在实践的编程运用中,运用较多的办法是:程序的初始化部分用汇编言语完结,然后用C/C++完结首要的编程使命,程序在碑文时首要完结初始化进程,然后跳转到C/C++程序代码中,汇编程序和C/C++程序之间一般没有参数的传递,也没有频频的彼此调用,因而,整个程序的结构显得相对简略,简略了解。以下是一个这种结构程序的根本示例,该程序依据第五、六章所描绘的硬件渠道:
;*
; Institute of Automation, Chinese Academy of Sciences
;File Name: Init.s
;Description:
;Author: JuGuang,Lee
;Date:
;
IMPORT Main ;告知编译器该标号为一个外部标号
AREA Init,CODE,READONLY ;界说一个代码段
ENTRY ;界说程序的进口点
LDR R0,=0x3FF0000 ;初始化体系配置寄存器,具体内容可参阅第五、六章
LDR R1,=0xE7FFFF80
STR R1,[R0]
LDR SP,=0x3FE1000 ;初始化用户仓库,具体内容可参阅第五、六章
BL Main ;跳转到Main()函数处的C/C++代码碑文
END ;标识汇编程序的完毕
以上的程序段完结一些简略的初始化,然后跳转到Main()函数所标识的C/C++代码处碑文首要的使命,此处的Main仅为一个标号,也可运用其他称号,与C言语程序中的main()函数没有联系。
/*
* Institute of Automation, Chinese Academy of Sciences
* File Name: main.c
* Description: P0,P1 LED flash.
* Author: JuGuang,Lee
* Date:
/
void Main(void)
{
int i;
*((volatile unsigned long *) 0x3ff5000) = 0x0000000f;
while(1)
{
*((volatile unsigned long *) 0x3ff5008) = 0x00000001;
for(i=0; i<0x7fFFF; i++);
*((volatile unsigned long *) 0x3ff5008) = 0x00000002;
for(i=0; i<0x7FFFF; i++);
}
}
4.4本章末节
4.4本章末节
本章介绍了ARM程序设计的一些根本概念,以及在汇编言语程序设计中常见的伪指令、汇编言语的根本查办格局等,汇编言语程序的根本结构等,一起简略介绍了C/C++和汇编言语的混合编程等问题,这些问题均为程序设计中的根本问题,期望读者把握,留意本章最终的两个示例均与后边章节介绍的依据S3C4510B的硬件渠道有联系,读者能够参阅第五、六章的相关内容。