`-Wl,-z,now' works and the GNU-IFUNC resolver is called before `main'. But RTLD_NOW returns handle and GNU-IFUNC gets called only after `dlsym'. Even if the executable calling dlopen(, RTLD_NOW) uses -Wl,-z,-now. The first part of the test below is correct: + ./mc f main But this part prints: + ./mcd dlsym f while I expect: + ./mcd f dlsym This behavior determines how the glibc Bug 2328 should be resolved in GDB. cat >lc.c <<EOH #include <stdio.h> static int fi (int a) { return a + 1; } asm (".type f, @gnu_indirect_function"); int (* f (void)) (int a) { puts ("f"); return fi; } EOH cat >mc.c <<EOH #include <stdio.h> extern int f (int a); int main (void) { puts ("main"); return f (-1); } EOH cat >mcd.c <<EOH #include <stdio.h> #include <dlfcn.h> int main (void) { void *h = dlopen ("./lc.so", RTLD_NOW); puts ("dlsym"); int (*fp) (int a) = (int (*) (int a)) dlsym (h, "f"); return fp (-1); } EOH gcc -o lc.so lc.c -Wall -g -shared -fPIC; gcc -o mc mc.c -Wall -g -Wl,-z,now ./lc.so; gcc -o mcd mcd.c -Wall -g -Wl,-z,now -ldl; (set -x; ./mc; ./mcd)
Tested on Fedora 15: glibc-2.13.90-6.i686 glibc-2.13.90-6.x86_64
There is nothing to change in the dynamic linker. When you dynamically load the DSO this doesn't magically make a relocation appear. In your test, the symbol f doesn't have any relocation attached to it and this is correct. This is really the expected behavior. Without a relocation or returning the symbol address (as in dlsym) there is no place to store the result of the ifunc function call.
I agree now, there is no <f@plt> stub anywhere in the dlopen case, thanks.