diff options
author | Kevin Buettner <kevinb@redhat.com> | 2000-11-10 01:07:59 +0000 |
---|---|---|
committer | Kevin Buettner <kevinb@redhat.com> | 2000-11-10 01:07:59 +0000 |
commit | af21058b0321e272e6d0ad2877f402b286b0fb18 (patch) | |
tree | 6acfd191996764a2f84790aa50d1702c089bd93c /gdb/solib-svr4.c | |
parent | 8c7ea8cbe4ab9d39cd2ff54b2008898c2c596274 (diff) | |
download | gdb-af21058b0321e272e6d0ad2877f402b286b0fb18.tar.gz |
Add code for relocating dynamic executables.
Diffstat (limited to 'gdb/solib-svr4.c')
-rw-r--r-- | gdb/solib-svr4.c | 111 |
1 files changed, 110 insertions, 1 deletions
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index b5a0725480d..bbe90a6c959 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -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 |