Assembly 为什么不是';使用0Eh 10h中断时,文本是否有颜色?

Assembly 为什么不是';使用0Eh 10h中断时,文本是否有颜色?,assembly,x86,nasm,x86-64,qemu,Assembly,X86,Nasm,X86 64,Qemu,我使用10h中断,将AH作为0Eh输出“Hello World!”文本已输出,但未着色。我正在qemu-system-x86_64上运行它,并使用NASM进行组装,我的代码如下: BITS 16 start: mov ax, 07C0h ; Set up 4K stack space after this bootloader add ax, 288 ; (4096 + 512) / 16 bytes per paragraph

我使用10h中断,将AH作为0Eh输出“Hello World!”文本已输出,但未着色。我正在qemu-system-x86_64上运行它,并使用NASM进行组装,我的代码如下:

 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


    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 'Hello World!', 0


 print_string:                   ; Routine: output string in SI to screen
    mov ah, 0Eh             ; int 10h 'print char' function
    mov bh, 0x00
    mov bl, 0x03

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

 .done:
    ret


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

我可以用09代替0E,在10小时中断时使用彩色打印。但是,要使用此方法,必须更改每个字符后的光标位置。这是工作代码

     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


    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 'Hello World!', 0


print_string:                   ; Routine: output string in SI to screen


 .repeat:
    mov ah, 09h             ; int 10h 'print char' function
    mov bh, 0x00
    mov bl, 0x03
    mov cx, 01h
    lodsb                   ; Get character from string
    cmp al, 0
    je .done                ; If char is zero, end of string
    int 10h                 ; Otherwise, print it
    mov bh, 00h
    mov ah, 03h
    int 10h
    mov ah, 02h
    mov bh, 00h
    inc dl
    int 10h
    jmp .repeat

 .done:
    ret


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

我可以用09代替0E,在10小时中断时使用彩色打印。但是,要使用此方法,必须更改每个字符后的光标位置。这是工作代码

     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


    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 'Hello World!', 0


print_string:                   ; Routine: output string in SI to screen


 .repeat:
    mov ah, 09h             ; int 10h 'print char' function
    mov bh, 0x00
    mov bl, 0x03
    mov cx, 01h
    lodsb                   ; Get character from string
    cmp al, 0
    je .done                ; If char is zero, end of string
    int 10h                 ; Otherwise, print it
    mov bh, 00h
    mov ah, 03h
    int 10h
    mov ah, 02h
    mov bh, 00h
    inc dl
    int 10h
    jmp .repeat

 .done:
    ret


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

要更改光标位置,请执行以下操作:

text_string db 'Hello World!', 0
text_len = ($-text_string)-1

    mov ah,3
    xor bh,bh
    int 10h
    add dh,text_len
    cmp dh,79
    jb short P1
    sub dh,79
    inc dl
P1: mov ah,2
    int 10h
RBIL->inter61a.zip->INTERRUP.A

--------V-1002-------------------------------
INT 10 - VIDEO - SET CURSOR POSITION
AH = 02h
BH = page number
    0-3 in modes 2&3
    0-7 in modes 0&1
    0 in graphics modes
DH = row (00h is top)
DL = column (00h is left)
Return: nothing
SeeAlso: AH=03h,AH=05h,INT 60/DI=030Bh,MEM 0040h:0050h
--------V-1003-------------------------------
INT 10 - VIDEO - GET CURSOR POSITION AND SIZE
AH = 03h
BH = page number
    0-3 in modes 2&3
    0-7 in modes 0&1
    0 in graphics modes
Return: AX = 0000h (Phoenix BIOS)
CH = start scan line
CL = end scan line
DH = row (00h is top)
DL = column (00h is left)
Notes:  a separate cursor is maintained for each of up to 8 display pages
many ROM BIOSes incorrectly return the default size for a color display
  (start 06h, end 07h) when a monochrome display is attached
