装配16位中断

时间:2017-05-11 12:49:17

标签: assembly x86

; another attempt to terminate program with Esc that hooks
; keyboard interrupt
    [org 0x100]
    jmp start
    oldisr: dd 0 ; space for saving old isr
; keyboard interrupt service routine
kbisr: push ax
    push es
    mov ax, 0xb800
    mov es, ax ; point es to video memory
    in al, 0x60 ; read a char from keyboard port
    cmp al, 0x2a ; is the key left shift
    jne nextcmp ; no, try next comparison
    mov byte [es:0], 'L' ; yes, print L at top left
    jmp nomatch ; leave interrupt routine
    nextcmp: cmp al, 0x36 ; is the key right shift
    jne nomatch ; no, leave interrupt routine
    mov byte [es:0], 'R' ; yes, print R at top left
    nomatch: ; mov al, 0x20
; out 0x20, al
    pop es
    pop ax
    jmp far [cs:oldisr] ; call the original ISR
; iret
start: xor ax, ax
    mov es, ax ; point es to IVT base
    mov ax, [es:9*4]
    mov [oldisr], ax ; save offset of old routine
    mov ax, [es:9*4+2]
    mov [oldisr+2], ax ; save segment of old routine
    cli ; disable interrupts
    mov word [es:9*4], kbisr ; store offset at n*4
    mov [es:9*4+2], cs ; store segment at n*4+2
    sti ; enable interrupts
l1: mov ah, 0 ; service 0 – get keystroke
    int 0x16 ; call BIOS keyboard service
    cmp al, 27 ; is the Esc key pressed
    jne l1 ; if no, check for next key
    mov ax, 0x4c00 ; terminate program
    int 0x21

我很想知道为什么我们只能使用cs:offset来调用此程序中的oldIsr。为什么只是 CS ???

在这条线上

jmp far [cs:oldisr] ; call the original ISR

背后的目的是什么? 请解释一下!!!

1 个答案:

答案 0 :(得分:3)

在16b实模式中断处理程序代码中,你不知道段寄存器的值,它们可以是任何东西。通常你可以期望至少stack(ss:sp)合理有效并且足够大以存储返回地址和少量字节用于处理程序,并且cs也固定为处理程序代码,因为如果不同cs值将CPU执行一些不同的指令,而不是你的。

因此,为了避免存储旧的/未知ds,设置处理程序变量的数据段以及通过ds:前缀访问它们,然后恢复ds的麻烦,更容易将变量放在代码本身旁边,并按cs:oldisr解决,因为已知cs的值是您需要的。

我会尝试以更简单的方式编写它:

mov ax,[si]默认情况下使用ds(* 1),即它实际上正在执行mov ax,[ds:si]

您可以通过明确编写段寄存器来覆盖默认值,如mov ax,[cs:si]

16b实模式下的物理内存地址为:segment_value * 16 + offset_value

当代码进入您的ISR处理程序时,您不知道在中断时{0}}或ds中正在运行的代码有什么。它可能指向内存中的任何位置(而不是你的变量!)。

但是你知道,es指向你的处理程序指令(否则CPU会在别处执行指令,因为CPU会在cs处执行来自内存的下一条指令。)

只需了解您的处理程序如何保留/设置/恢复cs:ip,这就是您必须使用es进行的示例,才能使用ds

ds已经保留在堆栈上,设置为您的代码段,cs(在旧处理程序中)将恢复它。

1)IRET默认使用bpss默认使用stos/movs/cmpsds,只有源es 1}}可以被覆盖,目标的ds是固定的。