我正在尝试实现一个非常简单的函数来在我的内核中打印字符串。
这个麻烦对我来说似乎很奇怪,我在想我可能错过了一些重要的事情,但我不知道是什么。
所以,我有一个不起作用的代码:
void print (char c) {
static unsigned i =0;
if (c == '\n')
i += 80 - i % 80;
else {
*(reinterpret_cast<uint16_t*>(0xb8000) + i)
= static_cast<uint16_t>(c) | 0x0f << 8;
++i;
}
}
void print (const char* txt) {
for (int i=0; txt[i]!=0; ++i)
print(txt[i]);
}
请查看此摘录中的第 3 行: if (c=='\n') 如果我将其更改为无辜者会怎样: if (false) 那么它神奇地完美地工作......它不适用于 if(c =='T') 或其他任何东西,反正我的测试代码中还没有 '\n' :
print("test");
我想知道是否出于某种模糊的原因,
i += 80 - i % 80;
部分正在制造麻烦,但如果我用分号更改它并没有更好的效果......
但这还不是全部。我正在使用这些标志进行编译:
clang++ -target i386 -std=c++11 -O2 -fno-builtin -nostdlib -ffreestanding -fno-exceptions -fno-rtti
如果我删除优化标志“-O2”,那么它在任何情况下都不会起作用。
我不明白我想念什么...请,你能帮帮我吗?我快疯了:P
=============编辑==============
经过调查,默认 qemu 设置似乎不支持 mtrrs(我使用特定的 cpu 设置检查了这一点)。在这里检查代码:(值得注意的是,osdev 说检查第 5 位,而 intel 说第 12 位,后者似乎在 qemu 下工作)
bool msr () {
uint32_t eax, edx;
cpu::cpuid(0x01, eax, edx);
return edx & (1<<12);
}
这是我当前的代码库。
void print (char c) {
static unsigned i =0;
if (c == '\n')
i += 80 - i % 80;
else {
volatile const auto b = reinterpret_cast<uint16_t*>(0xb8000);
b[i++] = static_cast<uint16_t>(c) | 0x0f << 8;
}
}
void print (const char* txt) {
for (int i=0; txt[i]!=0; ++i)
print(txt[i]);
}
//==============================================================================
// kmain
//==============================================================================
[[noreturn]] extern "C" void kmain () {
__asm__ __volatile__(
"mov %%cr0, %%eax \n"
"or $(1<<30), %%eax \n"
"mov %%eax, %%cr0 \n"
"wbinvd \n"
:
:
: "eax");
print("text text text");
for (;;);
}
这里的 asm 部分是设置 cr0 中的第 30 位,英特尔声称这是禁用缓存。这仍然会打印第一个字母,而打印较短的字符串则很好......
我不知道现在要搜索什么。你有什么主意吗 ?十分感谢
=============编辑==============
哇,刚刚发现了一个不错的bug...
解决方案在链接描述文件中:
.rodata BLOCK(4K) : ALIGN(4K) {
*(.rodata)
}
变成:
.rodata BLOCK(4K) : ALIGN(4K) {
*(.rodata*)
}
只是因为 clang 生成的不是.rodata部分,而是.rodata.str1.1部分。这导致缺少rodata字符串,除非它短到4个字符,在这种情况下,它会被表示为一个int ...与-O2。