Question

My questions:

  1. Is function pointer equality guaranteed by the C standard?
  2. If the answer of (1) is yes. Is that the case regardless of the pointer being obtained in different final compilation units (e.g. main executable and a shared library)?
  3. How does the dynamic loader deal with that? (I can think about a few reasons for which this might be tricky, all related to PIC code (e.g. GOT tables in elf and whatever equivalent COFF uses for that)). Regardless of (1) and (2) the linux loader seems to guarantee this.

Here is an example. The questions above boil down to whether C guarantees what main.c prints: "Function equality: 1" or "Function equality: 0" and, in the first case, how does the dynamic loader make that happen.

common.h:

extern void * getc_main;
extern void * getc_shared;
void assign_getc_shared(); 

main.c:

#include <stdio.h>
#include "common.h"

int main()
{
  getc_main = (void*) getc;
  assign_getc_shared();
  printf("Function equality: %d\n", getc_main == getc_shared);
  return 0;
}

shared.c:

#include <stdio.h>
#include "common.h"

void assign_getc_shared()
{
   getc_shared = (void*) getc;
}

In Unix this would be compiled with the following commands:

cc -shared -fPIC -o libshared.so shared.c
cc -o main main.c -L. -lshared

And executed with:

LD_LIBRARY_PATH=. ./main
Was it helpful?

Solution

C 2011 (N1570 Committee Draft) 6.5.9 6: “Two pointers compare equal if and only if … both are pointers to the same … function …. So, yes, two pointers to the same function compare equal.

When the address of a function is taken in two different object modules, the compiler puts a placeholder in the object code. That placeholder is filled in when the object modules are linked into an executable or linked with a dynamic library at run-time.

For dynamic libraries, either the dynamic loader fills in all placeholders in the executable as necessary or the address of each function is actually the location of some stub code that jumps to the actual function, and a placeholder in or used by that stub code is filled in by the dynamic loader.

Additionally, note that an executable can contain more than one instance of a function. The compiler might insert the function inline in several places or might, for reasons of its own, include a specialization of the function as well as a general version. However, when the address of the function is taken, the compiler must provide the address of a single general version. (Or the compiler must ensure the program behaves as if that were done. E.g., if the compiler can detect that the program does not compare pointers, then it might, in theory, be able to use a different address for some instances of the address of the function.)

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