C ++を使用できる場合は、次のようにします。
template <int N> static inline void GetInInterrupt (void)
{
__asm__ ("int %0\n" : "N"(N));
}
しましょう。そのテンプレートを次のように使用する場合:
GetInInterrupt<123>();
GetInInterrupt<3>();
GetInInterrupt<23>();
GetInInterrupt<0>();
これにより、次のオブジェクトコードが作成されます。
0: cd 7b int $0x7b
2: cc int3
3: cd 17 int $0x17
5: cd 00 int $0x0
これはかなり最適です(int3
ブレークポイントopである場合でも)。また、オペランドが0..255
範囲外の場合、N
それのみを許可する制約があるため、コンパイル時の警告が作成されます。
編集:もちろん、昔ながらのCスタイルのマクロも同様に機能します。
#define GetInInterrupt(arg) __asm__("int %0\n" : : "N"((arg)) : "cc", "memory")
C++テンプレート関数と同じコードを作成します。動作の仕方により、インラインアセンブリを埋め込むときに命令を並べ替えようとしないように、int
(制約を介して)コンパイラにバリアセマンティクスについて通知することをお勧めします。"cc", "memory"
両方の制限は、明らかに、割り込み番号がコンパイル時定数でなければならないという事実です。どうしてもそれを望まない場合は、switch()
たとえば、255のケースすべてをカバーすることで作成されたステートメントを作成するBOOST_PP_REPEAT()
ことは、自己変更コードよりも優れたオプションです。
#include <boost/preprocessor/repetition/repeat.html>
#define GET_INTO_INT(a, INT, d) case INT: GetInInterrupt<INT>(); break;
void GetInInterrupt(int interruptNumber)
{
switch(interruptNumber) {
BOOST_PP_REPEAT(256, GET_INTO_INT, 0)
default:
runtime_error("interrupt Number %d out of range", interruptNumber);
}
}
これはプレーンCで実行できます(もちろん、プレーンのテンプレート関数呼び出しを変更した場合__asm__
)-ブーストプリプロセッサライブラリはC++コンパイラに依存しないため...そしてgcc4.7.2はこのために次のコードを作成します:
GetInInterrupt:
.LFB0:
cmpl $255, %edi
jbe .L262
movl %edi, %esi
xorl %eax, %eax
movl $.LC0, %edi
jmp runtime_error
.p2align 4,,10
.p2align 3
.L262:
movl %edi, %edi
jmp *.L259(,%rdi,8)
.section .rodata
.align 8
.align 4
.L259:
.quad .L3
.quad .L4
[ ... ]
.quad .L258
.text
.L257:
#APP
# 17 "tccc.c" 1
int $254
# 0 "" 2
#NO_APP
ret
[ ... accordingly for the other vectors ... ]
ただし、上記を実行する場合は注意してください...コンパイラ(4.8までのgcc)は、アウェイを最適化するのに十分なインテリジェントではありません。つまり、インラインとしてではなく、の完全なジャンプテーブルバージョンを作成するswitch()
と言ってもより単純な実装になります。static __inline__ ...
GetInInterrupt(3)
int3