【问题标题】:execute a C++ procedure in an asm file using linker "ld"使用链接器“ld”在 asm 文件中执行 C++ 过程
【发布时间】:2019-07-27 01:46:59
【问题描述】:

我从系统编程开始,但是我遇到了一个小僵局。 我不知道如何使用 NASM 和 g++ 编译器在 asm 文件中运行 cpp 过程。

这是我的文件 kernel.asm:

[BITS 32]

EXTERN scrollup, print
global _start

_start :
    mov ax , msggdt
    push ax
    call print
    pop ax

    mov ax , msggdt32
    push ax
    call print
    pop ax

    mov ax , 3
    push ax
    call scrollup
    pop ax



end:
    jmp end

msggdt : db "Load gdt",13 , 10,0
msggdt32 : db "Load protected mode",13,10,0

我的 cpp 文件包含函数 printscrollup

我的编译器是:NASM 2.14 版和 gcc 8.2.0 版(Debian 8.2.0-21)

g++ -c screen.cpp
screen.cpp: In function ‘void _putcar_(uchar)’:
screen.cpp:63:59: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
   video = (unsigned char*) (RAMSCREEN + 2 * kX + 160 * kY ) ;

nasm -f elf64 -o kernel.o kernel.asm

您可能注意到了,我尝试调用ld 4 次——不仅要更改对象的顺序,还要更改输出。但是,没有任何效果。

ld --oformat binary -Ttext 1000 screen.o kernel.o  -o screen
ld: kernel.o: in function `_start':
kernel.asm:(.text+0x7): undefined reference to `print'
ld: kernel.asm:(.text+0x14): undefined reference to `print'
ld: kernel.asm:(.text+0x21): undefined reference to `scrollup'


ld --oformat binary -Ttext 1000 screen.o kernel.o  -o kernel
ld: kernel.o: in function `_start':
kernel.asm:(.text+0x7): undefined reference to `print'
ld: kernel.asm:(.text+0x14): undefined reference to `print'
ld: kernel.asm:(.text+0x21): undefined reference to `scrollup'

ld --oformat binary -Ttext 1000 kernel.o  screen.o -o kernel
ld: kernel.o: in function `_start':
kernel.asm:(.text+0x7): undefined reference to `print'
ld: kernel.asm:(.text+0x14): undefined reference to `print'
ld: kernel.asm:(.text+0x21): undefined reference to `scrollup'

ld --oformat binary -Ttext 1000 kernel.o  screen.o -o screen
ld: kernel.o: in function `_start':
kernel.asm:(.text+0x7): undefined reference to `print'
ld: kernel.asm:(.text+0x14): undefined reference to `print'
ld: kernel.asm:(.text+0x21): undefined reference to `scrollup'

【问题讨论】:

  • 在您的 C++ 文件中,将从程序集调用的函数调用需要定义为 extern "C" 以删除名称重整。由于您是在 Linux 上构建的,这意味着您很可能会生成 ELF 对象。你的 C++ 函数不应该有一个前导下划线(如果你在 MacOS 或本机 Windows 上会有所不同)。因为这不是 minimal reproducible example,所以很难说出你的 C++ 代码是什么样的(我必须根据一些错误猜测)
  • 支持迈克尔。您可以使用 readelf 查看损坏的名称。还要注意整个事情的位数:我看到了 16、32 和 64 位的使用/格式。此外,不要忽略警告,尤其是在构建操作系统时。最后,您似乎正在使用 C++,但像 C 一样编程,请考虑切换到后者(可能更容易处理)。
  • Margaret 是正确的。鉴于有关 GDT 的评论以及您正在使用 -f elf64 进行汇编的事实,您似乎正在尝试创建 64 位可执行文件,您可以使用 @ 指定 32 位汇编代码生成987654329@,但您的代码似乎是实模式。除非您知道自己在做什么,否则这将走向一个痛苦的世界,因为 GCC 对生成可以在 16 位模式下运行的代码的支持非常缺乏(这是一个严重的hack) 即使使用-m16 GCC 选项。
  • 我建议使用 GRUB/Multiboot 并且不要创建自己的自定义引导加载程序。然后你需要决定你是在写 64 位操作系统还是 32 位操作系统。

标签: c++ g++ x86-64 nasm osdev


【解决方案1】:

我可以做链接。但是,我使用了:

gcc -c screen.c
nasm -f elf64 -o kernel.o kernel.asm

所以我必须有一个 c 文件而不是 c ++ .. 我不明白为什么。 有人可以向我解释为什么它有效吗?

【讨论】:

  • 正如 cmets 中提到的,这是因为 C++ 在函数声明上做了name mangling
  • 非常感谢@MichaelPetch。确实,我的目标是使用 gdt 在保护模式下编译我的内核代码。顺便说一句,我编译了我的 32 位格式代码,但是对于我的 c 文件,我不知道如何编译 32 位格式。另外,我预计当我要使用ld时,会出现一个错误,它与我的i386架构不兼容:x86-64 总之,希望这是真正的问题:如何编译我的32位c文件使用我的保护模式?在 ld 上使用哪些参数来链接我的两个生成的目标文件?
  • 您的 16 位引导加载程序必须使用 -f bin 构建,我假设您已经这样做了。如果你正在构建一个 32 位内核,任何与你的内核相关的 .asm 文件都需要使用 -felf32(而不是 -f elf64)。您还需要使用选项 -m32 编译所有 C 文件(如果您没有使用看起来不是的交叉编译器)。如果与 LD 链接,则需要使用 -melf_i386
  • 我的最后一条评论也在我的另一个 Stackoverflow answers未定义行为的可能原因 部分中进行了讨论
  • @MichaelPetch 通过接受以其他方式编译,并且就我想创建自己的引导而言,我想知道原因,当我启动时,它不显示在核心。这是 gdt 的错误配置吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-20
  • 2021-07-12
  • 2013-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多