所有关于电路
技术文章

如何编写汇编语言:基本汇编指令在ARM指令集

2019年2月8日通过斯蒂芬·圣迈克尔

学习一些基本的指令用于ARM指令集用于编程ARM内核。

学习一些基本的指令用于ARM指令集用于编程ARM内核。

本文旨在帮助您了解ARM核心编程的基本汇编指令。

我们将从以前的帖子手臂注册文件-请考虑审核信息在继续之前,我们会参考注册外延和寄存器国旗在下面的说明。

这些信息将在下一篇文章中用于程序覆盆子π,它使用一个32位的ARM核心。在本文中,我们将集中我们的注意力在32位v7指令和32位寄存器。

注意:以后版本的覆盆子π,Raspbian运行,使用一个64位ARMv8处理器,但在32位模式下运行它就像老v7版本。在以后的文章中我们可能覆盖ARMv8。

支持信息:

机器代码

使用指令processor-let的看一眼代表的机器代码指令。因为大多数的指示我们将进行数据操作,我抓起数据处理指令的v7手册

图1所示。部门数据处理指令

图1显示了32位中发现一只手臂数据处理指令;每一位都有一个特定的目的,单独或一组的一部分。

条件字段是4位宽,大约有15个条件代码。操作码是4位宽,坐在之间的直接标志,表明操作数2拥有立即值,将标志,我们可以使用更新操作期间状态寄存器(稍后将详细介绍这些)。注意到它的操作码,决定了这样的项目,减法,或者独家或处理器将执行。

经过下面的说明,我们将参考图1和尝试看看汇编指令被编码成二进制。不要害怕挖掘臂手动的更多信息。

如何阅读汇编指令:助记符和操作数

每一个指令开始助记符表示一个操作。助记符后的操作数将动手术。这些通常是目标和源操作数所示。

助记符DEST, SRC1 SRC2

添加指令(在后面的一节)R2增加R1和将导致寄存器R0(见前一篇文章的解释这些外延)。这是典型的方式阅读汇编指令。增加R1和R2 (R0的结果)。相当于将执行的机器代码处理器显示与加法指令。

电导率的字段包含“1110”总是执行。这些使用条件时发挥作用后缀附加到添加操作。下一个字段是未使用和设置为0。“我”字段是零,因为“Op2”是一个注册并不是一个直接的价值。“年代”字段是零,因为我们没有添加一个年代添加操作,即。,我们不希望这个指令更新状态寄存器旗帜(N Z, C, V,上面所讨论的)。

如果你回头参照图1,注意添加的操作码。0100 b。这告诉处理器设置datapath公司的添加操作。最后三个字段是R1 (0001 b), R0 (0000 b),和R2 (….0010b)。

气孔导度我OpCd S Rn Rd Op2

添加R0, R1, R2 @ 1110 | 00 | 0 | 0100 | 0 | 0001 | 0000 | 000000000010

操作数在一条指令通常是注册,但他们也可以内存地址或直接值。立即使用价值是一个确切的数字。这些都是用#符号前缀。例如,而不是使用R2,上图,我们可以使用当前值42。这说明如下所示:

气孔导度我OpCd S Rn Rd Op2

增加了R4, R6, 42 # @ 1110 | 00 | 1 | 0100 | 1 | 0110 | 0100 | 000000101010

这个指令增加42在R4 R6并将结果。这次“我”设置为1,因为我们使用的是立即值操作数2。操作码是一样的因为我们还在做加法。注意到“S”字段是1;所以我们希望这个添加操作来更新我们的状态寄存器旗帜在执行期间。

下一个指令可以使用电导率的字段检查状态标志,有条件地执行基于结果。“Rn”是0110 b,代表R6,和R4 Rd是0100 b。的直接价值Op2是42号的12位二进制表示。本节的其余部分列出了最基本的ARM指令的一个子集,一个简短的描述和例子。

数据处理指令

下面的指示操作数据。这可以执行数学函数的算术运算,比较操作或数据移动。

除了(添加)

(添加)R2增加R1和R0的结果。除了携带(ADC)增加了R2 R1,随着携带国旗。这是与数字打交道时使用超过一个32位的字。

添加R0, R1, R2

ADC R0、R1、R2

减法(子)

