我正在尝试实现一个非常简单的函数来在我的内核中打印字符串。
麻烦对我来说似乎很奇怪,我想我可能错过了一些重要的东西,但我不知道是什么。
所以,我有一个不起作用的代码:
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':< / p>
print("test");
我想知道,出于任何不明原因,
i += 80 - i % 80;
部分是制造麻烦,但如果我用分号改变它就没有效果......
但这不是全部。我正在编译这些标志:
clang++ -target i386 -std=c++11 -O2 -fno-builtin -nostdlib -ffreestanding -fno-exceptions -fno-rtti
如果我删除了优化标志'-O2',那么它在任何情况下都不会起作用。
我不明白我想念的是什么...... 请你能帮助我吗?我变得疯了:P
============= EDIT =============
经过调查,似乎默认的qemu设置不支持mtrrs(我使用特定的cpu设置检查了这个)。检查代码: (值得注意的是osdev说第5位检查,而英特尔说第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,intel声称它是禁用缓存。 这仍然打印第一个字母,而较短的字符串打印得很好......
我现在不知道该搜索什么。你有什么主意吗 ?谢谢你很多
============= EDIT =============
哇,刚刚发现了这个漂亮的虫子......解决方案在链接器脚本中:
.rodata BLOCK(4K) : ALIGN(4K) {
*(.rodata)
}
成为:
.rodata BLOCK(4K) : ALIGN(4K) {
*(.rodata*)
}
因为clang生成的不是 .rodata 部分,而是 .rodata.str1.1 部分。 这导致没有rodata字符串,除非它像4个字符一样短,在这种情况下它会被表示为一个int ... with -O2。