是什么原因导致“x.asm:(.text+0xd): 对‘y’的未定义引用”?

Leo*_*cat 4 x86 assembly gcc nasm osdev

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

启动.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
Run Code Online (Sandbox Code Playgroud)

内核.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.");
}
Run Code Online (Sandbox Code Playgroud)

链接器.ld:

ENTRY(loader)
SECTIONS {
      . = 0x100000;
      .text : { *(.text) }
}
Run Code Online (Sandbox Code Playgroud)

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

如果我尝试这个命令:

ld -T linker.ld -elf_i386 -o final.bin boot.o kernel.o
Run Code Online (Sandbox Code Playgroud)

它说:“boot.asm:(.text+0xd): 对‘kernel_main’的未定义引用”。我怎样才能解决这个问题?我在 Windows 上工作,不想运行带有 Linux 或其他任何东西的虚拟机。提前致谢!

编辑:这是我的 GCC 命令:

gcc -m32 -o kernel.o srckernel.c -nostdlib -nostartfiles -nodefaultlibs
Run Code Online (Sandbox Code Playgroud)

这是我的 NASM 命令:

nasm -f elf32 -o boot.o boot.asm
Run Code Online (Sandbox Code Playgroud)

Mic*_*tch 5

有很多事情是错误的。我假设给出错误:

boot.asm:(.text+0xd): 未定义的引用kernel_main

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

您的主要问题是:

  • 该选项-elf_i386可能本来就是这样的,-melf_i386但实际上是不正确的。对于面向 Windows 的 GCC,您将需要使用-mi386peWin32 PE/COFF 格式输出。Windows GCC 链接器通常不知道如何生成 ELF 可执行文件。-N我还建议在使用 LD 输出 i386pe 格式时使用该选项。将链接器命令更改为:

    ld -N -T linker.ld -mi386pe -o final.bin boot.o kernel.o
    
    Run Code Online (Sandbox Code Playgroud)
  • 对于 Win32 PE/COFF 对象1:使用 CDECL 调用约定的函数必须在其前面添加下划线 ( _)kernel_main需要是_kernel_main。您需要将这些行更改为boot.asm

    extern kernel_main
    call kernel_main
    
    Run Code Online (Sandbox Code Playgroud)

    到:

    extern _kernel_main
    call _kernel_main
    
    Run Code Online (Sandbox Code Playgroud)
  • 您没有展示如何编译kernel.c和如何组装boot.asm,但它们应该类似于:

    nasm -f win32 boot.asm -o boot.o
    gcc -g -c -m32 -ffreestanding kernel.c -o kernel.o
    
    Run Code Online (Sandbox Code Playgroud)
  • 当您设法生成它时final.bin,它是一个 Windows PE 可执行文件。多重引导规范需要ELF 可执行文件。final.bin使用LD链接后,您可以final.bin使用以下命令转换为 ELF 格式:

    objcopy -O elf32-i386 final.bin final.elf
    
    Run Code Online (Sandbox Code Playgroud)

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

  • 您的 Multiboot 标头存在问题boot.asm。Multiboot 的魔力值0x1badb002不是0xbad。由于您尚未在 Multiboot 标头中指定视频配置,FLAGS因此不应设置位 1,FLAGS应为 0x1 而不是 0x3。将您的多重引导标头更改为:

    MAGIC equ 0xbad
    FLAGS equ 0x3
    
    Run Code Online (Sandbox Code Playgroud)

    到:

    MAGIC equ 0x1badb002
    FLAGS equ 0x1
    
    Run Code Online (Sandbox Code Playgroud)

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

qemu-system-i386 -kernel final.elf
Run Code Online (Sandbox Code Playgroud)

我得到的输出是:

在此输入图像描述


脚注:

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