处理器执行的指令被分成两类最基本的汇编指令有几条。

PowerPC汇编指令
高级编程与低级编程的对比
大多数编程语言都与处理器保持着相当程度的独立性。但都有一些特殊特性依赖于处理器的某些功能,它们更有可能是特定于操作系统的,而不是特定于处理器的。构建高级编程语言的目的是在程序员和硬件体系结构间搭建起一座桥梁。这样做有多方面的原因。尽管可移植性是原因之一,但更重要的一点或许是提供一种更友好的模型,这种模型的建立方式更接近程序员的思考方式,而不是芯片的连线方式。
然而,在汇编语言编程中,您要直接应对处理器的指令集。这意味着您看系统的方式与硬件相同。这也有可能使汇编语言编程变得更为困难,因为编程模型的建立更倾向于使硬件工作,而不是密切反映问题域。这样做的好处在于您可以更轻松地完成系统级任务、执行那些与处理器相关性很强的优化任务。而缺点是您必须在那个级别上进行思考,依赖于一种特定的处理器系列,往往还必须完成许多额外的工作以准确地建模问题域。
关于汇编语言,很多人未想到的一个好处就是它非常具体。在高级语言中,对每个表达式都要进行许多处理。您有时不得不担忧幕后到底发生了哪些事情。在汇编语言编程中,您可以完全精确地掌控硬件的行为。您可以逐步处理硬件级更改。
汇编语言基础
在了解指令集本身之前,有两项关于汇编语言的关键内容需要理解,也就是内存模型和获取-执行周期。
内存模型非常简单。内存只存储一种东西 —— 固定范围内的数字,也称为字节(在大多数计算机上,这是一个 0 到 255 之间的数字)。每个存储单元都使用一个有序地址定位。设想一个庞大的空间,其中有许多信箱。每个信箱都有编号,且大小相同。这是计算机能够存储的惟一 内容。因此,所有一切最终都必须存储为固定范围内的数字。幸运的是,大多数处理器都能够将多个字节结合成一个单元来处理大数和具有不同取值范围的数字(例如浮点数)。但特定指令处理一块内存的方式与这样一个事实无关:每个存储单元都以完全相同的方式存储。除了内存按有序地址定位之外,处理器还维护着一组寄存器,这是容纳被操纵的数据或配置开关的临时位置。
控制处理器的基本过程就上获取-执行周期。处理器有一个称为程序计数器的寄存器,容纳要执行的下一条指令的地址。获取-执行的工作方式如下:
读程序计数器,从其中列出的地址处读取指令
更新程序计数器,使之指向下一条指令
加载处理该指令所需的全部内存项
完成这一切的实际原理极其复杂,特别是 POWER5 处理器可同步处理多达 5 条的指令。但上述介绍对于构思模型来说已足够。
PowerPC 体系结构按特征可表述为加载/存储 体系结构。这也就意味着,所有的计算都是在寄存器中完成的,而不是主存储器中。在将数据载入寄存器以及将寄存器中的数据存入内存时的内存访问非常简单。这与 x86 体系结构(比如说)不同,其中几乎每条指令都可对内存、寄存器或两者同时进行操作。加载/存储体系结构通常具有许多通用的寄存器。PowerPC 具有 32 个通用寄存器和 32 个浮点寄存器,每个寄存器都有编号(与 x86 完全不同,x86 为寄存器命名而不是编号)。操作系统的 ABI(应用程序二进制接口)可能主要使用通用寄存器。还有一些专用寄存器用于容纳状态信息并返回地址。管理级应用程序还可使用其他一些专用寄存器,但这些内容不在本文讨论之列。通用寄存器在
32 位体系结构中是 32 位的,在 64 位体系结构中则是 64 位的。本文主要关注 64 位体系结构。
汇编语言中的指令非常低级 —— 它们一次只能执行一项(有时可能是为数不多的几项)操作。例如,在 C 语言中可以写 d = a + b + c - d + some_function(e, f - g),但在汇编语言中,每一次加、减和函数调用操作都必须使用自己的指令,实际上函数调用可能需要使用几条指令。有时这看上去冗长麻烦。但有三个重要的优点。第一,简单了解汇编语言能够帮助您编写出更好的高级代码,因为这样您就可以了解较低的级别上究竟发生了什么。第二,能够处理汇编语言中的所有细节这一事实意味着您能够优化速度关键型循环,而且比编译器做得更出色。编译器十分擅长代码优化。但了解汇编语言可帮助您理解编译器进行的优化(在
gcc 中使用 -S 开关将使编译器生成汇编代码而不是对象代码),并且还能帮您找到编译器遗漏的地方。第三,您能够充分利用 PowerPC 芯片的强大力量,实际上这往往会使您的代码比高级语言中的代码更为简洁。
这里不再进一步解释,接下来让我们开始研究 PowerPC 指令集。下面给出了一些对新手很有帮助的 PowerPC 指令:
li REG, VALUE
加载寄存器 REG,数字为 VALUE
add REGA, REGB, REGC
将 REGB 与 REGC 相加,并将结果存储在 REGA 中
addi REGA, REGB, VALUE
将数字 VALUE 与 REGB 相加,并将结果存储在 REGA 中
mr REGA, REGB
将 REGB 中的值复制到 REGA 中
or REGA, REGB, REGC
对 REGB 和 REGC 执行逻辑 “或” 运算,并将结果存储在 REGA 中
ori REGA, REGB, VALUE
对 REGB 和 VALUE 执行逻辑 “或” 运算,并将结果存储在 REGA 中
and, andi, xor, xori, nand, nand, and nor
其他所有此类逻辑运算都遵循与 “or” 或 “ori” 相同的模式
ld REGA, 0(REGB)
使用 REGB 的内容作为要载入 REGA 的值的内存地址
lbz, lhz, and lwz
它们均采用相同的格式,但分别操作字节、半字和字(“z” 表示它们还会清除该寄存器中的其他内容)
跳转(或转移)到地址 ADDRESS 处的指令
bl ADDRESS
对地址 ADDRESS 的子例程调用
cmpd REGA, REGB
比较 REGA 和 REGB 的内容,并恰当地设置状态寄存器的各位
beq ADDRESS
若之前比较过的寄存器内容等同,则跳转到 ADDRESS
bne, blt, bgt, ble, and bge
它们均采用相同的形式,但分别检查不等、小于、大于、小于等于和大于等于
std REGA, 0(REGB)
使用 REGB 的地址作为保存 REGA 的值的内存地址
stb, sth, and stw
它们均采用相同的格式,但分别操作字节、半字和字
对内核进行系统调用
注意到,所有计算值的指令均以第一个操作数作为目标寄存器。在所有这些指令中,寄存器都仅用数字指定。例如,将数字 12 载入寄存器 5 的指令是 li 5, 12。我们知道,5 表示一个寄存器,12 表示数字 12,原因在于指令格式 —— 没有其他指示符。
每条 PowerPC 指令的长度都是 32 位。前 6 位确定具体指令,其他各位根据指令的不同而具有不同功能。指令长度固定这一事实使处理器更够更有效地处理指令。但 32 位这一限制可能会带来一些麻烦,后文中您将会看到。大多数此类麻烦的解决方法将在本系列的第 2 部分中讨论。
上述指令中有许多都利用了 PowerPC 的扩展记忆法。也就是说,它们实际上是一条更为通用的指令的特殊形式。例如,上述所有条件跳转指令实际上都是 bc(branch conditional)指令的特殊形式。bc 指令的形式是 bc MODE, CBIT, ADDRESS。CBIT 是条件寄存器要测试的位。MODE 有许多有趣的用途,但为简化使用,若您希望在条件位得到设置时跳转,则将其设置为 12;若希望在条件位未得到设置时跳转,则将其设置为 4。部分重要的条件寄存器位包括:表示小于的 8、表示大于的 9、表示相等的
10。因此,指令 beq ADDRESS 实际上就是 bc 12, 10 ADDRESS。类似地,li 是 addi 的特殊形式,mr 是 or 的特殊形式。这些扩展的记忆法有助于使 PowerPC 汇编语言程序更具可读性,并且能够编写出更简单的程序,同时也不会抵消更高级的程序和程序员可以利用的强大能力。
您的第一个 POWER5 程序
现在我们来看实际代码。我们编写的第一个程序仅仅载入两个值、将其相加并退出,将结果作为状态代码,除此之外没有其他功能。将一个文件命名为 sum.s,在其中输入如下代码:
清单 1. 您的第一个 POWER5 程序
#Data sections holds writable memory declarations
.align 3 #align to 8-byte boundary
#This is where we will load our first value from
first_value:
#"quad" actually emits 8-byte entities
second_value:
#Write the "official procedure descriptor" in its own section
.section ".opd","aw"
.align 3 #align to 8-byte boundary
#procedure description for ._start
.global _start
#Note that the description is named _start,
# and the beginning of the code is labeled ._start
.quad ._start, , 0
#Switch to ".text" section for program code
#Use register 7 to load in an address
#64-bit addresses must be loaded in 16-bit pieces
#Load in the high-order pieces of the address
#Shift these up to the high-order bits
rldicr 7, 7, 32, 31
#Load in the low-order pieces of the address
oris 7, 7,
#Load in first value to register 4, from the address we just loaded
ld 4, 0(7)
#Load in the address of the second value
rldicr 7, 7, 32, 31
oris 7, 7,
#Load in the second value to register 5, from the address we just loaded
ld 5, 0(7)
#Calculate the value and store into register 6
add 6, 4, 5
#Exit with the status
#system call is in register 0
#Move result into register 3 for the system call
讨论程序本身之前,先构建并运行它。构建此程序的第一步是汇编 它:
as -m64 sum.s -o sum.o
这会生成一个名为 sum.o 的文件,其中包含对象代码,这是汇编代码的机器语言版,还为连接器增加了一些附加信息。“-m64” 开关告诉汇编程序您正在使用 64 位 ABI 和 64 位指令。所生成的对象代码是此代码的机器语言形式,但无法直接按原样运行,还需要进行连接,之后操作系统才能加载并运行它。连接的方法如下:
ld -melf64ppc sum.o -o sum
这将生成可执行的 sum。要运行此程序,按如下方法操作:
这将输入 “3”,也就是最终结果。现在我们来看看这段代码的实际工作方式。
由于汇编语言代码的工作方式非常接近操作系统的级别,因此组织方式与它将生成的对象和可执行文件也很相近。那么,为了理解代码,我们首先需要理解对象文件。
对象和可执行文件划分为 “节”。程序执行时,每一节都会载入地址空间内的不同位置。它们都具有不同的保护和目的。我们需要关注的主要几节包括:
包含用于该程序的预初始化数据
包含实际代码(过去称为程序文本)
包含 “正式过程声明”,它用于辅助连接函数和指定程序的入口点(入口点就是要执行的代码中的第一条指令)
我们的程序做的第一件事就是切换到 .data 节,并将对齐量设置为 8 字节的边界(.align 3 会将汇编程序的内部地址计数器对齐为 2^3 的倍数)。
first_value: 这一行是一个符号声明。它将创建一个称为 first_value 的符号,与汇编程序中列出的下一条声明或指令的地址同义。请注意,first_value 本身是一个常量 而不是变量,尽管它所引用的存储地址可能是可更新的。first_value 只是引用内存中特定地址的一种简化方法。
下一条伪指令 .quad 1 创建一个 8 字节的数据值,容纳值 1。
之后,我们使用类似的一组伪指令定义地址 second_value,容纳 8 字节数据项,值为 2。
.section ".opd", "aw" 为我们的过程描述符创建一个 “.opd” 节。强制这一节对齐到 8 字节边界。然后将符号 _start 声明为全局符号,也就是说它在连接后不会被丢弃。然后声明 _start 腹稿本身( .globl 汇编程序未定义 _start,它只是使其在定义后成为全局符号)。接下来生成的三个数据项是过程描述符,本系列后续文章中将讨论相关内容。
现在转到实际程序代码。.text 伪指令告诉汇编程序我们将切换到 “text” 一节。之后就是 ._start 的定义。
第一组指令载入第一个值的地址,而非值本身。由于 PowerPC 指令仅有 32 位长,指令内仅有 16 位可用于加载常量值(切记,address of first_value 是常量)。由于地址最多可达到 64 位,因此我们必须采用每次一段的方式载入地址(本系列的第 2 部分将介绍如何避免这样做)。汇编程序中的 @ 符号指示汇编程序给出一个符号值的特殊处理形式。这里使用了以下几项:
表示一个常量的第 48-63 位
表示一个常量的第 32-47 位
表示一个常量的第 16-31 位
表示一个常量的第 0-15 位
所用的第一条指令表示 “载入即时移位(load immediate shifted)”。这会在最右端(first_value 的第 48-63 位)载入值,将数字移位到左边的 16 位,然后将结果存储到寄存器 7 中。寄存器 7 的第 16-31 位现包含地址的第 48-63 位。接下来我们使用 “or immediate” 指令对寄存器 7 和右端的值(first_value 的第 32-47 位)执行逻辑或运算,将结果存储到寄存器 7 中。现在地址的第 32-47 位存储到了寄存器的第 0-15 位中。寄存器
7 现左移 32 位,0-31 位将清空,结果存储在寄存器 7 中。现在寄存器 7 的第 32-63 位包含我们所载入的地址的第 32-63 位。下两条指令使用了 “or immediate” 和 “or immediate shifted” 指令,以类似的方式载入第 0-31 位。
仅仅是要载入一个 64 位值就要做许多工作。这也就是为什么 PowerPC 芯片上的大多数操作都通过寄存器完成,而不通过立即值 —— 寄存器操作可一次使用全部 64 位,而不仅限于指令的长度。下一期文章将介绍简化这一任务的寻址模式。
现在只要记住,这只会载入我们想载入的值的地址。现在我们希望将值本身载入寄存器。为此,将使用寄存器 7 去告诉处理器希望从哪个地址处载入值。在圆括号中填入 “7” 即可指出这一点。指令 ld 4, 0(7) 将寄存器 7 中地址处的值载入寄存器 4(0 表示向该地址加零)。现在寄存器 4 是第一个值。
使用类似的过程将第二个值载入寄存器 5。
加载寄存器之后,即可将数字相加了。指令 add 6, 4, 5 将寄存器 4 的内容与寄存器 5 的内容相加,并将结果存储在寄存器 6(寄存器 4 和寄存器 5 不受影响)。
既然已经计算出了所需值,接下来就要将这个值作为程序的返回/退出值了。在汇编语言中退出一个程序的方法就是发起一次系统调用(使用 exit 系统调用退出)。每个系统调用都有一个相关联的数字。这个数字会在实现调用前存储在寄存器 0 中。从寄存器 3 开始存储其余参数,系统调用需要多少参数就使用多少寄存器。然后 sc 指令使内核接收并响应请求。exit 的系统调用号是 1。因此,我们需要首先将数字 1 移动到寄存器 0 中。
在 PowerPC 机器上,这是通过加法完成的。addi 指令将一个寄存器与一个数字相加,并将结果存储在一个寄存器中。在某些指令中(包括 addi),如果指定的寄存器是寄存器 0,则根本不会加上寄存器,而是使用数字 0。这看上去有些令人糊涂,但这样做的原因在于使 PowerPC 能够为相加和加载使用相同的指令。
退出系统调用接收一个参数 —— 退出值。它存储在寄存器 3 中。因此,我们需要将我们的应答从寄存器 6 移动到寄存器 3 中。“register move” 指令 rm 3, 6 执行所需的移动操作。现在我们就可以告诉操作系统已经准备好接受它的处理了。
调用操作系统的指令就是 sc,表示 “system call”。这将调用操作系统,操作系统将读取我们置于寄存器 0 和寄存器 3 中的内容,然后退出,以寄存器 3 的内容作为返回值。在命令行中可使用命令 echo $? 检索该值。
需要指出,这些指令中许多都是多余的,目的仅在于教学。例如,first_value 和 second_value 实际上是常量,因此我们完全可以直接载入它们,跳过数据节。同样,我们也能一开始就将结果存储在寄存器 3 中(而不是寄存器 6),这样就可以免除一次寄存器移动操作。实际上,可以将寄存器同时 作为源寄存器和目标寄存器。所以,如果想使其尽可能地简洁,可将其写为如下形式:
清单 2. 第一个程序的简化版本
.section ".opd", "aw"
.global _start
.quad ._start, , 0
#load "1" into register 3
#load "2" into register 4
add 3, 3, 4
#add register 3 to register 4 and store the result in register 3
#load "1" into register 0 for the system call
查找最大值
我们的下一个程序将提供更多一点的功能 —— 查找一组值中的最大值,退出并返回结果。
在名为 max.s 的文件中键入如下代码:
清单 3. 查找最大值
###PROGRAM DATA###
#value_list is the address of the beginning of the list
value_list:
.quad 23, 50, 95, 96, 37, 85
#value_list_end is the address immediately after the list
value_list_end:
###STANDARD ENTRY POINT DECLARATION###
.section "opd", "aw"
.global _start
.quad ._start, , 0
###ACTUAL CODE###
#REGISTER USE DOCUMENTATION
#register 3 -- current maximum
#register 4 -- current value address
#register 5 -- stop value address
#register 6 -- current value
#load the address of value_list into register 4
rldicr 4, 4, 32, 31
oris 4, 4,
#load the address of value_list_end into register 5
rldicr 5, 5, 32, 31
oris 5, 5,
#initialize register 3 to 0
#MAIN LOOP
#compare register 4 to 5
#if equal branch to end
#load the next value
ld 6, 0(4)
#compare register 6 (current value) to register 3 (current maximum)
#if reg. 6 is not greater than reg. 3 then branch to loop_end
ble loop_end
#otherwise, move register 6 (current) to register 3 (current max)
#advance pointer to next value (advances by 8-bytes)
addi 4, 4, 8
#go back to beginning of loop
#set the system call number
#register 3 already has the value to exit with
#signal the system call
为汇编、连接和运行程序,执行:
as -a64 max.s -o max.o
ld -melf64ppc max.o -o max
您之前已体验了一个 PowerPC 程序,也了解了一些指令,那么应该可以看懂部分代码。数据节与上一个程序基本相同,差别只是在 value_list 声明后有几个值。注意,这不会改变 value_list —— 它依然是指向紧接其后的第一个数据项地址的常量。对于之后的数据,每个值使用 64 位(通过 .quad 表示)。入口点声明与前一程序相同。
对于程序本身,需要注意的一点就是我们记录了各寄存器的用途。这一实践将很好地帮助您跟踪代码。寄存器 3 存储当前最大值,初始设置为 0。寄存器 4 包含要载入的下个值的地址。最初是 value_list,每次遍历前进 8 位。寄存器 5 包含紧接 value_list 中数据之后的地址。这使您可以轻松比较寄存器 4 和寄存器 5,以便了解是否到达了列表末端,并了解何时需要跳转到 end。寄存器 6 包含从寄存器 4 指向的位置处载入的当前值。每次遍历时,它都会与寄存器 3(当前最大值)比较,如果寄存器 6
较大,则用它取代寄存器 3。
注意,我们为每个跳转点标记了其自己的符号化标签,这使我们能够将这些标签作为跳转指令的目标。例如,beq end 跳转到这段代码中紧接 end 符号定义之后的代码处。
要注意的另外一条指令是 ld 6, 0(4)。它使用寄存器 4 中的内容作为存储地址来检索一个值,此值随后存储到寄存器 6 中。
[原创] PowerPC 汇编入门与优化
Powerpc汇编学习之一
PowerPC寄存器指令
PowerPC汇编指令集简析-(1)
PowerPC介绍
没有更多推荐了,
(window.slotbydup=window.slotbydup || []).push({
id: "5865575",
container: s,
size: "300,250",
display: "inlay-fix"第1章 汇编语言基础习题答案_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
享专业文档下载特权
&赠共享文档下载特权
&100W篇文档免费专享
&每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
第1章 汇编语言基础习题答案
阅读已结束,下载本文需要
定制HR最喜欢的简历
你可能喜欢【图文】CPU指令及汇编练习题_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
享专业文档下载特权
&赠共享文档下载特权
&100W篇文档免费专享
&每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
CPU指令及汇编练习题
阅读已结束,下载本文到电脑
定制HR最喜欢的简历
你可能喜欢这世界里的每一个人,每一个东西,包括高山大海,刀剑风云,其本质都是一串数字流。...
ARM 汇编指令集
& & & &ARM处理器的指令集可以分为跳转指令、数据处理指令、程序状态寄存器(PSR)处理指令、加载/存储指令、协处理器指令和异常产生指令6大指令。
一、&跳转指令
&&&&&&&&跳转指令用于实现程序流程的跳转,在ARM程序中有以下两种方法可以实现程序流程的跳转
&&&&&&Ⅰ.使用专门的跳转指令;
&&&&&&Ⅱ.直接向程序计数器PC写入跳转地址值,通过向程序计数器PC写入跳转地址值,可以实现在4GB的地址空间中的任意跳转,在跳转之前结合使用MOV&&LR,PC等类似指令,可以保存将来的返回地址值,从而实现在4GB连续的线性地址空间的子程序调用。
ARM指令集中的跳转指令可以完成从当前指令向前或向后的32MB的地址空间的跳转,包括以下4条指令:
B指令的格式为:
&&&&&&B{条件}&目标地址
B指令是最简单的跳转指令。一旦遇到一个B指令,ARM处理器将立即跳转到给定的目标地址,从那里继续执行。注意存储在跳转指令中的实际值是相对当前PC&值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。它是24位有符号数,左移两位后有符号扩展为32&位,表示的有效偏移为26&位(前后32MB的地址空间)。以下指令:
B&&&&Label&&&&&&&&&&&&&;程序无条件跳转到标号Label处执行
CMP&R1,#0&&&&&&;当CPSR寄存器中的Z条件码置位时,程序跳转到标号Label处执行
BEQ&Label&&&&&&&
BL指令的格式为:
&&&&&&BL{条件}&目标地址
BL是另一个跳转指令,但跳转之前,会在寄存器R14中保存PC的当前内容,因此,可以通过将R14的内容重新加载到PC中,来返回到跳转指令之后的那个&指令处执行。该指令是实现子程序调用的一个基本但常用的手段。
以下指令:
BL&&&Label&&&&&&&&&;当程序无条件跳转到标号Label处执行时,同时将当前的&PC值保存到R14(LR)中
3、BLX指令
BLX指令的格式为:&
&&&&&&&BLX&目标地址
BLX指令从ARM指令集跳转到指令中所指定的目标地址,并将处理器的工作状态有ARM状态切换到Thumb状态,该指令同时将PC的当前内容保存到寄存器R14中。因此,当子程序使用Thumb指令集,而调用者使用ARM指令集时,可以通过BLX指令实现子程序的调用和处理器工作状态的切换。同时,子程序的返回可以通过将寄存器R14值复制到PC中来完成。
BX指令的格式为:
&&&&&&&BX{条件}&目标地址
BX指令跳转到指令中所指定的目标地址,目标地址处的指令既可以是ARM指令,也可以是Thumb指令。
二、数据处理指令
&&&&&&&&&数据处理指令可分为数据传送指令、算术逻辑运算指令&和比较指令等。
1)、数据传送指令用于在寄存器和存储器之间进行数据的双向传输;
2)、算术逻辑运算指令完成常用的算术与逻辑的运算,该类指令不但将运算结果保存在目的寄存器中,同时更新CPSR中的相应条件标志位;
3)、比较指令不保存运算结果,只更新CPSR中相应的条件标志位。
数据处理指令共以下16条。
1、MOV指令(传送)
MOV指令的格式为:
&&&&&&&&MOV{条件}{S}&目的寄存器,源操作数
MOV指令可完成从另一个寄存器、被移位的寄存器或将一个立即数加载到目的寄存器。其中S选项决定指令的操作是否影响CPSR中条件标志位的值,当没有S&时指令不更新CPSR中条件标志位的值。
指令示例:
MOV&R1,R0&&&&&&&&&&&&&&&&&&&&;将寄存器R0的值传送到寄存器R1
MOV&PC,R14&&&&&&&&&&&&&&&&&&;将寄存器R14的值传送到&PC,常用于子程序返回
MOV&R1,R0,LSL#3&&&&;将寄存器R0的值左移3位后传送到R1
2、MVN指令(求反)
MVN指令的格式为:
&&&&&&&&MVN{条件}{S}&目的寄存器,源操作数
MVN指令可完成从另一个寄存器、被移位的寄存器、或将一个立即数加载到目的寄存器。与MOV指令不同之处是在传送之前按位被取反了,即把一个被取反的值&传送到目的寄存器中。其中S决定指令的操作是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。
指令示例:
MVN&R0,#0&&&&&&&&&&&&;将&立即数0取反传送到寄存器R0中,完成后R0=-1
3、CMP指令(比较)
CMP指令的格式为:
&&&&&&&&CMP{条件}&操作数1,操作数2
CMP指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行比较,同时更新CPSR中条件标志位的值。该指令进行一次减法运算,但不存储结果,只更改条件标志位。&标志位表示的是操作数1与操作数2的关系(大、小、相等),例如,当操作数1大于操作操作数2,则此后的有GT后缀的指令将可以执行。
指令示例:
CMP&&&R1,R0&&&&&&&;将寄存器R1的值与寄存器R0的值相减,并根据&结果设置CPSR的标志位
CMP&R1,#100&&&;将寄存器R1的值与立即数100相减,并根&据结果设置CPSR的标志位
4、CMN指令(负数比较)
CMN指令的格式为:
&&&&&&&&&CMN{条件}&操作数1,操作数2
CMN指令用于把一个寄存器的内容和另一个寄存器的内容或立即数取反后进行比较,同时更新CPSR中条件标志位的值。该指令实际完成操作数1和操作数2相&加,并根据结果更改条件标志位。
指令示例:
CMN&&&R1,R0&&&&&;将寄存器R1的值与寄存器R0的值相加,并根据&结果设置CPSR&的标志位
CMN&R1,#100&&;将寄存器R1的值与立即数100相加,并根据&结果设置CPSR的标志位
5、TST指令(测试)
TST指令的格式为:
&&&&&&&TST{条件}&操作数1,操作数2
TST指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位的与运算,并根据运算结果更新CPSR中条件标志位的值。操作数1是要测试的数&据,而操作数2是一个位掩码,该指令一般用来检测是否设置了特定的位。
指令示例:
TST&&&R1,#%1&&&&&&&&&&&&;用于测试在寄存器R1中是否设置了最低位(%表&示二进制数)
TST&R1,#0xffe&&&&&&&&&&&;将寄存器R1的值与立即数0xffe按位与,并根据&结果设置CPSR的标志位
6、TEQ指令(测试相等)
TEQ指令的格式为:
&&&&&&&&TEQ{条件}&操作数1,操作数2
TEQ指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位的异或运算,并根据运算结果更新CPSR中条件标志位的值。该指令通常用于比较操作数1和操作数2是否相等。
指令示例:
TEQ&&&R1,R2&&&&&&&&&&;将寄存器R1的值与寄存器R2的值按位异或,并根据结果&设置CPSR的标志位
7、ADD指令(相加)
ADD指令的格式为:
&&&&&&&&ADD{条件}{S}&目的寄存器,操作数1,操作数2
ADD指令用于把两个操作数相加,并将结果存放到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。
指令示例:
ADD&&&&&R0,R1,R2&&&&&&&&&&&&&&&&&&;&R0&=&R1&+&R2
ADD&&&&&R0,R1,#256&&&&&&&&&&&&&&&&;&R0&=&R1&+&256
ADD&&&&&R0,R2,R3,LSL#1&&&&&&&;&R0&=&R2&+&(R3&&&&1)
8、ADC指令(带进位相加)
ADC指令的格式为:
&&&&&&&ADC{条件}{S}&目的寄存器,操作数1,操作数2
ADC指令用于把两个操作数相加,再加上CPSR中的C条件标志位的值,并将结果存放到目的寄存器中。它使用一个进位标志位,这样就可以做比32位大的数&的加法,注意不要忘记设置S后缀来更改进位标志。操作数1应是一个寄存器,操作数2可以是一&个寄存器,被移位的寄存器,或一个立即数。
以下指令序列完成两个128位数的加法,第一个数由高到低存放在寄存器R7~R4,第二个数由高到低存放在寄存器R11~R8,运算结果由高到低存放在寄&存器R3~R0:
ADDS&&&&R0,R4,R8&&&&&&&&&&;&加低端的字
ADCS&&&&R1,R5,R9&&&&&&&&&&;&加第二个字,带进位
ADCS&&&&R2,R6,R10&&&&&&&&;&加第三个字,带进位
ADC&&&&&&R3,R7,R11&&&&&&&&;&加第四个字,带进位
9、SUB指令(相减)
SUB指令的格式为:
&&&&&&&SUB{条件}{S}&目的寄存器,操作数1,操作数2
SUB指令用于把操作数1减去操作数2,并将结果存放到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令可用于有符号数或无符号数的减法运算。
指令示例:
SUB&&&&&R0,R1,R2&&&&&&&&&&&&&&&&&;&R0&=&R1&-&R2
SUB&&&&&R0,R1,#256&&&&&&&&&&&&;&R0&=&R1&-&256
SUB&&&&&R0,R2,R3,LSL#1&&&&&&;&R0&=&R2&-&(R3&&&&1)
10、~~~~C指令
~~~~C指令的格式为:
~~~~C{条件}{S}&目的寄存器,操作数1,操作数2
~~~~C指令用于把操作数1减去操作数2,再减去CPSR中的C条件标志位的反码,并将结果存放到目的寄存器中。操作数1应是一个寄存器,操作数2可以&是一个寄存器,被移位的寄存器,或一个立即数。该指令使用进位标志来表示借位,这样就可以做大于32位的减法,注意不要忘记设置S后缀来更改进位标志。该指令可用于有符号数或无符号数的减法运算。
指令示例:
SUBS&&&&R0,R1,R2&&&&&&&&;R0&=&R1&-&R2&-&!C,并根据结果设置CPSR的进位标志位
11、R~~~~指令
R~~~~指令的格式为:
R~~~~{条件}{S}&目的寄存器,操作数1,操作数2
R~~~~指令称为逆向减法指令,用于把操作数2减去操作数1,并将结果存放到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位&的寄存器,或一个立即数。该指令可用于有符号数或无符号数的减法运算。
指令示例:
R~~~~&&&&&R0,R1,R2&&&&&&&&&&&&&&&&&&&&&&&&&;&R0&=&R2&–&R1
R~~~~&&&&&R0,R1,#256&&&&&&&&&&&&&&&&&&&&&;&R0&=&256&–&R1
R~~~~&&&&&R0,R2,R3,LSL#1&&&&&&&&&&&;&R0&=&(R3&&&&1)&-&R2
12、RSC指令(反向带进位减)
RSC指令的格式为:
&&&&&&&&RSC{条件}{S}&目的寄存器,操作数1,操作数2
RSC指令用于把&操作数2减去操作数1,再减去CPSR中的C条件标志位的反码,并将结果存放到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位&的寄存器,或一个立即数。该指令使用进位标志来表示借位,这样就可以做大于32位的减法,注意不要忘记设置S后缀来更改进位标志。该指令可用于有符号数或&无符号数的减法运算。
指令示例:
RSC&&&&&R0,R1,R2&&&&&&&&&&&;R0&=&R2&–&R1&-&!C
13、AND指令(逻辑位&与)
AND指令的格式为:
&&&&&&&AND{条件}{S}&目的寄存器,操作数1,操作数2
AND指令用于在两个操作数上进行逻辑与运算,并把结果放置到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于屏蔽操作数1的某些位。
指令示例:
AND&R0,R0,#3&&&&&&&&&&;该指令保持R0的0、1位,其余位清零。
14、ORR指令(逻辑位&或)
ORR指令的格式为:
&&&&&&&&&ORR{条件}{S}&目的寄存器,操作数1,操作数2
ORR指令用于在两个操作数上进行逻辑或运算,并把结果放置到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于设置操作数1的某些位。
指令示例:
ORR&R0,R0,#3&&&&&&&&;该指令设置R0的0、1位,其余位保持不变。
15、EOR指令(逻辑位&异或)
EOR指令的格式为:
&&&&&&&&EOR{条件}{S}&目的寄存器,操作数1,操作数2
EOR指令用于在两个操作数上进行逻辑异或运算,并把结果放置到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一&个立即数。该指令常用于反转操作数1的某些位。
指令示例:
EOR&R0,R0,#3&&&&&&&&;该指令反转R0的0、1位,其余位保持不变。
16、BIC指令(位清零)
BIC指令的格式为:
&&&&&&&BIC{条件}{S}&目的寄存器,操作数1,操作数2
BIC指令用于清除操作数1的某些位,并把结果放置到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。&操作数2为32位的掩码,如果在掩码中设置了某一位,则清除这一位。未设置的掩码位保持不&变。
指令示例:
BIC&R0,R0,#%1011&&&&;该指令清除R0中的位&0、1、和&3,其余的位保持不变。
三、乘法指令与乘加指令
&&&&&&ARM&微处理器支持的乘法指令与乘加指令共有6条,可分为运算结果为32位和运算结果为64位两类,与前面的数据处理指令不同,指令中的所有操作数、目的寄存器&必须为通用寄存器,不能对操作数使用立即数或被移位的寄存器,同时,目的寄存器和操作数1必须是不同的寄存器。&
乘法指令与乘加指令共有以下6条:
1、MUL指令(相乘)
MUL指令的格式为:
&&&&&MUL{条件}{S}&目的寄存器,操作数1,操作数2
MUL指令完成将操作数1与操作数2的乘法运算,并把结果放置到目的寄存器中,同时可以根据运算结果设置CPSR中相应的条件标志位。其中,操作数1和操&作数2均为32位的有符号数或无符号数。
指令示例:
MUL&R0,R1,R2&&&&&&&&&&&&;R0&=&R1&×&R2
MULS&R0,R1,R2&&&&&&&&&&&&;R0&=&R1&×&R2,同时设置CPSR中的相关条件标志位
2、MLA指令(带累加的相乘)
MLA指令的格式为:
&&&&&MLA{条件}{S}&目的寄存器,操作数1,操作数2,操作数3
MLA指令完成将操作数1与操作数2的乘法运算,再将乘积加上操作数3,并把结果放置到目的寄存器中,同时可以根据运算结果设置CPSR中相应的条件标志&位。其中,操作数1和操作数2均为32位的有符号数或无符号数。
指令示例:
MLA&&&R0,R1,R2,R3&&&&&&&&&&&&;R0&=&R1&×&R2&+&R3
MLAS&R0,R1,R2,R3&&&&&&&&&&&&;R0&=&R1&×&R2&+&R3,同时设置CPSR中的相关条件标志位
3、SMULL指令
SMULL指令的格式为:
&&&&&SMULL{条件}{S}&&&目的寄存器Low,目的寄存器High,操作数1,操作数2
SMULL指令完成将操作数1与操作数2的乘法运算,并把结果的低32位放置到目的寄存器Low中,结果的高32位放置到目的寄存器High中,同时可以&根据运算结果设置CPSR中相应的条件标志位。其中,操作数1和操作数2均为32位的有符号数。
指令示例:
SMULL&&&R0,R1,R2,R3&&&&&;R0&=&(R2&×&R3)的低32位
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;R1&=&(R2&×&R3)的高32位
4、SMLAL指令
SMLAL指令的格式为:
&&&&SMLAL{条件}{S}&&&目的寄存器Low,目的寄存器High,操作数1,操作数2
SMLAL指令完成将操作数1与操作数2的乘法运算,并把结果的&低32位同目的寄存器Low中的值相加后又放置到目的寄存器Low中,结果的高32位同目的寄存器High中的值相加后又放置到目的寄存器High中,同&时可以根据运算结果设置CPSR中相应的条件标志位。其中,操作数1和操作数2均为32位的有符号数。
对于目的寄存器Low,在指令执行前存放64位加数的低32位,指令执行后存放结果的低32位;对于目的寄存器High,在指令执行前存放64位加数的高32位,指令执行后存放结果的高32位。
指令示例:
SMLAL&&&R0,R1,R2,R3&&&&&&&;R0&=&(R2&×&R3)的低32位&+&R0
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;R1&=&(R2&×&R3)的高32位&+&R1
5、UMULL指令
UMULL指令的格式为:
&&&&UMULL{条件}{S}&&&目的寄存器Low,目的寄存器High,操作数1,操作数2
UMULL指令完成将操作数1与操作数2的乘法运算,并把结果的低32位放置到目的寄存器Low中,结果的高32位放置到目的寄存器High中,同时可以&根据运算结果设置CPSR中相应的条件标志位。其中,操作数1和操作数2均为32位的无符号数。
指令示例:
UMULL&&&R0,R1,R2,R3&&&&&&&;R0&=&(R2&×&R3)的低32位
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;R1&=&(R2&×&R3)的高32位
6、UMLAL指令
UMLAL指令的格式为:
&&&&UMLAL{条件}{S}&&&目的寄存器Low,目的寄存器High,操作数1,操作数2
UMLAL指令完成将操作数1与操作数2的乘法运算,并把结果的&低32位同目的寄存器Low中的值相加后又放置到目的寄存器Low中,结果的高32位同目的寄存器High中的值相加后又放置到目的寄存器High&中,同&时可以根据运算结果设置CPSR中相应的条件标志位。其中,操作数1和操作数2均为32位的无符号数。
对于目的寄存器Low,在指令执行前存放64位加数的低32位,指令执行后存放结果的低32位;对于目的寄存器High,在指令执行前存放64位加数的高32位,指令执行后存放结果的高32位。
指令示例:
UMLAL&&&R0,R1,R2,R3&&&&&&&&&&&&;R0&=&(R2&×&R3)的低32位&+&R0
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;R1&=&(R2&×&R3)的高32位&+&R1
四、程序状态寄存器访问指令
1、MRS指令
MRS指令的格式为:
&&&&&&&&&MRS{条件}&&&&通用寄存器&程序状态寄存器(CPSR或SPSR)
MRS指令用于将程序状态寄存器的内容传送到通用寄存器中。该指令一般用在以下两种情况:
Ⅰ.当需要改变程序状态寄存器的内容时,可用MRS将程序状态寄存器的内容读入通用寄存器,修改后再写回程序状态寄存器。
Ⅱ.当在异常处理或进程切换时,需要保存程序状态寄存器的值,可先用该指令读出程序状态寄存器的值,然后保存。
指令示例:
MRS&R0,CPSR&&&&&&&&&&&&&&&&&&&&&&&&&;传送CPSR的内容到R0
MRS&R0,SPSR&&&&&&&&&&&&&&&&&&&&&&&&&;传送&SPSR的内容到R0
2、MSR指令
MSR指令的格式为:
&&&&&&&&MSR{条件}&&&&程序状态寄存器(CPSR或SPSR)_&域&,操作数
MSR指令用于将操作数的内容传送到程序状态寄存器的特定域中。其中,操作数可以为通用寄存器或立即数。&域&用于设置程序状态寄存器中需要&操作的位,32位的程序状态寄存器可分为4个域:
位[31:24]为条件位域,用f表示;
位[23:16]为状态位域,用s表示;
位[15:8]&为扩展位域,用x表示;
位[7:0]&&&&为控制位域,用c表示;
该指令通常用于恢复或改变程序状态寄存器的内容,在使用时,一般要在MSR指令中指明将要操作的域。
指令示例:
MSR&CPSR,R0&&&&&&&&;传送R0的内容到CPSR
MSR&SPSR,R0&&&&&&&&;传送R0的内容到SPSR
MSR&CPSR_c,R0&&&&&;传送R0的内容到SPSR,但仅仅修改CPSR中的控制位域
五、加载/存储指令
ARM微处理器支持加载/存储指令用于在寄存器和存储器之间传送数据,加载指令用于将存储器中的数据传送到寄存器,存储&指令则完成相反的操作。常用的加载存储指令如下:
1、LDR指令
LDR指令的格式为:
&&&&&&&&LDR{条件}&目的寄存器,&存储器地址&
LDR指令用于从存储器中将一个32位的字数据传送到目的寄存器中。该指令通常用于从存储器中读取32位的字数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。该指令在程序设计中比较常用,且寻址方式灵活多样,请读者认真掌握。
指令示例:
LDR&R0,[R1]&&&&&&&&&&&&&&&&;将存储器地址为R1的字数据读入寄存器R0。
LDR&R0,[R1,R2]&&&&&&&;将存储器地址为R1+R2的字数据读入寄存器R0。
LDR&R0,[R1,#8]&&&&&&&&;将存储器地址为R1+8的字数据读入寄存器R0。
LDR&R0,[R1,R2]&!&&&;将存储器地址为R1+R2的字数据读入寄存器R0,并将新地址R1+R2写入R1。
LDR&R0,[R1,#8]&!&&;将存储器地址为R1+8的字数据读入寄存器R0,并将新地址&R1+8写入R1。
LDR&R0,[R1],R2&&&&&&&&;将存储器地址为R1的字数据读入寄存器R0,并将新地址&R1+R2写入R1。
LDR&R0,[R1,R2,LSL#2]!&;将存储器地址为R1+R2×4的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。
LDR&R0,[R1],R2,LSL#2&&&&&&;将存储器地址为R1的字数据读入&寄存器R0,并将新地址R1+R2×4写入R1。
2、LDRB指令
LDRB指令的格式为:
&&&&&&&&&&&LDR{条件}B&目的寄存器,&存储器地址&
LDRB指令用于从存储器中将一个8位的字节数据传送到目的寄存器中,同时将寄存器的高24位清零。&该指令通常用于从存储器中读取8位的字节数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目&的地址,从而可以实现程序流程的跳转。
指令示例:
LDRB&R0,[R1]&&&&&&&&;将存储器地址为R1的字节数据读入寄存器R0,并将R0的高24位清零。
LDRB&R0,[R1,#8]&&&&&&&;将存储器地址为R1+8的字节数据读入寄存器R0,并将R0的高24位清零。
3、LDRH指令
LDRH指令的格式为:
&&&&&&&&&LDR{条件}H&目的寄存器,&存储器地址&
LDRH指令用于从存储器中将一个16位的半字数据传送到目的寄存器中,同时将寄存器的高16位清零。&该指令通常用于从存储器中读取16位的半字数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作&目的地址,从而可以实现程序流程的跳转。
指令示例:
LDRH&&&R0,[R1]&&&&&&&&&&&&&;将存储器地址为R1的半字数据读入寄存器&R0,并将R0的高16位清零。
LDRH&R0,[R1,#8]&&&&&;将存储器地址为R1+8的半字数据读入寄存器R0,并将R0&的高16位清零。
LDRH&R0,[R1,R2]&&&&&;将存储器地址为R1+R2的半字数据读入寄存器R0,并将&R0的高16位清零。
4、STR指令
STR指令的格式为:
&&&&&&&&STR{条件}&源寄存器,&存储器地址&
STR指令用于从源寄存器中将一个32位的字数据传送到存储器中。&该指令在程序设计中比较常用,且寻址方式灵活多样,使用方式可参考指令LDR。
指令示例:
STR&R0,[R1],#8&&&&&&&&&&&;将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1。
STR&R0,[R1,#8]&&&&&&&&&&;将R0中的字数据写入以R1+8为地址的存储器中。
5、STRB指令
STRB指令的格式为:
&&&&&&&&STR{条件}B&源寄存器,&存储器地址&
STRB指令用于从源寄存器中将一个8位的字节数据传送到存储器中。该字节数据为源寄存器中的低8位。
指令示例:
STRB&&&&R0,[R1]&&&&&&&&&&&&&;将寄存器R0中的字节数据写入以R1为地&址的存储器中。
STRB&&&&R0,[R1,#8]&&&&&;将寄存器R0中的字节数据写入以R1+8为地址的存&储器中。
6、STRH指令
STRH指令的格式为:
&&&&&&STR{条件}H&源寄存器,&存储器地址&
STRH指令用于从源寄存器中将一个16位的半字数据传送到存储器中。该半字数据为源寄存器中的低16位。
指令示例:
STRH&&&R0,[R1]&&&&&&&&&&&&;将寄存器R0中的半字数据写入以R1为地址的&存储器中。
STRH&&&R0,[R1,#8]&&&&;将寄存器R0中的半字数据写入以R1+8&为地址的存储器中。
六、批量数据加载/存储指令
&&&&&&ARM微处理器所支持批量数据加载/存储指令可以一次在一片连续的存储器单元和多个寄存器之间传送数据,批量加载指令&用于将一片连续的存储器中的数据传送到多个寄存器,批量数据存储指令则完成相反的操作。
常用的加载存储指令如下:LDM(或STM)指令
&LDM(或STM)指令的格式为:
&&&&&&&&&&&&&LDM(或STM){条件}{类型}&基址寄存器{!},寄存器列表{∧}
LDM(或STM)指令用于从由基址寄存器所指示的一片连续存储器到寄存器列表所指示的多个寄存器之间传送数据,该指令的常见用途是将多个寄存器的内容入栈或出栈。其中,{类型}为&以下几种情况:
IA&&&&每次传送后地址加1;
IB&&&&&&每次传送前地址加1;
DA&&&每次传送后地址减1;
DB&&&每次传送前地址减1;
FD&&&满递减堆栈;
ED&&&空递减堆栈;
FA&&&满递增堆栈;
EA&&&空递增堆栈;
{!}为可选后缀,若选用该后缀,则当数据&传送完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变。
基址寄存器不允许为R15,寄存器列表可以为R0~R15的任意组合。
{∧}为可选后缀,当指令为LDM且寄存器列表中包含R15,选用该后缀时表示:除了正常的数据传送之外,还将SPSR复制到CPSR。同时,该后缀还表&示传入或传出的是用户模式下的寄存器,而不是当前模式下的寄存器。
指令示例:
STMFD&R13!,{R0,R4-R12,LR}&&&&&&&&;将寄存器列表中的寄存器(R0,R4到R12,LR)存入堆栈。
LDMFD&R13!,&{R0,R4-R12,PC}&&&&&&&;将堆栈内容恢复到寄存器(R0,R4到R12,LR)。
七、数据交换指令
1、SWP指令
SWP指令的格式为:
&&&&&&&&SWP{条件}&目的寄存器,源寄存器1,[源寄存器2]
SWP指令用于将源寄存器2所指向的存储器中的字数据传送到目的寄存器中,同时将源寄存器1中的字数据传送到源寄存器2所指向的存储器中。显然,当源寄存&器1和目的寄存器为同一个寄存器时,指令交换该寄存器和存储器的内容。
指令示例:
SWP&&&R0,R1,[R2]&&&&&;将R2所指向的存储器中的字数据传送到R0,同时将R1&中的字数据传送到R2所指向的存储单元。
SWP&&&R0,R0,[R1]&&&&&;该指令完成将R1所指向的存储器中的字数&据与R0中的数据交换。
2、SWPB指令
SWPB指令的格式为:
&&&&&&&&&&&SWP{条件}B&目的寄存器,源寄存器1,[源寄存器2]
SWPB指令用于将源寄存器2所指向的存储器中的字节数据传送到目的寄存器中,目的寄存器的高24清零,同时将源寄存&器1中的字节数据传送到源寄存器2所指向的存储器中。显然,当源寄存器1和目的寄存器为同一个寄存器时,指令交换该寄存器和存储器的内容。
指令示例:
SWPB&&&R0,R1,[R2]&&&&&&&;将R2所指向的存储器中的字节数据传送到&R0,R0的高24位清零,同时将R1中的低8位数据传送到R2所指向的存储单元。
SWPB&&&R0,R0,[R1]&&&&&&;该指令完成将R1所指向的存储器中的&字节数据与R0中的低8位数据交换。
八、移位指令
1、LSL(或ASL)
LSL(或ASL)的格式为:
&&&&&&&&通用寄存器,LSL(或ASL)&操作数&&&&&&
LSL(或ASL)可完成对通用寄存器中的内容进行逻辑(或算术)的左移操作,按操作数所指定的数量向左移位,低位用零来填充。&其中,操作数可以是通用寄存器,也可以是立即数(0~31)。
MOV&&&R0,&R1,&LSL&#2&&&&&&&&&&;将R1中的内容左移两位后传送到R0&中。
LSR的格式为:
&&&&&&通用寄存器,LSR&操作数&&&&&&
LSR可完成对通用寄存器中的内容进行右移的操作,按操作数所指定的数量向右移位,左端用零来填充。其中,操作数可以&是通用寄存器,也可以是立即数(0~31)。
操作示例:&
MOV&&&R0,&R1,&LSR&#2&&&&&&&&&;将R1中的内容右移两位后传送到R0&中,左端用零来填充。
ASR的格式为:
&&&&&通用寄存器,ASR&操作数&&&&&&
ASR可完成对通用寄存器中的内容进行右移的操作,按操作数所指定的数量向右移位,左端用第31位的值来填充。其中,操作数可以是通用寄存器,也可以是立&即数(0~31)。
操作示例:
MOV&&&&R0,&R1,&ASR&#2&&&&&&&&;将R1中的内容右移两位后传送到R0&中,左端用第31位的值来填充。
ROR的格式为:
&&&&&&&&通用寄存器,ROR&操作数&&&&&&
ROR可完成对通用寄存器中的内容进行循环右移的操作,按操作数所指定的数量向右循环移位,左端用右端移出的位来填充。其中,操作数可以是通用寄存器,也&可以是立即数(0~31)。显然,当进行32位的循环右移操作时,通用寄存器中的值不改变。
操作示例:
MOV&&&&R0,&R1,&ROR&#2&&&&&&&;将R1中的内容循环右移两位后传送到R0&中。
RRX的格式为:
&&&&&&&通用寄存器,RRX&操作数&&&&&&
RRX可完成对通用寄存器中的内容进行带扩展的循环右移的操作,按操作数所指定的数量向右循环移位,左端用进位标志位C来填充。其中,操作数可以是通用寄&存器,也可以是立即数(0~31)。
操作示例:
MOV&&&R0,&R1,&RRX&#2&&&&&&&&&;将R1中的内容进行带扩展的循环右移两位&后传送到R0中。
九、协处理器指令
1、CDP指令
CDP指令的格式为:
&&&&&&&&CDP{条件}&协处理器编码,协处理器操作码1,目的寄存器,源寄存器1,源寄存器2,协处理器操作码2。
CDP指令用于ARM处理器通知ARM协处理器执行特定的操作,若协处理器不能成功完成特定的操作,则产生未定义指令异常。其中协处理器操作码1和协处理&器操作码2为协处理器将要执行的操作,目的寄存器和源寄存器均为协处理器的寄存器,指令不涉及ARM处理器的寄存器和存储器。
指令示例:
CDP&&&P3,2,C12,C10,C3,4&&&;该指令完成协处理器P3的初始化&
2、LDC指令
LDC指令的格式为:
&&&&&&&&&LDC{条件}{L}&协处理器编码,目的寄存器,[源寄存器]
LDC指令用于将源寄存器所指向的存储器中的字数据传送到目的寄存器中,若协处理器不能成功完成传送操作,则产生未定义指令异常。其中,{L}选项表示指&令为长读取操作,如用于双精度数据的传输。
指令示例:
LDC&&&P3,C4,[R0]&&&&&&&&;将ARM处理器的寄存器R0所指向的存储器中的字数&据传送到协处理器P3的寄存器C4中。&
3、STC指令
STC指令的格式为:
STC{条件}{L}&协处理器编码,源寄存器,[目的寄存器]
STC指令用于将源寄存器中的字数据传送到目的寄存器所指向的存储器中,若协处理器不能成功完成传送操作,则产生未定义指令异常。其中,{L}选项表示指&令为长读取操作,如用于双精度数据的传输。
指令示例:
STC&&&P3,C4,[R0]&&&&&;将协处理器P3的寄存器C4中的字数据传送到ARM处理&器的寄存器R0所指向的存储器中。&
4、MCR指令
MCR指令的格式为:
MCR{条件}&协处理器编码,协处理器操作码1,源寄存器,目的寄存器1,目的寄存器2,协处理器操作码2。
MCR指令用于将ARM处理器寄存器中的数据传送到协处理器寄存器中,若协处理器不能成功完成操作,则产生未定义指令异常。其中协处理器操作码1和协处理&器操作码2为协处理器将要执行的操作,源寄存器为ARM处理器的寄存器,目的寄存器1和目的寄存器2均为协处理器的寄&存器。
指令示例:
MCR&&&P3,3,R0,C4,C5,6&&&&&;将ARM处理器寄存器R0中的数据传送到协处&理器P3的寄存器C4和C5中。&
5、MRC指令
MRC指令的格式为:
MRC{条件}&协处理器编码,协处理器操作码1,目的寄存器,源寄存器1,源寄存器2,协处理器操作码2。
MRC指令用于将协处理器寄存器中的数据传送到ARM处理器寄存器中,若协处理器不能成功完成操作,则产生未定义指令异常。其中协处理器操作码1和协处理&器操作码2为协处理器将要执行的操作,目的寄存器为ARM处理器的寄存器,源寄存器1和源寄存器2均为协处理器的寄存器。
指令示例:
MRC&&&P3,3,R0,C4,C5,6&&&&&;该指令将协处理器P3的寄存器中的数据传送到&ARM处理器寄存器中。
十、异常产生指令
1、SWI指令
SWI指令的格式为:
SWI{条件}&24位的立即数
SWI指令用于产生软件中断,以便用户程序能调用操作系统的系统例程。操作系统在SWI的异常处理程序中提供相应的系统服务,指令中24位的立即数指定用&户程序调用系统例程的类型,相关参数通过通用寄存器传递,当指令中24位的立即数被忽略时,用户程序调用系统例程的类型由通用寄存器R0的内容决定,同&时,参数通过其他通用寄存器传递。&
指令示例:
SWI&&&0x02&&&&&&&&&&&&&&&&;该指令调用操作系统编号位02的系统例程。
2、BKPT指令
BKPT指令的格式为:
BKPT&&&16位的立即数
BKPT指令产生软件断点中断,可用于程序的调试。
ARM汇编伪指令
&&&&&&&在ARM汇编语言程序里,有一些特殊指令助记符,这些助记符与指令系统的助记符不同,没有相对应的操作码,通常称这些特殊指令助记符为伪指令,他们所完成的操作称为伪操作。伪指令在源程序中的作用是为完成汇编程序作各种准备工作的,这些伪指令仅在汇编过程中起作用,一旦汇编结束,伪指令的使命就完成。&&&&&
&&&&&在ARM&的汇编程序中,有如下几种伪指令:符号定义伪指令、数据定义伪指令、汇编控制伪指令、宏指令以及其他伪指令。&
一、符号定义(Symbol&Definition)伪指令&&&&
符号定义伪指令用于定义ARM&汇编程序中的变量、对变量赋值以及定义寄存器的别名等操作。&&&&
常见的符号定义伪指令有如下几种:&&&&
&&&&—&用于定义全局变量的GBLA&、GBLL&和GBLS&。&&&&
&&&&—&用于定义局部变量的LCLA&、LCLL&和LCLS&。&&&&
&&&&—&用于对变量赋值的SETA&、SETL&、SETS&。&&&&
&&&&—&为通用寄存器列表定义名称的RLIST&。&&&&
1、GBLA、GBLL&和GBLS&&&&
语法格式:&&&&
&&&&GBLA&(GBLL&或GBLS&)全局变量名&&&&
&&&&GBLA&、GBLL&和GBLS&伪指令用于定义一个ARM&程序中的全局变量,并将其初始化。其中:&&&&
&&&&GBLA&伪指令用于定义一个全局的数字变量,并初始化为0&;&&&&
&&&&GBLL&伪指令用于定义一个全局的逻辑变量,并初始化为F(假);&&&&
&&&&GBLS&伪指令用于定义一个全局的字符串变量,并初始化为空;&&&&
&&&&由于以上三条伪指令用于定义全局变量,因此在整个程序范围内变量名必须唯一。&&&&
使用示例:&&&&
&&&&GBLA&Test1&;&&&&&&&&&&&定义一个全局的数字变量,变量名为&Test1。&&&&
&&&&Test1&SETA&0xaa&;&&&将该变量赋值为0xaa。&&&&
&&&&GBLL&Test2&;&&&&&&&&&&&&定义一个全局的逻辑变量,变量名为&Test2。&&&&
&&&&Test2&SETL&{TRUE}&;将该变量赋值为真。&&&&
&&&&GBLS&Test3&;&&&&&&&&&&&&&定义一个全局的字符串变量,变量名为&Test3。&&&&
&&&&Test3&SETS&“Testing”&;将该变量赋值为&Testing”。&&
2、LCLA、LCLL&和LCLS&&&&
语法格式:&&&&
&&&&LCLA&(LCLL&或&LCLS&)局部变量名&&&&
&&&&LCLA&、LCLL&和LCLS&伪指令用于定义一个ARM&程序中的局部变量,并将其初始化。其中:&&&&
&&&&LCLA伪指令用于定义一个局部的数字变量,并初始化为0&;&&&&
&&&&LCLL伪指令用于定义一个局部的逻辑变量,并初始化为F(假);&&&&
&&&&LCLS伪指令用于定义一个局部的字符串变量,并初始化为空;&&&&
&&&&以上三条伪指令用于声明局部变量,在其作用范围内变量名必须唯一。&&&&
使用示例:&&&&
&&&&LCLA&Test4&;&&&&&&&&&&&&声明一个局部的数字变&量,变量名为Test4。&&
&&&&Test3&SETA&0xaa&;&&&将该变量赋值为0xaa。&&&
&&&LCLL&Test5&;&&&&&&&&&&&&&声明一个局部的逻辑变&量,变量名为Test5。&&&&
&&&&Test4&SETL&{TRUE}&;将该变量赋值为真。&&&&
&&&&LCLS&Test6&;&&&&&&&&&&&&&定义一个局部的字&符串变量,变量名为Test6。&&&&
&&&&Test6&SETS&“Testing”&;将该变量赋值为&&Testing”。&&&
3、SETA、SETL&和SETS&&&&
语法格式:&&&&
&&&&变量名&SETA&(SETL&或&SETS&)表达式&&&&
&&&&伪指令&SETA&、SETL&、SETS&用于给一个已经定义的全局变量或局部变量赋值。&&&&
&&&&SETA伪指令用于给一个数学变量赋值;&&&&
&&&&SETL伪指令用于给一个逻辑变量赋值;&&&&
&&&&SETS伪指令用于给一个字符串变量赋值;&&&&
&&&&其中,变量名为已经定义过的全局变量或局部变量,表达式为将要赋给变量的值。&&&&
&使用示例:&&&&
&&&&LCLA&Test3&;&&&&&&&&&&&&&声明一个局部的数字变量,变量名为&Test3。&&&&
&&&&Test3&SETA&0xaa&;&&&&将该变量赋值为0xaa。&&&&
&&&&LCLL&Test4&;&&&&&&&&&&&&&声明一个局部的逻辑变量,变量名为&Test4。&&&&
&&&&Test4&SETL&{TRUE}&;将该变量赋值为真。&&&
4&、RLIST&&&&
语法格式:&&&&
&&&&名称&RLIST&{&寄存器列表&}&&&&
RLIST伪指令可用于对一个通用寄存器列表定义名称,使用该伪指令定义的名称可在ARM&指令&LDM/STM中使用。在LDM/STM指令中,列表中的寄存器访问次序为根据寄存器的编号由低到高,而与列表中的寄存器排列次序无关。&&&&
使用示例:&&&&
&&&&RegList&RLIST&{R0-R5&,R8&,R10}&;将寄存器列表名称定义为&RegList&,可在ARM指令LDM/STM中通过该名称访问寄存器列表。&&&
二、数据定义(Data&Definition)伪指令&&&&
数据定义伪指令一般用于为特定的数据分配存储单元,同时可完成已分配存储单元的初始化。&&&&
常见的数据定义伪指令有如下几种:&&&&
&&&&—&DCB&用于分配一片连续的字节存储单元并用指定的数据初始化。&&&&
&&&&—&DCW(DCWU)用于分配一片连续的半字存储单元并用指定的数据初始化。&&&&
&&&&—&DCD&(DCDU)用于分配一片连续的字存储单元并用指定的数据初始化。&&&&
&&&&—&DCFD(DCFDU)用于为双精度的浮点数分配一片连续的字存储单元并用指定的数据初始化。&&&&
&&&&—&DCFS(DCFSU)用于为单精度的浮点数分配一片连续的字存储单元并用指定的数据初始化。&&&&
&&&&—&DCQ(DCQU)用于分配一片以8字节为单位的连续的存储单元并用指定的数据初始化。&&&&
&&&&—&SPACE&用于分配一片连续的存储单元。&&&&
&&&&—&MAP&用于定义一个结构化的内存表首地址。&&&&
&&&&—&FIELD&用于定义一个结构化的内存表的数据域。&&&
1、DCB&&&&
&&&&语法格式:&&&&
&&&&标号&DCB&表达式&&&&
&&&&DCB伪指令用于分配一片连续的字节存储单元并用伪指令中指定的表达式初始化。其中,表达式可以为0~255的数字或字符串。DCB&也可用“=”代替。&&&&
&&&&使用示例:&&&&
&&&&Str&DCB&“This&is&a&test”&;分配一片连续的字节存储单元并初始化。&
2、DCW(或DCWU)&&&&
&&&&语法格式:&
&&&&标号&DCW&(或DCWU)&表达式&&&&
&&&&DCW(或DCWU)伪指令用于分配一片连续的半字存储单元并用伪指令中指定的表达式初始化。&&&&
&&&&其中,表达式可以为程序标号或数字表达式。&&
&&&&用DCW分配的字存储单元是半字对齐的,而用DCWU分配的字存储单元并不严格半字对齐。&&&&
&&&&使用示例:&&&&
&&&&DataTest&DCW&1&,2&,3&;分配一片连续的半字存储单元并初始化。&&&&
3、DCD(或DCDU)&&&&
&&&&语法格式:&&&&
&&&&标号&DCD(或DCDU)&表达式&&&&
&&&&DCD(或DCDU)伪指令用于分配一片连续的字存储单元并用伪指令中指定的表达式初始化。其中,表达式可以为程序标号或数字表达式。DCD也可&用&&”&代替。&&&&
&&&&用DCD分配的字存储单元是字对齐的,而用DCDU分配的字存储单元并不严格字对齐。&&&&
&&&&使用示例:&&&&
&&&&DataTest&DCD&4&,5&,6&;分配一片连续的字存储单元并初始化。&
4、DCFD(或DCFDU)&&&&
&&&&语法格式:&&&&
&&&&标号&DCFD(或DCFDU)&表达式&&&&
&&&&DCFD(或DCFDU)伪指令用于为双精度的浮点数分配一片连续的字存储单元并用伪指令中指定的表达式初始化。每个双精度的浮点数占据两个字单元。用&DCFD分配的字存储单元是字对齐的,而用DCFDU分配的字存储单元并不严格字对齐。&&&&
&&&&使用示例:&&&&&&&FDataTest&DCFD&2E115&,-5E7&;分配一片连续的字存储单元并初始化&为指定的双精度数。&&&&
5、DCFS(或DCFSU)&&&&
&&&&语法格式:&&&&
&&&&标号&DCFS(或DCFSU)&表达式&&&&
&&&&DCFS(或DCFSU)伪指令用于为单精度的浮点数分配一片连续的字存储单元并用伪指令中指定的表达式初始化。每个单精度的浮点数占据一个字单元。用&DCFS分配的字存储单元是字对齐的,而用DCFSU分配的字存储单元并不严格字对齐。&&&&
&&&&使用示例:&&&&
&&&&FDataTest&DCFS&2E5&,-5E&-7&;分配一片连续的字存储单元并初始化为&指定的单精度数。&&&&
6、DCQ(或DCQU)&&&&
&&&&语法格式:&&&&
&&&&标号&DCQ(或DCQU)&表达式&&&&
&&&&DCQ(或DCQU)伪指令用于分配一片以8个字节(双字)为单位的连续存储区域并用伪指令中指定的表达式&初始化。&用DCQ分配的存储单元是字对齐的,而用DCQU&分配的存储单元并不严格字对齐。&&&&
&&&&使用示例:&&&&
&&&&DataTest&DCQ&100&;分配一片连续的存储单元并初始化为指定的值。&
7、SPACE&&&&
&&&&语法格式:&&&&
&&&&标号&SPACE&表达式&&&&
&&&&SPACE伪指令用于分配一片连续的存储区域并初始化为0&。其中,表达式为要分配的字节数。&&&&
&&&&SPACE也可用“&%&”代替。&&&&
&&&&使用示例:&&&&
&&&&DataSpace&SPACE&100&;分配连续100字节的存储单元并初始化为0&。&&&&
8、MAP&&&&
&&&&语法格式:&&&&
&&&&MAP&表达式&{&,基址寄存器&}&&&&
&&&&MAP伪指令用于定义一个结构化的内存表的首地址。MAP也可用“^”&代替。&&&&
&&&&表达式可以为程序中的标号或数学表达式,基址寄存器为可选项,当基址寄存器选项不存在时,表达式的值即为内存表的首地址,当该选项存在时,内存表的首地址&为表达式的值与基址寄存器的和。&&&&
&&&&MAP伪指令通常与FIELD伪指令配合使用来定义结构化的内存表。&&&&
&&&&使用示例:&&&&
&&&&MAP&0x100&,R0&;定义结构化内存表首地址的值为0x100+R0&。&
9、FILED&&&&
&&&&语法格式:&&&&
&&&&标号&FIELD&表达式&&&&
&&&&FIELD伪指令用于定义一个结构化内存表中的数据域。FILED&也可用“#”&代替。&&&&
&&&&表达式的值为当前数据域在内存表中所占的字节数。&&&&
&&&&FIELD伪指令常与MAP伪指令配合使用来定义结构化的内存表。MAP伪指令定义内存表的首地址,FIELD伪指令定义内存表中的各个数据域,并可以为&每个数据域指定一个标号供其他的指令引用。&&&&
&&&&注意MAP和FIELD伪指令仅用于定义数据结构,并不实际分配存储单元。&&&&
&&&&使用示例:&&&&
&&&&MAP&0x100&;&定义结构化内存表首地址的值为0x100。&&&&
&&&&A&FIELD&16&;&定义A的长度为16字节,位置为0x100。&&&&
&&&&B&FIELD&32&;&定义B的长度为32字节,位置为0x110。&&&&
&&&&S&FIELD&256&;定义S的长度为256字节,位置为0x130。&&&
三、汇编控制(Assembly&Control)伪指令&&&&
汇编控制伪指令用于控制汇编程序的执行流程,常用的汇编控制伪指令包括以下几条:&&&&
&&&&—&IF&、ELSE&、ENDIF&&&&
&&&&—&WHILE&、WEND&&&&
&&&&—&MACRO&、MEND&&&&
&&&&—&MEXIT&
1、IF、ELSE、ENDIF&&&&
语法格式:&&&&
& & IF&逻辑表达式&&&&
&&&&指令序列&1&&&&
&&&&ELSE&&&&
&&&&指令序列&2&&&&
&&&&ENDIF&&&&
&&&&IF&、ELSE&、ENDIF伪指令能根据条件的成立与否决定是否执行某个指令序列。当IF后面的逻辑表达式为真,则执行指令序列1&,否则执行指令序列2&。其中,ELSE及指令序列2可以没有,此时,当IF后面的逻辑表达式为真,则执行指令序列1&,否则继续执行后面的指令。&&&&
&&&&IF&、ELSE&、ENDIF伪指令可以嵌套使用。&&&&
&&&&使用示例:&&&&
&&&&GBLL&Test&;声明一个全局的逻辑变量,变量名为Test&&&
&&&&IF&Test&=&TRUE&&&&
&&&&指令序列&1&&&&
&&&&ELSE&&&&
&&&&指令序列&2&&&&
&&&&ENDIF&&&&
2、WHILE、WEND&&&&
语法格式:&&&&
& & WHILE&逻辑表达式&&&&
&&&&指令序列&&&&
&&&&WEND&&&&
&&&&WHILE&、WEND伪指令能根据条件的成立与否决定是否循环执行某个指令序列。当WHILE后面的逻辑表达式为真,则执行指令序列,该指令序列执行完毕后,再判断&逻辑表达式的值,若为真则继续执行,一直到逻辑表达式的值为假。&&&&
&&&&WHILE&、WEND伪指令可以嵌套使用。&&&&
使用示例:& &&
&&&&GBLA&Counter&;&&&声明一个全局的数学变量,变量名为Counter&&&&
&&&&Counter&SETA&3&;由变量Counter&控制循环次数&&&&
&&&&……&&&&
&&&&WHILE&Counter&&&10&&&&
&&&&指令序列&&&&
&&&&WEND&&&&
3、MACRO、MEND&&&&
语法格式:&&&&
&&&&$&标号&宏名&$&参数&1&,$&参数&2&,……&&&&
&&&&指令序列&&&&
&&&&MEND&&&
&&&&MACRO&、MEND伪指令可以将一段代码定义为一个整体,称为宏指令,然后就可以在程序中通过宏指令多次调用该段代码。其中,$标号在宏指令被展开时,标号会被替&换为用户定义的符号,宏指令可以使用一个或多个参数,当宏指令被展开时,这些参数被相应的值替换。&&&&
&&&&宏指令的使用方式和功能与子程序有些相似,子程序可以提供模块化的程序设计、节省存储空间并提高运行速度。但在使用子程序结构时需要保护现场,从而增加了&系统的开销,因此,在代码较短且需要传递的参数较多时,可以使用宏指令代替子程序。&&&&
&&&&包含在MACRO和MEND之间的指令序列称为宏定义体,在宏定义体的第一行应声明宏的原型(包含宏名、所需的参数),然后就可以在汇编程序中通过宏名来&调用该指令序列。在源程序被编译时,汇编器将宏调用展开,用宏定义中的指令序列代替程序中的宏调用,并将实际参数的值传递给宏定义中的形式参数。&&&
&&&&MACRO、MEND伪指令可以嵌套使用。&&&
4、MEXIT&&&&
语法格式:&&&&
& & MEXIT&&&&
&&&&MEXIT用于从宏定义中跳转出去。&&
四、其他常用的伪指令&&&&
还有一些其他的伪指令,在汇编程序中经常会被使用,包括以下几条:&&&&
&&&&—&AREA
&&&&—&ALIGN&&&&
&&&&—&CODE16&、CODE32&&&&
&&&&—&ENTRY&&&&
&&&&—&END&&&&
&&&&—&EQU&&&&
&&&&—&EXPORT(或GLOBAL&)&&&&
&&&&—&IMPORT&&&&
&&&&—&EXTERN&&&&
&&&&—&GET(或INCLUDE&)&&&&
&&&&—&INCBIN&&&&
&&&&—&RN&&&&
&&&&—&ROUT&&&&
1、AREA&&&&
语法格式:&&&&
&&&&AREA&段名&属性1&,属性2&,……&&&&
&&&&AREA伪指令用于定义一个代码段或数据段。其中,段名若以数字开头,则该段名需用“|”括起来,如:|1_test|&。&&&&
&&&&属性字段表示该代码段(或数据段)的相关属性,多个属性用逗号分隔。常用的属性如下:&&&&
&&&&—&CODE&属性:用于定义代码段,默认为READONLY&。&&&&
&&&&—&DATA&属性:用于定义数据段,默认为READWRITE&。&&&&
&&&&—&READONLY&属性:指定本段为只读,代码段默认为READONLY&。&&&&
&&&&—&READWRITE&属性:指定本段为可读可写,数据段的默认属性为READWRITE&。&&&&
&&&&—&ALIGN&属性:使用方式为ALIGN表达式。在默认时,ELF(可执行连接文件)的代码段和数据段是按字对齐的,表达式的取值范围为0~31,相应的对齐方式为2&表达式次方。&&&&
&&&&—&COMMON&属性:该属性定义一个通用的段,不包含任何的用户代码和数据。各源文件中同名的COMMON段共享同一段存储单元。&
&&&&一个汇编语言程序至少要包含一个段,当程序太长时,也可以将程序分为多个代码段和数据段。&&&&
&&&&使用示例:&&&&
AREA&Init&,CODE&,READONLY&;&&&该伪指令定义了一个代码段,段&名为Init&,属性为只读。&&&&
2、ALIGN&&&&
&语法格式:&&&&
&&&&ALIGN&{&表达式&{&,偏移量&}}&&&&
&&&&ALIGN伪指令可通过添加填充字节的方式,使当前位置满足一定的对齐方式。其中,表达式的值用于指定对齐方式,可能的取值为2的幂,如1&、2&、4&、8&、16&等。若未指定表达式,则将当前位置对齐到下一个字的位置。偏移量也为一个数字表达式,若使用该字段,则当前位置的对齐方式为:2的表达式次幂+偏移&量。&&&&
&&&&使用示例:&&&&
&&&&AREA&Init&,CODE&,READONLY&,ALIEN=3&;指定后面的指令为8&字节对齐。&&&&
&&&&指令序列&&&&
&&&&END&&&&
3、CODE16、CODE32&&&&
语法格式:&&&&
&&&&CODE16(或CODE32)&&&&
&&&&CODE16伪指令通知编译器,其后的指令序列为16位的Thumb指令。&&&&
&&&&CODE32伪指令通知编译器,其后的指令序列为32位的ARM指令。&&&&
&&&&若在汇编源程序中同时包含ARM指令和Thumb指令时,可用CODE16伪指令通知编译器其后的指令序列为16位的Thumb指令,CODE32伪指令&通知编译器其后的指令序列为32位的ARM指令。因此,在使用ARM指令和Thumb指令混合编程的代码里,可用这两条伪指令进行切换,但注意他们只通知&编译器其后指令的类型,并不能对处理器进行状态的切换。&&&&
&&&&使用示例:&&&&
&&&&AREA&Init&,CODE&,READONLY&&&&&&&……&&&&
&&&&CODE32&;&&&&&&&&&&&&&&&&&&&&通知编译器其后的指令为32位的&ARM指令&&&&
&&&&LDR&R0&,=NEXT+1&;将跳转地址放入寄存器R0&&&&
&&&&BX&R0&;&&&&&&&&&&&&&&&&&&&&&&&&&程序跳转到新的位置执行,&并将处理器切换到Thumb工作状态&&&&
&&&&……&&&&
&&&&CODE16&;&&&&&&&&&&&&&&&&&&&&&通知编译器其后的指令为16位的&Thumb指令&&&&
&&&&NEXT&LDR&R3,=0x3FF&&&&
&&&&……&&&
&&&&END&;
4、ENTRY&&&&
语法格式:&&&&
&&&&ENTRY&&&&
&&&&ENTRY伪指令用于指定汇编程序的入口点。在一个完整的汇编程序中至少要有一个ENTRY(也可以有多个,当有多个ENTRY时,程序的真正入口点由链&接器指定),但在一个源文件里最多只能有一个ENTRY(可以没有)。&&&&
&&&&使用示例:&&&&
&&&&AREA&Init&,CODE&,READONLY&&&&
&&&&ENTRY&;&指定应用程序的入口点&&&&
&&&&……&&&&
5、END&&&&
语法格式:&&&&
&&&&END&&&&
&&&&END伪指令用于通知编译器已经到了源程序的结尾。&&&&
&&&&使用示例:&&&&
&&&&AREA&Init&,CODE&,READONLY&&&&
&&&&……&&
&&&&END&;指定应用程序的结尾&&&
6、EQU&&&&
语法格式:&&&&
&&&&名称&EQU&表达式&{&,类型&}&&&&
&&&&EQU伪指令用于为程序中的常量、标号等定义一个等效的字符名称,类似于C语言中的#define&。其中EQU可用“*”代替。名称为EQU伪指令定义的字符名称,当表达式为32位的常量时,可以指定&表达式的数据类型,可以有以下三种类型:&&&&
&&&&CODE16&、CODE32&和DATA&&&&
&&&&使用示例:&&&&
&&&&Test&EQU&50&;&&&&&&&&&&&&&&&&&&&&&&&定义标号Test&的值为50。&&&&
&&&&Addr&EQU&0x55&,CODE32&;&定义Addr的值为0x55&,且该处为32位的ARM指令。&&&&
7、EXPORT(或GLOBAL)&&&&
语法格式:&&&&
&&&&EXPORT&标号&{[WEAK]}&&&&
&&&&EXPORT伪指令用于在程序中声明一个全局的标号,该标号可在其他的文件中引用。EXPORT&可用GLOBAL代替。标号在程序中区分大小写,[WEAK]&选项声明其他的同名标号优先于该标号被引用。&&&&
&&&&使用示例:&&&&
&&&&AREA&Init&,CODE&,READONLY&&&&
&&&&EXPORT&Stest&;声明一个可全局引用的标号Stest&&&
&&&&END&&&&
8、IMPORT&&&&
语法格式:&&&&
&&&&IMPORT&标号&{[WEAK]}&&&&
&&&&IMPORT伪指令用于通知编译器要使用的标号在其他的源文件中定义,但要在当前源文件中引用,而且无论当前源文件是否引用该标号,该标号均会被加入到当前源文件的符号表中。标&号在程序中区分大小写,[WEAK]&选项表示当所有的源文件都没有定义这样一个标号时,编译器也不给出错误信息,在多数情况下将该标号置为0&,若该标号为B或BL指令引用,则将B或BL指令置为NOP操作。&&&&
&&&&使用示例:&&&&
&&&&AREA&Init&,CODE&,READONLY&&&&
&&&&IMPORT&Main&;通知编译器当前文件要引用标号Main,但Main在其他源文件中定&义。&
&&&&END&&&&
9、EXTERN&&&&
语法格式:&&&&
&&&&EXTERN&标号&{[WEAK]}&&&&
&&&&EXTERN伪指令用于通知编译器要使用的标号在其他的源文件中定义,但要在当前源文件中引用,如果当前源文件实际并未引用该标号,该&标号就不会被加入到当前源文件的符号表中。标号在程序中区分大小写,&[WEAK]&选项表示当所有的源文件都没有定义这样一个标号时,编译器也不给出错误信息,在多数情况下将该标号置为0&,若该标号为B或BL指令引用,则将B或BL指令置为NOP操作。&&&&
&&&&使用示例:&&&&
&&&&AREA&Init&,CODE&,READONLY&&&&
&&&&EXTERN&Main&;通知编译器当前文件要引用标号Main,但Main在其他源文件中定&义。&&&
&&&&END&&&&
10、GET(或INCLUDE)&&&&
语法格式:&&&&
&&&&GET&文件名&&&&
&&&&GET伪指令用于将一个源文件包含到当前的源文件中,并将被包含的源文件在当前位置进行汇编处理。可&以使用INCLUDE代替GET。&&&&
&&&&汇编程序中常用的方法是在某源文件中定义一些宏指令,用EQU定义常量的符号名称,用MAP和FIELD定义结构化的数据类型,然后用GET伪指令将这个&源文件包含到其他的源文件中。使用方法与C&语言中的&include”&相似。&&&&
&&&&GET伪指令只能用于包含源文件,包含目标文件需要使用INCBIN伪指令&&&&
&&&&使用示例:&&&&
&&&&AREA&Init&,CODE&,READONLY&&&&
&&&&GET&a1.s&;&&&&&&&&通知编译器当前源文件包含源文件a1.s&&&&
&&&&GET&C:\a2.s&;&通知编译器当前源文件包含源文件C:\a2.s&
&&&&END&&&
11、INCBIN&&&&
&语法格式:&&&&
&&&&INCBIN&文件名&&&&
&&&&INCBIN伪指令用于将一个目标文件或数据文件包含到当前的源文件中,被包含的文件不作任何变动的存放在当前文件中,编译器从其后开始继续处理。&&&&
&&&&使用示例:&&&&
&&&&AREA&Init&,CODE&,READONLY&&&&
&&&&INCBIN&a1.dat&;&&&&&通知编译器当前源文件包含文件a1.dat&&&&
&&&&INCBIN&C:\a2.txt&;通知编译器当前源文件包含文件C:\a2.txt&&
&&&&END&&&&
12、RN&&&&
语法格式:&&&&
&&&&名称&RN&表达式&&&&
&&&&RN伪指令用于给一个寄存器定义一个别名。采用这种方式可以方便程序员记忆该寄存器的功能。其中,名称为给寄存器定义的别名,表达式为寄存器的编码。&&
&&&&使用示例:&&&&
&&&&Temp&RN&R0&;将R0定义一个别名Temp&&&&
13、ROUT&&
&&&&语法格式:&&&&
&&&&{名称}&ROUT&&&&
&&&&ROUT伪指令用于给一个局部变量定义作用范围。在程序中未使用该伪指令时,局部&变量的作用范围为所在的AREA,而使用ROUT后,局部变量的作为范围为当前ROUT和下一个ROUT之间。
&3.&BNE&与&&BEQ
TST&&&&&R0,&#0X8
BNE&&&&SuspendUp&;BNE指令是“不相等(或不为0)跳转指令”:&
LDR&&&R1,#0x
先进行and运算,如果R0的第四位不为1,则结果为零,则设置zero=1(继续下面的LDR指令);
否则,如果R0的第四位为1,zero=0(跳到SuspendUp处执行)。
tst&和bne连用:&先是用tst进行位与运算,然后将位与的结果与0比较,如果不为0,则跳到bne紧跟着的标记(如bne&sleep,则跳到sleep处)。
tst&和beq连用:&先是用tst进行位与运算,然后将位与的结果与0比较,如果为0,则跳到beq紧跟着的标记(如bne&AAAA,则跳到AAAA处)。
ARM的六大类指令集---LDR、LDRB、LDRH、LDM、STR、STRB、STRH、STM
ARM 指令集 之 PUSH and POP
ARM汇编指令
ARM学习笔记4
ARM汇编指令汇总
ARM指令集详解(超详细!带实例!)
嵌入式Linux ARM汇编(三)——ARM汇编指令
ARM 最基本指令运算
没有更多推荐了,
(window.slotbydup=window.slotbydup || []).push({
id: "5865575",
container: s,
size: "300,250",
display: "inlay-fix"}

我要回帖

更多关于 处理器执行指令的过程 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信