64 位内核奇怪的行为

64 bits kernel weird behaviour

我无法理解这个问题:

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

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

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

如果我不声明任何东西,代码会很好用(你好)。

main.c

#include "system.h"

int main(void)
{
    init_video();
    move_csr();
    p("HELLO[=10=]");
    while(1){}
    return 1;

}

system.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]=='[=12=]') 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;

代码运行良好。

我不太了解汇编,也许我遗漏了一些关于如何管理内存的重要信息。

Michael Petch 的回答

Looking inside your kernel.bin file the HELLO string seems to be partially in the first 512 bytes and the remainder outside. As you add or remove code it alters where that string is placed (whether it is in the first 512 bytes or not) and is likely why your code acts differently. You definitely will have to look at reading more than 1 sector to resolve this.

问题是加载程序文件仅读取 kernel.bin 的一个扇区,因此我尝试打印的字符串仅被部分加载。解决方案是修改引导加载程序,以便它为 运行 代码加载足够的扇区。

[编辑]

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