diff options
author | Ulrich Drepper <drepper@redhat.com> | 2001-12-12 00:21:26 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2001-12-12 00:21:26 +0000 |
commit | 32e6df3621edc5067dfd6e87a387e1751f67f708 (patch) | |
tree | 957300a92ed16417fb46ce240d19f965fe773181 /sysdeps/sparc | |
parent | 4be601a15e63d03adf55c48c19dda2d2e7377d8a (diff) | |
download | glibc-32e6df3621edc5067dfd6e87a387e1751f67f708.tar glibc-32e6df3621edc5067dfd6e87a387e1751f67f708.tar.gz glibc-32e6df3621edc5067dfd6e87a387e1751f67f708.tar.bz2 glibc-32e6df3621edc5067dfd6e87a387e1751f67f708.zip |
Update.
2001-12-11 Jakub Jelinek <jakub@redhat.com>
* elf/Makefile (dl-routines): Add conflict.
(rtld-ldscript-in, rtld-ldscript, rtld-parms): Remove.
(ld.so): Add _begin local symbol.
* elf/elf.h (DT_VALTAGIDX, DT_VALNUM, DT_ADDRTAGIDX, DT_ADDRNUM):
Define.
* elf/dl-deps.c (_dl_build_local_scope): New.
(_dl_map_object_deps): If LD_TRACE_PRELINKING, compute local scopes
of all libraries.
* elf/do-rel.h (VALIDX): Define.
(elf_dynamic_do_rel): If ELF_MACHINE_PLT_REL is defined, don't do
lazy binding for RELA. If DT_GNU_PRELINKED, DT_RELACOUNT relocations
can be skipped.
* elf/dl-conflict.c: New file.
* elf/dl-lookup.c (_dl_debug_bindings): New.
(_dl_lookup_symbol): Use _dl_debug_bindings. Reference_name is always
non-NULL.
(_dl_lookup_symbol_skip): Likewise.
(_dl_lookup_versioned_symbol): Likewise.
(_dl_lookup_versioned_symbol_skip): Likewise.
* elf/dl-runtime.c (PLTREL): If ELF_MACHINE_PLT_REL is defined,
define to ElfW(Rel).
* elf/dynamic-link.h (elf_get_dynamic_info): Record selected dynamic
tags in the DT_VALRNGLO..DT_VALRNGHI and DT_ADDRRNGLO..DT_ADDRRNGHI
ranges.
Don't adjust address dynamic tags if l_addr is 0.
* elf/rtld.c (_dl_trace_prelink, _dl_trace_prelink_map): New variables.
(_dl_start): Skip ELF_DYNAMIC_RELOCATE if ld.so is prelinked.
(VALIDX, ADDRIDX): Define.
(_dl_start_final): Initialize _dl_rtld_map's l_map_start and l_map_end.
(dl_main): Print library list for LD_TRACE_PRELINKING.
If prelinking information can be used, skip relocating libraries and
call _dl_resolve_conflicts instead.
(process_envvars): Handle LD_TRACE_PRELINKING envvar.
* elf/dl-load.c (_dl_map_object): Don't create fake libs
if LD_TRACE_PRELINKING.
* include/link.h (struct link_map) [l_info]: Add DT_VALNUM
+ DT_ADDRNUM.
* sysdeps/generic/ldsodefs.h (_dl_trace_prelink_map): New declaration.
(DL_DEBUG_PRELINK): Define.
(_dl_resolve_conflicts): Add prototype.
* sysdeps/alpha/dl-machine.h (elf_machine_runtime_setup): Reinitialize
.plt for prelinked libraries where prelinking info cannot be used.
(elf_machine_rela): If relocating R_ALPHA_JMP_SLOT in .gnu.conflict
section, use RESOLVE_CONFLICT_FIND_MAP to find out reloc's link_map.
* sysdeps/arm/bits/link.h: New file.
* sysdeps/arm/dl-machine.h (elf_machine_runtime_setup): Save original
content of .got[1].
(ELF_MACHINE_NO_RELA): Only define if RTLD_BOOTSTRAP.
(ELF_MACHINE_PLT_REL): Define.
(elf_machine_rela, elf_machine_rela_relative): New.
(elf_machine_lazy_rel): Reinitialize R_ARM_JUMP_SLOT address instead
of adjusting it if prelinked and prelinking cannot be used.
* sysdeps/i386/bits/link.h: New file.
* sysdeps/i386/dl-machine.h (elf_machine_runtime_setup): Save original
content of .got[1].
(ELF_MACHINE_NO_RELA): Only define if RTLD_BOOTSTRAP.
(ELF_MACHINE_PLT_REL): Define.
(elf_machine_rela, elf_machine_rela_relative): New.
(elf_machine_lazy_rel): Reinitialize R_386_JUMP_SLOT address instead
of adjusting it if prelinked and prelinking cannot be used.
* sysdeps/powerpc/dl-machine.h (elf_machine_rela): If relocating
conflicts, skip finaladdr computation. Use RESOLVE_CONFLICT_FIND_MAP
to find out map for R_PPC_JMP_SLOT relocs.
* sysdeps/sparc/sparc32/dl-machine.h (VALIDX): Define.
(OPCODE_BA): Define.
(elf_machine_runtime_setup): Reinitialize .plt for prelinked
libraries where prelinking info cannot be used.
(sparc_fixup_plt): Renamed from elf_machine_fixup_plt.
(elf_machine_fixup_plt): Call sparc_fixup_plt.
(elf_machine_rela): Set value to 0 if relocating conflicts.
Call sparc_fixup_plt for R_SPARC_JMP_SLOT.
* sysdeps/sparc/sparc64/dl-machine.h (VALIDX): Define.
(sparc64_fixup_plt): Fix a typo.
(elf_machine_rela): Set value to 0 if relocating conflicts.
Handle R_SPARC_JMP_SLOT relocs when relocating conflicts.
(elf_machine_runtime_setup): Reinitialize .plt for prelinked
libraries where prelinking info cannot be used.
* sysdeps/sh/bits/link.h: New file.
* sysdeps/sh/dl-machine.h (elf_machine_runtime_setup): Save original
content of .got[1].
(elf_machine_lazy_rel): Reinitialize R_SH_JMP_SLOT address instead
of adjusting it if prelinked and prelinking cannot be used.
* sysdeps/s390/s390-32/bits/link.h: New file.
* sysdeps/s390/s390-32/dl-machine.h (elf_machine_runtime_setup):
Save original content of .got[1].
(elf_machine_lazy_rel): Reinitialize R_390_JMP_SLOT address instead
of adjusting it if prelinked and prelinking cannot be used.
* sysdeps/s390/s390-64/bits/link.h: New file.
* sysdeps/s390/s390-64/dl-machine.h (elf_machine_runtime_setup):
Save original content of .got[1].
(elf_machine_lazy_rel): Reinitialize R_390_JMP_SLOT address instead
of adjusting it if prelinked and prelinking cannot be used.
* sysdeps/x86_64/bits/link.h: New file.
* sysdeps/x86_64/dl-machine.h (elf_machine_runtime_setup):
Save original content of .got[1].
(elf_machine_lazy_rel): Reinitialize R_X86_64_JMP_SLOT address instead
of adjusting it if prelinked and prelinking cannot be used.
Diffstat (limited to 'sysdeps/sparc')
-rw-r--r-- | sysdeps/sparc/sparc32/dl-machine.h | 99 | ||||
-rw-r--r-- | sysdeps/sparc/sparc64/dl-machine.h | 66 |
2 files changed, 144 insertions, 21 deletions
diff --git a/sysdeps/sparc/sparc32/dl-machine.h b/sysdeps/sparc/sparc32/dl-machine.h index d98848b5dd..19a3897edb 100644 --- a/sysdeps/sparc/sparc32/dl-machine.h +++ b/sysdeps/sparc/sparc32/dl-machine.h @@ -23,6 +23,10 @@ #include <sys/param.h> #include <ldsodefs.h> +#ifndef VALIDX +# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \ + + DT_EXTRANUM + DT_VALTAGIDX (tag)) +#endif /* Some SPARC opcodes we need to use for self-modifying code. */ #define OPCODE_NOP 0x01000000 /* nop */ @@ -30,6 +34,7 @@ #define OPCODE_SETHI_G1 0x03000000 /* sethi ?, %g1; add value>>10 */ #define OPCODE_JMP_G1 0x81c06000 /* jmp %g1+?; add lo 10 bits of value */ #define OPCODE_SAVE_SP 0x9de3bfa8 /* save %sp, -(16+6)*4, %sp */ +#define OPCODE_BA 0x30800000 /* b,a ?; add PC-rel word address */ /* Protect some broken versions of gcc from misinterpreting weak addresses. */ #define WEAKADDR(x) ({ __typeof(x) *_px = &x; \ @@ -139,6 +144,37 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) plt[1] = OPCODE_CALL | ((rfunc - (Elf32_Addr) &plt[1]) >> 2); plt[2] = OPCODE_NOP; /* Fill call delay slot. */ plt[3] = (Elf32_Addr) l; + if (__builtin_expect (l->l_info[VALIDX(DT_GNU_PRELINKED)] != NULL, 0) + || __builtin_expect (l->l_info [VALIDX (DT_GNU_LIBLISTSZ)] != NULL, 0)) + { + /* Need to reinitialize .plt to undo prelinking. */ + unsigned long *hwcap; + int do_flush; + Elf32_Rela *rela = (Elf32_Rela *) D_PTR (l, l_info[DT_JMPREL]); + Elf32_Rela *relaend + = (Elf32_Rela *) ((char *) rela + + l->l_info[DT_PLTRELSZ]->d_un.d_val); + weak_extern (_dl_hwcap); + hwcap = WEAKADDR(_dl_hwcap); + do_flush = (!hwcap || (*hwcap & HWCAP_SPARC_FLUSH)); + + /* prelink must ensure there are no R_SPARC_NONE relocs left + in .rela.plt. */ + while (rela < relaend) + { + *(unsigned int *) rela->r_offset + = OPCODE_SETHI_G1 | (rela->r_offset - (Elf32_Addr) plt); + *(unsigned int *) (rela->r_offset + 4) + = OPCODE_BA | ((((Elf32_Addr) plt + - rela->r_offset - 4) >> 2) & 0x3fffff); + if (do_flush) + { + __asm __volatile ("flush %0" : : "r"(rela->r_offset)); + __asm __volatile ("flush %0+4" : : "r"(rela->r_offset)); + } + ++rela; + } + } } return lazy; @@ -292,10 +328,10 @@ _dl_start_user: .previous"); static inline Elf32_Addr -elf_machine_fixup_plt (struct link_map *map, lookup_t t, - const Elf32_Rela *reloc, - Elf32_Addr *reloc_addr, Elf32_Addr value) +sparc_fixup_plt (const Elf32_Rela *reloc, Elf32_Addr *reloc_addr, + Elf32_Addr value, int t) { + Elf32_Sword disp = value - (Elf32_Addr) reloc_addr; #ifndef RTLD_BOOTSTRAP /* Note that we don't mask the hwcap here, as the flush is essential to functionality on those cpu's that implement it. */ @@ -309,23 +345,44 @@ elf_machine_fixup_plt (struct link_map *map, lookup_t t, ld.so will not execute corrupt PLT entry instructions. */ const int do_flush = 1; #endif + + if (0 && disp >= -0x800000 && disp < 0x800000) + { + /* Don't need to worry about thread safety. We're writing just one + instruction. */ - /* For thread safety, write the instructions from the bottom and - flush before we overwrite the critical "b,a". This of course - need not be done during bootstrapping, since there are no threads. - But we also can't tell if we _can_ use flush, so don't. */ - - reloc_addr[2] = OPCODE_JMP_G1 | (value & 0x3ff); - if (do_flush) - __asm __volatile ("flush %0+8" : : "r"(reloc_addr)); - - reloc_addr[1] = OPCODE_SETHI_G1 | (value >> 10); - if (do_flush) - __asm __volatile ("flush %0+4" : : "r"(reloc_addr)); + reloc_addr[0] = OPCODE_BA | ((disp >> 2) & 0x3fffff); + if (do_flush) + __asm __volatile ("flush %0" : : "r"(reloc_addr)); + } + else + { + /* For thread safety, write the instructions from the bottom and + flush before we overwrite the critical "b,a". This of course + need not be done during bootstrapping, since there are no threads. + But we also can't tell if we _can_ use flush, so don't. */ + + reloc_addr += t; + reloc_addr[1] = OPCODE_JMP_G1 | (value & 0x3ff); + if (do_flush) + __asm __volatile ("flush %0+4" : : "r"(reloc_addr)); + + reloc_addr[0] = OPCODE_SETHI_G1 | (value >> 10); + if (do_flush) + __asm __volatile ("flush %0" : : "r"(reloc_addr)); + } return value; } +static inline Elf32_Addr +elf_machine_fixup_plt (struct link_map *map, lookup_t t, + const Elf32_Rela *reloc, + Elf32_Addr *reloc_addr, Elf32_Addr value) +{ + return sparc_fixup_plt (reloc, reloc_addr, value, 1); +} + /* Return the final value of a plt relocation. */ static inline Elf32_Addr elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc, @@ -366,10 +423,11 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc, else #endif { -#ifndef RTLD_BOOTSTRAP +#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP const Elf32_Sym *const refsym = sym; #endif Elf32_Addr value; +#ifndef RESOLVE_CONFLICT_FIND_MAP if (sym->st_shndx != SHN_UNDEF && ELF32_ST_BIND (sym->st_info) == STB_LOCAL) value = map->l_addr; @@ -379,11 +437,14 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc, if (sym) value += sym->st_value; } +#else + value = 0; +#endif value += reloc->r_addend; /* Assume copy relocs have zero addend. */ switch (r_type) { -#ifndef RTLD_BOOTSTRAP +#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 @@ -410,7 +471,9 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc, *reloc_addr = value; break; case R_SPARC_JMP_SLOT: - elf_machine_fixup_plt(map, 0, reloc, reloc_addr, value); + /* At this point we don't need to bother with thread safety, + so we can optimize the first instruction of .plt out. */ + sparc_fixup_plt (reloc, reloc_addr, value, 0); break; #ifndef RTLD_BOOTSTRAP case R_SPARC_8: diff --git a/sysdeps/sparc/sparc64/dl-machine.h b/sysdeps/sparc/sparc64/dl-machine.h index 9d2f2187ae..913f98a5e1 100644 --- a/sysdeps/sparc/sparc64/dl-machine.h +++ b/sysdeps/sparc/sparc64/dl-machine.h @@ -24,6 +24,11 @@ #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) @@ -147,7 +152,7 @@ sparc64_fixup_plt (struct link_map *map, const Elf64_Rela *reloc, insns[1] = 0x40000000 | (displacement >> 2); __asm __volatile ("flush %0 + 4" : : "r" (insns)); - insns[t] = 0x8210000f; + insns[0] = 0x8210000f; __asm __volatile ("flush %0" : : "r" (insns)); } /* Worst case, ho hum... */ @@ -251,10 +256,11 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc, else #endif { -#ifndef RTLD_BOOTSTRAP +#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; @@ -264,11 +270,14 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc, if (sym) value += sym->st_value; } +#else + value = 0; +#endif value += reloc->r_addend; /* Assume copy relocs have zero addend. */ switch (r_type) { -#ifndef RTLD_BOOTSTRAP +#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 @@ -371,8 +380,18 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc, 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 + in .gnu.conflict section. + r_addend non-zero does not mean it is a .plt[32768+] + reloc, instead it is the actual address of the function + to call. */ + sparc64_fixup_plt (NULL, reloc, reloc_addr, value, 0, 0); +#else sparc64_fixup_plt (map, reloc, reloc_addr, value, reloc->r_addend, 0); +#endif break; #ifndef RTLD_BOOTSTRAP case R_SPARC_UA16: @@ -536,6 +555,47 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) /* Now put the magic cookie at the beginning of .PLT2 Entry .PLT3 is unused by this implementation. */ *((struct link_map **)(&plt[16 + 0])) = l; + + if (__builtin_expect (l->l_info[VALIDX(DT_GNU_PRELINKED)] != NULL, 0) + || __builtin_expect (l->l_info [VALIDX (DT_GNU_LIBLISTSZ)] != NULL, 0)) + { + /* Need to reinitialize .plt to undo prelinking. */ + Elf64_Rela *rela = (Elf64_Rela *) D_PTR (l, l_info[DT_JMPREL]); + Elf64_Rela *relaend + = (Elf64_Rela *) ((char *) rela + + l->l_info[DT_PLTRELSZ]->d_un.d_val); + + /* prelink must ensure there are no R_SPARC_NONE relocs left + in .rela.plt. */ + while (rela < relaend) + { + if (__builtin_expect (rela->r_addend, 0) != 0) + { + Elf64_Addr slot = ((rela->r_offset + 0x400 + - (Elf64_Addr) plt) + / 0x1400) * 0x1400 + + (Elf64_Addr) plt - 0x400; + /* ldx [%o7 + X], %g1 */ + unsigned int first_ldx = *(unsigned int *)(slot + 12); + Elf64_Addr ptr = slot + (first_ldx & 0xfff) + 4; + + *(Elf64_Addr *) rela->r_offset + = (Elf64_Addr) plt + - (slot + ((rela->r_offset - ptr) / 8) * 24 + 4); + ++rela; + continue; + } + + *(unsigned int *) rela->r_offset + = 0x03000000 | (rela->r_offset - (Elf64_Addr) plt); + *(unsigned int *) (rela->r_offset + 4) + = 0x30680000 | ((((Elf64_Addr) plt + 32 + - rela->r_offset - 4) >> 2) & 0x7ffff); + __asm __volatile ("flush %0" : : "r" (rela->r_offset)); + __asm __volatile ("flush %0+4" : : "r" (rela->r_offset)); + ++rela; + } + } } return lazy; |