我正在写一个具有键盘/光标支持的小内核。一切正常,直到我从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/