是什么原因导致 "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。
很长一段时间我都没有使用 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
和你如何 assembleboot.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 中指定视频配置 headerFLAGS
不应设置位 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。