3

I am trying to compile a program so that it starts on a different entry point. I am running WSL1 with Ubuntu 20.04.5, and GCC and G++ 9.4.0

I found that adding the flag -Wl,--entry=foo to the compiler will link foo() as the entry function. Testing, this has worked with gcc, but not with g++.

Using the example file src/main.c:

#include <stdlib.h>
#include <stdio.h>

int main()
{
    printf("Entering %s:%s\n", __FILE__, __func__);
    return 0;
}

int not_main()
{
    printf("Entering %s:%s\n", __FILE__, __func__);
    exit(0); // Necessary, otherwise it throws a segfault
}

When compiled with gcc -Wl,--entry=not_main -o entry.o src/main.c the output is what I want: Entering src/main.c:not_main.

However, when compiled with g++ -Wl,--entry=not_main -o entry.o src/main.c, the following warning appears: /usr/bin/ld: warning: cannot find entry symbol not_main; defaulting to 0000000000001080.

This defaults to the main() function, outputting Entering src/main.c:main. The function not_main() is not found by the linker, but it is present in the source code.

The documentation for g++ says:

g++ is a program that calls GCC and automatically specifies linking against the C++ library.

I don't see how g++ can differ from gcc, if internally one calls the other. I understand that it is not the compiler but the linker which changes the entry point, and that g++ (unlike gcc) is linking against the C++ library, but I fail to understand how that is problematic.

What am I missing?

RoGuinart
  • 45
  • 4
  • Not that it would cause this issue, but sending the final, linked executable into a file named `entry.o` is rather unusual. – Thomas Jan 27 '23 at 11:07
  • An issue you need to be aware of is global constructors. In C++, those execute before `main` is called. `g++` knows this, and tells GCC to use a wrapper entry point. This wrapper calls global constructors, `main`, and then global destructors. – MSalters Jan 27 '23 at 13:27

2 Answers2

5

Because of name mangling, the function is not not_main but _Z8not_mainv.

how g++ can differ from gcc,

What is the difference between g++ and gcc? why use g++ instead of gcc to compile *.cc files?

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • Thank you, this seems to solve it. Are there rules to name-mangling, so that I may predict names? I usually work with C, so in header files I use extern "C" in case it's compiled as C++. Would this solve name-mangling? – RoGuinart Jan 27 '23 at 11:13
  • You would better use `extern "C"`. Anwyay: https://itanium-cxx-abi.github.io/cxx-abi/abi.html – KamilCuk Jan 27 '23 at 11:15
  • 1
    Note that name mangling is compiler-specific. – Thomas Jan 27 '23 at 11:43
4

C++, unlike C, uses name mangling to distinguish different overloads of the same function name.

When compiled with gcc:

$ objdump -t entry.o | grep not_main
000000000000117c g     F .text  0000000000000036              not_main

When compiled with g++:

$ objdump -t entry.o | grep not_main
0000000000000000         *UND*  0000000000000000              not_main
000000000000117c g     F .text  0000000000000036              _Z8not_mainv

The *UND*efined reference to not_main was probably placed there by the linker since you requested this as the entry point. The actual not_main function has its name mangled to _Z8not_mainv.

To export not_main under its original name, use extern "C":

extern "C" int not_main()
{
    printf("Entering %s:%s\n", __FILE__, __func__);
    exit(0); // Necessary, otherwise it throws a segfault
}
Thomas
  • 174,939
  • 50
  • 355
  • 478
  • There are situations where C uses name mangling too, for example when you have variables with the same name but in multiple scopes, or external linkage, or perhaps when an identifier name becomes longer than what's guaranteed by the translation limits. – Lundin Jan 27 '23 at 11:38