2017-01-27 5 views
3

私はg ++インラインアセンブラでまだ苦労しており、使い方を理解しようとしています。g ++から簡単な逆アセンブルされたコードを理解しようとしています

私はここからのコードの一部を適応しました:(gccのinfoファイル中の「C式オペランドとアセンブラ命令」より引用)http://asm.sourceforge.net/articles/linasm.html

static inline uint32_t sum0() { 
    uint32_t foo = 1, bar=2; 
    uint32_t ret; 
    __asm__ __volatile__ (
     "add %%ebx,%%eax" 
     : "=eax"(ret)    // ouput 
     : "eax"(foo), "ebx"(bar) // input 
     : "eax"     // modify 
    ); 
    return ret; 
} 

私は最適化を無効にまとめました:

g++ -Og -O0 inline1.cpp -o test 

逆アセンブルコードは私を困惑:

(gdb) disassemble sum0 
Dump of assembler code for function sum0(): 
    0x00000000000009de <+0>: push %rbp     ;prologue... 
    0x00000000000009df <+1>: mov %rsp,%rbp    ;prologue... 
    0x00000000000009e2 <+4>: movl $0x1,-0xc(%rbp)  ;initialize foo 
    0x00000000000009e9 <+11>: movl $0x2,-0x8(%rbp)  ;initialize bar 
    0x00000000000009f0 <+18>: mov -0xc(%rbp),%edx  ; 
    0x00000000000009f3 <+21>: mov -0x8(%rbp),%ecx  ; 
    0x00000000000009f6 <+24>: mov %edx,-0x14(%rbp)  ; This is unexpected 
    0x00000000000009f9 <+27>: movd -0x14(%rbp),%xmm1  ; why moving variables 
    0x00000000000009fe <+32>: mov %ecx,-0x14(%rbp)  ; to extended registers? 
    0x0000000000000a01 <+35>: movd -0x14(%rbp),%xmm2  ; 
    0x0000000000000a06 <+40>: add %ebx,%eax    ; add (as expected) 
    0x0000000000000a08 <+42>: movd %xmm0,%edx   ; copying the wrong result to ret 
    0x0000000000000a0c <+46>: mov %edx,-0x4(%rbp)  ; "  " "  "  " " 
    0x0000000000000a0f <+49>: mov -0x4(%rbp),%eax  ; "  " "  "  " " 
    0x0000000000000a12 <+52>: pop %rbp     ; 
    0x0000000000000a13 <+53>: retq 
End of assembler dump. 

期待どおり、sum0()関数は間違った値を返します。

どのような考えですか?何が起こっている?それをどうやって得るの?

- EDIT - @MarcGlisseのコメントに基づいて 、私が試した:

static inline uint32_t sum0() { 
    uint32_t foo = 1, bar=2; 
    uint32_t ret; 
    __asm__ __volatile__ (
     "add %%ebx,%%eax" 
     : "=a"(ret)    // ouput 
     : "a"(foo), "b"(bar)  // input 
     : "eax"     // modify 
    ); 
    return ret; 
} 

私は、次のしてきたチュートリアルでは、誤解を招くようです。出力/入力フィールドの "eax"は、レジスタ自体を意味するのではなく、略語表のe、a、x略語を意味します。

とにかく、私はまだそれを正しくしません。上記のコードはコンパイルエラーになります: 'asm'オペランドには不可能な制約があります。

なぜ表示されません。

+0

最適化を有効にすると、そのことを理解しやすくなります。 –

+0

"eax"はあなたが思っていることを意味するものではなく、 "a"が必要です。そして、出力がぎっしりと詰まったものとしてマークする必要はありません。 –

+1

より注意深くお読みください。「出力が詰まっているとマークする必要はありません。 –

答えて

2

x86の拡張インラインアセンブリの制約は、official documentationに記載されています。
complete documentationも読む価値があります。

ご覧のとおり、制約はすべて1文字です。
foo foの制約「EAX」は3つの制約を指定:あなたはeaxが、それはそこに入力オペランドを置くことができない上書きされ、それがxmm0を選ぶことGCCを言っているので

a
   The a register.

x
   Any SSE register.

e
   32-bit signed integer constant, or ...

を。

When the compiler selects the registers to use to represent the input operands, it does not use any of the clobbered registers

proper constraint is simply "a"
クローバーから(つまり、上位ビットがゼロになるため)を削除し、「cc」を追加する必要があります。eaxを削除する必要があります。

+0

ありがとう!結果のコードを表示するために質問を編集しました。 – Chocksmith

+0

@Chocksmith Gladが役に立ちました。しかし、私の答えは、あなたの問題を解決したことを伝えるために必要なすべてのものをマークしているので、冗長です。私はそれをSOのガイドラインに準拠させるためにあなたの編集をロールバックしています:)それはまた、同じ問題を持つ将来の読者を助けるでしょう –

関連する問題