* Deferred Binding of Function Pointers in SHLIB @ 2016-01-01 0:00 Suprateeka R Hegde 2016-01-01 0:00 ` Roland McGrath 0 siblings, 1 reply; 5+ messages in thread From: Suprateeka R Hegde @ 2016-01-01 0:00 UTC (permalink / raw) To: gnu-gabi Hi Consider this case: --- $ cat libmain.c #include <stdio.h> extern void foo(void); void (*func_p)(void) = foo; void libmain() { printf("printf()\n"); (*func_p)(); } $ cc -shared -fpic libmain.c -o libmain.so $ cc main.c -L. -lmain -Wl,--unresolved-symbols=ignore-all $ LD_LIBRARY_PATH=. ./a.out ./a.out: symbol lookup error: ./libmain.so: undefined symbol: foo --- Though lazy binding is default, it does not seem to be applicable to shared libraries. However, if the same libmain.c is made into an executable, as in: --- $ cat libmain.c #include <stdio.h> extern void foo(void); void (*func_p)(void) = foo; int main() { printf("printf()\n"); (*func_p)(); return 0; } $ cc libmain.c -Wl,--unresolved-symbols=ignore-all $ ./a.out printf() Segmentation fault (core dumped) --- That means lazy binding has happened. I would like to see both shlibs and executable behavior same here. What is the problem if we make this change? This can be part of the GNU-gABI itself. -- Supra ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Deferred Binding of Function Pointers in SHLIB 2016-01-01 0:00 Deferred Binding of Function Pointers in SHLIB Suprateeka R Hegde @ 2016-01-01 0:00 ` Roland McGrath 2016-01-01 0:00 ` Suprateeka R Hegde 0 siblings, 1 reply; 5+ messages in thread From: Roland McGrath @ 2016-01-01 0:00 UTC (permalink / raw) To: hegdesmailbox; +Cc: gnu-gabi I think you are confused about what you're observing. Lazy binding happens only for PLT entries, i.e. for direct function calls. There is never lazy binding for data initializers like your example uses. Your use of -Wl,--unresolved-symbols=ignore-all means that the non-shared case (libmain.c as executable) is simply mis-linked. (If you remove that switch, then the link will fail to complete and you can never get a binary to run.) After linking it's as if you'd instead had "void (*func_p)(void) = 0;" in the source. No kind of binding at all happens at runtime. The reason you saw the output from printf is because there was no kind of symbol resolution happening at all, and so nothing to fail at startup--your program starts up fine, does what it does, and only crashes when it tries to call the function pointer with value 0. In the shared library case, foo is left undefined in the DSO. The same would happen without --unresolved-symbols=ignore-all. (To see link-time checking for apparent definedness of referenced symbols, use -Wl,-z,defs.) Because the reference to foo is in a data initializer rather than a PLT entry (i.e., what you'd get if main had the line "foo();"), it has to be resolved at startup time by the dynamic linker before any of your code runs at all. Since that resolution fails, the dynamic linker bails out before even trying to start your program. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Deferred Binding of Function Pointers in SHLIB 2016-01-01 0:00 ` Roland McGrath @ 2016-01-01 0:00 ` Suprateeka R Hegde 2016-01-01 0:00 ` Carlos O'Donell 0 siblings, 1 reply; 5+ messages in thread From: Suprateeka R Hegde @ 2016-01-01 0:00 UTC (permalink / raw) To: Roland McGrath; +Cc: gnu-gabi Thanks for the response. You are right that my observation is incorrect. However something else is the story here. And my requirement/proposal is still valid. Read more inline. On 11-Jun-2016 03:06 AM, Roland McGrath wrote: > I think you are confused about what you're observing. Lazy binding > happens only for PLT entries, i.e. for direct function calls. There > is never lazy binding for data initializers like your example uses. Yes, I got confused. Coming after a decade of work on a platform where PIC is default, I missed adding -fpic while creating the executable. And I thought -fpic is default. That is the difference that confused me. In addition I was lazy enough not to debug, but to rely on messages of the dynamic linker. This is what happened: In executable, --- $ cat exe.c #include <stdio.h> extern void foo(void); void (*func_p)(void) = NULL; int main() { printf("printf()\n"); func_p = foo; (*func_p)(); return 0; } $ cc exe.c -Wl,--unresolved-symbol=ignore-all $ ./a.out printf() Segmentation fault (core dumped) --- printf() is called and then SEGV. Observe there is no message from dynamic linker at startup regarding UNDEF foo. In contrast, in the shlib case, --- $ cat main.c extern void libmain(void); int main() { libmain(); return 0; } $ cat libmain.c #include <stdio.h> extern void foo(void); void (*func_p)(void) = NULL; int libmain() { printf("printf()\n"); func_p = foo; (*func_p)(); return 0; } $ cc -fpic -shared libmain.c -Wl,--unresolved-symbol=ignore-all $ cc main.c -L. -lmain -Wl,--unresolved-symbol=ignore-all $ LD_LIBRARY_PATH=. ./a.out ./a.out: symbol lookup error: ./libmain.so: undefined symbol: foo --- Observe that there is an error message from the dynamic linker at startup even before printf is called. This missing startup message made me think that, in case of executable, there is lazy bind happening. (Sorry I should have debugged it and not relied on the message) Just because of the non-PIC mode for exe, the dynamic linker is deprived of the capability to give out a neat error message and exit gracefully. Had the same executable been built with -fpic, the result would have been same -- error message from the dynamic linker: --- $ cc exe.c -Wl,--unresolved-symbol=ignore-all $ ./a.out ./a.out: symbol lookup error: ./a.out: undefined symbol: foo --- However, the story does not end here. I make a minor change to exe.c: --- $ cat exe.c #include <stdio.h> extern void foo(void); void (*func_p)(void) = foo; /* func_p initialized before main */ int main() { printf("printf()\n"); (*func_p)(); return 0; } $ cat libfoo.c #include <stdio.h> void foo(void) { printf("In Foo\n"); } $ cc -fpic -shared libfoo.c -o libfoo.so $ cc exe.c -L. -lfoo --- After the exe build, change libfoo.c and make foo() as bar(), but keep the name of shlib same -- libfoo.so. What I did is, provide a well defined foo() during link edit time. But remove foo() at runtime. Then I see: --- $ LD_LIBRARY_PATH=. ./a.out printf() ./a.out: symbol lookup error: ./a.out: undefined symbol: foo LD_BIND_NOW=1 LD_LIBRARY_PATH=. ./a.out ./a.out: symbol lookup error: ./a.out: undefined symbol: foo --- Observe that without LD_BIND_NOW, lazy bind is happening. With LD_BIND_NOW, its all at startup and hence printf() is not even called. Now, convert this modified exe.c into a shlib as before, and again remove foo at runtime. Then, there is no lazy bind at all. I see: --- $ LD_LIBRARY_PATH=. ./a.out ./a.out: symbol lookup error: ./libmain.so: undefined symbol: foo --- So, observing all these, it is all about whether foo gets a JUMP_SLOT reloc or not. In other words, foo gets a PLT or not (?). What I want to propose is that the behavior should be consistent across exe and shlib. However, It is not the case as seen above. Is there any anti option to -fno-plt of GCC6 :-) > Your use of -Wl,--unresolved-symbols=ignore-all means that the > non-shared case (libmain.c as executable) is simply mis-linked. (If > you remove that switch, then the link will fail to complete and you > can never get a binary to run.) Not really. One can get the symbols at runtime too. Not everything need to be resolved at link-edit time. For instance, using LD_PRELOAD, dlopen-with-RTLD_GLOBAL, etc. (See my thread on GNU dlopen vs POSIX/IEEE on the mailing list: https://sourceware.org/ml/gnu-gabi/2016-q2/msg00015.html) My real case is as follows: I have an executable with hundreds of function pointers as an array. Functions are called using array index which depends on the arguments passed to the executable. This executable is short lived and in each invocation calls only one function. Without lazy bind, all these function pointers are being resolved at startup. This increases startup time which becomes significant given the fact that the executable is very short lived. -- Supra ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Deferred Binding of Function Pointers in SHLIB 2016-01-01 0:00 ` Suprateeka R Hegde @ 2016-01-01 0:00 ` Carlos O'Donell 2016-01-01 0:00 ` Suprateeka R Hegde 0 siblings, 1 reply; 5+ messages in thread From: Carlos O'Donell @ 2016-01-01 0:00 UTC (permalink / raw) To: hegdesmailbox, Roland McGrath; +Cc: gnu-gabi On 06/13/2016 11:27 AM, Suprateeka R Hegde wrote: > I have an executable with hundreds of function pointers as an array. > Functions are called using array index which depends on the arguments > passed to the executable. This executable is short lived and in each > invocation calls only one function. Could you please provide a small code example that shows the exact problem? -- Cheers, Carlos. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Deferred Binding of Function Pointers in SHLIB 2016-01-01 0:00 ` Carlos O'Donell @ 2016-01-01 0:00 ` Suprateeka R Hegde 0 siblings, 0 replies; 5+ messages in thread From: Suprateeka R Hegde @ 2016-01-01 0:00 UTC (permalink / raw) To: Carlos O'Donell, Roland McGrath; +Cc: gnu-gabi On 14-Jun-2016 02:33 AM, Carlos O'Donell wrote: > On 06/13/2016 11:27 AM, Suprateeka R Hegde wrote: >> I have an executable with hundreds of function pointers as an array. >> Functions are called using array index which depends on the arguments >> passed to the executable. This executable is short lived and in each >> invocation calls only one function. > > Could you please provide a small code example that shows the exact > problem? Its already there. The examples I have given are also exact problems. The shlib behavior and exe behavior are different. -- Supra ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2016-06-18 4:11 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2016-01-01 0:00 Deferred Binding of Function Pointers in SHLIB Suprateeka R Hegde 2016-01-01 0:00 ` Roland McGrath 2016-01-01 0:00 ` Suprateeka R Hegde 2016-01-01 0:00 ` Carlos O'Donell 2016-01-01 0:00 ` Suprateeka R Hegde
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).