GNU ARM 汇编程序将 mov 更改为 add?

Ale*_*nea 3 assembly encoding arm gnu thumb

社区!

我有以下单行源文件,称为 first.S

mov R1, R2
Run Code Online (Sandbox Code Playgroud)

我生成一个目标文件如下:

$ arm-none-eabi-as -mcpu=cortex-m3 -march=armv7 -mthumb -c -o first.o first.S 
Run Code Online (Sandbox Code Playgroud)

那我拆开看看

$ arm-none-eabi-objdump -d first.o

first.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <.text>:
   0:   1c11        adds    r1, r2, #0
Run Code Online (Sandbox Code Playgroud)

显然,在这种情况下,两条指令(movadd)具有相同的、所需的效果。

不过,问题是:为什么?

根据 ARMv7-M 体系结构参考手册,mov 寄存器指令存在多种编码,但是汇编程序选择将其编码为add指令。

在任何文件中是否有描述此类决定的地方?

谢谢!

old*_*mer 5

从开始时间为拇指指令集,编码

0001110xxxnnnddd 
Run Code Online (Sandbox Code Playgroud)

是一个

adds rd,rn,#xxx
Run Code Online (Sandbox Code Playgroud)

这是更有效的编码IF标志的修改对您来说是可以的。

伪指令 mov rd,rn 意味着标志可以改变(显然是文档中的每个武器 asm 和气体)。所以原始编码没问题。

现在由反汇编程序选择 if immed == 0 然后打印 mov rd,rn vs add rd,rn,#0,两者都是正确的反汇编。

现在,一个寄存器高一个低的 mov 说:

Unlike the low register MOV instruction described in MOV (2) on page A7-73, this instruction does not change the flags.
Run Code Online (Sandbox Code Playgroud)

现在它进入了完全由汇编程序而不是目标(非 ARM)定义的汇编语言,以及可怕的统一语法等等。所以现在它变成了一个工具特定的东西。例如,用于拇指的 Gnu 汇编器不喜欢添加(非统一语法,我发现对于拇指使用起来要容易得多)您执行添加并获得添加。

.thumb
add r0,r1,#0
mov r0,r1
adds r0,r1,#0
movs r0,r1

arm-none-eabi-as so.s -o so.o
so.s: Assembler messages:
so.s:5: Error: instruction not supported in Thumb16 mode -- `adds r0,r1,#0'

.thumb
add r0,r1,#0
mov r0,r1
movs r0,r1

00000000 <.text>:
   0:   1c08        adds    r0, r1, #0
   2:   1c08        adds    r0, r1, #0
   4:   1c08        adds    r0, r1, #0
Run Code Online (Sandbox Code Playgroud)

然而,它对 movs 很好。

0x1c08 = 0x0001110000001000,这是一个添加拇指指令,当这一切开始时返回到 armv4t。

.syntax unified
.thumb
add r0,r1,#0
mov r0,r1
adds r0,r1,#0
movs r0,r1


   0:   f101 0000   add.w   r0, r1, #0
   4:   4608        mov r0, r1
   6:   1c08        adds    r0, r1, #0
   8:   0008        movs    r0, r1
Run Code Online (Sandbox Code Playgroud)

所以现在在这种情况下,它是一种不同的汇编语言(相同的工具不同的汇编语言)

所以这个汇编语言尊重 add vs add 和 mov vs movs。

为了在没有闪光的情况下进行添加,您需要thumb2 编码。没有标志的 mov 是高位寄存器 mov 0x4608 0100011000001000 0x46xx

add 和往常一样,movs 现在被编码为左移,但不是反汇编 lsl r0,r1,#0,而是反汇编为 mov r0,r1,更多的是让您咀嚼,而不仅仅是将 mov 反汇编为添加。他们为什么不使用添加?这是另一个问题,如果您至少在旧的 arm arm 中查看 mov low registers 指令,它会描述显示添加编码的标志会发生什么。但是,如果您查看 lsl 描述,标志是不同的,那么 lsl 并不能替代具有标志的 mov,至少如寿命最长的 ARM ARM(用拇指)中所述。

好吧,这是有道理的,他们对较老的手臂有帮助。如果立即数为零,则没有进位,因此将其描述为与有符号溢出标志一起设置为零。

Lsl 将一个文档中的进位显示为未更改而不是零。因此,也许随着时间的推移在指令的实现中发生了一些变化,或者 ARM ARMS 之一是错误的(这种情况经常发生)。


简短的回答, mov rd,rn 一直是作为添加记录的伪指令,反汇编程序可以选择将其打印出来,这取决于反汇编程序。

汇编语言由工具而不是目标定义,因此工具确定在其语法中使用哪种标志解决方案,并可以在添加、mov 高位寄存器、thumb2 编码或其他一些编码之间进行选择。

我们不知道为什么的问题,为什么选择一种编码而不是另一种编码,其中可能有相同的编码,通常选择较短的编码(thumb 与 thumb2 扩展)(x86 中的 xor 与 mov 立即数,零作为立即数)。但是 lsl vs add vs sub vs ...

您可以在 arm 文档中找到其他伪指令(记录当时其工具的汇编语言),以及汇编程序添加到其汇编语言中的伪指令,如 nop。

.thumb
nop
mov r8,r8
mov r4,r4

00000000 <.text>:
   0:   46c0        nop         ; (mov r8, r8)
   2:   46c0        nop         ; (mov r8, r8)
   4:   1c24        adds    r4, r4, #0
Run Code Online (Sandbox Code Playgroud)

现在的问题是他们为什么不直接打印出来:

   0:   1c08        mov r0,r1  ; (adds r0, r1, #0)
Run Code Online (Sandbox Code Playgroud)

我也喜欢反汇编器如何将分号作为注释边界,而汇编语言奇怪地不支持它(就像地球上的所有其他汇编器(以及大多数)一样)。

当然,反汇编程序不知道创建该机器代码的汇编程序是什么,因此对于有伪指令显示两者的情况会很好。