您的位置:首页 > 其它

30天自制操作系统day22

2015-07-27 13:54 253 查看

栈异常的处理

当在应用程序中访问一个数组时,如果index超过数组的大小,可能会引起栈异常,因为只有访问到位置超过应用程序数据段的范围时才会导致异常。栈异常会触发0x0c中断。

处理异常时,最好能够显示发生异常的指令地址。因为中断时,CPU自动PUSH应用程序的EIP,CS,ESP,SS等,可以从栈上获得EIP。

中断后又执行了

PUSH    ES
PUSH    DS
PUSHAD


所以栈上保存的数据是

esp[0]:     EDI
esp[1]:     ESI
esp[2]:     EBP
esp[3]:     ESP
esp[4]:     EBX
esp[5]:     EDX
esp[6]:     ECX
esp[7]:     EAX
esp[8]:     DS
esp[9]:     ES
esp[10]:    错误编号
esp[11]:    EIP
esp[12]:    CS
esp[13]:    EFLAGS
esp[14]:    ESP
esp[15]:    SS


其中,0-7是PUSHAD,10-15是中断时CPU自动PUSH的,CS:EIP指向中断时应用程序运行的位置,SS,ESP是应用程序的数据段号和栈地址。所以昨天没弄明白的地方可以解释了。CPU自动做了CS,EIP,SS,ESP的切换。返回时需要
ADD ESP,4
是为了跳过
esp[10]:错误编号
,这时栈上有EIP和CS,就可以IRETD返回了。

在中断处理函数中获取esp[11],打印,就能知道发生异常的地址了。

强制结束任务

就像Linux里
CTRL+C
那样,需要一个按键用了强制结束任务,避免死循环。由于console_task正在执行应用程序,无法接受输入,所以在bootpack.c的处理键盘输入时进行。结束任务的代码:

io_cli();
task_cons->tss.eax = (int) &(task_cons->tss.esp0);
task_cons->tss.eip = (int) asm_end_app;
io_sti();


实际上是跳转到了asm_end_app:

_asm_end_app:
MOV     ESP,[EAX]
MOV     DWORD [EAX+4],0
POPAD
RET


在start_app()时,我们把操作系统的ESP放到了tss->esp0的位置。结束任务时,把&tss->esp0赋给EAX,然后在_asm_end_app中恢复到ESP中。

用C语言显示字符串

之前写的汇编程序,显示字符串没问题。但如果是用C语言写的就出错。原因是编译出来的.hrb文件中,包含代码部分和数据部分。这些部分的位置,大小会写在文件头中。如果没有把数据部分复制到相应的地址去,就会访问不到。

.hrb文件头部主要包括:

0x0000  需要操作系统为程序准备的数据段大小(包括了栈的大小)
0x000c  ESP的初始值、数据段的起始位置
0x0010  数据段中数据部分的大小(不包括栈大小)
0x0014  .hrb文件内,数据部分的位置(需要从这里开始复制)


所以在cmp_app()中需要做如下修改:

segsiz = *((int *) (p + 0x0000));
esp    = *((int *) (p + 0x000c));
datsiz = *((int *) (p + 0x0010));
dathrb = *((int *) (p + 0x0014));
q = (char *) memman_alloc_4k(memman, segsiz);
*((int *) 0xfe8) = (int) q;
set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60);
set_segmdesc(gdt + 1004, segsiz - 1, (int) q, AR_DATA32_RW + 0x60);
for (i = 0; i < datsiz; i++) {
q[esp + i] = p[dathrb + i];
}


分配数据段q,大小为segsiz,从esp开始,将代码段p中datahrb开始的datsiz个字节复制过来。也就是数据部分刚好在栈的上面。

显示窗口的API

显示窗口的API大体和显示字符的API一样,都是将参数放入寄存器然后中断。但是显示窗口需要窗口的SHEET结构作为返回值。返回值放在EAX中。

在中断调用asm_hrb_api()时,用了两次PUSHAD,分别是保存旧值和传参数。可以直接将SHEET结构的地址直接写到栈上,具体是写到第一次PUSHAD中的EAX中。最后POPAD就可以放到EAX里了。

得到了SHEET结构,又可以添加在窗口显示字符等API了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: