2016-05-19 12 views
1

インラインアセンブリを使用して、2つのメモリ位置をC変数に読み込み、2つのC変数を他のメモリ位置に格納する必要があります。私が書いたインラインコードは次のようになります。インラインCアセンブリが独自の変数を呼び出す

unsigned int us32 = (uint32_t)us; 
__asm__ __volatile__("ldr %1, [%4, #0x10]\r\n" //read my 2 memory locations 
        "ldr %0, [%4, #0x18]\r\n" 
        "str %2, [%4, #0x14]\r\n" //write my 3 memory locations 
        "str %2, [%4, #0x18]\r\n"  
        "str %3, [%4, #0x10]\r\n" 
        : "=l" (leftover_time), "=l" (rollflag) 
        : "l" (us32), "l" (ena), "l" (s) 
        : "memory", "cc"); 

私のインラインコードから生成されたアセンブリは、しかし、動作するようには思えません。私はr2とr3に格納したい変数をロードして、ロードしようとしている変数をすぐに見つけ出します。これは私が時間の異なるインラインアセンブリのチュートリアルを読んで、私は&ダブルチェック私の入力/出力制約をチェックしましたし、私はちょうどよ、私はarm-none-eabi-objdump

us32 = (uint32_t)us; 
c8e:  6bbb   ldr  r3, [r7, #56] ; 0x38 
c90:  637b   str  r3, [r7, #52] ; 0x34 
__asm__ __volatile__("ldr %1, [%4, #0x10]\r\n" 
;;; These 4 instructions load the variables I want to write to memory 
;;; into r2 and r3 
c92:  2207   movs r2, #7 
c94:  4b39   ldr  r3, [pc, #228] ; (d7c <reschedule+0x16c>) 
c96:  6819   ldr  r1, [r3, #0] 
c98:  6b7b   ldr  r3, [r7, #52] ; 0x34 

;;; BOOM!! r2 and r3 have been clobbered, they no longer contain the 
;;; values that I want to write (a constant #7 and unsigned in us32). 
;;; 
;;; The data that I want to read is indeed pointed by r1 + 16 and r1 + 24 
c9a:  690b   ldr  r3, [r1, #16] 
c9c:  698a   ldr  r2, [r1, #24] 
c9e:  614b   str  r3, [r1, #20] 
ca0:  618b   str  r3, [r1, #24] 
ca2:  610a   str  r2, [r1, #16] 
ca4:  633a   str  r2, [r7, #48] ; 0x30 
ca6:  62fb   str  r3, [r7, #44] ; 0x2c 

を使用してしまった以下の解体からかなり明確です私の頭を掻きながらここに座っている。誰かが私の間違いを捕まえることができます

私はarm-none-eabi-gccバージョン4.8.4

+0

あなたのコードはフラグを壊さないので、あなたは '' cc ''clobberは必要ありません。メモリ出力オペランドを使用した場合、 ''メモリ ''クラバーを避けることもできます。 (clobberのドキュメントのようにすべてのストアをカバーするダミー構造体が示唆しているか、またはgccがアドレッシングモードを選択できるように各ストアの個々のメモリオペランドを指定するか、[[named] "r"(operands)もう一度番号を付け加えると混乱を避けることができます。 –

+0

'strd'を同じレジスタで2回使うと、最初の2つのストアを1つの命令で実行できますか?いいえの場合は、#10と#14の店舗を並べ替えることができますが、それはインオーダーCPUで悪化します。 –

+1

@PeterCordes "cc"フラグは、私が書いた他のコードから継承されています。私はそれらを削除します。名前付きレジスタと構造体についてのヒントをありがとう。また、m0 +を使用しているため、 'strd'を実行できません。これは、その命令をサポートしていません。 –

答えて

3

関連段落はthe extended asm documentationの真ん中に隠された権利である:

は、入力を重複してはならない、すべての出力オペランドに(Modifiersを参照)&制約修飾子を使用します。さもなければ、GCCは出力を生成する前にアセンブラコードがその入力を消費すると仮定して、無関係の入力オペランドと同じレジスタに出力オペランドを割り当てることができる。アセンブラコードが実際に複数の命令で構成されている場合、この仮定は誤っている可能性があります。

負荷の前に店舗がある場合は、実際にその仮定を満たしていればすべてが問題ありません。そうしないと、出力を初期クロバーのオペランドとしてマークする必要があります。つまり、"=&l"です。

+0

うわー...それは私の問題を完全に解決しました。私は読んだ後にそれを見つけることができなかったとは信じられません。 gccが自動的に&を仮定していないことは私にはかなり驚きです。 –

+1

@johnny_boy:GNU Cのインラインasm構文は、コンパイラが発行することができない単一の命令をラップするために設計されています。そのため、デフォルトはそうです。通常、コンパイラにできるだけ多くのことをさせるのが最善です。 GNU Cインラインへのリンク集については、[この回答の下](http://stackoverflow.com/questions/34520013/using-base-pointer-register-in-c-inline-asm/34522750#34522750)を参照してください。 asmガイドとQ&A。それらはすべてx86を使用しますが、概念はARMにも等しく適用されます。 GNU Cを書くことは、制約を間違えてしまうので、asmを学ぶ最も難しい方法です。 –

+0

@johnny_boyほとんどの場合、可能な場合には、出力レジスタに再利用されるすべての入力レジスタが必要になります。代替手段がasmの周りのスタックに流出することを意味します。 – Notlikethat

2

を使用していますが、入力を消費する前r2r3を上書きさ、あなたはコンパイラに知らせるのを忘れていました。あなたは彼らのために&早期クロバー修飾子を必要とする:

入力を重複してはならない、すべての出力オペランド の「&」制約修飾子を(修飾子を参照)を使用します。そうでなければ、 出力を生成する前に、アセンブラコードがその入力を消費すると仮定して、 オペランドを無関係な入力オペランドと同じレジスタに割り当てることができます。この仮定は、アセンブラコード が実際に複数の命令で構成されている場合は、誤っている可能性があります。

Source

関連する問題