Skip to contentSkip to conversation

man3/dlopen.3: Describe confusing dladdr() behavior

PATCH In review Petr Baudis 2 participants 5 messages Dec 5, 2008 – Dec 6, 2008 4 messages not in the archive Man-pages: manual pages for Linux -- Sections 2, 3, 4, 5, and 7

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 man3/dlopen.3: Describe confusing dladdr() behavior

dladdr() will act unexpectedly if called from non-pic code on a compile-time-generated function pointer:

Quoted 6 lines

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>

int
main(void)

Quoted 11 lines
{
	void *func;
	Dl_info info = {};

	func = printf;
	dladdr(func, &info);
	printf("%s at %p resolved from %s\n", info.dli_sname,
			func, info.dli_fname);

	return 0;
}

In the long term, it might make sense to make dladdr() recognize plt pointers and recurse, but I'm too afraid of Ulrich ;-) (and he seems to be heavy proponent of pic code anyway, so the chances for that to be accepted probably aren't high).

man3/dlopen.3 +27 -1
index d302360..649c449 100644
@@ -30,8 +30,9 @@
 .\" Modified by Matt Domsch, 2003-04-09: _init and _fini obsolete
 .\" Modified by Michael Kerrisk <[email protected]> 2003-05-16.
 .\" Modified by Walter Harms: dladdr, dlvsym
+.\" Modified by Petr Baudis <[email protected]>, 2008-12-04: dladdr caveat
 .\"
-.TH DLOPEN 3 2008-10-27 "Linux" "Linux Programmer's Manual"
+.TH DLOPEN 3 2008-12-04 "Linux" "Linux Programmer's Manual"
 .SH NAME
 dladdr, dlclose, dlerror, dlopen, dlsym, dlvsym \- programming interface to
 dynamic linking loader
@@ -408,12 +409,37 @@ Since glibc 2.2.3,
 .BR atexit (3)
 can be used to register an exit handler that is automatically
 called when a library is unloaded.
+
 .SS History
 The dlopen interface standard comes from SunOS.
 That system also has
 .BR dladdr (),
 but not
 .BR dlvsym ().
+
+.SH BUGS
+Sometimes, the function pointers you pass to
+.BR dladdr ()
+may surprise you.  On some architectures (notably i386 and x86_64),
+.IR "dli_fname " and " dli_fbase"
+may end up pointing back at the object where you called
+.BR dladdr ()
+from, even if the function used as an argument should come from
+a dynamically linked library.
+.PP
+The problem is that the function pointer will still be resolved
+at the compile time, but point merely to the
+.I plt
+section of the original object (which dispatches the call after
+asking the dynamic linker to resolve the symbol).
+To work this around, you can try to compile the code to be
+position-independent: then, the compiler cannot prepare the pointer
+at the compile time anymore and today's gcc will just load
+the final symbol address from the
+.I GOT
+at runtime before passing it to
+.BR dladdr ().
+
 .SH EXAMPLE
 Load the math library, and print the cosine of 2.0:
 .nf

--
To unsubscribe from this list: send the line "unsubscribe linux-man" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): [email protected]

#2 lore raw

Petr,

Thanks for the patch!

Quoted 20 lines · Petr Baudis

dladdr() will act unexpectedly if called from non-pic code on a compile-time-generated function pointer:

Quoted 17 lines

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>

int
main(void)

{
      void *func;
      Dl_info info = {};

      func = printf;
      dladdr(func, &info);
      printf("%s at %p resolved from %s\n", info.dli_sname,
                      func, info.dli_fname);

      return 0;

Thanks for the patch. For the change log, I added sample runs. See my follow-up mail.

I've applied the patch pretty much as you gave it for 3.15. Some notes below, including a question or two.

Quoted 23 lines

In the long term, it might make sense to make dladdr() recognize plt pointers and recurse, but I'm too afraid of Ulrich ;-) (and he seems to be heavy proponent of pic code anyway, so the chances for that to be accepted probably aren't high).

man3/dlopen.3 +2 -1
index d302360..649c449 100644
@@ -30,8 +30,9 @@
 .\" Modified by Matt Domsch, 2003-04-09: _init and _fini obsolete
 .\" Modified by Michael Kerrisk <[email protected]> 2003-05-16.
 .\" Modified by Walter Harms: dladdr, dlvsym
+.\" Modified by Petr Baudis <[email protected]>, 2008-12-04: dladdr caveat
 .\"
-.TH DLOPEN 3 2008-10-27 "Linux" "Linux Programmer's Manual"
+.TH DLOPEN 3 2008-12-04 "Linux" "Linux Programmer's Manual"
 .SH NAME
 dladdr, dlclose, dlerror, dlopen, dlsym, dlvsym \- programming interface to
 dynamic linking loader

