Gcc 64位内核异常行为

Gcc 64位内核异常行为,gcc,kernel,x86-64,osdev,Gcc,Kernel,X86 64,Osdev,我很难理解这个问题: 我有一段代码被引导加载程序调用,但当我编译并运行一个应该打印HELLO的测试时,可能会发生以下三种情况之一: 如果我声明另一个类型为unsigned的变量,代码将只打印字符串的一半(HE) 如果我声明另一种类型的var,它将不会打印任何内容() 如果我不声明任何东西,代码将运行良好(您好) main.c #include "system.h" int main(void) { init_video(); move_csr(); p("HELLO\0

我很难理解这个问题:

我有一段代码被引导加载程序调用,但当我编译并运行一个应该打印HELLO的测试时,可能会发生以下三种情况之一:

如果我声明另一个类型为unsigned的变量,代码将只打印字符串的一半(HE)

如果我声明另一种类型的var,它将不会打印任何内容()

如果我不声明任何东西,代码将运行良好(您好)

main.c

#include "system.h"

int main(void)
{
    init_video();
    move_csr();
    p("HELLO\0");
    while(1){}
    return 1;

}
系统.h

#ifndef __SYSTEM_H
#define __SYSTEM_H

/* MAIN.C */

extern void move_csr(void);

extern void init_video();
extern void pc(unsigned char);
extern void p(char*);

#endif
scrn.c

#include "system.h"

unsigned char *textmemptr;
int attrib = 0x0F;
int csr_x = 0, csr_y = 0;

void init_video() {
    textmemptr = (unsigned char*) 0xB8000;
    return;
}

void move_csr(void) {
        unsigned temp = csr_y * 80 + csr_x;
}

void pc(unsigned char c) {
    *textmemptr = c;
    textmemptr += 2;
}

void p(char* string) {
    for (int i = 0; ; i++) {
        if (string[i]=='\0') return;
        pc(string[i]);
    }
}
build.sh

#!/bin/bash

nasm -f bin boot.asm -o boot.bin
nasm -f elf64 loader.asm -o loader.o

#cc -m64  -ffreestanding -fno-builtin -nostdlib -c main.c
#-Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin
cc -m64 -masm=intel -fno-builtin -c main.c scrn.c
ld  -Ttext 0x100000 -o kernel.elf loader.o main.o scrn.o
objcopy -R .note -R .comment -S -O binary kernel.elf kernel.bin

dd if=/dev/zero of=image.bin bs=512 count=2880
dd if=boot.bin of=image.bin conv=notrunc
dd if=kernel.bin of=image.bin conv=notrunc bs=512 seek=1

rm ./boot.bin ./kernel.bin ./main.o ./loader.o ./kernel.elf

#qemu-system-x86_64 image.bin format=raw

qemu-system-x86_64 -drive file=image.bin,format=raw,index=0,media=disk -m 512
如果我抑制该行:

unsigned temp = csr_y * 80 + csr_x;
代码工作得很好


我对汇编知之甚少,也许我遗漏了一些关于如何管理内存的重要信息。

迈克尔·佩奇的回答

查看kernel.bin文件内部,HELLO字符串似乎是 部分在前512字节中,其余在外部。正如你所说 或者删除它改变字符串放置位置的代码(无论它是否在 前512字节(或否),这可能是代码起作用的原因 不同地你肯定要看不止一本书 部门来解决这个问题

问题是加载程序文件只读取kernel.bin的一个扇区,所以我试图打印的字符串只加载了一部分。解决方案是修改引导加载程序,使其加载足够的扇区以运行代码

[编辑]


正如Michael Petch所建议的,将
-z max page size=0x1000
添加到构建脚本中的
ld
,大大减少了.bin文件的大小。

要运行64位代码,您需要处于64位模式。您的boot.asm是否真的变为64位模式?或者您正在32位保护模式下运行?您所描述的内容通常与在32位保护模式下运行64位代码有关。很可能是别的,但这只是一个猜测,没有看到项目的其余部分。我可能需要查看boot.asm(甚至可能是loader.asm),以了解您是否处于32位保护模式或64位长模式)嘿@MichaelPetch很高兴再次收到您的来信。加载程序代码太大,无法在这里发布,我已经将其上载到我的github,如果它可以帮助您猜测问题的话。与此同时,我在试图弄清楚我是否在做你猜到的事情。谢谢。看起来您试图进入64位长模式(看起来没问题,但我只是快速查看了一下)。从磁盘读取内核的代码只读取内核的1个扇区。您的内核是否可能大于512字节?您可能需要将整个项目放在github上进行故障排除。非常感谢,我将研究如何从磁盘加载多个扇区,同时,我已将原始文件夹上载到github,以便您可以查看它。(基本上是我发布的代码+加载器+一些内存函数)。再次感谢你!扇区是512字节。如果你的
kernel.bin
是@MichaelPetch,我会很惊讶。事实上,它神奇地工作了,所以我认为它是合适的,我检查了一下,但没有,我正在更正最后一行。