With PhysTechSoft's PTS ROM-DOS the BH value is ignored on entry.
SeeAlso: AH=01h,AH=02h,AH=12h/BL=34h,MEM 0040h:0050h,MEM 0040h:0060h
我更喜欢直接写入0B800h的地址

    mov ah,3   ; calculating the target offset address from the cursor position
    xor bh,bh
    int 10h

    xor cx,cx
    add dl,dl  ; column
    mov cl,dl

    xor ax,ax
    mov al,dh  ; row
    mov bx,160
    mul bx

    add ax,cx
    mov di,ax

    mov ax,0B800h
    mov es,ax
    mov si,text_string
    mov cx,text_len
    mov ah,3  ; color
    cld
RP: lodsb     ; get byte from DS:SI
    stosw     ; store word in ES:DI
    loop RP

未测试,但我希望没有出现错误。

要更改光标位置:

text_string db 'Hello World!', 0
text_len = ($-text_string)-1

    mov ah,3
    xor bh,bh
    int 10h
    add dh,text_len
    cmp dh,79
    jb short P1
    sub dh,79
    inc dl
P1: mov ah,2
    int 10h
RBIL->inter61a.zip->INTERRUP.A

--------V-1002-------------------------------
INT 10 - VIDEO - SET CURSOR POSITION
AH = 02h
BH = page number
    0-3 in modes 2&3
    0-7 in modes 0&1
    0 in graphics modes
DH = row (00h is top)
DL = column (00h is left)
Return: nothing
SeeAlso: AH=03h,AH=05h,INT 60/DI=030Bh,MEM 0040h:0050h
--------V-1003-------------------------------
INT 10 - VIDEO - GET CURSOR POSITION AND SIZE
AH = 03h
BH = page number
    0-3 in modes 2&3
    0-7 in modes 0&1
    0 in graphics modes
Return: AX = 0000h (Phoenix BIOS)
CH = start scan line
CL = end scan line
DH = row (00h is top)
DL = column (00h is left)
Notes:  a separate cursor is maintained for each of up to 8 display pages
many ROM BIOSes incorrectly return the default size for a color display
  (start 06h, end 07h) when a monochrome display is attached
With PhysTechSoft's PTS ROM-DOS the BH value is ignored on entry.
SeeAlso: AH=01h,AH=02h,AH=12h/BL=34h,MEM 0040h:0050h,MEM 0040h:0060h
我更喜欢直接写入0B800h的地址

    mov ah,3   ; calculating the target offset address from the cursor position
    xor bh,bh
    int 10h

    xor cx,cx
    add dl,dl  ; column
    mov cl,dl

    xor ax,ax
    mov al,dh  ; row
    mov bx,160
    mul bx

    add ax,cx
    mov di,ax

    mov ax,0B800h
    mov es,ax
    mov si,text_string
    mov cx,text_len
    mov ah,3  ; color
    cld
RP: lodsb     ; get byte from DS:SI
    stosw     ; store word in ES:DI
    loop RP

未测试,但我希望没有错误。

我认为比标记为已接受的更好的方法是使用中断10h的函数13h。此函数用于将整个字符串以及属性(颜色)发送到屏幕。此功能有四种操作模式,在
AL
寄存器中指定

AL=00h:
BL
中的属性分配所有字符;不要更新光标位置。
AL=01h:
BL
中的属性分配所有字符;更新光标位置。
AL=02h:使用字符串中的属性;不要更新光标位置。
AL=03h:使用字符串中的属性;更新光标位置

因此,您可以通过在模式
00h
01h
BL
中指定属性,为整个字符串使用相同的属性(颜色),或者将属性混合在字符串本身中,以使用不同的属性打印每个字符

我看到这种方法的唯一缺点是,您必须预先知道字符串的长度(将其放入
CX
),因为此函数不能处理以null结尾的字符串。
但是,另一方面,将字符串的一个字节长度存储在其字符之前,而不是在其字符之后存储空字符,可能有一些好处:不需要遍历整个字符串就可以知道其长度;一个字节的长度不会比空终止符占据更多的位置。即使是两个字节的长度也不是很大的浪费。您可以将两字节的长度直接加载到
CX
中。您也可以对单字节长度执行同样的操作,但请确保在之后清除
CH

单独使用字符串的每个字符的ability属性有时也很有用

其他寄存器与往常一样:
BH
是页码。
DX
是屏幕上字符串的起始位置:
DH:DL=Y:X