man3/dlopen.3 Since glibc 2.2.3, · line 412

Quoted 4 lines
man3/dlopen.3 +1 -0
@@ -408,12 +409,37 @@ Since glibc 2.2.3,
 .BR atexit (3)
 can be used to register an exit handler that is automatically
 called when a library is unloaded.
+

The convention in man-pages is not to add blank lines before .SS / .SH. Dropped.

man3/dlopen.3 Since glibc 2.2.3, · line 419

Quoted 7 lines
man3/dlopen.3 +1 -0
 .SS History
 The dlopen interface standard comes from SunOS.
 That system also has
 .BR dladdr (),
 but not
 .BR dlvsym ().
+

See above.

man3/dlopen.3 Since glibc 2.2.3, · line 432

Quoted 13 lines
man3/dlopen.3 +13 -0
+.SH BUGS
+Sometimes, the function pointers you pass to
+.BR dladdr ()
+may surprise you.  On some architectures (notably i386 and x86_64),
+.IR "dli_fname " and " dli_fbase"
+may end up pointing back at the object where you called
+.BR dladdr ()
+from, even if the function used as an argument should come from
+a dynamically linked library.
+.PP
+The problem is that the function pointer will still be resolved
+at the compile time, but point merely to the
+.I plt

(It would be kind here to explain what "plt" stand as for. I added "Procedure Linkage Table".)

man3/dlopen.3 Since glibc 2.2.3,

Quoted 4 lines
man3/dlopen.3 +4 -0
+section of the original object (which dispatches the call after
+asking the dynamic linker to resolve the symbol).
+To work this around, you can try to compile the code to be
+position-independent:

I added: "gcc -fPIC" here

Quoted 2 lines

then, the compiler cannot prepare the pointer
+at the compile time anymore and today's gcc will just load

I made it "gcc(1)", but this doesn't seem quite right. It's not gcc in operation at program run time. can you more precisely say what you mean here.

Quoted 2 lines

+the final symbol address from the
+.I GOT

(I added "Global Offset Table")

man3/dlopen.3 Since glibc 2.2.3, · line 445

Quoted 6 lines
man3/dlopen.3 +3 -0
+at runtime before passing it to
+.BR dladdr ().
+
 .SH EXAMPLE
 Load the math library, and print the cosine of 2.0:
 .nf

Cheers,

Michael

Signature · 9 lines
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
git://git.kernel.org/pub/scm/docs/man-pages/man-pages.git
man-pages online: http://www.kernel.org/doc/man-pages/online_pages.html
Found a bug? http://www.kernel.org/doc/man-pages/reporting_bugs.html
--
To unsubscribe from this list: send the line "unsubscribe linux-man" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): cfd18e0f0812051450q438f9564w2f1aa7a82a993990-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#4 lore raw

Petr,

Below the changelog entry and diff that I actually applied.

Cheers,

Michael

commit ce02f233b3e884fe1fa303d5694ead012b298410

