读懂ARM汇编程序,你只差这篇!保姆级教程(附完整示例剖析)!

快速学习嵌入式开发其他基础知识?>>>>>>>>> 返回专栏总目录 《嵌入式工程师自我修养/C语言》<<<<<<<<<

Tip📌:鼠标悬停双虚线关键词/句,可获得更详细的描述

第一、二、三章节都是针对ARM编译器下的汇编语言描述的,学习了这些之后再看第四章节能更好地区分它和GNU GCC下的汇编语言的区别。

一、ARM汇编程序初体验

  建议阅读本文前,先阅读《万字长文带你由浅入深夯实ARM汇编基础——汇编指令及寻址方式最全梳理(附示例)!》。在上述ARM汇编基础一文中,我们详细梳理了各种寻址方式及汇编指令。对这些指令的熟练掌握需要大量阅读汇编代码,而实际上一份完整的汇编代码除了指令,还有一些伪指令或者叫伪操作,想快速读懂或者方便地编写汇编代码离不开这些伪操作。

  ARM汇编程序是以段(section)为单位进行组织的。在一个汇编文件中,可以有不同的section,比如我们经常提到的代码段、数据段等,各个段之间相互独立,一个ARM汇编程序至少要有一个代码段。我们可以使用AREA伪操作来标识一个段的起始、段名、段的属性(CODE、DATA)和读写权限(READONLY、READWRITE)。下面给出一个具体的示例初步感受下:

Tip📌:在汇编程序中,使用分号;来注释代码。

AREA COPY,CODE,READONLY			;该汇编代码的第一个段:段名为COPY,是代码段,属性为只读
	ENTRY						;用ENTRY伪操作来标识汇编程序的运行入口
START							;标号START,类似C语言中的函数名,在汇编语言中,标号代表的指令地址
	LDR R0, =SRC				;
	LDR R1, =DST
	MOV R2, #10
LOOP							;标号,结合下面的BNE LOOP指令构成了一个循环程序
	LDR R3, [R0], #4
	STR R3, [R1], #4
	SUBS R2, R2, #1
	BNE LOOP
AREA COPYDATA,DATA,READWRITE	;该汇编代码的第二个段:段名为COPYDATA,是数据段,具有读写权限
SRC DCD 1,2,3,4,5,6,7,8,9,0
DST DCD 0,0,0,0,0,0,0,0,0
	END							;用END伪操作来标识汇编程序的结束

二、符号、标号、伪操作详解

2.1 符号和标号

  在ARM汇编程序中,我们可以使用符号来标识一个地址、变量或数字常量。当用符号来标识一个地址时,这个符号通常又被称为标号。符号的命名规则和C语言的标识符命名规则一样:由字母、数字和下画线组成,符号的开头不能使用数字,但标号命名没有那么严格,标号的开头不仅可以是数字,甚至整个标号可以是一个纯数字。

  符号的命名在其作用域内必须唯一,不能与系统内部或系统预定义的符号同名,不能与指令助记符、伪指令同名。一般情况下,一个符号的作用域是整个汇编源文件。有时候我们会直接通过数字[0,99]而不是使用字符来进行地址引用,我们称这种数字为局部标号。局部标号的作用域为当前段,在汇编程序中,我们可以使用下面的格式来引用局部标号。

%{
   F|B|A|T} N{
   routename}		;大括号{
   }括起来的部分是可选项
  • %:引用符号,对一个局部标号产生引用
  • F:指示编译器只向前搜索
  • B:指示编译器只向后搜索
  • A:指示编译器搜索宏的所有宏命令层
  • T:指示编译器搜索宏的当前层
  • N:局部标号的名字
  • routename:局部标号作用范围名称,使用ROUT定义

Tip📌:
  若B、F没有指定,编译器将默认先向后搜索,然后向前搜索。
  若A、T都没指定,则汇编程序默认搜索从当前层到最顶层的所有宏命令,但不搜索较低层的宏命令。
  若在标签中或者对标签的引用中指定了routename,则汇编程序将其与最近的一个前ROUT指令的名称进行比较,不匹配则汇编失败。

基于开头的那个例子我们把loop标号改为纯数字0:

