C Language
インラインアセンブリ
サーチ…
備考
インラインアセンブリは、Cソースコードの途中でアセンブリ命令を追加する方法です。 ISO C標準では、インラインアセンブリのサポートは必要ありません。必須ではないため、インラインアセンブリの構文はコンパイラによって異なります。通常はサポートされていますが、インラインアセンブリを使用する理由はほとんどなく、多くの理由がありません。
長所
- パフォーマンス操作のための特定のアセンブリ命令を記述することによって、コンパイラによって生成されたアセンブリコードよりも優れたパフォーマンスを達成することができます。これらのパフォーマンスの向上はまれであることに注意してください。ほとんどの場合、Cコードを並べ替えるだけでパフォーマンスが向上し、オプティマイザがその機能を果たすことができます。
- ハードウェアインタフェースデバイスドライバまたはプロセッサのスタートアップコードは、正しいレジスタにアクセスし、特定の動作が特定の順序で発生することをオペレーション間の特定の遅延で保証するために、いくつかのアセンブリコードを必要とする場合があります。
短所
- コンパイラの移植性インラインアセンブリの構文は、あるコンパイラから別のコンパイラに同じであることが保証されていません。別のコンパイラでサポートされるはずのインラインアセンブリを使用してコードを記述する場合は、プリプロセッサマクロ(
#ifdef
)を使用して、使用されているコンパイラを確認します。次に、サポートされているコンパイラごとに別々のインラインアセンブリセクションを作成します。 - プロセッサーの移植性 x86プロセッサー用のインラインアセンブリーは作成できず、ARMプロセッサー上で動作するはずです。インラインアセンブリは、特定のプロセッサまたはプロセッサファミリ用に記述されています。異なるプロセッサでサポートしたいインラインアセンブリがある場合は、プリプロセッサマクロを使用して、コードがコンパイルされているプロセッサを確認し、適切なアセンブリコードセクションを選択します。
- 将来のパフォーマンスの変更インラインアセンブリは、特定のプロセッサクロック速度に基づいて遅延を予想して記述することができます。プログラムがより高速なクロックを持つプロセッサ用にコンパイルされている場合、アセンブリコードが期待どおりに実行されないことがあります。
gcc基本asmサポート
gccを使った基本的なアセンブリのサポートには、次の構文があります。
asm [ volatile ] ( AssemblerInstructions )
ここで、 AssemblerInstructions
は、指定されたプロセッサの直接アセンブリコードです。 volatileキーワードはオプションであり、gccは基本的なasm文の中でコードを最適化しないため、何の効果もありません。 AssemblerInstructions
は、複数のアセンブリ命令を含めることができます。 asmルーチンがC関数の外部になければならない場合は、基本asmステートメントが使用されます。次の例は、GCCのマニュアルです。
/* Note that this code will not compile with -masm=intel */
#define DebugBreak() asm("int $3")
この例では、コードの他の場所でDebugBreak()
を使用すると、アセンブリ命令int $3
が実行されます。 gccは基本的なasm文のコードを変更しなくても、オプティマイザは引き続き連続したasm文を動かすことができることに注意してください。特定の順序で実行する必要があるアセンブリ命令が複数ある場合は、それらを1つのasmステートメントに含めます。
gcc拡張asmサポート
gccの拡張asmサポートには、次の構文があります。
asm [volatile] ( AssemblerTemplate
: OutputOperands
[ : InputOperands
[ : Clobbers ] ])
asm [volatile] goto ( AssemblerTemplate
:
: InputOperands
: Clobbers
: GotoLabels)
ここAssemblerTemplate
アセンブラ命令についての鋳型である、 OutputOperands
アセンブリコードで変更することができる任意のC変数である、 InputOperands
入力パラメータとして使用される任意のC変数である、 Clobbers
アセンブリコードによって変更されるリストまたはレジスタであり、 GotoLabels
アセンブリコードで使用されるgoto文ラベルです。
拡張フォーマットはC関数内で使用され、インラインアセンブリのより一般的な使用法です。以下は、ARMプロセッサ用の16ビットおよび32ビットの数値をバイトスワップするLinuxカーネルの例です。
/* From arch/arm/include/asm/swab.h in Linux kernel version 4.6.4 */
#if __LINUX_ARM_ARCH__ >= 6
static inline __attribute_const__ __u32 __arch_swahb32(__u32 x)
{
__asm__ ("rev16 %0, %1" : "=r" (x) : "r" (x));
return x;
}
#define __arch_swahb32 __arch_swahb32
#define __arch_swab16(x) ((__u16)__arch_swahb32(x))
static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
{
__asm__ ("rev %0, %1" : "=r" (x) : "r" (x));
return x;
}
#define __arch_swab32 __arch_swab32
#endif
各asmセクションは変数x
をその入力および出力パラメータとして使用します。 C関数は、操作された結果を返します。
拡張されたasm形式では、gccはCコードの最適化に使用するのと同じ規則に従ってasmブロック内のアセンブリ命令を最適化することができます。 asmセクションを変更しない場合は、asmセクションにvolatile
キーワードを使用します。
gccマクロのインラインアセンブリ
アセンブリーの指示をマクロの中に入れ、関数を呼び出すようにマクロを使用することができます。
#define mov(x,y) \
{ \
__asm__ ("l.cmov %0,%1,%2" : "=r" (x) : "r" (y), "r" (0x0000000F)); \
}
/// some definition and assignment
unsigned char sbox[size][size];
unsigned char sbox[size][size];
///Using
mov(state[0][1], sbox[si][sj]);
Cコードに埋め込まれたインラインアセンブリ命令を使用すると、プログラムの実行時間を改善できます。これは、AESのような暗号アルゴリズムのような時間的に重大な状況に非常に役立ちます。たとえば、AESアルゴリズムで必要とされる簡単なシフト演算の場合、CのRotate Right
シフト演算子の代わりにCのRotate Right
シフト命令を使用することができ>>
。
'AES256'の実装では、 'AddRoundKey()'関数に以下のような文があります:
unsigned int w; // 32-bit
unsigned char subkey[4]; // 8-bit, 4*8 = 32
subkey[0] = w >> 24; // hold 8 bit, MSB, leftmost group of 8-bits
subkey[1] = w >> 16; // hold 8 bit, second group of 8-bit from left
subkey[2] = w >> 8; // hold 8 bit, second group of 8-bit from right
subkey[3] = w; // hold 8 bit, LSB, rightmost group of 8-bits
/// subkey <- w
単にw
のビット値をsubkey
配列に代入します。
私たちは、1つのアセンブリを持つ3つのシフト+割り当て、1つのアサインC式に変更することができますRotate Right
操作を。
__asm__ ("l.ror %0,%1,%2" : "=r" (* (unsigned int *) subkey) : "r" (w), "r" (0x10));
最終結果はまったく同じです。