Author: Petr Baudis <[email protected]>
Date:   Fri Dec 5 17:45:53 2008 -0500
    dlopen.3: Describe confusing dladdr() behavior

    dladdr() will act unexpectedly if called from non-pic code on a
    compile-time-generated function pointer:

        /* test_dladdr.c */

        #define _GNU_SOURCE
        #include <dlfcn.h>
        #include <stdio.h>

        int
        main(void)
        {
            void *func;
            Dl_info info = {};

            func = printf;
            dladdr(func, &info);
            printf("%s at %p resolved from %s\n", info.dli_sname,
                    func, info.dli_fname);

            return 0;
        }

        $ cc test_dladdr.c -ldl
        $ ./a.out
        printf at 0x804838c resolved from ./a.out
        $ cc -fPIC test_dladdr.c -ldl
        $ ./a.out
        _IO_printf at 0xb7f71c30 resolved from /lib/libc.so.6

    In the long term, it might make sense to make dladdr() recognize
    plt pointers and recurse, but I'm too afraid of Ulrich ;-)
    (and he seems to be heavy proponent of pic code anyway, so
    the chances for that to be accepted probably aren't high).

    Signed-off-by: Petr Baudis <[email protected]>
    Signed-off-by: Michael Kerrisk <[email protected]>
man3/dlopen.3 +30 -1
index d302360..43fba7c 100644
@@ -30,8 +30,9 @@
 .\" Modified by Matt Domsch, 2003-04-09: _init and _fini obsolete
 .\" Modified by Michael Kerrisk <[email protected]> 2003-05-16.
 .\" Modified by Walter Harms: dladdr, dlvsym
+.\" Modified by Petr Baudis <[email protected]>, 2008-12-04: dladdr caveat
 .\"
-.TH DLOPEN 3 2008-10-27 "Linux" "Linux Programmer's Manual"
+.TH DLOPEN 3 2008-12-05 "Linux" "Linux Programmer's Manual"
 .SH NAME
 dladdr, dlclose, dlerror, dlopen, dlsym, dlvsym \- programming interface to
 dynamic linking loader
@@ -414,6 +415,34 @@ That system also has
 .BR dladdr (),
 but not
 .BR dlvsym ().
+.SH BUGS
+Sometimes, the function pointers you pass to
+.BR dladdr ()
+may surprise you.
+On some architectures (notably i386 and x86_64),
+.I dli_fname
+and
+.I dli_fbase
+may end up pointing back at the object from which you called
+.BR dladdr (),
+even if the function used as an argument should come from
+a dynamically linked library.
+.PP
+The problem is that the function pointer will still be resolved
+at compile time, but merely point to the
+.I plt
+(procedure linkage table)
+section of the original object (which dispatches the call after
+asking the dynamic linker to resolve the symbol).
+To work this around, you can try to compile the code to be
+position-independent
+.RI ( "cc -fPIC" ): then, the compiler cannot prepare the pointer
+at compile time anymore and today's
+.BR gcc (1)
+will just load the final symbol address from the
+.I GOT
+(Global Offset Table) at run time before passing it to
+.BR dladdr ().
 .SH EXAMPLE
 Load the math library, and print the cosine of 2.0:
 .nf

--
To unsubscribe from this list: send the line "unsubscribe linux-man" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): cfd18e0f0812051455s5b1800a2ve00dcb21cdd4baa1-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#6 lore raw

Hi!

Quoted 7 lines · Michael Kerrisk

man3/dlopen.3 That system also has

Quoted 4 lines · Petr Baudis
man3/dlopen.3 +4 -0
+section of the original object (which dispatches the call after
+asking the dynamic linker to resolve the symbol).
+To work this around, you can try to compile the code to be
+position-independent:

I added: "gcc -fPIC" here

Sometimes, -fpic might be better idea, for executables -fpie or -fPIE is better choice, which is why I chose not to mention a particular switch. It should be easy to look that up in the gcc manual page and you should understand the implications of this choice before doing it anyway.

Quoted 6 lines
Quoted 2 lines

then, the compiler cannot prepare the pointer
+at the compile time anymore and today's gcc will just load

I made it "gcc(1)", but this doesn't seem quite right. It's not gcc in operation at program run time. can you more precisely say what you mean here.

What about "code generated by today's gcc"? (I don't know if gcc always behaved like that or what do other compilers do, and I'm not willing to do the research in this case.)

Quoted 11 lines · Michael Kerrisk
man3/dlopen.3 +7 -0
@@ -414,6 +415,34 @@ That system also has
 .BR dladdr (),
 but not
 .BR dlvsym ().
+.SH BUGS
+Sometimes, the function pointers you pass to
+.BR dladdr ()
+may surprise you.
+On some architectures (notably i386 and x86_64),
+.I dli_fname
+and

man3/dlopen.3 That system also has · line 434

Quoted 10 lines
man3/dlopen.3 +10 -0
+.I dli_fbase
+may end up pointing back at the object from which you called
+.BR dladdr (),
+even if the function used as an argument should come from
+a dynamically linked library.
+.PP
+The problem is that the function pointer will still be resolved
+at compile time, but merely point to the
+.I plt
+(procedure linkage table)

The section name is "plt" but the expanded name should be capitalized, while...

man3/dlopen.3 That system also has · line 444

Quoted 10 lines
man3/dlopen.3 +10 -0
+section of the original object (which dispatches the call after
+asking the dynamic linker to resolve the symbol).
+To work this around, you can try to compile the code to be
+position-independent
+.RI ( "cc -fPIC" ): then, the compiler cannot prepare the pointer
+at compile time anymore and today's
+.BR gcc (1)
+will just load the final symbol address from the
+.I GOT
+(Global Offset Table) at run time before passing it to

...here I guess either the acronym is not necessary or it should be "got" for consistency (the section name).

Quoted 4 lines
man3/dlopen.3 +1 -0
+.BR dladdr ().
 .SH EXAMPLE
 Load the math library, and print the cosine of 2.0:
 .nf
Signature · 7 lines
				Petr "Pasky" Baudis
People who take cold baths never have rheumatism, but they have
cold baths.
--
To unsubscribe from this list: send the line "unsubscribe linux-man" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): [email protected]

