3

我正在处理中断,并且在运行代码时遇到了这个问题:

DATA SEGMENT
    INPUTV DW 0035H, 0855H, 2011H, 1359H
    OUTPUTV DB 4 DUP(0)
    DIVIDER DB 09
    ERROR_FLAG DB 0
DATA ENDS

_STACK SEGMENT STACK
    DW 100 DUP(0)
    TOP_STACK LABEL WORD
_STACK ENDS

CODE SEGMENT
    ASSUME CS:CODE, DS:DATA, SS:_STACK
MAIN:
    MOV AX, _STACK
    MOV SS, AX
    MOV SP, OFFSET TOP_STACK
    MOV AX, DATA
    MOV DS, AX

    MOV AX, 0000H
    MOV ES, AX
    MOV WORD PTR ES:0002, SEG INT_PROC  ;PUSHING CS TO STACK
    MOV WORD PTR ES:0000, OFFSET INT_PROC   ;PUSHING IP TO STACK

    MOV SI, OFFSET INPUTV
    MOV BX, OFFSET OUTPUTV

    MOV CX, 4H
REPEAT:
    MOV AX, [SI]
    DIV DIVIDER
    CMP ERROR_FLAG, 1H
    JE ERROR_ENCOUNTER
    MOV [BX], AL
    JMP SKIP
ERROR_ENCOUNTER:
    MOV BYTE PTR [BX], 0H
    MOV ERROR_FLAG, 0H
SKIP:
    ADD SI,2
    INC BX
    LOOP REPEAT
    INT 3H
CODE ENDS

INT_SEG SEGMENT 
    ASSUME CS:INT_SEG
INT_PROC PROC
        MOV ERROR_FLAG, 1
        IRET
    INT_PROC ENDP
INT_SEG ENDS

END MAIN

程序从 IRET 指令从 ISR(这里是 INT_PROC)返回后

    INT_PROC PROC
            MOV ERROR_FLAG, 1
            IRET

它正在执行该行:

    DIV DIVIDER

一次又一次,而它应该去:

    CMP ERROR_FLAG, 1H

在此处调试图像

我在论坛上发现了这个,它也说同样的:

返回中断处理程序后程序计数器去了哪里?

为什么会发生这种情况,我该如何解决?请帮忙。

4

3 回答 3

2

x86 架构定义了三类软件生成的中断:

  • 陷阱,显式和有意调用的中断。这些通常是INT指令的结果,本身并不表示问题。推送的IP是后面指令的IP,所以在处理程序返回后,不会重试该指令。或者,如果无法解决故障,它可能会终止进程。
  • 错误,例如页面错误和被零除。这些指示未完成的指令。推送的IP是产生故障的指令的IP;中断处理程序有机会尝试清除事物(最常见的是通过在内存页面中分页导致页面错误),然后重试指令。
  • Aborts,一种异常类型的故障,本质上是不可恢复的(除非终止进程)。中断处理程序不应返回。

在除以零的情况下,继续执行除法并不是一个好的响应,因为这样就跳过了一条指令。真的,这些更像是中止而不是故障。不应使用中断处理程序来破解“替代行为”。

于 2016-01-10T11:47:40.357 回答
1

当您执行IRET时,CPU 将再次执行导致异常的指令。例如,这对于处理页面错误很有用。

您应该IP在异常处理程序中修改存储在异常堆栈上的值,以便 CPU 执行所需的指令。

于 2016-01-10T11:32:47.770 回答
0

由于除法异常是故障,所以保存的 CS:IP 将指向该DIV指令。简单地从中断返回将重新执行错误指令。解决方案是更改堆栈中 IP 的值。它的美妙之处在于您根本不再需要ERROR_FLAG变量。

INT_PROC PROC
    pop  ax
    push ERROR_ENCOUNTER
    xor  ax, ax  ;Eliminates the need for the SKIP label and some instructions.
    iret
INT_PROC ENDP

请注意,在设置 InterruptVector0 时禁用中断是明智的。

MOV AX, 0000H
MOV ES, AX
cli
MOV WORD PTR ES:0002, SEG INT_PROC
MOV WORD PTR ES:0000, OFFSET INT_PROC
sti

你的循环可能很紧:

    MOV CX, 4H
REPEAT:
    MOV AX, [SI]
    DIV DIVIDER
ERROR_ENCOUNTER:
    MOV [BX], AL
    ADD SI, 2
    INC BX
    LOOP REPEAT
于 2016-02-21T15:38:03.980 回答