【问题标题】:Weird print string output from INT 0x10来自 INT 0x10 的奇怪打印字符串输出
【发布时间】:2012-03-26 12:24:28
【问题描述】:

您好,我已将除法溢出中断重定向到我自定义创建的中断,该中断在屏幕上打印“你好,我在这里”,而不是打印奇怪的 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 因为任何东西乘以零都意味着相同,那么为什么是 4 ?提前谢谢

【问题讨论】:

    标签: assembly dos nasm interrupt bios


    【解决方案1】:

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

    push cs
    push es
    

    应该是:

    push cs
    pop  es
    

    否则:

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

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

    mov eax, dwarray[edx*4]
    

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

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

    而且,顺便说一句,您可能想要更改中断向量而不确保在此过程中禁用中断。如果在您写入tsr 的偏移量之后触发中断,但在您写入段之前,结果将不会很漂亮。

    【讨论】:

    • 您不能使用 dx 进行间接寻址(bxbpsidi 是唯一的 16 位选项)并且您不能扩展寄存器除非它们是 32 位的(edx*2 可以)。
    【解决方案2】:

    您的代码中有多个问题。查看 cmets:

    [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

    【讨论】:

      猜你喜欢
      • 2017-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-23
      相关资源
      最近更新 更多