【问题标题】:Make a simple CRT0 in C or assembly用 C 或汇编制作一个简单的 CRT0
【发布时间】:2013-02-23 16:42:20
【问题描述】:

我又回到了 C/C++ 和 ASM,我想玩一点火。我发现,当您将代码编译并链接到 Windows 的可执行文件中时,它会动态链接到一些库,这些库必须存在于预期运行该应用程序的任何计算机上。您可以指定编译器不链接它们并为此创建自己的库。

除此之外(如果我在这里所说的一切都错了,请纠正我)还有一个目标文件,它始终与我们应用程序的主代码一起编译和链接。它是 crt0.o(C 运行时)文件,据我所知,它准备堆栈,获取 argc 和 argv 并调用 main 函数(可能还有其他东西)。我也相信它是系统在执行应用程序时调用的第一段代码。

所以,我正在尝试创建一个简单的 crt0.obj 并将其链接到一个简单的 C++ 目标文件

int main(int argc, char** argv) {
    return 0; 
}

我使用 GCC,但我不想使用任何标准库,所以我的命令如下所示:

g++ -s -nostartfiles -nodefaultlibs -nostdlib testapp.cpp -o test.exe crt0.o

我想 -nostartfiles 指令告诉链接器不要嵌入默认的 crt0.o,因此它希望我为任何函数提供每个定义并处理应用。我在这里有点困惑。

无论如何,我想创建一个非常基本的 crt0 目标文件,它足以让 GCC 创建我的可执行文件,并让系统启动它。我知道 Internet 上有很多代码文件(C 和 ASM),但我想编写自己的代码文件以了解它是如何工作的。我需要的不仅仅是代码,而是关于它必须做什么以及如何编译/链接以实现它的一点帮助。 如果您知道任何有用的链接,也非常感谢。

我的疑问是:
1.编译器/链接如何从我的代码和 C 运行时创建最终文件?我是否必须从 crt0.o 调用 main 函数(使用 extern 指令)?当我执行g++ -s -nostartfiles -nodefaultlibs -nostdlib testapp.cpp -o test.exe 时,我得到“* undefined reference to __main*”错误。在crt0.o文件中定义了main函数吗?奇怪的是,如果我将int main 更改为int start,我没有收到任何错误。这是什么意思?
2. crt0 必须包含哪些基本操作(例如获取命令行参数、调用 main)?
3. 我的代码文件是 CPP,crt0 是 C 文件中的一个程序集(用 GCC 编译)。我将发布一些我设法从我发现并部分理解的片段中创建的“frankencode”:

// crt0.c
__asm(".section .text\n" 
".global _start\n"
"_start:\n"
"mov $0, %ebp\n"
"push %ebp\n"
"mov %esp, %ebp\n"
"push %esi\n"
"push %edi\n"
"call _init\n"
"pop %edi\n"
"pop %esi\n"
"call main\n"
"movl %eax, %edi\n"
"call exit\n"
".section .init\n"
".global _init\n"
"_init:\n"
"push %ebp\n"
"mov %esp, %ebp\n"
".section .fini\n"
".global _fini\n"
"_fini:\n"
"push %ebp\n"
"mov %esp, %ebp\n");

4.) 所以,在这个文件中,我调用了一些初始化函数。 init 和 fini 函数已经创建(它们看起来像简单的构造函数和析构函数,我不知道)还有 main 函数,我不知道它与 .cpp main 函数有什么关系。我的意思是,我应该导入它吗?主函数和退出函数都出现undefined reference 错误。
5.) c0 必须具有特定格式或包含特定函数以便系统找到它的开始吗?

嗯,我认为制作一个小的 crt0 并让编译器将其附加到可执行文件并不难,但有些东西我无法正确看到。我希望有人可以帮助我将所有这些组合在一起。谢谢

【问题讨论】:

  • 您的实际目标是什么?
  • 在 C 中创建一个简单的 crt0,将其链接到一个 C++ 文件并让该文件只运行该文件。
  • 是的,但是您是否期望能够执行cout << "hello world!\n"、调用rand()、调用new/delete 或使用具有静态存储持续时间的对象等?这些都是启动时准备的东西。
  • 不,只是为了能够运行main函数,没有别的。

标签: c++ assembly runtime crt


【解决方案1】:

我没有要测试的 Windows 机器,但这应该是您需要的基本位:

#// crt0.c
__asm(".section .text\n" 
".global _start\n"
"_start:\n"
"mov $0, %ebp\n"
"push %ebp\n"
"mov %esp, %ebp\n"
"call main\n"
"pop  %ebp\n"
"ret\n");

编辑:空__main:

__asm(".global __main\n"
      "__main:\n" 
      "ret\n");

【讨论】:

  • 是的,但是当我编译包含 main 函数的 cpp 时,我得到“未定义的 __main 引用”。所以,我不知道如何让编译器知道在哪里可以找到我从这段代码中调用的 main。
  • 如果你拆解你的main.o,它是否会调用__main?我认为 MingW 这样做是为了调用一些构造函数和类似的东西。在这种情况下,您必须添加我在上面编辑过的代码 [cmets 中的代码变成糊状...]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-22
  • 2015-08-24
相关资源
最近更新 更多