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

2024-02-09

我已经很长一段时间没有使用 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

内核.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.");
}

链接器.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 或其他任何东西的虚拟机。提前致谢!

编辑: 这是我的海湾合作委员会命令:

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

这是我的 NASM 命令:

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

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

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

您没有使用 ELF 交叉编译器,而是使用生成本机 Windows 可执行文件的 GCC 编译器(即 Cygwin 和 MinGW)。我强烈建议使用 i686(或 x86_64)ELF交叉编译器 https://wiki.osdev.org/GCC_Cross-Compiler#Windows_Users用于操作系统开发,尤其是 Windows 上的操作系统开发。

您的主要问题是:

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

    ld -N -T linker.ld -mi386pe -o final.bin boot.o kernel.o
    
  • With Win32 PE/COFF objects1: functions that use the CDECL calling convention have to have an underscore (_) prepended https://devblogs.microsoft.com/oldnewthing/20040108-00/?p=41163 to them. kernel_main needs to be _kernel_main. You need to change these lines in boot.asm from:

    extern kernel_main
    call kernel_main
    

    to:

    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 可执行文件。这多重启动规范 https://www.gnu.org/software/grub/manual/multiboot/multiboot.html需要 ELF 可执行文件。链接到后final.bin使用LD,您可以转换final.bin转换为 ELF 格式:

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

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

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

    MAGIC equ 0xbad
    FLAGS equ 0x3
    

    to:

    MAGIC equ 0x1badb002
    FLAGS equ 0x1
    

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

qemu-system-i386 -kernel final.elf

我得到的输出是:


