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



嗨,我已经重定向了除法溢出中断以指向我自定义创建的中断,该中断在屏幕上打印"你好,伙计,我在这里",而是打印奇怪的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 是除法溢出中断的位置? Coz 的 0*4 是什么 乘以零意味着相同,那么为什么是 4 ? 提前致谢

至于你奇怪的性格问题,我想:

push cs
push es

应该是:

push cs
pop  es

否则:

  1. 你的推力和爆裂声不平衡。
  2. 您的es段寄存器未设置为es:bp正确指向消息。它将打印es触发中断时指向的段中偏移message的任何内容,而不是实际消息所在的代码段。
  3. 它最终也会崩溃。

对于0*4问题,我不确定。自从我做 x86 以来已经有一段时间了,但我知道您可以通过以下方式扩展间接寻址模式:

mov eax, dwarray[edx*4]

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

不过,我认为立即偏移不需要这样做,所以我怀疑这只是样板代码,只需将0替换为相关的中断编号即可更改任何中断。

而且,顺便说一句

,您可能不希望在不确保在此过程中禁用中断的情况下更改中断向量。如果在写入偏移量 tsr 之后但在写入段之前触发中断,则结果将不漂亮。

代码中有多个问题。查看评论:

[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

最新更新