为什么Solaris汇编程序生成的机器代码与GNU汇编程序不同?

时间:2013-07-31 14:25:43

标签: linux assembly solaris x86-64

我为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上反汇编。

的Solaris

$ 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为8b cf生成mov %edi,%ecx,而气体为同一指令生成89 f9。这是因为在x86下编码相同指令的各种方法还是这两种编码真的有区别吗?

2 个答案:

答案 0 :(得分:6)

某些x86指令具有多个执行相同操作的编码。特别是,任何作用于两个寄存器的指令都可以交换寄存器,并反转指令中的方向位。

给定的汇编器/编译器选择哪一个只取决于工具作者选择的内容。

答案 1 :(得分:1)

未指定movxoradd操作的操作数大小。这造成了一些歧义。 GNU汇编程序手册i386 Mnemonics提到了这一点:

  

如果指令没有指定后缀,则尝试根据目标寄存器操作数(按惯例最后一个)填写缺少的后缀。 [...] 请注意,这与AT&amp; T Unix汇编程序不兼容,它假定缺少助记符后缀意味着长操作数大小。

这意味着GNU汇编器选择不同 - 它将选择具有指定目标操作数的R / M字节的操作码(因为目标大小是已知/隐含的),而AT&amp; T选择其中R / M的操作码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