public inbox for libc-hacker@sourceware.org
 help / color / mirror / Atom feed
* Symbol binding in shared libraries...
@ 2000-03-10 11:24 Scott Bambrough
  2000-03-10 11:47 ` Roland McGrath
  0 siblings, 1 reply; 2+ messages in thread
From: Scott Bambrough @ 2000-03-10 11:24 UTC (permalink / raw)
  To: libc-hacker mailing list

Hi guys,

The ARM port has a problem with PC24 relocs appearing in the .text segment of a
shared library.  These are PC relative branches, where the offset is a signed
integer which must be representable in 26 bits.  This means that I may not be
able to branch everywhere in the address space, so when fixing up the relocs in
ld-linux.so I need to do a range check.

I sent a patch for this problem a few weeks ago, and since then Phil Blundell
discovered a bug in my implementation.  I've been investigating this in much
greater detail and have run into something unusual, that I'd like an opinion on.

I've been testing with the following code from elf_machine_rel in dl-machine.h. 
It is used to fix up the relocs in the .text segment.  A small program seems to
work fine with this code, but larger programs like mozilla and orbit have
problems with odd range check failures.

case R_ARM_PC24:
{
  signed int addend;
  signed int offset;

  addend = *reloc_addr & 0x00ffffff;
  if (addend & 0x00800000) addend |= 0xff000000;

  /* Calculate a new 32 bit offset. */
  offset = value - (unsigned int)reloc_addr + (addend << 2);
             
  /* Range check the offset.  The offset is a 26 bit signed
  integer represented in two's complement notation.  Thus the
  offset can be in the range [-2^25 , 2^25 - 1].  The offset is
  stored in 24 bits, the bottom two bits are assumed to be zero.
  This means the offset must be a multiple of 4. 
  Note: 2^25 = 33554432.  */
             
  if ( (offset > 33554431)     /* value > 2^25 - 1 */
    || (offset < -33554432)    /* value < 2^25 */
    || (offset & 0x00000003) )  /* value not a multiple of 4 */
  {
    char buf[] = "R_ARM_PC24 relocation out of range (0x00000000).";
    char *bp;

    char bvalue[] = "value = 0x00000000";
    char baddr[] = "reloc_addr = 0x00000000";
    char breloc[] = "*reloc_addr = 0x00000000";
    char baddend[] = "addend = 0x00000000";
                
    if (NULL != sym) {
       bp = ((char*)map->l_info[DT_STRTAB]->d_un.d_ptr) + sym->st_name;
       _dl_sysdep_message (bp, "\n", NULL);
    }       
    bp = _itoa_word (value, &bvalue[sizeof bvalue - 1], 16, 0);
    _dl_sysdep_message (bvalue, "\n", NULL);
    bp = _itoa_word (reloc_addr, &baddr[sizeof baddr - 1], 16, 0);
    _dl_sysdep_message (baddr, "\n", NULL);
    bp = _itoa_word (*reloc_addr, &breloc[sizeof breloc - 1], 16, 0);
    _dl_sysdep_message (breloc, "\n", NULL);
    bp = _itoa_word (addend, &baddend[sizeof baddend - 1], 16, 0);
    _dl_sysdep_message (baddend, "\n", NULL);
               
    bp = _itoa_word (offset, &buf[sizeof buf - 3], 16, 0);
    _dl_signal_error (0, map->l_name, buf);
  }
               
  offset = offset >> 2;
  value = (*reloc_addr & 0xff000000) | (offset & 0x00ffffff);
  *reloc_addr = value;
}
break;

If I use Orbit as an example test case I get the following output:

[root@hackwrench ORBit-0.5.0]# orbit-event-server 
er_IOP_ServiceContext
value = 0x020010f8
reloc_addr = 0x400f7e34
*reloc_addr = 0xebfffffe
addend = 0xfffffffe
orbit-event-server: error in loading shared libraries: /usr/lib/libIIOP.so.0:
R_ARM_PC24 relocation out of range (0xc1f092bc).

I checked all the math by hand in this case, and the value for assignments in
the above code are correct, given the equations used.  The offset (0xc1f092bc)
is way out of line.  The problem is the contents of `value` as determined by
RESOLVE.

The symbol name is also bogus, and I'm not sure why.  I'm sure the code in
libIIOP.so is attempting to use fflush in libc.  If I look in
orbit-event-server, the PLT entry for fflush is at 0x20010f8, which is what
`value` is set to after RESOLVE is run.  Also if I change:

   bp = ((char*)map->l_info[DT_STRTAB]->d_un.d_ptr) + sym->st_name;
to
   bp = ((char*)map->l_info[DT_STRTAB]->d_un.d_ptr) + refsym->st_name;

then I get `fflush` printed out instead of `er_IOP_ServiceContext`.

The dynamic loader seems to be binding to the PLT entry in the main executable
for fflush, rather than the address of fflush in libc.so.  Phil delved into the
symbol resolution code and noticed that readelf reports the PLT entries as
STB_GLOBAL, so the code in dl-lookup will consider them valid candidates for
binding to.  The main program's symbol table seems to be searched first which is
why the symbols are picked up in preference to the ones in libc.so.  Is this
correct behaviour?

I don't fully understand what should be going on here.  Can someone help me out?

Thanks,

Scott

-- 
Scott Bambrough - Software Engineer
REBEL.COM    http://www.rebel.com
NetWinder    http://www.netwinder.org

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Symbol binding in shared libraries...
  2000-03-10 11:24 Symbol binding in shared libraries Scott Bambrough
@ 2000-03-10 11:47 ` Roland McGrath
  0 siblings, 0 replies; 2+ messages in thread
From: Roland McGrath @ 2000-03-10 11:47 UTC (permalink / raw)
  To: Scott Bambrough; +Cc: libc-hacker mailing list

>    bp = ((char*)map->l_info[DT_STRTAB]->d_un.d_ptr) + sym->st_name;
> to
>    bp = ((char*)map->l_info[DT_STRTAB]->d_un.d_ptr) + refsym->st_name;

The former is incorrect.  SYM is a symbol from another object (you don't
know which at this point in the code), and you are using its string-table
offset with the string table from the MAP object.  REFSYM is a symbol in
the MAP object that has the name you want, so the latter is correct.  This
sort of oversight suggests to me you might not have read all the code you
are working with as closely as you could have.

> The dynamic loader seems to be binding to the PLT entry in the main
> executable for fflush, rather than the address of fflush in libc.so.

It is clearly stated in the spec (I don't have a citation off hand) that
this is the specified behavior for references that aren't from a PLT.
Consider `return &foo;' in a shared object and `if (ptr == &foo)' in the
main executable, where `&foo' in non-PIC code will have been fixed at link
time to the address of the executable's PLT entry for `foo'.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2000-03-10 11:47 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2000-03-10 11:24 Symbol binding in shared libraries Scott Bambrough
2000-03-10 11:47 ` Roland McGrath

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).