第3章 ARM汇编语言程序设计
arm汇编语言程序设计步骤

arm汇编语言程序设计步骤ARM汇编语言是一种底层的计算机编程语言,常用于嵌入式系统和低功耗设备。
在进行ARM汇编语言程序设计时,需要按照以下步骤进行。
1. 定义代码段(Code Section)首先,我们需要定义代码段,用于存放我们编写的指令代码。
在ARM汇编语言中,代码段通常以".text"开始,以".section"结束。
2. 定义全局变量段(Data Section)全局变量段用于存放程序中需要初始化的全局变量。
在ARM汇编语言中,全局变量段通常以".data"开始,以".section"结束。
在定义全局变量时,需要使用合适的指令来分配内存空间,并为变量赋初值。
3. 定义堆栈段(Stack Section)堆栈段用于存放程序运行中产生的临时变量和函数调用所需要的数据。
在ARM汇编语言中,堆栈段通常以".bss"开始,以".section"结束。
在定义堆栈时,需要预留足够的内存空间。
4. 编写指令代码在代码段中,我们可以编写各种指令代码来实现具体的功能。
ARM汇编语言提供了丰富的指令集,可以进行算术运算、逻辑运算、数据传输等操作。
需要根据具体需求选择合适的指令。
5. 定义程序入口程序入口是程序开始执行的地方,通常是一个标签(Label),用于表示指令代码的起始位置。
在ARM汇编语言中,可以使用".globl"指令定义程序入口,并使用标签名进行标识。
6. 进行程序调用如果需要调用其他函数或子程序,则需要使用特定的指令来实现跳转。
在ARM汇编语言中,可以使用"b"指令进行无条件跳转,使用"bl"指令进行函数调用,并将返回地址保存在链接寄存器中。
7. 进行程序返回当函数执行完毕后,需要返回到函数调用的位置。
在ARM汇编语言中,可以使用"bx lr"指令实现跳转到链接寄存器中保存的返回地址。
ARM汇编语言程序设计

是由物理寄存器r1来存放r0所代表的值。
Chavezwang@
计算机学院嵌入式实验室
19
北京理工大学珠海学院
嵌入式系统设计及应用开发
内联汇编中虚拟寄存器举例
int main(void) #include <stdio.h> void test_inline_register(void) { int i; int r5,r6,r7; __asm { MOV i,#0 loop: MOV r5,#0 MOV r6,#0 MOV r7,#0 ADD i,i,#1 CMP i,#3 BNE loop } }
北京理工大学珠海学院
嵌入式系统设计及应用开发
何时使用内联汇编和嵌入型汇编
程序中使用饱和算术运算(Saturating arithmetic),如SSAT16 和 USAT16指令。
程序中需要对协处理器进行操作。 在C或C++程序中完成对程序状态寄存器的操作
注:使用内联汇编编写的程序代码效率也比较高
③ 不能在程序中使用“.”或{PC}得到当前指令地址值。
④ 在16进制常量前加“0x”。
⑤ 建议不要对堆栈进行操作。
Chavezwang@
计算机学院嵌入式实验室
16
北京理工大学珠海学院
嵌入式系统设计及应用开发
内联汇编的限制2
⑥ 编译器可能会使用r12和r13寄存器存放编译的中间结果, 在计算表达式值可能会将寄存器r0~r3、r12及r14用于子程 序调用。另外在内联汇编中设置程序状态寄存器CPSR中的 标志位NZCV时,要特别小心。内联汇编中的设置很可能会 和编译器计算的表达式的结果冲突。
编译器使用一套规则的来设置寄存器的用法
第3章4 ARM指令集及程序设计资料

