我目前正在从头开始开发一个操作系统内核。
我想使用一个函数,使用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并打印消息时,我得到:
c - 写入0xB8000/指针损坏时的行为异常-LMLPHP
在字符串的开头还有一个我没有加的字符。
当我将内存转储到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++ ;
}

我明白了:
c - 写入0xB8000/指针损坏时的行为异常-LMLPHP

最佳答案

编辑:好吧,我只是想知道问题出在哪里,但不是真正的原因。
问题在于编译和链接。。。
我以前是为64位elf编译的,现在改为32位编译/链接,文本打印正确,没有工件。

关于c - 写入0xB8000/指针损坏时的行为异常,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58633806/

10-10 10:47