For reference, I came up with this solution a while back. It's a touch on the cheeky side but may be portable to some selection of glibc versions at least. Basically it interposes a wrapper function around __libc_start_main (in crt1.o) which steals the argc and argv, and then defines a constructor that ends up first in the link order to do the real initialisation so as not to screw up the regular glibc init stuff. The attached example is based on the old-style winestub.c and a c++ program but the point is easy to see. (Pass "-Wl,--wrap,__libc_start_main" to gcc to make ld do the relevant switching trick.) Eventually I ended up just tweaking the offending program to do less in its constructors, but maybe this is still of some use? Cheers, -Matt.
/* Sample winestub.c file for compiling programs with libwine.so. */ #include <string.h> #include "winbase.h" #include "winuser.h" #include "xmalloc.h" extern int PASCAL WinMain(HINSTANCE,HINSTANCE,LPSTR,int); static HINSTANCE hInstance; /* external declaration here because we don't want to depend on Wine headers */ #ifdef __cplusplus extern "C" HINSTANCE MAIN_WinelibInit( int *argc, char *argv[] ); #else extern HINSTANCE MAIN_WinelibInit( int *argc, char *argv[] ); #endif /* Magic to make global C++ constructors work properly */ #ifdef __cplusplus static int stolen_argc; static char **stolen_argv; extern "C" { /* This will point to the actual __libc_start_main in crt1.o */ int __real___libc_start_main (int (*main) (int, char **, char **), int argc, char **argv, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void *stack_end); /* And this is magically called instead */ /* This happens before both constructors and main() - steal argc and argv */ /* here so we can initialise WineLib in a constructor */ int __wrap___libc_start_main (int (*main) (int, char **, char **), int argc, char **argv, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void *stack_end) { stolen_argc = argc; stolen_argv = argv; __real___libc_start_main (main, argc, argv, init, fini, rtld_fini, stack_end); return 0; } } /* Declare a static object to sneak a WineLib constructor in before other */ /* constructors and main(). WineLib program's global constructors can now */ /* do Win32 API calls and work properly */ class WL_init { public: WL_init (void) { if (!(hInstance = MAIN_WinelibInit( &stolen_argc, stolen_argv ))) exit(0); } } wl_init; #endif /* Most Windows C/C++ compilers use something like this to */ /* access argc and argv globally: */ int _ARGC; char **_ARGV; int main( int argc, char *argv [] ) { LPSTR lpszCmdParam; int i, len = 0, retv; _ARGC = argc; _ARGV = (char **)argv; #ifndef __cplusplus if (!(hInstance = MAIN_WinelibInit( &argc, argv ))) return 0; #endif /* Alloc szCmdParam */ for (i = 1; i < argc; i++) len += strlen(argv[i]) + 1; lpszCmdParam = (LPSTR) xmalloc(len + 1); /* Concatenate arguments */ if (argc > 1) strcpy(lpszCmdParam, argv[1]); else lpszCmdParam[0] = '\0'; for (i = 2; i < argc; i++) strcat(strcat(lpszCmdParam, " "), argv[i]); retv = WinMain (hInstance, /* hInstance */ 0, /* hPrevInstance */ lpszCmdParam, /* lpszCmdParam */ SW_NORMAL); /* nCmdShow */ ExitProcess( retv ); return retv; }