减法(子)减去从R1和R2 R0的结果。减法与携带(SBC)减去从R1和R2,如果携带标志被清除,减去一个结果。这相当于借入算术和确保多词减法的正常工作。

子R0、R1、R2

SBC R0、R1、R2

比较(CMP)和比较消极(复合材料)

比较(CMP)和负(复合材料)比较两个操作数进行比较。CMP减去R1 R0和复合材料增加了R1的R2,然后更新状态标志根据加法或减法的结果。

CMP R0, R1

复合材料R1, R2

移动(MOV)

此举(MOV)操作这听起来像什么。数据从一个地方移动到另一个地方。下面,R1复制到R0。第二行把立即8成R0值。

MOV R0, R1

MOV R0, # 8

移动负面(MVN)

移动- (MVN)执行类似的操作,但补充(反转)的数据。这是有用的执行操作时负数,特别是与二进制补码表示法。下面的指令不是8,即9日R0。添加一个结果,你已经完成了两个补充和获得8。

MVN R0, # 8

和执行逐位和R2和R1和R0的结果。立即R2值可以用来代替。

R0, R1, R2

奥尔和三次采油

奥尔和三次采油执行逐位XOR, R2和R1的分别。

奥尔R0、R1、R2

三次采油R0, R1, R2

一些明确的(BIC)

一些明确的(BIC)执行逐位和R2和R1,但首先补充R2的比特。这个操作通常是使用直接值,在第二行,直接值,0 xff倒,随后将之与R1。进行“与”操作的第一个字节八0 R1将清除这些位,即。,他们等于零,结果将在R0。

BIC R0、R1、R2

BIC R0, R1, # 0 xff

测试部分(TST)和测试等价(可)

测试部分(TST)和测试等价(可)存在测试位位于寄存器。这些指令不使用目的寄存器,而只是根据结果更新状态寄存器。测试执行逐位和两个操作数。通过使用一个面具两个操作数,我们可以测试如果个体在R0设置。

在这种情况下,我们校验位3(位掩码= 1000 b = 8)和基于结果设置Z标志。可执行类似的功能,异或和非常适合检查是否两个寄存器是相等的。这个更新N和Z国旗,因此它也数字签署工作;N设置为1,如果他们是不同的迹象。

结核菌素R0, # 8

可R1, R2

乘法(MUL)

乘法(MUL)繁殖R1, R2并将R0中的结果。乘法不能立即使用价值。

MUL R0、R1、R2

指令移动和旋转

逻辑左移位(LSL)

逻辑左移位(LSL)转变R1的比特值转变。在这种情况下,立即值3,最重要的部分。转移的最后一点是放入携带国旗,和最低有效位充满了0。下面,R1被立即值3,左移或值介于0到31日在R2和R0。一个逻辑左移两位乘以一个值。这是一种并不昂贵的方式做简单的乘法。

LSL R0, R1, # 3

LSL R0, R1, R2

逻辑右移(LSR)

逻辑右移(LSR)工作在反向时尚LSL和由两个有效地将一个值。最重要的部分充满了0,最后最低有效位是放入携带国旗。

LSR R0, R1, # 2

算术右移(ASR)

算术右移(ASR)执行相同的工作LSR但是是专为数字签名。它复制符号位回过去的位置在左边。

ASR R0, R1, # 4

向右旋转(ROR)

向右旋转(ROR)旋转的所有比特一个单词,一些价值。而不是用0填充左边的位,位转移只是把回另一端。


ROR R0, R1, # 5

为分支操作指令

一个处理器的一个重要功能是两个代码路径之间的选择的能力基于一组输入。这正是分支操作。通常一个处理器执行一条指令后,通过增加R15,程序计数器(PC),由四个字节(即。一个单指令的长度)。分支改变了个人电脑到另一个位置用一个标签代表的汇编代码。

分支(B)

分支(B)移动指定的电脑一个地址标签。标签(在下面的例子中“循环”)代表一段代码,处理器执行下一个。标签仅仅是文本,通常是一个有意义的词。

B循环

分支链接(提单)

分支链接(提单)执行类似的操作,但它下一条指令的地址复制到R14、链接寄存器(LR)。这是伟大的在执行子程序/过程调用,因为一旦完成部分代码的标签我们可以使用LR回到分支。下面,我们部门的标签“子程序”,然后使用链接寄存器回到下一个指令。

