《ARM汇编语言程序设计基础.ppt》由会员分享,可在线阅读,更多相关《ARM汇编语言程序设计基础.ppt(68页珍藏版)》请在金锄头文库上搜索。
1、XUPT 嵌入式系统嵌入式系统 原理与原理与应用应用第四章第四章 ARM汇编语言程序设计基础汇编语言程序设计基础 目目 录录v4.1 ARM汇编语言的程序结构汇编语言的程序结构 v4.2 ARM汇编语言程序设计汇编语言程序设计 v4.3 C与汇编混合编程与汇编混合编程v本章小结本章小结 24.1 ARM汇编语言的程序结构汇编语言的程序结构v本章通过一个完整的本章通过一个完整的ARM汇编例子入手,给出了汇编例子入手,给出了ARM汇编程序的基本汇编程序的基本框架,并详细介绍了编写汇编程序常用的汇编器伪指令,具备了这些基框架,并详细介绍了编写汇编程序常用的汇编器伪指令,具备了这些基础知识,学生就能自
2、己动手编写汇编程序。础知识,学生就能自己动手编写汇编程序。v4.1.1 一个简单的一个简单的ARM汇编程序例子汇编程序例子v4.1.2 汇编器伪指令汇编器伪指令v4.1.3 汇编语言的规范汇编语言的规范4.1.1 一个简单的一个简单的ARM汇编程序例子汇编程序例子4v一段完整的一段完整的ARM汇编语言程序,由若干个段组成,段可以分为代码段汇编语言程序,由若干个段组成,段可以分为代码段和数据段,代码段的内容为执行代码,数据段存放代码运行时需要用到和数据段,代码段的内容为执行代码,数据段存放代码运行时需要用到的变量。的变量。v程序框架可抽象如下:程序框架可抽象如下: AREA代码段名字代码段名字,
3、CODE,READONLYENTRYCODE32;添加用户代码添加用户代码AREA数据段名字数据段名字,DATA,READWRITE;添加用户数据添加用户数据ENDv指令和汇编器伪指令的比较指令和汇编器伪指令的比较 指令语句:在汇编后能产生目标代码的语句,指令语句:在汇编后能产生目标代码的语句,CPU可以执行并能完可以执行并能完成一定的功能,例如成一定的功能,例如MOV,ADD等;等; 汇编器伪指令:在汇编后不产生目标代码的语句,仅在汇编过程中汇编器伪指令:在汇编后不产生目标代码的语句,仅在汇编过程中告诉汇编器如何汇编。汇编器伪指令的作用包括:定义数据、分配存储告诉汇编器如何汇编。汇编器伪指令
4、的作用包括:定义数据、分配存储区、定义段、定义宏、定义子程序等。一旦汇编结束,它们的使命就完区、定义段、定义宏、定义子程序等。一旦汇编结束,它们的使命就完成了。成了。4.1.2 汇编器伪指令汇编器伪指令v在在 ARM 的汇编程序中,有如下几种汇编器伪指令:符号定义伪指令,的汇编程序中,有如下几种汇编器伪指令:符号定义伪指令,数据定义伪指令,段定义伪指令,模块控制伪指令,汇编控制伪指令,数据定义伪指令,段定义伪指令,模块控制伪指令,汇编控制伪指令,宏处理伪指令等。宏处理伪指令等。1.段定义相关伪指令段定义相关伪指令AREA语法格式:语法格式: AREA段名段名 属性属性1, 属性属性2, 程序程
5、序4-1中使用如下语句定义段:中使用如下语句定义段:AREA MAIN, CODE, READONLY;定义代码段,名字为定义代码段,名字为MAINAREA NUM,DATA, READWRITE;定义数据段,名字为定义数据段,名字为NUMvAREA伪指令用于定义一个代码段或数据段。其中,段名若以数字开头,伪指令用于定义一个代码段或数据段。其中,段名若以数字开头,则该段名需用则该段名需用 “ | ” 括起来,如括起来,如 |1_data| 。属性字段表示该代码段。属性字段表示该代码段(或数据段)的相关属性,例如:(或数据段)的相关属性,例如:CODE(定义代码段),(定义代码段),DATA(定
6、(定义数据段),义数据段),READONLY(只读),(只读),READWRITE(读写)。多个(读写)。多个属性用逗号分隔。属性用逗号分隔。v一个汇编程序至少应该有一个代码段,由具体的设计需求,也可由多个一个汇编程序至少应该有一个代码段,由具体的设计需求,也可由多个代码段和数据段组成,多个段在程序汇编链接时最终形成一个可执行的代码段和数据段组成,多个段在程序汇编链接时最终形成一个可执行的映象文件。可执行映象文件通常由以下几部分构成:映象文件。可执行映象文件通常由以下几部分构成: 一个或多个代码段,代码段的属性为只读。一个或多个代码段,代码段的属性为只读。 零个或多个包含初始化数据的数据段,数
7、据段的属性为可读写。零个或多个包含初始化数据的数据段,数据段的属性为可读写。 零个或多个不包含初始化数据的数据段,数据段的属性为可读写。零个或多个不包含初始化数据的数据段,数据段的属性为可读写。vENTRYENTRY用于指示程序的入口,其后紧跟着第一条可执行语句。用于指示程序的入口,其后紧跟着第一条可执行语句。vCODE16/CODE32CODE16用于通知汇编器,本语句后面的指令序列为用于通知汇编器,本语句后面的指令序列为16位的位的Thumb指令。指令。CODE32用于通知汇编器,本语句后面的指令序列为用于通知汇编器,本语句后面的指令序列为32位的位的ARM指令。指令。vENDEND用于指
8、示程序的结束,每一个汇编源程序都必须以用于指示程序的结束,每一个汇编源程序都必须以END语句结语句结束,以通知汇编器结束汇编。束,以通知汇编器结束汇编。2. 数据定义伪指令数据定义伪指令DCB(Define ? Byte)语法格式(方括号内的内容为可选项):语法格式(方括号内的内容为可选项):标号标号 DCB 表达式表达式 , 表达式表达式 vDCB用于在内存中分配一片连续的字节单元,用于在内存中分配一片连续的字节单元,并用表达式进行初始化。每个表达式可以是并用表达式进行初始化。每个表达式可以是数字或字符串,数字的范围在数字或字符串,数字的范围在0255内,也内,也可以为算术表达式,例如:可以
9、为算术表达式,例如:StrDCB “Hello World!” num_bDCB2+3, 3*5v字符串只能用字符串只能用DCB定义。定义。 DCW(Define ? Word)语法格式:标号语法格式:标号 DCW 表达式表达式 , 表达式表达式vDCW用于在内存中分配一片连续的半字单元,并用于在内存中分配一片连续的半字单元,并用指定的表达式进行初始化。这些分配的内容是用指定的表达式进行初始化。这些分配的内容是半字对齐的。其中表达式可以为程序标号或者数半字对齐的。其中表达式可以为程序标号或者数字表达式。例如:字表达式。例如:num_w DCW 0x1234,0x5678DCD(Define ?
10、 Double word)语法格式:标号语法格式:标号 DCD 表达式表达式 , 表达式表达式 vDCD用于在内存中分配一片连续的字单元,并用用于在内存中分配一片连续的字单元,并用指定的表达式进行初始化。这些分配的内容是字指定的表达式进行初始化。这些分配的内容是字对齐的。其中表达式可以为程序标号或者数字表对齐的。其中表达式可以为程序标号或者数字表达式。例如:达式。例如:num_d DCD -5,0x90abcdefSPACE语法格式:标号语法格式:标号SPACE表达式表达式 vSPACE用于分配一片连续的存储区域并初始化为用于分配一片连续的存储区域并初始化为0。其中,表达式为。其中,表达式为要
11、分配的字节数。例如:要分配的字节数。例如:data SPACE 1024 ;分配分配1024个字节空间并初始化为个字节空间并初始化为0LTORGvLTORG用于声明一个文字池,用来存放常量,特别是不符合用于声明一个文字池,用来存放常量,特别是不符合8位位图位位图数据标准的常数。其使用情景及实例见本章的数据标准的常数。其使用情景及实例见本章的4.2.1节。节。v3. 宏处理伪指令宏处理伪指令MACRO和和ENDM语法格式:语法格式:宏名宏名MACRO 参数参数1, 参数参数2宏体宏体ENDMvMACRO用于定义一个宏,引用宏时需使用宏名,并传递实参。用于定义一个宏,引用宏时需使用宏名,并传递实参
12、。ENDM用于结束宏定义。用于结束宏定义。v例如:以下定义一个宏,实现参数例如:以下定义一个宏,实现参数x与参数与参数y相加再减去参数相加再减去参数z,结果放,结果放在参数在参数x中,三个参数均为存储器操作数。中,三个参数均为存储器操作数。addmMACRO x, y, zLDR R2,=xLDR R1,R2LDR R3,=yLDR R4,=zADD R1,R1, R3SUB R1,R1, R4STR R1,R2ENDM4.1.3 汇编语言的规范汇编语言的规范1.语句的格式语句的格式ARM(Thumb)汇编语言的语句格式为:)汇编语言的语句格式为:标号标号 指令或伪指令指令或伪指令;注释注释v
13、语句书写时需遵循以下规则:语句书写时需遵循以下规则: 所有标号必须在一行的顶格书写,其后不要添加所有标号必须在一行的顶格书写,其后不要添加“:”号;号; 所有的指令均不能顶格写;所有的指令均不能顶格写; 如果同一行有两条汇编语句,需要在它们之间以如果同一行有两条汇编语句,需要在它们之间以“;”隔开;如果一隔开;如果一条语句要分多行显示,需要使用条语句要分多行显示,需要使用“”放在分隔处;放在分隔处; 每一条指令的助记符可以全部用大写、或全部用小写,但不能在一每一条指令的助记符可以全部用大写、或全部用小写,但不能在一条指令中大、小写混用。条指令中大、小写混用。 注释使用分号注释使用分号“;” ,
14、不要在语句中间添加注释。,不要在语句中间添加注释。2.标号标号v在汇编语言程序设计中,可以使用各种标号表示指令或数据的地址,以在汇编语言程序设计中,可以使用各种标号表示指令或数据的地址,以增加程序的可读性。例如程序增加程序的可读性。例如程序4-1中的:中的:loop1LDRR3,R0, #4 BNEloop1 ;如果如果R1不为零,则转向不为零,则转向loop1处处v以下为标号命名规则:以下为标号命名规则: 标号不应与指令或伪指令同名标号不应与指令或伪指令同名 标号在其作用范围内必须唯一。标号在其作用范围内必须唯一。 标号区分大小写,同名的大、小写标号被视为两个不同的标号。标号区分大小写,同名
15、的大、小写标号被视为两个不同的标号。 自定义的不能与系统保留字相同。自定义的不能与系统保留字相同。3.常量和变量常量和变量v程序中的程序中的常量常量是指其值在程序的运行过程中不能被改变的量,是指其值在程序的运行过程中不能被改变的量,变量变量是是指其值在程序的运行过程中可以改变的量。指其值在程序的运行过程中可以改变的量。vARM汇编程序支持逻辑量、数字和字符串。汇编程序支持逻辑量、数字和字符串。 数字一般为数字一般为32位的整数,无符号数取值范围为位的整数,无符号数取值范围为0232-1,带符号数,带符号数取值范围为取值范围为-231231-1。 逻辑量只有两种取值:真或假。逻辑量只有两种取值:
16、真或假。 字符串用于在程序的运行中保存一个字符串,其长度不应超出字符串变字符串用于在程序的运行中保存一个字符串,其长度不应超出字符串变量所能表示的范围。量所能表示的范围。4.2 ARM汇编语言程序设计汇编语言程序设计 v程序设计的三种基本结构是顺序结构、分支结构和循环结构,以解决不程序设计的三种基本结构是顺序结构、分支结构和循环结构,以解决不同的问题。在同的问题。在ARM汇编语言中采用跳转语句来实现分支与循环结构。汇编语言中采用跳转语句来实现分支与循环结构。v在进行程序设计时,首先分析该程序的流程,绘制流程图,再根据流程在进行程序设计时,首先分析该程序的流程,绘制流程图,再根据流程图编写代码。
17、图编写代码。v4.2.1 顺序程序顺序程序v4.2.2 分支程序分支程序v4.2.3 循环程序循环程序v4.2.4 子程序子程序v4.2.5 基于查表法的程序设计基于查表法的程序设计4.2.1 顺序程序顺序程序顺序程序是一种最简单的程序结构,它按照语句编写的顺序从上往下执顺序程序是一种最简单的程序结构,它按照语句编写的顺序从上往下执行,直到最后退出程序。行,直到最后退出程序。v例例4-2:计算:计算100-50,结果存放到,结果存放到R1寄存器中。寄存器中。 v在在ADS中建立工程,编写以上程序,并进行汇编链接,使用中建立工程,编写以上程序,并进行汇编链接,使用AXD进行进行调试。程序调试结果
18、:寄存器调试。程序调试结果:寄存器R1的内容为的内容为0x32,即为十进制的,即为十进制的50,程序运行结果正确。程序运行结果正确。v缺省文字池缺省文字池vARM规定:可由一个规定:可由一个8位的常数经过循环右移偶数位(位的常数经过循环右移偶数位(0,2,4,30)得到的数据,称为)得到的数据,称为8位位图数据。只有位位图数据。只有8位位图数据可以直位位图数据可以直接采用立即数寻址方式来获取,其余的数据只能使用文字池的方式,通接采用立即数寻址方式来获取,其余的数据只能使用文字池的方式,通过存储器访问指令来加载,下面我们改变数据的大小,使得所访问立即过存储器访问指令来加载,下面我们改变数据的大小
19、,使得所访问立即数数不再是数数不再是8位位图数据。位位图数据。 v例例4-3:计算:计算0x123456-0x123,结果存放到,结果存放到R0寄存器中。寄存器中。v程序如下:程序如下:v汇编提示错误信息为:汇编提示错误信息为:v文字池是一片用于存放常量的地方,文字池是一片用于存放常量的地方,LDR指令寻址文字池,可以访问任指令寻址文字池,可以访问任意的意的32位数据。在汇编过程中,汇编器会默认的在每个段的末尾开辟位数据。在汇编过程中,汇编器会默认的在每个段的末尾开辟一个文字池,下面我们采用缺省文字池的方式来重写例一个文字池,下面我们采用缺省文字池的方式来重写例4-3:v例例4-3-1:采用缺
20、省文字池的方式实现例:采用缺省文字池的方式实现例4-3。v调试信息:调试信息:v地址地址0x8000存放代码段中的第一条可执行语句存放代码段中的第一条可执行语句LDR R1, =0x123456,地址,地址0x8018存放代码段在的最后一条可执行语句存放代码段在的最后一条可执行语句SWI 0X123456,代码段的地址范围在,代码段的地址范围在0x80000x801b之间。之间。实线框住的部分表示汇编器自动生成的文字池。该文字池就在紧跟着代实线框住的部分表示汇编器自动生成的文字池。该文字池就在紧跟着代码段的位置,存放着三个码段的位置,存放着三个LDR访问的数据:访问的数据:0x123456,0
21、x123,0x20026。v自定义文字池自定义文字池v文字池的使用限制是:文字池的使用限制是:LDR指令的寻址范围是前后指令的寻址范围是前后4KB,不能使文字,不能使文字池与访问它的池与访问它的LDR指令之间的距离超过这个范围。如果用户程序比较指令之间的距离超过这个范围。如果用户程序比较大,则可能使整个程序段超过大,则可能使整个程序段超过4KB的范围,这样汇编器在程序段的末的范围,这样汇编器在程序段的末尾开辟的缺省文字池与访问它的尾开辟的缺省文字池与访问它的LDR指令之间的距离就有可能超出范指令之间的距离就有可能超出范围,围,LDR指令就不能正确加载数据了。指令就不能正确加载数据了。v在缺省文
22、字池的例子程序中添加伪代码在缺省文字池的例子程序中添加伪代码SPACE 4096,开辟,开辟4096个个字节的空间(字节的空间(4096B=4KB),则代码段大小超过),则代码段大小超过4KB。 v以上代码汇编提示错误信息如图以上代码汇编提示错误信息如图4-7所示,汇编器提示:缺省文字池距所示,汇编器提示:缺省文字池距离访问它的离访问它的LDR太远,建议使用太远,建议使用LTORG伪指令来创建自定义文字池。伪指令来创建自定义文字池。在例在例4-3-2中,使用中,使用LTORG伪指令在程序中创建自定义文字池。伪指令在程序中创建自定义文字池。v例例4-3-2:采用自定义文字池的方式实现例:采用自定
23、义文字池的方式实现例4-3。v采用采用LTORG伪指令自定义文字池,该程序汇编链接成功。一般伪指令自定义文字池,该程序汇编链接成功。一般LTORG伪指令放在跳转指令伪指令放在跳转指令B之后,使得在数据段中开辟的文字池中之后,使得在数据段中开辟的文字池中存放的数据不被当做指令执行。虚线框住的部分为自定义文字池,实线存放的数据不被当做指令执行。虚线框住的部分为自定义文字池,实线框住的部分为缺省文字池。框住的部分为缺省文字池。4.2.2 分支程序分支程序vARM汇编分支程序采用转移指令汇编分支程序采用转移指令B或条件转移指令或条件转移指令BX来实现。来实现。 v例例4-4:给定符号函数:给定符号函数
24、: ,假定,假定x是是-5。 4.2.3 循环程序循环程序1.计数控制循环计数控制循环v已知循环次数,可以用计数器控制循环的次数来进行程序的设计。已知循环次数,可以用计数器控制循环的次数来进行程序的设计。v例例4-5:计算:计算1+2+3+100的结果,并存放到的结果,并存放到sum单元。单元。2.条件控制循环条件控制循环v有些情况无法确定循环的次数,这时只有些情况无法确定循环的次数,这时只能通过循环结束的条件来判断是否结束能通过循环结束的条件来判断是否结束循环。循环。v例例4-6:计算:计算1+2+3+n,当计,当计算结果大于算结果大于10000时停止循环,在数时停止循环,在数据段中定义据段
25、中定义sum和和n两个变量,并将加两个变量,并将加法和存放到法和存放到sum单元,将最后一个加数单元,将最后一个加数存放到存放到n单元。单元。4.2.4 子程序子程序v在在ARM汇编中,通过汇编中,通过BL指令可以指令可以实现子程序的调用,在跳转时实现子程序的调用,在跳转时LR寄寄存器自动保存紧跟着存器自动保存紧跟着BL指令的下一指令的下一条指令的地址。在子程序的结束处,条指令的地址。在子程序的结束处,可以通过可以通过MOV PC,LR返回主程序返回主程序中。中。 v子程序的定义一般放在程序结束返子程序的定义一般放在程序结束返回编译器调试环境的语句之后,回编译器调试环境的语句之后,END之前,
26、这样使得子程序的定义之前,这样使得子程序的定义代码参与编译,但不会在定义的位代码参与编译,但不会在定义的位置执行。只有调用该子程序才会执置执行。只有调用该子程序才会执行。行。 v主程序在调用子程序时,往往需要向子程序传递一些参数,同样,子主程序在调用子程序时,往往需要向子程序传递一些参数,同样,子程序在运行完毕后也可能要把结果传回给调用程序。程序在运行完毕后也可能要把结果传回给调用程序。 1.寄存器传递参数寄存器传递参数2.存储区域传递参数存储区域传递参数3.堆栈传递参数堆栈传递参数v例例4-7:用子程序实现内存块拷:用子程序实现内存块拷贝,将字符串从源位置拷到目贝,将字符串从源位置拷到目的位
27、置。的位置。v分析:源串为分析:源串为“I am an ARM program!”,目的串区,目的串区域初始化为域初始化为“0”,将源串内容,将源串内容依次取出,放入相应的寄存器,依次取出,放入相应的寄存器,再写入目的串的对应位置。要再写入目的串的对应位置。要判断串的结束点,判断串的结束点,C语言中自动语言中自动在串尾位置添加一个在串尾位置添加一个“0”,其其ASCII码即为码即为00H,但汇编,但汇编语言不能默认添加一个结束字语言不能默认添加一个结束字符,这里,我们仿照符,这里,我们仿照C语言,在语言,在串结束位置添加串结束位置添加00H。 v例例4-8:将以:将以src开始的数字串中的前开
28、始的数字串中的前n个数字相加,其和存入个数字相加,其和存入dst起始起始的单元中。的单元中。4.2.5 基于查表法的程序设计基于查表法的程序设计v查表法是查表法是ARM汇编中的一种常见的编程技巧,当程序中涉及较多的数汇编中的一种常见的编程技巧,当程序中涉及较多的数据,子程序等,可以通过地址对它们进行访问。通常有以下几种方法来据,子程序等,可以通过地址对它们进行访问。通常有以下几种方法来装载地址:装载地址:(1)通过)通过ADR或或ADRL伪指令来装载地址,伪指令来装载地址,ADR适用于小范围的地适用于小范围的地址读取,址读取,ADRL适合中等范围的地址读取;例如:适合中等范围的地址读取;例如:
29、ADR R0, table(2)通过)通过LDR伪指令来装载地址,伪指令来装载地址,LDR适用于大范围的地址读取。例适用于大范围的地址读取。例如完成上述功能也可写做:如完成上述功能也可写做:LDR R0, =tablev例子例子4-9:用查表法查平方表,在数据段中定义:用查表法查平方表,在数据段中定义n,在,在s_tab中查中查n的的平方值,存入平方值,存入result单元。单元。v例例4-10:用查表法实现程序,在数据段中定义变量:用查表法实现程序,在数据段中定义变量m和和x,y,result,其中由,其中由m的值分别选择不同的计算公式来计算的值分别选择不同的计算公式来计算result, 4
30、.3 C与汇编混合编程与汇编混合编程vC语言与汇编语言分别有各自的优缺点。采用语言与汇编语言分别有各自的优缺点。采用C语言进行算法设计和程语言进行算法设计和程序编写时,是面向过程的,整个流程清晰,实现起来较容易,且提供很序编写时,是面向过程的,整个流程清晰,实现起来较容易,且提供很多接口函数。多接口函数。C语言的由于编译时生成的可执行文件大,因此实时性难语言的由于编译时生成的可执行文件大,因此实时性难以控制,也不能对硬件进行直接的操作。采用汇编语言进行程序设计时,以控制,也不能对硬件进行直接的操作。采用汇编语言进行程序设计时,比比C语言的流程更不容易理解和设计,但汇编语言汇编生成的可执行文语言
31、的流程更不容易理解和设计,但汇编语言汇编生成的可执行文件小,执行速度快,实时性高,且能对内存,外设端口进行直接的读写件小,执行速度快,实时性高,且能对内存,外设端口进行直接的读写操作。如果将二者结合起来进行开发,能简化编程难度,保证实时性,操作。如果将二者结合起来进行开发,能简化编程难度,保证实时性,并能对硬件进行访问。并能对硬件进行访问。4.3.1 C语言内嵌汇编代码语言内嵌汇编代码4.3.2 C与汇编文件变量互访与汇编文件变量互访4.3.3 ARM过程调用标准过程调用标准APCS4.3.4 C程序调用汇编子程序程序调用汇编子程序4.3.5 汇编程序调用汇编程序调用C函数函数4.3.1 C语
32、言内嵌汇编代码语言内嵌汇编代码vADS支持支持C语言内嵌汇编,其编译器语言内嵌汇编,其编译器armcc,armcpp,armasm能能相互调用,实现此类程序的编译。相互调用,实现此类程序的编译。v在在ADS中,支持下列语法的中,支持下列语法的C内嵌汇编语句:内嵌汇编语句:_asm/asm前面使用的是双下划线前面使用的是双下划线汇编语句汇编语句1 ; 汇编语句汇编语句2汇编语句汇编语句3vC内嵌汇编能实现某些内嵌汇编能实现某些C语言不便实现的功能,支持语言不便实现的功能,支持ARM和和Thumb指指令,但不能直接引用令,但不能直接引用C中定义的变量,并且在数据交换的时候必须遵守中定义的变量,并且
33、在数据交换的时候必须遵守ATPCS (ARM-Thumb Procedure Call Standard)规定。通)规定。通常应注意以下几点:常应注意以下几点:1.不能直接向不能直接向PC赋值,要实现跳转,仅能使用跳转类指令中的赋值,要实现跳转,仅能使用跳转类指令中的B和和BL;2.在内嵌汇编中,一般不要直接指定物理寄存器,而要让编译器自动在内嵌汇编中,一般不要直接指定物理寄存器,而要让编译器自动分配;分配;3.如果一定要使用物理寄存器,要注意以下原则:如果一定要使用物理寄存器,要注意以下原则:R12与与R13常用于常用于存放中间编译结果,不能使用;存放中间编译结果,不能使用;R0R3在过程调
34、用中用于传递参数,在过程调用中用于传递参数,不能使用;不能使用;R14用于过程调用的返回,也不能使用;用于过程调用的返回,也不能使用;4.内嵌汇编语句可以通过指针方式访问内嵌汇编语句可以通过指针方式访问C中的变量;但内嵌汇编中定中的变量;但内嵌汇编中定义的变量不能在义的变量不能在C中被访问。中被访问。v例例4-11:用:用C内嵌汇编实现程序,定义一个由数字内嵌汇编实现程序,定义一个由数字0-9、标点符号和小、标点符号和小写字母组成的串写字母组成的串src,完成将,完成将src中各字符都拷贝到目的字符串中各字符都拷贝到目的字符串dst,并,并且将且将dst中的小写字母都变成大写字母,其余符号不变
35、。中的小写字母都变成大写字母,其余符号不变。4.3.2 C与汇编文件变量互访与汇编文件变量互访v当一个工程中既有汇编文件又有当一个工程中既有汇编文件又有C文件时,两个文件有时需要进行变量文件时,两个文件有时需要进行变量互访。在汇编文件中访问互访。在汇编文件中访问C文件中的变量,可以通过文件中的变量,可以通过LDR伪指令读取该伪指令读取该C变量的地址,并通过地址来访问该变量。如果这个变量在变量的地址,并通过地址来访问该变量。如果这个变量在C文件中被文件中被声明为全局变量,则它是可以被其它文件访问的,否则不行。声明为全局变量,则它是可以被其它文件访问的,否则不行。v在汇编文件中访问在汇编文件中访问
36、C文件中的变量文件中的变量 v在在C文件中访问汇编文件中的变量文件中访问汇编文件中的变量 v汇编文件访问汇编文件访问C文件中的变量其具体方法:文件中的变量其具体方法:(1)在)在C文件中定义全局变量文件中定义全局变量var;(2)在汇编程序中用)在汇编程序中用IMPORT引入变量引入变量var;(3)使用伪指令)使用伪指令LDR获取变量获取变量var变量的地址;变量的地址;(4)使用指令)使用指令LDR获取变量获取变量var的值。的值。v在在C文件中访问汇编文件中的变量:文件中访问汇编文件中的变量:(1)在汇编文件中,用伪指令)在汇编文件中,用伪指令“GLOBAL”定义全局变量,变量名必须是定
37、义全局变量,变量名必须是以下划线以下划线“_”为起始的字母字符串;为起始的字母字符串;(2)C文件中用文件中用extern引入该变量;引入该变量;(3)在)在C文件中用变量名访问该变量。文件中用变量名访问该变量。v例例4-12:在:在C文件中定义变量文件中定义变量c_var,初始值为,初始值为1,在汇编文件中改变,在汇编文件中改变它,输出改变前后它,输出改变前后c_var的值;在汇编文件中定义变量的值;在汇编文件中定义变量_asm_var,初始值为初始值为2,在,在C文件中改变它,输出改变前后文件中改变它,输出改变前后_asm_var的值。的值。v; var.s文件的内容文件的内容4.3.3
38、ARM过程调用标准过程调用标准APCSvARM过程调用标准过程调用标准ATPCS(ARM-Thumb Procedure Call Standard)提供了一种)提供了一种C程序与汇编程序互访的规范,规定了两者间程序与汇编程序互访的规范,规定了两者间子程序调用的基本规则,包括:子程序调用过程中寄存器的使用规则、子程序调用的基本规则,包括:子程序调用过程中寄存器的使用规则、堆栈使用规则以及参数传递规则。有了这些规则,单独编译的堆栈使用规则以及参数传递规则。有了这些规则,单独编译的C语言程语言程序可以和汇编程序之间能实现链接和相互调用。序可以和汇编程序之间能实现链接和相互调用。v参数传递规则参数传
39、递规则当参数个数不超过当参数个数不超过4个时,使用寄存器个时,使用寄存器R0R3来传递参数;当参数超来传递参数;当参数超过过4个时,将剩余的参数使用堆栈传递。在传递参数时,将所有参数看个时,将剩余的参数使用堆栈传递。在传递参数时,将所有参数看作是存放在连续的内存字单元的字数据。入栈的顺序与参数传递的顺序作是存放在连续的内存字单元的字数据。入栈的顺序与参数传递的顺序相反,即最后一个字数据先入栈。相反,即最后一个字数据先入栈。v子程序结果返回规则子程序结果返回规则1.结果为一个结果为一个32位整数时,通过位整数时,通过R0返回;返回;2.结果为一个结果为一个64位整数时,通过位整数时,通过R0和和
40、R1返回;返回;3.对于位数更多的结果,需要通过内存来传递。对于位数更多的结果,需要通过内存来传递。寄存器寄存器APCSAPCS命名命名寄存器使用规则寄存器使用规则R0R0R3R3a0a0a3a3子程序间通过寄存器子程序间通过寄存器R0R0R3R3来传递参数。被调用的来传递参数。被调用的子程序在返回前无需恢复寄存器子程序在返回前无需恢复寄存器R0R0R3R3的内容。的内容。R4R4R11R11v1v1v8v8在子程序中使用寄存器在子程序中使用寄存器R4R4R11R11来保存局部变量。如来保存局部变量。如果在子程序中使用了寄存器果在子程序中使用了寄存器v1v1v8v8中的某些寄存器,中的某些寄存
41、器,则子程序进入时必须保存这些寄存器的值,在返回则子程序进入时必须保存这些寄存器的值,在返回前必须恢复。在前必须恢复。在ThumbThumb程序中,通常只能使用寄存器程序中,通常只能使用寄存器R4R4R7R7来保存局部变量。来保存局部变量。R12R12R13R13SPSP堆栈指针,在子程序中,堆栈指针,在子程序中,R13R13不能用作其他用途,在不能用作其他用途,在进入子程序和退出时,其值必须相等。进入子程序和退出时,其值必须相等。R14R14LRLR连接寄存器,用于保存子程序的返回地址。最好不连接寄存器,用于保存子程序的返回地址。最好不要用作其他用途。要用作其他用途。R15R15PCPC程序
42、计数器,不能用于其他用途。程序计数器,不能用于其他用途。 寄存器的使用规则寄存器的使用规则4.3.4 C程序调用汇编子程序程序调用汇编子程序vC语言调用汇编程序子程序,需要以下步骤:语言调用汇编程序子程序,需要以下步骤:(1)在汇编文件中,用该子程序名作为汇编代码段的段名,在汇编程序)在汇编文件中,用该子程序名作为汇编代码段的段名,在汇编程序中用伪指令中用伪指令EXPORT导出子程序名,并在代码段结尾处使用导出子程序名,并在代码段结尾处使用MOV PC,LR返回;返回;(2)在)在C文件中用关键字文件中用关键字extern声明该汇编子程序的函数原型,并将定声明该汇编子程序的函数原型,并将定义好
43、形参,则义好形参,则C程序就能调用该函数;程序就能调用该函数;(3)如果在函数调用时需传递参数,参数)如果在函数调用时需传递参数,参数1,2,3,4默认使用寄存器默认使用寄存器R0R3传递,如果参数个数多于传递,如果参数个数多于4个,则使用堆栈传递;个,则使用堆栈传递;(4)如果函数有返回值,则默认用)如果函数有返回值,则默认用R0返回。返回。v例例4-13:在汇编文件中定义子程序:在汇编文件中定义子程序add3,能实现三个数的相加并返,能实现三个数的相加并返回和值,在回和值,在C文件中调用函数文件中调用函数add3,实现三个数的相加并输出结果。,实现三个数的相加并输出结果。4.3.5 汇编程
44、序调用汇编程序调用C函数函数vC语言调用汇编程序子程序,需要以下步骤:语言调用汇编程序子程序,需要以下步骤:(1)在汇编文件中,用伪指令)在汇编文件中,用伪指令IMPORT将要调用的将要调用的C函数引用;函数引用;(2)如果在函数调用时需传递参数,参数)如果在函数调用时需传递参数,参数1,2,3,4默认使用寄存器默认使用寄存器R0R3传递,如果参数个数多于传递,如果参数个数多于4个,则使用堆栈传递;个,则使用堆栈传递;(3)如果函数有返回值,则默认用)如果函数有返回值,则默认用R0返回。返回。v例例4-14:在:在C文件中定义函数文件中定义函数sum,实现三个数的相加并返回和。在,实现三个数的
45、相加并返回和。在汇编文件中调用汇编文件中调用sum子程序。子程序。本章小结本章小结v本章通过一个完整的本章通过一个完整的ARM汇编例子入手,给出了汇编例子入手,给出了ARM汇编程序的基本汇编程序的基本框架,并详细介绍了编写汇编程序常用的汇编器伪指令,具备了这些基框架,并详细介绍了编写汇编程序常用的汇编器伪指令,具备了这些基础知识,学生就能自己动手编写汇编程序。础知识,学生就能自己动手编写汇编程序。v4.2节详细的介绍了顺序程序、分支程序、循环程序和子程序的编写。节详细的介绍了顺序程序、分支程序、循环程序和子程序的编写。在顺序程序中,通过对例子的修改,引出在顺序程序中,通过对例子的修改,引出8位
46、位图数的概念,并给出缺位位图数的概念,并给出缺省文字池和自定义文字池的使用方法。在循环程序中,分别给出计数控省文字池和自定义文字池的使用方法。在循环程序中,分别给出计数控制循环和条件控制循环的例子,在子程序中分别讨论了通过寄存器,存制循环和条件控制循环的例子,在子程序中分别讨论了通过寄存器,存储器和堆栈传递参数的方法。在本节最后给出基于查表法的程序设计方储器和堆栈传递参数的方法。在本节最后给出基于查表法的程序设计方法。法。v4.3节讨论了节讨论了C与与ARM汇编混合编程问题,其中包括汇编混合编程问题,其中包括C语言内嵌汇编代码、语言内嵌汇编代码、C与汇编文件变量互访。与汇编文件变量互访。C与汇
47、编之间进行函数(子程序)相互调用时,需与汇编之间进行函数(子程序)相互调用时,需要遵循要遵循ARM过程调用标准过程调用标准APCS,介绍了,介绍了APCS标准后,分别通过两小节标准后,分别通过两小节讲述了讲述了C程序调用汇编子程序和汇编程序调用程序调用汇编子程序和汇编程序调用C函数的方法。函数的方法。v在学习本章时,读者可以使用在学习本章时,读者可以使用ADS调试书中的例子程序,并参照附录中给出调试书中的例子程序,并参照附录中给出的的ADS使用方法,查看程序的运行结果。动手实践能取得更好的学习效果。使用方法,查看程序的运行结果。动手实践能取得更好的学习效果。v习题习题v1、请写出带有一个代码段
48、和一个数据段的、请写出带有一个代码段和一个数据段的ARM汇编程序框架。汇编程序框架。v2、画图说明下列数据定义伪指令所分配的存储空间及初始化的数值。、画图说明下列数据定义伪指令所分配的存储空间及初始化的数值。v(1) BYTE_VAR DCB “ABCD” ,-5,0x78, 9*10v(2) WORD_VAR DCW -5, 0x12, 0x5678v(3) DWORD_VAR DCD -5, 0x12, 0x567890abv3、在、在ADS中编写一段汇编程序,添加题中编写一段汇编程序,添加题2中的数据定义伪指令,验证中的数据定义伪指令,验证题题2是否正确完成,并查看是否正确完成,并查看B
49、YTE_VAR,WORD_VAR和和DWORD_VAR是否连续分配空间,如果没有,请问为什么会出现这是否连续分配空间,如果没有,请问为什么会出现这种情况呢?种情况呢?v4、语句、语句MOV R1,#0x123456能通过编译吗?如果不行,请进行能通过编译吗?如果不行,请进行修改,使之能通过编译。修改,使之能通过编译。5. 什么是8位位图数?什么情况下可以使用缺省文字池?什么情况下需要自定义文字池?6. 编写程序,给定符号函数:,定义数据段,存放变量x和y,假定x是-9,函数值计算出来存放到y单元。7、编写程序,定义字变量buf,存放10个带符号数,比较10个数的大小,将最小数存放到min单元,最大数存放到max单元。8、编写程序,定义立方表tab,存放010的立方值,定义变量x,y,假定x=6,查tab表得出x,存放到y单元。9、在C程序中内嵌ARM汇编,实现1+2+100,并在C程序中将结果输出到屏幕上。10、在汇编中实现子程序max:两个数比较大小,返回大数,并在C程序中调用。11、在C程序中实现函数max,两个数比较大小,返回大数,并在汇编程序中调用。vTHE END