如果你可以使用 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
情况,这是断点操作)。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) - 因为 boost 预处理器库不依赖于 C++ 编译器......并且 gcc 4.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 ... ]
请注意,如果您执行上述操作...编译器(gcc 高达并包括 4.8)不够智能,无法优化switch()
离开,即即使您说它static __inline__ ...
会创建完整的跳转表版本,GetInInterrupt(3)
而不是内联int3
的 as会更简单的实现。