提单子例程

子程序:

MOV PC, LR

我们使用一个MOV指令把链接寄存器回程序计数器。这返回程序的子程序调用之后,标记 。注意使用LR和电脑上面。ARM汇编器识别这些R14、R15分别。这提供了一个方便的提醒程序员所执行的操作。

加载和存储指令

计算机的内存存储数据所需的处理器。访问这些数据通过使用一个地址。首先将一个地址注册,我们可以访问的数据的地址。这就是为什么我们使用加载和存储操作。

加载寄存器(异地恋)

加载寄存器(LDR)加载数据位于一个地址到目的寄存器。寄存器的括号R1表示包含一个地址。通过使用括号我们把地址R0的数据,而不是地址。我们也可以用这个符号来定位数据抵消从某个地址,在第二行所示。R0将包含数据R1包含两个单词远离任何地址。

异地恋R0, (R1)

异地恋R0, R1, # 8

我们也可以使用标签来表示一个地址,和相应的数据可以被加载到一个寄存器。下面第一行的加载地址标签为R0“信息”。的值存储在该地址然后访问和R1在第二行。

异地恋R0, = info

异地恋R1 (R0)

存储(STR)

存储(STR)执行补充操作负荷。STR把寄存器的内容到一个内存位置。下面的代码将数据存储在R1在R0的地址。再次,方括号表示R0拥有一个地址,我们想修改数据地址。

STR R1 (R0)

加载和存储类型:字节(B),半字(H)、词(省略),签署(某人),无符号(B)

加载和存储都可以用一种附加到他们。这种表示指令是否操纵一个字节(B),半字(H),或词(省略)和数据是否签署(某人)或无符号(B)。

一个地方这对字符串操作可能派上用场,ASCII字符长度为一个字节。这些操作也允许使用偏移加载或存储时,见最后一行。

异地恋R0, = @ 32位地址加载到R0文本

STRB R1 (R0) @字节存储在内存的地址

STRB R1 (R0, + R2) @存储字节地址+ R2抵消

说明条件

正如前面提到的,使用的助记符指令代码附加到他们可以有可选条件。这允许有条件执行。

记住,旗帜(在前一篇文章)Z (zero)、C (c进行)、N (n它的),和V (overflow)。

强制指令更新状态寄存器,一个可选的年代可以附加到迄今为止最助记符提到。一旦更新状态寄存器,许多有条件的后缀,如下所示,可以用来控制指令是否执行。这些后缀对应的二进制代码的前四位数据处理指令如上所示(参见图1)。


图2。条件后缀

这些后缀添加到编写装配时助记符。下面的清单显示了几个条件后缀使用前面提到的指令。

因为我们会组装GNU汇编在下一篇文章中,我们需要使用@符号来表示一个评论。

.global的地方

开始:

MOV R0, # 3 @ 3成R0值

MOV R1, @ # 0 0的值放入R1

循环:

CMP R0, R1 @比较R1 R0(有效R0 - R1)

说真的做@如果他们相等(Z = 1)部门做标签

ADDGT R1, # 1 @如果R0大于R1 R1加1

SUBLT R1, # 1 @如果R0小于R1减去1 R1

B循环@分支,重新运行循环

完成:

@做其他东西


希望这篇文章能给你一个基本的理解基本指令用于手臂核心程序。在下一篇文章中,我们将使用这些知识在一个简单的示例使用一个覆盆子π编程的核心。

3评论
  • 约翰Długosz 2019年2月09年,

    你应该序言指出这个遗产编码不是我们现在使用的,并在64位代码是完全不可用。Thumb2编码紧凑和可变长度,没有条件谓词的指令代码。

    喜欢的。 回复
  • redrooster01 2019年2月16日

    谢谢你指出了约翰,但有多少人阅读注释吗?这篇文章是由疏忽误导,应该修改或重写。

    喜欢的。 回复
  • RK37 2019年2月19日

    谢谢你的评论。作者的原文引用不同的手臂版本,但失去了这些信息当文章出版之前被重组。介绍性的部分已经被修改,以避免混乱,你指的。

    喜欢的。 回复