我为amd64编写了这个小程序集文件。对于这个问题,代码所做的并不重要。
.globl fib
fib: mov %edi,%ecx
xor %eax,%eax
jrcxz 1f
lea 1(%rax),%ebx
0: add %rbx,%rax
xchg %rax,%rbx
loop 0b
1: ret
然后,我开始组装,然后在Solaris和Linux上拆卸它。
索拉里斯
$ as -o y.o -xarch=amd64 -V y.s
as: Sun Compiler Common 12.1 SunOS_i386 Patch 141858-04 2009/12/08
$ dis y.o
disassembly for y.o
section .text
0x0: 8b cf movl %edi,%ecx
0x2: 33 c0 xorl %eax,%eax
0x4: e3 0a jcxz +0xa <0x10>
0x6: 8d 58 01 leal 0x1(%rax),%ebx
0x9: 48 03 c3 addq %rbx,%rax
0xc: 48 93 xchgq %rbx,%rax
0xe: e2 f9 loop -0x7 <0x9>
0x10: c3 ret
Linux
$ as --64 -o y.o -V y.s
GNU assembler version 2.22.90 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.22.90.20120924
$ objdump -d y.o
y.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <fib>:
0: 89 f9 mov %edi,%ecx
2: 31 c0 xor %eax,%eax
4: e3 0a jrcxz 10 <fib+0x10>
6: 8d 58 01 lea 0x1(%rax),%ebx
9: 48 01 d8 add %rbx,%rax
c: 48 93 xchg %rax,%rbx
e: e2 f9 loop 9 <fib+0x9>
10: c3 retq
为什么生成的机器代码是不同的?Sun为mov %edi,%ecx
生成mov %edi,%ecx
,而gas为同一指令生成89 f9
。这是因为在x86下编码同一条指令的各种方式,还是这两种编码确实有特殊的区别?
发布于 2013-07-31 14:29:53
一些x86指令具有多个编码,这些编码可以完成相同的任务。特别是,在两个寄存器上工作的任何指令都可以交换寄存器,并反转指令中的方向位。
给定的汇编程序/编译器选择哪一个只取决于作者所选择的工具。
发布于 2013-08-05 20:42:14
您没有为mov
、xor
和add
操作指定操作数大小。这就造成了一些模糊。GNU汇编程序手册i386记忆学提到了以下内容:
如果指令没有指定后缀,则尝试根据目标寄存器操作数(最后一个按惯例)填充缺失的后缀。...请注意,这与AT&T Unix汇编程序不兼容,后者假定缺少的助记符后缀意味着长操作数大小。
这意味着GNU汇编程序的选择不同--它将选择带有R/M字节指定目标操作数的操作码(因为目标大小为已知/隐含的),而AT&T则选择R/M字节指定源操作数的操作码(因为操作数大小是隐含的)。
不过,我已经做了这个实验,并在程序集源中给出了显式的操作数大小,并且它不改变GNU汇编程序输出。不过,上面还有文件的另一部分,
可以通过可选的助记符后缀指定不同的编码选项。当从一个寄存器移动到另一个寄存器时,“.s”后缀交换编码中的2寄存器操作数。
使用GNU as
,下面的源代码创建了从Solaris as
获得的操作码
.globl fib
fib: movl.s %edi,%ecx
xorl.s %eax,%eax
jrcxz 1f
leal 1(%rax),%ebx
0: addq.s %rbx,%rax
xchgq %rax,%rbx
loop 0b
1: ret
https://stackoverflow.com/questions/17973103
复制相似问题