如何更改 c++ 文件的 mach-o 可执行文件的入口点?

How can I change entry point for a mach-o executable for a c++ file?

我正在尝试编写一个没有 main 的 c++ 程序。是否可以将 mach-o 可执行文件的入口点更改为自定义函数(main() 除外)?

如果不是,那么,是否可以在调用实际 C main 之前包装 main 来调用我的 main 版本?

编辑:

我想让我的自定义函数调用 C main。如果我给它一个构造函数属性或将它添加到 ctor 列表中,那么 main 将被调用两次。我不希望这种情况发生。

P.S 我正在 Mac OS X High Sierra 中使用 clang 版本 9.1.0

构建可执行文件

您可以使用_start()

它设置一些东西,填充参数数组 argv,计算那里有多少个参数,然后调用 main。在mainreturns之后调用exit

这里有一些参考资料:

http://learningpearls.blogspot.com/2011/02/start-function-inside-c.html

您可以将 -e <symbol name> 选项传递给链接器 (ld) 以指定不同的入口点。默认入口点不是main;它是由 crt1.o 提供的 start,然后调用 main.

您可以使用 ld 的 -e <symbol> 选项,您可以将其作为 -Wl,-e,_<symbol> 从 clang 中调用。从历史上看,程序的入口点是 crt0.o 中的 _start,但是自从 Mac OS X 10.8 和 iOS 以来,这在达尔文上就不是一回事了6.0,其中引入了 LC_MAIN 加载命令(替换 LC_UNIXTHREAD)。 "old" 方式仍然可以使用,但必须使用 -no_new_main 链接器标志显式启用(它有对应的 -new_main,如果您需要的话)。曾经由 crt0.o 承担的职责已转移到动态链接器 /usr/lib/dyld,它可以根据需要处理 LC_MAINLC_UNIXTHREAD

所以给定一个 C 程序 main:

// t.c
#include <stdio.h>

int main(int argc, const char **argv)
{
    printf("test %i\n", argc);
    return 0;
}

您可以像这样轻松创建 C++ 文件:

// t.cpp

extern int main(int, const char**);

extern "C" int derp(int argc, const char **argv)
{
    return main(0, (const char*[]){ (const char*)0 });
}

并用clang++ -o t t.cpp -xc t.c -Wl,-e,_derp编译它们。
请务必将 derp 声明为 extern "C",或在命令行中指定损坏的符号。

您还可以使用 otool 检查生成的可执行文件,以确保它使用 LC_MAIN 而不是 LC_UNIXTHREAD:

bash$ otool -l ./t | fgrep -B1 -A3 LC_MAIN
Load command 11
       cmd LC_MAIN
   cmdsize 24
  entryoff 3808
 stacksize 0