是什么原因导致 "x.asm:(.text+0xd): undefined reference to `y'"?

What causes "x.asm:(.text+0xd): undefined reference to `y'"?

很长一段时间我都没有使用 C 和汇编程序进行编程(大约 2 年)。现在我决定重新开始,但我想做一些更复杂的事情。我考虑过创建一个简单的内核。现在我在网上找到了这个源代码:

boot.asm:

global loader
extern kernel_main
MAGIC equ 0xbad
FLAGS equ 0x3
CHECKSUM equ -(MAGIC+FLAGS)

section .text
align 4
dd MAGIC
dd FLAGS
dd CHECKSUM

loader:
call kernel_main
cli

quit:
hlt
jmp quit

kernel.c:

void print(char *text) {
    char *memory = (char*)0xb8000;
    while(*text) {
        *memory++ = *text++;
        *memory++ = 0x3;
    }
}

void kernel_main() {
    print("My cat sometimes smells like cafe. I love it.");
}

linker.ld:

ENTRY(loader)
SECTIONS {
      . = 0x100000;
      .text : { *(.text) }
}

注意:我用 "GCC" 编译了 C 文件,用 "NASM" 编译了汇编文件。

如果我尝试这个命令:

ld -T linker.ld -elf_i386 -o final.bin boot.o kernel.o

上面写着:"boot.asm:(.text+0xd): undefined reference to `kernel_main'"。 我怎样才能解决这个问题? 我正在 windows 上工作,不想 运行 带有 Linux 或任何东西的虚拟机。提前致谢!

编辑: 这是我的 GCC 命令:

gcc -m32 -o kernel.o srckernel.c -nostdlib -nostartfiles -nodefaultlibs

这是我的 NASM 命令:

nasm -f elf32 -o boot.o boot.asm

有很多地方不对。我会假设错误:

boot.asm:(.text+0xd): undefined reference to kernel_main

您没有使用 ELF 交叉编译器,而是使用生成本机 Windows 可执行文件(即 Cygwin 和 MinGW)的 GCC 编译器。我强烈建议使用 i686(或 x86_64)ELF cross compiler 进行 OS 开发,尤其是 Windows.

您的主要问题是:

  • 选项 -elf_i386 可能是 -melf_i386 但这甚至是不正确的。对于目标为 windows 的 GCC,您需要使用 -mi386pe 输出为 Win32 PE/COFF 格式。 Windows GCC 链接器通常不知道如何生成 ELF 可执行文件。我还建议在使用 LD 输出 i386pe 格式时使用 -N 选项。将您的链接器命令更改为:

    ld -N -T linker.ld -mi386pe -o final.bin boot.o kernel.o
    
  • With Win32 PE/COFF objects1: 使用 CDECL 调用约定的函数必须有一个 underscore (_) prepended给他们。 kernel_main 需要 _kernel_main。您需要将 boot.asm 中的这些行更改为:

    extern kernel_main
    call kernel_main
    

    至:

    extern _kernel_main
    call _kernel_main
    
  • 你没有展示你如何编译 kernel.c 和你如何 assemble boot.asm 但它们看起来应该类似于:

    nasm -f win32 boot.asm -o boot.o
    gcc -g -c -m32 -ffreestanding kernel.c -o kernel.o
    
  • 当您设法生成 final.bin 时,它是一个 Windows PE 可执行文件。 Multiboot specification 需要 ELF 可执行文件。使用 LD 链接到 final.bin 后,您可以将 final.bin 转换为 ELF 格式:

    objcopy -O elf32-i386 final.bin final.elf
    

    final.elf 现在应该可以用作 Multiboot ELF 可执行文件。

  • boot.asm 中的多重启动 header 存在问题。 Multiboot 魔法值是 0x1badb002 而不是 0xbad。由于您没有在您的 Multiboot 中指定视频配置 header FLAGS 不应设置位 1,因此 FLAGS 应该是 0x1 而不是 0x3。将您的 Multiboot header 更改为:

    MAGIC equ 0xbad
    FLAGS equ 0x3
    

    至:

    MAGIC equ 0x1badb002
    FLAGS equ 0x1
    

通过上述更改,我能够生成一个名为 final.elf 的 ELF 可执行文件。当 运行 与 QEMU 使用命令时:

qemu-system-i386 -kernel final.elf

我得到的输出是:


脚注:

  • 1生成 Win64 PE32+ 时,函数名称上的额外下划线不适用 objects。