x86中内存分段的混乱

sar*_*hak 6 c x86 assembly

在这里,我制作了一个代码,用于将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等)的影响?

amd*_*mdn 4

例程 _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_Screenhttp://en.wikipedia.org/wiki/VGA-known_text_mode

  • @sarthak 正如 chqrlie 指出的那样,最初编写的函数修改了 DS 段寄存器和 SI 通用寄存器 - 这些寄存器必须由被调用者根据 16 位 x86 调用约定保存,请参阅 http://www.agner 的第 6 节。 org/optimize/calling_conventions.pdf。即使您递增 SI,mov [si],cx 也不起作用的原因是因为它具有 16 位(一个字)的隐含操作数大小,并且 x86 支持未对齐存储,因此它将存储属性但丢弃下一个字符(然后偏移 SI+1)。 (2认同)