○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