How can I invoke a function with multiple distinct signatures (as glibc invokes main)?

69 views Asked by At

The C++ Standard indicates that the main can have two possible signatures.

int main()               // (1)
int main(int, char*[])   // (2)

Moreover, main() is typically called from __libc_start_main, which is defined in csu/libc-start.c in the glibc source code. The invocation of main inside this function is copied below.

result = main (argc, argv, __environ MAIN_AUXVEC_PARAM);

We observe that the call here uses three arguments, and this appears to not produce any linker errors, despite the fact that the signature does not match either of the above two forms.


I am writing a threading library which defines main(), and would like the application to be able to define one of the following two functions.

int AppMain()               // (1)
int AppMain(int, char*[])   // (2)

Unfortunately, if I declare AppMain using the second form above and invoke it from my library's main, and the application uses the first form instead, then I get a unresolved reference linker error indicating that the function I invoked does not exist.

Since this does not seem to be a problem for glibc with respect to main, how might I write my invocation or declaration in a way that avoids the linker error?


Here is an easy way to reproduce the problem.

Makefile

CCFLAGS=-Wall -Werror

all: libLib.a App

libLib.a: Lib.o
    ar rcs $@ $^

App: App.o libLib.a
    g++ -o $@ $< -L. -lLib

%.o: %.cc
    g++ $(CCFLAGS)  -O3 $(LIBS) -fPIC -c  -o $@ $<

Lib.cc

#include <stdio.h>

int AppMain(int argc, char** argv);

#undef main
int main(int argc, char** argv){
    printf("Hello World\n");    
    AppMain(argc, argv);
}

App.cc (Working Version)

#include <stdio.h>

int AppMain(int argc, char** argv){
    printf("Application says Hello world\n");
    return 0;
}

App.cc (Non-Working Version)

#include <stdio.h>

int AppMain(){
    printf("Application says Hello world\n");
    return 0;
}

Under the second version, here is the linker error.

./libLib.a(Lib.o): In function `main':
Lib.cc:(.text.startup+0x24): undefined reference to `AppMain(int, char**)'
collect2: error: ld returned 1 exit status
Makefile:9: recipe for target 'App' failed
make: *** [App] Error 1
1

There are 1 answers

0
Armali On

Regardless of suggestions to do it differently, I just answer your question

how might I write my invocation or declaration in a way that avoids the linker error?

You may write your definition in App.cc as

extern "C" int AppMain()
{
    …

and your declaration in Lib.cc as

extern "C" int AppMain(int argc, char** argv);

to avoid that name mangling, the same as it's most probably done in glibc. There may be C++ compilers where this doesn't work, but it certainly works with the GCC.