INT 0x10输出奇怪的打印字符串

时间:2012-03-09 00:58:23

标签: assembly dos nasm interrupt bios

嗨我已经重定向分频溢出中断指向我自定义创建的中断,在屏幕上打印'你好我在这里',而不是打印奇怪的ascii字符。有人可以告诉我为什么吗?这是代码

[ORG 100h]
jmp start
message:    dw      'hello man here i am'


prntstr:    push ax
            push bx
            push cx
            push dx
            push si
            push di
            push bp
            push ds
            push es
            push cs
            pop ds

            mov ah, 0x13
            mov al, 1
            mov bh, 0
            mov bl, 7
            mov dx,0x0a03
            mov cx,11
            push cs
            push es
            mov bp,message
            int 0x10
            pop es
            pop ds
            pop bp
            pop di
            pop si
            pop dx
            pop cx
            pop bx
            pop ax
            ret
tsr:        mov ah, 0
            int 0x16
            call prntstr
            iret
            ;mov ah,4ch
            ;mov al, 6
            ;int 0x21
            ;iret


divs:       mov ax,0x8569
            mov dl,2
            div dl
            ret


start:      xor ax,ax
            mov es,ax
            mov word[es:0*4], tsr
            mov [es:0*4+2],cs
            call divs

            mov ax,0x4c00
            int 0x21

我不明白的代码是我在es:0 * 4设置偏移量的地方 - 我认为00是除法溢出中断的位置?什么是0 * 4 for coz任何乘以零意味着相同,那为什么4?提前谢谢

2 个答案:

答案 0 :(得分:1)

至于你奇怪的角色问题,我想:

push cs
push es

应该是:

push cs
pop  es

否则:

  1. 你的推动和弹出是不平衡的。
  2. 您的es段注册表未设置为es:bp以正确指向该消息。它将打印段message中偏移es处的任何内容,当您的中断触发时,而不是在您的实际消息所在的代码段中。
  3. 它最终也会崩溃。
  4. 对于0*4问题,我不确定。我做了x86已经有一段时间,但我知道你可以扩展间接寻址模式,例如:

    mov eax, dwarray[edx*4]
    

    确保访问正确的内存位置。在添加到edx基地址之前,这会将dwarray缩放到正确的值。

    我认为不需要立即补偿,所以我怀疑只需用相关代替0就可以更改任何中断的样板代码中断号码。

    另外,您可能想要更改中断向量而不确保在此过程中禁用中断。如果中断在之后触发你已经写了tsr的偏移量,但是之前的你已经写了段,那么结果将不会很好。

答案 1 :(得分:0)

您的代码中存在多个问题。见评论:

[ORG 100h]
jmp start
message:    db      'hello man here i am' ; chars are 8-bit, hence db, not dw
msglen      equ $ - message ; calculate message length

prntstr:    push ax
            push bx
            push cx
            push dx
            push si
            push di
            push bp
            push ds
            push es

            ;push cs ; not really needed here
            ;pop ds

            mov ah, 0x13
            mov al, 1
            mov bh, 0
            mov bl, 7
            mov dx,0x0a03
            mov cx,msglen ; use proper message length

            push cs
            pop es ; not "push es" - copy'n'paste bug !!!

            mov bp,message
            int 0x10

            pop es
            pop ds
            pop bp
            pop di
            pop si
            pop dx
            pop cx
            pop bx
            pop ax
            ret

tsr:
            call prntstr

            ; skip DIV (by advancing IP) to avoid infinite loop on DIV
            push bp
            mov bp, sp
            add word [bp+1*2], divend-divstart; IP (location of divstart) on the stack
            pop bp

            push ax ; save AX because int 0x16 will change it
            mov ah, 0
            int 0x16
            pop ax ; restore AX

            iret

divs:       mov ax,0x8569
            mov dl,2
divstart:
            div dl
divend:
            ret

start:
            mov  ax, 3
            int 0x10 ; clear screen by setting mode 3

            xor ax,ax
            mov es,ax

            cli                 ; update ISR address w/ ints disabled
            push word[es:0*4+2] ; preserve ISR address
            push word[es:0*4]
            mov word[es:0*4], tsr
            mov [es:0*4+2],cs
            sti

            call divs

            cli                 ; update ISR address w/ ints disabled
            pop  word[es:0*4]   ; restore ISR address
            pop  word[es:0*4+2]
            sti

            mov ax,0x4c00
            int 0x21

4是一个远指针大小(偏移量为2个字节,段选择器为2个字节)。因此,对于int 0,中断向量表中的地址将为0*4,对于int 1,它将为1*4,对于int n,它将为n*4 }}。在这种特殊情况下,乘法是不必要的,但它不会影响代码生成,因为汇编程序将为0计算并替换0*42替换0*4+2。< / p>