Module Name: src Committed By: joerg Date: Thu Mar 29 13:23:40 UTC 2018
Modified Files: src/distrib/sets/lists/comp: md.sparc md.sparc64 src/lib/csu/common: crt0-common.c src/libexec/ld.elf_so/arch/sparc: mdreloc.c src/libexec/ld.elf_so/arch/sparc64: mdreloc.c src/sys/arch/sparc/include: Makefile src/sys/arch/sparc64/include: Makefile Added Files: src/sys/arch/sparc/include: elf_support.h src/sys/arch/sparc64/include: elf_support.h Log Message: 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. To generate a diff of this commit: cvs rdiff -u -r1.92 -r1.93 src/distrib/sets/lists/comp/md.sparc cvs rdiff -u -r1.199 -r1.200 src/distrib/sets/lists/comp/md.sparc64 cvs rdiff -u -r1.15 -r1.16 src/lib/csu/common/crt0-common.c cvs rdiff -u -r1.53 -r1.54 src/libexec/ld.elf_so/arch/sparc/mdreloc.c cvs rdiff -u -r1.67 -r1.68 src/libexec/ld.elf_so/arch/sparc64/mdreloc.c cvs rdiff -u -r1.33 -r1.34 src/sys/arch/sparc/include/Makefile cvs rdiff -u -r0 -r1.1 src/sys/arch/sparc/include/elf_support.h cvs rdiff -u -r1.30 -r1.31 src/sys/arch/sparc64/include/Makefile cvs rdiff -u -r0 -r1.1 src/sys/arch/sparc64/include/elf_support.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/distrib/sets/lists/comp/md.sparc diff -u src/distrib/sets/lists/comp/md.sparc:1.92 src/distrib/sets/lists/comp/md.sparc:1.93 --- src/distrib/sets/lists/comp/md.sparc:1.92 Sat Feb 3 21:27:45 2018 +++ src/distrib/sets/lists/comp/md.sparc Thu Mar 29 13:23:39 2018 @@ -1,4 +1,4 @@ -# $NetBSD: md.sparc,v 1.92 2018/02/03 21:27:45 mrg Exp $ +# $NetBSD: md.sparc,v 1.93 2018/03/29 13:23:39 joerg Exp $ ./usr/include/gcc-4.5/tgmath.h comp-obsolete obsolete ./usr/include/gcc-4.8/tgmath.h comp-c-include obsolete ./usr/include/gcc-4.8/visintrin.h comp-c-include obsolete @@ -24,6 +24,7 @@ ./usr/include/sparc/disklabel.h comp-c-include ./usr/include/sparc/eeprom.h comp-c-include ./usr/include/sparc/elf_machdep.h comp-c-include +./usr/include/sparc/elf_support.h comp-c-include ./usr/include/sparc/endian.h comp-c-include ./usr/include/sparc/endian_machdep.h comp-c-include ./usr/include/sparc/fbio.h comp-obsolete obsolete @@ -92,6 +93,7 @@ ./usr/include/sparc64/disklabel.h comp-c-include ./usr/include/sparc64/eeprom.h comp-c-include ./usr/include/sparc64/elf_machdep.h comp-c-include +./usr/include/sparc64/elf_support.h comp-c-include ./usr/include/sparc64/endian.h comp-c-include ./usr/include/sparc64/endian_machdep.h comp-c-include ./usr/include/sparc64/fbio.h comp-obsolete obsolete Index: src/distrib/sets/lists/comp/md.sparc64 diff -u src/distrib/sets/lists/comp/md.sparc64:1.199 src/distrib/sets/lists/comp/md.sparc64:1.200 --- src/distrib/sets/lists/comp/md.sparc64:1.199 Sat Feb 3 21:27:45 2018 +++ src/distrib/sets/lists/comp/md.sparc64 Thu Mar 29 13:23:39 2018 @@ -1,4 +1,4 @@ -# $NetBSD: md.sparc64,v 1.199 2018/02/03 21:27:45 mrg Exp $ +# $NetBSD: md.sparc64,v 1.200 2018/03/29 13:23:39 joerg Exp $ ./usr/include/g++/bits/sparc comp-c-include compat ./usr/include/g++/bits/sparc/c++config.h comp-c-include gcc,compat ./usr/include/g++/bits/sparc64 comp-c-include compat @@ -28,6 +28,7 @@ ./usr/include/sparc/disklabel.h comp-c-include ./usr/include/sparc/eeprom.h comp-c-include ./usr/include/sparc/elf_machdep.h comp-c-include +./usr/include/sparc/elf_support.h comp-c-include ./usr/include/sparc/endian.h comp-c-include ./usr/include/sparc/endian_machdep.h comp-c-include ./usr/include/sparc/fbio.h comp-obsolete obsolete @@ -95,6 +96,7 @@ ./usr/include/sparc64/disklabel.h comp-c-include ./usr/include/sparc64/eeprom.h comp-c-include ./usr/include/sparc64/elf_machdep.h comp-c-include +./usr/include/sparc64/elf_support.h comp-c-include ./usr/include/sparc64/endian.h comp-c-include ./usr/include/sparc64/endian_machdep.h comp-c-include ./usr/include/sparc64/fbio.h comp-obsolete obsolete Index: src/lib/csu/common/crt0-common.c diff -u src/lib/csu/common/crt0-common.c:1.15 src/lib/csu/common/crt0-common.c:1.16 --- src/lib/csu/common/crt0-common.c:1.15 Fri Mar 9 20:20:47 2018 +++ src/lib/csu/common/crt0-common.c Thu Mar 29 13:23:39 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: crt0-common.c,v 1.15 2018/03/09 20:20:47 joerg Exp $ */ +/* $NetBSD: crt0-common.c,v 1.16 2018/03/29 13:23:39 joerg Exp $ */ /* * Copyright (c) 1998 Christos Zoulas @@ -36,7 +36,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: crt0-common.c,v 1.15 2018/03/09 20:20:47 joerg Exp $"); +__RCSID("$NetBSD: crt0-common.c,v 1.16 2018/03/29 13:23:39 joerg Exp $"); #include <sys/types.h> #include <sys/exec.h> @@ -140,6 +140,14 @@ static void fix_iplt(void) __noinline; #include <stdio.h> extern const Elf_Rela __rela_iplt_start[] __dso_hidden __weak; extern const Elf_Rela __rela_iplt_end[] __dso_hidden __weak; +#ifdef __sparc__ +#define IFUNC_RELOCATION R_TYPE(JMP_IREL) +#include <machine/elf_support.h> +#define write_plt(where, value) sparc_write_branch((void *)where, (void *)value) +#else +#define IFUNC_RELOCATION R_TYPE(IRELATIVE) +#define write_plt(where, value) *where = value +#endif static void fix_iplta(void) @@ -150,31 +158,20 @@ fix_iplta(void) rela = __rela_iplt_start; relalim = __rela_iplt_end; -#if DEBUG - printf("%p - %p\n", rela, relalim); -#endif for (; rela < relalim; ++rela) { - if (ELF_R_TYPE(rela->r_info) != R_TYPE(IRELATIVE)) + if (ELF_R_TYPE(rela->r_info) != IFUNC_RELOCATION) abort(); where = (Elf_Addr *)(relocbase + rela->r_offset); -#if DEBUG - printf("location: %p\n", where); -#endif target = (Elf_Addr)(relocbase + rela->r_addend); -#if DEBUG - printf("target: %p\n", (void *)target); -#endif target = ((Elf_Addr(*)(void))target)(); -#if DEBUG - printf("...resolves to: %p\n", (void *)target); -#endif - *where = target; + write_plt(where, target); } } #endif #ifdef HAS_IPLT extern const Elf_Rel __rel_iplt_start[] __dso_hidden __weak; extern const Elf_Rel __rel_iplt_end[] __dso_hidden __weak; +#define IFUNC_RELOCATION R_TYPE(IRELATIVE) static void fix_iplt(void) @@ -186,7 +183,7 @@ fix_iplt(void) rel = __rel_iplt_start; rellim = __rel_iplt_end; for (; rel < rellim; ++rel) { - if (ELF_R_TYPE(rel->r_info) != R_TYPE(IRELATIVE)) + if (ELF_R_TYPE(rel->r_info) != IFUNC_RELOCATION) abort(); where = (Elf_Addr *)(relocbase + rel->r_offset); target = ((Elf_Addr(*)(void))*where)(); Index: src/libexec/ld.elf_so/arch/sparc/mdreloc.c diff -u src/libexec/ld.elf_so/arch/sparc/mdreloc.c:1.53 src/libexec/ld.elf_so/arch/sparc/mdreloc.c:1.54 --- src/libexec/ld.elf_so/arch/sparc/mdreloc.c:1.53 Sun Mar 25 18:56:01 2018 +++ src/libexec/ld.elf_so/arch/sparc/mdreloc.c Thu Mar 29 13:23:39 2018 @@ -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_ _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_Entr 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; Index: src/libexec/ld.elf_so/arch/sparc64/mdreloc.c diff -u src/libexec/ld.elf_so/arch/sparc64/mdreloc.c:1.67 src/libexec/ld.elf_so/arch/sparc64/mdreloc.c:1.68 --- src/libexec/ld.elf_so/arch/sparc64/mdreloc.c:1.67 Mon Dec 25 17:00:15 2017 +++ src/libexec/ld.elf_so/arch/sparc64/mdreloc.c Thu Mar 29 13:23:39 2018 @@ -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_Add * 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_ _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) { Index: src/sys/arch/sparc/include/Makefile diff -u src/sys/arch/sparc/include/Makefile:1.33 src/sys/arch/sparc/include/Makefile:1.34 --- src/sys/arch/sparc/include/Makefile:1.33 Wed Jul 23 18:19:45 2014 +++ src/sys/arch/sparc/include/Makefile Thu Mar 29 13:23:39 2018 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.33 2014/07/23 18:19:45 alnsn Exp $ +# $NetBSD: Makefile,v 1.34 2018/03/29 13:23:39 joerg Exp $ INCSDIR= /usr/include/sparc @@ -6,7 +6,7 @@ INCS= ansi.h aout_machdep.h apmvar.h asm bswap.h bootinfo.h \ cdefs.h cgtworeg.h cpu.h cpuconf.h \ disklabel.h \ - eeprom.h elf_machdep.h endian.h endian_machdep.h \ + eeprom.h elf_machdep.h elf_support.h endian.h endian_machdep.h \ fenv.h float.h frame.h fsr.h \ idprom.h ieee.h ieeefp.h \ int_const.h int_fmtio.h int_limits.h int_mwgwtypes.h int_types.h \ Index: src/sys/arch/sparc64/include/Makefile diff -u src/sys/arch/sparc64/include/Makefile:1.30 src/sys/arch/sparc64/include/Makefile:1.31 --- src/sys/arch/sparc64/include/Makefile:1.30 Wed Jul 23 18:19:45 2014 +++ src/sys/arch/sparc64/include/Makefile Thu Mar 29 13:23:40 2018 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.30 2014/07/23 18:19:45 alnsn Exp $ +# $NetBSD: Makefile,v 1.31 2018/03/29 13:23:40 joerg Exp $ INCSDIR= /usr/include/sparc64 @@ -6,7 +6,7 @@ INCS= ansi.h aout_machdep.h asm.h autoco bswap.h bsd_openprom.h \ cdefs.h cgtworeg.h cpu.h ctlreg.h \ disklabel.h \ - eeprom.h elf_machdep.h endian.h endian_machdep.h \ + eeprom.h elf_machdep.h elf_support.h endian.h endian_machdep.h \ fenv.h float.h frame.h fsr.h \ idprom.h ieee.h ieeefp.h instr.h intr.h \ int_const.h int_fmtio.h int_limits.h int_mwgwtypes.h int_types.h \ Added files: Index: src/sys/arch/sparc/include/elf_support.h diff -u /dev/null src/sys/arch/sparc/include/elf_support.h:1.1 --- /dev/null Thu Mar 29 13:23:40 2018 +++ src/sys/arch/sparc/include/elf_support.h Thu Mar 29 13:23:39 2018 @@ -0,0 +1,64 @@ +/* $NetBSD: elf_support.h,v 1.1 2018/03/29 13:23:39 joerg Exp $ */ + +/*- + * Copyright (c) 2018 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _SPARC_ELF_SUPPORT_H +#define _SPARC_ELF_SUPPORT_H + +static inline void +sparc_write_branch(void *where_, void *target) +{ + const unsigned int BAA = 0x30800000U; /* ba,a (offset / 4) */ + const unsigned int SETHI = 0x03000000U; /* sethi %hi(0), %g1 */ + const unsigned int JMP = 0x81c06000U; /* jmpl %g1+%lo(0), %g0 */ + + unsigned int *where = (unsigned int *)where_; + unsigned long value = (unsigned long)target; + unsigned long offset = value - (unsigned long)where; + +#define HIVAL(v, s) (((v) >> (s)) & 0x003fffffU) +#define LOVAL(v, s) (((v) >> (s)) & 0x000003ffU) + if (offset + 0x800000 <= 0x7ffffc) { + /* Displacement is within 8MB, use a direct branch. */ + where[0] = BAA | ((offset >> 2) & 0x3fffff); + __asm volatile("iflush %0+0" : : "r" (where)); + return; + } + + /* + * The absolute address is a 32bit value. + * This can be encoded as: + * sethi %hi(value), %g1 + * jmp %g1+%lo(value) + */ + where[1] = JMP | LOVAL(value, 0); + __asm volatile("iflush %0+4" : : "r" (where)); + where[0] = SETHI | HIVAL(value, 10); + __asm volatile("iflush %0+0" : : "r" (where)); +#undef HIVAL +#undef LOVAL +} +#endif Index: src/sys/arch/sparc64/include/elf_support.h diff -u /dev/null src/sys/arch/sparc64/include/elf_support.h:1.1 --- /dev/null Thu Mar 29 13:23:40 2018 +++ src/sys/arch/sparc64/include/elf_support.h Thu Mar 29 13:23:40 2018 @@ -0,0 +1,186 @@ +/* $NetBSD: elf_support.h,v 1.1 2018/03/29 13:23:40 joerg Exp $ */ + +/*- + * Copyright (c) 2000 Eduardo Horvath. + * Copyright (c) 2018 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _SPARC64_ELF_SUPPORT_H +#define _SPARC64_ELF_SUPPORT_H + +#ifdef __arch64__ +/* + * Create a jump to the location `target` starting at `where`. + * This requires up to 6 instructions. + * The first instruction is written last as it replaces a branch + * in the PLT during lazy binding. + * The resulting code can trash %g1 and %g5. + */ +static inline void +sparc_write_branch(void *where_, void *target) +{ + const unsigned int BAA = 0x30800000U; /* ba,a (offset / 4) */ + const unsigned int SETHI = 0x03000000U; /* sethi %hi(0), %g1 */ + const unsigned int JMP = 0x81c06000U; /* jmpl %g1+%lo(0), %g0 */ + const unsigned int OR = 0x82106000U; /* or %g1, 0, %g1 */ + const unsigned int XOR = 0x82186000U; /* xor %g1, 0, %g1 */ + const unsigned int MOV71 = 0x8213e000U; /* or %o7, 0, %g1 */ + const unsigned int MOV17 = 0x9e106000U; /* or %g1, 0, %o7 */ + const unsigned int CALL = 0x40000000U; /* call 0 */ + const unsigned int SLLX = 0x83287000U; /* sllx %g1, 0, %g1 */ + const unsigned int NEG = 0x82200001U; /* neg %g1 */ + const unsigned int SETHIG5 = 0x0b000000U; /* sethi %hi(0), %g5 */ + const unsigned int ORG5 = 0x82104005U; /* or %g1, %g5, %g1 */ + + unsigned int *where = (unsigned int *)where_; + unsigned long value = (unsigned long)target; + unsigned long offset = value - (unsigned long)where; + +#define HIVAL(v, s) (((v) >> (s)) & 0x003fffffU) +#define LOVAL(v, s) (((v) >> (s)) & 0x000003ffU) + if (offset + 0x800000 <= 0x7ffffc) { + /* Displacement is within 8MB, use a direct branch. */ + where[0] = BAA | ((offset >> 2) & 0x3fffff); + __asm volatile("iflush %0+0" : : "r" (where)); + return; + } + + if (value <= 0xffffffffUL) { + /* + * The absolute address is a 32bit value. + * This can be encoded as: + * sethi %hi(value), %g1 + * jmp %g1+%lo(value) + */ + where[1] = JMP | LOVAL(value, 0); + __asm volatile("iflush %0+4" : : "r" (where)); + where[0] = SETHI | HIVAL(value, 10); + __asm volatile("iflush %0+0" : : "r" (where)); + return; + } + + if (value >= 0xffffffff00000000UL) { + /* + * The top 32bit address range can be encoded as: + * sethi %hix(addr), %g1 + * xor %g1, %lox(addr), %g1 + * jmp %g1 + */ + where[2] = JMP; + where[1] = XOR | (value & 0x00003ff) | 0x1c00; + __asm volatile("iflush %0+4" : : "r" (where)); + __asm volatile("iflush %0+8" : : "r" (where)); + where[0] = SETHI | HIVAL(~value, 10); + __asm volatile("iflush %0+0" : : "r" (where)); + return; + } + + if ((offset + 4) + 0x80000000UL <= 0x100000000UL) { + /* + * Displacement of the second instruction is within + * +-2GB. This can use a direct call instruction: + * mov %o7, %g1 + * call (value - .) + * mov %g1, %o7 + */ + where[1] = CALL | ((-(offset + 4)>> 2) & 0x3fffffffU); + where[2] = MOV17; + __asm volatile("iflush %0+4" : : "r" (where)); + __asm volatile("iflush %0+8" : : "r" (where)); + where[0] = MOV71; + __asm volatile("iflush %0+0" : : "r" (where)); + return; + } + + if (value < 0x100000000000UL) { + /* + * The absolute address is a 44bit value. + * This can be encoded as: + * sethi %h44(addr), %g1 + * or %g1, %m44(addr), %g1 + * sllx %g1, 12, %g1 + * jmp %g1+%l44(addr) + */ + where[1] = OR | (((value) >> 12) & 0x00001fff); + where[2] = SLLX | 12; + where[3] = JMP | LOVAL(value, 0); + __asm volatile("iflush %0+4" : : "r" (where)); + __asm volatile("iflush %0+8" : : "r" (where)); + __asm volatile("iflush %0+12" : : "r" (where)); + where[0] = SETHI | HIVAL(value, 22); + __asm volatile("iflush %0+0" : : "r" (where)); + return; + } + + if (value > 0xfffff00000000000UL) { + /* + * The top 44bit address range can be encoded as: + * sethi %hi((-addr)>>12), %g1 + * or %g1, %lo((-addr)>>12), %g1 + * neg %g1 + * sllx %g1, 12, %g1 + * jmp %g1+(addr&0x0fff) + */ + unsigned long neg = (-value)>>12; + where[1] = OR | (LOVAL(neg, 0)+1); + where[2] = NEG; + where[3] = SLLX | 12; + where[4] = JMP | (value & 0x0fff); + __asm volatile("iflush %0+4" : : "r" (where)); + __asm volatile("iflush %0+8" : : "r" (where)); + __asm volatile("iflush %0+12" : : "r" (where)); + __asm volatile("iflush %0+16" : : "r" (where)); + where[0] = SETHI | HIVAL(neg, 10); + __asm volatile("iflush %0+0" : : "r" (where)); + return; + } + + /* + * The general case of a 64bit address is encoded as: + * 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) + */ + where[1] = SETHIG5 | HIVAL(value, 10); + where[2] = OR | LOVAL(value, 32); + where[3] = SLLX | 32; + where[4] = ORG5; + where[5] = JMP | LOVAL(value, 0); + __asm volatile("iflush %0+4" : : "r" (where)); + __asm volatile("iflush %0+8" : : "r" (where)); + __asm volatile("iflush %0+12" : : "r" (where)); + __asm volatile("iflush %0+16" : : "r" (where)); + __asm volatile("iflush %0+20" : : "r" (where)); + where[0] = SETHI | HIVAL(value, 42); + __asm volatile("iflush %0+0" : : "r" (where)); +#undef HIVAL +#undef LOVAL +} +#else +#include <sparc/elf_support.h> +#endif +#endif