cgccld

`gcc -undef` leads to `cannot find entry symbol _start`; defaulting to x


When running gcc -undef file.c, on a file containing nothing but a main function, I get this warning from ld:

/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000401020

There are SO questions about the same warning related to option -nostdlib and -nostartfiles, but I did not use them.

Even if I manually redefined all of the predefined symbols (retrieved using echo | gcc -dM -E -) as #defines and add them to my source file, running gcc -undef on it will still produce the same warning.

The GCC documentation about -undef contains only the following:

-undef

Do not predefine any system-specific or GCC-specific macros. The standard predefined macros remain defined.

And among the predefined macros, I see nothing related to the standard C library, to main, or to _start. __STDC_HOSTED__ is still defined (despite -undef). If I run gcc -undef main.c -c, the resulting main.o file is identical despite -undef. So it's clearly something related to linking. But as mentioned before, GCC documentation about -undef does not mention anything about linking, and GCC Linking Options has no -undef option.

What is going on, and is there a way to use -undef and still be able to compile and link a file using gcc, e.g. by adding other options?

Edit: following suggestions, I tried running gcc -Wl,-verbose with and without -undef, and the only difference is this:

...
 /usr/bin/ld: mode elf_x86_64
+attempt to open /usr/lib/gcc/x86_64-redhat-linux/14/../../../../lib64/crt1.o succeeded
+/usr/lib/gcc/x86_64-redhat-linux/14/../../../../lib64/crt1.o
 attempt to open /usr/lib/gcc/x86_64-redhat-linux/14/../../../../lib64/crti.o succeeded
...

But it's not clear to me why -undef affects the opening of crt1.o.


Solution

  • This appears to be a GCC bug. As you can see if you add the -v option, the gcc compiler driver passes -undef as a command line parameter to the linker ld, which makes no sense and causes undesired behavior. I've reported it as bug 118975.

    GNU ld has an option --undefined=sym which causes the symbol sym to be treated as undefined for the link (e.g. so as to pull in a library module that defines it), but not causing an error if it remains undefined. In its command line syntax, ld also:

    The net effect of passing -undef to the linker, then, is that the next parameter on the ld command line is treated as if it were the argument of the --undefined option. In my test, that parameter is the path to the startup code file Scrt1.o (apparently crt1.o on your installation), which is where the _start symbol is defined. So that path is treated as a symbol to be undefined (harmless in itself) and not as a file to be linked. Thus Scrt1.o is omitted from the link and you get a warning about _start being undefined; moreover, the output executable won't work.

    There's an easy workaround: compile and link the file in two steps, and don't pass -undef when linking (as it should only affect preprocessing anyway).

    gcc -c -undef main.c
    gcc main.o