インラインアセンブラ

出典: フリー百科事典『ウィキペディア(Wikipedia)』
移動: 案内検索

インラインアセンブラ: Inline assembler)とはプログラミング用語であり、最も低レベルなアセンブリ言語で記述されたコードをC言語Adaのような高級言語ソースコードに埋め込む機能のこと。一部のコンパイラがこの機能を有する。一般的に次の3つの理由で実装される。

最適化の例とプロセッサ固有命令の例[編集]

x86FPUを利用して変数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;
}

外部リンク[編集]