我目前正在观看有关基本图形操作系统开发的 Udemy 教程,该教程刚刚开始解释如何使用位图字体在 VBE 图形模式下呈现文本。演示者创建一个函数(由 python 脚本自动生成)通过在一组数组中查找来返回给定字符的给定行。
这里的关键点是代码使用了一组二进制数据数组,每个数组包含 13 个字符的位图,就像这样。
int getArialCharacter(int index, int y) {
unsigned int characters_arial_0[][150] = {
{ // List of 15 10-digit binary numbers, corresponding to rows of ASCII code 0 },
{ // List of 15 10-digit binary numbers, corresponding to rows of ASCII code 1 },
...
{ // List of 15 10-digit binary numbers, corresponding to rows of ASCII code 12 }
};
unsigned int characters_arial_1[][150] = { ... };
unsigned int characters_arial_2[][150] = { ... };
unsigned int characters_arial_3[][150] = { ... };
unsigned int characters_arial_4[][150] = { ... };
unsigned int characters_arial_5[][150] = { ... };
unsigned int characters_arial_6[][150] = { ... };
unsigned int characters_arial_7[][150] = { ... };
int start = (int)(' ');
if (index >= start && index < start + 13) {
return characters_arial_0[index - start][y];
}
else if (index >= start + 13 && index < start + 13 * 2) {
return characters_arial_1[index - (start + 13)][y];
}
...
else if (index >= start + 13 * 7 && index < start + 13 * 8) {
return characters_arial_7[index - (start + 13 * 7)][y];
}
}
我认为这似乎很奇怪且不必要,所以我尝试将其重构为使用单个数组(尽管使用不同的字体),如下所示:
int font_func(int index, int y)
{
// I also tried uint8_t[128][64]
uint8_t chars[][64] = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0000 (nul)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0001
...
};
return chars[index][y];
}
但是,当我尝试使用它时,根本没有文本打印到屏幕上。我能想到 3 种解释,但没有一个能完全让我满意:
-
- 由于我们的链接器只链接文本部分而不链接数据部分(链接命令为
ld -m elf_i386 -o boot/bin/kernel.img -Ttext 0x1000 boot/bin/kernel_entry.bin boot/bin/kernel.o
),因此不会链接大数组。这种解释似乎很弱,因为教程版本中的各个较小的数组链接得很好。
- 由于我们的链接器只链接文本部分而不链接数据部分(链接命令为
-
- 由于尚未实现 memcpy,因此声明启用了优化的大型数据结构会导致对 memcpy 的调用不正确。这种解释似乎也很薄弱,因为我希望得到编译器警告。
-
- 我在实施的其他地方犯了一些错误。这似乎不太可能,因为我唯一改变的是传递给打印函数的函数指针。(为了记录,我已经尝试过考虑签名和未签名的字符。没有运气。)
这个问题的根源似乎是什么?谢谢您的帮助。
如果有帮助,该项目的 makefile 如下所示:
all: bootloader
bootloader:
nasm boot/boot.asm -f bin -o boot/bin/boot.bin
nasm boot/kernel_entry.asm -f elf -o boot/bin/kernel_entry.bin
gcc -m32 -fno-lto -nostdlib -ffreestanding -nodefaultlibs -c boot/final.c -o boot/bin/kernel.o
ld -m elf_i386 -o boot/bin/kernel.img -Ttext 0x1000 boot/bin/kernel_entry.bin boot/bin/kernel.o
objcopy -O binary -j .text boot/bin/kernel.img boot/bin/kernel.bin
cat boot/bin/boot.bin boot/bin/kernel.bin > os.img
clear:
rm -f boot/boot.img
run:
qemu-system-x86_64 -vga virtio -drive format=raw,file=os.img
编辑 2:可在此处找到最小可重现示例:https ://drive.google.com/drive/folders/1Z5wlXrtRbXQ1wNhBU2_YsSMovaGe7DvB?usp=sharing