我一直在尝试使用 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指令转换为汇编的二进制/十六进制/机器代码
提前感谢您的帮助。
答案 0 :(得分:32)
以下是数据处理指令的编码方式:
您的页面中有条件代码表。寄存器的编号为0000
到1111
。
您的所有示例属于同一类别。图片是从我的硬盘驱动器上的某些文档中提取的,但我也设法通过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。