脚注:

  • 1The extra underscore on function names doesn't apply when generating Win64 PE32+ objects.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • 如何让c代码执行hex机器代码?

    我想要一个简单的 C 方法能够在 Linux 64 位机器上运行十六进制字节码 这是我的 C 程序 char code x48 x31 xc0 include
  • 如何为单个函数设置 ICC 属性“fp-model precision”,以防止关联优化?

    我正在实施卡汉求和 http en wikipedia org wiki Kahan summation algorithm 在支持 gcc47 gcc48 clang33 icc13 和 icc14 编译的项目中 作为该算法的一部分 我想
  • 使用动态链接器包装 glibc 函数

    我正在尝试包装 GLIBCfstat通过将我的库注入可执行文件来实现函数 可以是任何其他 这只是概念证明 我通过将我的库放置在可执行文件的位置来做到这一点RPATH用名字指着libc so 6 我的库的源代码如下 define GNU SO
  • 如何使用 #pragma 在 G++ 中启用优化

    我想在没有命令行参数的情况下启用 g 优化 我知道 GCC 可以通过写来做到这一点 pragma GCC optimize 2 在我的代码中 但它似乎在 G 中不起作用 此页面可能有帮助 http gcc gnu org onlinedoc
  • 列出 C 常量/宏

    有没有办法使GNU C 预处理器 cpp 或其他一些工具 列出给定点上的所有可用宏及其值C file 我正在寻找特定于系统的宏 同时移植一个已经精通 UNIX 的程序并加载一堆稀疏的 UNIX 系统文件 只是想知道是否有比寻找定义更简单的方
  • CALL指令是否总是将EIP指向的地址压入堆栈?

    x86架构中函数调用时是否存在返回地址不入栈的情况 No CALL根据定义 将在跳转到目标地址之前将返回地址压入堆栈 该返回地址是EIP or RIP sizeof call instruction 通常为 5 个字节 英特尔 64 和 I
  • 为什么 Solaris 汇编器生成的机器代码与 GNU 汇编器在这里不同?

    我为 amd64 编写了这个小汇编文件 对于这个问题来说 代码的作用并不重要 globl fib fib mov edi ecx xor eax eax jrcxz 1f lea 1 rax ebx 0 add rbx rax xchg r
  • GCC 4.7 字符串文字的源字符编码和执行字符编码?

    Linux x86 64 上的 GCC 4 7 是否具有默认字符编码 用于验证和解码 C 源文件中字符串文字的内容 这是可配置的吗 此外 当将字符串数据从字符串文字链接到输出的数据部分时 它是否具有默认的执行字符编码 这是可配置的吗 在任何
  • 在 x86 Intel VT-X 非根模式下,是否可以在每个指令边界传递中断?

    除了不将中断传送到虚拟处理器的某些正常指定条件 cli if 0 等 之外 客户机中的所有指令实际上都是可中断的吗 也就是说 当传入的硬件中断先传递给 LAPIC 然后传递给处理器时 据说会发生一些内部魔法 将其转换为虚拟中断给来宾 使用虚
  • 奇怪的 MSC 8.0 错误:“ESP 的值未在函数调用中正确保存...”

    我们最近尝试将一些 Visual Studio 项目分解为库 并且在测试项目中一切似乎都编译和构建得很好 其中一个库项目作为依赖项 然而 尝试运行该应用程序给我们带来了以下令人讨厌的运行时错误消息 运行时检查失败 0 ESP 的值未在函数调
  • 为什么 Visual Studio 使用 xchg ax,ax

    我正在查看程序的反汇编 因为它崩溃了 并注意到很多 xchg ax ax 我用谷歌搜索了一下 发现它本质上是一个 nop 但是为什么 Visual Studio 会执行 xchg 而不是 noop 该应用程序是一个C NET3 5 64位应
  • 尝试使用 x86 程序集 GNU GAS 在数组索引处赋值时出现错误

    我在用x86GNU 与 GCC 的程序集 并尝试实现相当于以下内容的程序集c c int x 10 x 0 5 但是 当我尝试运行 使用命令 a out 我的汇编代码如下 第一次编译后gcc filename s 错误Segmentatio
  • 利用 SSE 和其他 CPU 扩展

    在我的代码库中有几个地方 对于大型数据集 相同的操作会重复很多次 在某些情况下 处理这些需要花费相当长的时间 我相信使用SSE来实现这些循环应该可以显着提高它们的性能 特别是在对同一组数据执行许多操作的情况下 因此一旦数据最初被读入缓存 就
  • 使用 AVX 内在函数代替 SSE 并不能提高速度 - 为什么?

    我已经使用 Intel 的 SSE 内在函数相当长一段时间了 并取得了良好的性能提升 因此 我希望 AVX 内在函数能够进一步加速我的程序 不幸的是 直到现在情况并非如此 可能我犯了一个愚蠢的错误 所以如果有人能帮助我 我将非常感激 我使用
  • 在 x86 ASM 中测试零通常哪个更快:“TEST EAX, EAX”与“TEST AL, AL”?

    测试 AL 中的字节是否为零 非零通常哪个更快 TEST EAX EAX TEST AL AL 假设之前有一个 MOVZX EAX BYTE PTR ESP 4 指令加载了一个带有零扩展的字节参数到 EAX 的其余部分 防止了我已经知道的组
  • Nasm 打印到下一行

    我用 nasm Assembly 编写了以下程序 section text global start start Input variables mov edx inLen mov ecx inMsg mov ebx 1 mov eax 4
  • GCC 对潜在有效的代码抛出 init-list-lifetime 警告?

    我在 Debian不稳定的GCC 9 3 0上运行 我从事的一个项目最近发生了变化 引入了类似于下面的代码 include
  • 为什么 -march=native 很少使用?

    对于大多数 C C 编译器 有一个可传递给编译器的标志 march native 它告诉编译器调整为主机 CPU 的微架构和 ISA 扩展生成的代码 即使它的名称不同 基于 LLVM 的编译器通常也有一个等效的选项 例如rustc or s
  • 如何在编译C代码时禁用警告?

    我正在使用 32 位 Fedora 14 系统 我正在使用编译我的源代码gcc 有谁知道如何在编译c代码时禁用警告 EDIT 是的 我知道 最好的办法是修复这些警告以避免任何未定义 未知的行为 但目前在这里 我第一次编写了巨大的代码 并且在
  • 有没有办法使用 i387 fsqrt 指令获得正确的舍入?

    有没有办法使用 i387 fsqrt 指令获得正确的舍入 除了改变精确模式在 x87 控制字中 我知道这是可能的 但这不是一个合理的解决方案 因为它存在令人讨厌的重入型问题 如果 sqrt 操作中断 精度模式将出错 我正在处理的问题如下 x

随机推荐