您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 其它行业文档 > 第3章-ARM汇编语言程序设计-GNU-汇编
ADS/SDTIDE开发环境:它由ARM公司开发,使用了CodeWarrior公司的编译器;集成了GNU开发工具的IDE开发环境:它由GNU的汇编器as、交叉编译器gcc、和链接器ld等组成。汇编语言都具有一些相同的基本特征。①一条指令一行。②使用标号(label)给内存单元提供名称,从第1列开始书写。③指令必须从第2列或能区分标号的地方开始书写。④注释跟在指定的注释字符后面(ARM使用的是“;”/”@”),一直书写到行尾。ARM汇编语言基本的的语句格式如下:{symbol}{instruction|directive|pseudo-instruction}{;comment}符号指令、伪指令或伪操作[;/@注释]①符号由大小写字母、数字及下画线组成,符号不能用数字开头。②符号区分大小写,同名的大、小写符号会被编译器认为是两个不同的符号。③符号在其作用范围内必须唯一。④自定义的符号名不能与系统的保留字相同。⑤符号名不应与指令或伪指令同名。伪操作(Directive)是ARM汇编语言程序里的一些特殊的指令助记符,其作用主要是为完成汇编程序做各种准备工作,对源程序运行汇编程序处理,而不是在计算机运行期间由处理器执行。不同的编译程序所使用的伪操作有所不同。常量编译控制伪操作程序代码控制伪操作宏及条件编译伪指令其他伪指令GNUARM汇编伪操作Linux汇编行结构任何汇编行都是如下结构:[:][}@comment[:][}@注释LinuxARM汇编中,任何以冒号结尾的标识符都被认为是一个标号,而不一定非要在一行的开始。【例1】定义一个add”的函数,返回两个参数的和。.section.text,“x”.globaladd@givethesymboladdexternallinkageadd:ADDr0,r0,r1@addinputargumentsMOVpc,lr@returnfromsubroutine@endofprogramLinux汇编程序中的标号Linux汇编程序中的标号标号只能由a~z,A~Z,0~9,“.”,”_”等字符组成。当标号为0~9的数字时为局部标号,局部标号可以重复出现,使用方法如下:标号f:在引用的地方向前的标号标号b:在引用的地方向后的标号【例2】使用局部符号的例子,一段循环程序1:subsr0,r0,#1@每次循环使r0=r0-1bne1f@跳转到1标号去执行局部标号代表它所在的地址,因此也可以当作变量或者函数来使用。Linux汇编程序中的分段(1).section伪操作用户可以通过.section伪操作来自定义一个段,格式如下:.sectionsection_name[,flags[,%type[,flag_specific_arguments]]]每一个段以段名为开始,以下一个段名或者文件结尾为结束。这些段都有缺省的标志(flags),连接器可以识别这些标志。(与armasm中的AREA相同)。下面是ELF格式允许的段标志a允许段,w可写段x:执行段例子:.section.mysection@自定义数据段,段名为“.mysection”预定义段.text、.data、.bss语法格式.text{subsection}.data{subsection}@初始化数据.bss{subsection}作用.text、.data和.bss将汇编系统预定义的段名编译到相应的代码段、数据段和bss段。注意:源程序中.bss段应该在.text之前。说明bss段通常是指用来存放程序中未初始化的全局变量的一块内存区域数据段通常是指用来存放程序中已初始化的全局变量的一块内存区域举例.section.datainitializedatahere.section.bssuninitializeddatahere.section.text.global_start_start:instructioncodegoeshere.end语法格式.end作用表明源文件的结束,如果该标号之后还有代码,不会被编译到执行文件中.include语法格式.includefilename作用可以将指定的文件在使用位置处展开,一般是头文件.incbin语法格式.incbinfile[,skip[,count]]作用可以将原封不动的一个二进制文件编译到当前文件中。其中,skip表明是从文件开始跳过skip个字节开始读取文件,count是读取的字数.if、.else/.endif语法格式.if条件表达式代码段1.else代码段2.endif.macro、.exitm和.endm语法格式.macro宏名参数名列表@伪操作.macro定义一个宏宏体.endm@.endm表示宏结束说明如果宏使用参数,那么在宏体中使用该参数时添加前缀“\”。宏定义时的参数还可以使用默认值,可以使用.exitm伪指令来退出宏举例.macroSHIFTLEFTa,b.if\b0MOV\a,\a,ASR#-\b.exitm.endifMOV\a,\a,LSL#\b.endm.string/.asciz/.ascii语法格式.string/.asciz/.ascii表达式{,表达式}...作用.string/.asciz/.ascii定义多个字符串。注意:ascii伪操作定义的字符串需要自动添加结尾字符'\0'举例.stringabcd,hello.equ、.set语法格式.equ(.set)常量名,表达式作用.equ和.set用于为程序中标号定义名称举例.equabc3@让abc=3.global/.globl语法格式.global/.globlsymbol作用.global和.globl用来定义一个全局的符号.extern语法格式.externlabel作用.extern用于声明一个外部标号.ltorg、.pool语法格式.ltorg/.pool作用.ltorg和.pool用于声明一个数据缓冲池的开始,它可以分配很大的空间伪指令是ARM处理器支持的汇编语言程序里的特殊助记符,它不在处理器运行期间由机器执行,只是在汇编时将被合适的机器指令代替成ARM或Thumb指令,从而实现真正的指令操作。ARM汇编语言伪指令如表3-2所示。在汇编编译器编译源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错误,编译失败。ADR伪指令中的地址是基于PC或寄存器的,当ADR伪指令中的地址是基于PC时,该地址与ADR伪指令必须在同一个代码段中。地址表达式expr的取值范围如下:当地址值是字节对齐时,其取指范围为−255B~255B;当地址值是字对齐时,其取指范围为−1020B~1020B。ARM伪指令——小范围的地址读取ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中。在汇编编译器编译源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错误,编译失败。...ADRR0,Delay...DelayMOVR0,r14...应用示例(源程序):使用伪指令将程序标号Delay的地址存入R0...0x20ADDr1,pc,#0x3c......0x64MOVr0,r14...ARM伪指令——小范围的地址读取ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中。在汇编编译器编译源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错误,编译失败。...ADRR1,Delay...DelayMOVR0,r14...应用示例(源程序):编译后的反汇编代码:使用伪指令将程序标号Delay的地址存入R0地址程序代码ARM伪指令——小范围的地址读取ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中。在汇编编译器编译源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错误,编译失败。...ADRR0,Delay...DelayMOVR0,r14...应用示例(源程序):...0x20ADDr0,pc,#0x3c......0x64MOVr0,r14...编译后的反汇编代码:使用伪指令将程序标号Delay的地址存入R0ADR伪指令被汇编成一条指令ARM伪指令——小范围的地址读取ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中。在汇编编译器编译源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错误,编译失败。应用示例2(查表):ADRR0,DISP_TAB;加载转换表地址LDRBR1,[R0,R2];使用R2作为参数,进行查表…DISP_TAB:.word0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8在汇编编译源程序时,LDR伪指令被编译器替换成一条合适的指令。若加载的常数未超出MOV或MVN的范围,则使用MOV或MVN指令代替该LDR伪指令,否则汇编器将常量放入文字池,并使用一条程序相对偏移的LDR指令从文字池读出常量。示例:LDRr1,=0xff;将0xff读取到r1中;编译后得到MOVr1,0xff示例:LDRr1,=ADDR;将外部地址ADDR读取到R1中汇编后将得到:;LDRr1,[PC,OFFSET_TO_LPOOL];…;LPOOL.wordADDR.text.global_start_start:movr0,#9movr1,#15loop:cmpr0,r1//比较r0r1subltr1,r1,r0//若r0r1则r1=r1–r0subgtr0,r0,r1//若r1r0则r0=r0–r1bneloop//若r0r1不相等则继续循环stop:bstop.end用预先设定的行标与B、BL结合可以设计各种循环结构。例如:LOOPADDR0,R0,R1;R0=R0+R1CMPR0,#3;比较R0和#3BLSLOOP;ifR03then跳转到LOOP循环.end在ARM汇编语言程序中,子程序的调用一般是通过BL指令来实现的。在程序中,使用指令:BL子程序名即可完成子程序的调用。该指令在执行时完成如下操作:将子程序的返回地址存放在连接寄存器LR中,同时将程序计数器PC指向子程序的入口点,当子程序执行完毕需要返回调用处时,只需要将存放在LR中的返回地址重新复制给程序计数器PC即可。在调用子程序的同时,也可以完成参数的传递和从子程序返回运算的结果,通常可以使用寄存器R0~R3完成。以下是使用BL指令调用子程序的汇编语言源程序的基本结构:……BLPRINT_TEXT;跳转到子程序PRINT_TEXT,并保存PC至LR……PRINT_TEXT;子程序入口……MOVPC,LR;子程序运行完毕将PC置为LR,准备返回.end【例3-3】给出一个输出HelloWorld的程序。.sectionHelloWorld,;声明代码段.equSWI_WriteC&0;输出R0中的字符,&0为预定义的输出代码段入口.equSWI_Exit&11;程序结束&11为预定义程序结束代码入口.text.global_start_start:;代码的入口ADRR1,TEXT;R1→HelloWorldLOOP:LDRBR0,[R1],#1;读取下一个字节CMPR0,#0;检查文本终点SWINESWI_WriteC;若非终点,则打印BNELOOP
本文标题:第3章-ARM汇编语言程序设计-GNU-汇编
链接地址:https://www.777doc.com/doc-7293361 .html