参数个数固定子程序参数传递规则
如果系统不包含浮点运算的硬件部件,浮点参 数会通过相应的规则转换成整数参数(若没有 浮点参数,此步省略),然后依次将各字数据 传送到寄存器R0~R3中。如果参数多于4个, 将剩余的字数据传送堆栈中,入栈的顺序与参 数顺序相反,即最后一个字数据先入栈。在参 数传递时,将所有参数看作是存放在连续的内 存字单元的字数据。
调用ARM汇编语言子程序
在ARM汇编语言中,子程序调用是通过BL指令完成的 BL指令的语法格式如下:
BL subname 其中,subname是调用的子程序的名称。
BL指令完成两个操作:将子程序的返回地址放在LR寄 存器中,同时将PC寄存器值设置成目标子程序的第一 条指令地址。
在子程序返回时可以通过将LR寄存器的值传送到PC寄 存器中来实现。
}
int caller1(void) {
return func1(1,2,3,4); }
func1 0x000000 : ADD 0x000004 : ADD 0x000008 : ADD 0x00000c : MOV
r0,r0,r1 r0,r0,r2 r0,r0,r3 pc,lr
caller1 0x000014 : MOV 0x000018 : MOV 0x00001c : MOV 0x000020 : MOV 0x000024 : BL
1
什么是ATPCS规则
为了使单独编译的C语言程序和汇 编程序之间能够相互调用,必须为 子程序间的调用规定一定的规则。 ATPCS就是ARM程序和Thumb程序 中子程序调用的基本规则。
2
1 ATPCS概述
ATPCS规定了一些子程序间调用的基本规则。 这些基本规则包括子程序调用过程中寄存器、 数据栈的使用规则以及参数的传递规则。
《汇编语言程序设计 —基于ARM体系结构 (第4版)》教学课件—03ARM指令系统

图3-1程序设计语言的层次结构
为了提高程序设计的效率,人们提出了汇编语言的概念。将机器码用指令助记符表示,这样就比机器语言方便得多。不过,在使用汇编语言后,虽然编程的效率和程序的可读性都有所提高,但汇编语言同机器语言非常接近,它的书写风格在很大程度上取决于特定计算机的机器指令,所以它仍然是一种面向机器的语言。 为了更好地进行程序设计,提高程序设计的效率,人们又提出了高级语言程序设计的概念。如C、JAVA等,这类高级语言对问题的描述十分接近人们的习惯,并且还具有较强的通用性。这就给程序员带来极大的方便。当然这类高级语言在执行前必须转换为汇编语言或其它中间语言,最终转换为机器语言。通常有两
3.2 ARM汇编语言
3.2.1指令和指令格式3.2.2指令的可选后缀3.2.3指令的条件执行3.2.4 ARM指令分类
3.2.1指令和指令格式
1.指令和指令系统 指令是指示计算机进行某种操作的命令 指令的集合称为指令系统。指令系统的功能强弱在很大程度上决定了这类计算机智能 的高低,它集中地反映了微处理器的硬件功能和属性。2.指令的表示方法从形式上看,ARM指令在机器中的表示格式是用32位的二进制数表示。计算机根据二 进制代码去完成所需的操作,如ARM中有一条指令为:ADDEQS R0,R1,#8;其二进制代码形式为:
3.1 指令基础
3.1.1程序设计语言的层次结构3.1.2指令周期和时序3.1.3程序的执行过程
3.1.1程序设计语言的层次结构
计算机程序设计语言的层次结构如图3-1所示,分为机器语言级、汇编语言级、高级语言级,机器语言是与计算机硬件最为密切的一种语言,它由微程序解释机器指令统。这一级也是硬件级,是软件系统和硬件系统之间的纽带。
例如:在8MHz的ARM微处理器中,一个 S 周期是125ns,而一个 N 周期 是 250ns。应当注意到这些时序不是 ARM 的属性,而是内存系统 的属性。例如,一个 8MHz的ARM微处理器可以与一个给出125ns 的 N 周期的 RAM 系统相连接。处理器的速率是 8MHz 只是简单 的意味着如果你使任何类型的周期,在长度上小于 125ns 则它不 保证能够工作。图3-2显示一种ARM存储器周期时序。
ARM汇编语言程序设计

