65

Under what situation is it possible for GCC to not throw an "undefined reference" link error message when trying to call made-up functions?

For example, a situation in which this C code is compiled and linked by GCC:

void function()
{
    made_up_function_name();
    return;
}

...even though made_up_function_name is not present anywhere in the code (not headers, source files, declarations, nor any third party library).

Can that kind of code be accepted and compiled by GCC under certain conditions, without touching the actual code? If so, which?

Thanks.

EDIT: no previous declarations or mentions to made_up_function_name are present anywhere else. Meaning that a grep -R of the whole filesystem will only show that exact single line of code.

STenyaK
  • 1,047
  • 1
  • 8
  • 15
  • It can (as long as you're compiling C, not C++). What are you trying to accomplish though? – Jerry Coffin Apr 05 '11 at 17:11
  • I'm not trying to accomplish anything, it's already happening and I'd like to know why it's possible. The made_up_function_name is actually present in the final, linked binary if I use "-g" and edit the file with a text editor. – STenyaK Apr 05 '11 at 17:17
  • 1
    As for why, see: http://stackoverflow.com/questions/4914589/c-prototype-functions/4914683, http://stackoverflow.com/questions/4800102/not-including-stdlib-h-does-not-produce-any-compiler-error/4800138#4800138, and probably quite a few more. – Jerry Coffin Apr 05 '11 at 17:20
  • All proposed answers require the function to at least be defined, even if prototype is optional. "made_up_function_name" is not defined nor prototyped anywhere. – STenyaK Apr 05 '11 at 17:31
  • 3
    that prevents it from *linking* successfully, but not from compiling. – Jerry Coffin Apr 05 '11 at 17:34
  • What are you trying to build? If it's shared library then this symbol might come from another library that was loaded via `LD_PRELOAD` or `dlopen("somelib.so", RTLD_GLOBAL)`. – ivaigult Aug 02 '16 at 11:39

7 Answers7

111

Yes, it is possible to avoid reporting undefined references - using --unresolved-symbols linker option.

g++ mm.cpp -Wl,--unresolved-symbols=ignore-in-object-files

From man ld

--unresolved-symbols=method

Determine how to handle unresolved symbols. There are four possible values for method:

       ignore-all
           Do not report any unresolved symbols.

       report-all
           Report all unresolved symbols.  This is the default.

       ignore-in-object-files
           Report unresolved symbols that are contained in shared
           libraries, but ignore them if they come from regular object
           files.

       ignore-in-shared-libs
           Report unresolved symbols that come from regular object
           files, but ignore them if they come from shared libraries.  This
           can be useful when creating a dynamic binary and it is known
           that all the shared libraries that it should be referencing
           are included on the linker's command line.

The behaviour for shared libraries on their own can also be controlled by the --[no-]allow-shlib-undefined option.

Normally the linker will generate an error message for each reported unresolved symbol but the option --warn-unresolved-symbols can change this to a warning.

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
Dmitry Yudakov
  • 15,364
  • 4
  • 49
  • 53
  • What are the equivalents for `clang`? – igagis Apr 19 '21 at 00:43
  • Also: what are the equivalents for `mingw-gcc` ? The option is recognized, but it doesn't seem to do anything. – Michael Oct 25 '22 at 17:32
  • I'm right there with you, @Michael - mine accepts the option but still throws an Undefined Reference error. – Stryker2k2 Jul 11 '23 at 15:51
  • 1
    @Stryker2k2 Then I'll be the bearer of bad news: after researching the topic further, Windows does not support libraries with undefined symbols, so that feature just cannot be made available. – Michael Jul 12 '23 at 17:46
4

TL;DR It can not complain, but you don't want that. Your code will crash if you force the linker to ignore the problem. It'd be counterproductive.

Your code relies on the ancient C (pre-C99) allowing functions to be implicitly declared at their point of use. Your code is semantically equivalent to the following code:

void function()
{
    int made_up_function_name(...); // The implicit declaration

    made_up_function_name(); // Call the function
    return;
}

The linker rightfully complains that the object file that contains the compiled function() refers to a symbol that wasn't found anywhere else. You have to fix it by providing the implementation for made_up_function_name() or by removing the nonsensical call. That's all there's to it. No linker-fiddling involved.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • 3
    If making a shared library, though, this makes sense. – Topological Sort Feb 11 '19 at 13:51
  • It does not make sense at all: symbols that you wish to import aren't undefined, they are just dynamically bound. I doubt very much that you've actually tried it out and can provide some real scenario - think of a series of bash commands that create the sources, compile and link them, and dump the binaries and demonstrate those undefined-at-link-time symbols. – Kuba hasn't forgotten Monica Feb 11 '19 at 13:54
  • Let's be civil. So: we have libraries that work together: say, SDL2, and add-on libraries SDL2_ttf, SDL2_image, and SDL2_mixer. Do each of the add-ons need to link in SDL2? Wouldn't that give a program that links in all 4 of these libraries, 4 copies of the functions in SDL2? – Topological Sort Feb 11 '19 at 14:51
  • Not at all, and it wouldn't get multiple copies whether the libraries where statically or dynamically linked into the resulting executable, with the only limitation that if the add-ons were dynamically linked to SDL2, but SDL2 wasn't dynamically linked to the executable, then the executable itself would need to export SDL2's symbols. This is possible in both PE and ELF, and while it may not be very popular, there are valid use cases for it. Say that you're wrapping Python and want to statically linkit, but still want the users to be able to add their own Python C modules to your application. – Kuba hasn't forgotten Monica Feb 11 '19 at 17:26
  • A caveat is that if SDL2_foo are shared modules and link statically to SDL2, then each will carry its own copy of SDL2, and we don't want that of course. – Kuba hasn't forgotten Monica Feb 11 '19 at 17:32
  • Perhaps the point of confusion here is that `made_up_function_name` is allowed to be undefined due to dynamic linking: not at all. Dynamic linking means that you link with a stub (import) library, and that library tells the linker what symbols to pull from what dynamically-loaded module. So even though the values (addresses) of the symbols are not known at link time, it is known that they'll be available at runtime - or the loader will abort. If the linker receives neither a static value for the symbol, nor an instruction that it be dynamically determined, then it will validly complain! – Kuba hasn't forgotten Monica Feb 11 '19 at 17:32
3

When you build with the linker flag -r or --relocatable it will also not produce any "undefined reference" link error messages.

This is because -r will link different objects in a new object file to be linked at a later stage.

Simon Hänisch
  • 4,740
  • 2
  • 30
  • 42
3

If you declare the prototype of the function before using it , it shold compile. Anyway the error while linking will remain.

void made_up_function_name();
void function()
{
    made_up_function_name();
    return;
}
Heisenbug
  • 38,762
  • 28
  • 132
  • 190
  • Edited question to reflect this: there's absolutely no other mention to the made up function, other than the call line shown in the example. – STenyaK Apr 05 '11 at 17:19
2

And then there is this nastiness with the -D flag passed to GCC.

$cat undefined.c
void function()
{
    made_up_function_name();
    return;
}


int main(){
}

$gcc undefined.c -Dmade_up_function_name=atexit
$

Just imagine looking for the definition of made_up_function_name- it appears nowhere yet "does things" in the code. I can't think of a nice reason to do this exact thing in code.

The -D flag is a powerful tool for changing code at compile time.

Tim Williscroft
  • 3,705
  • 24
  • 37
  • The `-D` flag changes code at *compile* time. Then there's stuff like `-Wl,--wrap` which does that at link time. – sam hocevar Aug 03 '12 at 12:31
  • And if one combines `-D` with pre-processor token merging then the text `made_up_function_name` need not appear as-such in any makefile or build script either. – Greg A. Woods Aug 03 '16 at 00:54
1

If function() is never called, it might not be included in the executable, and the function called from it is not searched for either.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • so it might compile even without declaring the prototype and then be linked too? I think that at least the prototype should be declared, otherwise it would generate a parsing error, right? – Heisenbug Apr 05 '11 at 17:35
  • @0verbose - It depends on which C standard you use. Originally, prototypes were not needed. And later only if you had parameter types other than int. – Bo Persson Apr 05 '11 at 17:59
0

The "standard" algorithm according to which POSIX linkers operate leaves open the possibility that the code will compile and link without any errors. See here for details: https://stackoverflow.com/a/11894098/187690

In order to exploit that possibility the object file that contains your function (let's call it f.o) should be placed into a library. That library should be mentioned in the command line of the compiler (and/or linker), but by that moment no other object file (mentioned earlier in the command line) should have made any calls to function or any other function present in f.o. Under such circumstances linker will see no reason to retrieve f.o from the library. Linker will completely ignore f.o, completely ignore function and, therefore, remain completely oblivious of the call to made_up_function_name. The code will compile even though made_up_function_name is not defined anywhere.

Community
  • 1
  • 1
AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765