如何编写一个在 NASM 16 位实模式下打印以 null 结尾的字符串的函数?

ahs*_*n-a 3 x86 assembly bios nasm x86-16

我有一个简单的程序,它将一些以空结尾的字符串移动到寄存器bx

[org 0x7c00]    ; Tells the assembler where the code will be loaded
    mov ah, 0x0e

    mov bx, HELLO_MSG   ; Moves string inside of HELLO_MSG to bx
    call print_string   ; Calls the print_string function inside of ./print_string.asm

    mov bx, GOODBYE_MSG ; Moves string inside of GOODBYE_MSG to bx
    call print_string

    jmp $   ; Hangs

%include "print_string.asm"

HELLO_MSG:
    db 'Hello, World!', 0

GOODBYE_MSG:
    db 'Goodbye!', 0

    times 510-($-$$) db 0
    dw 0xaa55
Run Code Online (Sandbox Code Playgroud)

和一个print_string内部函数./print_string.asm

print_string:
    mov ah, 0x0e
    int 0x10
    ret
Run Code Online (Sandbox Code Playgroud)

print_string 函数不起作用。根据我的理解,ah有存储的值0x0e,所以如果al有值并且X运行,它告诉BIOS在屏幕上int 0x10显示值。al我如何为字符串复制这个?

Sep*_*and 5

print_string:
  mov ah, 0x0e
  int 0x10
  ret
Run Code Online (Sandbox Code Playgroud)

您的print_string例程使用 BIOS.Teletype 函数 0Eh。此功能将显示寄存器中保存的单个字符AL。由于此 BIOS 函数还要求您提供所需的 DisplayPage inBH和所需的 GraphicsColor in (仅当显示器处于图形视频模式时),因此使用寄存器作为此print_stringBL例程的参数可能不是最好的主意。BX

您的新例程必须循环遍历字符串并对字符串中包含的每个字符使用单字符输出函数。因为您的字符串是以零结尾的,所以一旦遇到该零字节,您就会停止循环。

[org 7C00h]

cld                  ; This makes sure that below LODSB works fine
mov  si, HELLO_MSG
call print_string
mov  si, GOODBYE_MSG
call print_string

jmp  $

print_string:
    push bx          ; Preserve BX if you need to!
    mov  bx, 0007h   ; DisplayPage BH=0, GraphicsColor BL=7 (White)
    jmp  .fetch
  .print:
    mov  ah, 0Eh     ; BIOS.Teletype
    int  10h
  .fetch:
    lodsb            ; Reads 1 character and also advances the pointer
    test al, al      ; Test if this is the terminating zero
    jnz  .print      ; It's not, so go print the character
    pop  bx          ; Restore BX
    ret
Run Code Online (Sandbox Code Playgroud)