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