○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