将非常简单的ARM指令转换为二进制/十六进制

时间:2012-08-02 21:20:29

标签: assembly binary hex arm opcodes

我一直在尝试使用 this page 以及其他各种指南来弄清楚如何将非常简单的ARM指令表达为二进制和十六进制。对我来说这似乎应该是一个简单的过程,但我仍然不明白。以下是一些例子。

基本NOP:

       what goes here?          what goes here?
             _↓_                  _____↓____
            |   |                |          |
mov r0, r0 ; ????00?1101?????????????????????
                         |__||__|
                          ↑    ↑
                 how do I express registers?

其他人的基本问题。

比较两个寄存器:

cmp r1, r0

立即添加注册值:

add r0, #0x1a

所有这些在线教程都非常出色地描述了如何使用这些指令,但是我找不到任何实际操作如何将ARM指令转换为汇编的二进制/十六进制/机器代码

提前感谢您的帮助。

3 个答案:

答案 0 :(得分:32)

以下是数据处理指令的编码方式:

ARM data processing instructions

您的页面中有条件代码表。寄存器的编号为00001111

您的所有示例属于同一类别。图片是从我的硬盘驱动器上的某些文档中提取的,但我也设法通过google找到它。编写这些指令是一项繁琐的工作。

所以,mov r0, r0应该是这样的:

1110 00 0 0 1101 0000 0000 00000000

我把Rn设为0,因为它实际上不适用于MOV。如果是CMP,我相信,S始终为1.

答案 1 :(得分:10)

首先,您需要在infocenter.arm.com上获取ARM体系结构参考手册(ARM ARM),参考手册,获取最旧的(armv5或其他)。指令集在那里很好地定义。

其次,你为什么不组装一些指令,看看会发生什么?

;@test.s
cmp r1, r0
add r0, #0x1a

你有什么交叉汇编程序(在构建gcc目录中查看脚本的http://github.com/dwelch67/raspberrypi,只需在该脚本中运行binutils)

arm-none-linux-gnueabi-as test.s  -o test.o
arm-none-linux-gnueabi-objdump -D test.o
arm-none-linux-gnueabi vs arm-none-elf vs arm-elf等对此无关紧要,都做同样的事情

Disassembly of section .text:

00000000 <.text>:
   0:   e1510000    cmp r1, r0
   4:   e280001a    add r0, r0, #26

完整32位arm指令(不是拇指)的前四位是条件代码,请参阅ARM ARM中的条件字段部分。 0xE表示始终执行此指令。 0b0000是eq仅在z标志置位时执行,0b0001 ne仅在z清除时执行,等等。

在ARM ARM中推入arm指令集,然后按字母顺序列出arm指令,然后找到cmp它以cond 00I10101开头snz shifter

从上面的cmp指令我们看到1110 000101010001 ...所以我是零位15:12是零位27:26是零而24:21是1010所以这是一个cmp指令

上面的第19位到第16位是0b001,对于ARM ARM中的移位器操作数是rn,因此rn = 1(r1)它告诉您查看寻址模式1数据处理操作数并且在pdf中有一个链接到页面

我们知道我们希望第二个操作数只是一个寄存器,称为数据处理操作数 - 寄存器和页码,转到该页面上的页面15:12是11:4是0和3: 0是rm。我们从cmp指令中知道15:12应该为零,我不知道它是否关心,cmp不会将结果存储到寄存器中,因此不使用rd。使用rm,在这种情况下我们想要r0,所以0b0000进入3:0也注意它将位27:25显示为零,在cmp指令25中是I,我们现在知道我们想要零那么

cmp页面和这个数据处理之间的

- 注册页面我们有整个图片

1110 condition
000 
1010 opcode
1 S (store flags, that is a 1 for a cmp to be useful)
0001 rn
0000 rd/dont care/sbz
00000
000
0000 rm

cmp rn,rm
cmp r1,r0

add类似但使用立即数,所以转到alpha指令列表中的add指令。我们现在从cmp知道这个类指令的24:21是操作码,我们几乎可以直接从移位器操作数的东西继续那里继续

这次我们正在添加rd,rn,#immediate

所以请查找#immediate

的页面

,编码是

1110 condition, always
001 (note the immediate bit is set)
0100 (opcode for add for this type of instruction)
0 (S not saving the flags, it would be adds r0,r0,#26 for that)
0000 (rn = r0)
0000 (rd = r0)

现在是有趣的部分,我们可以编码26种不同的方式。位7:0是立即数,位11:8允许立即旋转,26是0x1A,我们可以简单地将0x1A置于低8位并将旋转设置为0,这就是gnu汇编器所做的。可能在低8位中加一个0x68,在rotate_imm字段1101000中右移一个1 * 2位的1是11010 = 0x1A = 26。

答案 2 :(得分:6)

您应该获得ARM ARM的副本,它描述了所有指令的编码。

大多数ARM指令使用高4位作为条件代码。如果您不想有条件地运行指令,只需使用伪条件AL(1110)。

编码中的第一个寄存器(Rn)不用于MOV指令,应根据ARM ARM的定义设置为0000。

第二个寄存器是目的地,在这里你只需编码寄存器号,所以在你的情况下它也是0000,因为你使用r0作为destinal,对于r4它将是0100。

余数是所谓的移位操作数,非常灵活。它可以是一个简单的寄存器,如你的情况(r0)那么它只是0000 0000 0000,其中最后4位再次编码寄存器。它还可以编码不同类型的移位,并使用寄存器或立即值进行旋转以进行数据处理。

但它也可能是一个直接的位置,其中8位在底部位编码,而前4位在2位步骤中定义右旋转。在这种情况下,bit25也将为1,在所有其他情况下,它为0。