汇编文本颜色

4

我正在用汇编语言制作一个 ISO 文件,希望能够给文本添加颜色(在这种情况下是红色)。
有人知道如何实现吗?

[BITS 16]
[ORG 0x7C00]

jmp main

main:
    mov si, string ; si=string
    call printstr
    jmp $

printstr:
    lodsb ; al=&si[0]
    cmp al,0 ;FLAGS = 0
    jnz print
    ret

print:
    mov  ah,0Eh
    int  10h
    jmp printstr

string db "HELLO WORLD!",13,10,0

times 510 - ($-$$) db 0
dw 0xAA55

2
你可以考虑使用Int 10/AH=09h - Michael Petch
2
或者你可以直接写入文本模式视频缓冲区 B800h,它由字符:属性字节对组成。在这种情况下,这个SO问题可能会有所帮助。'attr'设置了文本颜色前景和背景。 - zx485
可能是bootloader printing on video memory 0xb8000的重复问题。 - Preston Hager
2个回答

5
作为初步建议,始终设置引导加载程序所依赖的段寄存器。在这里,由于使用了 lodsb[ORG 0x7C00],您必须设置 DS=0。 最好确保方向标志 DF 处于已知状态。简单的 cld 即可。
回答您的问题。您使用的 BIOS.Teletype 函数 0Eh 可以产生所需的红色 但仅在图形视频模式下。因此,下一个解决方案将起作用:
[BITS 16]
[ORG 7C00h]
    jmp     main
    ...
main:
    xor     ax, ax     ; DS=0
    mov     ds, ax
    cld                ; DF=0 because our LODSB requires it
    mov     ax, 0012h  ; Select 640x480 16-color graphics video mode
    int     10h
    mov     si, string
    mov     bl, 4      ; Red
    call    printstr
    jmp     $

printstr:
    mov     bh, 0     ; DisplayPage
print:
    lodsb
    cmp     al, 0
    je      done
    mov     ah, 0Eh   ; BIOS.Teletype
    int     10h
    jmp     print
done:
    ret

string db "HELLO WORLD!",13,10,0

times 510 - ($-$$) db 0
dw      0AA55h

如果您希望使用文本视频模式,则BIOS.WriteCharacterWithAttribute函数09h是正确的选择。
请注意,参数不同。BL现在保存属性字节,指定同时显示2种颜色(前景色在低四位中,背景色在高四位中),另一个参数使用CX寄存器。
另一点是这个函数将为每个ASCII码显示一个有颜色的字符。因此回车符(13)和换行符(10)将无法正确解释,除非您采取措施。
然而,最重要的事实是该函数不会推进光标。幸运的是,有一个不错的技巧。只需依次调用两个函数09h和0Eh即可...
示例:
[BITS 16]
[ORG 7C00h]
    jmp     main
    ...
main:
    xor     ax, ax     ; DS=0
    mov     ds, ax
    cld                ; DF=0 because our LODSB requires it
    mov     ax, 0003h  ; Select 80x25 16-color text video mode
    int     10h
    mov     si, string
    mov     bl, 04h    ; RedOnBlack
    call    printstr
    jmp     $

printstr:
    mov     cx, 1     ; RepetitionCount
    mov     bh, 0     ; DisplayPage
print:
    lodsb
    cmp     al, 0
    je      done
    cmp     al, 32
    jb      skip
    mov     ah, 09h   ; BIOS.WriteCharacterWithAttribute
    int     10h
skip:
    mov     ah, 0Eh   ; BIOS.Teletype
    int     10h
    jmp     print
done:
    ret

string db "HELLO WORLD!",13,10,0

times 510 - ($-$$) db 0
dw      0AA55h

4
我是点赞,但我想提一下,如果你要使用字符串指令(LODSx / CMPSx / SCASx等),你还需要确保方向标志被设置为所需的方式(当然,这个代码中需要向前,就需要使用CLD)。BIOS不能保证方向标志被清除。顺带一提:其中一个模拟器曾经有一个有趣的错误,如果你使用STD来反转方向,Int 13h / Ah = 2磁盘读取会失败,哈哈。 - Michael Petch

2
你可以使用Int 10 / AH:0x09。它的参数与Int 10 / AH:0x0E相同,除了BH是文本颜色。只需将以下行添加到您的代码即可。"最初的回答"
mov ah, 09h
mov bh, 0xF0     ; add this line, this is the text color (white on black)
int 10h

我使用的另一种方法是,在保护模式下无法使用BIOS函数时,使用位于0x0B800处的内存。通用代码如下:

Original Answer翻译成"最初的回答"

mov ebx, 0xb800      ; the address for video memeory
mov ah, 0xF0         ; the color byte is stored in the upper part of ax (ah).
printstr:
  lodsb              ; load char at si into al and increment si.
  cmp al, 0
  je .done
  mov [ebx], ax      ; move the character into video memeory.
  add ebx, 2         ; move the video memeory pointer up two bytes.
  jmp printstr
.done:
  ret

查看此问题的其他资源可能包括:

注:Original Answer翻译成“最初的回答”。

你的第一段代码中是指 mov ah, 0Eh 还是 mov ah, 09h - Michael Petch
@Michael,我确实是指mov ah, 09h。很好的发现,答案已经被编辑为正确的数字。 - Preston Hager
3
请注意,Int 10/AH:0x09 对控制字符的行为与 Int 10/AH:0x0E截然不同。具体而言,前者将显示类似回车、换行和退格键的字符;后者则会移动光标以替代显示控制字符。 - Brendan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接