在这里,我编写了将ASCII字符写入VGA内存的代码:

.global _put_in_mem
_put_in_mem:
push bp
mov bp, sp
mov cx, [bp + 4]
mov si, [bp + 6]
mov bx, 0xb800
mov ds, bx
mov [si], cx
add bx, 0x1
mov cx, 0x7
mov [si], cx
pop bp
ret

这是通过如下所示的kernel.c文件调用的:
void main()
{
 extern void put_in_mem();
 char c = 'e';
 put_in_mem(c, 0xA0);
}

上面的代码旨在在QEmu的第二行的开头打印“e”,但并非如此。我尝试使用GDB进行调试,发现该命令
mov bx, 0xb800

在GDB中已成为
mov    -0x4800,%bx

并且此命令后ebx中的值为0x0。
为什么未在bx寄存器中加载该值?

此外,我认为移动指令使用ds寄存器作为其段基础,并从ds的内容中偏移所有地址。因此,根据这种推理,我认为
mov [si], cx

指令cx寄存器的内容将被放置在地址0xb8a0中。这样对吗? mov指令也可以受任何其他段寄存器(例如cs,es等)影响吗?

最佳答案

例程_put_in_mem有两个问题,它不保留必须根据16位x86调用约定保留的寄存器DS和SI,请参见this document的第6节,并且不存储字符和属性字节适本地。

.global _put_in_mem
_put_in_mem:
push bp
mov bp, sp
mov cx, [bp + 4]
mov si, [bp + 6]   # si must be preserved across function calls
mov bx, 0xb800
mov ds, bx         # ds must be preserved across function calls
mov [si], cx
add bx, 0x1
mov cx, 0x7        # low byte 0x7, upper byte = character = 0x00
mov [si], cx       # si has not changed... overwriting with 0x0007
pop bp
ret

这是修复它的一种方法:
.global _put_in_mem
_put_in_mem:
push bp
mov bp, sp
mov cx, [bp + 4]   # cx = xxcc, where cc is ASCII character
mov ch, 0x7        # attribute byte: light-grey on black
mov bx, [bp + 6]   # bx = offset into VGA video buffer
mov ax, 0xb800     # VGA video buffer base at 0xb800 x 16
mov es, ax         # use ES segment register instead of DS
mov es:[bx], cx    # store ASCII at es:[bx], attribute at es:[bx+1]
pop bp
ret

在文本模式下,VGA attribute字节跟随字符字节。属性0x7表示在黑色背景上显示为浅灰色...请参见http://wiki.osdev.org/Printing_To_Screenhttp://en.wikipedia.org/wiki/VGA-compatible_text_mode

10-08 07:11