exception - 操作系统开发 : How to avoid an infinite loop after an exception routine

标签 exception assembly operating-system x86 interruption

几个月来,我一直在研究“自制”操作系统。 目前,它启动并进入 32 位保护模式。 我已经加载了中断表,但还没有设置分页。

现在,在编写我的异常例程时,我注意到当一条指令抛出异常时,会执行异常例程,但随后 CPU 会跳回到抛出异常的指令!这并不适用于所有异常(例如,除零异常将跳回到除法指令之后的指令),但让我们考虑以下一般保护异常:

MOV EAX, 0x8
MOV CS, EAX

我的例程很简单:它调用一个显示红色错误消息的函数。

结果:MOV CS,EAX 失败 -> 显示我的错误信息 -> CPU 跳回 MOV CS -> 无限循环发送错误信息。

我和一位操作系统和 Unix 安全方面的老师谈过这个问题。 他告诉我他知道 Linux 有办法解决这个问题,但他不知道是哪一个。

天真的解决方案是从例程中解析抛出指令,以获得该指令的长度。 该解决方案非常复杂,我觉得在每个受影响的异常例程中添加对相对繁重的函数的调用有点不舒服...

因此,我想知道这是否是解决该问题的另一种方法。也许有一个“魔法”寄存器包含可以改变这种行为的位?

--

非常感谢您提供任何建议/信息。

--

编辑:似乎很多人想知道为什么我要跳过有问题的指令并恢复正常执行。

我有两个原因:

  1. 首先,终止进程是一种可能的解决方案,但不是一个彻底的解决方案。这不是它在 Linux 中的完成方式,例如,(AFAIK)内核发送信号(我认为是 SIGSEGV)但不会立即中断执行。这是有道理的,因为应用程序可以阻止或忽略信号并恢复自己的执行。这是一种非常优雅的方式来告诉应用程序它做错了 IMO。

  2. 另一个原因:如果内核本身执行了非法操作怎么办?可能是由于错误,但也可能是由于内核扩展。正如我在评论中所说:在那种情况下我应该怎么做?我是否应该终止内核并显示一个带有笑脸的漂亮蓝屏?

这就是为什么我希望能够跳过指令。 “猜测”指令大小显然不是一个选项,解析指令似乎相当复杂(并不是说我介意实现这样的例程,但我需要确保没有更好的方法)。

最佳答案

不同的异常有不同的原因。有些异常是正常的,异常只是告诉内核它需要做什么才允许软件继续运行。这方面的例子包括页面错误告诉内核它需要从交换空间加载数据,未定义的指令异常告诉内核它需要模拟 CPU 不支持的指令,或者调试/断点异常告诉内核它需要通知调试器。对于这些,内核修复问题并静默继续是正常的。

一些异常表示异常情况(例如,软件崩溃)。处理这些类型的异常的唯一明智的方法是停止运行该软件。您可以保存信息(例如核心转储)或显示信息(例如“蓝屏死机”)以帮助调试,但最终软件会停止(要么进程终止,要么内核进入“什么都不做直到用户重置计算机“状态”)。

忽略异常情况只会让人们更难找出问题所在。例如,想象一下上厕所的指令:

  • 进入浴室
  • 脱裤子
  • 开始生成输出

现在假设第 2 步失败是因为您穿着短裤(“找不到裤子”异常)。您是想在那一点上停下来(使用易于理解的错误消息或其他内容),还是忽略该步骤并在所有有用的诊断信息都消失后尝试找出问题所在?

关于exception - 操作系统开发 : How to avoid an infinite loop after an exception routine,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9151429/

相关文章:

c - 当堆栈增长时,谁负责向操作系统请求页面?

c - 操作系统 : wait() in child process

objective-c - 为什么这个 NSInvocation 会引发异常?

c++ - 一个 SSE Stdlib 式的库?

assembly - 8086 汇编语言中的换行符 : my text prints stair-stepped

assembly - 为什么EDX中的地址在lstrlen之后增加了1个字节?

linux - 什么时候使用虚拟内存是个坏主意?

java - 抛出已检查异常与抛出包装的 RuntimeException

java - 在 Stream API 中使用 checked 装饰器函数是好的解决方案吗?

c# - 为什么没有捕获异常?