如何让gcc编译中断函数

在x86中,一般函数通过"call"指令调用,"ret"指令返回,但是中断函数不同,它在中断或者异常发生时自动切入(或者使用"int"指令),此时cpu会向栈中压入一堆寄存器来保护现场,如果是异常,还会多压一个错误代码,因此编写中断函数返回时要使用"iret"指令,但是gcc默认是无法编译出iret指令的。当然,有一些IDE自定义了一些东西可以用来编译中断函数,也有一些人会直接用内联汇编解决,但用内联不是一个好办法。通过查询gcc手册,我发现gcc-7.5增加了对x86架构中断函数的支持,可以用来写中断程序。但是要注意,编译时要添加("-mgeneral-regs-only "),gcc才可以编译中断函数。

gcc手册网址:https://gcc.gnu.org/onlinedocs

位置:https://gcc.gnu.org/onlinedocs/gcc-7.5.0/gcc/x86-Function-Attributes.html#x86-Function-Attributes

/*uword_t 类型是用来读取异常压入的错误代码的,gcc手册很贴心的给出了32位和64位系统对于该类型的定义*/
#ifdef __x86_64__
typedef unsigned long long int uword_t;
#else
typedef unsigned int uword_t;
#endif

/*这个结构用来读取中断发生时cpu压栈的数据,但是因为平台不同,cpu的操作也可能不同,所以需要自己根据自己的平台定义*/
struct interrupt_frame;

__attribute__ ((interrupt))		/*这就是gcc增加的用来描述中断函数的符号,只有gcc-7.5及7.5以上支持*/
void div_error(struct interrupt_frame* frame,uword_t error_code)
/*这是个除法错误异常(除以0造成的),因为异常和中断不同,异常会多压入一个错误代码,因此上面的参数多了一个uword_t error_code*/
{
	/*code*/
    return;
}

__attribute__ ((interrupt))
void timer_int(struct interrupt_frame* frame)
/*这是时钟中断,间隔一定时间会向cpu发送一次中断,windows下是100Hz。中断不会压入错误代码,因此也就没有uword_t error_code*/
{
	/*code*/
    return;
}

使用以下代码编译测试:

typedef unsigned int uint32;

struct interrupt_frame{
uint32 eip;
uint32 cs;
uint32 eflags;
};

__attribute__ ((interrupt))
void timer_int(struct interrupt_frame* frame)
{
	return;
}

gcc命令:gcc main1.c -mgeneral-regs-only -S

生成的汇编文件如下:

	.file	"main1.c"
	.text
	.globl	_timer_int
	.def	_timer_int;	.scl	2;	.type	32;	.endef
_timer_int:
LFB0:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	pushl	%eax
	subl	$4, %esp
	.cfi_offset 0, -12
	leal	4(%ebp), %eax
	movl	%eax, -8(%ebp)
	nop
	addl	$4, %esp
	popl	%eax
	.cfi_restore 0
	popl	%ebp
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	iret
	.cfi_endproc
LFE0:
	.ident	"GCC: (i686-win32-dwarf-rev0, Built by MinGW-W64 project) 8.1.0"

可以看到,返回确实被编译为了"iret"。

下面是手册中对此的说明(x86架构)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章