○GCC x86インラインアセンブラ

asm ("命令 source,dest");



■グローバル変数 ---------------------------------------------------------
そのまま使えます

#include <stdio.h>

int i;
int j;

main(){
  i=10;
  asm ("movl i,%eax");
  asm ("add $10,%eax");  //数値は先頭に$マークを付ける
  asm ("movl %eax,j");

  printf("%d %d\n",i,j);
}


▼上のプログラムの書き方を変えたもの

#include <stdio.h>

int i;
int j;

main(){
  i=10;
  asm (  "movl i,%eax  \n\t"
    "add $10,%eax  \n\t"
    "movl %eax,j");

  printf("%d %d\n",i,j);
}



■自動変数 ---------------------------------------------------------
自動変数はフレームポインタebpを使ってアクセスする

#include <stdio.h>

main(){
  int i;  //-4(%ebp)
  int j;  //-8(%ebp)
  i=10;
  asm (  "movl -4(%ebp),%eax  \n\t"
    "add $10,%eax    \n\t"
    "movl %eax,-8(%ebp)");

  printf("%d %d\n",i,j);
}


■関数 ---------------------------------------------------------
関数の引数はフレームポインタebpを使ってアクセスする

引数でわたされたa b cを自動変数のaa bb ccにコピーする関数

void test(int a,int b,int c){
  int aa;
  int bb;
  int cc;

  // a の値を aa に複製
  asm ("movl 8(%ebp),%eax");
  asm ("movl %eax,-4(%ebp)");

  // b の値を bb に複製
  asm ("movl 12(%ebp),%eax");
  asm ("movl %eax,-8(%ebp)");

  // c の値を cc に複製
  asm ("movl 16(%ebp),%eax");
  asm ("movl %eax,-12(%ebp)");

  printf("%d %d %d\n",aa,bb,cc);
}

▼上の場合ebpとの関係は次のようになります

引数
a  8(%ebp)
b  12(%ebp)
c  16(%ebp)

自動変数
aa  -4(%ebp)
bb  -8(%ebp)
cc  -12(%ebp)



■アセンブラのみで関数を作成 ---------------------------------------------------------

▼関数の戻り値が整数もしくはポインタの場合%eaxに戻り値を入れる

#include <stdio.h>

asm ("test:");    //関数名
asm ("  movl $20,%eax");  //戻り値を%eaxに入れる
asm ("  ret");    //戻る

extern int test();

main(){
  int i=test();
  printf("%d\n",i);
}


▼関数の戻り値が浮動小数点の場合
戻り値は、FTPレジスタの先頭に置く

#include <stdio.h>

float i=10.01;

asm ("test:");
asm ("  fld i");  //FTPレジスタにプッシュする
asm ("  ret");

extern float test();

main(){
  printf("%g\n",test());
}



■拡張機能 ---------------------------------------------------------


asm (アセンブラ : "=レジスタ文字"(出力先変数) : "レジスタ文字"(入力元変数) : 退避するレジスタ);


▼レジスタと修飾文字

"a"  %eax
"b"  %ebx
"c"  %ecx
"d"  %edx
"s"  %esi
"D"  %edi
"r"  レジスタの自動割り当て

"t"  浮動小数点レジスタの先頭
"u"  浮動小数点レジスタの2番目
"f"  浮動小数点レジスタの自動割り当て

退避するレジスタは"%eax","%ebx"の様に指定します。
項目は , で区切り複数指定できます。

▼レジスタを自動で割り当ててadd命令を実行する
%0 %1 %2などは、前から何番目のレジスタを使用するかを意味する

int test(int i,int j){
  int k;
  asm ("add %1,%2" :  "=r"(k) : "r" (i) ,"r" (j));
  return k;
}

▼レジスタを割り当てて、add命令を実行する

int test(int i,int j){
  int k;
  asm volatile ("nop" :: "a" (i));    // 変数 i を %eax に入れて
  asm volatile ("nop" :: "b" (j));    // 変数 j を %ebx に入れて
  asm volatile ("add %eax,%ebx");  // %eax と %ebx に対して add 命令を実行
  asm volatile ("nop" :"=b"(k));    // %ebx を 変数 k に入れる
  return k;
}


▼浮動小数点を計算する

double test(double i,double j){
  double k;
  asm ("fadd %1,%2" : "=&t"(k) : "f"(i),"f"(j));
  return k;
}



▲トップページ > Linux と C