I am trying to write a c++ program without main. Is it possible to change the entry point of a mach-o executable to a custom function (other than main()
)?
If not, then, is it possible to wrap main
to call my version of main before the actual C main
is called?
Edit:
I want to my custom function to call the C main
. If I gave it a constructor attribute or added it to ctor list then main
will be called twice. I do not want that to happen.
P.S I'm building executables in Mac OS X High Sierra with clang version 9.1.0
You can use the -e <symbol>
option of ld, which you can invoke as -Wl,-e,_<symbol>
from clang. Historically, the entry point of a program would be _start
from crt0.o, however that has not been a thing on Darwin since Mac OS X 10.8 and iOS 6.0, where the LC_MAIN
load command was introduced (replacing LC_UNIXTHREAD
). The "old" way can still be used, but would have to be explicitly enabled with the -no_new_main
linker flag (which has a counterpart -new_main
, should you ever need it). The duty once carried by crt0.o has been shifted to the dynamic linker, /usr/lib/dyld
, which can handle both LC_MAIN
and LC_UNIXTHREAD
as needed.
So given a C program with a main
:
// t.c
#include <stdio.h>
int main(int argc, const char **argv)
{
printf("test %i\n", argc);
return 0;
}
You can easily create a C++ file like this:
// 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 });
}
And compile them with clang++ -o t t.cpp -xc t.c -Wl,-e,_derp
.
Just be sure to either declare derp
as extern "C"
, or specify the mangled symbol on the command line.
You can also inspect the resulting executable with otool
to make sure it uses LC_MAIN
rather than LC_UNIXTHREAD
:
bash$ otool -l ./t | fgrep -B1 -A3 LC_MAIN
Load command 11
cmd LC_MAIN
cmdsize 24
entryoff 3808
stacksize 0