问题
I'm doing an iso file in assembly and I want to add color to the text (in this case: red).
Does anyone know how to do it?
[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
回答1:
As a preliminary advice, always setup the segment registers that your bootloader depends on. Here, because of lodsb
together with [ORG 0x7C00]
, you must set DS=0
.
Best also make sure the direction flag DF is in a known state. A simple cld
will be enough.
To answer your question. The BIOS.Teletype function 0Eh that you use, can produce the desired red color but only while in a graphics video mode. Next solution will thus work:
[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
If however you want to work with the text video mode then BIOS.WriteCharacterWithAttribute function 09h is the right choice.
- Pay attention because the parameters are different.
BL
now holds an attribute byte that specifies 2 colors at the same time (foreground in the low nibble and background in the high nibble) and an extra parameter uses theCX
register. - Another point is that this function will show a colored glyph for every ASCII code. So the carriage return (13) and linefeed (10) will not get interpreted correctly unless you take measures.
- The most important fact however is that this function does not advance the cursor. Luckily there's a neat trick. Just invoke both functions 09h and 0Eh in a row and voilà...
Example:
[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
回答2:
You can use Int 10/AH:0x09. It has the same arguments as Int 10/AH:0x0E, except that BH is the text color. Simply add the following line to your code.
mov ah, 09h
mov bh, 0xF0 ; add this line, this is the text color (white on black)
int 10h
Another alternative that I use, since BIOS functions, aren't available in protected mode. Using the memory at 0x0B800. The general code then becomes:
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
Additional resources for looking into this may include:
- Editing Video Memory Directly.
- Source code for Example OS using these methods.
- Int 10h/AH:0x09
来源:https://stackoverflow.com/questions/55009353/assembly-text-colors