在这里,我制作了一个代码,用于将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
Run Code Online (Sandbox Code Playgroud)
这是通过如下所示的kernel.c文件调用的:
void main()
{
extern void put_in_mem();
char c = 'e';
put_in_mem(c, 0xA0);
}
Run Code Online (Sandbox Code Playgroud)
上面的代码是为了在QEmu的第二行开头打印"e",但事实并非如此.我尝试使用GDB调试这个并找到该命令
mov bx, 0xb800
Run Code Online (Sandbox Code Playgroud)
在GDB中已成为
mov -0x4800,%bx
Run Code Online (Sandbox Code Playgroud)
此命令后的ebx中的值为0x0.
为什么没有在bx寄存器中加载该值?
此外,我认为移动指令使用ds寄存器作为其段基,并从ds的内容中偏移所有地址.所以根据这个推理,我假设什么时候
mov [si], cx
Run Code Online (Sandbox Code Playgroud)
指令cx寄存器的内容将放在地址0xb8a0.它是否正确?mov指令是否也会受到任何其他segement寄存器(如cs,es等)的影响?
例程 _put_in_mem 有几个问题,它不保留根据 16 位 x86 调用约定必须保留的寄存器 DS 和 SI,请参阅本文档的第 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
Run Code Online (Sandbox Code Playgroud)
这是修复它的一种方法:
.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
Run Code Online (Sandbox Code Playgroud)
在文本模式下, VGAattribute字节位于字符字节之后。0x7 属性意味着在黑色背景上显示为浅灰色...请参阅http://wiki.osdev.org/Printing_To_Screen和http://en.wikipedia.org/wiki/VGA-known_text_mode