📄 dl-machine.h
字号:
/* Machine-dependent ELF dynamic relocation inline functions. MIPS64 version. Copyright (C) 1996,1997,1999,2000,2001,2002 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Kazumoto Kojima <kkojima@info.kanagawa-u.ac.jp>. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */#ifndef dl_machine_h#define dl_machine_h#define ELF_MACHINE_NAME "MIPS"#define ELF_MACHINE_NO_PLT#include <entry.h>#ifndef ENTRY_POINT#error ENTRY_POINT needs to be defined for MIPS.#endif#ifndef _RTLD_PROLOGUE# define _RTLD_PROLOGUE(entry) "\n\t.globl " __STRING(entry) \ "\n\t.ent " __STRING(entry) \ "\n\t" __STRING(entry) ":\n\t"#endif#ifndef _RTLD_EPILOGUE# define _RTLD_EPILOGUE(entry) "\t.end " __STRING(entry) "\n"#endif/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. This makes no sense on MIPS but we have to define this to R_MIPS_REL32 to avoid the asserts in dl-lookup.c from blowing. */#define ELF_MACHINE_JMP_SLOT R_MIPS_REL32#define elf_machine_type_class(type) ELF_RTYPE_CLASS_PLT/* Translate a processor specific dynamic tag to the index in l_info array. */#define DT_MIPS(x) (DT_MIPS_##x - DT_LOPROC + DT_NUM)#if 0/* We may need 64k alignment. */#define ELF_MACHINE_ALIGN_MASK 0xffff#endif/* * MIPS libraries are usually linked to a non-zero base address. We * subtrace the base address from the address where we map the object * to. This results in more efficient address space usage. */#if 0#define MAP_BASE_ADDR(l) ((l)->l_info[DT_MIPS(BASE_ADDRESS)] ? \ (l)->l_info[DT_MIPS(BASE_ADDRESS)]->d_un.d_ptr : 0)#else#define MAP_BASE_ADDR(l) 0x5ffe0000#endif/* If there is a DT_MIPS_RLD_MAP entry in the dynamic section, fill it in with the run-time address of the r_debug structure */#define ELF_MACHINE_DEBUG_SETUP(l,r) \do { if ((l)->l_info[DT_MIPS (RLD_MAP)]) \ *(ElfW(Addr) *)((l)->l_info[DT_MIPS (RLD_MAP)]->d_un.d_ptr) = \ (ElfW(Addr)) (r); \ } while (0)/* Return nonzero iff ELF header is compatible with the running host. */static inline int __attribute__ ((unused))elf_machine_matches_host (const ElfW(Ehdr) *ehdr){ switch (ehdr->e_machine) { case EM_MIPS: case EM_MIPS_RS3_LE: return 1; default: return 0; }}static inline ElfW(Addr) *elf_mips_got_from_gpreg (ElfW(Addr) gpreg){ /* FIXME: the offset of gp from GOT may be system-dependent. */ return (ElfW(Addr) *) (gpreg - 0x7ff0);}/* Return the link-time address of _DYNAMIC. Conveniently, this is the first element of the GOT. This must be inlined in a function which uses global data. */static inline ElfW(Addr)elf_machine_dynamic (void){ register ElfW(Addr) gp __asm__ ("$28"); return *elf_mips_got_from_gpreg (gp);}/* Return the run-time load address of the shared object. */static inline ElfW(Addr)elf_machine_load_address (void){ ElfW(Addr) addr; asm (" .set noreorder\n" " dla %0, here\n" " bltzal $0, here\n" " nop\n" "here: dsubu %0, $31, %0\n" " .set reorder\n" : "=r" (addr) : /* No inputs */ : "$31"); return addr;}/* The MSB of got[1] of a gnu object is set to identify gnu objects. */#define ELF_MIPS_GNU_GOT1_MASK 0x80000000/* Relocate GOT. */static inline voidelf_machine_got_rel (struct link_map *map, int lazy){ ElfW(Addr) *got; ElfW(Sym) *sym; int i, n; const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);#define RESOLVE_GOTSYM(sym) \ ({ \ const ElfW(Sym) *ref = sym; \ ElfW(Addr) sym_loadaddr; \ sym_loadaddr = _dl_lookup_symbol (strtab + sym->st_name, &ref, \ map->l_scope, \ map->l_name, R_MIPS_REL32);\ (ref)? sym_loadaddr + ref->st_value: 0; \ }) got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]); /* got[0] is reserved. got[1] is also reserved for the dynamic object generated by gnu ld. Skip these reserved entries from relocation. */ i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2: 1; n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val; /* Add the run-time display to all local got entries. */ while (i < n) got[i++] += map->l_addr; /* Handle global got entries. */ got += n; sym = (ElfW(Sym) *) D_PTR (map, l_info[DT_SYMTAB]); sym += map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val; i = (map->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val - map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val); while (i--) { if (sym->st_shndx == SHN_UNDEF) { if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC) { if (sym->st_value && lazy) *got = sym->st_value + map->l_addr; else *got = RESOLVE_GOTSYM (sym); } else /* if (*got == 0 || *got == QS) */ *got = RESOLVE_GOTSYM (sym); } else if (sym->st_shndx == SHN_COMMON) *got = RESOLVE_GOTSYM (sym); else if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC && *got != sym->st_value && lazy) *got += map->l_addr; else if (ELFW(ST_TYPE) (sym->st_info) == STT_SECTION) { if (sym->st_other == 0) *got += map->l_addr; } else *got = RESOLVE_GOTSYM (sym); got++; sym++; }#undef RESOLVE_GOTSYM return;}/* Set up the loaded object described by L so its stub function will jump to the on-demand fixup code in dl-runtime.c. */static inline intelf_machine_runtime_setup (struct link_map *l, int lazy, int profile){ ElfW(Addr) *got; extern void _dl_runtime_resolve (ElfW(Word)); extern int _dl_mips_gnu_objects;#ifdef RTLD_BOOTSTRAP { return lazy; }#endif if (lazy) { /* The GOT entries for functions have not yet been filled in. Their initial contents will arrange when called to put an offset into the .dynsym section in t8, the return address in t7 and then jump to _GLOBAL_OFFSET_TABLE[0]. */ got = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]); /* This function will get called to fix up the GOT entry indicated by the register t8, and then jump to the resolved address. */ got[0] = (ElfW(Addr)) &_dl_runtime_resolve; /* Store l to _GLOBAL_OFFSET_TABLE[1] for gnu object. The MSB of got[1] of a gnu object is set to identify gnu objects. Where we can store l for non gnu objects? XXX */ if ((got[1] & ELF_MIPS_GNU_GOT1_MASK) != 0) got[1] = (ElfW(Addr)) ((unsigned) l | ELF_MIPS_GNU_GOT1_MASK); else _dl_mips_gnu_objects = 0; } /* Relocate global offset table. */ elf_machine_got_rel (l, lazy); return lazy;}/* Get link_map for this object. */static inline struct link_map *elf_machine_runtime_link_map (ElfW(Addr) gpreg, ElfW(Addr) stub_pc){ extern int _dl_mips_gnu_objects; /* got[1] is reserved to keep its link map address for the shared object generated by the gnu linker. If all are such objects, we can find the link map from current GPREG simply. If not so, get the link map for caller's object containing STUB_PC. */ if (_dl_mips_gnu_objects) { ElfW(Addr) *got = elf_mips_got_from_gpreg (gpreg); ElfW(Word) g1; g1 = ((ElfW(Word) *) got)[1]; if ((g1 & ELF_MIPS_GNU_GOT1_MASK) != 0) { struct link_map *l = (struct link_map *) (g1 & ~ELF_MIPS_GNU_GOT1_MASK); ElfW(Addr) base, limit; const ElfW(Phdr) *p = l->l_phdr; ElfW(Half) this, nent = l->l_phnum; /* For the common case of a stub being called from the containing object, STUB_PC will point to somewhere within the object that is described by the link map fetched via got[1]. Otherwise we have to scan all maps. */ for (this = 0; this < nent; this++) { if (p[this].p_type == PT_LOAD) { base = p[this].p_vaddr + l->l_addr; limit = base + p[this].p_memsz; if (stub_pc >= base && stub_pc < limit) return l; } this++; } } } { struct link_map *l = GL(dl_loaded); while (l) { ElfW(Addr) base, limit; const ElfW(Phdr) *p = l->l_phdr; ElfW(Half) this, nent = l->l_phnum;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -