5

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   

生成されたマシン コードが異なるのはなぜですか? 太陽は生成さ8b cfmov %edi,%ecx、ガス89 f9はまったく同じ命令で生成されます。これは、x86 で同じ命令をエンコードするさまざまな方法によるものですか、それともこれら 2 つのエンコーディングには実際に特定の違いがありますか?

4

2 に答える 2

6

一部の x86 命令には、同じことを行う複数のエンコーディングがあります。特に、2 つのレジスタに作用する命令は、レジスタをスワップし、命令の方向ビットを反転させることができます。

特定のアセンブラー/コンパイラーがどれを選択するかは、ツールの作成者が選択したものに依存します。

于 2013-07-31T14:29:53.067 に答える
1

、および演算のオペランド サイズが指定されていません。これにより、あいまいさが生じます。GNU アセンブラーのマニュアルi386 Mnemonicsでは、次のように言及されています。movxoradd

命令で接尾辞が指定されていない場合、 as は、デスティネーション レジスタ オペランド (規則による最後のオペランド) に基づいて、欠落している接尾辞を埋めようとします。[...] . これは AT&T Unix アセンブラと互換性がないことに注意してください。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
于 2013-08-05T20:42:14.997 に答える