使用0Eh 10h中断时,为什么要使用文本颜色?

时间:2014-05-17 22:22:48

标签: 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
    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

4 个答案:

答案 0 :(得分:2)

我可以使用09进行10h中断而不是0E打印颜色。但是,您必须在每个字符后更改光标位置才能使用此方法。这是工作代码。

     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

答案 1 :(得分:1)

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

  

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

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

我用这种方法看到的唯一缺点就是你必须先知道字符串的长度(把它放到CX中),因为这个函数不能用以空字符结尾的字符串。
但是,另一方面,在字符之前存储字符串的一个字节长度而不是字符之后的空字符可能有一些好处:您不需要遍历整个字符串以了解其长度;并且一个字节的长度不会占用空终止符。即使是两个字节的长度也不是浪费。您可以将两个字节的长度直接加载到CX。您也可以使用一个字节长度执行相同的操作,但请确保之后清除CH

单独使用能力属性字符串的每个字符也可能有用。

其他寄存器与往常一样:
BH是页码。
DX是在屏幕上显示字符串的位置:DH:DL = Y:X
ES:BP指向内存中字符串的第一个字符。

如果使用电传打字模式(01h03h),则可正确解释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已正确设置):

               # Print a string with attributes.
               lea   msgHello, %si      # String to print (after 2-byte length)
               mov   $0x0C,    %bl      # Attributes: light red on black.
               call  putsa

               # Print it one more time with different attributes.
               # Note we don't have to set the pointer: it's already set.
               mov   $0x0C,    %bl      # Attributes: yellow on black.
               call  putsa

数据部分:

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

哦,服务仅适用于日期为1986年1月19日及以后的XT,AT,EGA和PC敞篷车。但我想这不会造成任何问题,除非你正在处理一件严重的旧垃圾; -J

答案 2 :(得分:1)

;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   

答案 3 :(得分:0)

要更改光标位置:

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的segmentaddress。

    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

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