【问题标题】:Converting very simple ARM instructions to binary/hex将非常简单的 ARM 指令转换为二进制/十六进制
【发布时间】:2012-07-31 22:14:30
【问题描述】:

我一直在尝试使用 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 指令转换为二进制/十六进制/机器代码的教程.

提前感谢您的帮助。

【问题讨论】:

  • 好问题;不幸的是,链接已经死了。对于路过的人,这是一个快速的web archive link

标签: assembly binary hex arm opcodes


【解决方案1】:

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

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

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

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

1110 00 0 0 1101 0000 0000 00000000

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

【讨论】:

    【解决方案2】:

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

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

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

    无论你有什么交叉汇编器(请参阅 build 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 指令(不是 thumb)的前四位是条件代码,请参阅 ARM ARM 中的条件字段部分。 0xE 表示总是,总是执行这条指令。 0b0000 是 eq 仅在设置了 z 标志时执行,0b0001 ne 仅在 z 清零时执行,等等。

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

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

    上面的 19 到 16 位是 0b001,它是 rn,所以 rn = 1 (r1) 用于 ARM ARM 中的移位器操作数,它告诉您查看寻址模式 1 数据处理操作数,并在 pdf 中有指向页面的链接

    我们知道我们希望第二个操作数只是一个寄存器,也就是所谓的数据处理操作数——寄存器和一个页码,转到那个页上的那个页 15:12 是 rd 11:4 是零和 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 是此类指令的操作码,我们几乎可以直接进入移位器操作数的内容以从那里继续

    这次我们在做 add 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,向右旋转 1*2 位是 11010 = 0x1A = 26。

    【讨论】:

      【解决方案3】:

      你应该得到一份 ARM ARM 的副本,它描述了所有指令的编码。

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

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

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

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

      但它也可以是立即数,其中 8 位在底部位中编码,前 4 位定义以 2 位步长的右循环。在这种情况下,bit25 也将为 1,在所有其他情况下为 0。

      【讨论】:

      • ARM ARM 是一个有趣的首字母缩写词,但在 Google 上搜索它却非常困难。扩展名为《ARM 架构参考手册》,免费注册后可在here 获得。
      • @Kevin 不,展开其实是高级(减少指令集计算)机器架构参考手册。但这不是一个好的谷歌搜索:)
      猜你喜欢
      • 2015-01-28
      • 2012-06-26
      • 2016-08-28
      • 2013-07-25
      相关资源
      最近更新 更多