ES:BP
指向内存中字符串的第一个字符

如果使用电传打字机模式(
01h
03h
),ASCII控制字符将正确解释,而不是打印为符号。它们还将光标位置更新到字符串的末尾

要使其连续工作,可以使用函数
AH=03h
获取光标位置。这样做是为了将光标位置加载到
DH:DL
,以便在随后调用
AH=13h
时直接使用它从该位置打印字符串。我是这样做的:

# Get cursor position.
getcur:        mov   $0x03, %ah         # Get cursor position into DH:DL = Y:X.
               int   $0x10              # Video BIOS interrupt.
               ret                      # Return to the caller.

# Print string with attributes.
# `putsa` expects attributes in `BL`.
# `puts` uses the default attributes (silver on black).
# Both expect a pointer to the string in `ES:SI`.
# The string should start with a 2-byte length information.
puts:          mov   $0x07,   %bl       # Default attribute: silver on black.
putsa:         call  getcur             # Get cursor position into DH:DL.
               mov   (%si),   %cx       # Length of the string into `CX`.
               mov   %si,     %bp       # Prepare the pointer:
               add   $2,      %bp       # Skip the 2-byte length word.
               mov   $0,      %bh       # Use page #0.
               mov   $0x1301, %ax       # Print string and update cursor.
               int   $0x10              # Video BIOS interrupt.
               ret                      # Return to the caller.
调用(假设
ES
设置正确):

数据部分:

msgHello:     .word 13                  # Length of the string.
              .ascii "Hello, World!"    # The string itself.

哦,服务仅适用于1986年1月19日及以后的XTs、ATs、EGAs和PC敞篷车。但我想这不会带来任何问题,除非你正在处理一件严重的旧垃圾-J

我认为比标记为接受的更好的方法是使用中断10h的函数13h。此函数用于将整个字符串以及属性(颜色)发送到屏幕。此功能有四种操作模式,在
AL
寄存器中指定

;make to use mov ah,0eh

bits 16

org 0x7c00


jmp basla

; clear screen with colour you want

basla:

  ;pencere boyutu 80x25 karakter

  mov ah,06h
  mov al,00h
  mov bh,0ach ; ah zemin rengi,ch karakter rengi
  mov cx,00h ;silmeye pencerenin sol ustunden basla
  mov dx,184fh ;18h(24.satir) ve 4fh(79.sutun)a kadar sil.
  int 10h

;then print your program

  mov di,isim ;dizinin ilk adresini di kutuk yazmacina ata
  call yazbas  ; alt program cagriliyor

  mov di,isim2 ;ikinci dizinin adresi ataniyor
  call yazbas  ;ayni alt program cagriliyor

  jmp $ ;sonsuz dongu

yazbas:

   mov ah,0eh

   mov al,[di]
   int 10h
   inc di
   or al,al
   jz bitti
   jmp yazbas

bitti:

ret

isim db "attila oguz",0

isim2 db "isletim duzenegine giris",0

times 510-($-$$) db 0

dw 0xaa55   
AL=00h:
BL
中的属性分配所有字符;不要更新光标位置。
AL=01h:
BL
中的属性分配所有字符;更新光标位置。
AL=02h:使用字符串中的属性;不要更新光标位置。
AL=03h:使用字符串中的属性;更新光标位置

因此,您可以通过在模式
00h
01h
BL
中指定属性,为整个字符串使用相同的属性(颜色),或者将属性混合在字符串本身中,以使用不同的属性打印每个字符

我看到这种方法的唯一缺点是,您必须预先知道字符串的长度(将其放入
CX
),因为此函数不能处理以null结尾的字符串。
但是,另一方面,将字符串的一个字节长度存储在其字符之前,而不是在其字符之后存储空字符,可能有一些好处:不需要遍历整个字符串就可以知道其长度;一个字节的长度不会比空终止符占据更多的位置。即使是两个字节的长度也不是很大的浪费。您可以将两字节的长度直接加载到
CX
中。您也可以对单字节长度执行同样的操作,但请确保在之后清除
CH

单独使用字符串的每个字符的ability属性有时也很有用

其他寄存器与往常一样:
BH
是页码。
DX
是启动