os dev:vga打印字符串和奇怪的编译器行为

时间:2014-07-13 15:39:07

标签: c++ string optimization kernel vga

我正在尝试实现一个非常简单的函数来在我的内核中打印字符串。

麻烦对我来说似乎很奇怪,我想我可能错过了一些重要的东西,但我不知道是什么。

所以,我有一个不起作用的代码:

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。

0 个答案:

没有答案