【问题标题】:Assembly bootloader keeps printing S with 'mov ah, 09h'程序集引导加载程序一直使用“mov ah, 09h”打印 S
【发布时间】:2021-07-19 09:17:26
【问题描述】:

每次我尝试为我的程序集引导加载程序添加颜色时,它总是打印“S”,我不知道为什么!

代码:

            BITS 16
    
    start:
        mov ax, 07C0h       ; Set up 4K stack space after this bootloader
        add ax, 288     ; (4096 + 512) / 16 bytes per paragraph
        mov ss, ax
        mov sp, 4096
    
        mov ax, 07C0h       ; Set data segment to where we're loaded
        mov ds, ax
    
    
        ;setting video mode
        mov ah, 00h
      mov al,00h
      int 10h
        ;setting cursor position
        mov ah, 02h  
        mov dh, 10    ;row 
        mov dl, 45     ;column
        int 10h
    
        mov si, text_string ; Put string position into SI
        call print_string   ; Call our string-printing routine
    
        jmp $           ; Jump here - infinite loop!
    
    
        text_string db 'KRIPKE OS', 0
    
    
    print_string:           ; Routine: output string in SI to screen
    mov ah, 09h
    mov bl, 2  ;colour
    mov cx, 1    ;no.of times

.repeat:
    lodsb           ; Get character from string
    cmp al, 0
    je .done    ; If char is zero, end of string
    int 10h         ; Otherwise, print it
    mov ah, 02h
    add dl, 1
    jmp .repeat

.done:
    ret

    
    
        times 510-($-$$) db 0   ; Pad remainder of boot sector with 0s
        dw 0xAA55       ; The standard PC boot signature

请帮我解决这个问题。 我认为 bl 寄存器可能有问题。 我需要在顶部添加 [org 0x7c00] 吗?

输出: K then lots of spaces

【问题讨论】:

  • 由于您将 DS 设置为 0x7c0,因此您需要 [org 0] 而不是 [org 0x7c00],因为这是代码开始时与 DS 的偏移量。也许这是默认设置,我不确定,但无论哪种方式,明确地编写它都不会造成伤害。
  • 我不是 100% 确定,但我怀疑 INT 0x10 / AH = 0x09 在写入后不会更新光标位置。因此,您将每个字符都写在前面的字符之上,而您看到的只是最后一个字符,即S,并且由于您将 CX 设置为 9,因此它重复了 9 次。
  • 是否有我可以用来了解我需要什么 ORIGIN 的组织列表?
  • @NateEldredge 那没用 :(
  • 我不知道您所说的“组织列表”是什么意思。弄清楚要使用什么 ORG 指令只是与加载 DS 的方式保持一致的问题。这是逻辑,不是参考。

标签: assembly operating-system x86-16 bootloader


【解决方案1】:

int 10h / ah=09h BIOS 调用不会更新光标位置,因此您需要在打印每个字符后重复您的int 10h / ah=02h,并增加位置。您当前的代码将mov ah, 02hadd dl, 1 放入循环中,但实际上并没有进行第二次int 10h 调用。在每个字符输出调用之前,您还必须将 ah 重置为 09h

更好的是,在输出字符之前更新循环中的光标位置。这也意味着您在调用print_string或进入循环之前不再设置光标位置。

我会写:

print_string:           ; Routine: output string in SI to screen
    mov dl, 45      ; initial cursor column column
    mov dh, 10      ; row
    mov bl, 2       ; colour
    mov cx, 1       ; no.of times

.repeat:
    mov ah, 02h     ; update cursor position
    int 10h
    inc dl          ; same as `add dl, 1` but smaller 

    lodsb           ; Get character from string
    cmp al, 0
    je .done        ; If char is zero, end of string
    mov ah, 09h     ; Otherwise, print it
    int 10h         


    jmp .repeat

.done:
    ret

为了进一步增强,让print_string 的调用者设置dh,dl 的值,以便它可以在任何需要的位置打印。或许还有bl,这样调用者也可以选择颜色。

【讨论】:

  • 对我来说,它打印的是 RIPKE OS 而不是 KRIPKE OS。 :(
  • 但是当我将 dl 从 45 移动到 46 时它可以工作。什么??
  • 字符串的第一个字母在第一个设置的光标位置打印,但是为什么?
  • @Louiskoder:谢谢,现在应该修复了。循环的第一次迭代将光标列设置回 45,以便第二个字符覆盖第一个字符。
【解决方案2】:

知道了! Nate 是对的,但忘记添加 mov ah, 02hint 10h

print_string:           ; Routine: output string in SI to screen
      mov ah, 02h
      mov dl, 0   ; initial cursor column
      mov dh, 0     ; row
      int 10h
      mov bl, 2       ; colour
      mov cx, 1       ; no.of times

    .repeat:
      lodsb           ; Get character from string
      cmp al, 0
      je .done        ; If char is zero, end of string
      mov ah, 09h     ; Otherwise, print it
      int 10h         
    
      mov ah, 02h     ; update cursor position
      int 10h
      inc dl          ; same as `add dl, 1` but smaller 
    
      jmp .repeat
    
    .done:
      ret

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-09
    • 1970-01-01
    • 2013-07-07
    • 1970-01-01
    • 2016-10-25
    • 2016-10-30
    • 1970-01-01
    • 2015-07-16
    相关资源
    最近更新 更多