「インラインアセンブラ」の版間の差分
表示
削除された内容 追加された内容
編集の要約なし |
|||
11行目: | 11行目: | ||
[[x86]]の[[FPU]]を利用して変数xのタンジェントを計算する[[D言語]]で記述されたインラインアセンブラの例。x86系プロセッサで利用可能な[[円周率]]の近似値を得るための<code>fldpi</code>命令を利用でき、コンパイラが浮動小数点を用いた場合より高速である。 |
[[x86]]の[[FPU]]を利用して変数xのタンジェントを計算する[[D言語]]で記述されたインラインアセンブラの例。x86系プロセッサで利用可能な[[円周率]]の近似値を得るための<code>fldpi</code>命令を利用でき、コンパイラが浮動小数点を用いた場合より高速である。 |
||
< |
<syntaxhighlight lang="d"> |
||
// 変数xのタンジェントを計算する |
// 変数xのタンジェントを計算する |
||
real tan(real x) |
real tan(real x) |
||
43行目: | 43行目: | ||
; |
; |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
== システムコールの例 == |
== システムコールの例 == |
||
52行目: | 52行目: | ||
基本的なインラインアセンブラの形式は非常に単純である。基本形は下記のとおり([[GNUコンパイラコレクション|GCC]]のみ、Visual Studio では __asm{ }の形式に直す必要がある)。 |
基本的なインラインアセンブラの形式は非常に単純である。基本形は下記のとおり([[GNUコンパイラコレクション|GCC]]のみ、Visual Studio では __asm{ }の形式に直す必要がある)。 |
||
< |
<syntaxhighlight lang="c">asm("アセンブリコード");</syntaxhighlight> |
||
例: |
例: |
||
< |
<syntaxhighlight lang="c">asm("movl %ecx, %eax"); /* ecxの中身をeaxに移動する */</syntaxhighlight> |
||
または |
または |
||
< |
<syntaxhighlight lang="c">__asm__("movb %bh, (%eax)"); /* bhから1バイトをeaxが指し示すメモリに移動する */</syntaxhighlight> |
||
<code>asm</code>と<code>__asm__</code>はいずれも正しい。もし<code>asm</code>というキーワードがソースコード中のほかのキーワードと重複している場合は<code>__asm__</code>を利用してもよい。 |
<code>asm</code>と<code>__asm__</code>はいずれも正しい。もし<code>asm</code>というキーワードがソースコード中のほかのキーワードと重複している場合は<code>__asm__</code>を利用してもよい。 |
||
< |
<syntaxhighlight lang="c"> |
||
extern int errno; |
extern int errno; |
||
87行目: | 87行目: | ||
return res; |
return res; |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
==注== |
==注== |
2020年7月5日 (日) 23:02時点における版
インラインアセンブラ(英: Inline assembler)は、高水準言語の処理系中に埋込まれているアセンブラ、ないし、そのような言語でソースコード中(インライン)にアセンブリ言語によるコードを埋込むことができる、という機能である。たとえば以下のような利用法がある。
- 最適化
- アルゴリズムで最も性能に影響する部分をアセンブリ言語に置き換える。これによりプログラマはコンパイラの制約を受けることなく自由に細工を施すことができる。
- プロセッサ固有の特殊な命令の利用
- コンペア・アンド・スワップやテスト・アンド・セットのような、セマフォやロックを実装するための命令があるプロセッサがあるが、それらの機能を言語拡張などではなく[1]、インラインアセンブラにより直接簡便に利用できる。他には、SIMD拡張命令など具体的にはSPARCのVIS、インテルのMMXやSSE、モトローラのAltivecといった命令はコンパイラからの有効的利用が難しく(研究はさかんに行われているが)、インラインアセンブラを利用してC言語中から直接利用することで高い性能を実現できることがある。
- システムコール
- システムコールのAPIは、現代では通常はC言語のライブラリとして定義されているが、上述の特殊な命令と同様にSVC命令などを直接利用して呼び出すためにアセンブリ言語が利用される。
最適化の例とプロセッサ固有命令の例
x86のFPUを利用して変数xのタンジェントを計算するD言語で記述されたインラインアセンブラの例。x86系プロセッサで利用可能な円周率の近似値を得るためのfldpi
命令を利用でき、コンパイラが浮動小数点を用いた場合より高速である。
// 変数xのタンジェントを計算する
real tan(real x)
{
asm
{
fld x[EBP] ; // xをロード
fxam ; // 不正な値の検査
fstsw AX ;
sahf ;
jc trigerr ; // xはNAN(非数)、無限、または空
// 387は非正規化数を扱えない
SC18: fptan ;
fstp ST(0) ; // dump X, which is always 1
fstsw AX ;
sahf ;
jnp Lret ; // C2 = 1 (xは範囲外)
// argument reductionしてxを有効範囲内に収める
fldpi ;
fxch ;
SC17: fprem1 ;
fstsw AX ;
sahf ;
jp SC17 ;
fstp ST(1) ; // piをスタックから除去
jmp SC18 ;
}
trigerr:
return real.nan;
Lret:
;
}
システムコールの例
メモリが保護されている環境でOSの機能を直接呼び出すことは一般的に不可能である。OSはユーザーモードより上位の特権モード(カーネルモード)で動作しており、OSにリクエストするためには(ソフトウェア)割り込みを利用する。これを行う機能をもつ高級言語はほとんどなく、システムコールのためのラッパー関数はインラインアセンブラを用いて記述されている。
下記のC言語によるサンプルにはシステムコールのラッパーも含まれる。一般的にはマクロと組み合わせて記述するが、ここでは説明のためにあえてマクロを利用していない。
基本的なインラインアセンブラの形式は非常に単純である。基本形は下記のとおり(GCCのみ、Visual Studio では __asm{ }の形式に直す必要がある)。
asm("アセンブリコード");
例:
asm("movl %ecx, %eax"); /* ecxの中身をeaxに移動する */
または
__asm__("movb %bh, (%eax)"); /* bhから1バイトをeaxが指し示すメモリに移動する */
asm
と__asm__
はいずれも正しい。もしasm
というキーワードがソースコード中のほかのキーワードと重複している場合は__asm__
を利用してもよい。
extern int errno;
int funcname(int arg1, int *arg2, int arg3)
{
int res;
__asm__ volatile(
"int $0x80" /* OSに命令を発行する */
: "=a" (res) /* eaxの中身("a")を結果として返す */
"+b" (arg1), /* arg1をebxに渡す ("b") */
"+c" (arg2), /* arg2をecxに渡す ("c") */
"+d" (arg3) /* arg3をedxに渡す ("d") */
: "a" (128) /* システムコール番号をeaxに渡す ("a") */
: "memory", "cc"); /* メモリと条件レジスタが修正されたことをコンパイラに通知する */
/* エラーが発生した場合、OSは負数を返す。
* エラーが発生するとラッパー関数は-1を返し、グローバル変数errnoに値をセットする */
if (-125 <= res && res < 0) {
errno = -res;
res = -1;
}
return res;
}
注
- ^ GCCはそれらをサポートする組込み関数を持っている( https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html )