diff options
| author | joerg <joerg@NetBSD.org> | 2018-03-29 13:23:39 +0000 |
|---|---|---|
| committer | joerg <joerg@NetBSD.org> | 2018-03-29 13:23:39 +0000 |
| commit | a0c0dc619f4e2111431640f5a95d13c6495091fb (patch) | |
| tree | 43088921b33878199dc6206d935ab0508a61c26f /libexec/ld.elf_so/arch | |
| parent | 84674ffc6c79621980e2d4e3cd9f81414aa27da3 (diff) | |
Move the complex logic for dynamically writing branches from ld.elf_so
into a header for reuse in crt0.o for static ifunc support. Change the
existing logic for sparc64 to use the Bicc variant of ba,a as it allows
+-8MB displacement compared to the BPcc variant's +-1MB. Teach the sparc
variant the same trick for using ba,a and not sethi+jmp when possible.
Diffstat (limited to 'libexec/ld.elf_so/arch')
| -rw-r--r-- | libexec/ld.elf_so/arch/sparc/mdreloc.c | 35 | ||||
| -rw-r--r-- | libexec/ld.elf_so/arch/sparc64/mdreloc.c | 212 |
2 files changed, 12 insertions, 235 deletions
diff --git a/libexec/ld.elf_so/arch/sparc/mdreloc.c b/libexec/ld.elf_so/arch/sparc/mdreloc.c index 15dd64bc262..53d1835e371 100644 --- a/libexec/ld.elf_so/arch/sparc/mdreloc.c +++ b/libexec/ld.elf_so/arch/sparc/mdreloc.c @@ -1,4 +1,4 @@ -/* $NetBSD: mdreloc.c,v 1.53 2018/03/25 18:56:01 joerg Exp $ */ +/* $NetBSD: mdreloc.c,v 1.54 2018/03/29 13:23:39 joerg Exp $ */ /*- * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc. @@ -31,9 +31,11 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: mdreloc.c,v 1.53 2018/03/25 18:56:01 joerg Exp $"); +__RCSID("$NetBSD: mdreloc.c,v 1.54 2018/03/29 13:23:39 joerg Exp $"); #endif /* not lint */ +#include <machine/elf_support.h> + #include <errno.h> #include <stdio.h> #include <stdlib.h> @@ -404,31 +406,6 @@ _rtld_relocate_plt_lazy(Obj_Entry *obj) return 0; } -static inline void -_rtld_write_plt(Elf_Word *where, Elf_Addr value) -{ - /* - * At the PLT entry pointed at by `where', we now construct - * a direct transfer to the now fully resolved function - * address. The resulting code in the jump slot is: - * - * sethi %hi(roffset), %g1 - * sethi %hi(addr), %g1 - * jmp %g1+%lo(addr) - * - * We write the third instruction first, since that leaves the - * previous `b,a' at the second word in place. Hence the whole - * PLT slot can be atomically change to the new sequence by - * writing the `sethi' instruction at word 2. - */ - const uint32_t SETHI = 0x03000000U; - const uint32_t JMP = 0x81c06000U; - where[2] = JMP | (value & 0x000003ff); - where[1] = SETHI | ((value >> 10) & 0x003fffff); - __asm volatile("iflush %0+8" : : "r" (where)); - __asm volatile("iflush %0+4" : : "r" (where)); -} - void _rtld_call_ifunc(Obj_Entry *obj, sigset_t *mask, u_int cur_objgen) { @@ -444,7 +421,7 @@ _rtld_call_ifunc(Obj_Entry *obj, sigset_t *mask, u_int cur_objgen) _rtld_exclusive_exit(mask); target = _rtld_resolve_ifunc2(obj, target); _rtld_exclusive_enter(mask); - _rtld_write_plt(where, target); + sparc_write_branch(where + 1, (void *)target); } while (obj->ifunc_remaining_nonplt > 0 && _rtld_objgen == cur_objgen) { @@ -521,7 +498,7 @@ _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr * rdbg(("bind now/fixup in %s --> new=%p", defobj->strtab + def->st_name, (void *)value)); - _rtld_write_plt(where, value); + sparc_write_branch(where + 1, (void *)value); if (tp) *tp = value; diff --git a/libexec/ld.elf_so/arch/sparc64/mdreloc.c b/libexec/ld.elf_so/arch/sparc64/mdreloc.c index 5c144e80a32..9c559612205 100644 --- a/libexec/ld.elf_so/arch/sparc64/mdreloc.c +++ b/libexec/ld.elf_so/arch/sparc64/mdreloc.c @@ -1,4 +1,4 @@ -/* $NetBSD: mdreloc.c,v 1.67 2017/12/25 17:00:15 joerg Exp $ */ +/* $NetBSD: mdreloc.c,v 1.68 2018/03/29 13:23:39 joerg Exp $ */ /*- * Copyright (c) 2000 Eduardo Horvath. @@ -32,9 +32,11 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: mdreloc.c,v 1.67 2017/12/25 17:00:15 joerg Exp $"); +__RCSID("$NetBSD: mdreloc.c,v 1.68 2018/03/29 13:23:39 joerg Exp $"); #endif /* not lint */ +#include <machine/elf_support.h> + #include <errno.h> #include <stdio.h> #include <stdlib.h> @@ -192,19 +194,6 @@ static const long reloc_target_bitmask[] = { /* * Instruction templates: */ -#define BAA 0x30680000 /* ba,a %xcc, 0 */ -#define SETHI 0x03000000 /* sethi %hi(0), %g1 */ -#define JMP 0x81c06000 /* jmpl %g1+%lo(0), %g0 */ -#define NOP 0x01000000 /* sethi %hi(0), %g0 */ -#define OR 0x82106000 /* or %g1, 0, %g1 */ -#define XOR 0x82186000 /* xor %g1, 0, %g1 */ -#define MOV71 0x8213e000 /* or %o7, 0, %g1 */ -#define MOV17 0x9e106000 /* or %g1, 0, %o7 */ -#define CALL 0x40000000 /* call 0 */ -#define SLLX 0x83287000 /* sllx %g1, 0, %g1 */ -#define NEG 0x82200001 /* neg %g1 */ -#define SETHIG5 0x0b000000 /* sethi %hi(0), %g5 */ -#define ORG5 0x82104005 /* or %g1, %g5, %g1 */ /* %hi(v)/%lo(v) with variable shift */ @@ -589,34 +578,6 @@ static inline void _rtld_write_plt(Elf_Word *where, Elf_Addr value, const Elf_Rela *rela, const Obj_Entry *obj) { - Elf_Addr offset, offBAA; - - /* - * At the PLT entry pointed at by `where', we now construct a direct - * transfer to the now fully resolved function address. - * - * A PLT entry is supposed to start by looking like this: - * - * sethi %hi(. - .PLT0), %g1 - * ba,a %xcc, .PLT1 - * nop - * nop - * nop - * nop - * nop - * nop - * - * When we replace these entries we start from the last instruction - * and do it in reverse order so the last thing we do is replace the - * branch. That allows us to change this atomically. - * - * We now need to find out how far we need to jump. We have a choice - * of several different relocation techniques which are increasingly - * expensive. - */ - - offset = ((Elf_Addr)where) - value; - offBAA = value - (((Elf_Addr)where) + 4); /* ba,a at where[1] */ if (rela && rela->r_addend) { Elf_Addr *ptr = (Elf_Addr *)where; /* @@ -625,169 +586,8 @@ _rtld_write_plt(Elf_Word *where, Elf_Addr value, const Elf_Rela *rela, * PLT section. Update it to point to the target function. */ ptr[0] += value - (Elf_Addr)obj->pltgot; - } else if (offBAA <= (1L<<20) && (Elf_SOff)offBAA >= -(1L<<20)) { - /* - * We're within 1MB -- we can use a direct branch insn. - * - * We can generate this pattern: - * - * sethi %hi(. - .PLT0), %g1 - * ba,a %xcc, addr - * nop - * nop - * nop - * nop - * nop - * nop - * - */ - where[1] = BAA | ((offBAA >> 2) & 0x7ffff); - __asm volatile("iflush %0+4" : : "r" (where)); - } else if (value < (1L<<32)) { - /* - * We're within 32-bits of address zero. - * - * The resulting code in the jump slot is: - * - * sethi %hi(. - .PLT0), %g1 - * sethi %hi(addr), %g1 - * jmp %g1+%lo(addr) - * nop - * nop - * nop - * nop - * nop - * - */ - where[2] = JMP | LOVAL(value, 0); - where[1] = SETHI | HIVAL(value, 10); - __asm volatile("iflush %0+8" : : "r" (where)); - __asm volatile("iflush %0+4" : : "r" (where)); - } else if ((Elf_SOff)value <= 0 && (Elf_SOff)value > -(1L<<32)) { - /* - * We're within 32-bits of address -1. - * - * The resulting code in the jump slot is: - * - * sethi %hi(. - .PLT0), %g1 - * sethi %hix(addr), %g1 - * xor %g1, %lox(addr), %g1 - * jmp %g1 - * nop - * nop - * nop - * nop - * - */ - where[3] = JMP; - where[2] = XOR | (value & 0x00003ff) | 0x1c00; - where[1] = SETHI | HIVAL(~value, 10); - __asm volatile("iflush %0+12" : : "r" (where)); - __asm volatile("iflush %0+8" : : "r" (where)); - __asm volatile("iflush %0+4" : : "r" (where)); - } else if ((offset+8) <= (1L<<31) && - (Elf_SOff)(offset+8) >= -((1L<<31) - 4)) { - /* - * We're within 32-bits -- we can use a direct call insn - * - * The resulting code in the jump slot is: - * - * sethi %hi(. - .PLT0), %g1 - * mov %o7, %g1 - * call (.+offset) - * mov %g1, %o7 - * nop - * nop - * nop - * nop - * - */ - offset += 8; /* call is at where[2], 8 byte further */ - where[3] = MOV17; - where[2] = CALL | ((-offset >> 2) & 0x3fffffff); - where[1] = MOV71; - __asm volatile("iflush %0+12" : : "r" (where)); - __asm volatile("iflush %0+8" : : "r" (where)); - __asm volatile("iflush %0+4" : : "r" (where)); - } else if ((Elf_SOff)value > 0 && value < (1L<<44)) { - /* - * We're within 44 bits. We can generate this pattern: - * - * The resulting code in the jump slot is: - * - * sethi %hi(. - .PLT0), %g1 - * sethi %h44(addr), %g1 - * or %g1, %m44(addr), %g1 - * sllx %g1, 12, %g1 - * jmp %g1+%l44(addr) - * nop - * nop - * nop - * - */ - where[4] = JMP | LOVAL(value, 0); - where[3] = SLLX | 12; - where[2] = OR | (((value) >> 12) & 0x00001fff); - where[1] = SETHI | HIVAL(value, 22); - __asm volatile("iflush %0+16" : : "r" (where)); - __asm volatile("iflush %0+12" : : "r" (where)); - __asm volatile("iflush %0+8" : : "r" (where)); - __asm volatile("iflush %0+4" : : "r" (where)); - } else if ((Elf_SOff)value < 0 && (Elf_SOff)value > -(1L<<44)) { - /* - * We're within 44 bits. We can generate this pattern: - * - * The resulting code in the jump slot is: - * - * sethi %hi(. - .PLT0), %g1 - * sethi %hi((-addr)>>12), %g1 - * or %g1, %lo((-addr)>>12), %g1 - * neg %g1 - * sllx %g1, 12, %g1 - * jmp %g1+(addr&0x0fff) - * nop - * nop - * - */ - Elf_Addr neg = (~value+1)>>12; - where[5] = JMP | (value & 0x0fff); - where[4] = SLLX | 12; - where[3] = NEG; - where[2] = OR | (LOVAL(neg, 0)+1); - where[1] = SETHI | HIVAL(neg, 10); - __asm volatile("iflush %0+20" : : "r" (where)); - __asm volatile("iflush %0+16" : : "r" (where)); - __asm volatile("iflush %0+12" : : "r" (where)); - __asm volatile("iflush %0+8" : : "r" (where)); - __asm volatile("iflush %0+4" : : "r" (where)); } else { - /* - * We need to load all 64-bits - * - * The resulting code in the jump slot is: - * - * sethi %hi(. - .PLT0), %g1 - * sethi %hh(addr), %g1 - * sethi %lm(addr), %g5 - * or %g1, %hm(addr), %g1 - * sllx %g1, 32, %g1 - * or %g1, %g5, %g1 - * jmp %g1+%lo(addr) - * nop - * - */ - where[6] = JMP | LOVAL(value, 0); - where[5] = ORG5; - where[4] = SLLX | 32; - where[3] = OR | LOVAL(value, 32); - where[2] = SETHIG5 | HIVAL(value, 10); - where[1] = SETHI | HIVAL(value, 42); - __asm volatile("iflush %0+24" : : "r" (where)); - __asm volatile("iflush %0+20" : : "r" (where)); - __asm volatile("iflush %0+16" : : "r" (where)); - __asm volatile("iflush %0+12" : : "r" (where)); - __asm volatile("iflush %0+8" : : "r" (where)); - __asm volatile("iflush %0+4" : : "r" (where)); + sparc_write_branch(where + 1, (void *)value); } } @@ -851,7 +651,7 @@ _rtld_call_ifunc(Obj_Entry *obj, sigset_t *mask, u_int cur_objgen) _rtld_exclusive_exit(mask); target = _rtld_resolve_ifunc2(obj, target); _rtld_exclusive_enter(mask); - _rtld_write_plt(where2, target, NULL, obj); + sparc_write_branch(where2 + 1, (void *)target); } while (obj->ifunc_remaining_nonplt > 0 && _rtld_objgen == cur_objgen) { |
