我正在写一个具有键盘/光标支持的小内核。一切正常,直到我从unistd.h添加了功能

内核

#include "keyboard_map.h"
#include "keyboard.c"
#include "video.c"
#include <unistd.h>

void kmain(void)
{
    terminal_initialize();
    terminal_writestring("Hello, kernel World!\n");
    idt_init();
    kb_init();
    kprint_newline();
    writeSector();
    sleep(1);
    unsigned char c = readSector2();
    kprint((const char *)c);

    while(1);
}


内核

bits 32

%define     COLS    80

section .text

    ;multiboot spec

    align 4

    dd 0x1BADB002              ;magic

    dd 0x00                    ;flags

    dd - (0x1BADB002 + 0x00)   ;checksum. m+f+c should be zero




global start

global keyboard_handler

global read_port

global write_port

global load_idt


extern kmain        ;this is defined in the c file

extern keyboard_handler_main



read_port:

mov edx, [esp + 4]

        ;al is the lower 8 bits of eax

in al, dx   ;dx is the lower 16 bits of edx

ret




write_port:

mov   edx, [esp + 4]

mov   al, [esp + 4 + 4]

out   dx, al

ret




load_idt:

mov edx, [esp + 4]

lidt [edx]

sti                 ;turn on interrupts

ret




keyboard_handler:

call    keyboard_handler_main

iretd




start:

cli                 ;block interrupts

mov esp, stack_space

call kmain

hlt                 ;halt the CPU




section .bss

resb 8192; 8KB for stack

stack_space:


链接

OUTPUT_FORMAT(elf32-i386)

ENTRY(start)

SECTIONS

 {

   . = 0x100000;

   .text : { *(.text) }

   .data : { *(.data) }

   .bss  : { *(.bss)  }

 }


我正在使用gcc交叉编译器通过终端对其进行编译,然后在qemu上运行

nasm -f elf /Users/par/Desktop/kernel.asm -o kasm.o
/usr/local/gcc-4.8.1-for-linux32/bin/i586-pc-linux-gcc -m32 -c -std=c99     /Users/par/Documents/HelloC/HelloC/kernel.c -o kc.o
/usr/local/gcc-4.8.1-for-linux32/bin/i586-pc-linux-ld -m elf_i386 -T /Users/par/Desktop/link.ld -o kernel kasm.o kc.o
qemu-system-i386 -kernel kernel


我是c编程的新手,所以希望这对那里的人来说是一个简单的问题。项目中还有其他几个c文件,但是我相信问题一定在上面。如果取消了unistd.h和sleep()的话,一切都会起作用,但是在尝试与该引用链接时,将产生一个错误,指出“对kc.o中的sleep()函数的未定义引用”。

这些引用也可以在项目中的其他地方正常工作...

 #include <stddef.h>
 #include <stdint.h>


...这进一步使我感到困惑,为什么unistd.h无法链接...但可以编译。

最佳答案

包括unistd.h只是告诉编译器有关库中定义的内容(函数等)的信息。它描述了库的接口,但没有描述库功能的实现。

这就是您的程序编译的原因。 unistd.h中有一个sleep()声明。它可能看起来像这样:

unsigned sleep(unsigned);


您可以看一下,它是一个文本文件。

问题在于,当您尝试链接时,没有任何东西定义sleep()。通常,sleep()和其他标准函数存在于预编译的库中。名称类似libc.a的文件.a文件是一个包含目标文件的归档文件,这些文件实现了库的功能,链接程序可以将这些文件与您的目标文件链接,以解析对诸如sleep()之类的引用。

stddef.h stdint.h起作用的原因是,它们主要定义了在编译时使用的类型和宏,但不需要在链接时插入任何其他目标代码。

您的链接行不包含任何库。我怀疑这是因为您的裸机环境中没有任何东西。

您有两种选择。您可以尝试移植一个预先存在的库以在您的环境中工作,或者可以编写自己的sleep()函数。

您可以看一下ELLCC,它是提供库的(几个)跨开发工具链之一。 ELLCC的裸机库正在开发中,但是查看ELK blog posts可能会给您一些想法。

关于c - 内核编译,但不会与unistd.h引用链接,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34184743/

10-12 07:36
查看更多