ARM汇编语言程序设计习题.ppt

上传人:tia****nde 文档编号:12805213 上传时间:2020-05-25 格式:PPT 页数:115 大小:437.50KB
返回 下载 相关 举报
ARM汇编语言程序设计习题.ppt_第1页
第1页 / 共115页
ARM汇编语言程序设计习题.ppt_第2页
第2页 / 共115页
ARM汇编语言程序设计习题.ppt_第3页
第3页 / 共115页
点击查看更多>>
资源描述
1,第5章ARM指令集和汇编语言程序,本章主要介绍以下内容:ARM汇编语言程序格式典型ARM汇编语言程序举例ARM汇编与C,C+混合编程,2,嵌入式系统开发中汇编语言设计的意义,汇编语言程序设计更能充分发挥处理器的硬件特性两个优势操作系统移植需要编写几百行底层硬件的汇编语言程序,这是C语言不可取代的。优化算法的时空效率,C语言的目标代码优化是编译器完成的,而汇编语言的目标代码优化是人工完成的。人是算法的创造者,也是编译器的设计者,人工优化比编译器质量高。弱点编程效率低,开发周期长,经济代价大。,3,5.1ARM汇编语言程序格式,两种ARM汇编语言格式ARM汇编语言程序格式主要有两种:基于ADS1.2集成开发环境的汇编器格式包括SDT在内,统称为ADS基于Linux的GNU汇编器格式在本章主要介绍基于ARM公司ADS集成开发环境汇编器格式的汇编语言程序设计。在后面将介绍基于GNU汇编器的ARM汇编语言程序编写方法。,4,预定义寄存器名及内部变量名,ARM汇编器中将几十个寄存器名称作为保留字预先给与了定义,这些预定义寄存器名都是大小写敏感的,它们都与具体的寄存器一一对应。参看下面的表格。,5,ARM公司ADS预定义的寄存器名一览表,6,ARM公司ADS预定义的寄存器名一览表(续),7,ARM汇编语言程序的部分内部变量名清单,8,ARM汇编语言程序的语句格式,ARM汇编语言程序的语句格式格式如下:symbolinstruction|directive|pseudo-instruction;comment对应的中文语句格式描述是:符号(标号)指令|指示符|伪指令;注释语句格式中,花括号括起来的部分表示可以省略;竖线分隔的字段表示可以替换。,9,ARM汇编语言程序中的符号,ARM汇编语句中的符号可以是指令地址或标号、变量、常量和局部标号,符号属性可以是程序相关的、寄存器相关的或者是绝对地址。,10,(一)符号命名和书写规则,符号的命名和书写有以下规则:符号命名可以使用大小写字母,数字和下划线。符号是大小写字母敏感的。除本地行号外,名称不能以数字开头。一个程序段中不能重名。符号在其作用范围内必须唯一。符号不能够与系统内部变量或者系统预定义的符号同名。例如:a1orR0、sp、cpsr、PCor.、VARor、CONFIG、CPU等等。,11,符号命名和书写规则(续),当程序中的符号与指令助记符或者指示符同名时,用双竖线将符号括起来。如|buffe_a|,这时双竖线并不是符号的组成部分。在ARM汇编语言程序中,所有符号必须在一行的最左边位置开始书写,即所谓的顶格书写,不允许包含空格或者制表符。符号的字符序列中不能大小写字母相混杂。,12,(二)常量,ARM汇编语言中使用到的常量可以是数字常量、字符常量、字符串常量和布尔常量。数字常量有以下3种表示方式:1)十进制数,如:535,246。2)十六进制数,如:0 x645,0 xff00。3)n进制数,格式为n_XXX,其中n表示n进制,从29,XXX是具体的数字。例如:8_3777,8_5237702,数字常量,13,字符常量,字符常量由一对单引号括起来,包括一个单字符或者标准C中的转义字符。例如:A,n。字符串常量由一对双引号以及由它括住的一组字符串组成,包括标准C中的转义字符。如果需要使用双引号或字符$,则必须用”和$代替。例如执行语句:strtwoSETS“Thisischaracterof”其编译结果是:字符串“Thisischaracterof”被赋值给strtwo变量。,14,$在汇编语句中的使用举例,GBLSadd4ffadd4ffSETS“ADDr4,r4,#0 xFF“;setupadd4ff$add4ff.00;invokeadd4ff;thisproduces;ADDr4,r4,#0 xFF00;elaboratesubstitutionGBLSs1GBLSs2GBLSfixupGBLAcountcountSETA14s1SETSa$b$count;s1nowhasvaluea$b0000000Es2SETSabcFixupSETS|xy$s2.z|;fixupnowhasvalue|xyabcz|C$code|MOVr4,#16;butthelabelhereisC$code,15,逻辑值常量,布尔常量TRUE和FALSE在表达式中写为:TRUE,FALSE。,16,(三)表达式,ARM汇编语言中的表达式由符号、数值、单目操作符、双目操作符以及括号组成。运算的优先级次序与标准C一样。,17,字符串表达式,字符串由字符串常量、字符串变量、操作符以及括号组成。最大长度为512字节,最短0个字节。字符串表达式的组成元素有:字符串常量、字符串变量、操作符等。字符串常量由包含在双引号内的一系列字符组成。当在字符串中包含美元符号$或者引号”时,用$表示一个$,用”表示一个”。字符串变量用指示符GBLS(全局字符串)或者LCLS(局部字符串)声明,用SETS赋值。取值范围与字符表达式相同。,18,ARM汇编语言中的字符串操作符,19,指令格式说明:LENX;返回X字符串长度STRM;将数字M转换成一个字符串XRIGHTN;返回X字符串右边长度为N的子串XLEFTN;返回X字符串左边长度为N的子串CHRM;返回数字M表示的单个字符XCCY;返回字符串X和Y连接的字符串,20,数字表达式,数字表达式由数字常量、数字变量、操作符和括号组成。数字表达式表示的是一个32位数的整数,其取值范围为0232-1;当作为有符号数时,其取值范围为-231231-1。汇编器对-n和232-n不做区别,汇编时对关系运算符采用无符号数方式处理,这就意味着0-1是FALSE。,21,逻辑表达式,逻辑表达式由逻辑常量、逻辑操作符、关系操作符以及括号组成。取值范围为FALSE和TRUE。,22,(四)地址标号,当符号代表地址时称为标号(Label)。以数字开头的标号其作用范围是当前段(没有使用ROUT指示符时),这种标号又称为局部标号(LocalLabel)。,23,三种类型标号,(1)PC相关标号(2)寄存器相关标号(3)绝对地址,24,PC相关标号,PC相关标号表示程序计数器加减一个数值常数后得到的地址值。常用来指明一个分支指令的目标地址,或者访问嵌入在代码段中的一个数据项。具体标记方法是:在汇编语言程序指令的前面写入标号,或者在一个数据指示符前面写入标号。通常用DCB或者DCD等指示符定义。,25,DCB,DCD指令格式:XDCBEXP1,EXP2如定义一个字节为单位的标号XSTRDCB“HELLOWORLD!”,0DCB0 x32,0 x34,0 x35XDCDEXP1,EXP2定义一个字为单位的标号LDRPC,RESETADDRRESETADDRDCDRESETRESET,26,寄存器相关标号,寄存器标号表示指定寄存器的值加减一个数值常数后得到的地址值。常常用于访问位于数据段中的数据。通常用MAP或者FIELD等指示符定义。格式:MAPEXPR,BASEREGLABLEFIELDEXPR如:MAP0 x00400000,R9COUNTFIELD4XFIELD8YFIELD8,27,绝对地址,绝对地址是一个32位的无符号数字常量,可寻址范围是0231-1。使用它可以直接寻址整个地址空间。,28,(五)段内标号和段外标号,ARM处理器的地址标号分为段内标号和段外标号。段内标号的地址值在汇编时确定,段外标号的地址值在连接时确定。,29,程序相对寻址和寄存器相对寻址,在程序段中标号代表其所在位置与段首地址的偏移量,根据程序计数器和偏移量计算地址称为程序相对寻址。在映像文件中定义的标号代表标号到映像首地址的偏移量。映像的首地址通常被赋予一个寄存器,根据该寄存器值与偏移量计算地址称为寄存器相对寻址。,30,(六)局部标号,ARM汇编语言的宏常常使用局部标号。局部标号提供分支指令在汇编程序的局部范围内进行跳转,主要用途是汇编子程序中的循环和条件编码。它是一个099之间的数字,后面可以有选择地附带一个符号名称。局部标号特别适用于宏。,31,局部标号(续1),使用ROUT指示符可以限制局部标号的范围。只能在该局部标号的范围引用局部标号。如果在该范围的上下两个方向都没有匹配的标号,汇编器将给出一个错误信号并停止汇编。局部标号语法格式如下:nroutname被引用的局部标号语法规则是:%F|BA|Tnroutname,32,局部标号(续2),n是局部标号的数字号。routname是当前局部范围的名称。%表示引用操作。F指示汇编器只向前搜索B指示汇编器只向后搜索A指示汇编器搜索宏的所有嵌套层次T指示汇编器搜索宏的当前层次如果F和B都没有指定,则汇编器首先向前搜索,再向后搜索。如果A和T都没有指定,汇编器搜索从宏的当前层次到宏的最高层次,比当前层次低的宏不再搜索。,33,ARM汇编语言程序编写规范,ARM汇编语言程序源代码中允许有空行,可以在汇编程序中加上一个空白行,来增加程序的可阅读性。此外需要注意的是:指令,指示符,伪指令前必须加空格或者Tab制表符,这就是说指令,指示符,伪指令不可以从行的最左边开始书写,即不能顶格书写。在ARM汇编语言程序中,所有标号必须在一行的最左边的位置开始书写,标号的后面不要加“:”。指令,指示符,寄存器名可以用小写字母也可以用大写字母来表示,但不能大小写字母相杂。,34,ARM汇编语言程序编写规范(续),当一行写不下时,可以用反斜线作为这一行最后的符号,然后另起一行接下去写,这样汇编器会将这两行代码看作一行代码。需要注意的是,如果在被引号括住的字符串中使用反斜线,则反斜线不能起到续行的作用。每行的长度限制一般在128255个字符串之间。分号;除非在字符串常量中出现,否则它的出现就表示着注释的开始,此注释直至行尾结束。可以将注释单独列为一行。所有注释被汇编器忽略。,35,汇编语句规则举例,AREAStartup,Code,READONLYSTR1SETS“ThisisanARMprocessor”SENTBLDRR3,=BLKADDRESSANDSR2,R2,#0X40FIELD4,AREARRoutineA,Code,READONLYMOVR10,#0XFF00SUB1MOVR6,#100SEC:MOVR8,#0X200FloopMovR2,#3BLoop,36,5.1.4ARM汇编语言指示符,ARM汇编语言程序指示符的英文原文是directive,ARM指示符相当于x86处理器汇编语言程序中的伪指令。ARM指示符语句与ARM机器指令不存在一一对应的关系,它指示汇编器在汇编目标代码时进行变量定义、存储单元分配等操作。ARM指示符大致可以分成6种类型,分别是:符号定义、数据定义、汇编控制、框架控制、信息报告和杂项。,37,AREA指示符用于定义一个代码段或者数据段。语法格式AREAsectionname,attr,attr.其中:sectionname为所定义的代码段或者数据段的名称。如果该名称是以数字开头的,则该名称必须用“”括起来,如1_datasec。还有一些代码段具有约定的名称,如.text表示C语言编译器产生的代码段或者是与C语言库相关的代码段。Attr是该代码段(或者程序段)的属性。在AREA指示符中,各属性间用逗号隔开。,(一)AREA指示符,38,AREA的属性,下面列举主要的属性:ALIGN=expression。默认的情况下,ELF的代码段和数据段是4字节对齐的。Expression可以取031的数值,相应的对齐方式为(2expression)字节对齐。如expression=3时为8字节对齐。ASSOC=section。指定与本段相关的ELF段。任何时候连接section段也必须包括sectionname段。CODE定义代码段。默认属性为READONLY。COMDEF定义一个通用的段。该段可以包含代码或者数据。在个源文件中,同名的COMDEF段必须相同。,39,AREA的属性(续),COMMON定义一个通用的段。该段不包含任何用户代码和数据,连接器将其初始化为0。各源文件中同名的COMMON段公用同样的内存单元,连接器为其分配合适的尺寸。DATA定义数据段。默认属性为READWRITE。NOINIT指定本数据段仅仅保留了内存单元,而没有将各初始值写入内存单元,或者将个内存单元值初始化为0。READONLY指定本段为只读,代码段的默认属性为READONLY。READWRITE指定本段为可读可写,数据段的默认属性为READWRITE。,40,AREA指示符举例,举例下面的指示符定义了一个代码段,代码段的名称为Mainpro,属性为READONLY。AREAMainpro,CODE,READONLY;codesegment,41,(二)ENTRY指示符,ENTRY指示符指定程序的入口点语法格式ENTRY使用说明一个程序(可以包含多个源文件)中至少要有一个ENTRY(可以有多个ENTRY),但一个源文件中最多只能有一个ENTRY(可以没有ENTRY)。示例AREAexample,CODE,READONLYENTRY;应用程序的入口点,42,(三)CODE16和CODE32指示符,CODE16指示符告诉汇编编译器后面的指令序列为16位的Thumb指令。CODE32指示符告诉汇编编译器后面的指令序列为32位的ARM指令。语法格式CODE16/CODE32使用说明当汇编源程序中同时包含ARM指令和Thumb指令时,使用CODE16指示符告诉汇编编译器后面的指令序列为16位的Thumb指令;使用CODE32指示符告诉汇编编译器后面的指令序列为32位的ARM指令。但是,CODE16指示符和CODE32指示符只是告诉编译器后面指令的类型,该指示符本身并不进行程序状态的切换。,43,CODE16/CODE32举例,在下面的例子中,程序先在ARM状态下执行,然后通过BX指令切换到Thumb状态,并跳转到相应的Thumb指令处执行。在Thumb程序入口处用CODE16指示符标识下面的指令为Thumb指令。参看下面的指令段:.AREAChangeState,CODE,READONLYCODE32;指示下面的指令为ARM指令LDRr0,=start+1BXr0;切换到Thumb,并跳转到start处执行CODE16;指示下面的指令为Thumb指令startMOVr1,#10,44,(四)EQU指示符,EQU指示符为数字常量、基于寄存器的值和程序中的标号(基于PC的值)定义一个字符名称。*是EQU的同义词。语法格式nameEQUexpr,type其中:expr为基于寄存器的地址值、程序中的标号、32位的地址常量或者32位的常量。name为EQU指示符为expr定义的字符名称。type当expr为32位常量时,可以使用type指示expr表示的数据的类型。,45,EQU(续),type有下面3种取值:CODE16CODE32DATA使用说明EQU指示符的作用类似于C语言中的#define,用于为一个常量定义字符名称。示例abcdEQU2;定义abcd符号的值为2abcdEQUlabel+16;定义abcd符号的值(label+16)addr1EQU0 xlC,CODE32;定义addr1符号值为;绝对地址值0 xlC,而且该处为ARM指令。,46,(五)ROUT指示符,ROUT指示符用于标记局部标号使用范围的边界。用法如下:NAMEROUT使用说明:NAME是指定作用范围的名称使用ROUT指示符用于规定局部标号的使用范围。避免无意之中用错局部标号导致的越界。如:SUB1ROUTSUB1ROUT,47,ROUT(续),ROUTAROUT;定义局部标号有效范围,名称为ROUTA3ROUTA;定义ROUTA中的局部标号3BEQ%4;若条件成立,则跳转到局部标号4的位置BEQ%3;若条件成立,则跳转到局部标号3的位置4ROUTA;定义ROUTA中的局部标号4OTHERPROGROUT;定义新的局部标号有效范围,48,(六)END指示符,END指示符告诉编译器已经到了源程序结尾。语法格式:END使用说明:每一个汇编源程序都包含END指示符,以告诉本源程序的结束。示例:AREAexampleCODE,READONLYEND,49,(七)ALIGN指示符,ALIGN指示符通过添加补丁字节使当前位置满足一定的对齐方式。语法格式ALIGNexpr,offset其中,expr为数字表达式,用于指定对齐方式。可能的取值为2的次幂,如1、2、4、8等。如果指示符中没有指定expr,则当前位置对齐到下一个字边界处。offset为数字表达式。表示当前位置到下一个地址之间按照:offset+n*expr的方式进行对齐,50,ALIGN(续1),使用说明下面的情况中,需要特定的地址对齐方式:Thumb的宏指令ADR要求地址是字对齐的,而Thumb代码中地址标号可能不是字对齐的。这时就要使用指示符ALIGN4使Thumb代码中的地址标号字对齐。由于有些ARM处理器的CACHE采用了其他对齐方式,如16字节的对齐方式,这时使用ALIGN指示符指定合适的对齐方式可以充分发挥该CACHE的性能优势。LDRD及STRD指令要求内存单元是8字节对齐的。这样在为这两个指令分配的内存单元前要使用ALIGN8实现8字节对齐方式。地址标号通常自身没有对齐要求。而在ARM代码中要求地址标号是字对齐的,在Thumb代码中要求字节对齐。这样需要使用合适的ALIGN指示符来调整对齐方式。,51,(八)DCB指示符,DCB用于在内存中分配一个字节单元或者一组字节单元,并用指定的EXPR对其进行初始化语法格式:labelDCBuexpr,exprlabel是可选项,expr为-128255的值或字符串。例:AREADCB_EXAMPLE,CODEDCB1ALIGN4,2DCB1Prompt1DCB“NOWtheinformationmanagementsystemisrunning!”,0,52,(九)MAP指示符,MAP用于将一个结构化内存的首地址映射到一个指定地址。是MAP的同义词语法格式:MAPexpr,base-register当只有expr时,expr表示此内存首地址的值。当包括base-register时内存首地址值为base-register+expr如MAP0 x00,r9;表示结构化内存首地址为r9+0timerFIELD4;表示一个数据域timer长度4字节,53,(十)FIELD指示符,FIELD用于定义一个结构化内存区域中的数据域。常与MAP联合使用,#是FIELD的同义词。语法格式:labelFIELDexprlabel是当前数据域的一个标号,expr是当前数据域的长度例:YEARFIELD4;数据域YEAR4字节MONTHFIELD2;数据域MONTH2字节DAYFIELD2;数据FIELD2字节,54,(十一)SPACE指示符,SPACE用于分配一个全0的内存区域。%是SPACE的同义词。语法格式:labelSPACEexprlabel是该内存域的标识,expr表示本内存空间的大小(以字节为单位)。例:data_timerSPACE0 x1000;定义一个4K字节的内存空间,初值为0ALIGN;恢复字对齐,55,课后练习P17711、请注释以下每条指令1)GBLSadd4ffadd4ffSETSADDr4,r4,#0 xFF“$add4ff.002)xyzROUT3xyzB%F3zxxROUT,56,AAPCS,2007年ARM公司正式推出了AAPCS标准ARMArchtectureProcedureCallStandardAAPCS是ATPCS的改进版目前,AAPCS和ATPCS都是可用的标准,57,AAPCS和ATPCS规范要点,寄存器的使用规则堆栈使用规则参数传递规则,58,ATPCS,ATPCS(ARM-ThumbProcedureCallStandard)规定了一些子程序间调用的基本规则,这些规则包括子程序调用过程中寄存器的使用规则,数据栈的使用规则,参数的传递规则。有了这些规则之后,单独编译的C语言程序就可以和汇编程序相互调用。使用ADS的C语言编译器编译的C语言子程序满足用户指定的ATPCS类型。而对于汇编语言来说,则需要用户来保证各个子程序满足ATPCS的要求。,59,寄存器的使用规则,子程序间通过寄存器R0R3来传递参数。这时,寄存器R0R3可记作a0a3。被调用的子程序在返回前无需恢复寄存器R0R3的内容。在子程序中,使用寄存器R4R11来保存局部变量。这时,寄存器R4R11可以记作v1v8。如果在子程序中使用了寄存器v1v8中的某些寄存器,则子程序进入时必须保存这些寄存器的值,在返回前必须恢复这些寄存器的值。在Thumb程序中,通常只能使用寄存器R4R7来保存局部变量。寄存器R12用作过程调用中间临时寄存器,记作IP。在子程序之间的连接代码段中常常有这种使用规则。,60,寄存器的使用规则(续),寄存器R13用作堆栈指针,记作SP。在子程序中寄存器R13不能用作其他用途。寄存器SP在进入子程序时的值和退出子程序时的值必须相等。寄存器R14称为连接寄存器,记作LR。它用于保存子程序的返回地址。如果在子程序中保存了返回地址,寄存器R14则可以用作其他用途。寄存器R15是程序计数器,记作PC。它不能用作其它用途。,61,堆栈使用规则,ATPCS规定堆栈为FD类型,即满递减堆栈,并且对堆栈的操作是8字节对齐。对于汇编程序来说,如果目标文件中包含了外部调用,则必须满足下列条件:(1)外部接口的堆栈必须是8字节对齐的。(2)在汇编程序中使用PRESERVE8伪指令告诉连接器,本汇编程序数据是8字节对齐的。,62,参数传递规则,如果系统不包含浮点运算的硬件部件,浮点参数会通过相应的规则转换成整数参数(若没有浮点参数,此步省略),然后依次将各字数据传送到寄存器R0R3中。如果参数多于4个,将剩余的字数据传送堆栈中,入栈的顺序与参数顺序相反,即最后一个字数据先入栈。在参数传递时,将所有参数看作是存放在连续的内存字单元的字数据。,63,子程序结果返回规则,子程序中结果返回的规则如下:结果为一个32位整数时,可以通过寄存器R0返回;结果为一个64位整数时,可以通过寄存器R0和Rl返回;结果为一个浮点数时,可以通过浮点运算部件的寄存器f0、d0或s0来返回;结果为复合型浮点数(如复数)时,可以通过寄存器f0fn或d0dn来返回;对于位数更多的结果,需要通过内存来传递。,64,(一)条件执行举例,求a和b两整数最大公约数的C程序While(a!=b)If(ab)a-=b;elseb-=a;,5.2典型ARM汇编语言程序举例,65,条件执行举例(续),如果用ARM汇编子程序来实现,就是求r1和r2两个寄存器中的两个整数的最大公约数。使用条件执行指令表示只有以下4句代码:gcdcmpr1,r2;cmp与subs功能类似subgtr1,r1,r2;如果r1r2执行此指令subltr2,r2,r1;如果r1r2则转gcd标号注:函数结束时r1=r2,都可以用作返回值。,66,(二)32位地址送入一个寄存器中,下面指令段中的load指令根据输入参数决定调用那个函数。具体做法是将函数的绝对地址通过LDR指令存入在r4寄存器中,由于是32的绝对地址,LDR会被解释成以下操作:将函数的绝对地址放入一个文字池(Literalpool,嵌入在代码中的用以存放常数的区域)。产生一条形如:LDRrnpc,#offsettoliteralpool的指令来将这个绝对地址读入到指定的寄存器中。类似地LDR指令也通过上述方法读入一个32位的绝对数。在下例中,LDR指令将32位绝对数0 x11552634读入到r0寄存器中,用作调用routine1或者routine2的参数。,67,32位地址送入一个寄存器中(续),;voidload(inti);voidroutine1(int1);voidroutine2(int2);AREALOAD,CODE,READONLYIMPORTroutine1IMPORTroutine2EXPORTloadloadstmfdr13!,r4,r14ldrr4,=routine1;首先将32位地址存放在附近的区域cmpsr0,#1ldrner4,=routine2ldrr0=0 x11552634;函数的第1个int参数bxr4ldmfdr13!,r4,r14bxr14,68,(三)从IRQ和FIQ异常处理程序返回,从IRQ和FIQ异常处理程序返回时,返回地址应该是LR-4。有三种不同的编程方法,分别列出如下:返回方式1INT_HANDLERSUBSPC,LR,#4;PC=R14-4,69,从IRQ和FIQ异常处理程序返回(2),返回方式2INT_HANDLERSUBR14,R14,#4;R14-=4MOVSPC,LR,70,从IRQ和FIQ异常处理程序返回(3),返回方式3INT_HANDLERSUBR14,R14,#4;R14=R144STMFDR13!,R0-R3,R14LDMFDR13!,R0-R3,R15,71,(四)循环结构,在ARM汇编中,没有专门的指令用来实现循环,一般通过跳转指令加条件码的形式来实现。可以采用比较指令CMP或者减法指令SUB等实现。参看下面的指令段:LOOPADDR4,R4,R0ADDR0,R0,#1CMPR0,R1BLELOOP;R0小于等于R1场合跳转在做完了两次加法操作后,比较R0,R1的值,影响条件标志。最后的条件跳转语句根据CMP指令执行的结果来决定是否进行循环。,72,(五)调用ARM汇编语言子程序,在ARM汇编语言中,子程序调用是通过BL指令完成的。BL指令的语法格式如下:BLsubname其中,subname是调用的子程序的名称。BL指令完成两个操作:将子程序的返回地址放在LR寄存器中,同时将PC寄存器值设置成目标子程序的第一条指令地址。在子程序返回时可以通过将LR寄存器的值传送到PC寄存器中来实现。子程序调用时通常使用寄存器R0R3来传递参数和返回结果。,73,调用汇编子程序举例,子程序DOADD完成加法运算,操作数放在R0和R1寄存器中,结果放在R0中。AREAEXAMPLE2,CODE,READONLYENTRYstartMOVr0,#10;R0设置输入参数MOVr1,#3;R1设置输入参数BLdoadd;调用子程序doadddoaddADDr0,r0,r1;子程序实体MOVpc,lr;从子程序中返回END,74,(六)高效率程序分支,设有C语言程序Intc_switch(inti)switch(i)case0:returnmethod0();case1:returnmethod1():case2:returnmethod2():case3:returnmethod3():case4:returnmethod4():default:returnmethod();,可有汇编与之功能等价Arm_swithcmpr0,#5addltpc,pc,r0,lsl#2BmethodBmethod0Bmethod1Bmethod2Bmethod3Bmethod4,75,(七)数据块复制示范程序,本程序将数据从源数据区复制到目标数据区复制时,以8个字为单位进行。对于最后所剩不足8个字的数据,以字为单位进行复制,这时程序跳转到copywords处执行。在进行以8个字为单位的数据复制时,保存了所用的8个工作寄存器。程序清单如下面所示。,76,数据块复制示范程序(1),AREABlock,CODE,READONLY;设置段名称及属性numEQU20;设置将要复制的字数ENTRY;标识程序入口点StartLDRr0,=src;r0寄存器指向源数据区srcLDRr1,=dst;r1寄存器指向目标数据区dst,77,数据块复制示范程序(2),MOVr2,#num;r2指定将要复制的字数MOVsp,#0 x400;设置数据栈指针(r13),用于保存工作寄存器数值blockcopy;进行以8个字为单位的数据复制MOVSr3,r2,LSR#3;需要进行的以8个字为单位的复制次数BEQcopywords;对于剩下不足8个字的数据,跳转到copywords,以字为单位复制STMFDsp!,r4r11;保存工作寄存器,压栈octcopyLDMIAr0!,r4-r11;从源数据区读取8个字的数据,放到8个寄存器中,并更新目标数据区指针r0STMIAr1!,r4-r11;将这8个字数据写入到目标数据区中,并更新目标数据区指针r1SUBSr3,r3,#1;将块复制次数减1BNEoctcopy;循环,直到完成以8个字为单位的块复制LDMFDsp!,r4-r11;恢复工作寄存器值,出栈,78,数据块复制示范程序(3),copywordsANDSr2,r2,#7;剩下不足8个字的数据的字数BEQstop;数据复制完成wordcopyLDRr3,r0,#4;从源数据区读取1个字的数据,放到r3寄存器中,并更新目标数据区指针r0,后索引偏移STRr3,r1,#4;将这r3中数据写入到目标数据区中,并更新目标数据区指针r1,后索引偏移,79,数据块复制示范程序(4),SUBSr2,r2,#l;将字数减1BNEwordcopy;循环,直到完成以字为单位的数据复制STOPAREABlockData,DATA,READWRITE;定义数据区BlockDatasrcDCD1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4dstDCD0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0;定义源数据区src及目标数据区dstEND;结束汇编,80,课后练习1、请指出以下程序中的错误2、将以面的C分支程序改为功能相同的汇编程序,AREARRoutineA,Code,READONLYMOVR10,#0XFF00SUB1MOVR6,#100SEC:MOVR8,#0X200FloopMovR2,#3BLoop,Intc_switch(inti)switch(i)case0:returnmethod0();case1:returnmethod1():case2:returnmethod2():default:returnmethod();,81,5.3ARM汇编、C和C+混合编程,在C/C+程序中如果必须使用汇编指令来完成某些操作,可以采用两种方法:1.采用内嵌汇编,即在C/C+源程序中嵌入一块汇编代码,让这块汇编代码来完成特定的操作;2.将必须使用汇编代码的部分独立编写成在一个文件中,形成一个子程序,C/C+程序可以调用这些汇编程序来完成特定的操作。,82,5.3.1内嵌汇编,内嵌汇编(inlineassembly)的语法如下:_asm指令;指令/*注释*/指令,83,内嵌汇编的指令用法,内嵌在C或者C+程序中的ARM汇编指令与普通(ADS)格式的ARM汇编指令有所不同。其主要原因在于C/C+编译器在编译C/C+源代码的同时要兼顾处理内嵌汇编程序,因此CPU的内部寄存器资源使用有额外约束。以下讲解内嵌ARM汇编指令的用法。,84,ARM内嵌汇编程序的操作数,操作数内嵌汇编指令中作为操作数的寄存器和常量可以是表达式。这些表达式可以是char,short或int类型,而且这些表达式都是作为无符号数进行操作。若需要带符号,用户需要自己处理与符号有关的操作。编译器将会计算这些表达式的值,并为其分配寄存器。,85,ARM内嵌汇编程序的物理寄存器,物理寄存器内嵌汇编程序中使用物理寄存器有以下限制。不能直接向PC寄存器赋值,程序跳转只能使用B或BL指令实现不要使用过于复杂的C表达式,因为将会需要较多的物理寄存器,这将导致与其他指令中用到的物理寄存器产生使用冲突。编译器可能会使用R12或R13存放编译的中间结果,在计算表达式的值时可能会将寄存器R0R3,R12和R14用于子程序调用。因此在内嵌的汇编指令中不要将这些寄存器同时指定为指令中的物理寄存器。通常内嵌的汇编指令中不要指定物理寄存器,因为这可能会影响编译器分配寄存器,进而影响代码的效率。,86,其他内嵌汇编程序的编写注意点,常量:在内嵌汇编指令中,常量前面的“#”可以省略。指令展开:内嵌汇编指令中,如果包含常量操作数,该指令可能被内嵌汇编器展开成几条指令。标号:C程序中的标号可以被内嵌的汇编指令使用,但是只有指令B可以使用C程序中的标号,而指令BL则不能使用。内存单元的分配:所有的内存分配均由C编译器完成,分配的内存单元通过变量供内嵌汇编器使用。内嵌汇编器不支持内嵌程序中用于内存分配的伪指令。,87,内嵌汇编程序中的SWI和BL指令,SWI和BL指令:在两个指令使用到内嵌汇编中,除了正常的操作数域外,还必须增加以下3个可选的寄存器列表:用于输入参数的寄存器列表。用于存储返回结果的寄存器列表。用于表示那些寄存器将有可能会被修改的寄存器列表。,88,内嵌汇编代码举例字符串复制(1),#includevoidstr_cpy(constchar*src,char*dst)intch;_asmloop:/普通ARM汇编代码中的标号后面不能跟冒号。C程序中/的标号可以被内嵌的汇编指令使用。ARM内嵌汇编代码中/只有B指令可以使用C的标号,而BL指令不能够使用C代码/的标号。C程序的标号后面跟冒号,由Goto语句转向标号处。LDRBch,src,#1STRBch,dst,#1CMPch,#0BNEloop,89,内嵌汇编代码举例字符串复制(2),intmain(void)constchar*a=Helloworld!n;charb20;/doinlineassemblyroutinestr_cpy(a,b)_asmMOVR0,a/将串a的串首地址送到R0寄存器MOVR1,b/将串b的串首地址送到R1寄存器BLstr_cpy,R0,R1/调用C函数str_cpy()printf(Originalstring:%sn,a);printf(Copiedstring:%sn,b);/半主机方式显示复制前后的两个串return(0);,90,5.3.2C/C+程序与ARM汇编语言程序的相互调用,C/C+程序与汇编程序相互调用时,应遵守相应的ATPCS,主要有五种调用。ARM汇编子程序调用C语言子程序ARM汇编子程序调用C+语言子程序C语言程序调用ARM汇编语言子程序C+语言程序调用ARM汇编语言子程序C语言程序调用C+语言子程序下面就每种具体情况逐一举例说明。,91,C/C+程序调用ARM汇编程序要点,设计汇编程序必须遵守ATPCS,保证程序调用时参数的正确传递。在汇编程序中使用EXPORT指示符声明本程序可以被别的程序调用。在C语言程序中使用extern关键词声明该汇编程序可以被调用,C+语言程序使用extern“C”来声明该汇编程序可以被调用。,92,例1C程序调用ARM汇编子程序,/*main_0522.csemihostingoutputmode*/#includeexternintasmfile(intarg1,intarg2,intarg3);intmain(void)inta1=1,a2=2,a3=4;printf(ExampleofCProgramcallingAssemblyprogram!n);printf(%d+%d+%d)*600=%dn,a1,a2,a3,asmfile(a1,a2,a3);,93,C程序调用ARM汇编子程序(续),;ASM_0522.sEXPORTasmfileAREAMy_pro,CODE,READONLYasmfileSTMFDSP!,R4-R6,R8,R7addr0,r0,r1addr0,r0,r2movr4,#600mulr3,r0,r4movr0,r3LDMFDSP!,R4-R6,R8,R7movpc,lrEND,94,例2ARM汇编程序调用C子程序,本案例程序比较两个IP地址的大小,a1a4存放IP地址1的值(按照ATPCS传递参数),b1b4存放IP地址2的值(通过栈传递参数),如果IP地址1的值大于IP地址2的值则返回1,如果IP地址1的值小于IP地址2的值则返回-1,如果两者相等则返回零。IP地址1取值:192,168,1,152,IP地址2取值:172,0,0,151,95,例2ARM汇编程序调用C子程序(续),/*C代码部分*/#includeexternintfunction(void);/*声明function是外部函数*/intcompare_ip(inta1,inta2,inta3,inta4,intb1,intb2,intb3,intb4)if(a1!=b1)returna1b1?1:-1;if(a2!=b2)returna2b2?1:-1;if(a3!=b3)returna3b3?1:-1;if(a4!=b4)returna4b4?1:-1;return0;intmain()printf(Thisisaexampleofsemihostingn);printf(resultis%dn,function();,96,例2ARM汇编调用C子程序(续2),AREAFUNCTION,CODE,READONLY;ARM汇编子程序IMPORTcompare_ipEXPORTfunctionfunctionSTMFDr13!,r0-r3,r14;保存寄存器到栈区MOVr3,#0 x97;存入IP地址2的4个数,0 x97=151MOVr2,#0;存入0MOVr1,#0;存入0MOVr0,#0 xac;存入0 xac=172STMIAr13,r0-r3;R0-R3覆盖存入栈区的R0-R3位置MOVr3,#0 x98;存入IP地址1的4个数,0 x98=152MOVr2,#1;存入1MOVr1,#0 xa8;存入0 xa8=168MOVr0,#0 xc0;存入0 xc0=192BLcompare_ip;调用C语言函数进行IP值比较ADDr13,r13,#0 x10;栈指针上移4个字(元素)LDRpc,r13,#4;将保存的r14值加载到PC,而后r13加4END;本段汇编代码的操作图解参看下一页,97,例2ARM汇编调用C子程序(续3),ARM汇编语言子程序Function的栈区操作图解,98,例3ARM汇编程序调用C+子程序,/这是C+调用ARM汇编的范例程序/文件名:try_C+_call_S/main函数位于这个.CPP文件externCvoidasmfunc(void);intmain(void)asmfunc();,99,例3ARM汇编调用C+子程序(续),;这个ARM汇编语言程序被main函数调用;该函数又调用ARM汇编函数cppfunc;AREAmypro,CODE,READONLYIMPORTcppfuncEXPORTasmfuncasmfuncSTMFDsp!,lrBLcppfuncLDMFDsp!,pcEND,100,例3ARM汇编调用C+子程序(续2),#include#includeusingnamespacestd;constdoublePI=3.1415926;classpointpublic:point()x=0;y=0;point(doublea,doubleb)x=a;y=b;point(point,101,例3ARM汇编调用C+子程序(续3),doubleGetX()returnx;doubleGetY()returny;point,102,例3ARM汇编调用C+子程序(续4),this-x=length*cos(a+degree*PI/180);this-y=length*sin(a+degree*PI/180);return*this;private:doublex,y;,103,例3ARM汇编调用C+子程序(续5),externCintcppfunc()pointa(1.5,1.9);pointb(2.0,0.0);pointc(1.0,1.0);a.Move(b);c.Rotate(90);coutais(a.GetX(),a.GetY()endl;coutbis(b.GetX(),b.GetY()endl;coutcis(c.GetX(),c.GetY()endl;coutaandbsretangleareaisa.GetArea(b)endl;coutbandcsretangleareaisb.GetArea(c)endl;coutaandcsretangleareaisa.GetArea(c)cacppfunc(s);/*调用C+函数cppfunc(),初始化s*/,106,例4C语言程序调用C+子程序(续1),intmain()structSs;f(,107,例4C语言程序调用C+子程序(续2),/CPP.CPP函数清单classS/hasnobaseclassesorvirtualfunctionspublic:charca12;S()ca0=0;externCvoidcppfunc(S*p)/DefinitionoftheC+functiontobecalledfromC./ThefunctioniswritteninC+,onlythelinkageisCchar*tmp=world!;char*source=p-ca;while(*source!=0)/扫描过原先在c程序中的赋值source+;*source+=;/将结束符改为空格while(*source+=*tmp+);/copyworldtop-ca,108,ARM汇编(子)程序的相互调用,基本要点:如果一个ARM汇编语言程序文件含有调用外部汇编语言程序文件中子程序(函数)的指令,则需要用IMPORT指示符来指明将要调用的子程序名称。如果本汇编语言程序文件中的某个子程序(函数),需要被外部的ARM汇编语言程序文件中的语句调用,则需要用EXPORT指示符来指明将要被调用的子程序(函数)名称。被执行的汇编子程序在运行前,要注意将寄存器组压入栈区,返回时要注意将栈区保存的工作现场恢复到处理器的寄存器组。,109,5.3.45级流水线的互锁问题,ARM9指令流水线有5级。五个流水线阶段分别是:取指、译码、ALU、LS1、LS2。流水线的增加增加了系统的吞吐量,但也引起了流水线互锁(pipelineinterlock),即一条指令需要前一条指令的执行结果,而这时结果还没有出来,那么处理器就会等待。,110,9级流水线互锁现象举例,互锁使得指令的执行周期增加,下面举例说明:LDRr1,r2,#8ADDr0,r0,r1MOVr2,#0,111,案例9级流水线互锁现象的图解,112,案例9级流水线互锁现象的解决,如果将指令顺序该为:LDRr1,r2,#8MOVr2,#0ADDr0,r0,r1这样的指令顺序执行由于没有产生流水线互锁,执行上述指令只需要3个周期,即一个时钟周期完成一条指令。在保持结果正确无误的前提下,比修改之前减少了一个时钟周期。,113,5.3.5GNU格式的ARM汇编语言程序设计,GNU格式ARM汇编语言程序主要用于基于ARM硬件平台和Linux操作系统的嵌入式开发。GNU提供的相关汇编器是arm-elf-as(简称为as),连接器是arm-elf-ld(简称为ld)。GNU格式ARM汇编程序与ADS格式ARM汇编程序有较大的区别。,114,基于ARM处理器的GNU汇编语句格式如下:,:注释其中的第1个字段label是标号,第2个字段instructionordircetive是指令或者GNU的汇编指示符。与ADS格式的汇编语言程序不同,在GNU格式汇编语言程序的源代码行里不需要缩进指令和指示符。限于篇幅,更多的教学内容请大家阅读教材5.4节完成。,115,课后练习1、请说明在C语言、C+和汇编语言中分别什么指令进行外部函数声明?2、在ADS编译系统中,C语言中内嵌汇编的语法格式是怎样的?3、为什么在C语言内嵌汇编指令对物理寄存器的使用要进行限制?4、在汇编子程序调用中使用哪几个寄存器进行参数传递?使用哪几个寄存器进行参数返回?如果需要传递的参数多于四个将如何进行参数传递?,
展开阅读全文
相关资源
相关搜索

当前位置:首页 > 图纸专区 > 课件教案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!