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

时间:2018-06-29 21:15:56

标签: c++ clang mach-o

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

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

编辑:

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

P.S我正在Mac OS X High Sierra中使用9.1.0版创建可执行文件

3 个答案:

答案 0 :(得分:4)

您可以使用ld的-e <symbol>选项,可以从clang中以-Wl,-e,_<symbol>的身份调用。从历史上看,程序的入口点是来自crt0.o的_start,但是自Mac OS X 10.8和iOS 6.0引入LC_MAIN load命令以来,这在Darwin上就不存在了(替换LC_UNIXTHREAD)。仍然可以使用“旧”方式,但是必须使用-no_new_main链接器标志(如果需要,可以使用对应的-new_main)显式启用它。由crt0.o承担的职责已转移到动态链接程序/usr/lib/dyld,该链接程序可以根据需要处理LC_MAINLC_UNIXTHREAD

给定一个带有main的C程序:

// 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

答案 1 :(得分:3)

您可以将-e <symbol name>选项传递给链接器(ld),以指定其他入口点。默认入口点不是mainstart由crt1.o提供,并依次调用main

答案 2 :(得分:1)

您可以使用_start()

它设置一些东西,填充参数数组argv,计算那里有多少参数,然后调用mainmain返回后,将调用exit

以下是一些参考:
https://stackoverflow.com/a/29694977/2302572
http://learningpearls.blogspot.com/2011/02/start-function-inside-c.html