内核编译但不会 link 与 unistd.h 引用

Kernel compiles but won't link with unistd.h reference

我正在编写一个具有 keyboard/cursor 支持的小内核。一切正常,直到我从 unistd.h

添加一个函数

kernel.c

#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);
}

kernel.asm

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:

link.ld

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() 被删除,一切都正常,但是当尝试使用该引用 link 时会产生一个错误,显示 "Undefined reference to function sleep() in kc.o"。

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

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

...这让我更加困惑为什么 unistd.h 不会 link... 但会编译。

Including unistd.h 只是告诉编译器关于库中定义的东西(函数等)。它描述了库的接口,但没有描述库功能的实现。

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

unsigned sleep(unsigned);

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

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

stddef.h stdint.h 工作的原因是它们主要定义在编译时使用的类型和宏,但不需要在 [=33 处插入任何额外的目标代码=]时间。

您的 link 行不包含任何库。我怀疑那是因为你的裸机环境没有任何东西。

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

你可以看看ELLCC which is one (of several) cross development tool chains that provide libraries. ELLCC's bare-metal libraries are a work in progress, but looking at the ELK blog posts可能会给你一些想法。