Add code for relocating dynamic executables.

This commit is contained in:
Kevin Buettner 2000-11-10 01:07:59 +00:00
parent ef5c4bfce0
commit e2a44558ad
2 changed files with 117 additions and 1 deletions

View File

@ -1,3 +1,10 @@
2000-11-09 Kevin Buettner <kevinb@redhat.com>
Changes based on a patch from Ulrich Drepper:
* solib-svr4.c (svr4_relocate_main_executable): New function.
(svr4_solib_create_inferior_hook): Call
svr4_relocate_main_executable.
2000-11-09 J.T. Conklin <jtc@redback.com>
* config/i386/nbsd.mh: Remove solib.o, solib-svr4.o from NATDEPFILES.

View File

@ -1437,6 +1437,112 @@ svr4_special_symbol_handling (void)
#endif /* !SVR4_SHARED_LIBS */
}
/* Relocate the main executable. This function should be called upon
stopping the inferior process at the entry point to the program.
The entry point from BFD is compared to the PC and if they are
different, the main executable is relocated by the proper amount.
As written it will only attempt to relocate executables which
lack interpreter sections. It seems likely that only dynamic
linker executables will get relocated, though it should work
properly for a position-independent static executable as well. */
static void
svr4_relocate_main_executable (void)
{
asection *interp_sect;
CORE_ADDR pc = read_pc ();
/* Decide if the objfile needs to be relocated. As indicated above,
we will only be here when execution is stopped at the beginning
of the program. Relocation is necessary if the address at which
we are presently stopped differs from the start address stored in
the executable AND there's no interpreter section. The condition
regarding the interpreter section is very important because if
there *is* an interpreter section, execution will begin there
instead. When there is an interpreter section, the start address
is (presumably) used by the interpreter at some point to start
execution of the program.
If there is an interpreter, it is normal for it to be set to an
arbitrary address at the outset. The job of finding it is
handled in enable_break().
So, to summarize, relocations are necessary when there is no
interpreter section and the start address obtained from the
executable is different from the address at which GDB is
currently stopped.
[ The astute reader will note that we also test to make sure that
the executable in question has the DYNAMIC flag set. It is my
opinion that this test is unnecessary (undesirable even). It
was added to avoid inadvertent relocation of an executable
whose e_type member in the ELF header is not ET_DYN. There may
be a time in the future when it is desirable to do relocations
on other types of files as well in which case this condition
should either be removed or modified to accomodate the new file
type. (E.g, an ET_EXEC executable which has been built to be
position-independent could safely be relocated by the OS if
desired. It is true that this violates the ABI, but the ABI
has been known to be bent from time to time.) - Kevin, Nov 2000. ]
*/
interp_sect = bfd_get_section_by_name (exec_bfd, ".interp");
if (interp_sect == NULL
&& (bfd_get_file_flags (exec_bfd) & DYNAMIC) != 0
&& bfd_get_start_address (exec_bfd) != pc)
{
struct cleanup *old_chain;
struct section_offsets *new_offsets;
int i, changed;
CORE_ADDR displacement;
/* It is necessary to relocate the objfile. The amount to
relocate by is simply the address at which we are stopped
minus the starting address from the executable.
We relocate all of the sections by the same amount. This
behavior is mandated by recent editions of the System V ABI.
According to the System V Application Binary Interface,
Edition 4.1, page 5-5:
... Though the system chooses virtual addresses for
individual processes, it maintains the segments' relative
positions. Because position-independent code uses relative
addressesing 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.
The same language also appears in Edition 4.0 of the System V
ABI and is left unspecified in some of the earlier editions. */
displacement = pc - bfd_get_start_address (exec_bfd);
changed = 0;
new_offsets = xcalloc (sizeof (struct section_offsets),
symfile_objfile->num_sections);
old_chain = make_cleanup (free, new_offsets);
for (i = 0; i < symfile_objfile->num_sections; i++)
{
if (displacement != ANOFFSET (symfile_objfile->section_offsets, i))
changed = 1;
new_offsets->offsets[i] = displacement;
}
if (changed)
objfile_relocate (symfile_objfile, new_offsets);
do_cleanups (old_chain);
}
}
/*
GLOBAL FUNCTION
@ -1489,9 +1595,12 @@ svr4_special_symbol_handling (void)
Also, what if child has exit()ed? Must exit loop somehow.
*/
void
static void
svr4_solib_create_inferior_hook (void)
{
/* Relocate the main executable if necessary. */
svr4_relocate_main_executable ();
/* If we are using the BKPT_AT_SYMBOL code, then we don't need the base
yet. In fact, in the case of a SunOS4 executable being run on
Solaris, we can't get it yet. current_sos will get it when it needs