public inbox for gnu-gabi@sourceware.org
 help / color / mirror / Atom feed
* 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   ` 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 ` 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 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     ` 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).