【发布时间】:2020-05-09 14:25:08
【问题描述】:
我有一个用 C 编写的 32 位内核的简单实现(它是一个独立的实现):(VGA 屏幕处于 80*25 彩色文本模式)
#include<stdint.h>
#define COLOR 0x39
#define VIDEO_MEMORY 0xb8000
uint32_t get_cursor();
void set_cursor(uint32_t);
void puts(char* Message);
void kmain()
{
puts("This is a test message..");
return;
}
void puts(char* Message)
{
uint32_t pointer = get_cursor();
pointer <<= 1;
char* VGA_CURSOR = (char*) VIDEO_MEMORY;
VGA_CURSOR += pointer;
while (*Message)
{
*VGA_CURSOR = *Message;
Message++;
VGA_CURSOR ++;
*VGA_CURSOR = COLOR;
VGA_CURSOR ++;
}
VGA_CURSOR -= VIDEO_MEMORY;
pointer = (uint32_t)VGA_CURSOR;
pointer >>= 1;
set_cursor(pointer);
}
set_cursor 和 get_cursor 函数在程序集中定义如下:
[bits 32]
[global set_cursor]
[global get_cursor]
set_cursor: ;ebx is the location
mov ebx,[esp+0x18]
mov al, 0x0f ;Refer to the index register table port mapping for CRT (low byte)
mov dx, 0x3d4 ; port number CRT index
out dx,al ;Write 0x0f in port 0x3D4 --- note that the port registers are 1 byte in size
mov dx,0x3d5 ;port number CRT data
mov al,bl
out dx,al
mov al, 0x0e ;Refer to the index register table port mapping for CRT (high byte)
mov dx, 0x3d4 ; port number CRT index
out dx,al
mov dx,0x3d5 ;port number CRT data
mov al,bh
out dx,al
ret
get_cursor:
mov al, 0x0f ;Refer to the index register table port mapping for CRT (low byte)
mov dx, 0x3d4 ; port number CRT index
out dx,al ;Write 0x0f in port 0x3D4 --- note that the port registers are 1 byte in size
mov dx,0x3d5 ;port number CRT data
in al,dx ;Store the low byte in al -- Hardware forced to use al
mov bl,al
mov al, 0x0e ;Refer to the index register table port mapping for CRT (high byte)
mov dx, 0x3d4 ; port number CRT index
out dx,al ;Write 0x0f in port 0x3D4 --- note that the port registers are 1 byte in size
mov dx,0x3d5 ;port number CRT data
in al,dx ;Store the high byte in al -- Hardware forced to use al
mov bh,al ;Store the high byte in bh
xor eax,eax
mov ax,bx
ret
在这里,getcursor 函数似乎工作正常(它获取范围从 0 到 80*25 的光标值) 我知道 setcursor 的实现也是对的。 (我在纯汇编代码中使用过它)。我相信在堆栈上传递值时存在错误。 我哪里错了?
【问题讨论】:
-
mov ebx,[esp+0x18]不正确。在 32 位 ABI 参数是在堆栈上传递的。在 ESP+0 处是返回地址(由call指令或等效指令放在那里)。 ESP+4 将是第一个参数。如果你使用mov ebx,[esp+4]会发生什么? -
+4 因为 IP 是 32 位的?
-
此外,EBX 在 GCC
-m32使用的调用约定中保留调用。使用movzx ecx, word [esp+4]将返回地址上方的 2 个字节加载到 ECX,而不是 EBX。 (或使用gcc -m32 -mregparm=3使其在 EAX、ECX、EDX 寄存器中传递参数(按 IIRC 的顺序),而不是低效的堆栈参数约定。) -
ESP+4 因为返回地址是32位(4字节)(返回地址是ESP+0, ESP+1, ESP+2, ESP+3
-
还有:
xor eax,eax;mov ax,bx??你忘了movzx eax, bx吗?或者更好的是,以另一种顺序读取输入(如果可能的话),这样你最后就可以在 AL 中获得正确的值,并且可以将另一个值移动到 AH 中。 (并且在函数的开头对 EAX 进行异或零,这样它就会被零扩展)。同样,您可能不想破坏调用者的 EBX。
标签: c assembly x86 kernel osdev