123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- /* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
- /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
- #include "elf.h"
- #ifndef VERSYMIDX
- # define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
- #endif
- #ifndef DT_THISPROCNUM
- # define DT_THISPROCNUM 0
- #endif
- #define IN_RANGE(l, addr) \
- ((ElfW(Addr)) (addr) >= (l)->l_map_start && (ElfW(Addr)) (addr) < (l)->l_map_end)
- #define RELOCATE(l, addr) \
- ((typeof(addr)) (IN_RANGE((l), (addr)) ? (ElfW(Addr)) (addr) : \
- (ElfW(Addr)) (addr) + (ElfW(Addr)) ((l)->l_addr)))
- #ifdef __x86_64__
- # include "dl-machine-x86_64.h"
- #endif
- /* Read the dynamic section at DYN and fill in INFO with indices DT_*. */
- static inline
- void __attribute__ ((unused, always_inline))
- elf_get_dynamic_info (struct link_map * l)
- {
- #if __ELF_NATIVE_CLASS == 32
- typedef Elf32_Word d_tag_utype;
- #elif __ELF_NATIVE_CLASS == 64
- typedef Elf64_Xword d_tag_utype;
- #endif
- ElfW(Dyn) * dyn = l->l_ld;
- while (dyn->d_tag != DT_NULL) {
- int tag = 0;
- if ((d_tag_utype) dyn->d_tag < DT_NUM)
- tag = dyn->d_tag;
- else if (dyn->d_tag >= DT_LOPROC &&
- dyn->d_tag < DT_LOPROC + DT_THISPROCNUM)
- tag = dyn->d_tag - DT_LOPROC + DT_NUM;
- else if ((d_tag_utype) DT_VERSIONTAGIDX (dyn->d_tag) < DT_VERSIONTAGNUM)
- tag = VERSYMIDX (dyn->d_tag);
- else if ((d_tag_utype) DT_EXTRATAGIDX (dyn->d_tag) < DT_EXTRANUM)
- tag = DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
- + DT_VERSIONTAGNUM;
- else if ((d_tag_utype) DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM)
- tag = DT_VALTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
- + DT_VERSIONTAGNUM + DT_EXTRANUM;
- else if ((d_tag_utype) DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM)
- tag = DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
- + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM;
- if (tag)
- l->l_info[tag] = dyn;
- ++dyn;
- }
- if (l->l_addr) {
- # define ADJUST_DYN_INFO(tag) \
- do { \
- if (l->l_info[tag] != NULL) { \
- l->l_info[tag]->d_un.d_ptr = \
- RELOCATE(l, l->l_info[tag]->d_un.d_ptr); \
- /* debug("relocate info[%d] = %p\n", \
- tag, l->l_info[tag]->d_un.d_ptr); */ \
- } \
- } while(0);
- ADJUST_DYN_INFO (DT_HASH);
- ADJUST_DYN_INFO (DT_PLTGOT);
- ADJUST_DYN_INFO (DT_STRTAB);
- ADJUST_DYN_INFO (DT_SYMTAB);
- # if ! ELF_MACHINE_NO_RELA
- ADJUST_DYN_INFO (DT_RELA);
- # endif
- # if ! ELF_MACHINE_NO_REL
- ADJUST_DYN_INFO (DT_REL);
- # endif
- ADJUST_DYN_INFO (DT_JMPREL);
- ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM));
- ADJUST_DYN_INFO (DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM
- + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM);
- # undef ADJUST_DYN_INFO
- }
- /* Then a bunch of assertion, we could kind of ignore them */
- if (l->l_info[DT_PLTREL] != NULL) {
- #if ELF_MACHINE_NO_RELA
- assert (l->l_info[DT_PLTREL]->d_un.d_val == DT_REL);
- #elif ELF_MACHINE_NO_REL
- assert (l->l_info[DT_PLTREL]->d_un.d_val == DT_RELA);
- #else
- assert (l->l_info[DT_PLTREL]->d_un.d_val == DT_REL
- || l->l_info[DT_PLTREL]->d_un.d_val == DT_RELA);
- #endif
- }
- #if ! ELF_MACHINE_NO_RELA
- if (l->l_info[DT_RELA] != NULL)
- assert (l->l_info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela)));
- # endif
- # if ! ELF_MACHINE_NO_REL
- if (l->l_info[DT_REL] != NULL)
- assert (l->l_info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel)));
- #endif
- }
- /* Get the definitions of `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.
- These functions are almost identical, so we use cpp magic to avoid
- duplicating their code. It cannot be done in a more general function
- because we must be able to completely inline. */
- /* On some machines, notably SPARC, DT_REL* includes DT_JMPREL in its
- range. Note that according to the ELF spec, this is completely legal!
- But conditionally define things so that on machines we know this will
- not happen we do something more optimal. */
- #ifdef ELF_MACHINE_PLTREL_OVERLAP
- /* ELF_MACHINE_PLTREL_OVERLAP is only used for s390, powerpc and sparc.
- We will keep it for now */
- static void
- _elf_dynamic_do_reloc(struct link_map * l, int dt_reloc, int dt_reloc_sz,
- void (*do_reloc) (struct link_map *, ElfW(Addr), int))
- {
- struct { ElfW(Addr) start, size; } ranges[3];
- ranges[0].size = ranges[1].size = ranges[2].size = 0;
- if (l->l_info[dt_reloc]) {
- ranges[0].start = D_PTR (l->l_info[dt_reloc]);
- ranges[0].size = l->l_info[dt_reloc_sz]->d_un.d_val;
- }
- for (int ranges_index = 0; ranges_index < 3; ++ranges_index)
- (*do_reloc) (l,
- ranges[ranges_index].start,
- ranges[ranges_index].size);
- }
- #else
- /* Now this part is for our x86s machines */
- static void __attribute__((unused))
- _elf_dynamic_do_reloc(struct link_map * l, int dt_reloc, int dt_reloc_sz,
- void (*do_reloc) (struct link_map * l, ElfW(Addr), int))
- {
- struct { ElfW(Addr) start, size; } ranges[2];
- ranges[0].size = ranges[1].size = 0;
- ranges[0].start = ranges[1].start = 0;
- if (l->l_info[dt_reloc]) {
- ranges[0].start = D_PTR (l->l_info[dt_reloc]);
- ranges[0].size = l->l_info[dt_reloc_sz]->d_un.d_val;
- }
- if (l->l_info[DT_PLTREL]
- && l->l_info[DT_PLTREL]->d_un.d_val == dt_reloc) {
- ElfW(Addr) start = D_PTR (l->l_info[DT_JMPREL]);
- /* This test does not only detect whether the relocation
- sections are in the right order, it also checks whether
- there is a DT_REL/DT_RELA section. */
- if (ranges[0].start + ranges[0].size != start) {
- ranges[1].start = start;
- ranges[1].size = l->l_info[DT_PLTRELSZ]->d_un.d_val;
- } else {
- /* Combine processing the sections. */
- assert (ranges[0].start + ranges[0].size == start);
- ranges[0].size += l->l_info[DT_PLTRELSZ]->d_un.d_val;
- }
- }
- for (int ranges_index = 0; ranges_index < 2; ++ranges_index)
- (*do_reloc) (l,
- ranges[ranges_index].start,
- ranges[ranges_index].size);
- }
- #endif
- #define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, l) \
- _elf_dynamic_do_reloc(l, DT_##RELOC, DT_##RELOC##SZ, \
- &elf_dynamic_do_##reloc)
- #if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA
- # define _ELF_CHECK_REL 0
- #else
- # define _ELF_CHECK_REL 1
- #endif
- #if ! ELF_MACHINE_NO_REL
- # include "do-rel.h"
- # define ELF_DYNAMIC_DO_REL(l) \
- _ELF_DYNAMIC_DO_RELOC (REL, rel, l)
- # define ELF_DYNAMIC_COPY_REL(l1, l2) elf_dynamic_copy_rel(l1, l2)
- #else
- /* nothing to do */
- # define ELF_DYNAMIC_DO_REL(l)
- # define ELF_DYNAMIC_COPY_REL(l1, l2)
- #endif
- #if ! ELF_MACHINE_NO_RELA
- # define DO_RELA
- # include "do-rel.h"
- # define ELF_DYNAMIC_DO_RELA(l) \
- _ELF_DYNAMIC_DO_RELOC (RELA, rela, l)
- # define ELF_DYNAMIC_COPY_RELA(l1, l2) elf_dynamic_copy_rela(l, l2)
- #else
- /* nothing to do */
- # define ELF_DYNAMIC_DO_RELA(l)
- # define ELF_DYNAMIC_COPY_RELA(l1, l2)
- #endif
- /* This can't just be an inline function because GCC is too dumb
- to inline functions containing inlines themselves. */
- # define ELF_DYNAMIC_RELOCATE(l) \
- do { \
- ELF_DYNAMIC_DO_REL(l); \
- ELF_DYNAMIC_DO_RELA(l); \
- } while (0)
- #define ELF_DYNAMIC_COPY(l1, l2) \
- do { \
- ELF_DYNAMIC_COPY_REL(l1, l2); \
- ELF_DYNAMIC_COPY_RELA(l1, l2); \
- } while (0)
|