#8 lore raw

Hi Petr,

Thanks for checking the patch.

Quoted 11 lines · Petr Baudis

Hi!

Quoted 7 lines · Michael Kerrisk

Review

Quoted 4 lines · Petr Baudis
(quoted diff) +4 -0
+section of the original object (which dispatches the call after
+asking the dynamic linker to resolve the symbol).
+To work this around, you can try to compile the code to be
+position-independent:

I added: "gcc -fPIC" here

Quoted 4 lines

Sometimes, -fpic might be better idea, for executables -fpie or -fPIE is better choice, which is why I chose not to mention a particular switch. It should be easy to look that up in the gcc manual page and you should understand the implications of this choice before doing it anyway.

Fair enough. I removed "gcc -fPIC".

Quoted 8 lines
Quoted 6 lines
Quoted 2 lines

then, the compiler cannot prepare the pointer
+at the compile time anymore and today's gcc will just load

I made it "gcc(1)", but this doesn't seem quite right. It's not gcc in operation at program run time. can you more precisely say what you mean here.

What about "code generated by today's gcc"?

Yep, i made it something like that.

Quoted 21 lines

(I don't know if gcc always
behaved like that or what do other compilers do, and I'm not willing to do the research in this case.)

Quoted 16 lines · Michael Kerrisk
(quoted diff) +12 -0
@@ -414,6 +415,34 @@ That system also has
 .BR dladdr (),
 but not
 .BR dlvsym ().
+.SH BUGS
+Sometimes, the function pointers you pass to
+.BR dladdr ()
+may surprise you.
+On some architectures (notably i386 and x86_64),
+.I dli_fname
+and
+.I dli_fbase
+may end up pointing back at the object from which you called
+.BR dladdr (),
+even if the function used as an argument should come from
+a dynamically linked library.
Quoted 8 lines

Review That system also has · line 434

Quoted 5 lines
(quoted diff) +5 -0
+.PP
+The problem is that the function pointer will still be resolved
+at compile time, but merely point to the
+.I plt
+(procedure linkage table)

The section name is "plt" but the expanded name should be capitalized, while...

Done.

Quoted 5 lines
Quoted 5 lines
(quoted diff) +5 -0
+section of the original object (which dispatches the call after
+asking the dynamic linker to resolve the symbol).
+To work this around, you can try to compile the code to be
+position-independent
+.RI ( "cc -fPIC" ): then, the compiler cannot prepare the pointer
Quoted 8 lines

Review That system also has · line 444

Quoted 5 lines
(quoted diff) +5 -0
+at compile time anymore and today's
+.BR gcc (1)
+will just load the final symbol address from the
+.I GOT
+(Global Offset Table) at run time before passing it to

...here I guess either the acronym is not necessary or it should be "got" for consistency (the section name).

Done.

Quoted 4 lines

Review That system also has · line 448

Quoted 4 lines
(quoted diff) +1 -0
+.BR dladdr ().
 .SH EXAMPLE
 Load the math library, and print the cosine of 2.0:
 .nf

Below is the change for man-pages-3.16.

Cheers,

Michael

man3/dlopen.3 +6 -7
@@ -32,7 +32,7 @@
 .\" Modified by Walter Harms: dladdr, dlvsym
 .\" Modified by Petr Baudis <[email protected]>, 2008-12-04: dladdr caveat
 .\"
-.TH DLOPEN 3 2008-12-05 "Linux" "Linux Programmer's Manual"
+.TH DLOPEN 3 2008-12-06 "Linux" "Linux Programmer's Manual"
 .SH NAME
 dladdr, dlclose, dlerror, dlopen, dlsym, dlvsym \- programming interface to
 dynamic linking loader
@@ -431,17 +431,16 @@ a dynamically linked library.
 The problem is that the function pointer will still be resolved
 at compile time, but merely point to the
 .I plt
-(procedure linkage table)
+(Procedure Linkage Table)
 section of the original object (which dispatches the call after
 asking the dynamic linker to resolve the symbol).
-To work this around, you can try to compile the code to be
-position-independent
-.RI ( "cc -fPIC" ):
+To work around this,
+you can try to compile the code to be position-independent:
 then, the compiler cannot prepare the pointer
 at compile time anymore and today's
 .BR gcc (1)
-will just load the final symbol address from the
-.I GOT
+will generate code that just loads the final symbol address from the
+.I got
 (Global Offset Table) at run time before passing it to
 .BR dladdr ().
 .SH EXAMPLE

--
To unsubscribe from this list: send the line "unsubscribe linux-man" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html