Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Wed, 16 Jan 2013 11:49:43 -0500
From: Rich Felker <>
Subject: Re: dladdr()

On Wed, Jan 16, 2013 at 03:24:24PM +0100, musl wrote:
> > i ran hello in gdb and it seems
> >  sym->st_shndx==0
> > for the "puts" symbol, i dont know the semantics of
> > st_shndx, but the following patch makes hello.c work:
> > 
> > diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c
> > index 935367e..ba0bd8f 100644
> > --- a/src/ldso/dynlink.c
> > +++ b/src/ldso/dynlink.c
> > @@ -1178,7 +1178,7 @@ int __dladdr(void *addr, Dl_info *info)
> >         }
> > 
> >         for (; nsym; nsym--, sym++) {
> > -               if (sym->st_shndx && sym->st_value
> > +               if (/*sym->st_shndx &&*/ sym->st_value
> >                  && (1<<(sym->st_info&0xf) & OK_TYPES)
> >                  && (1<<(sym->st_info>>4) & OK_BINDS)) {
> >                         void *symaddr = p->base + sym->st_value;
> > 
> You're right, sym->st_shndx only tells if the symbol is external
> (resolved during relocation process) or internal (defined in the
> current shared object).

st_shndx==0 is used for PLT entries. Oddly, I get (for hello.c):

Symbol table '.dynsym' contains 9 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 FUNC    GLOBAL DEFAULT  UND printf
     2: 080482c0     0 FUNC    GLOBAL DEFAULT  UND puts
     3: 00000000     0 FUNC    GLOBAL DEFAULT  UND dladdr

So the symbol value (the address of the PLT entry) seems to be filled
in only for symbols which are also used to take the address of a
function. Other symbols in the PLT (which are used only for resolving
the PLT entry at load time) lack addresses. I suspect this could
prevent correct dladdr behavior in some cases, but I can't think of a
serious usage case that would be broken right off.

Anyway, I'm applying nsz's patch (without the commented code :) which
should make the situation much better (hopefully as good as glibc's).

> BTW dli_fbase is still wrong. It should be
> 	info->dli_fbase = p->map;
> and not
> 	info->dli_fbase = p->base;

I notice it disagrees with glibc, but I'm not sure I agree it's wrong.
The man page states that dli_fbase is the "Address at which shared
object is loaded", which is never clearly defined. On the other hand,
dl_iterate_phdr's dlpi_addr is specified to contain the "Base address
of object", which is defined below as "the difference between the
virtual memory address of the shared object and the offset of that
object in the file from which it was loaded". To me, this seems like
the main/only "load address" that would be of interest to a program.
However, there's also an interest in matching historical practice,
especially since dladdr is not a standard function and the existing
implementations could be seen as the "real" specification. Do you know
what other systems like BSD do?


Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.