📄 dl-machine.h
字号:
/* Machine-dependent ELF dynamic relocation inline functions. Sparc64 version. Copyright (C) 1997,1998,1999,2000,2001,2002 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 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. */#define ELF_MACHINE_NAME "sparc64"#include <string.h>#include <sys/param.h>#include <ldsodefs.h>#include <sysdep.h>#ifndef VALIDX# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \ + DT_EXTRANUM + DT_VALTAGIDX (tag))#endif#define ELF64_R_TYPE_ID(info) ((info) & 0xff)#define ELF64_R_TYPE_DATA(info) ((info) >> 8)/* Return nonzero iff ELF header is compatible with the running host. */static inline intelf_machine_matches_host (const Elf64_Ehdr *ehdr){ return ehdr->e_machine == EM_SPARCV9;}/* We have to do this because elf_machine_{dynamic,load_address} can be invoked from functions that have no GOT references, and thus the compiler has no obligation to load the PIC register. */#define LOAD_PIC_REG(PIC_REG) \do { Elf64_Addr tmp; \ __asm("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t" \ "rd %%pc, %0\n\t" \ "add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t" \ "add %0, %1, %0" \ : "=r" (PIC_REG), "=r" (tmp)); \} while (0)/* 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 Elf64_Addrelf_machine_dynamic (void){ register Elf64_Addr *elf_pic_register __asm__("%l7"); LOAD_PIC_REG (elf_pic_register); return *elf_pic_register;}/* Return the run-time load address of the shared object. */static inline Elf64_Addrelf_machine_load_address (void){ register Elf32_Addr *pc __asm ("%o7"); register Elf64_Addr *got __asm ("%l7"); __asm ("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t" "call 1f\n\t" " add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t" "call _DYNAMIC\n\t" "call _GLOBAL_OFFSET_TABLE_\n" "1:\tadd %1, %0, %1\n\t" : "=r" (pc), "=r" (got)); /* got is now l_addr + _GLOBAL_OFFSET_TABLE_ *got is _DYNAMIC pc[2]*4 is l_addr + _DYNAMIC - (long)pc - 8 pc[3]*4 is l_addr + _GLOBAL_OFFSET_TABLE_ - (long)pc - 12 */ return (Elf64_Addr) got - *got + (Elf32_Sword) ((pc[2] - pc[3]) * 4) - 4;}/* We have 4 cases to handle. And we code different code sequences for each one. I love V9 code models... */static inline voidsparc64_fixup_plt (struct link_map *map, const Elf64_Rela *reloc, Elf64_Addr *reloc_addr, Elf64_Addr value, Elf64_Addr high, int t){ unsigned int *insns = (unsigned int *) reloc_addr; Elf64_Addr plt_vaddr = (Elf64_Addr) reloc_addr; Elf64_Sxword disp = value - plt_vaddr; /* Now move plt_vaddr up to the call instruction. */ plt_vaddr += ((t + 1) * 4); /* PLT entries .PLT32768 and above look always the same. */ if (__builtin_expect (high, 0) != 0) { *reloc_addr = value - map->l_addr; } /* Near destination. */ else if (disp >= -0x800000 && disp < 0x800000) { /* As this is just one instruction, it is thread safe and so we can avoid the unnecessary sethi FOO, %g1. b,a target */ insns[0] = 0x30800000 | ((disp >> 2) & 0x3fffff); __asm __volatile ("flush %0" : : "r" (insns)); } /* 32-bit Sparc style, the target is in the lower 32-bits of address space. */ else if (insns += t, (value >> 32) == 0) { /* sethi %hi(target), %g1 jmpl %g1 + %lo(target), %g0 */ insns[1] = 0x81c06000 | (value & 0x3ff); __asm __volatile ("flush %0 + 4" : : "r" (insns)); insns[0] = 0x03000000 | ((unsigned int)(value >> 10)); __asm __volatile ("flush %0" : : "r" (insns)); } /* We can also get somewhat simple sequences if the distance between the target and the PLT entry is within +/- 2GB. */ else if ((plt_vaddr > value && ((plt_vaddr - value) >> 31) == 0) || (value > plt_vaddr && ((value - plt_vaddr) >> 31) == 0)) { unsigned int displacement; if (plt_vaddr > value) displacement = (0 - (plt_vaddr - value)); else displacement = value - plt_vaddr; /* mov %o7, %g1 call displacement mov %g1, %o7 */ insns[2] = 0x9e100001; __asm __volatile ("flush %0 + 8" : : "r" (insns)); insns[1] = 0x40000000 | (displacement >> 2); __asm __volatile ("flush %0 + 4" : : "r" (insns)); insns[0] = 0x8210000f; __asm __volatile ("flush %0" : : "r" (insns)); } /* Worst case, ho hum... */ else { unsigned int high32 = (value >> 32); unsigned int low32 = (unsigned int) value; /* ??? Some tricks can be stolen from the sparc64 egcs backend constant formation code I wrote. -DaveM */ if (__builtin_expect (high32 & 0x3ff, 0)) { /* sethi %hh(value), %g1 sethi %lm(value), %g5 or %g1, %hm(value), %g1 or %g5, %lo(value), %g5 sllx %g1, 32, %g1 jmpl %g1 + %g5, %g0 nop */ insns[5] = 0x81c04005; __asm __volatile ("flush %0 + 20" : : "r" (insns)); insns[4] = 0x83287020; __asm __volatile ("flush %0 + 16" : : "r" (insns)); insns[3] = 0x8a116000 | (low32 & 0x3ff); __asm __volatile ("flush %0 + 12" : : "r" (insns)); insns[2] = 0x82106000 | (high32 & 0x3ff); } else { /* sethi %hh(value), %g1 sethi %lm(value), %g5 sllx %g1, 32, %g1 or %g5, %lo(value), %g5 jmpl %g1 + %g5, %g0 nop */ insns[4] = 0x81c04005; __asm __volatile ("flush %0 + 16" : : "r" (insns)); insns[3] = 0x8a116000 | (low32 & 0x3ff); __asm __volatile ("flush %0 + 12" : : "r" (insns)); insns[2] = 0x83287020; } __asm __volatile ("flush %0 + 8" : : "r" (insns)); insns[1] = 0x0b000000 | (low32 >> 10); __asm __volatile ("flush %0 + 4" : : "r" (insns)); insns[0] = 0x03000000 | (high32 >> 10); __asm __volatile ("flush %0" : : "r" (insns)); }}static inline Elf64_Addrelf_machine_fixup_plt (struct link_map *map, lookup_t t, const Elf64_Rela *reloc, Elf64_Addr *reloc_addr, Elf64_Addr value){ sparc64_fixup_plt (map, reloc, reloc_addr, value + reloc->r_addend, reloc->r_addend, 1); return value;}/* Return the final value of a plt relocation. */static inline Elf64_Addrelf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc, Elf64_Addr value){ /* Don't add addend here, but in elf_machine_fixup_plt instead. value + reloc->r_addend is the value which should actually be stored into .plt data slot. */ return value;}#ifdef RESOLVE/* Perform the relocation specified by RELOC and SYM (which is fully resolved). MAP is the object containing the reloc. */static inline voidelf_machine_rela (struct link_map *map, const Elf64_Rela *reloc, const Elf64_Sym *sym, const struct r_found_version *version, Elf64_Addr *const reloc_addr){ const unsigned long int r_type = ELF64_R_TYPE_ID (reloc->r_info);#if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC if (__builtin_expect (r_type == R_SPARC_RELATIVE, 0)) *reloc_addr = map->l_addr + reloc->r_addend;# ifndef RTLD_BOOTSTRAP else if (r_type == R_SPARC_NONE) /* Who is Wilbur? */ return;# endif else#endif {#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP const Elf64_Sym *const refsym = sym;#endif Elf64_Addr value;#ifndef RESOLVE_CONFLICT_FIND_MAP if (sym->st_shndx != SHN_UNDEF && ELF64_ST_BIND (sym->st_info) == STB_LOCAL) value = map->l_addr; else { value = RESOLVE (&sym, version, r_type); if (sym) value += sym->st_value; }#else value = 0;#endif value += reloc->r_addend; /* Assume copy relocs have zero addend. */ switch (r_type) {#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP case R_SPARC_COPY: if (sym == NULL) /* This can happen in trace mode if an object could not be found. */ break; if (sym->st_size > refsym->st_size || (GL(dl_verbose) && sym->st_size < refsym->st_size)) { const char *strtab; strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); _dl_error_printf ("\%s: Symbol `%s' has different size in shared object, consider re-linking\n", rtld_progname ?: "<program name unknown>", strtab + refsym->st_name); } memcpy (reloc_addr, (void *) value, MIN (sym->st_size, refsym->st_size)); break;#endif case R_SPARC_64: case R_SPARC_GLOB_DAT: *reloc_addr = value; break;#ifndef RTLD_BOOTSTRAP case R_SPARC_8: *(char *) reloc_addr = value; break; case R_SPARC_16: *(short *) reloc_addr = value; break; case R_SPARC_32: *(unsigned int *) reloc_addr = value; break; case R_SPARC_DISP8: *(char *) reloc_addr = (value - (Elf64_Addr) reloc_addr); break; case R_SPARC_DISP16: *(short *) reloc_addr = (value - (Elf64_Addr) reloc_addr); break; case R_SPARC_DISP32: *(unsigned int *) reloc_addr = (value - (Elf64_Addr) reloc_addr); break; case R_SPARC_WDISP30: *(unsigned int *) reloc_addr = ((*(unsigned int *)reloc_addr & 0xc0000000) | ((value - (Elf64_Addr) reloc_addr) >> 2)); break; /* MEDLOW code model relocs */ case R_SPARC_LO10: *(unsigned int *) reloc_addr = ((*(unsigned int *)reloc_addr & ~0x3ff) | (value & 0x3ff)); break; case R_SPARC_HI22: *(unsigned int *) reloc_addr = ((*(unsigned int *)reloc_addr & 0xffc00000) | (value >> 10)); break; case R_SPARC_OLO10: *(unsigned int *) reloc_addr = ((*(unsigned int *)reloc_addr & ~0x1fff) | (((value & 0x3ff) + ELF64_R_TYPE_DATA (reloc->r_info)) & 0x1fff)); break; /* MEDMID code model relocs */ case R_SPARC_H44: *(unsigned int *) reloc_addr = ((*(unsigned int *)reloc_addr & 0xffc00000) | (value >> 22)); break; case R_SPARC_M44: *(unsigned int *) reloc_addr = ((*(unsigned int *)reloc_addr & ~0x3ff) | ((value >> 12) & 0x3ff)); break; case R_SPARC_L44: *(unsigned int *) reloc_addr = ((*(unsigned int *)reloc_addr & ~0xfff) | (value & 0xfff)); break; /* MEDANY code model relocs */ case R_SPARC_HH22: *(unsigned int *) reloc_addr = ((*(unsigned int *)reloc_addr & 0xffc00000) | (value >> 42)); break; case R_SPARC_HM10: *(unsigned int *) reloc_addr = ((*(unsigned int *)reloc_addr & ~0x3ff) | ((value >> 32) & 0x3ff)); break; case R_SPARC_LM22: *(unsigned int *) reloc_addr = ((*(unsigned int *)reloc_addr & 0xffc00000) | ((value >> 10) & 0x003fffff)); break;#endif case R_SPARC_JMP_SLOT:#ifdef RESOLVE_CONFLICT_FIND_MAP /* R_SPARC_JMP_SLOT conflicts against .plt[32768+] relocs should be turned into R_SPARC_64 relocs
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -