【问题标题】:What causes "x.asm:(.text+0xd): undefined reference to `y'"?是什么导致“x.asm:(.text+0xd): undefined reference to 'y'”?
【发布时间】:2019-12-07 23:56:26
【问题描述】:

很长一段时间我都没有使用 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”编译了 Assembler 文件。

如果我尝试这个命令:

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

它说:“boot.asm:(.text+0xd): undefined reference to `kernel_main'”。 我怎样才能解决这个问题? 我在 Windows 上工作,不想用 Linux 或任何东西运行 VM。提前致谢!

编辑: 这是我的 GCC 命令:

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

这是我的 NASM 命令:

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

【问题讨论】:

  • -elf_i386 应该是 -melf_i386 如果有的话。还显示gccnasm 命令行。请注意,mingw gcc 可能会在符号前添加前导下划线,因此您可能需要 extern _kernel_maincall _kernel_main

标签: gcc assembly x86 nasm osdev


【解决方案1】:

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

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

您没有使用 ELF 交叉编译器,并且您使用的是生成本机 Windows 可执行文件(即 Cygwin 和 MinGW)的 GCC 编译器。我强烈建议使用 i686(或 x86_64)ELF cross compiler 进行操作系统开发,尤其是在 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
    
  • 对于 Win32 PE/COFF 对象1:使用 CDECL 调用约定的函数必须具有underscore (_) prependedkernel_main 必须是 _kernel_main。您需要将boot.asm 中的这些行从:

    extern kernel_main
    call kernel_main
    

    到:

    extern _kernel_main
    call _kernel_main
    
  • 您没有展示如何编译 kernel.c 以及如何组装 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 现在应该可以用作多重引导 ELF 可执行文件了。

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

    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+ 对象时,函数名称上的额外下划线不适用。

【讨论】:

  • 谢谢!这就是我所期望的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-05
  • 2011-02-15
  • 1970-01-01
相关资源
最近更新 更多