为什么 GNU 作为 x86 和 ARM 之间的语法不同?
Why is GNU as syntax different between x86 and ARM?
我刚开始学习 ARM 汇编,我不明白为什么 GNU as 语法与 x86* 的语法不同。
由于指令相同,我希望除了指令本身之外的一切都像 x86*,但相反,我正在努力加载字符串的地址等。我从头开始通过在线阅读一些 PDF,man 2 syscall
和反编译基本示例,因为我不确定我可以在网上找到的各种 Hello World 的价值。
我的问题:
- 寄存器不需要
%
印记
- 整数常量可以有一个
#
或 $
印记。事实上,如果我编译 mov r0, [=16=]
,objdump -D
会返回 mov r0, #1
.
一切都归结为相同的mov r0, #1
:
mov %r0,
10080: e3a00001 mov r0, #1
mov r0,
10084: e3a00001 mov r0, #1
mov %r0, #1
10088: e3a00001 mov r0, #1
mov r0, #1
1008c: e3a00001 mov r0, #1
我无法直接使用标签的地址来加载字符串地址,所以我需要为此使用一个变量。 mov r1, $hello
或 ldr r1, $hello
不起作用。在 x86_64 中,我会写 mov $hello, %rsi
。所以我正在做 gcc 所做的事情,我正在用另一个标签的地址创建一个词。
我无法将我的常量 .rodata
或我得到一个 Error: internal_relocation (type: OFFSET_IMM) not fixed up
,但是将所有内容都放在 .text
中有效(这部分与语法)
.section .text
hello:
.asciz "Hello World\n"
.set hello_len, .-hello
hello_addr:
.word hello
.align 4
.global _start
_start:
mov r0,
ldr r1, hello_addr
mov r2, $hello_len
mov r7,
swi [=11=]
mov r0, [=11=]
mov r7,
swi [=11=]
GNU Assembler (GAS) 使用 AT&T 语法进行 x86 汇编的原因是为了与 AT&T 的 x86 汇编程序兼容。 AT&T 没有使用基于英特尔官方 x86 汇编语法的语法,而是选择基于其早期的 68000 和 PDP-11 汇编器创建新语法。当将 x86 支持添加到 GNU 编译器 (GCC) 时,它会生成 AT&T 语法汇编,因为那是他们使用的汇编器。在此之后的某个时间创建 GAS 时,GNU 汇编程序必须使用该语法。
然而,没有用于 ARM CPUs 的 AT&T 汇编器版本。当 GNU 项目开始将 GCC 和 GAS 移植到 ARM 目标时,没有理由为 ARM 汇编创建他们自己的新的和不兼容的语法。相反,他们基于 ARM 的官方语法使用的语法。这意味着您可以在 ARM 的官方文档中查找 ARM 指令,并使用您在 GNU 汇编程序中看到的语法和操作数顺序。在使用 AT&T 语法编写 x86 程序集时,您只需了解规则和例外情况,这些规则和例外情况在任何地方都没有正式记录。
在ARM汇编中不能将地址直接加载到寄存器中的原因不是语法问题。 ARM CPU 根本没有可以做到这一点的指令。所有 ARM 指令的大小都相同,均为 32 位,因此没有空间将 32 位地址编码为立即操作数。然而,ARM 汇编程序确实提供了一个 pseudo-instruction form of LDR 可以处理自动加载 32 位地址和常量:ldr r1, =hello
。这将导致汇编程序将 32 位常量存储在文字 table 中,并使用 PC 相关的 LDR 指令将其加载到内存中。如果加载的常量恰好足够小,可以直接使用 MOV 或 MVN 加载,则生成该指令。
你不能把常量放在.rodata
中的原因要么是因为它太远了,无法使用PC相关的LDR指令进行寻址(它需要在+/-4KB内,因为最大的位移无法放入单个 32 位 ARM 指令)或您使用的对象格式不支持对不同部分的 PC 相对寻址。 (您的 ldr r1, hello_addr
指令使用 PC 相对寻址,因为无法在 ARM 指令中编码 32 位地址。)
汇编语言是由汇编器定义的,汇编器是解析它的程序。创建或创建汇编程序符合处理器供应商(IP 或芯片)的最大利益。记录机器语言也符合他们的最大利益,因此他们将机器语言与他们创建或签订的汇编语言相匹配,以便这些项目一起工作。汇编语言绝不是适用于所有平台的通用语言,没有理由假设对于同一目标,不同的汇编器会使用相同的汇编语言,最著名的是 AT&T 与 intel x86 的悲惨结果。英特尔本可以做得更好,但它是 CISC 并且在当时是有意义的(mov 指令如此重载,但汇编语言仍然可以更干净一些,请记住我们已经有几十年的经验了).
据我所知,GNU 在添加目标时总是会破坏目标存在的汇编语言,因此他们会为该目标创建新的汇编语言。也许故意不兼容,有时关闭,但仍然足以不兼容。同样,有一些指令适用于 gnu 汇编器汇编语言,但也存在差异。现实情况是,不是 "GNU" 而是个人或团队选择为该目标创建该端口,他们做任何他们想做的事,这就是汇编语言的本质。
如果你在 ARM 之前学习 x86 我真的很同情你,我真的希望 x86 不是你的第一个汇编语言。从历史上看,百分号寄存器不是 x86 的东西,有人觉得他们需要添加它真的有点可悲,而当时许多汇编程序已经编写表明不需要这样的东西。 ARM 汇编语言,无论是 GNU 还是众多 ARM 汇编程序中的一种,都是目前最干净的汇编语言之一,最有意义,最不模糊。
重要的是机器代码,机器代码是您必须符合该目标的标准,而不是汇编语言。你能不能把机器码写出来,汇编语言能不能做的各不相同,这就是汇编语言的本质。与 AT&T 和完成单个 GNU 目标端口的人们一样,当然欢迎您编写自己的汇编器和汇编语言,如果您使用通用文件格式作为对象输出(在 ARM 的情况下为 elf),那么您可以使用汇编器编写汇编语言,然后 link 使用 C 或其他使用 GNU 工具的语言。没有人会阻止你这样做,这是学习指令集的一个很好的方法,我更喜欢写一个反汇编程序或一个指令集模拟器,而不是写一个汇编程序(大约是一个周末任务,也许还有几个工作日晚上进行微调)也会做得很好
人们可以很容易地抱怨 x86 GNU 汇编语言看起来不像 arm 或 mips,填空。不是很相关,原因很明显。 Ssemi-portable 与 gnu 端口之前的文档或工具。这本身就是为什么甚至完全使用 gnu 汇编程序的原因......如果 arm 后端是按照其他一些处理器常见的语法设计的,那么有人会制作一个备用端口。另请注意,在 gnu 世界中发生了令人不安的武器组装混乱,也许您应该赶上这股潮流……
回答你的实际问题,因为你确实有实际问题。这些是 x86 和 arm 完全不同的指令集。 CISC 与 RISC,您不能拥有固定大小的指令并适合您想要的任何大小。立即数有规则(请阅读 ARM 文档以了解您尝试使用的说明)否则您必须执行 pc 相对负载,并且 pc 相对负载可以达到的距离是有限的,您可能从一些 x86 指令中理解影响范围有限。至此各种汇编器给了我们一个伪代码的解决方案:
ldr r0,=0x00110000
ldr r0,=0x12345678
ldr r0,=mylabel
ldr r0,mylabeladd
ldr r0,myvalue
b .
mylabeladd: .word mylabel
mylabel: .word 1,2,3,4
myvalue: .word 0x11223344
给予
00000000 <mylabeladd-0x18>:
0: e3a00811 mov r0, #1114112 ; 0x110000
4: e59f0024 ldr r0, [pc, #36] ; 30 <myvalue+0x4>
8: e59f0024 ldr r0, [pc, #36] ; 34 <myvalue+0x8>
c: e59f0004 ldr r0, [pc, #4] ; 18 <mylabeladd>
10: e59f0014 ldr r0, [pc, #20] ; 2c <myvalue>
14: eafffffe b 14 <mylabeladd-0x4>
00000018 <mylabeladd>:
18: 0000001c andeq r0, r0, r12, lsl r0
0000001c <mylabel>:
1c: 00000001 andeq r0, r0, r1
20: 00000002 andeq r0, r0, r2
24: 00000003 andeq r0, r0, r3
28: 00000004 andeq r0, r0, r4
0000002c <myvalue>:
2c: 11223344 ; <UNDEFINED> instruction: 0x11223344
30: 12345678 eorsne r5, r4, #120, 12 ; 0x7800000
34: 0000001c andeq r0, r0, r12, lsl r0
如果他们不适合它或者如果它是一个标签,他们会为您创造价值(在 .text 中,因为您不能假设您可以到达任何其他部分)。如果他们可以为您创建一个 mov(至少 GAS 可以)。
或者您可以像在 mylabeladd
中那样自己制作 pc 相对负载
如果您想访问任何其他部分,则必须正确执行:
.globl _start
_start:
mov r3,#1
ldr r0,=mydata
str r3,[r0]
ldr r1,mydataadd
str r3,[r1]
b .
mydataadd: .word mydata
.data
mydata: .word 0
在 linked
时给予
00001000 <_start>:
1000: e3a03001 mov r3, #1
1004: e59f0010 ldr r0, [pc, #16] ; 101c <mydataadd+0x4>
1008: e5803000 str r3, [r0]
100c: e59f1004 ldr r1, [pc, #4] ; 1018 <mydataadd>
1010: e5813000 str r3, [r1]
1014: eafffffe b 1014 <_start+0x14>
00001018 <mydataadd>:
1018: 80000000 andhi r0, r0, r0
101c: 80000000 andhi r0, r0, r0
Disassembly of section .data:
80000000 <__data_start>:
80000000: 00000000 andeq r0, r0, r0
你必须为外部标签做同样的事情,但对于分支等,它在同一个 .text 部分,linker 会尽力帮助你。
.globl _start
_start:
b fun
在另一个文件中
.globl fun
fun:
b .
不足为奇...
00000000 <_开始>:
0: eaffffff b 4
00000004 :
4: eafffffe b 4
但是如果
.thumb
.thumb_func
.globl fun
fun:
b .
谢谢 gnu!
00000000 <_start>:
0: ea000000 b 8 <__fun_from_arm>
00000004 <fun>:
4: e7fe b.n 4 <fun>
...
00000008 <__fun_from_arm>:
8: e59fc000 ldr r12, [pc] ; 10 <__fun_from_arm+0x8>
c: e12fff1c bx r12
10: 00000005 andeq r0, r0, r5
14: 00000000 andeq r0, r0, r0
或者模拟一个非常大的程序
.globl _start
_start:
b fun
.space 0x10000000
感叹:
arm-none-eabi-ld -Ttext=0 so.o x.o -o so.elf
so.o: In function `_start':
(.text+0x0): relocation truncated to fit: R_ARM_JUMP24 against symbol `fun' defined in .text section in x.o
那么就像跨栏一样
.globl _start
_start:
ldr r0,=fun
bx fun
.ltorg
.space 0x10000000
那行得通...
00000000 <_start>:
0: e51f0000 ldr r0, [pc, #-0] ; 8 <_start+0x8>
4: e12fff10 bx r0
8: 1000000d andne r0, r0, sp
...
1000000c <fun>:
1000000c: e7fe b.n 1000000c <fun>
但你必须确保 link 人正在帮助你,因为它可能不会帮助你,而且从手臂到拇指的蹦床也不总是在那里......
.globl _start
_start:
b fun
.globl more_fun
more_fun:
b .
其他文件
.thumb
.thumb_func
.globl fun
fun:
b more_fun
生成完全损坏的代码。
00000000 <_start>:
0: ea000002 b 10 <__fun_from_arm>
00000004 <more_fun>:
4: eafffffe b 4 <more_fun>
00000008 <fun>:
8: e7fc b.n 4 <more_fun>
a: 0000 movs r0, r0
c: 0000 movs r0, r0
...
00000010 <__fun_from_arm>:
10: e59fc000 ldr r12, [pc] ; 18 <__fun_from_arm+0x8>
14: e12fff1c bx r12
18: 00000009 andeq r0, r0, r9
1c: 00000000 andeq r0, r0, r0
现在如果我使用了更多可能有效的 gnu 特定语法...
.globl _start
_start:
b fun
void more_fun ( void )
{
return;
}
不,猜不到
00000000 <_start>:
0: ea000002 b 10 <__fun_from_arm>
00000004 <more_fun>:
4: e12fff1e bx lr
00000008 <fun>:
8: e7fc b.n 4 <more_fun>
a: 0000 movs r0, r0
c: 0000 movs r0, r0
...
00000010 <__fun_from_arm>:
10: e59fc000 ldr r12, [pc] ; 18 <__fun_from_arm+0x8>
14: e12fff1c bx r12
18: 00000009 andeq r0, r0, r9
1c: 00000000 andeq r0, r0, r0
虽然所有的乐趣都...很明显,您正在处理不同的指令集 x86、arm、mips、avr、msp430、pdp11、xtensa、risc-v 和其他 gnu 支持的目标。一旦你学会了一种或两种或三种汇编语言,其余的相似多于不同,语法就是语法,很容易超越,真正的问题是你能用那个指令集做什么或不能做什么。答案通常在该供应商的文档中(而不仅仅是您搜索的一些指令集参考)
我刚开始学习 ARM 汇编,我不明白为什么 GNU as 语法与 x86* 的语法不同。
由于指令相同,我希望除了指令本身之外的一切都像 x86*,但相反,我正在努力加载字符串的地址等。我从头开始通过在线阅读一些 PDF,man 2 syscall
和反编译基本示例,因为我不确定我可以在网上找到的各种 Hello World 的价值。
我的问题:
- 寄存器不需要
%
印记 - 整数常量可以有一个
#
或$
印记。事实上,如果我编译mov r0, [=16=]
,objdump -D
会返回mov r0, #1
.
一切都归结为相同的mov r0, #1
:
mov %r0,
10080: e3a00001 mov r0, #1
mov r0,
10084: e3a00001 mov r0, #1
mov %r0, #1
10088: e3a00001 mov r0, #1
mov r0, #1
1008c: e3a00001 mov r0, #1
我无法直接使用标签的地址来加载字符串地址,所以我需要为此使用一个变量。
mov r1, $hello
或ldr r1, $hello
不起作用。在 x86_64 中,我会写mov $hello, %rsi
。所以我正在做 gcc 所做的事情,我正在用另一个标签的地址创建一个词。我无法将我的常量
.rodata
或我得到一个Error: internal_relocation (type: OFFSET_IMM) not fixed up
,但是将所有内容都放在.text
中有效(这部分与语法)
.section .text
hello:
.asciz "Hello World\n"
.set hello_len, .-hello
hello_addr:
.word hello
.align 4
.global _start
_start:
mov r0,
ldr r1, hello_addr
mov r2, $hello_len
mov r7,
swi [=11=]
mov r0, [=11=]
mov r7,
swi [=11=]
GNU Assembler (GAS) 使用 AT&T 语法进行 x86 汇编的原因是为了与 AT&T 的 x86 汇编程序兼容。 AT&T 没有使用基于英特尔官方 x86 汇编语法的语法,而是选择基于其早期的 68000 和 PDP-11 汇编器创建新语法。当将 x86 支持添加到 GNU 编译器 (GCC) 时,它会生成 AT&T 语法汇编,因为那是他们使用的汇编器。在此之后的某个时间创建 GAS 时,GNU 汇编程序必须使用该语法。
然而,没有用于 ARM CPUs 的 AT&T 汇编器版本。当 GNU 项目开始将 GCC 和 GAS 移植到 ARM 目标时,没有理由为 ARM 汇编创建他们自己的新的和不兼容的语法。相反,他们基于 ARM 的官方语法使用的语法。这意味着您可以在 ARM 的官方文档中查找 ARM 指令,并使用您在 GNU 汇编程序中看到的语法和操作数顺序。在使用 AT&T 语法编写 x86 程序集时,您只需了解规则和例外情况,这些规则和例外情况在任何地方都没有正式记录。
在ARM汇编中不能将地址直接加载到寄存器中的原因不是语法问题。 ARM CPU 根本没有可以做到这一点的指令。所有 ARM 指令的大小都相同,均为 32 位,因此没有空间将 32 位地址编码为立即操作数。然而,ARM 汇编程序确实提供了一个 pseudo-instruction form of LDR 可以处理自动加载 32 位地址和常量:ldr r1, =hello
。这将导致汇编程序将 32 位常量存储在文字 table 中,并使用 PC 相关的 LDR 指令将其加载到内存中。如果加载的常量恰好足够小,可以直接使用 MOV 或 MVN 加载,则生成该指令。
你不能把常量放在.rodata
中的原因要么是因为它太远了,无法使用PC相关的LDR指令进行寻址(它需要在+/-4KB内,因为最大的位移无法放入单个 32 位 ARM 指令)或您使用的对象格式不支持对不同部分的 PC 相对寻址。 (您的 ldr r1, hello_addr
指令使用 PC 相对寻址,因为无法在 ARM 指令中编码 32 位地址。)
汇编语言是由汇编器定义的,汇编器是解析它的程序。创建或创建汇编程序符合处理器供应商(IP 或芯片)的最大利益。记录机器语言也符合他们的最大利益,因此他们将机器语言与他们创建或签订的汇编语言相匹配,以便这些项目一起工作。汇编语言绝不是适用于所有平台的通用语言,没有理由假设对于同一目标,不同的汇编器会使用相同的汇编语言,最著名的是 AT&T 与 intel x86 的悲惨结果。英特尔本可以做得更好,但它是 CISC 并且在当时是有意义的(mov 指令如此重载,但汇编语言仍然可以更干净一些,请记住我们已经有几十年的经验了).
据我所知,GNU 在添加目标时总是会破坏目标存在的汇编语言,因此他们会为该目标创建新的汇编语言。也许故意不兼容,有时关闭,但仍然足以不兼容。同样,有一些指令适用于 gnu 汇编器汇编语言,但也存在差异。现实情况是,不是 "GNU" 而是个人或团队选择为该目标创建该端口,他们做任何他们想做的事,这就是汇编语言的本质。
如果你在 ARM 之前学习 x86 我真的很同情你,我真的希望 x86 不是你的第一个汇编语言。从历史上看,百分号寄存器不是 x86 的东西,有人觉得他们需要添加它真的有点可悲,而当时许多汇编程序已经编写表明不需要这样的东西。 ARM 汇编语言,无论是 GNU 还是众多 ARM 汇编程序中的一种,都是目前最干净的汇编语言之一,最有意义,最不模糊。
重要的是机器代码,机器代码是您必须符合该目标的标准,而不是汇编语言。你能不能把机器码写出来,汇编语言能不能做的各不相同,这就是汇编语言的本质。与 AT&T 和完成单个 GNU 目标端口的人们一样,当然欢迎您编写自己的汇编器和汇编语言,如果您使用通用文件格式作为对象输出(在 ARM 的情况下为 elf),那么您可以使用汇编器编写汇编语言,然后 link 使用 C 或其他使用 GNU 工具的语言。没有人会阻止你这样做,这是学习指令集的一个很好的方法,我更喜欢写一个反汇编程序或一个指令集模拟器,而不是写一个汇编程序(大约是一个周末任务,也许还有几个工作日晚上进行微调)也会做得很好
人们可以很容易地抱怨 x86 GNU 汇编语言看起来不像 arm 或 mips,填空。不是很相关,原因很明显。 Ssemi-portable 与 gnu 端口之前的文档或工具。这本身就是为什么甚至完全使用 gnu 汇编程序的原因......如果 arm 后端是按照其他一些处理器常见的语法设计的,那么有人会制作一个备用端口。另请注意,在 gnu 世界中发生了令人不安的武器组装混乱,也许您应该赶上这股潮流……
回答你的实际问题,因为你确实有实际问题。这些是 x86 和 arm 完全不同的指令集。 CISC 与 RISC,您不能拥有固定大小的指令并适合您想要的任何大小。立即数有规则(请阅读 ARM 文档以了解您尝试使用的说明)否则您必须执行 pc 相对负载,并且 pc 相对负载可以达到的距离是有限的,您可能从一些 x86 指令中理解影响范围有限。至此各种汇编器给了我们一个伪代码的解决方案:
ldr r0,=0x00110000
ldr r0,=0x12345678
ldr r0,=mylabel
ldr r0,mylabeladd
ldr r0,myvalue
b .
mylabeladd: .word mylabel
mylabel: .word 1,2,3,4
myvalue: .word 0x11223344
给予
00000000 <mylabeladd-0x18>:
0: e3a00811 mov r0, #1114112 ; 0x110000
4: e59f0024 ldr r0, [pc, #36] ; 30 <myvalue+0x4>
8: e59f0024 ldr r0, [pc, #36] ; 34 <myvalue+0x8>
c: e59f0004 ldr r0, [pc, #4] ; 18 <mylabeladd>
10: e59f0014 ldr r0, [pc, #20] ; 2c <myvalue>
14: eafffffe b 14 <mylabeladd-0x4>
00000018 <mylabeladd>:
18: 0000001c andeq r0, r0, r12, lsl r0
0000001c <mylabel>:
1c: 00000001 andeq r0, r0, r1
20: 00000002 andeq r0, r0, r2
24: 00000003 andeq r0, r0, r3
28: 00000004 andeq r0, r0, r4
0000002c <myvalue>:
2c: 11223344 ; <UNDEFINED> instruction: 0x11223344
30: 12345678 eorsne r5, r4, #120, 12 ; 0x7800000
34: 0000001c andeq r0, r0, r12, lsl r0
如果他们不适合它或者如果它是一个标签,他们会为您创造价值(在 .text 中,因为您不能假设您可以到达任何其他部分)。如果他们可以为您创建一个 mov(至少 GAS 可以)。
或者您可以像在 mylabeladd
中那样自己制作 pc 相对负载如果您想访问任何其他部分,则必须正确执行:
.globl _start
_start:
mov r3,#1
ldr r0,=mydata
str r3,[r0]
ldr r1,mydataadd
str r3,[r1]
b .
mydataadd: .word mydata
.data
mydata: .word 0
在 linked
时给予00001000 <_start>:
1000: e3a03001 mov r3, #1
1004: e59f0010 ldr r0, [pc, #16] ; 101c <mydataadd+0x4>
1008: e5803000 str r3, [r0]
100c: e59f1004 ldr r1, [pc, #4] ; 1018 <mydataadd>
1010: e5813000 str r3, [r1]
1014: eafffffe b 1014 <_start+0x14>
00001018 <mydataadd>:
1018: 80000000 andhi r0, r0, r0
101c: 80000000 andhi r0, r0, r0
Disassembly of section .data:
80000000 <__data_start>:
80000000: 00000000 andeq r0, r0, r0
你必须为外部标签做同样的事情,但对于分支等,它在同一个 .text 部分,linker 会尽力帮助你。
.globl _start
_start:
b fun
在另一个文件中
.globl fun
fun:
b .
不足为奇...
00000000 <_开始>: 0: eaffffff b 4
00000004 : 4: eafffffe b 4
但是如果
.thumb
.thumb_func
.globl fun
fun:
b .
谢谢 gnu!
00000000 <_start>:
0: ea000000 b 8 <__fun_from_arm>
00000004 <fun>:
4: e7fe b.n 4 <fun>
...
00000008 <__fun_from_arm>:
8: e59fc000 ldr r12, [pc] ; 10 <__fun_from_arm+0x8>
c: e12fff1c bx r12
10: 00000005 andeq r0, r0, r5
14: 00000000 andeq r0, r0, r0
或者模拟一个非常大的程序
.globl _start
_start:
b fun
.space 0x10000000
感叹:
arm-none-eabi-ld -Ttext=0 so.o x.o -o so.elf
so.o: In function `_start':
(.text+0x0): relocation truncated to fit: R_ARM_JUMP24 against symbol `fun' defined in .text section in x.o
那么就像跨栏一样
.globl _start
_start:
ldr r0,=fun
bx fun
.ltorg
.space 0x10000000
那行得通...
00000000 <_start>:
0: e51f0000 ldr r0, [pc, #-0] ; 8 <_start+0x8>
4: e12fff10 bx r0
8: 1000000d andne r0, r0, sp
...
1000000c <fun>:
1000000c: e7fe b.n 1000000c <fun>
但你必须确保 link 人正在帮助你,因为它可能不会帮助你,而且从手臂到拇指的蹦床也不总是在那里......
.globl _start
_start:
b fun
.globl more_fun
more_fun:
b .
其他文件
.thumb
.thumb_func
.globl fun
fun:
b more_fun
生成完全损坏的代码。
00000000 <_start>:
0: ea000002 b 10 <__fun_from_arm>
00000004 <more_fun>:
4: eafffffe b 4 <more_fun>
00000008 <fun>:
8: e7fc b.n 4 <more_fun>
a: 0000 movs r0, r0
c: 0000 movs r0, r0
...
00000010 <__fun_from_arm>:
10: e59fc000 ldr r12, [pc] ; 18 <__fun_from_arm+0x8>
14: e12fff1c bx r12
18: 00000009 andeq r0, r0, r9
1c: 00000000 andeq r0, r0, r0
现在如果我使用了更多可能有效的 gnu 特定语法...
.globl _start
_start:
b fun
void more_fun ( void )
{
return;
}
不,猜不到
00000000 <_start>:
0: ea000002 b 10 <__fun_from_arm>
00000004 <more_fun>:
4: e12fff1e bx lr
00000008 <fun>:
8: e7fc b.n 4 <more_fun>
a: 0000 movs r0, r0
c: 0000 movs r0, r0
...
00000010 <__fun_from_arm>:
10: e59fc000 ldr r12, [pc] ; 18 <__fun_from_arm+0x8>
14: e12fff1c bx r12
18: 00000009 andeq r0, r0, r9
1c: 00000000 andeq r0, r0, r0
虽然所有的乐趣都...很明显,您正在处理不同的指令集 x86、arm、mips、avr、msp430、pdp11、xtensa、risc-v 和其他 gnu 支持的目标。一旦你学会了一种或两种或三种汇编语言,其余的相似多于不同,语法就是语法,很容易超越,真正的问题是你能用那个指令集做什么或不能做什么。答案通常在该供应商的文档中(而不仅仅是您搜索的一些指令集参考)