简单的C内核字符指针不工作(Simple C Kernel char Pointers Aren&#

2019-07-30 05:20发布

我试图让使用C.一切加载一个简单的内核和工作正常,我可以访问视频存储和显示字符,但是当我试图实现某种原因它不工作的简单放功能。 我已经尽我自己的代码和其他的。 此外,当我尝试使用该函数外部声明的变量似乎并没有工作。 这是我自己的代码:

#define PUTCH(C, X) pos = putc(C, X, pos)
#define PUTSTR(C, X) pos = puts(C, X, pos)

int putc(char c, char color, int spos) {
    volatile char *vidmem = (volatile char*)(0xB8000);
    if (c == '\n') {
        spos += (160-(spos % 160));
    } else {
        vidmem[spos] = c;
        vidmem[spos+1] = color;
        spos += 2;
    }
    return spos;
}
int puts(char* str, char color, int spos) {
    while (*str != '\0') {
        spos = putc(*str, color, spos);
        str++;
    }
    return spos;
}
int kmain(void) {
    int pos = 0;
    PUTSTR("Hello, world!", 6);
    return 0;
}

spos (起始位置)的东西,因为我不能让全球定位变量。 putc工作正常,但puts不。 我也试过这样:

unsigned int k_printf(char *message, unsigned int line) // the message and then the line #
{
    char *vidmem = (char *) 0xb8000;
    unsigned int i=0;

    i=(line*80*2);

    while(*message!=0)
    {
        if(*message=='\n') // check for a new line
        {
            line++;
            i=(line*80*2);
            *message++;
        } else {
            vidmem[i]=*message;
            *message++;
            i++;
            vidmem[i]=7;
            i++;
        };
    };

    return(1);
};

int kmain(void) {
    k_printf("Hello, world!", 0);
    return 0;
}

为什么没有这方面的工作? 我尝试使用我的看跌期权执行与我的家乡GCC(没有颜色和SPOS数据和使用printf("%c")它工作得很好。

Answer 1:

既然你有与一般的全局变量的一个问题,这个问题最有可能与其中连接放置您的“Hello World”字符串文字在内存中,这样做。 这是由于字符串字面量通常存储在链接器全局内存的只读部分的事实......你有没有详细的你究竟是如何编译和链接你的内核,所以我会尝试像下面有什么东西其是否正常工作:

int kmain(void) 
{
    char array[] = "Hello World\n";
    int pos = 0;
    puts(array, 0, pos);
    return 0;
}

这将分配堆栈,而不是全局存储器上的字符数组,并避免与其中连接决定将全局变量的任何问题。

一般而言,创建一个简单的内核时,要编译并链接与外部OS库没有依赖性平坦的二进制文件。 如果你与像GRUB多重引导兼容引导装载程序时,您可能想看看从裸骨骼样本代码多重规格的网页 。



Answer 2:

由于这得到了SO之外的引用,我将添加一个普遍的答案

周围有几个互联网内核的例子,而且很多是在下降的各种状态 - 例如多重引导的示例代码缺乏汇编指令。 如果你正在寻找工作的开始,一个已知的很好的例子,可以发现http://wiki.osdev.org/Bare_Bones

到底有应妥善处理三两件事:

  1. 该引导程序将需要正确加载内核,因此他们必须在一定的格式上达成一致。 GRUB定义了相当普遍的标准是多引导,但你可以滚你自己。 归结起来,你需要选择的文件格式和位置在您的内核和相关元数据的所有部分在内存中结束了内核代码永远不会得到执行之前。 人们通常会使用具有多重ELF格式包含在其标头信息

  2. 编译器必须能够创建二进制代码是相关的平台。 一个典型的PC启动在16位模式之后,BIOS或引导程序往往可能决定改变它。 通常情况下,如果你使用GRUB的遗产,多引导规范其合同让你在32位模式。 如果您在使用64位Linux的默认编译器设置,你最终得到了错误的架构(这恰好是足够相似,你可能得到的东西你想要的结果)代码。 编译器也想改名的部分或包括特定于平台的机制和安全功能,如堆栈探测或金丝雀。 特别是在Windows编译器往往是注入当然休息的时候不进入Windows的情况下运行的特定主机代码。 故意提供的示例使用一个单独的编译器,以防止各种问题在这个category.these

  3. 链接器必须能够在代码中创建一个坚持到bootloader的合同输出需要的方式结合在一起。 接头具有生成二进制的默认方式,并且通常不是在所有你想要的。 在几乎所有情况下,选择了这个任务GNU LD意味着你需要编写一个能赋予你想要的地方所有部分链接脚本。 省略的部分会导致数据失踪,在错误的位置,部分可能使图像无法启动。 假设你有GNU LD,你也可以使用捆绑nm和objdump的工具,除了您所选择的十六进制编辑器来告诉你事情已经出现在你的输出二进制文件,有了它,检查你是否一直在下面已被合同为您设置。

这一基本类型的问题最终被追踪到不遵守以上的一个或多个步骤。 在这个答案的顶部使用参考,并去找差异。



文章来源: Simple C Kernel char Pointers Aren't Working