避免C程序中的主(入口点)

Kar*_*uru 17 c compiler-construction operating-system function entry-point

是否可以避免C程序中的入口点(主).在下面的代码中,是否可以在func()不通过main()以下程序调用via的情况下调用该调用?如果是,如何做,何时需要,为什么要给出这样的规定?

int func(void)
{
     printf("This is func \n");
     return 0;
}

int main(void)
{
     printf("This is main \n");
     return 0;
}
Run Code Online (Sandbox Code Playgroud)

Joe*_*ite 23

如果你正在使用gcc,我发现一个线程说你可以使用-e命令行参数指定一个不同的入口点; 所以你可以func用作你的入口点,这将留下main未使用的.

请注意,这实际上并不允许您调用另一个例程而不是main.取而代之的是,它可以让你调用另一个例程来代替_start,这是libc的启动程序-它一些设置,然后调用main.因此,如果执行此操作,您将丢失一些内置于运行时库中的初始化代码,其中可能包括解析命令行参数等内容.使用前请阅读此参数.

如果您正在使用其他编译器,则可能有也可能没有参数.


RBe*_*eig 16

当构建嵌入式系统固件直接从ROM运行时,我经常会避免命名入口点,main()以强调代码审查者代码的特殊性.在这些情况下,我提供了C运行时启动模块的自定义版本,因此很容易将其调用替换为main()其他名称,例如BootLoader().

我(或我的供应商)几乎总是必须在这些系统中自定义C运行时启动,因为RAM要求初始化代码才能开始正常运行并不罕见.例如,典型的DRAM芯片需要其控制硬件的惊人数量的配置,并且在它们有用之前通常需要大量(数千个总线时钟周期)延迟.在完成之前,甚至可能没有放置调用堆栈的位置,因此启动代码可能无法调用任何函数.即使RAM器件在上电时工作,也几乎总是有一些芯片选择硬件或一两个FPGA需要初始化才能让C运行时开始初始化.

当用C编写的程序加载并启动时,某些组件负责使main()存在的环境存在.在Unix,Linux,Windows和其他交互式环境中,大部分工作是加载程序的OS组件的自然结果.但是,即使在这些环境中,也需要进行一些初始化工作才能main()调用.如果代码实际上是C++,那么可能会有大量工作,包括为所有全局对象实例调用构造函数.

所有这些的细节由链接器及其配置和控制文件处理.链接器ld(1)有一个非常复杂的控制文件,它准确地告诉它在输出中包含哪些段,在什么地址以及以什么顺序包含.查找链接器控制文件,您隐式使用的工具链和读取它可能是有益的,链接器本身的参考手册和您的可执行文件必须遵循的ABI标准才能运行.

编辑:更直接地回答在更常见的背景下提出的问题:"你能打电话给foo而不是主?" 答案是"可能,但只是因为很棘手".

在Windows上,可执行文件和DLL的文件格式几乎相同.可以编写一个程序来加载在运行时命名的任意DLL,并在其中查找任意函数并调用它.一个这样的程序实际上作为标准Windows发行版的一部分提供:rundll32.exe.

由于.EXE文件可以由处理.DLL文件的相同API加载和检查,原则上如果.EXE具有命名该函数的EXPORTS部分foo,则可以编写类似的实用程序来加载和调用它.main当然,你不需要做任何特别的事情,因为这将是自然的切入点.当然,在实用程序中初始化的C运行时可能与可执行文件链接的C运行时不同.(Google为"DLL Hell"提示.)在这种情况下,您的实用程序可能需要更智能.例如,它可以充当调试器,以断点加载EXE main,运行到该断点,然后将PC更改为指向或进入foo并从那里继续.

因为.so文件在某些​​方面与真正的可执行文件类似,所以在Linux上可能存在某种类似的技巧.当然,可以使用像调试器一样的方法.


dmc*_*kee 5

根据经验,系统提供的加载器将始终运行main.有了足够的权威和能力,理论上你可以编写一个不同的加载器来做其他事情.