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

是否有可能避免C程序中的入口点(main)。 在下面的代码中,是否可以在不通过main()调用下面的程序的情况下调用func()调用? 如果是,如何去做,什么时候需要,为什么会有这样的规定?

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

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

如果你使用的是gcc,我发现一个线程说你可以使用-e命令行参数来指定一个不同的入口点; 所以你可以使用func作为你的入口点,这会使main未使用。

请注意,这实际上并不允许您调用其他例程而不是main 。 相反,它可以让你调用另一个例程而不是_start ,这是libc的启动例程 - 它执行一些设置,然后调用main 。 所以如果你这样做,你会失去一些内置到你的运行时库中的初始化代码,这可能包括诸如解析命令行参数之类的东西。 在使用之前阅读此参数。

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


当构建嵌入式系统固件直接从ROM运行时,我经常会避免指定入口点main()来强调代码审阅者代码的特殊性质。 在这些情况下,我提供了一个定制版本的C运行时启动模块,因此使用BootLoader()等其他名称很容易将其调用替换为main() BootLoader()

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

当用C编写的程序加载并启动时,某个组件负责创建调用main()的环境。 在Unix,Linux,Windows和其他交互式环境中,大部分努力是加载程序的OS组件的自然结果。 但是,即使在这些环境中, main()可以被调用之前也有一些初始化工作要做。 如果代码真的是C ++,那么可以进行大量的工作,包括调用所有全局对象实例的构造函数。

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

编辑:为了更直接地回答在更常见的上下文中提出的问题:“你可以调用foo而不是主要吗?” 答案是“也许,但是只能是棘手的”。

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

由于.EXE文件可以通过处理.DLL文件的相同API来加载和检查,因此原则上如果.EXE具有名称为foo的EXPORTS部分,则可以编写一个类似的实用程序来加载和调用它。 当然,你不需要对main做任何特殊的事情,因为这将是自然的切入点。 当然,在您的实用程序中初始化的C运行时可能不是与您的可执行文件链接的C运行时。 (谷歌的“DLL地狱”提示。)在这种情况下,你的工具可能需要更聪明。 例如,它可以作为一个调试器,在main处加载一个中断点,运行到该中断点,然后将PC指向或指向foo并从那里继续。

某些类似的欺骗可能在Linux上是可能的,因为.so文件在某些​​方面也与真正的可执行文件类似。 当然,像调试器一样行事的方法可以起作用。


经验法则是系统提供的加载程序将始终运行main。 如果拥有足够的权限和能力,你理论上可以编写一个不同的装载程序来做其他事情

链接地址: http://www.djcxy.com/p/86327.html

上一篇: Avoiding the main (entry point) in a C program

下一篇: C++ Header files and compilation process