diff options
Diffstat (limited to 'elf/dynamic-link.h')
-rw-r--r-- | elf/dynamic-link.h | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h new file mode 100644 index 0000000000..1c3af29d6a --- /dev/null +++ b/elf/dynamic-link.h @@ -0,0 +1,119 @@ +/* Inline functions for dynamic linking. +Copyright (C) 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <elf.h> + +/* This machine-dependent file defines these inline functions. */ + +static void elf_machine_rel (Elf32_Addr loadaddr, Elf32_Dyn *info[DT_NUM], + const Elf32_Rel *reloc, + Elf32_Addr sym_loadaddr, const Elf32_Sym *sym); +static void elf_machine_rela (Elf32_Addr loadaddr, Elf32_Dyn *info[DT_NUM], + const Elf32_Rela *reloc, + Elf32_Addr sym_loadaddr, const Elf32_Sym *sym); +static Elf32_Addr *elf_machine_got (void); +static Elf32_Addr elf_machine_load_address (void); + +#include <dl-machine.h> + + +#include <assert.h> + +/* Read the dynamic section at DYN and fill in INFO with indices DT_*. */ + +static inline void +elf_get_dynamic_info (Elf32_Dyn *dyn, Elf32_Dyn *info[DT_NUM]) +{ + unsigned int i; + + for (i = 0; i < DT_NUM; ++i) + info[i] = NULL; + + while (dyn->d_tag != DT_NULL) + { + assert (dyn->d_tag < DT_NUM); + info[dyn->d_tag] = dyn++; + } + + if (info[DT_RELA]) + assert (info[DT_RELAENT]->d_un.d_val == sizeof (Elf32_Rela)); + if (info[DT_REL]) + assert (info[DT_RELENT]->d_un.d_val == sizeof (Elf32_Rel)); + if (info[DT_PLTREL]) + assert (info[DT_PLTREL]->d_un.d_val == DT_REL || + info[DT_PLTREL]->d_un.d_val == DT_RELA); +} + +/* Perform the relocations specified by DYNAMIC on the running program + image. If LAZY is nonzero, don't relocate PLT entries. *RESOLVE is + called to resolve symbol values; it modifies its argument pointer to + point to the defining symbol, and returns the base load address of the + defining object. */ + +static inline void +elf_dynamic_relocate (Elf32_Dyn *dynamic[DT_NUM], Elf32_Addr loadaddr, + int lazy, Elf32_Addr (*resolve) (const Elf32_Sym **)) +{ + const Elf32_Sym *const symtab + = (const Elf32_Sym *) dynamic[DT_SYMTAB]->d_un.d_ptr; + + inline Elf32_Addr symvalue (Elf32_Word info, const Elf32_Sym **definer) + { + if (ELF32_R_SYM (info) == STN_UNDEF) + return 0; /* This value will not be consulted. */ + *definer = &symtab[ELF32_R_SYM (info)]; + return (*resolve) (definer); + } + + /* Perform Elf32_Rel relocations in the section found by RELTAG, SZTAG. */ + inline void do_rel (Elf32_Word reltag, Elf32_Word sztag) + { + const Elf32_Rel *r = (const Elf32_Rel *) dynamic[reltag]->d_un.d_ptr; + const Elf32_Rel *end = &r[dynamic[sztag]->d_un.d_val / sizeof *r]; + while (r < end) + { + const Elf32_Sym *definer; + Elf32_Addr loadbase = symvalue (r->r_info, &definer); + elf_machine_rel (loadaddr, dynamic, r, loadbase, definer); + ++r; + } + } + /* Perform Elf32_Rela relocations in the section found by RELTAG, SZTAG. */ + inline void do_rela (Elf32_Word reltag, Elf32_Word sztag) + { + const Elf32_Rela *r = (const Elf32_Rela *) dynamic[reltag]->d_un.d_ptr; + const Elf32_Rela *end = &r[dynamic[sztag]->d_un.d_val / sizeof *r]; + while (r < end) + { + const Elf32_Sym *definer; + Elf32_Addr loadbase = symvalue (r->r_info, &definer); + elf_machine_rela (loadaddr, dynamic, r, loadbase, definer); + ++r; + } + } + + if (dynamic[DT_RELA]) + do_rela (DT_RELA, DT_RELASZ); + if (dynamic[DT_REL]) + do_rel (DT_REL, DT_RELSZ); + if (dynamic[DT_JMPREL] && ! lazy) + /* Relocate the PLT right now. */ + (dynamic[DT_PLTREL]->d_un.d_val == DT_REL ? do_rel : do_rela) + (DT_JMPREL, DT_PLTRELSZ); +} |