Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 在从中断处理程序返回之前,是否必须弹出某些异常推送到堆栈中的错误代码?_Assembly_Operating System_X86_Interrupt_Osdev - Fatal编程技术网

Assembly 在从中断处理程序返回之前,是否必须弹出某些异常推送到堆栈中的错误代码?

Assembly 在从中断处理程序返回之前,是否必须弹出某些异常推送到堆栈中的错误代码?,assembly,operating-system,x86,interrupt,osdev,Assembly,Operating System,X86,Interrupt,Osdev,我加载了一个包含256个条目的idt表,所有条目都指向类似的处理程序: 对于异常8和10-14,推送异常编号(这些异常自动推送错误代码) 对于其他的,推送一个“虚拟”错误代码和异常号 然后跳转到一个公共处理程序 因此,当公共处理程序进入时,堆栈将正确对齐,并包含异常/中断号、错误代码(可能只是一个伪代码)、eflags、cs和eip 我的问题是从中断处理程序返回。我使用iret在从堆栈中取出异常编号和错误代码后返回,但这对异常nr8不起作用;如果我把错误代码留在堆栈上,那么它返回的很好 问题

我加载了一个包含256个条目的idt表,所有条目都指向类似的处理程序:

  • 对于异常8和10-14,推送异常编号(这些异常自动推送错误代码)
  • 对于其他的,推送一个“虚拟”错误代码和异常号
  • 然后跳转到一个公共处理程序
因此,当公共处理程序进入时,堆栈将正确对齐,并包含异常/中断号、错误代码(可能只是一个伪代码)、eflags、cs和eip

我的问题是从中断处理程序返回。我使用
iret
在从堆栈中取出异常编号和错误代码后返回,但这对异常nr8不起作用;如果我把错误代码留在堆栈上,那么它返回的很好

问题:

  • 对于将错误代码放在堆栈中的异常,是否必须将错误代码留在堆栈中?如果是,如何确定是否必须弹出错误代码
  • 一旦我启用中断,我总是得到异常8(双故障),但随后一切都正常运行(我正在开发一个业余操作系统)。这是正常行为还是我在什么地方有bug

如果CPU自动推送错误代码,处理程序必须在
iret
之前弹出它。如果是故障、陷阱或外部中断,
iret
指令不知道您来自何处。它总是这样做,并且它假设堆栈上没有错误代码

引用SDM(软件开发人员手册)第3卷第5章第5.13节“错误代码:

错误代码被推送到堆栈上 作为双字或双字(取决于 默认的中断、陷阱或任务 浇口尺寸)。保持堆栈对齐 对于双字推送,上半部分 保留错误代码的名称。注 当发生错误时,不会弹出错误代码 执行IRET指令以 从异常处理程序返回,因此 处理程序必须删除错误代码 在执行返回之前

您可以找到:

第3卷第1部分第5章描述了异常和中断处理。第2卷第1部分有iret指令的规范。

我不久前写了一篇文章。查看cvs存储库中的文件

请注意我们是如何设置处理程序的,大多数处理程序将一个虚拟dword推送到堆栈上,以解释自动推送错误代码的少数处理程序。然后,当我们通过iret返回时,我们总是可以假定堆栈上有2个DWORD,而不考虑中断,并在iret之前执行add esp,8以很好地清理这些内容

这应该回答你的第一个问题


至于您的第二个问题:当您启用中断时出现双重错误,…如果您没有正确设置,hmmm可能是分页的问题。可能还有一百万其他问题:)

我一启用中断就遇到了类似的“双故障”问题。嗯,它们看起来像双重故障,但实际上是计时器中断

双故障是中断编号
8

不幸的是,默认PIC配置将计时器中断作为中断号
(默认PIC\u基本+计时器\u偏移量)
=
(8+0)
=
8

屏蔽我所有的PIC中断(直到我准备好正确配置PIC)使这些双重故障的计时器中断静音

(PIC要求CPU在产生下一个中断之前确认中断。因为您的代码没有确认初始计时器中断,PIC再也没有给过您!这就是为什么您只得到一个中断,而不是预期的无数个中断。)

对于将错误代码放在堆栈中的异常,是否必须将错误代码留在堆栈中

正如其他人提到的,您必须执行以下任一操作:

pop %eax
/* Do something with %eax */
iret
或者,如果要忽略错误代码:

add $4, %esp
iret
如果您不这样做,
iret
将把错误代码解释为新的CS,您很可能会遇到如下所述的一般保护故障:

这就是我为说明这一点而创建的。尝试对弹出的
进行注释
,然后看到它爆炸

将以上内容与不弹出堆栈的比较

请注意,如果只执行
int$14
,则不会推送额外的字节:这仅发生在实际异常上

表6-1。“保护模式异常和中断”列“错误代码”包含推送或不推送错误代码的中断列表

38.9.2.2“页面错误代码”解释了错误的含义

处理这一问题的一个好方法是在堆栈上推一个虚拟错误代码
0
,用于中断,但这并不能使事情变得一致。詹姆斯·莫洛伊的教程

Linux内核4.2似乎也做了类似的事情。在it模式下,中断具有
错误\u code

trace_idtentry page_fault do_page_fault has_error_code=1
然后在同一文件上使用它,如下所示:

.ifeq \has_error_code
pushq $-1 /* ORIG_RAX: no syscall to restart */
.endif

出现错误时,会推送哪一个?\u error\u code=0

此外,最欢迎指向英特尔手册的指针:)我还没有在那里找到关于这些问题的任何信息。不知怎的,我错过了那一段:)所以现在我知道这是我代码中的一个错误。非常感谢你指出这一点!嗨,史蒂夫,谢谢你的回复:)我没有启用分页功能,我在GDT中只有3个有效条目(用于环0中的代码和数据,另一个用于实模式)。我通常处于受保护模式,但我回到真实模式使用一些BIOS例程(主要是从磁盘读取)。有什么线索吗?:)抱歉,现在想不出任何事情,可能切换回真实模式会导致问题链接到您的操作系统已死亡,可能您有GitHub版本?我正在制作一套教育操作系统。