首先,汇编语言是特定于汇编器的。
对于 gnu:
.thumb
.globl myfun
.thumb_func
myfun:
ldr r0,=0x12345678
myfun_inner:
ldr r1,[r0]
cmp r1,#0
bne my_fun_inner
bx lr
so.o: file format elf32-littlearm
Disassembly of section .text:
00000000 <myfun>:
0: 4802 ldr r0, [pc, #8] ; (c <myfun_inner+0xa>)
00000002 <myfun_inner>:
2: 6801 ldr r1, [r0, #0]
4: 2900 cmp r1, #0
6: d1fe bne.n 0 <my_fun_inner>
8: 4770 bx lr
a: 0000 .short 0x0000
c: 12345678 .word 0x12345678
gnu 有一个有趣的奇怪标签快捷方式,我不是特别喜欢,但有些人喜欢:
.thumb
.globl myfun
.thumb_func
myfun:
ldr r0,=0x12345678
1:
ldr r1,[r0]
cmp r1,#0
bne 1b
bx lr
将 1b 视为 1 向后,您可以在此代码中有多个 1:、2: 等标签,而 1b 或 1f 将引用最接近的 1:向前或向后。并产生相同的代码:
6: d1fe bne.n 0 <my_fun_inner>
这是一个相对跳转,所以即使我已经反汇编了对象,当你链接和反汇编链接的二进制文件时,这将是相同的机器代码:
ldr r0,=0x12345678
是一些 ARM 汇编程序支持的伪代码。 Gas 尤其会尝试找到优化的解决方案:
.thumb
ldr r0,=0x12345678
ldr r0,=1
ldr r0,=0x20002
00000000 <.text>:
0: 4802 ldr r0, [pc, #8] ; (c <.text+0xc>)
2: f04f 0001 mov.w r0, #1
6: f04f 1002 mov.w r0, #131074 ; 0x20002
a: 0000 .short 0x0000
c: 12345678 .word 0x12345678
现在这有点危险,因为它选择了 thumb2 指令,所以您可能希望对 cortex-ms 超级通用(到目前为止,实际的 armv8m 芯片)
.cpu cortex-m0
.thumb
ldr r0,=0x12345678
ldr r0,=1
ldr r0,=0x20002
00000000 <.text>:
0: 4801 ldr r0, [pc, #4] ; (8 <.text+0x8>)
2: 4802 ldr r0, [pc, #8] ; (c <.text+0xc>)
4: 4802 ldr r0, [pc, #8] ; (10 <.text+0x10>)
6: 0000 .short 0x0000
8: 12345678 .word 0x12345678
c: 00000001 .word 0x00000001
10: 00020002 .word 0x00020002
其中的 .short 有一个对齐间距,以保持单词对齐。这是 binutils 的尖端版本,您有时/经常会看到一个 nop 放置在其中以填充空间。所以现在也许该工具正在填充零。
最小的完成应该是
.cpu cortex-m0
.thumb
.globl myfun
.thumb_func
myfun:
ldr r0,=0x12345678
myfun_inner:
ldr r1,[r0]
cmp r1,#0
bne my_fun_inner
bx lr
如果你检查 gcc 的输出,你会看到一些更接近最大值的东西,还有更多的语法。因此,根据您的个人喜好,瞄准两者之间的某个地方。我经常不使用 .cpu,除非我需要,因为它过去默认为 armv4t,这几乎是“所有拇指变体”,但现在显然不是,所以我必须改变我的习惯。再次在这里,总是检查你的 asm 代码输出,尤其是在这个 arm arm/thumb 多个 thumb2 扩展,多个指令集使用相同的工具。