如何更改 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
。在main
returns之后调用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_MAIN
和 LC_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
我正在尝试编写一个没有 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
。在main
returns之后调用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_MAIN
和 LC_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