不能 Link GDT 和 IDT 一起

Can't Link together GDT and the IDT

我最近开始学习 James Molly 的内核开发教程,并且已经实现了 GDT 和 IDT。

当我 link 将高级函数与其低级汇编函数放在一起时,问题就出现了。

您可以在此处找到代码 Source on Github

这是目录结构

.
|-- arch
|-- boot
| |-- boot.s
| |-- buildboot.sh
| |-- gdt.s
| |-- idt.s
| `-- interrupt.s
|-- build
| |-- boot.s.o
| |-- gdt.o
| |-- gdt.s.o
| |-- idt.o
| |-- idt.s.o
| |-- interrupt.s.o
| |-- io.o
| |-- isr.o
| |-- main.o
| |-- memory.o
| |-- monitor.o
| `-- stdlib.o
|-- doc
| `-- Bug_Log.md
|-- include
| |-- gdt.cc
| |-- gdt.h
| |-- gdt.o
| |-- idt.cc
| |-- idt.h
| |-- idt.o
| |-- io.cc
| |-- io.h
| |-- io.o
| |-- isr.cc
| |-- isr.h
| |-- isr.o
| |-- memory.cc
| |-- memory.h
| |-- memory.o
| |-- monitor.cc
| |-- monitor.h
| |-- monitor.o
| |-- SConstruct
| |-- stdlib.cc
| |-- stdlib.h
| |-- stdlib.o
| `-- system.h
|-- JOSMake.sh
|-- link.ld
|-- main.cc
`-- ReadMe.md

这是 Bash 脚本 JOSmake.sh

    #
# Build File for JOS
#
# To Build
#     bash build.sh
# To Run
#   bash run.sh

# ----------------------------------------------------------------------------------------------
# JOS uses assembly to build the bootsector
# Compile the boot Sectors in boot
echo "==============================================="
echo "-------- Building Boot Sectors ----------------"
cd boot
# Run the Make Script inside the boot directory
bash buildboot.sh
cd ..
echo "==============================================="
# ----------------------------------------------------------------------------------------------

# ----------------------------------------------------------------------------------------------
# Compile the C++ Sources into Respective Objects
# Compile main.cc
echo "==============================================="
echo "--------- Compiling C++ Sources --------------"
g++ -c -nostdlib -nostdinc -fno-builtin -fno-stack-protector -ffreestanding -m32 -o main.o main.cc
mv main.o build
# Run scons to build the Entire Lbrary of C++ Files
cd include
rm *.o
scons
# Move all Object Files into Build Directory
cp *.o ../build
cd ..
echo "==============================================="
# ----------------------------------------------------------------------------------------------

# ----------------------------------------------------------------------------------------------
## When Everything is Finished Link together the Objects into a Kernel File
echo "==============================================="
echo "--------- Linking ----------------"
cd build
# require ld , link.ld
ld  -T '../link.ld' -m elf_i386 -o  kernel.jos *.o
# Clean Up After Build
#rm *.o
echo "==============================================="
# ----------------------------------------------------------------------------------------------

# ----------------------------------------------------------------------------------------------
## When Everything is Finished Run the Kernel
qemu-system-i386 -kernel kernel.jos
# -----------------------------------------------------------------------------------------

这是buildboot.sh

    # Builds the Boot files for JOS
# require 'nasm'

# Add all the Assembly Files Here
nasm -f elf -o boot.s.o boot.s
nasm -f elf -o gdt.s.o gdt.s
nasm -f elf -o idt.s.o idt.s
nasm -f elf -o interrupt.s.o interrupt.s

# Move the Entire Object Files into the Build Directory
mv *.o ../build

这是我 运行 脚本

时的终端输出
    ===============================================
-------- Building Boot Sectors ----------------
===============================================
===============================================
--------- Compiling C++ Sources --------------
In file included from include/system.h:22:0,
                 from main.cc:6:
include/idt.h:34:13: warning: ‘void init_idt()’ used but never defined
static void init_idt();
             ^
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o gdt.o -c -nostdlib -nostdinc -fno-builtin -fno-stack-protector -ffreestanding -m32 gdt.cc
g++ -o idt.o -c -nostdlib -nostdinc -fno-builtin -fno-stack-protector -ffreestanding -m32 idt.cc
g++ -o io.o -c -nostdlib -nostdinc -fno-builtin -fno-stack-protector -ffreestanding -m32 io.cc
g++ -o isr.o -c -nostdlib -nostdinc -fno-builtin -fno-stack-protector -ffreestanding -m32 isr.cc
g++ -o memory.o -c -nostdlib -nostdinc -fno-builtin -fno-stack-protector -ffreestanding -m32 memory.cc
g++ -o monitor.o -c -nostdlib -nostdinc -fno-builtin -fno-stack-protector -ffreestanding -m32 monitor.cc
g++ -o stdlib.o -c -nostdlib -nostdinc -fno-builtin -fno-stack-protector -ffreestanding -m32 stdlib.cc
scons: done building targets.
===============================================
===============================================
--------- Linking ----------------
gdt.o: In function `init_gdt()':
gdt.cc:(.text+0xb0): undefined reference to `gdt_flush(unsigned int)'
idt.o: In function `init_idt()':
idt.cc:(.text+0x3a): undefined reference to `isr0()'
idt.cc:(.text+0x51): undefined reference to `isr1()'
idt.cc:(.text+0x68): undefined reference to `isr2()'
idt.cc:(.text+0x7f): undefined reference to `isr3()'
idt.cc:(.text+0x96): undefined reference to `isr4()'
idt.cc:(.text+0xad): undefined reference to `isr5()'
idt.cc:(.text+0xc4): undefined reference to `isr6()'
idt.cc:(.text+0xdb): undefined reference to `isr7()'
idt.cc:(.text+0xf2): undefined reference to `isr8()'
idt.cc:(.text+0x109): undefined reference to `isr9()'
idt.cc:(.text+0x120): undefined reference to `isr10()'
idt.cc:(.text+0x137): undefined reference to `isr11()'
idt.cc:(.text+0x14e): undefined reference to `isr12()'
idt.cc:(.text+0x165): undefined reference to `isr13()'
idt.cc:(.text+0x17c): undefined reference to `isr14()'
idt.cc:(.text+0x193): undefined reference to `isr15()'
idt.cc:(.text+0x1aa): undefined reference to `isr16()'
idt.cc:(.text+0x1c1): undefined reference to `isr17()'
idt.cc:(.text+0x1d8): undefined reference to `isr18()'
idt.cc:(.text+0x1ef): undefined reference to `isr19()'
idt.cc:(.text+0x206): undefined reference to `isr20()'
idt.cc:(.text+0x21d): undefined reference to `isr21()'
idt.cc:(.text+0x234): undefined reference to `isr22()'
idt.cc:(.text+0x24b): undefined reference to `isr23()'
idt.cc:(.text+0x262): undefined reference to `isr24()'
idt.cc:(.text+0x279): undefined reference to `isr25()'
idt.cc:(.text+0x290): undefined reference to `isr26()'
idt.cc:(.text+0x2a7): undefined reference to `isr27()'
idt.cc:(.text+0x2be): undefined reference to `isr28()'
idt.cc:(.text+0x2d5): undefined reference to `isr29()'
idt.cc:(.text+0x2ec): undefined reference to `isr30()'
idt.cc:(.text+0x303): undefined reference to `isr31()'
idt.cc:(.text+0x323): undefined reference to `idt_flush(unsigned int)'
interrupt.s.o: In function `isr_common_stub':
interrupt.s:(.text+0x10d): undefined reference to `isr_handler'
main.o: In function `main':
main.cc:(.text+0x17): undefined reference to `init_idt()'
===============================================
qemu: could not load kernel 'kernel.jos': No such file or directory

谁能指出我做错了什么

这看起来像是一个 name mangling 问题。

您所遵循的指南是用 C 语言编写的,如果您的 IDT 代码是使用 GCC 而不是 G++ 编译的,那么它可能 可以工作。但是,如果您选择使用 C++,则需要进行一些更改以允许从 C++ 引用汇编程序函数,反之亦然。

C 和汇编程序中的函数名称直接映射到符号名称,但 C++ 默认情况下会向符号名称添加一些额外的文本以包含有关 类、名称空间、重载等的信息。

为确保您的 C++ 代码可以使用正确的符号名称引用汇编程序函数,您必须告诉编译器对这些函数使用 C 链接。

在您的 C++ 头文件中查找您声明在汇编程序中实现的函数的位置,例如:idt.hh 中的 isrN() 函数 .

像这样将这些声明包装在 C 链接块中:

extern "C" {

extern int isr0();
extern int isr1();
// ... and so on for all your ASM functions.

}

并对应可从汇编程序调用的 C++ 函数执行相同操作。