【问题标题】:Linkage of standard libraries in C++ code called from ASM从 ASM 调用的 C++ 代码中标准库的链接
【发布时间】:2018-09-27 23:56:00
【问题描述】:

当我正在开发我的“OsDev”项目时,我正在学习新东西(对于由于 Web 开发而长期没有使用 C/C++ 编写代码的人来说,这有点“新”)。我在另一个线程中发现,从 ASM 调用 C++ 函数需要有一个 extern "C" 前缀,但现在我对标准库的衬里有问题,例如 cstdio 等。我坚持这条消息。

kc.o: In function `kmain':
kernel.cpp:(.text+0x3e4): undefined reference to `strlen`

C++

#include <string.h>
#include <cstdio>

#include "inc/screen.h"

extern "C" void kmain()
{
    clearScreen();
    kernel_print((char*)"Hello Github! :-)", 0x04);
}

如果我尝试使用strlen(),它将无法链接。 (顺便说一句。包括screen.h 出于某种原因正在工作)。 编译脚本

nasm -f elf32 kernel.asm -o kasm.o
g++ -c kernel.cpp -o kc.o -lgcc -m32  -Wall -Wextra -O2
ld -m elf_i386 -T link.ld -o kernel.bin kasm.o kc.o

link.ld

OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
SECTIONS
 {
   . = 0x100000;
   .text : { *(.text) }
   .data : { *(.data) }
   .bss  : { *(.bss)  }
 }

感谢您的任何建议。 :)

【问题讨论】:

  • "从 ASM 调用 C++ 函数需要有一个 extern "C" 前缀" - 不,它没有。通过确保 C 调用约定和没有 C++ 名称修饰,它确实使事情变得更容易,但是这里没有 requirement。你可以(原则上)从 asm 调用 any 函数——不管是什么语言——这可能并不容易——而且你需要知道你在做什么(根据我的经验;最大的障碍)。
  • 哦,好的。我刚刚在某处读到(关于名称修饰),并将其命名为“更简单”。总之,我猜它并没有解决我的链接问题。所以.. :/
  • 确保静态链接 libc。即使那样,也绝对不能保证哪些部件可以在您的玩具操作系统中运行。 strlen 如果你能走到那一步,可能会。 -lgcc 看起来也很可疑,您的链接器脚本也是如此(例如,它似乎没有复制 .rodata
  • 我认为-lgcc 在您的gcc -c 命令行中被忽略,因为您只是在创建.o,而不是链接。它不会创建部分链接的目标文件(因为这不是一个东西),它也不会静态地合并到静态库中的某些代码中。 将您需要的库放在您的ld 命令行中
  • @Jester:嗯,glibc strlen 可能会使用 SSE2 而无需检查。在这种情况下How do I enable SSE for my freestanding bootable code? 但也许你从静态链接 32 位 glibc 获得的版本不会。

标签: c++ assembly linker-errors osdev


【解决方案1】:

您的代码无法工作,因为内核不能直接使用共享库。

为什么我不能直接在我的内核中使用共享库?

当操作系统加载应用程序时,所有需要的文件都被带入其地址空间。这包括可执行文件和任何动态库(所有符合 ABI 的 ELF 应用程序将始终与系统库 - C 标准库或只是 libc 链接)。

但是在加载内核时,只加载了原始的可执行文件。 Multiboot 2(带有 GRUB 引导加载程序)将允许您加载可以是动态库的 kernel-modules。但是,您的内核必须知道如何将自己和物理内存中的内核模块链接起来。为此,您必须在内核中实现 ELF 解析器和动态链接器。

在实现之前,请确保您的内核足够成熟,可以系统地处理动态内存分配、分页和其他基本功能。

如何使用 libc 的美妙功能?

通常,您不会使用 libc 的所有用户空间功能。但是像memcpystrlenstrcpyn 之类的东西是绝对必要的。您必须自己实现这些功能,但更好的是,您可以更改这些功能的名称。例如,如果你喜欢camelCase作为函数名,那么你也可以使用copyMemorylengthOfString等函数名。

https://github.com/SukantPal/Silcos-Kernel

我已经构建了自己的内核,它在 KernelHost/Source/Util/CircuitPrimitive.cpp 中有一些所需功能的实现。你可以调查一下。此外,它还有一个成熟的模块链接器。 (KernelHost、ModuleFramework 等这些父文件夹包含单独的内核模块源代码)。

确保不要在你的内核中使用标准的 C 头文件,就像现在一样。自行实现所有必需的功能,包括printf

【讨论】:

    猜你喜欢
    • 2016-02-16
    • 1970-01-01
    • 1970-01-01
    • 2011-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-19
    相关资源
    最近更新 更多