ARM汇编语言程序设计1.ARM汇编语言概述2.ARM寄存器3.ARM指令ARM指令包括数据处理指令、传输指令、分支指令和其他特殊指令。
(1)数据处理指令:包括算术运算、逻辑运算、移位和旋转、比较和测试等。
(2)传输指令:用于数据的加载和存储,包括复制、分配和堆栈操作等。
(3)分支指令:用于控制程序流,包括无条件跳转、条件跳转和中断处理等。
4.ARM程序设计(1)初始化:程序开始时需要进行系统和寄存器的初始化。
可以将堆栈指针初始化,设置另外的寄存器和内存变量等。
(2)输入输出:程序可能需要从外部设备读取数据或向外部设备写入数据。
可以使用传输指令实现数据的输入和输出。
(3)运算处理:根据程序的需求,进行各种运算处理。
可以使用数据处理指令实现数据的加减乘除、逻辑运算等。
(4)循环和条件控制:根据需要,使用分支指令控制程序的流程。
可以使用无条件跳转、条件跳转和循环指令实现程序的循环和条件控制。
(5)结束:在程序执行完毕后,可以进行清理工作,例如释放内存、关闭设备等。
5.ARM程序设计实例下面是一个简单的ARM汇编程序示例,实现从数组中找到最大值并输出:.global _start.section .dataarray: .word 1, 3, 5, 2, 4max: .word 0.section .text_start:loop:next:在上述示例中,程序首先将数组的地址和最大值的地址加载到寄存器中。
然后使用循环和条件控制指令依次比较数组元素,找到最大值并将其存储在max变量中。
最后将最大值输出,并结束程序。
第3章ARM汇编语言程序设计

2.局部变量定义伪操作LCLA、LCLL和LCLS
(1)语法格式 LCLA、LCLL和LCLS伪指令用于定义一个 ARM程序中的局部变量并将其初始化。 语法格式如下: <lclx> <variable> (2)使用说明 (3)示例
3.变量赋值伪操作SETA、SETL和SETS
(1)语法格式 伪指令SETA、SETL和SETS用于给一个已 经定义的全局变量或局部变量赋值。 语法格式如下: Variable <setx> expr (2)使用说明 (3)示例
(2)用于定义局部变量的LCLA、LCLL和 LCLS。
(3)用于对变量赋值的SETA、SETL和 SETS。
(4)为通用寄存器列表定义名称的RLIST。
1.全局变量定义伪操作GBLA、GBLL和GBLS
(1)语法格式 GBLA、GBLL和GBLS伪操作用于定义一个 ARM程序中的全局变量并将其初始化。 语法格式如下: <gblx> <variable> (2)使用说明 (3)示例
4.通用寄存器列表定义伪操作RLIST
(1)语法格式 RLIST伪操作可用于对一个通用寄存器列 表定义名称,使用该伪操作定义的名称可在 ARM指令LDM/STM中使用。 语法格式如下: Name RLIST {list-of-registers} (2)使用说明 (3)示例
3.2.3 数据定义(Data Definition)伪操作
{label} DCFS{U} fpliteral{,fpliteral}
(2)使用说明 (3)示例
5.DCFD(或DCFDU)
(1)语法格式 DCFD(或DCFDU)伪指令用于为双精度
的浮点数分配一片连续的字存储单元并用伪指 令中指定的表达式初始化。
3ARM指令及汇编程序设计共31页文档

常量
数字常量
十进制 12,5,876,0 十六进制 0xFF,0x1 N进制 n-XXX,2-010111
字符常量
布尔常量
段定义
AREA Hello,CODE,READONLY ENTRY START MOV R7,#10
MOV R6,#5 ADD R6,R6,R7 B END
(9)FILED 语法格式:标号 FIELD 表达式
4 汇编控制伪指令
汇编控制伪指令用于控制汇编程序的执行流程, 常用的汇编控制伪指令包括以下几条: (1) IF、ELSE、ENDIF 语法格式: IF 逻辑表达式
指令序列 1
ELSE
指令序列 2
ENDIF
汇编控制伪指令(Cont.)
<>内的项是必须的
{}内的项是可选的
opcode 指令助记符,如LDR,STR等
cond 执行条件,如EQ,NE等
S 是否影响CPSR寄存器的值
Rd
目标寄存器
Rn
第一个操作数的寄存器
operand2 第二个操作数
第二个操作数
#immed_8r
常数表达式,必须是一个8位常数的偶数次循环移位 合法常量:0x3FC、0、0xF0000000、200、0xF0000001 非法常量:0x1FE、511、0xFFFF、0x1010、0xF0000010
数据常量定义伪指令
数据常量定义伪指令EQU用于为程序中的常量、 标号等定义一个等效的字符名称,类似于 C 语言 中的#define 。 EQU语法格式 : 名称 EQU 表达式 { ,类型 } ;其中 EQU 可用 “ * ” 代替。 名称为 EQU 伪指令定义的字符名称,当表达 式为 32 位的常量时,可以指定表达式的数据类 型,可以有以下三种类型: CODE16 、 CODE32 和 DATA 。
ARM汇编语言编程详解

