强制GNU AS使用替代方案

时间:2018-04-29 11:47:19

标签: assembly arm disassembly

我有一个ARM二进制文件和一些汇编代码。 二进制文件的反汇编读取

1e40 -> subs r0,r0,#1

汇编代码中的指令读取相同内容。 (代码使用.syntax unified指令)

但是当我使用GNU AS时(来自ARM 2017 Q4的gcc工具链), 它评估

subs r0,r0,#1

3801-> subs r0,#1

使用objdump

我想这两个可能是相同的,但是我仍然想知道是否有办法在第二个操作码中选择第一个操作码的生成,因为我相信它会导致我正在使用的设备出现问题

2 个答案:

答案 0 :(得分:3)

您没有说明架构,但由于它显然是Thumb,我将使用Cortex-M作为基础。

咨询" ARMv7-M应用级架构参考手册",可以轻松解码操作码。尝试一下,这是一个很好的做法,在编写机器级代码时,最好将它放在附近。

它们实际上是两个不同的指令,但具有相同的效果。

第一个操作码是指双寄存器(源,目标)操作,具有小的3位立即数(零扩展,范围0 ... 7)。这里,两个寄存器恰好是相同的寄存器,使其实际上是单寄存器递减。

第二个是单个寄存器减法,具有8位立即数操作数(零扩展,范围0 ... 255)。目前尚不清楚为什么你会得到两个不同的变体,但它们应该没有实际的区别(至少对于Cortex-M4而言,它们都需要一个时钟,如果其他架构有不同的值,我会感到惊讶。)

因此,反汇编反映了执行指令。 gas似乎将原来的双寄存器指令转换为单寄存器操作码。

请注意,有各种操作可能导致不同的操作码。对于给出的信息,不清楚为什么选择它们。 Imo,第二个更合理,第一个只有在涉及两个不同的寄存器时才有意义。

如果您的代码存在问题,则此指令最不可能发生。也许是时候启动调试器了。

答案 1 :(得分:3)

试试吧......

so.s

.thumb
sub r0,#1
.syntax unified
subs r0,r0,#1
sub r0,#1
subs.n r0,#1

汇编和反汇编

arm-none-eabi-as so.s -o so.o
arm-none-eabi-objdump -D so.o

so.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <.text>:
   0:   3801        subs    r0, #1
   2:   3801        subs    r0, #1
   4:   f1a0 0001   sub.w   r0, r0, #1
   8:   3801        subs    r0, #1

编辑奥拉夫的评论。

.thumb
sub r0,#1
sub r0,r0,#1
sub r1,r2,#1
.syntax unified
subs r0,r0,#1
sub r0,#1
subs.n r0,#1
subs.n r0,r0,#1
subs r1,r2,#1


00000000 <.text>:
   0:   3801        subs    r0, #1
   2:   3801        subs    r0, #1
   4:   1e51        subs    r1, r2, #1
   6:   3801        subs    r0, #1
   8:   f1a0 0001   sub.w   r0, r0, #1
   c:   3801        subs    r0, #1
   e:   3801        subs    r0, #1
  10:   1e51        subs    r1, r2, #1

我/你/我们必须深入了解汇编源,看看是否有解决方法。 Fuz可能有最简单的答案。可能的是,汇编程序针对具有更大灵活性的汇编程序进行了优化。您当然可以删除该优化/功能(如果没有标志)。

EDIT2

也许就是这样。

#define T_OPCODE_SUB_I8 0x3800
#define T_OPCODE_SUB_I3 0x1e00

    else if (rs == rd)
      {
        if (value & ~0xff)
          as_bad_where (fixP->fx_file, fixP->fx_line,
                _("immediate value out of range"));
        newval = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
        newval |= (rd << 8) | value;
      }
    else
      {
        if (value & ~0x7)
          as_bad_where (fixP->fx_file, fixP->fx_line,
                _("immediate value out of range"));
        newval = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
        newval |= rd | (rs << 3) | (value << 6);
      }

如果你添加这个

else if (value & ~0x7)
  {
    newval = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
    newval |= rd | (rs << 3) | (value << 6);
  }

前面的

else if (rs == rd)

然后

.cpu cortex-m7
.thumb
sub r0,r0,#15
sub r0,r0,#1
.syntax unified
subs.n r0,r0,#1
subs.n r0,r0,#15

给出了期望的结果。

   0:   1fc0        subs    r0, r0, #7
   2:   3801        subs    r0, #1
   4:   3801        subs    r0, #1
   6:   1fc0        subs    r0, r0, #7

所以我认为rs == rd阻止你生成你想要的指令。

编辑3

binutils 2.7没有这个定义T_OPCODE_SUB_I8所以也许没有拇指支持,没有深入挖掘。 binutils 2.8确实并且还包括这种优化。所以早在1997年就已存在。如果你想用gnu汇编程序生成有问题的指令,你需要修改gnu汇编程序......