问题
I'm working with interrupts and I'm facing this problem while running my code:
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
After the program returns from the ISR (here INT_PROC) from IRET instruction
INT_PROC PROC
MOV ERROR_FLAG, 1
IRET
it is executing the line:
DIV DIVIDER
again and again while it was supposed to go to:
CMP ERROR_FLAG, 1H
Debugging Image Here
I found this in the forum which also says the same:
Where the program counter goes after returning the interrupt handler?
why is that happening and how can i solve it? please help.
回答1:
The x86 architecture defines three classes of software-generated interrupts:
- Traps, explicitly and intentionally invoked interrupts. These are usually the result of the
INT
instruction, and don't indicate a problem per se. The pushed IP is that of the following instruction, so following the return of the handler, the instruction is not retried. Or it could just kill the process, if there's no way to resolve the fault. - Faults, such as page faults and division by zero. These indicate an un-completable instruction. The pushed IP is that of the instruction generating the fault; the interrupt handler gets a chance to try to clear things up (most commonly, by paging in the memory page which led to the page fault), and then the instruction is retried.
- Aborts, an unusual type of fault which is essentially unrecoverable (except by terminating the process). The interrupt handler should not return.
In the case of division by zero, resuming following the division isn't a good response, because then an instruction has been skipped. Really, these are more like aborts than faults. The interrupt handler should not be used to hack in "alternative behavior".
回答2:
When you execute IRET
, the CPU will execute the instruction which is the cause of the exception again. This is useful for dealing with page fault, for example.
You should modify the value of IP
stored on the stack on the exception in the exception handler so that the CPU will execute the desired instruction.
回答3:
Since the division exception is a fault, the saved CS:IP will point at the DIV
instruction. Simply returning from the interrupt will re-execute the faulty instruction. The solution is to change the value for IP that's on the stack. The beauty of it is that you no longer need the ERROR_FLAG variable at all.
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
Please note that it would have been wise to disable interrupts while setting up 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
Your loop could be this tight:
MOV CX, 4H
REPEAT:
MOV AX, [SI]
DIV DIVIDER
ERROR_ENCOUNTER:
MOV [BX], AL
ADD SI, 2
INC BX
LOOP REPEAT
来源:https://stackoverflow.com/questions/34704121/program-keeps-returning-to-same-line-after-isr-assembly-8086