6.13利用宏重用异常处理代码

目的:系统异常那么多,难道每个异常都定义一个函数吗?这就要涉及函数的重用

c语言里面可以利用宏来定义函数

汇编同样可以用宏来定义函数

.macro
.macro exception_handler name num with_error_code  //传入三个参数函数的name,编号num,错误码with_error_code
    .text
.macro exception_handler name num with_error_code  // 异常的名字和代码
	.extern do_handler_\name
	.global exception_handler_\name
exception_handler_\name:
	// 保存所有寄存器
	// 如果没有错误码,压入一个缺省值
	// 这样堆栈就和有错误码的情形一样了
	.if \with_error_code == 0
		push $0     // $表示立即数
	.endif

	// 压入异常号
	push $\num
	pusha  // 保存通用寄存器
	// 保存段寄存器
	push %ds
	push %es
	push %fs
	push %gs

	push %esp
	call do_handler_\name
	add $(1*4), %esp		// 丢掉esp,没有用pop指令,这块代码1需要重用
		// 恢复保存的寄存器
	pop %gs
	pop %fs
	pop %es
	pop %ds
	popa
	// 跳过压入的异常号和错误码,有无错误码被硬件自动压入,全部都拿出去
	add $(2*4), %esp
	iret  //中断返回指令,所以不能用c语言去写
	
.endm

因为有些异常会有Error Code,系统会自动压入,但是有些异常没有Error Code,为了统一处理(后面add $(2*4), %esp,不然这里就要分情况了),没有Error Code的异常我们假设其Error Code为0;

\name就是缺省的参数

这个地方有一个疑难点:

对于那些带Error Code的异常,最后我们pop的时候(add $(2*4), %esp),为什么要pop两个单元,系统自动压入的,还要我们手动弹出吗?要手动弹出,intel编程手册就是这么写的

利用汇编宏函数

//start.S
exception_handler unknown, -1, 0 //传入的三个残数
exception_handler divider, 0, 0 

最后反汇编生成的东西

exception_handler_unknown

在irq.h里面定义好那个函数

void exception_handler_unknown (void);
void exception_handler_divider (void);

有个很奇葩的事,就是在宏汇编代码里面,无法调试

所以

到了除0这句代码,直接跳转到了

对比这句代码eip的值

除0代码的逻辑地址,对应上了

这是直接给出结论了,中间有安装idt表的过程(为什么0能对应上除0异常都是我们手动安排好的)

void irq_init(void) {	
	for (uint32_t i = 0; i < IDT_TABLE_NR; i++) {
    	gate_desc_set(idt_table + i, KERNEL_SELECTOR_CS, (uint32_t) exception_handler_unknown,
                  GATE_P_PRESENT | GATE_DPL0 | GATE_TYPE_IDT);
	}
	// 设置异常处理接口
	irq_install(IRQ0_DE, (irq_handler_t)exception_handler_divider);
	lidt((uint32_t)idt_table, sizeof(idt_table));
}

int irq_install(int irq_num, irq_handler_t handler) {
	if (irq_num >= IDT_TABLE_NR) {
		return -1;
	}

    gate_desc_set(idt_table + irq_num, KERNEL_SELECTOR_CS, (uint32_t) handler,
                  GATE_P_PRESENT | GATE_DPL0 | GATE_TYPE_IDT);
	return 0;
}

解释irq_handler_t类型

//irq.h
typedef void(*irq_handler_t)(void); 

是用来定义函数指针类型的

参数为void,返回值为void

pos:学操作系统底层要强压下来,不能学一天玩一天

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值