我正在编写一个支持键盘/光标的小内核。一切都很好,直到我从unistd.h添加一个函数
kernel.c
@EmbeddedId
kernel.asm
@Embeddable
link.ld
#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);
}
我通过终端用gcc交叉编译器编译它,并在qemu上运行
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:
我是c编程的新手,所以希望对于那里的人来说这是一个简单的问题。项目中还有其他几个c文件,但我确信问题必须在某个地方。如果unistd.h和sleep()被删除,一切都会有效,但是会在kc.o&#34;中创建一个错误,表示&#34;未定义的函数sleep()的引用。当试图链接该引用时。
这些参考文献在项目的其他地方也可以正常工作......
OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
SECTIONS
{
. = 0x100000;
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss) }
}
...这进一步让我感到困惑,为什么unistd.h不会链接......但会编译。
答案 0 :(得分:1)
包含unistd.h只是告诉编译器库中定义的东西(函数等)。它描述了库的接口,但没有描述库功能的实现。
这就是你的程序编译的原因。 unistd.h中有一个sleep()声明。它可能看起来像这样:
unsigned sleep(unsigned);
您可以查看它,它是一个文本文件。
问题在于,当您尝试链接时,没有任何内容定义sleep()。通常,sleep()和其他标准函数存在于预编译库中。名称类似于libc.a的东西.a文件是包含目标文件的存档,这些目标文件实现了库的功能,链接器可以将其与目标文件链接以解析对sleep()等内容的引用。
stddef.h stdint.h工作的原因是它们主要定义在编译时使用的类型和宏,但在链接时不需要任何其他目标代码。
您的链接行不包含任何库。我怀疑这是因为你的裸机环境没有。
你有几个选择。您可以尝试移植预先存在的库以在您的环境中工作,或者您可以编写自己的sleep()函数。
您可以查看ELLCC,它是提供库的一个(多个)交叉开发工具链。 ELLCC的裸机库正在进行中,但查看ELK blog posts可能会给你一些想法。