GNU ARM 汇编程序将 mov 更改为 adds?
GNU ARM assembler changes mov into adds?
社区!
我有以下单行源文件,名为 first.S
mov R1, R2
我生成的目标文件如下:
$ arm-none-eabi-as -mcpu=cortex-m3 -march=armv7 -mthumb -c -o first.o first.S
那我拆机了
$ 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
显然,本例中的两条指令(mov
和 add
)具有相同的预期效果。
但问题是:为什么?
根据 ARMv7-M 体系结构参考手册,mov 寄存器指令存在多种编码,但汇编程序选择将其编码为 add
指令。
任何文档中是否有描述此类决定的地方?
谢谢!
如 https://static.docs.arm.com/ddi0403/eb/DDI0403E_B_armv7m_arm.pdf#G11.5007716 , the move instruction's opcode is also 2bytes and therefore there is no advantage in using either of those. https://developer.arm.com/documentation/ddi0337/e/instruction-timing/processor-instruction-timings 所述,两条指令都使用 1 CPU 周期来完成。
然而,编码 T2 https://static.docs.arm.com/ddi0403/eb/DDI0403E_B_armv7m_arm.pdf#G11.5007716 会有一个空字节,这在某些情况下很糟糕(漏洞利用)。
但是我可以想象构建一个汇编器会更容易,它产生的操作码差异越小。
从thumb指令集开始,编码
0001110xxxnnnddd
是一个
adds rd,rn,#xxx
它是更有效的编码IF修改标志对你来说没问题。
伪指令 mov rd,rn 意味着标志可以改变(文档中的 arm asm 和 gas 显然)。这样原始编码就可以了。
现在由反汇编程序来选择是否使用 if immed == 0 then print mov rd,rn vs adds 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.
现在它进入了完全由汇编器而不是目标(不是 ARM)定义的汇编语言,以及可怕的统一语法等等。所以现在它变成了一个特定于工具的东西。例如,用于 thumb 的 Gnu 汇编程序不喜欢添加(非统一语法,我发现它更容易用于 thumb)你做一个添加并得到一个添加。
.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
不过用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
所以现在在这种情况下,它是一种不同的汇编语言(相同的工具不同的汇编语言)
所以这种汇编语言支持 add 与 adds 和 mov 与 movs。
为了在没有 flahs 的情况下进行添加,您需要 thumb2 编码。没有flags的mov是高位寄存器 mov 0x4608 0100011000001000 0x46xx
adds 和往常一样,movs 现在被编码为左移,但不是反汇编 lsl r0,r1,#0,而是反汇编为 mov r0,r1,更多供您咀嚼而不是只是 mov 反汇编作为添加。为什么他们不使用 adds?这是另一个问题,如果你至少在旧的 arm arm 中查看 mov low registers 指令,它描述了它显示添加编码的标志发生了什么。但是如果你看一下 lsl 的描述,标志是不同的,lsl 不是一个带有标志的 mov 的替代品,至少如最长寿的 ARM ARM(用拇指)中所描述的那样。
好的,这是有道理的,他们对年长的手臂很有帮助。如果立即数为零,则没有进位,因此它被描述为与带符号的溢出标志一起设置为零。
Lsl 在一个文档和另一个文档中显示进位不变而不是零。因此,随着时间的推移,指令的实现可能发生了一些变化,或者 ARM ARMS 之一是错误的(经常发生)。
简短的回答,mov rd,rn 一直是伪指令,记录为 adds,反汇编程序可以选择以反汇编程序的任何方式打印出来。
汇编语言是由工具而不是目标定义的,因此该工具确定在其语法中使用哪个标志解决方案,并可以在添加、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
现在的问题是他们为什么不打印出来:
0: 1c08 mov r0,r1 ; (adds r0, r1, #0)
我也很喜欢反汇编程序如何暗示分号作为注释边界,而汇编语言奇怪地不支持它(就像地球上的所有其他汇编程序一样(大多数))。
当然,反汇编程序不知道创建该机器代码的汇编程序是什么,因此对于存在显示两者的伪指令的情况会很好。
社区!
我有以下单行源文件,名为 first.S
mov R1, R2
我生成的目标文件如下:
$ arm-none-eabi-as -mcpu=cortex-m3 -march=armv7 -mthumb -c -o first.o first.S
那我拆机了
$ 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
显然,本例中的两条指令(mov
和 add
)具有相同的预期效果。
但问题是:为什么?
根据 ARMv7-M 体系结构参考手册,mov 寄存器指令存在多种编码,但汇编程序选择将其编码为 add
指令。
任何文档中是否有描述此类决定的地方?
谢谢!
如 https://static.docs.arm.com/ddi0403/eb/DDI0403E_B_armv7m_arm.pdf#G11.5007716 , the move instruction's opcode is also 2bytes and therefore there is no advantage in using either of those. https://developer.arm.com/documentation/ddi0337/e/instruction-timing/processor-instruction-timings 所述,两条指令都使用 1 CPU 周期来完成。
然而,编码 T2 https://static.docs.arm.com/ddi0403/eb/DDI0403E_B_armv7m_arm.pdf#G11.5007716 会有一个空字节,这在某些情况下很糟糕(漏洞利用)。
但是我可以想象构建一个汇编器会更容易,它产生的操作码差异越小。
从thumb指令集开始,编码
0001110xxxnnnddd
是一个
adds rd,rn,#xxx
它是更有效的编码IF修改标志对你来说没问题。
伪指令 mov rd,rn 意味着标志可以改变(文档中的 arm asm 和 gas 显然)。这样原始编码就可以了。
现在由反汇编程序来选择是否使用 if immed == 0 then print mov rd,rn vs adds 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.
现在它进入了完全由汇编器而不是目标(不是 ARM)定义的汇编语言,以及可怕的统一语法等等。所以现在它变成了一个特定于工具的东西。例如,用于 thumb 的 Gnu 汇编程序不喜欢添加(非统一语法,我发现它更容易用于 thumb)你做一个添加并得到一个添加。
.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
不过用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
所以现在在这种情况下,它是一种不同的汇编语言(相同的工具不同的汇编语言)
所以这种汇编语言支持 add 与 adds 和 mov 与 movs。
为了在没有 flahs 的情况下进行添加,您需要 thumb2 编码。没有flags的mov是高位寄存器 mov 0x4608 0100011000001000 0x46xx
adds 和往常一样,movs 现在被编码为左移,但不是反汇编 lsl r0,r1,#0,而是反汇编为 mov r0,r1,更多供您咀嚼而不是只是 mov 反汇编作为添加。为什么他们不使用 adds?这是另一个问题,如果你至少在旧的 arm arm 中查看 mov low registers 指令,它描述了它显示添加编码的标志发生了什么。但是如果你看一下 lsl 的描述,标志是不同的,lsl 不是一个带有标志的 mov 的替代品,至少如最长寿的 ARM ARM(用拇指)中所描述的那样。
好的,这是有道理的,他们对年长的手臂很有帮助。如果立即数为零,则没有进位,因此它被描述为与带符号的溢出标志一起设置为零。
Lsl 在一个文档和另一个文档中显示进位不变而不是零。因此,随着时间的推移,指令的实现可能发生了一些变化,或者 ARM ARMS 之一是错误的(经常发生)。
简短的回答,mov rd,rn 一直是伪指令,记录为 adds,反汇编程序可以选择以反汇编程序的任何方式打印出来。
汇编语言是由工具而不是目标定义的,因此该工具确定在其语法中使用哪个标志解决方案,并可以在添加、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
现在的问题是他们为什么不打印出来:
0: 1c08 mov r0,r1 ; (adds r0, r1, #0)
我也很喜欢反汇编程序如何暗示分号作为注释边界,而汇编语言奇怪地不支持它(就像地球上的所有其他汇编程序一样(大多数))。
当然,反汇编程序不知道创建该机器代码的汇编程序是什么,因此对于存在显示两者的伪指令的情况会很好。