cとアセンブリの混合プログラミング

13475 ワード

様々な高級言語が盛んな今日、なぜアセンブリを使うのでしょうか.実は主な原因はあります:第一に、C言語で肝心な場所にアセンブリを埋め込むと、いくつかの肝心なアルゴリズムなど、最大の性能向上を得ることができます.第二に、ハードウェア関連の機能を実現する(この点は組み込み開発でよく用いられる).第三に、C言語で実現できない特性をアセンブリで実現することができ、例えばlock命令を用いて原子操作を実現することができる.本稿では、アセンブリ言語をc言語に埋め込む基礎を紹介し、2つの例を示した.
小宇のブログ
データベースでは、tasロックなどの特殊な操作を実現するために、アセンブリを使用して完了する必要があります.例えばPostgreSQLのtasロックはアセンブリで書かれています.では、どのようにcとアセンブリを混合してプログラミングしますか?まず基本文法を紹介します.c言語にアセンブリを埋め込む文法は以下の通りです.
     asm [volatile] ( AssemblerTemplate
                      : OutputOperands
                      [ : InputOperands
                      [ : Clobbers ] ])
asm:埋め込みアセンブリの開始を示すvolatile:コンパイラ最適化をオフにすることで、一部のコンパイラが無効とみなされるアセンブリを削除しないAssemblerTemplate:アセンブリを生成するためのテンプレートで、アセンブリコードとプレースホルダが含まれているOutputOperands:アセンブリで修正されたcプログラムの変数、カンマ区切りInputOperands:アセンブリで読み取ったcプログラムの変数をカンマ区切りClobbers:OutputOperandsにリストされている以外はアセンブリで修正されたregisterまたはその他の値
以下、上記の内容をそれぞれご紹介します
AssemblerTemplate
アセンブリテンプレートは実際には文字列です.たとえば
        "   cmpb    $0,%1   
"
" jne 1f
"
" lock
"
" xchgb %0,%1
"

中にはOutputOperandsInputOperandsへの引用が含まれています.次にコンパイラは、アセンブリ魔板の参照などを実際のアセンブリ命令に変換します.アセンブルテンプレートにはアセンブル命令のほかに、特殊記号がいくつかあります.特殊記号は他の意味を表しています.%n:引用OutputOperandsInputOperandsのいくつかの値%%:アセンブルに出力%記号%=:1つの数字を出力します.毎回違います.一般的にgotoラベルとして使用されます.%{:出力{%|:出力|%}:出力}OutputOperands OutputOperandsの文法は以下の通り.
[ [asmSymbolicName] ] constraint (cvariablename)

asmSymbolicName asmSymbolicNameasm記号名、asmテンプレート内に%[Value]で指定されている場合.では、OutputOperands[ [asmSymbolicName] ] constraint (cvariablename)具体的なcプログラム変数名にマッピングできます.例:
    int a,b;
    /* a=1;b=2;*/
    asm("mov $1,%[a]
"
"mov $2,%[b]
"
:[a]"+rm"(a),[b]"+rm"(b) :/* no output */ :"cc"); printf("a=%d
b=%d
"
,a,b);
asm 名称を使用していない場合は、0の下付きで始まる変数名%0%1で参照してください.例:
    int a,b;
    /* a=1;b=2;*/
    asm("mov $1,%0
"
"mov $2,%1
"
:"+rm"(a),"+rm"(b) :/* no output */ :"cc"); printf("a=%d
b=%d
"
,a,b);

constraint
1つの文字列を定義記号として使用します.定義子は変数配置の位置を説明するために使用する=この変数は既存の変数を上書きする+変数は読み書き用r変数をregisterレジスタに入れるm変数をmemoryに置く
cvariablename
cプログラムコンテキストの変数名を参照
InputOperands
文字通りInputOperands入力された変数を表し、これらの変数がアセンブリされて使用されます.
Clobbers cc以上のアセンブラコードがフラグビットを変更しているmemory以上のアセンブラコードがメモリ読み書きされている
では、基本的な文法を説明した後、いくつかの例を簡単に見てみましょう.
例1-代入
最も簡単な例として、アセンブルされたmov命令を用いて、値を付与する.
#include
#include
int main()
{
    int a,b;
    __asm__("mov $1,%0
"
"mov $2,%1
"
:"+rm"(a),"+rm"(b) :/* no output */ :"cc"); printf("a=%d
b=%d
"
,a,b); }

結果は,a,bが既に付与されていることがわかる.
$ ./main 
a=1
b=2

実際に生成されたアセンブリ:
0000000000400526 
: 400526: 55 push %rbp 400527: 48 89 e5 mov %rsp,%rbp 40052a: 48 83 ec 10 sub $0x10,%rsp 40052e: 8b 55 f8 mov -0x8(%rbp),%edx 400531: 8b 45 fc mov -0x4(%rbp),%eax 400534: ba 01 00 00 00 mov $0x1,%edx 400539: b8 02 00 00 00 mov $0x2,%eax 40053e: 89 55 f8 mov %edx,-0x8(%rbp) 400541: 89 45 fc mov %eax,-0x4(%rbp) 400544: 8b 55 fc mov -0x4(%rbp),%edx 400547: 8b 45 f8 mov -0x8(%rbp),%eax 40054a: 89 c6 mov %eax,%esi 40054c: bf f4 05 40 00 mov $0x4005f4,%edi 400551: b8 00 00 00 00 mov $0x0,%eax 400556: e8 a5 fe ff ff callq 400400 @plt> 40055b: b8 00 00 00 00 mov $0x0,%eax 400560: c9 leaveq 400561: c3 retq 400562: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 400569: 00 00 00 40056c: 0f 1f 40 00 nopl 0x0(%rax)

例2–交換
一般的にc言語では、a,bの値を交換するには3つの文が必要です.
temp=a;
a=b;
b=temp;

アセンブリxchg命令により、1つの命令でa,b交換を完了し、中間変数を使用しない
#include
#include
int main()
{
    int a=2,b=1;
    /* a=b;b=a;*/
    asm("xchg %0,%1
"
:"+rm"(a),"+rm"(b) :/* no output */ :"cc"); printf("a=%d
b=%d
"
,a,b); }

結果は,a,bが既に付与されていることがわかる.
$ ./main 
a=1
b=2

例3-tasロック
tasロックは、操作全体が1つの命令でのみ完了し、操作の「原子性」を保証するためにバスをロックする.それに比べて、C文はコンパイル後にいったいいくつかの命令が保証されていないのか、計算中にバスにロックをかけることも要求できない.このときはlockコマンドでこの作業を完了します.
static __inline__ int
tas(volatile lock_t *lock)
{
    register lock_t _res = 1;

    __asm__ __volatile__(
        "   cmpb    $0,%1   
"
" jne 1f
"
" lock
"
" xchgb %0,%1
"
"1:
"
: "+q"(_res), "+m"(*lock) : /* no inputs */ : "memory", "cc"); return (int) _res; }

上記コードのlock命令は次のxchgb命令交換*lockおよび_resの動作が原子的であることを確保している.これにより、取得*lockの値を戻り値として、*lockを1とする2つの動作が一気に完了します.
興味があればさらに読むことができます:gcc公式ドキュメント:https://gcc.gnu.org/onlinedocs/gcc-6.2.0/gcc/Extended-Asm.html#Extended-ASM Linuxアセンブリ言語開発ガイド:http://www.ibm.com/developerworks/cn/linux/l-assembly良いブログ:http://blog.csdn.net/hu3167343/article/details/37660593