Question

Suppose we have the following iterface to a library:

// my_interface.h
typedef float (*myfunc)(float);
myfunc get_the_func();

And suppose that the implementation is as follows:

// my_impl.c
#include <math.h>
myfunc get_the_func() {
    return sinf;
}

And now suppose the client code does the following:

#include "my_interface.h"
...
myfunc func = get_the_func();
printf("%f\n", func(0.0f));

Does the standard guarantee that get_the_function() will return the address of the standard math library sinf()? If so, where in the standard is this implied? Please note the sinf() is not explicitly called anywhere.

Was it helpful?

Solution

The standard does not require external functions to be called: being referenced is enough to be kept in the results of translation. According to the standard's section 5.1.1.2.1, during the eights (and last) phase of translation

All external object and function references are resolved. Library components are linked to satisfy external references to functions and objects not defined in the current translation.

Since returning a pointer to a function is considered a reference to it, the standard guarantees that sinf will be linked to whatever implementation that you supply to the linker, which may or may not be the one coming from the standard math library.

OTHER TIPS

The C standard doesn't guarantee that get_the_function() will return the address of the sinf function in the math library. The C standard guarantees that whatever the pointer is returned will be callable as if you called the sinf function and it will compare equal to any other pointer to that function.

On some architectures you might get a pointer to a descriptor of the function which the compiler handles specially and I've also seen function pointer values pointing to a dynamic linking trampoline and not the function itself.

I recall a discussion on the gcc mailing lists around 10 years ago if a function pointer cast to (void *) actually needs to compare equal to another function pointer cast to (void *) which was in connection with how IA64 implements function pointers (they could point to different descriptor structs in different libraries, which meant that to correctly implement compares the compiler would have to compare the contents of the descriptors and not the pointers themselves). But I don't remember what the standards lawyers decided and/or if this was solved in the linker.

Okay so NOWHERE in the standard does it say that just because you #include <math.h> that you will also link to the standard math library ... As a matter of fact that DOES NOT happen.

You HAVE to link to the libm in order to use the standard math library, as in:

cc -o foo foo.c -lm 
                ^^^^

The marked option is actually for the linker step, without it there is no linkage irrespective of whether you a function in a library as a return value or whether you use it to actually call the function.

The external symbols are resolved by either explicitly specifying the archives/objects/libraries or in case of systems / environments lazy linking during runtime through dynamic linking.

On environments that support dynamic linking, weak linking, lazy linking, etc. there is no guarantee that references will ever be resolved. For the resolution the execution path has to be traversed.

Let's say it is. Still, your client needs to provide a linkage path for resolving sinf as well either when they are linking or during runtime for environments that support it.

the point:

The client user has the ability to use any way to resolve the symbol to an address that they see fit; So, in fact, there is no way to guarantee that your client will link to the standard library and that it will resolve to the system library sinf. The only thing you know is that if that path is executed; it will either result in an address that can be looked up using the sinf link or it will crash unceremoniously for environments that don't have to resolve the symbols at link time.

update/clarification:

To clarify, if sinf is used as a variable; then it needs to be resolved but there is still NO guarantee that when the client code resolves the symbol when they go through their linking step that they will resolve it against the math library. If we are talking about GUARANTEES that is.

Now practically speaking, if the client links against the standard math library and doesn't pull of any of the overrides that they can (which I pointed out above) then yes that symbol will get resolved to require a linkage against the standard library (either static or dynamic)

My original answer is a bit ehem "prissy" for which I apologize because we were talking about standards and guarantees thus the rantish nature. There is nothing for example stopping the client simply doing something like this:

foo.c:

#include "my_interface.h"
...
myfunc func = get_the_func();
printf("%f\n", func(0.0f));

first pass compile:

cc -o foo foo.c

get an error that says sinf is unresolved and so the client edits her source file:

foo.c:

#include "my_interface.h"
...
void * sinef = NULL;
myfunc func = get_the_func();
printf("%f\n", func(0.0f));

and now you have a fully resolved but nicely crashing program;

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top