这里我制作了一个代码,用于将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);
}
以上代码旨在打印" e"在QEmu的第二行开头,但事实并非如此。我尝试使用GDB进行调试,发现命令
mov bx, 0xb800
GDB中的已成为
mov -0x4800,%bx
此命令后ebx中的值为0x0
为什么没有在bx寄存器中加载该值?
此外,我认为移动指令使用ds寄存器作为其段基,并从ds的内容中偏移所有地址。所以根据这个推理,我假设当
mov [si], cx
指令将cx寄存器的内容放在地址0xb8a0。它是否正确? mov指令是否也会受到任何其他segement寄存器(如cs,es等)的影响?
答案 0 :(得分:4)
例程_put_in_mem存在一些问题,它不保留必须根据16位x86调用约定保留的寄存器DS和SI,参见this document的第6节,它没有' t正确存储字符和属性字节。
.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_Screen和http://en.wikipedia.org/wiki/VGA-compatible_text_mode
答案 1 :(得分:3)
确保它不是意外的内存引用。由于你的gdb输出看起来像是& t,它通常会显示$ for immediates。因此,您怀疑您真正拥有的是使用地址0xb800处的内存内容加载bx。你能查一下机器代码吗?
机器代码为0xb8001e8b
确实,这是用于从内存加载的机器代码。查看as86 manual,您可以看到:
# Prefix for immediate operands.
mov ax,#1234
Immediate value, ax becomes 1234.
因此,您应该在您的immediates前面添加#符号。请注意,这适用于所有中级人员。
虽然这可以解决您提出的问题,但请参阅@ amdn&#39答案,了解您遇到的其他问题。