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

时间:2019-07-30 14:37:27

标签: gcc assembly x86 nasm osdev

很长一段时间我都没有使用C和Assembler编程(大约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):对`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

1 个答案:

答案 0 :(得分:4)

有很多错误。我会假设给出错误:

  

boot.asm :(。text + 0xd):对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
    
  • 使用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现在应该可以用作Multiboot ELF可执行文件。

  • boot.asm中的Multiboot标头存在问题。 Multiboot魔术值是0x1badb002而不是0xbad。由于尚未在Multiboot标头FLAGS中指定视频配置,因此不应该设置Bit 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

我得到的输出是:

enter image description here


脚注:

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