ARM汇编语言编程详解作者:机器人小助手摘要:本文旨在为读者提供一份详细的ARM汇编语言编程指南。
在介绍ARM汇编语言的基础知识后,我们将深入讨论ARM指令集的不同类型、寻址方式、寄存器的使用以及常见的编程技巧。
通过本文的学习,读者将能够深入了解ARM汇编语言的编程思想,并能够编写高效的ARM汇编语言程序。
一、ARM汇编语言简介ARM汇编语言是一种低级的程序设计语言,用于编写针对ARM架构的机器码指令。
它是一种类似于其他汇编语言的文本格式,用于表达机器指令和操作数。
通过编写ARM汇编语言程序,我们可以直接控制计算机的硬件资源,实现高效的程序执行。
二、ARM指令集概述ARM指令集是一套针对ARM架构的机器指令集合,包含多条不同功能的指令。
根据指令的功能和操作对象的不同,ARM指令可以分为数据处理指令、分支跳转指令、访存指令以及其他特殊指令。
1. 数据处理指令数据处理指令用于对操作数进行算术运算、逻辑运算、移位操作等。
这些指令可以对寄存器中的数据进行操作,并将结果存储回寄存器。
常见的数据处理指令有加法、减法、乘法、比较以及逻辑运算等。
2. 分支跳转指令分支跳转指令用于控制程序的流程,可以根据条件进行无条件跳转或有条件跳转。
通过分支跳转指令,我们可以实现程序的循环、条件分支等逻辑。
3. 访存指令访存指令用于读取或写入内存中的数据。
ARM汇编语言提供了多种不同的寻址方式,可以根据操作对象的不同进行选择。
使用访存指令,我们可以实现数据的存储和加载操作。
三、ARM汇编语言编程基础在进行ARM汇编语言编程时,我们需要了解一些基本的编程知识和技巧。
1. 寄存器的使用ARM架构提供了多个通用寄存器,用于存储临时数据。
在编写ARM汇编语言程序时,我们需要灵活使用寄存器,将数据加载到寄存器中进行计算,然后将结果保存回寄存器或内存。
2. 标志位的使用ARM架构提供了一组标志位,用于记录程序执行的状态和结果。
通过检查标志位的值,我们可以进行条件分支和判断,实现程序的流程控制。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
使用伪指令将程序标号 Delay的地址存入R0
ARM伪指令——小范围的地址读取
ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的 地址值读取到寄存器中。在汇编编译器编译源程序时,ADR伪指令被 编译器替换成一条合适的指令。通常,编译器用一条 ADD指令或 SUB 指令来实现该 ADR伪指令的功能,若不能用一条指令实现,则产生错 误,编译失败。 应用示例(源程序): 编译后的反汇编代码:
【例3-1】 汇编语言源程序的基本格式。 AREA EXAMPLE,CODE,READONLY 名称和属性,表示了一个段的开始 ENTRY ; 标识程序的入口点 start ; 以下为具体指令 MOV R0,#10 MOV R1,#3 ADD R0,R0,R1 END ; 标识源文件的结束 ; 定义段的
... ADR ... Delay MOV ... R0,r14 0x64 R1,Delay 0x20 ... ADD ... ... MOV ... r0,r14 r1,pc,#0x3c
使用伪指令将程序标号 Delay的地址存入R0
地址
程序代码
ARM伪指令——小范围的地址读取
ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的 地址值读取到寄存器中。在汇编编译器编译源程序时,ADR伪指令被 编译器替换成一条合适的指令。通常,编译器用一条ADD指令或SUB 指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错 误,编译失败。 应用示例(源程序): 编译后的反汇编代码:
【例3-3】 给出一个输出Hello World的程序。 AREA HelloWorld,CODE,READONLY SWI_WriteC EQU &0 ; 声明代码段 ; 输出R0中的字符,&0为预定义的 输出代码段入口 SWI_Exit EQU &11 ; 程序结束 &11为预定义程序结束代码入口 ENTRY ; 代码的入口 START ADR R1,TEXT ; R1→"Hello World" LOOP LDRB R0,[R1],#1 ; 读取下一个字节 CMP R0,#0 ; 检查文本终点 SWINE SWI_WriteC ; 若非终点,则打印 BNE LOOP ; 并返回LOOP SWI SWI_Exit ; 执行结束 TEXT = "Hello World",&0a,&0d,0 END ; 程序源代码结束
上述代码中,ADD指令可以根据已执行代码对状态寄存器的影响来决定 是否执行,从而构成简单的分支结构。另外,B、BL可以条件执行,从而 构成复杂的分支架构。 例如:
CMP R1,#3 ; 比较R1和#3 BHI END ; if R1>3 then END ADD R0,R0,#3 ; R0=R0+3 END
没有分支、循环等架构的程序,会顺序执行汇编指令, 实际的程序段中大量存在,可参见例3-1。 【例3-1】 汇编语言源程序的基本格式。 AREA EXAMPLE,CODE,READONLY 名称和属性,表示了一个段的开始 ENTRY ; 标识程序的入口点 Start ; 以下为具体指令 MOV R0,#10 MOV R1,#3 ADD R0,R0,R1 END ; 标识源文件的结束 ; 定义段的
ARM伪指令——小范围的地址读取
ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的 地址值读取到寄存器中。在汇编编译器编译源程序时,ADR伪指令被 编译器替换成一条合适的指令。通常,编译器用一条ADD指令或SUB 指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错 误,编译失败。 应用示例(源程序):
汇编语言都具有一些相同的基本特征。 ① 一条指令一行。 ② 使用标号(label)给内存单元提供名称,从第1列 开始书写。 ③ 指令必须从第2列或能区分标号的地方开始书写。 ④ 注释跟在指定的注释字符后面(ARM使用的是 “;”),一直书写到行尾。 ARM汇编语言基本的的语句格式如下: {symbol} {instruction |directive | pseudoinstruction} {;comment} 符号 指令、伪指令或伪操作 [; 注释]
... ADR ... Delay MOV ... R0,r14 0x64 R0,Delay 0x20 ... ADD ... ... MOV ... r0,r14 r0,pc,#0x3c
使用伪指令将程序标号 Delay的地址存入R0
ADR伪指令被汇编成一条指令
ARM伪指令——小范围的地址读取
ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的 地址值读取到寄存器中。在汇编编译器编译源程序时,ADR伪指令被 编译器替换成一条合适的指令。通常,编译器用一条ADD指令或SUB 指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错 误,编译失败。 应用示例2(查表): ADR LDRB … DISP_TAB DCB 0xC0,0xF9,0xA4,0xB0,0x99, 0x92,0x82,0xF8 R0,DISP_TAB R1,[R0,R2] ; 加载转换表地址 ; 使用R2作为参数,进行查表
伪指令是ARM处理器支持的汇编语言程序里的特殊 助记符,它不在处理器运行期间由机器执行,只是 在汇编时将被合适的机器指令代替成ARM或 Thumb指令,从而实现真正的指令操作。ARM汇 编语言伪指令如表3-2所示。
在汇编编译器编译源程序时,ADR伪指令被编译器替换 成一条合适的指令。通常,编译器用一条ADD指令或 SUB指令来实现该ADR伪指令的功能,若不能用一条指 令实现,则产生错误,编译失败。ADR伪指令中的地址 是基于PC或寄存器的,当ADR伪指令中的地址是基于 PC时,该地址与ADR伪指令必须在同一个代码段中。 地址表达式expr的取值范围如下: 当地址值是字节对齐时,其取指范围为−255B~255B; 当地址值是字对齐时,其取指范围为−1020B~1020B。
Linux汇编程序中的分段
(1).section伪操作 用户可以通过.section伪操作来自定义一个段,格式 如下: .section section_name [, "flags"[, %type[,flag_s pecific_arguments]]] 每一个段以段名为开始, 以下一个段名或者文件结尾 为结束。这些段都有缺省的标志(flags),连接器 可以识别这些标志。(与armasm中的AREA相同) 。 下面是ELF格式允许的段标志 <标志>含义 a 允 许段 w 可写段
.section .text, “x”
.global add @ give the symbol add external linkage add: ADD r0, r0, r1 @ add input arguments MOV pc, lr @ return from subroutine @ end of 大部分的指令都支持条件执行,因此类似C语言中的if-else 分支很容易实现。 例如:
CMP R1,#3 ; 比较R1和#3 ADDHI R0,R0,R1 ; if R1>3 then R0=R0+R1 ADDLS R0,R0,#3 ; if R1<3 then R0=R0+3
示例: LDR r1, =ADDR ; 将外部地址ADDR读取到R1中
汇编后将得到: ; LDR r1,[PC,OFFSET_TO_LPOOL] ;… ; LPOOL DCD ADDR
复习
ARM体系结构,工作模式和相关寄存器 ARM异常向量表 回顾学习过的ARM指令和ARM伪指令和伪操作
Linux 汇编程序中的标号
Linux 汇编程序中的标号 标号只能由a~z,A~Z ,0~9,“.”,”_”等字符组成。当标号为0~9的 数字时为局部标号,局部标号可以重复出现,使用方 法如下: 标号f: 在引用的地方向前的标号 标号b: 在引用的地方向后的标号 【例2】使用局部符号的例子,一段循环程序 1: subs r0,r0,#1 @每次循环使r0=r0-1 bne 1f @跳转到1标号去执行 局部标号代表它所在的地址,因此也可以当作变量或 者函数来使用。
Linux汇编行结构 任何汇编行都是如下结构: [:] [} @ comment [:] [} @ 注释
Linux ARM 汇编中,任何以冒号结尾的标识符都被认为是一个标号,而不一定非 要在一行的开始。
【例1】定义一个"add”的函数,返回两个参数的和。
在汇编编译源程序时,LDR伪指令被编译器替换成一条合适的指 令。若加载的常数未超出MOV或MVN的范围,则使用MOV或 MVN指令代替该LDR伪指令,否则汇编器将常量放入文字池,并 使用一条程序相对偏移的LDR指令从文字池读出常量。 示例: LDR r1,=0xff ; 将0xff读取到r1中 ; 编译后得到MOV r1,0xff
…… BL PRINT_TEXT ; 跳转到子程序 PRINT_TEXT,并保存PC至LR …… PRINT_TEXT ; 子程序入口 …… MOV PC,LR ; 子程序运行完毕将PC置为LR,准备返回 END
【例3-2】 实现1+2+……+N。
N EQU 5 ; 常量的定义 AREA Example,CODE,READONLY ; 定义段名属性等 ENTRY ; 程序入口 CODE32 ; ARM代码 START ; 行标定义 LDR R0,=N ; R0赋值 MOV R2,R0 ; R2充当计数器 MOV R0,#0 ; R0←0 MOV R1,#0 ; R1←0 LOOP ; 行标 CMP R1,R2 ; 比较R1 R2 BHI ADD_END ; 如果R1>R2 跳转到 ADD_END ; 分支的实现 ADD R0,R0,R1 ; R0←R0+R1 ADD R1,R1,#1 ; R1←R1+1 B LOOP ; 无条件跳转至LOOP ; 循环的实现 ADD_END ; 行标定义 B ADD_END ; 无条件跳转ADD_END END ; 代码结束