下面代码可以完成这一工作:
void foo()
{
int a,b,*p=0;
_except_register_handler(_except_handler);
{
*p=a+b;
}
goto _except_finish;
_except_handler:
{
printk(KERN_ERR”exception occur!\n”);
}
_except_finish:
_except_unregister_handler(_except_handler);
}
可是,事情并没有如此简单:
(1)标号的地址不能被直接引用来作为参数传给函数。
(2)注册时需要取得当前堆栈指针。
(3)因为编译器的优化,有些堆栈操作可能是被放在函数中间进行,如果贸然注册,很可能还会引起堆栈问题。
(4)在同一个函数里可能会多次注册异常处理,标号的命名是个相当艰巨的任务。
在分析了编译器生成的代码之后,如下的宏来完成这个任务:
#define BEGIN_EXCEPT_PROTECT() \
{ \
unsigned long u; \
asm volatile("jmp 1f\n"); \
asm volatile("2:\tpop %eax\n"); \
asm volatile("movl %%eax,%0\n":"=m"(u)); \
asm volatile("push %esp\n"); \
asm volatile("push %eax\n"); \
asm volatile("call __except_register_handler\n":"memory"); \
asm volatile("lea 8(%esp),%esp”); \
} \
{
#define EXCEPT_HANDLER() \
} \
{ \
asm volatile("jmp 3f\n"); \
asm volatile("1:\t call 2b\n":"memory"); \
} \
{
|