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