This is the mail archive of the gdb@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: relocation of shared libs not based at 0


On Dec 17,  3:23pm, Kris Warkentin wrote:

> I recently came across a problem debugging a core file with some of our
> older shared libs.  Info shared showed the relocations of the shared libs to
> be mangled (offset to 0x60... range rather than 0xb0... range).  We had
> recently changed our tools to always set the vaddr of shared libs to be zero
> because of this but I was speaking to one of our architects and he says that
> this shouldn't be.
> 
> One of the future optimizations we're looking at is pre-relocating shared
> libs so that they can be executed in place (on flash for instance) and the
> fact that the SysV stuff seems to assume that everything is based at zero is
> not particularily compatable with that.  I've attached an ugly patch that
> shows a fix.  This is for illustration only since solib.c is the wrong place
> to put this but it makes it clear what the issue is.
> 
> Can anyone with more knowledge than I enlighten me as to a) whether it is
> proper to allow shared objects to be non zero-based and b) a better way to
> do this.  I looked at putting it in solib-svr4.c but I don't have access to
> the bfd in there, at least in svr4_relocate_section_addresses().

With regard to a), it's okay for shared objects to be non-zero based.
We'll get to b) in a bit...

Let's first take a look at the existing code in GDB's solib-svr4.c:

static void
svr4_relocate_section_addresses (struct so_list *so,
                                 struct section_table *sec)
{
  sec->addr    = svr4_truncate_ptr (sec->addr    + LM_ADDR (so));
  sec->endaddr = svr4_truncate_ptr (sec->endaddr + LM_ADDR (so));
}

This code is adjusting the start and end addresses by LM_ADDR (so) which
is simply the l_addr field obtained from struct link_map.

On my i386 GNU/Linux system, the comment in link.h says that l_addr is
the "base address shared object is loaded at."  We must be very careful
with the term "base address" because it's quite possible that it means
something very different than what you think it does.  (I certainly found
it counter-intuitive.)

Here is what chapter 5 of the "System V Application Binary Interface,
Edition 4.1" says about the term "Base Address":

    As "Program Loading" in this chapter of the processor supplement
    describes, the virtual addresses in the program headers might not
    represent the actual virtual addresses of the program's memory
    image.  Executable files typically contain absolute code.  To let
    the process execute correctly, the segments must reside at the
    virtual addresses used to build the executable file.  On the other
    hand, shared object segments typically contain
    position-independent code.  This lets a segment's virtual address
    change from one process to another, without invalidating execu-
    tion behavior.  Though the system chooses virtual addresses for
    individual processes, it maintains the segments' relative
    positions.  Because position- independent code uses relative
    addressing between segments, the difference between virtual
    addresses in memory must match the difference between virtual
    addresses in the file.  The difference between the virtual address
    of any segment in memory and the corresponding virtual address in
    the file is thus a single constant value for any one executable or
    shared object in a given process.  This difference is the base
    address.  One use of the base address is to relocate the memory
    image of the program during dynamic linking.

    An executable or shared object file's base address is calculated
    during execution from three values:  the virtual memory load
    address, the maximum page size, and M the lowest virtual address
    of a program's loadable segment.  To compute the base address, one
    determines the memory address associated with the lowest p_vaddr
    value for a PT_LOAD segment.  This address is truncated to the
    nearest multiple of the maximum page size.  The corresponding
    p_vaddr value itself is also truncated to the nearest multiple of
    the maximum page size.  The base address is the difference between
    the truncated memory address and the truncated p_vaddr value.

    See this chapter in the processor supplement for more information
    and examples.  "Operating System Interface" of Chapter 3 in the
    processor supplement contains more information about the virtual
    address space and page size.

So, as I understand it, the "base address" is *not* an absolute
location, but is actually the difference between where the segment
ended up and the location assigned to it in the executable file.
Thus the "base address" is the proper value to use to relocate the
segment's start and end addresses.

Now, it's possible that my understanding is flawed.  If so, I await
enlightenment.  I think it's also possible that the shared library
implementation that you're using might not conform to the above
definition of "base address".  If that's the case, then you can either
attempt to get it fixed in the code which implements the dynamic
loader, or, if that's not possible, create a new solib backend for gdb
which implements support for your shared library machinery.  I suspect
it would be very similar to solib-svr4.c.

With regard to the two patches that have been posted for fixing this
problem, I don't think that either one is correct in light of the
above definition of "base address".

Kevin


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]