AREA COPY,CODE,READONLY
	ENTRY
START
	LDR R0, =SRC
	LDR R1, =DST
	MOV R2, #10
0								;定义局部标号:0
	LDR R3, [R0],#4
	STR R3, [R1], #4
	SUBS R2, R2, #1
	BNE %B0						;向后寻找(这行代码往上是后,往下是前)局部标号0并跳转,构成循环程序结构
AREA COPYDATA,DATA,READWRITE
SRC DCD 1,2,3,4,5,6,7,8,9,0
DST DCD 0,0,0,0,0,0,0,0,0
	END

2.2 伪操作

  我们知道C语言中有很多预处理命令(#include、#define、#if、#else、#end等)。编译器在编译C代码时,首先执行的就是预处理操作(对应:头文件包含、宏定义的嵌入展开,砍掉不参与编译的代码块等),如果在编译之前不做预处理操作,则编译器就会报错,因为实际上编译器并不认识这些预处理命令,他们不是C语言标准中的关键字。

  同样,汇编器也定义了一些特殊的指令助记符,就是所说的伪操作,他们就类似于C语言中的预处理命令,是为了方便对汇编程序做各种处理而生的。除了第一节提到的用AREA来定义一个段(section)、用ENTRY来指定汇编程序的执行入口、用END伪操作来标识汇编程序的结束以外,还有如下常用的伪操作:

/******************** 基础伪操作 ********************/
ALIGN 		;地址对齐
AREA		;用来定义一个代码段或数据段,常用的段属性为CODE/DATA
ENTRY		;指定汇编程序的执行入口
END			;用来告诉编译器源程序已到了结尾,停止编译
EQU			;赋值伪指令,类似宏,给常量定义一个符号名

CODE16/CODE32		;
  • 54
    点赞
  • 93
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是用 ARM 汇编语言实现计算 10! 的代码: ``` .global main main: mov r1, #10 @ r1 存储阶乘的值 mov r2, #1 @ r2 存储累乘的值 loop: cmp r1, #0 @ 比较 r1 是否等于 0 beq end @ 如果 r1 等于 0,跳转到 end 标签 mul r2, r2, r1 @ r2 = r2 * r1 sub r1, r1, #1 @ r1 = r1 - 1 b loop @ 跳转到 loop 标签 end: mov r0, r2 @ 将结果存储在 r0 中 mov r7, #1 @ 退出程序 swi 0 @ 调用系统中断 ``` 接下来是用调用子程序的方法实现从 1! 到 10! 的累加的代码: ``` .global main main: mov r1, #1 @ r1 存储阶乘的值,初始值为 1 mov r2, #0 @ r2 存储累加的值,初始值为 0 loop: cmp r1, #11 @ 比较 r1 是否等于 11 beq end @ 如果 r1 等于 11,跳转到 end 标签 bl factorial @ 调用 factorial 子程序 add r2, r2, r0 @ 将阶乘的结果加到累加器中 add r1, r1, #1 @ r1 = r1 + 1 b loop @ 跳转到 loop 标签 end: mov r0, r2 @ 将结果存储在 r0 中 mov r7, #1 @ 退出程序 swi 0 @ 调用系统中断 factorial: push {lr} @ 保存 lr 寄存器的值 mov r3, r1 @ 将 r1 的值保存到 r3 中 mov r4, #1 @ r4 存储累乘的值,初始值为 1 fact_loop: cmp r3, #0 @ 比较 r3 是否等于 0 beq fact_end @ 如果 r3 等于 0,跳转到 fact_end 标签 mul r4, r4, r3 @ r4 = r4 * r3 sub r3, r3, #1 @ r3 = r3 - 1 b fact_loop @ 跳转到 fact_loop 标签 fact_end: mov r0, r4 @ 将结果存储在 r0 中 pop {pc} @ 恢复 lr 寄存器的值并返回 ``` 在这个代码中,我们定义了一个名为 factorial 的子程序,它计算一个给定数的阶乘。然后在主程序中,我们使用循环来计算从 1! 到 10! 的累加,每次循环都调用 factorial 子程序来计算阶乘,并将结果加到累加器中。最终结果存储在 r0 中并退出程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

车载系统攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值