我目前正在从头开始开发一个操作系统内核。
我想使用一个函数,使用0xB8000内存位置在屏幕上写入字符。
问题如下:
我使用:
void video_write(const unsigned char *string , char color ){
unsigned char *p = (unsigned char*) string ;
char *c = (char*) (VIDEO_MEMORY ); //VIDEO_MEMORY is 0XB8000
while(*p != '\0')
{
*c = p[0] ;
c++ ;
*c = color ;
c++ ;
p++ ;
}
}
void clear_screen(){
char *c = (char*) VIDEO_MEMORY ;
int i = 0 ;
for(i ; i < 4000 ; i++){
*c='\0' ;
c++ ;
}
}
打印到屏幕上。
函数由以下调用:
void main(){
clear_screen() ;
video_write("Message\0" , 0x0E);
}
操作系统正确引导,但在输入32位PM并打印消息时,我得到:
在字符串的开头还有一个我没有加的字符。
当我将内存转储到0xB8000时,我得到:
00000000: c30e 4d0e 650e 730e 730e 610e 670e 650e ..M.e.s.s.a.g.e.
00000010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
十六进制中的4D是“M”。它应该是字符串中的第一个字符,但它不是,因为天知道是什么原因。
相反,第一个字符是C3,它是字符串开头的垃圾。
尽管如此,直接从main()函数打印这些字符是完美的,所以我猜字符串的指针损坏了。
你们知道那里发生了什么吗?
编辑:
以下是引导加载程序代码:
ifndef BOOT_ASM
%define BOOT_ASM
[org 0x7C00]
KERNEL_OFFSET equ 0x1000
[bits 16]
mov [BOOT_DRIVE] , dl
mov BP , 0x9000
mov SP , BP
call load_kernel
call switch_pm
%include "print.asm"
%include "hexprint.asm"
%include "disk_io.asm"
%include "GDT.asm"
load_kernel :
mov SI , KERNEL_MSG
call print_string
mov BX , KERNEL_OFFSET
mov DH , 15
mov DL , [BOOT_DRIVE]
call disk_load
ret
switch_pm:
cli
lgdt [gdt_descriptor]
mov EAX , CR0
or EAX , 1
mov CR0 , EAX
jmp CODE_SEG:PM_init
[bits 32]
PM_init:
mov AX , DATA_SEG
mov DS , AX
mov SS , AX
mov ES , AX
mov FS , AX
mov GS , AX
mov EBP , 0x90000
mov ESP , EBP
call BEGIN_PM
jmp $
BEGIN_PM :
call KERNEL_OFFSET
ret
BOOT_DRIVE: db 0
RM_MSG db "SAHARA OS , Real mode" , 0x0
PM_MSG db "SAHARA OS , Protected mode" , 0x0
KERNEL_MSG db "SaharaOS : Oasis kernel " , 0x0A , 0x0D , 0x0
times 510 - ($-$$) db 0
dw 0xaa55
%endif
(数据段是GDT中的,GDT数据-GDT开始)
在0x1000处,我执行这段代码,这是内核项
[bits 32]
[extern main]
call main
jmp $
在clear_screen()之后转储内存时,我只得到0,因此这是按预期工作的。
我认为真正包含此字符的是字符串变量,因为当我这样做时:
void video_write(const unsigned char *string , char color ){
unsigned char *p = (unsigned char*) string ;
p++ ;
char *c = (char*) (VIDEO_MEMORY ); //VIDEO_MEMORY is 0XB8000
while(*p != '\0')
{
*c = *p ;
c++ ;
*c = color ;
c++ ;
p++ ;
}
添加“p++;”,消息将不带工件地打印出来。
所以我不认为0xB8000中专门放了垃圾。
例如,偏移视频内存,以便在屏幕中间打印消息,会得到相同的结果:
当我将视频内存偏移任何值时:
void video_write(const unsigned char *string , char color ){
unsigned char *p = (unsigned char*) string ;
char *c = (char*) (VIDEO_MEMORY + 1980 ); //VIDEO_MEMORY is 0XB8000
while(*p != '\0')
{
*c = p[0] ;
c++ ;
*c = color ;
c++ ;
p++ ;
}
我明白了:
最佳答案
编辑:好吧,我只是想知道问题出在哪里,但不是真正的原因。
问题在于编译和链接。。。
我以前是为64位elf编译的,现在改为32位编译/链接,文本打印正确,没有工件。
关于c - 写入0xB8000/指针损坏时的行为异常,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58633806/