From 42be1f29f1f08ca9a38bbc0fe3b4bf75c3b43eed Mon Sep 17 00:00:00 2001 From: swcompiler Date: Fri, 29 Nov 2024 13:52:33 +0800 Subject: [PATCH 03/23] Sw64: ABI Implementation --- sysdeps/sw_64/__longjmp.S | 64 +++ sysdeps/sw_64/_mcount.S | 105 ++++ sysdeps/sw_64/bits/endianness.h | 11 + sysdeps/sw_64/bits/link.h | 64 +++ sysdeps/sw_64/bits/setjmp.h | 61 ++ sysdeps/sw_64/bsd-_setjmp.S | 1 + sysdeps/sw_64/bsd-setjmp.S | 1 + sysdeps/sw_64/crti.S | 101 ++++ sysdeps/sw_64/crtn.S | 49 ++ sysdeps/sw_64/dl-dtprocnum.h | 3 + sysdeps/sw_64/dl-machine.h | 463 +++++++++++++++ sysdeps/sw_64/dl-procinfo.c | 63 ++ sysdeps/sw_64/dl-procinfo.h | 58 ++ sysdeps/sw_64/dl-sysdep.h | 23 + sysdeps/sw_64/dl-trampoline.S | 540 ++++++++++++++++++ sysdeps/sw_64/ffs.S | 91 +++ sysdeps/sw_64/ffsll.S | 1 + sysdeps/sw_64/jmpbuf-offsets.h | 35 ++ sysdeps/sw_64/jmpbuf-unwind.h | 45 ++ sysdeps/sw_64/ldsodefs.h | 40 ++ sysdeps/sw_64/machine-gmon.h | 24 + sysdeps/sw_64/nptl/pthread-offsets.h | 3 + sysdeps/sw_64/nptl/pthreaddef.h | 31 + sysdeps/sw_64/setjmp.S | 121 ++++ sysdeps/sw_64/sotruss-lib.c | 48 ++ sysdeps/sw_64/start.S | 103 ++++ sysdeps/sw_64/sw8a/nptl/pthread-offsets.h | 3 + sysdeps/sw_64/sw8a/nptl/pthreaddef.h | 31 + sysdeps/sw_64/sw8a/nptl/tcb-offsets.sym | 13 + sysdeps/sw_64/tls-macros.h | 36 ++ sysdeps/sw_64/tst-audit.h | 24 + sysdeps/sw_64/tst-file-align.h | 20 + sysdeps/sw_64/unwind-arch.h | 28 + .../unix/sysv/linux/sw_64/____longjmp_chk.S | 145 +++++ 34 files changed, 2449 insertions(+) create mode 100644 sysdeps/sw_64/__longjmp.S create mode 100644 sysdeps/sw_64/_mcount.S create mode 100644 sysdeps/sw_64/bits/endianness.h create mode 100644 sysdeps/sw_64/bits/link.h create mode 100644 sysdeps/sw_64/bits/setjmp.h create mode 100644 sysdeps/sw_64/bsd-_setjmp.S create mode 100644 sysdeps/sw_64/bsd-setjmp.S create mode 100644 sysdeps/sw_64/crti.S create mode 100644 sysdeps/sw_64/crtn.S create mode 100644 sysdeps/sw_64/dl-dtprocnum.h create mode 100644 sysdeps/sw_64/dl-machine.h create mode 100644 sysdeps/sw_64/dl-procinfo.c create mode 100644 sysdeps/sw_64/dl-procinfo.h create mode 100644 sysdeps/sw_64/dl-sysdep.h create mode 100644 sysdeps/sw_64/dl-trampoline.S create mode 100644 sysdeps/sw_64/ffs.S create mode 100644 sysdeps/sw_64/ffsll.S create mode 100644 sysdeps/sw_64/jmpbuf-offsets.h create mode 100644 sysdeps/sw_64/jmpbuf-unwind.h create mode 100644 sysdeps/sw_64/ldsodefs.h create mode 100644 sysdeps/sw_64/machine-gmon.h create mode 100644 sysdeps/sw_64/nptl/pthread-offsets.h create mode 100644 sysdeps/sw_64/nptl/pthreaddef.h create mode 100644 sysdeps/sw_64/setjmp.S create mode 100644 sysdeps/sw_64/sotruss-lib.c create mode 100644 sysdeps/sw_64/start.S create mode 100644 sysdeps/sw_64/sw8a/nptl/pthread-offsets.h create mode 100644 sysdeps/sw_64/sw8a/nptl/pthreaddef.h create mode 100644 sysdeps/sw_64/sw8a/nptl/tcb-offsets.sym create mode 100644 sysdeps/sw_64/tls-macros.h create mode 100644 sysdeps/sw_64/tst-audit.h create mode 100644 sysdeps/sw_64/tst-file-align.h create mode 100644 sysdeps/sw_64/unwind-arch.h create mode 100644 sysdeps/unix/sysv/linux/sw_64/____longjmp_chk.S diff --git a/sysdeps/sw_64/__longjmp.S b/sysdeps/sw_64/__longjmp.S new file mode 100644 index 00000000..1321350e --- /dev/null +++ b/sysdeps/sw_64/__longjmp.S @@ -0,0 +1,64 @@ +/* Copyright (C) 1992-2023 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, see + . */ + +#define __ASSEMBLY__ + +#include +#include +#include + + +ENTRY(__longjmp) +#ifdef PROF + ldgp gp, 0(pv) + .set noat + ldi AT, _mcount + call AT, (AT), _mcount + .set at + .prologue 1 +#else + .prologue 0 +#endif + + mov a1, v0 + ldl s0, JB_S0*8(a0) + ldl s1, JB_S1*8(a0) + ldl s2, JB_S2*8(a0) + ldl s3, JB_S3*8(a0) + ldl s4, JB_S4*8(a0) + ldl s5, JB_S5*8(a0) + ldl ra, JB_PC*8(a0) + ldl fp, JB_FP*8(a0) + ldl t0, JB_SP*8(a0) + fldd $f2, JB_F2*8(a0) + fldd $f3, JB_F3*8(a0) + fldd $f4, JB_F4*8(a0) + fldd $f5, JB_F5*8(a0) + fldd $f6, JB_F6*8(a0) + fldd $f7, JB_F7*8(a0) + fldd $f8, JB_F8*8(a0) + fldd $f9, JB_F9*8(a0) +#ifdef PTR_DEMANGLE + PTR_DEMANGLE(ra, t1) + PTR_DEMANGLE2(t0, t1) + PTR_DEMANGLE2(fp, t1) +#endif + seleq v0, 1, v0, v0 + mov t0, sp + ret + +END(__longjmp) diff --git a/sysdeps/sw_64/_mcount.S b/sysdeps/sw_64/_mcount.S new file mode 100644 index 00000000..44871413 --- /dev/null +++ b/sysdeps/sw_64/_mcount.S @@ -0,0 +1,105 @@ +/* Machine-specific calling sequence for `mcount' profiling function. sw_64 + Copyright (C) 1995-2023 Free Software Foundation, Inc. + Contributed by David Mosberger (davidm@cs.arizona.edu). + 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, see + . */ + +/* Assembly stub to invoke _mcount(). Compiler generated code calls + this stub after executing a function's prologue and without saving any + registers. It is therefore necessary to preserve a0..a5 as they may + contain function arguments. To work correctly with frame- less + functions, it is also necessary to preserve ra. Finally, division + routines are invoked with a special calling convention and the + compiler treats those calls as if they were instructions. In + particular, it doesn't save any of the temporary registers (caller + saved registers). It is therefore necessary to preserve all + caller-saved registers as well. + + Upon entering _mcount, register $at hoflds the return address and ra + hoflds the return address of the function's caller (selfpc and frompc, + respectively in gmon.c language...). */ + +#include + + .set noat + .set noreorder + +LEAF(_mcount, 0xb0) + subl sp, 0xb0, sp + .prologue 0 + stl a0, 0x00(sp) + mov ra, a0 # a0 = caller-pc + stl a1, 0x08(sp) + mov $at, a1 # a1 = self-pc + stl $at, 0x10(sp) + + stl a2, 0x18(sp) + stl a3, 0x20(sp) + stl a4, 0x28(sp) + stl a5, 0x30(sp) + stl ra, 0x38(sp) + stl gp, 0x40(sp) + + br gp, 1f +1: ldgp gp, 0(gp) + + stl t0, 0x48(sp) + stl t1, 0x50(sp) + stl t2, 0x58(sp) + stl t3, 0x60(sp) + stl t4, 0x68(sp) + stl t5, 0x70(sp) + stl t6, 0x78(sp) + + stl t7, 0x80(sp) + stl t8, 0x88(sp) + stl t9, 0x90(sp) + stl t10, 0x98(sp) + stl t11, 0xa0(sp) + stl v0, 0xa8(sp) + + call ra, __mcount + + ldl a0, 0x00(sp) + ldl a1, 0x08(sp) + ldl $at, 0x10(sp) # restore self-pc + ldl a2, 0x18(sp) + ldl a3, 0x20(sp) + ldl a4, 0x28(sp) + ldl a5, 0x30(sp) + ldl ra, 0x38(sp) + ldl gp, 0x40(sp) + mov $at, pv # make pv point to return address + ldl t0, 0x48(sp) # this is important under OSF/1 to + ldl t1, 0x50(sp) # ensure that the code that we return + ldl t2, 0x58(sp) # can correctly compute its gp + ldl t3, 0x60(sp) + ldl t4, 0x68(sp) + ldl t5, 0x70(sp) + ldl t6, 0x78(sp) + ldl t7, 0x80(sp) + ldl t8, 0x88(sp) + ldl t9, 0x90(sp) + ldl t10, 0x98(sp) + ldl t11, 0xa0(sp) + ldl v0, 0xa8(sp) + + addl sp, 0xb0, sp + ret zero,($at),1 + + END(_mcount) + +weak_alias (_mcount, mcount) diff --git a/sysdeps/sw_64/bits/endianness.h b/sysdeps/sw_64/bits/endianness.h new file mode 100644 index 00000000..2c226169 --- /dev/null +++ b/sysdeps/sw_64/bits/endianness.h @@ -0,0 +1,11 @@ +#ifndef _BITS_ENDIANNESS_H +#define _BITS_ENDIANNESS_H 1 + +#ifndef _BITS_ENDIAN_H +# error "Never use directly; include instead." +#endif + +/* Sw_64 is little-endian. */ +#define __BYTE_ORDER __LITTLE_ENDIAN + +#endif /* bits/endianness.h */ diff --git a/sysdeps/sw_64/bits/link.h b/sysdeps/sw_64/bits/link.h new file mode 100644 index 00000000..312d8550 --- /dev/null +++ b/sysdeps/sw_64/bits/link.h @@ -0,0 +1,64 @@ +/* Copyright (C) 2005-2023 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, see + . */ + +#ifndef _LINK_H +# error "Never include directly; use instead." +#endif + +/* Registers for entry into PLT on Sw_64. */ +typedef struct La_sw_64_regs +{ + uint64_t lr_r26; + uint64_t lr_sp; + uint64_t lr_r16; + uint64_t lr_r17; + uint64_t lr_r18; + uint64_t lr_r19; + uint64_t lr_r20; + uint64_t lr_r21; + double lr_f16; + double lr_f17; + double lr_f18; + double lr_f19; + double lr_f20; + double lr_f21; +} La_sw_64_regs; + +/* Return values for calls from PLT on Sw_64. */ +typedef struct La_sw_64_retval +{ + uint64_t lrv_r0; + uint64_t lrv_r1; + double lrv_f0; + double lrv_f1; +} La_sw_64_retval; + +__BEGIN_DECLS + +extern Elf64_Addr +la_sw_64_gnu_pltenter (Elf64_Sym *__sym, unsigned int __ndx, + uintptr_t *__refcook, uintptr_t *__defcook, + La_sw_64_regs *__regs, unsigned int *__flags, + const char *__symname, long int *__framesizep); +extern unsigned int la_sw_64_gnu_pltexit (Elf64_Sym *__sym, unsigned int __ndx, + uintptr_t *__refcook, + uintptr_t *__defcook, + const La_sw_64_regs *__inregs, + La_sw_64_retval *__outregs, + const char *symname); + +__END_DECLS diff --git a/sysdeps/sw_64/bits/setjmp.h b/sysdeps/sw_64/bits/setjmp.h new file mode 100644 index 00000000..f8488a2f --- /dev/null +++ b/sysdeps/sw_64/bits/setjmp.h @@ -0,0 +1,61 @@ +/* Define the machine-dependent type `jmp_buf'. Sw_64 version. + Copyright (C) 1992-2023 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, see + . */ + +#ifndef _BITS_SETJMP_H +#define _BITS_SETJMP_H 1 + +#if !defined _SETJMP_H && !defined _PTHREAD_H +# error "Never include directly; use instead." +#endif + +/* The previous bits/setjmp.h had __jmp_buf defined as a structure. + We use an array of 'long int' instead, to make writing the + assembler easier. Naturally, user code should not depend on + either representation. */ + +/* + * Integer registers: + * $0 is the return value (va); + * $1-$8, $22-$25, $28 are call-used (t0-t7, t8-t11, at); + * $9-$14 we save here (s0-s5); + * $15 is the FP and we save it here (fp or s6); + * $16-$21 are input arguments (call-used) (a0-a5); + * $26 is the return PC and we save it here (ra); + * $27 is the procedure value (i.e., the address of __setjmp) (pv or t12); + * $29 is the global pointer, which the caller will reconstruct + * from the return address restored in $26 (gp); + * $30 is the stack pointer and we save it here (sp); + * $31 is always zero (zero). + * + * Floating-point registers: + * $f0 is the floating return value; + * $f1, $f10-$f15, $f22-$f30 are call-used; + * $f2-$f9 we save here; + * $f16-$21 are input args (call-used); + * $f31 is always zero. + * + * Note that even on Sw_64 hardware that does not have an FPU (there + * isn't such a thing currently) it is required to implement the FP + * registers. + */ + +#ifndef __ASSEMBLY__ +typedef long int __jmp_buf[17]; +#endif + +#endif /* bits/setjmp.h */ diff --git a/sysdeps/sw_64/bsd-_setjmp.S b/sysdeps/sw_64/bsd-_setjmp.S new file mode 100644 index 00000000..4e6a2da5 --- /dev/null +++ b/sysdeps/sw_64/bsd-_setjmp.S @@ -0,0 +1 @@ +/* _setjmp is in setjmp.S */ diff --git a/sysdeps/sw_64/bsd-setjmp.S b/sysdeps/sw_64/bsd-setjmp.S new file mode 100644 index 00000000..1da848d2 --- /dev/null +++ b/sysdeps/sw_64/bsd-setjmp.S @@ -0,0 +1 @@ +/* setjmp is in setjmp.S */ diff --git a/sysdeps/sw_64/crti.S b/sysdeps/sw_64/crti.S new file mode 100644 index 00000000..29cf51ec --- /dev/null +++ b/sysdeps/sw_64/crti.S @@ -0,0 +1,101 @@ +/* Special .init and .fini section support for Sw_64. + Copyright (C) 2001-2023 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. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + 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, see + . */ + +/* crti.S puts a function prologue at the beginning of the .init and + .fini sections and defines global symbols for those addresses, so + they can be called as functions. The symbols _init and _fini are + magic and cause the linker to emit DT_INIT and DT_FINI. + + This differs from what would be generated for ordinary code in that + we save and restore the GP within the function. In order for linker + relaxation to work, the value in the GP register on exit from a function + must be valid for the function entry point. Normally, a function is + contained within one object file and this is not an issue, provided + that the function reloads the gp after making any function calls. + However, _init and _fini are constructed from pieces of many object + files, all of which may have different GP values. So we must reload + the GP value from crti.o in crtn.o. */ + +#include +#include + +#ifndef PREINIT_FUNCTION +# define PREINIT_FUNCTION __gmon_start__ +#endif + +#ifndef PREINIT_FUNCTION_WEAK +# define PREINIT_FUNCTION_WEAK 1 +#endif + +#if PREINIT_FUNCTION_WEAK + weak_extern (PREINIT_FUNCTION) +#else + .hidden PREINIT_FUNCTION +#endif + + .section .init, "ax", @progbits + .globl _init + .hidden _init + .type _init, @function + .usepv _init, std +_init: + ldgp $29, 0($27) + subl $30, 16, $30 +#if PREINIT_FUNCTION_WEAK + ldi $27, PREINIT_FUNCTION +#endif + stl $26, 0($30) + stl $29, 8($30) +#if PREINIT_FUNCTION_WEAK + beq $27, 1f + call $26, ($27), PREINIT_FUNCTION + ldl $29, 8($30) +1: +#else + bsr $26, PREINIT_FUNCTION !samegp +#endif + .p2align 3 + + .section .fini, "ax", @progbits + .globl _fini + .hidden _fini + .type _fini,@function + .usepv _fini,std +_fini: + ldgp $29, 0($27) + subl $30, 16, $30 + stl $26, 0($30) + stl $29, 8($30) + .p2align 3 diff --git a/sysdeps/sw_64/crtn.S b/sysdeps/sw_64/crtn.S new file mode 100644 index 00000000..4de241a9 --- /dev/null +++ b/sysdeps/sw_64/crtn.S @@ -0,0 +1,49 @@ +/* Special .init and .fini section support for Sw_64. + Copyright (C) 2001-2023 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. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + 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, see + . */ + +/* crtn.S puts function epilogues in the .init and .fini sections + corresponding to the prologues in crti.S. */ + + .section .init, "ax", @progbits + ldl $26, 0($30) + ldl $29, 8($30) + addl $30, 16, $30 + ret + + .section .fini, "ax", @progbits + ldl $26, 0($30) + ldl $29, 8($30) + addl $30, 16, $30 + ret diff --git a/sysdeps/sw_64/dl-dtprocnum.h b/sysdeps/sw_64/dl-dtprocnum.h new file mode 100644 index 00000000..05777c06 --- /dev/null +++ b/sysdeps/sw_64/dl-dtprocnum.h @@ -0,0 +1,3 @@ +/* Number of extra dynamic section entries for this architecture. By + default there are none. */ +#define DT_THISPROCNUM DT_SW_64_NUM diff --git a/sysdeps/sw_64/dl-machine.h b/sysdeps/sw_64/dl-machine.h new file mode 100644 index 00000000..54822f12 --- /dev/null +++ b/sysdeps/sw_64/dl-machine.h @@ -0,0 +1,463 @@ +/* Machine-dependent ELF dynamic relocation inline functions. Sw_64 version. + Copyright (C) 1996-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson . + + 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, see + . */ + +/* This was written in the absence of an ABI -- don't expect + it to remain unchanged. */ + +#ifndef dl_machine_h +#define dl_machine_h 1 + +#define ELF_MACHINE_NAME "sw_64" + +#include +#include +#include + +/* Mask identifying addresses reserved for the user program, + where the dynamic linker should not map anything. */ +#define ELF_MACHINE_USER_ADDRESS_MASK 0x120000000UL + +/* Translate a processor specific dynamic tag to the index in l_info array. */ +#define DT_SW_64(x) (DT_SW_64_##x - DT_LOPROC + DT_NUM) + +/* Return nonzero iff ELF header is compatible with the running host. */ +static inline int +elf_machine_matches_host (const Elf64_Ehdr *ehdr) +{ + return ehdr->e_machine == EM_SW_64; +} + +/* Return the link-time address of _DYNAMIC. The multiple-got-capable + linker no longer allocates the first .got entry for this. But not to + worry, no special tricks are needed. */ +static inline Elf64_Addr +elf_machine_dynamic (void) +{ +#ifndef NO_AXP_MULTI_GOT_LD + return (Elf64_Addr) &_DYNAMIC; +#else + register Elf64_Addr *gp __asm__ ("$29"); + return gp[-4096]; +#endif +} + +/* Return the run-time load address of the shared object. */ + +static inline Elf64_Addr +elf_machine_load_address (void) +{ + /* This relies on the compiler using gp-relative addresses for static + * symbols. */ + static void *dot = ˙ + return (void *) &dot - dot; +} + +/* Set up the loaded object described by L so its unrelocated PLT + entries will jump to the on-demand fixup code in dl-runtime.c. */ + +static inline int +elf_machine_runtime_setup (struct link_map *map, struct r_scope_elem *scope[], + int lazy, int profile) +{ + extern char _dl_runtime_resolve_new[] attribute_hidden; + extern char _dl_runtime_profile_new[] attribute_hidden; + extern char _dl_runtime_resolve_old[] attribute_hidden; + extern char _dl_runtime_profile_old[] attribute_hidden; + + struct pltgot + { + char *resolve; + struct link_map *link; + }; + + struct pltgot *pg; + long secureplt; + char *resolve; + + if (map->l_info[DT_JMPREL] == 0 || !lazy) + return lazy; + + /* Check to see if we're using the read-only plt form. */ + secureplt = map->l_info[DT_SW_64 (PLTRO)] != 0; + + /* If the binary uses the read-only secure plt format, PG points to + the .got.plt section, which is the right place for ld.so to place + its hooks. Otherwise, PG is currently pointing at the start of + the plt; the hooks go at offset 16. */ + pg = (struct pltgot *) D_PTR (map, l_info[DT_PLTGOT]); + pg += !secureplt; + + /* This function will be called to perform the relocation. They're + not declared as functions to convince the compiler to use gp + relative relocations for them. */ + if (secureplt) + resolve = _dl_runtime_resolve_new; + else + resolve = _dl_runtime_resolve_old; + + if (__builtin_expect (profile, 0)) + { + if (secureplt) + resolve = _dl_runtime_profile_new; + else + resolve = _dl_runtime_profile_old; + + if (GLRO (dl_profile) && _dl_name_match_p (GLRO (dl_profile), map)) + { + /* This is the object we are looking for. Say that we really + want profiling and the timers are started. */ + GL (dl_profile_map) = map; + } + } + + pg->resolve = resolve; + pg->link = map; + + return lazy; +} + +/* Initial entry point code for the dynamic linker. + The C function `_dl_start' is the real entry point; + its return value is the user program's entry point. */ + +#define RTLD_START \ + asm("\ + .section .text \n\ + .set at \n\ + .globl _start \n\ + .ent _start \n\ +_start: \n\ + .frame $31,0,$31,0 \n\ + br $gp, 0f \n\ +0: ldgp $gp, 0($gp) \n\ + .prologue 0 \n\ + /* Pass pointer to argument block to _dl_start. */ \n\ + mov $sp, $16 \n\ + bsr $26, _dl_start !samegp \n\ + .end _start \n\ + /* FALLTHRU */ \n\ + .globl _dl_start_user \n\ + .ent _dl_start_user \n\ +_dl_start_user: \n\ + .frame $31,0,$31,0 \n\ + .prologue 0 \n\ + /* Save the user entry point address in s0. */ \n\ + mov $0, $9 \n\ + /* The special initializer gets called with the stack \n\ + just as the application's entry point will see it; \n\ + it can switch stacks if it moves these contents \n\ + over. */ \n\ +" RTLD_START_SPECIAL_INIT " \n\ + /* Call _dl_init(_dl_loaded, argc, argv, envp) to run \n\ + initializers. */ \n\ + ldih $16, _rtld_local($gp) !gprelhigh \n\ + ldl $16, _rtld_local($16) !gprellow \n\ + ldl $17, 0($sp) \n\ + ldi $18, 8($sp) \n\ + s8addl $17, 8, $19 \n\ + addl $19, $18, $19 \n\ + bsr $26, _dl_init !samegp \n\ + /* Pass our finalizer function to the user in $0. */ \n\ + ldih $0, _dl_fini($gp) !gprelhigh \n\ + ldi $0, _dl_fini($0) !gprellow \n\ + /* Jump to the user's entry point. */ \n\ + mov $9, $27 \n\ + jmp ($9) \n\ + .end _dl_start_user \n\ + .set noat \n\ +.previous"); + +#ifndef RTLD_START_SPECIAL_INIT +# define RTLD_START_SPECIAL_INIT /* nothing */ +#endif + +/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry + or TLS variables, so undefined references should not be allowed + to define the value. + + ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve + to one of the main executable's symbols, as for a COPY reloc. + This is unused on Sw_64. */ + +#define elf_machine_type_class(type) \ + (((type) == R_SW_64_JMP_SLOT || (type) == R_SW_64_DTPMOD64 \ + || (type) == R_SW_64_DTPREL64 || (type) == R_SW_64_TPREL64) \ + * ELF_RTYPE_CLASS_PLT) + +/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */ +#define ELF_MACHINE_JMP_SLOT R_SW_64_JMP_SLOT + +/* The sw_64 never uses Elf64_Rel relocations. */ +/*#define ELF_MACHINE_NO_REL 1 +#define ELF_MACHINE_NO_RELA 0 +*/ +/* We define an initialization functions. This is called very early in + * _dl_sysdep_start. */ +#define DL_PLATFORM_INIT dl_platform_init () + +static inline void __attribute__ ((unused)) dl_platform_init (void) +{ + if (GLRO (dl_platform) != NULL && *GLRO (dl_platform) == '\0') + /* Avoid an empty string which would disturb us. */ + GLRO (dl_platform) = NULL; +} + +/* Fix up the instructions of a PLT entry to invoke the function + rather than the dynamic linker. */ +static inline Elf64_Addr +elf_machine_fixup_plt (struct link_map *map, lookup_t t, + const ElfW (Sym) * refsym, const ElfW (Sym) * sym, + const Elf64_Rela *reloc, Elf64_Addr *got_addr, + Elf64_Addr value) +{ + const Elf64_Rela *rela_plt; + Elf64_Word *plte; + long int edisp; + + /* Store the value we are going to load. */ + *got_addr = value; + + /* If this binary uses the read-only secure plt format, we're done. */ + if (map->l_info[DT_SW_64 (PLTRO)]) + return value; + + /* Otherwise we have to modify the plt entry in place to do the branch. */ + + /* Recover the PLT entry address by calculating reloc's index into the + .rela.plt, and finding that entry in the .plt. */ + rela_plt = (const Elf64_Rela *) D_PTR (map, l_info[DT_JMPREL]); + plte = (Elf64_Word *) (D_PTR (map, l_info[DT_PLTGOT]) + 32); + plte += 3 * (reloc - rela_plt); + + /* Find the displacement from the plt entry to the function. */ + edisp = (long int) (value - (Elf64_Addr) &plte[3]) / 4; + + if (edisp >= -0x100000 && edisp < 0x100000) + { + /* If we are in range, use br to perfect branch prediction and + elide the dependency on the address load. This case happens, + e.g., when a shared library call is resolved to the same library. */ + + int hi, lo; + hi = value - (Elf64_Addr) &plte[0]; + lo = (short int) hi; + hi = (hi - lo) >> 16; + + /* Emit "lda $27,lo($27)" */ + plte[1] = 0xfb7b0000 | (lo & 0xffff); + + /* Emit "br $31,function" */ + plte[2] = 0x13e00000 | (edisp & 0x1fffff); + + /* Think about thread-safety -- the previous instructions must be + committed to memory before the first is overwritten. */ + __asm__ __volatile__("memb" : : : "memory"); + + /* Emit "ldah $27,hi($27)" */ + plte[0] = 0xff7b0000 | (hi & 0xffff); + } + else + { + /* Don't bother with the hint since we already know the hint is + wrong. Eliding it prevents the wrong page from getting pulled + into the cache. */ + + int hi, lo; + hi = (Elf64_Addr) got_addr - (Elf64_Addr) &plte[0]; + lo = (short) hi; + hi = (hi - lo) >> 16; + + /* Emit "ldq $27,lo($27)" */ + plte[1] = 0x8f7b0000 | (lo & 0xffff); + + /* Emit "jmp $31,($27)" */ + plte[2] = 0x0ffb0000; + /* Think about thread-safety -- the previous instructions must be + committed to memory before the first is overwritten. */ + __asm__ __volatile__("memb" : : : "memory"); + + /* Emit "ldah $27,hi($27)" */ + plte[0] = 0xff7b0000 | (hi & 0xffff); + } + + /* At this point, if we've been doing runtime resolution, Icache is dirty. + This will be taken care of in _dl_runtime_resolve. If instead we are + doing this as part of non-lazy startup relocation, that bit of code + hasn't made it into Icache yet, so there's nothing to clean up. */ + + return value; +} + +/* Return the final value of a plt relocation. */ +static inline Elf64_Addr +elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc, + Elf64_Addr value) +{ + return value + reloc->r_addend; +} + +/* Names of the architecture-specific auditing callback functions. */ +#define ARCH_LA_PLTENTER sw_64_gnu_pltenter +#define ARCH_LA_PLTEXIT sw_64_gnu_pltexit + +#endif /* !dl_machine_h */ + +#ifdef RESOLVE_MAP + +/* Perform the relocation specified by RELOC and SYM (which is fully resolved). + MAP is the object containing the reloc. */ +static inline void __attribute__ ((always_inline)) +elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[], + const Elf64_Rela *reloc, const Elf64_Sym *sym, + const struct r_found_version *version, + void *const reloc_addr_arg, int skip_ifunc) +{ + Elf64_Addr *const reloc_addr = reloc_addr_arg; + unsigned long int const r_type = ELF64_R_TYPE (reloc->r_info); + + /* We cannot use a switch here because we cannot locate the switch + jump table until we've self-relocated. */ + +#if !defined RTLD_BOOTSTRAP + if (__builtin_expect (r_type == R_SW_64_RELATIVE, 0)) + { + //# if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC + // /* Already done in dynamic linker. */ + Elf64_Addr reloc_addr_val; + // if (map != &GL(dl_rtld_map)) + //# endif + // { + /* XXX Make some timings. Maybe it's preferable to test for + unaligned access and only do it the complex way if necessary. */ + + /* Load value without causing unaligned trap. */ + memcpy (&reloc_addr_val, reloc_addr_arg, 8); + reloc_addr_val += map->l_addr; + + /* Store value without causing unaligned trap. */ + memcpy (reloc_addr_arg, &reloc_addr_val, 8); + // } + } + else +#endif + if (__builtin_expect (r_type == R_SW_64_NONE, 0)) + return; + else + { + struct link_map *sym_map + = RESOLVE_MAP (map, scope, &sym, version, r_type); + Elf64_Addr sym_value; + Elf64_Addr sym_raw_value; + + sym_raw_value = sym_value = reloc->r_addend; + if (sym_map) + { + sym_raw_value += sym->st_value; + sym_value += SYMBOL_ADDRESS (sym_map, sym, true); + } + + if (r_type == R_SW_64_GLOB_DAT) + *reloc_addr = sym_value; + else if (r_type == R_SW_64_JMP_SLOT) + elf_machine_fixup_plt (map, 0, 0, 0, reloc, reloc_addr, sym_value); +#ifndef RTLD_BOOTSTRAP + else if (r_type == R_SW_64_REFQUAD) + { + /* Store value without causing unaligned trap. */ + memcpy (reloc_addr_arg, &sym_value, 8); + } +#endif + else if (r_type == R_SW_64_DTPMOD64) + { +#ifdef RTLD_BOOTSTRAP + /* During startup the dynamic linker is always index 1. */ + *reloc_addr = 1; +#else + /* Get the information from the link map returned by the + resolv function. */ + if (sym_map != NULL) + *reloc_addr = sym_map->l_tls_modid; +#endif + } + else if (r_type == R_SW_64_DTPREL64) + { +#ifndef RTLD_BOOTSTRAP + /* During relocation all TLS symbols are defined and used. + Therefore the offset is already correct. */ + *reloc_addr = sym_raw_value; +#endif + } + else if (r_type == R_SW_64_TPREL64) + { +#ifdef RTLD_BOOTSTRAP + *reloc_addr = sym_raw_value + map->l_tls_offset; +#else + if (sym_map) + { + CHECK_STATIC_TLS (map, sym_map); + *reloc_addr = sym_raw_value + sym_map->l_tls_offset; + } +#endif + } + else + _dl_reloc_bad_type (map, r_type, 0); + } +} + +/* Let do-rel.h know that on Sw_64 if l_addr is 0, all RELATIVE relocs + can be skipped. */ +#define ELF_MACHINE_REL_RELATIVE 1 + +static inline void __attribute__ ((always_inline)) +elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc, + void *const reloc_addr_arg) +{ + /* XXX Make some timings. Maybe it's preferable to test for + unaligned access and only do it the complex way if necessary. */ + Elf64_Addr reloc_addr_val; + + /* Load value without causing unaligned trap. */ + memcpy (&reloc_addr_val, reloc_addr_arg, 8); + reloc_addr_val += l_addr; + + /* Store value without causing unaligned trap. */ + memcpy (reloc_addr_arg, &reloc_addr_val, 8); +} + +static inline void __attribute__ ((always_inline)) +elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[], + Elf64_Addr l_addr, const Elf64_Rela *reloc, + int skip_ifunc) +{ + Elf64_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset); + unsigned long int const r_type = ELF64_R_TYPE (reloc->r_info); + + if (r_type == R_SW_64_JMP_SLOT) + { + /* Perform a RELATIVE reloc on the .got entry that transfers + to the .plt. */ + *reloc_addr += l_addr; + } + else if (r_type == R_SW_64_NONE) + return; + else + _dl_reloc_bad_type (map, r_type, 1); +} + +#endif /* RESOLVE_MAP */ diff --git a/sysdeps/sw_64/dl-procinfo.c b/sysdeps/sw_64/dl-procinfo.c new file mode 100644 index 00000000..253f3aba --- /dev/null +++ b/sysdeps/sw_64/dl-procinfo.c @@ -0,0 +1,63 @@ +/* Data for Sw_64 version of processor capability information. + Copyright (C) 2008-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Aurelien Jarno , 2008. + + 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, see + . */ + +/* This information must be kept in sync with the _DL_PLATFORM_COUNT + definitions in procinfo.h. + + If anything should be added here check whether the size of each string + is still ok with the given array size. + + All the #ifdefs in the definitions are quite irritating but + necessary if we want to avoid duplicating the information. There + are three different modes: + + - PROCINFO_DECL is defined. This means we are only interested in + declarations. + + - PROCINFO_DECL is not defined: + + + if SHARED is defined the file is included in an array + initializer. The .element = { ... } syntax is needed. + + + if SHARED is not defined a normal array initialization is + needed. + */ + +#ifndef PROCINFO_CLASS +# define PROCINFO_CLASS +#endif + +#if !defined PROCINFO_DECL && defined SHARED +._dl_sw_64_platforms +#else +PROCINFO_CLASS const char _dl_sw_64_platforms[5][5] +#endif +#ifndef PROCINFO_DECL += { + "sw8a", "ev5", "sw6a", "sw6b", "sw6c" + } +#endif +#if !defined SHARED || defined PROCINFO_DECL +; +#else + , +#endif + +#undef PROCINFO_DECL +#undef PROCINFO_CLASS diff --git a/sysdeps/sw_64/dl-procinfo.h b/sysdeps/sw_64/dl-procinfo.h new file mode 100644 index 00000000..ea9df900 --- /dev/null +++ b/sysdeps/sw_64/dl-procinfo.h @@ -0,0 +1,58 @@ +/* Sw_64 version of processor capability information handling macros. + Copyright (C) 2008-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Aurelien Jarno , 2008. + + 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, see + . */ + +#ifndef _DL_PROCINFO_H +#define _DL_PROCINFO_H 1 + +#include + +/* Mask to filter out platforms. */ +#define _DL_HWCAP_PLATFORM (-1ULL) + +#define _DL_PLATFORMS_COUNT 5 + +static inline int __attribute__ ((unused, always_inline)) +_dl_string_platform (const char *str) +{ + int i; + + if (str != NULL) + for (i = 0; i < _DL_PLATFORMS_COUNT; ++i) + { + if (strcmp (str, GLRO (dl_sw_64_platforms)[i]) == 0) + return i; + } + return -1; +}; + +/* We cannot provide a general printing function. */ +#define _dl_procinfo(type, word) -1 + +/* There are no hardware capabilities defined. */ +#define _dl_hwcap_string(idx) "" + +/* By default there is no important hardware capability. */ +#define HWCAP_IMPORTANT (0) + +/* We don't have any hardware capabilities. */ +#define _DL_HWCAP_COUNT 0 + +#define _dl_string_hwcap(str) (-1) + +#endif /* dl-procinfo.h */ diff --git a/sysdeps/sw_64/dl-sysdep.h b/sysdeps/sw_64/dl-sysdep.h new file mode 100644 index 00000000..b3823567 --- /dev/null +++ b/sysdeps/sw_64/dl-sysdep.h @@ -0,0 +1,23 @@ +/* System-specific settings for dynamic linker code. Sw_64 version. + Copyright (C) 2002-2023 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, see + . */ + +#include_next + +/* _dl_argv cannot be attribute_relro, because _dl_start_user + might write into it after _dl_start returns. */ +#define DL_ARGV_NOT_RELRO 1 diff --git a/sysdeps/sw_64/dl-trampoline.S b/sysdeps/sw_64/dl-trampoline.S new file mode 100644 index 00000000..72178557 --- /dev/null +++ b/sysdeps/sw_64/dl-trampoline.S @@ -0,0 +1,540 @@ +/* PLT trampolines. Sw_64 version. + Copyright (C) 2005-2023 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, see + . */ + +#include + + .set noat + +.macro savei regno, offset + stl $\regno, \offset($30) + cfi_rel_offset(\regno, \offset) +.endm + +.macro savef regno, offset + fstd $f\regno, \offset($30) + cfi_rel_offset(\regno+32, \offset) +.endm + + .align 4 + .globl _dl_runtime_resolve_new + .ent _dl_runtime_resolve_new + +#undef FRAMESIZE +#define FRAMESIZE 14*8 + +_dl_runtime_resolve_new: + .frame $30, FRAMESIZE, $26, 0 + .mask 0x4000000, 0 + + ldih $29, 0($27) !gpdisp!1 + ldi $30, -FRAMESIZE($30) + stl $26, 0*8($30) + stl $16, 2*8($30) + + stl $17, 3*8($30) + ldi $29, 0($29) !gpdisp!1 + stl $18, 4*8($30) + mov $28, $16 /* link_map from .got.plt */ + + stl $19, 5*8($30) + mov $25, $17 /* offset of reloc entry */ + stl $20, 6*8($30) + mov $26, $18 /* return address */ + + stl $21, 7*8($30) + fstd $f16, 8*8($30) + fstd $f17, 9*8($30) + fstd $f18, 10*8($30) + + fstd $f19, 11*8($30) + fstd $f20, 12*8($30) + fstd $f21, 13*8($30) + .prologue 2 + + bsr $26, _dl_fixup !samegp + mov $0, $27 + + ldl $26, 0*8($30) + ldl $16, 2*8($30) + ldl $17, 3*8($30) + ldl $18, 4*8($30) + ldl $19, 5*8($30) + ldl $20, 6*8($30) + ldl $21, 7*8($30) + fldd $f16, 8*8($30) + fldd $f17, 9*8($30) + fldd $f18, 10*8($30) + fldd $f19, 11*8($30) + fldd $f20, 12*8($30) + fldd $f21, 13*8($30) + ldi $30, FRAMESIZE($30) + jmp $31, ($27), 0 + .end _dl_runtime_resolve_new + + .globl _dl_runtime_profile_new + .type _dl_runtime_profile_new, @function + +#undef FRAMESIZE +#define FRAMESIZE 20*8 + + /* We save the registers in a different order than desired by + .mask/.fmask, so we have to use explicit cfi directives. */ + cfi_startproc + +_dl_runtime_profile_new: + ldih $29, 0($27) !gpdisp!2 + ldi $30, -FRAMESIZE($30) + savei 26, 0*8 + stl $16, 2*8($30) + + stl $17, 3*8($30) + ldi $29, 0($29) !gpdisp!2 + stl $18, 4*8($30) + ldi $1, FRAMESIZE($30) /* incoming sp value */ + + stl $1, 1*8($30) + stl $19, 5*8($30) + stl $20, 6*8($30) + mov $28, $16 /* link_map from .got.plt */ + + stl $21, 7*8($30) + mov $25, $17 /* offset of reloc entry */ + fstd $f16, 8*8($30) + mov $26, $18 /* return address */ + + fstd $f17, 9*8($30) + mov $30, $19 /* La_sw_64_regs address */ + fstd $f18, 10*8($30) + ldi $20, 14*8($30) /* framesize address */ + + fstd $f19, 11*8($30) + fstd $f20, 12*8($30) + fstd $f21, 13*8($30) + stl $28, 16*8($30) + stl $25, 17*8($30) + + bsr $26, _dl_profile_fixup !samegp + mov $0, $27 + + /* Discover if we're wrapping this call. */ + ldl $18, 14*8($30) + bge $18, 1f + + ldl $26, 0*8($30) + ldl $16, 2*8($30) + ldl $17, 3*8($30) + ldl $18, 4*8($30) + ldl $19, 5*8($30) + ldl $20, 6*8($30) + ldl $21, 7*8($30) + fldd $f16, 8*8($30) + fldd $f17, 9*8($30) + fldd $f18, 10*8($30) + fldd $f19, 11*8($30) + fldd $f20, 12*8($30) + fldd $f21, 13*8($30) + ldi $30, FRAMESIZE($30) + jmp $31, ($27), 0 + +1: + /* Create a frame pointer and allocate a new argument frame. */ + savei 15, 15*8 + mov $30, $15 + cfi_def_cfa_register (15) + addl $18, 15, $18 + bic $18, 15, $18 + subl $30, $18, $30 + + /* Save the call destination around memcpy. */ + stl $0, 14*8($30) + + /* Copy the stack arguments into place. */ + ldi $16, 0($30) + ldi $17, FRAMESIZE($15) + call $26, memcpy + ldgp $29, 0($26) + + /* Reload the argument registers. */ + ldl $27, 14*8($30) + ldl $16, 2*8($15) + ldl $17, 3*8($15) + ldl $18, 4*8($15) + ldl $19, 5*8($15) + ldl $20, 6*8($15) + ldl $21, 7*8($15) + fldd $f16, 8*8($15) + fldd $f17, 9*8($15) + fldd $f18, 10*8($15) + fldd $f19, 11*8($15) + fldd $f20, 12*8($15) + fldd $f21, 13*8($15) + + call $26, ($27), 0 + ldgp $29, 0($26) + + /* Set up for call to _dl_audit_pltexit. */ + ldl $16, 16*8($15) + ldl $17, 17*8($15) + stl $0, 16*8($15) + ldi $18, 0($15) + stl $1, 17*8($15) + ldi $19, 16*8($15) + fstd $f0, 18*8($15) + fstd $f1, 19*8($15) + bsr $26, _dl_audit_pltexit !samegp + + mov $15, $30 + cfi_def_cfa_register (30) + ldl $26, 0($30) + ldl $15, 15*8($30) + ldi $30, FRAMESIZE($30) + ret + + cfi_endproc + .size _dl_runtime_profile_new, .-_dl_runtime_profile_new + + .align 4 + .globl _dl_runtime_resolve_old + .ent _dl_runtime_resolve_old + +#undef FRAMESIZE +#define FRAMESIZE 44*8 + +_dl_runtime_resolve_old: + ldi $30, -FRAMESIZE($30) + .frame $30, FRAMESIZE, $26 + /* Preserve all registers that C normally doesn't. */ + stl $26, 0*8($30) + stl $0, 1*8($30) + stl $1, 2*8($30) + stl $2, 3*8($30) + stl $3, 4*8($30) + stl $4, 5*8($30) + stl $5, 6*8($30) + stl $6, 7*8($30) + stl $7, 8*8($30) + stl $8, 9*8($30) + stl $16, 10*8($30) + stl $17, 11*8($30) + stl $18, 12*8($30) + stl $19, 13*8($30) + stl $20, 14*8($30) + stl $21, 15*8($30) + stl $22, 16*8($30) + stl $23, 17*8($30) + stl $24, 18*8($30) + stl $25, 19*8($30) + stl $29, 20*8($30) + fstd $f0, 21*8($30) + fstd $f1, 22*8($30) + fstd $f10, 23*8($30) + fstd $f11, 24*8($30) + fstd $f12, 25*8($30) + fstd $f13, 26*8($30) + fstd $f14, 27*8($30) + fstd $f15, 28*8($30) + fstd $f16, 29*8($30) + fstd $f17, 30*8($30) + fstd $f18, 31*8($30) + fstd $f19, 32*8($30) + fstd $f20, 33*8($30) + fstd $f21, 34*8($30) + fstd $f22, 35*8($30) + fstd $f23, 36*8($30) + fstd $f24, 37*8($30) + fstd $f25, 38*8($30) + fstd $f26, 39*8($30) + fstd $f27, 40*8($30) + fstd $f28, 41*8($30) + fstd $f29, 42*8($30) + fstd $f30, 43*8($30) + .mask 0x27ff01ff, -FRAMESIZE + .fmask 0xfffffc03, -FRAMESIZE+21*8 + /* Set up our GP. */ + br $29, .+4 + ldgp $29, 0($29) + .prologue 0 + /* Set up the arguments for _dl_fixup: + $16 = link_map out of plt0 + $17 = offset of reloc entry = ($28 - $27 - 20) /12 * 24 + $18 = return address + */ + subl $28, $27, $17 + ldl $16, 8($27) + subl $17, 20, $17 + mov $26, $18 + addl $17, $17, $17 + bsr $26, _dl_fixup !samegp + + /* Move the destination address into position. */ + mov $0, $27 + /* Restore program registers. */ + ldl $26, 0*8($30) + ldl $0, 1*8($30) + ldl $1, 2*8($30) + ldl $2, 3*8($30) + ldl $3, 4*8($30) + ldl $4, 5*8($30) + ldl $5, 6*8($30) + ldl $6, 7*8($30) + ldl $7, 8*8($30) + ldl $8, 9*8($30) + ldl $16, 10*8($30) + ldl $17, 11*8($30) + ldl $18, 12*8($30) + ldl $19, 13*8($30) + ldl $20, 14*8($30) + ldl $21, 15*8($30) + ldl $22, 16*8($30) + ldl $23, 17*8($30) + ldl $24, 18*8($30) + ldl $25, 19*8($30) + ldl $29, 20*8($30) + fldd $f0, 21*8($30) + fldd $f1, 22*8($30) + fldd $f10, 23*8($30) + fldd $f11, 24*8($30) + fldd $f12, 25*8($30) + fldd $f13, 26*8($30) + fldd $f14, 27*8($30) + fldd $f15, 28*8($30) + fldd $f16, 29*8($30) + fldd $f17, 30*8($30) + fldd $f18, 31*8($30) + fldd $f19, 32*8($30) + fldd $f20, 33*8($30) + fldd $f21, 34*8($30) + fldd $f22, 35*8($30) + fldd $f23, 36*8($30) + fldd $f24, 37*8($30) + fldd $f25, 38*8($30) + fldd $f26, 39*8($30) + fldd $f27, 40*8($30) + fldd $f28, 41*8($30) + fldd $f29, 42*8($30) + fldd $f30, 43*8($30) + /* Flush the Icache after having modified the .plt code. */ + imb + /* Clean up and turn control to the destination */ + ldi $30, FRAMESIZE($30) + jmp $31, ($27) + + .end _dl_runtime_resolve_old + + .globl _dl_runtime_profile_old + .usepv _dl_runtime_profile_old, no + .type _dl_runtime_profile_old, @function + + /* We save the registers in a different order than desired by + .mask/.fmask, so we have to use explicit cfi directives. */ + cfi_startproc + +#undef FRAMESIZE +#define FRAMESIZE 50*8 + + .align 4 +_dl_runtime_profile_old: + ldi $30, -FRAMESIZE($30) + cfi_adjust_cfa_offset (FRAMESIZE) + + /* Preserve all argument registers. This also constructs the + La_sw_64_regs structure. */ + savei 26, 0*8 + savei 16, 2*8 + savei 17, 3*8 + savei 18, 4*8 + savei 19, 5*8 + savei 20, 6*8 + savei 21, 7*8 + ldi $16, FRAMESIZE($30) + savef 16, 8*8 + savef 17, 9*8 + savef 18, 10*8 + savef 19, 11*8 + savef 20, 12*8 + savef 21, 13*8 + stl $16, 1*8($30) + + /* Preserve all registers that C normally doesn't. */ + savei 0, 14*8 + savei 1, 15*8 + savei 2, 16*8 + savei 3, 17*8 + savei 4, 18*8 + savei 5, 19*8 + savei 6, 20*8 + savei 7, 21*8 + savei 8, 22*8 + savei 22, 23*8 + savei 23, 24*8 + savei 24, 25*8 + savei 25, 26*8 + savei 29, 27*8 + savef 0, 28*8 + savef 1, 29*8 + savef 10, 30*8 + savef 11, 31*8 + savef 12, 32*8 + savef 13, 33*8 + savef 14, 34*8 + savef 15, 35*8 + savef 22, 36*8 + savef 23, 37*8 + savef 24, 38*8 + savef 25, 39*8 + savef 26, 40*8 + savef 27, 41*8 + savef 28, 42*8 + savef 29, 43*8 + savef 30, 44*8 + + /* Set up our GP. */ + br $29, .+4 + ldgp $29, 0($29) + + /* Set up the arguments for _dl_profile_fixup: + $16 = link_map out of plt0 + $17 = offset of reloc entry = ($28 - $27 - 20) /12 * 24 + $18 = return address + $19 = La_sw_64_regs address + $20 = framesize address + */ + subl $28, $27, $17 + ldl $16, 8($27) + subl $17, 20, $17 + mov $26, $18 + addl $17, $17, $17 + ldi $19, 0($30) + ldi $20, 45*8($30) + stl $16, 48*8($30) + stl $17, 49*8($30) + + bsr $26, _dl_profile_fixup !samegp + + /* Discover if we're wrapping this call. */ + ldl $18, 45*8($30) + bge $18, 1f + + /* Move the destination address into position. */ + mov $0, $27 + /* Restore program registers. */ + ldl $26, 0*8($30) + ldl $16, 2*8($30) + ldl $17, 3*8($30) + ldl $18, 4*8($30) + ldl $19, 5*8($30) + ldl $20, 6*8($30) + ldl $21, 7*8($30) + fldd $f16, 8*8($30) + fldd $f17, 9*8($30) + fldd $f18, 10*8($30) + fldd $f19, 11*8($30) + fldd $f20, 12*8($30) + fldd $f21, 13*8($30) + ldl $0, 14*8($30) + ldl $1, 15*8($30) + ldl $2, 16*8($30) + ldl $3, 17*8($30) + ldl $4, 18*8($30) + ldl $5, 19*8($30) + ldl $6, 20*8($30) + ldl $7, 21*8($30) + ldl $8, 22*8($30) + ldl $22, 23*8($30) + ldl $23, 24*8($30) + ldl $24, 25*8($30) + ldl $25, 26*8($30) + ldl $29, 27*8($30) + fldd $f0, 28*8($30) + fldd $f1, 29*8($30) + fldd $f10, 30*8($30) + fldd $f11, 31*8($30) + fldd $f12, 32*8($30) + fldd $f13, 33*8($30) + fldd $f14, 34*8($30) + fldd $f15, 35*8($30) + fldd $f22, 36*8($30) + fldd $f23, 37*8($30) + fldd $f24, 38*8($30) + fldd $f25, 39*8($30) + fldd $f26, 40*8($30) + fldd $f27, 41*8($30) + fldd $f28, 42*8($30) + fldd $f29, 43*8($30) + fldd $f30, 44*8($30) + + /* Clean up and turn control to the destination. */ + ldi $30, FRAMESIZE($30) + jmp $31, ($27) + +1: + /* Create a frame pointer and allocate a new argument frame. */ + savei 15, 45*8 + mov $30, $15 + cfi_def_cfa_register (15) + addl $18, 15, $18 + bic $18, 15, $18 + subl $30, $18, $30 + + /* Save the call destination around memcpy. */ + stl $0, 46*8($30) + + /* Copy the stack arguments into place. */ + ldi $16, 0($30) + ldi $17, FRAMESIZE($15) + call $26, memcpy + ldgp $29, 0($26) + + /* Reload the argument registers. */ + ldl $27, 46*8($30) + ldl $16, 2*8($15) + ldl $17, 3*8($15) + ldl $18, 4*8($15) + ldl $19, 5*8($15) + ldl $20, 6*8($15) + ldl $21, 7*8($15) + fldd $f16, 8*8($15) + fldd $f17, 9*8($15) + fldd $f18, 10*8($15) + fldd $f19, 11*8($15) + fldd $f20, 12*8($15) + fldd $f21, 13*8($15) + + call $26, ($27), 0 + ldgp $29, 0($26) + + /* Set up for call to _dl_audit_pltexit. */ + ldl $16, 48*8($15) + ldl $17, 49*8($15) + stl $0, 46*8($15) + ldi $18, 0($15) + stl $1, 47*8($15) + ldi $19, 46*8($15) + fstd $f0, 48*8($15) + fstd $f1, 49*8($15) + bsr $26, _dl_audit_pltexit !samegp + + mov $15, $30 + cfi_def_cfa_register (30) + ldl $26, 0($30) + ldl $15, 45*8($30) + ldi $30, FRAMESIZE($30) + ret + + cfi_endproc + .size _dl_runtime_profile_old, .-_dl_runtime_profile_old diff --git a/sysdeps/sw_64/ffs.S b/sysdeps/sw_64/ffs.S new file mode 100644 index 00000000..f03bf357 --- /dev/null +++ b/sysdeps/sw_64/ffs.S @@ -0,0 +1,91 @@ +/* Copyright (C) 1996-2023 Free Software Foundation, Inc. + Contributed by David Mosberger (davidm@cs.arizona.edu). + 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, see + . */ + +/* Finds the first bit set in an integer. Optimized for the Sw_64 + architecture. */ + +#include + + .set noreorder + .set noat + + +ENTRY(__ffs) +#ifdef PROF + ldgp gp, 0(pv) + ldi AT, _mcount + call AT, (AT), _mcount + .prologue 1 + zap $16, 0xF0, $16 + br $ffsl..ng +#else + .prologue 0 + zap $16, 0xF0, $16 + # FALLTHRU +#endif +END(__ffs) + + .align 4 +ENTRY(ffsl) +#ifdef PROF + ldgp gp, 0(pv) + ldi AT, _mcount + call AT, (AT), _mcount + .prologue 1 +$ffsl..ng: +#else + .prologue 0 +#endif + not $16, $1 # e0 : + ldi $2, -1 # .. e1 : + cmpgeb $1, $2, $3 # e0 : bit N == 1 for byte N == 0 + clr $0 # .. e1 : + addl $3, 1, $4 # e0 : + bic $4, $3, $3 # e1 : bit N == 1 for first byte N != 0 + and $3, 0xF0, $4 # e0 : + and $3, 0xCC, $5 # .. e1 : + and $3, 0xAA, $6 # e0 : + selne $4, 4, $0, $0 # .. e1 : + selne $5, 2, $5, $5 # e0 : + selne $6, 1, $6, $6 # .. e1 : + addw $0, $5, $0 # e0 : + addw $0, $6, $0 # e1 : $0 == N + ext0b $16, $0, $1 # e0 : $1 == byte N + ldi $2, 1 # .. e1 : + negl $1, $3 # e0 : + and $3, $1, $3 # e1 : bit N == least bit set of byte N + and $3, 0xF0, $4 # e0 : + and $3, 0xCC, $5 # .. e1 : + and $3, 0xAA, $6 # e0 : + selne $4, 5, $2, $2 # .. e1 : + selne $5, 2, $5, $5 # e0 : + selne $6, 1, $6, $6 # .. e1 : + s8addw $0, $2, $0 # e0 : fmuld byte ofs by 8 and sum + addw $5, $6, $5 # .. e1 : + addw $0, $5, $0 # e0 : + nop # .. e1 : + seleq $16, 0, $0, $0 # e0 : trap input == 0 case. + ret # .. e1 : 18 + +END(ffsl) + +weak_alias (__ffs, ffs) +libc_hidden_def (__ffs) +libc_hidden_builtin_def (ffs) +weak_extern (ffsl) +weak_alias (ffsl, ffsll) diff --git a/sysdeps/sw_64/ffsll.S b/sysdeps/sw_64/ffsll.S new file mode 100644 index 00000000..b2f46d89 --- /dev/null +++ b/sysdeps/sw_64/ffsll.S @@ -0,0 +1 @@ +/* This function is defined in ffs.S. */ diff --git a/sysdeps/sw_64/jmpbuf-offsets.h b/sysdeps/sw_64/jmpbuf-offsets.h new file mode 100644 index 00000000..394ec163 --- /dev/null +++ b/sysdeps/sw_64/jmpbuf-offsets.h @@ -0,0 +1,35 @@ +/* Private macros for accessing __jmp_buf contents. Sw_64 version. + Copyright (C) 2006-2023 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, see + . */ + +#define JB_S0 0 +#define JB_S1 1 +#define JB_S2 2 +#define JB_S3 3 +#define JB_S4 4 +#define JB_S5 5 +#define JB_PC 6 +#define JB_FP 7 +#define JB_SP 8 +#define JB_F2 9 +#define JB_F3 10 +#define JB_F4 11 +#define JB_F5 12 +#define JB_F6 13 +#define JB_F7 14 +#define JB_F8 15 +#define JB_F9 16 diff --git a/sysdeps/sw_64/jmpbuf-unwind.h b/sysdeps/sw_64/jmpbuf-unwind.h new file mode 100644 index 00000000..9c3bdff9 --- /dev/null +++ b/sysdeps/sw_64/jmpbuf-unwind.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2003-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 2003. + + 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, see + . */ + +#include +#include +#include +#include +#include +#include + +/* Test if longjmp to JMPBUF would unwind the frame containing a local + variable at ADDRESS. */ +#define _JMPBUF_UNWINDS(_jmpbuf, _address, _demangle) \ + ((void *) (_address) < (void *) _demangle ((_jmpbuf)[JB_SP])) + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +static inline uintptr_t __attribute__ ((unused)) _jmpbuf_sp (__jmp_buf regs) +{ + uintptr_t sp = regs[JB_SP]; + PTR_DEMANGLE (sp); + return sp; +} + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < _jmpbuf_sp (_jmpbuf) - (_adj)) + +/* We use the normal longjmp for unwinding. */ +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/sysdeps/sw_64/ldsodefs.h b/sysdeps/sw_64/ldsodefs.h new file mode 100644 index 00000000..e46085a0 --- /dev/null +++ b/sysdeps/sw_64/ldsodefs.h @@ -0,0 +1,40 @@ +/* Run-time dynamic linker data structures for loaded ELF shared objects. + Copyright (C) 2012-2023 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, see + . */ + +#ifndef __LDSODEFS_H + +# include + +struct La_sw_64_regs; +struct La_sw_64_retval; + +# define ARCH_PLTENTER_MEMBERS \ + Elf64_Addr (*sw_64_gnu_pltenter) (Elf64_Sym *, unsigned int, uintptr_t *, \ + uintptr_t *, struct La_sw_64_regs *, \ + unsigned int *, const char *name, \ + long int *framesizep); + +# define ARCH_PLTEXIT_MEMBERS \ + unsigned int (*sw_64_gnu_pltexit) ( \ + Elf64_Sym *, unsigned int, uintptr_t *, uintptr_t *, \ + const struct La_sw_64_regs *, struct La_sw_64_retval *, \ + const char *); + +# include_next + +#endif diff --git a/sysdeps/sw_64/machine-gmon.h b/sysdeps/sw_64/machine-gmon.h new file mode 100644 index 00000000..3a558bc6 --- /dev/null +++ b/sysdeps/sw_64/machine-gmon.h @@ -0,0 +1,24 @@ +/* Machine-specific calling sequence for `mcount' profiling function. sw_64 + Copyright (C) 1995-2023 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, see + . */ + +#define _MCOUNT_DECL(from, self) void __mcount (u_long from, u_long self) + +/* Call __mcount with our the return PC for our caller, and the return + PC our caller will return to. Empty since we use an assembly stub + instead. */ +#define MCOUNT diff --git a/sysdeps/sw_64/nptl/pthread-offsets.h b/sysdeps/sw_64/nptl/pthread-offsets.h new file mode 100644 index 00000000..370e18ac --- /dev/null +++ b/sysdeps/sw_64/nptl/pthread-offsets.h @@ -0,0 +1,3 @@ +#define __PTHREAD_MUTEX_KIND_OFFSET 16 + +#define __PTHREAD_RWLOCK_FLAGS_OFFSET 48 diff --git a/sysdeps/sw_64/nptl/pthreaddef.h b/sysdeps/sw_64/nptl/pthreaddef.h new file mode 100644 index 00000000..e1fb46a9 --- /dev/null +++ b/sysdeps/sw_64/nptl/pthreaddef.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2003-2023 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, see + . */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (4 * 1024 * 1024) + +/* Minimum guard size. */ +#define ARCH_MIN_GUARD_SIZE 0 + +/* Required stack pointer alignment at beginning. The ABI requires 16. */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 4096 + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) diff --git a/sysdeps/sw_64/setjmp.S b/sysdeps/sw_64/setjmp.S new file mode 100644 index 00000000..9b0867eb --- /dev/null +++ b/sysdeps/sw_64/setjmp.S @@ -0,0 +1,121 @@ +/* Copyright (C) 1992-2023 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, see + . */ + +#define __ASSEMBLY__ + +#include +#include +#include + + .ent __sigsetjmp + .global __sigsetjmp +__sigsetjmp: + ldgp gp, 0(pv) + +$sigsetjmp_local: +#ifndef PIC +#define FRAME 16 + subl sp, FRAME, sp + .frame sp, FRAME, ra, 0 + stl ra, 0(sp) + .mask 0x04000000, -FRAME +#else +#define FRAME 0 + .frame sp, FRAME, ra, 0 +#endif +#ifdef PROF + .set noat + ldi AT, _mcount + call AT, (AT), _mcount + .set at +#endif + .prologue 1 + + stl s0, JB_S0*8(a0) + stl s1, JB_S1*8(a0) + stl s2, JB_S2*8(a0) + stl s3, JB_S3*8(a0) + stl s4, JB_S4*8(a0) + stl s5, JB_S5*8(a0) +#ifdef PTR_MANGLE + PTR_MANGLE(t1, ra, t0) + stl t1, JB_PC*8(a0) +#else + stl ra, JB_PC*8(a0) +#endif +#if defined(PTR_MANGLE) && FRAME == 0 + PTR_MANGLE2(t1, sp, t0) +#else + addl sp, FRAME, t1 +# ifdef PTR_MANGLE + PTR_MANGLE2(t1, t1, t0) +# endif +#endif + stl t1, JB_SP*8(a0) +#ifdef PTR_MANGLE + PTR_MANGLE2(t1, fp, t0) + stl t1, JB_FP*8(a0) +#else + stl fp, JB_FP*8(a0) +#endif + fstd $f2, JB_F2*8(a0) + fstd $f3, JB_F3*8(a0) + fstd $f4, JB_F4*8(a0) + fstd $f5, JB_F5*8(a0) + fstd $f6, JB_F6*8(a0) + fstd $f7, JB_F7*8(a0) + fstd $f8, JB_F8*8(a0) + fstd $f9, JB_F9*8(a0) + +#ifndef PIC + /* Call to C to (potentially) save our signal mask. */ + call ra, __sigjmp_save + ldl ra, 0(sp) + addl sp, 16, sp + ret +#elif IS_IN (rtld) + /* In ld.so we never save the signal mask. */ + mov 0, v0 + ret +#else + /* Tailcall to save the signal mask. */ + br $31, __sigjmp_save !samegp +#endif + +END(__sigsetjmp) +hidden_def (__sigsetjmp) + +/* Put these traditional entry points in the same file so that we can + elide much of the nonsense in trying to jmp to the real function. */ + +ENTRY(_setjmp) + ldgp gp, 0(pv) + .prologue 1 + mov 0, a1 + br $sigsetjmp_local +END(_setjmp) +libc_hidden_def (_setjmp) + +ENTRY(setjmp) + ldgp gp, 0(pv) + .prologue 1 + mov 1, a1 + br $sigsetjmp_local +END(setjmp) + +weak_extern(_setjmp) +weak_extern(setjmp) diff --git a/sysdeps/sw_64/sotruss-lib.c b/sysdeps/sw_64/sotruss-lib.c new file mode 100644 index 00000000..0cf35da9 --- /dev/null +++ b/sysdeps/sw_64/sotruss-lib.c @@ -0,0 +1,48 @@ +/* Override generic sotruss-lib.c to define actual functions for Sw_64. + Copyright (C) 2012-2023 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, see + . */ + +#define HAVE_ARCH_PLTENTER +#define HAVE_ARCH_PLTEXIT + +#include + +ElfW (Addr) la_sw_64_gnu_pltenter (ElfW (Sym) * sym __attribute__ ((unused)), + unsigned int ndx __attribute__ ((unused)), + uintptr_t *refcook, uintptr_t *defcook, + La_sw_64_regs *regs, unsigned int *flags, + const char *symname, long int *framesizep) +{ + print_enter (refcook, defcook, symname, regs->lr_r16, regs->lr_r17, + regs->lr_r18, *flags); + + /* No need to copy anything, we will not need the parameters in any case. */ + *framesizep = 0; + + return sym->st_value; +} + +unsigned int +la_sw_64_gnu_pltexit (ElfW (Sym) * sym, unsigned int ndx, uintptr_t *refcook, + uintptr_t *defcook, const struct La_sw_64_regs *inregs, + struct La_sw_64_retval *outregs, const char *symname) +{ + print_exit (refcook, defcook, symname, outregs->lrv_r0); + + return 0; +} diff --git a/sysdeps/sw_64/start.S b/sysdeps/sw_64/start.S new file mode 100644 index 00000000..a0edc6ce --- /dev/null +++ b/sysdeps/sw_64/start.S @@ -0,0 +1,103 @@ +/* Startup code for Sw_64/ELF. + Copyright (C) 1993-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson + + 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. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + 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, see + . */ + +#include + + .text + .align 3 + .globl _start + .ent _start, 0 + .type _start,@function +_start: + .frame $15, 0, $15 + br gp, 1f +1: ldgp gp, 0(gp) + subl sp, 16, sp + mov 0, $15 + .prologue 0 + + rfpcr $f0 + fimovd $f0,a1 + ldi a2,1($31) + sll a2,45,a2 + bis a1,a2,a1 + ifmovd a1,$f0 + wfpcr $f0 + + /* Load address of the user's main function. */ + setfpec1 + ldi a0, main + + ldw a1, 16(sp) /* get argc */ + ldi a2, 24(sp) /* get argv */ + + /* Load address of our own entry points to .fini and .init. */ + mov $r31, a3 + mov $r31, a4 + + /* Store address of the shared library termination function. */ + mov v0, a5 + + /* Provide the highest stack address to the user code. */ + stl sp, 0(sp) + +/* For 256 simd, we should change the value of $SP to 32 bytes align */ + and sp, 0x1f, s0 + beq s0, 2f + subl sp, 0x10, sp +2: + /* Call the user's main function, and exit with its value. + But let the libc call main. */ + call ra, __libc_start_main + +/* Reload sp */ + beq s0, 3f + addl sp, 0x10, sp +3: + /* Die very horribly if exit returns. Call_pal hlt is callable from + kernel mode only; this will result in an illegal instruction trap. */ + sys_call 0 + .end _start + +/* For ECOFF backwards compatibility. */ +weak_alias (_start, __start) + +/* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .weak data_start + data_start = __data_start diff --git a/sysdeps/sw_64/sw8a/nptl/pthread-offsets.h b/sysdeps/sw_64/sw8a/nptl/pthread-offsets.h new file mode 100644 index 00000000..370e18ac --- /dev/null +++ b/sysdeps/sw_64/sw8a/nptl/pthread-offsets.h @@ -0,0 +1,3 @@ +#define __PTHREAD_MUTEX_KIND_OFFSET 16 + +#define __PTHREAD_RWLOCK_FLAGS_OFFSET 48 diff --git a/sysdeps/sw_64/sw8a/nptl/pthreaddef.h b/sysdeps/sw_64/sw8a/nptl/pthreaddef.h new file mode 100644 index 00000000..e1fb46a9 --- /dev/null +++ b/sysdeps/sw_64/sw8a/nptl/pthreaddef.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2003-2023 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, see + . */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (4 * 1024 * 1024) + +/* Minimum guard size. */ +#define ARCH_MIN_GUARD_SIZE 0 + +/* Required stack pointer alignment at beginning. The ABI requires 16. */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 4096 + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) diff --git a/sysdeps/sw_64/sw8a/nptl/tcb-offsets.sym b/sysdeps/sw_64/sw8a/nptl/tcb-offsets.sym new file mode 100644 index 00000000..1005621b --- /dev/null +++ b/sysdeps/sw_64/sw8a/nptl/tcb-offsets.sym @@ -0,0 +1,13 @@ +#include +#include + +-- + +-- Abuse tls.h macros to derive offsets relative to the thread register. +-- # define __builtin_thread_pointer() ((void *) 0) +-- # define thread_offsetof(mem) ((void *) &THREAD_SELF->mem - (void *) 0) +-- Ho hum, this doesn't work in gcc4, so Know Things about THREAD_SELF +#define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - sizeof(struct pthread)) + +MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +TID_OFFSET thread_offsetof (tid) diff --git a/sysdeps/sw_64/tls-macros.h b/sysdeps/sw_64/tls-macros.h new file mode 100644 index 00000000..0e9c7e26 --- /dev/null +++ b/sysdeps/sw_64/tls-macros.h @@ -0,0 +1,36 @@ +/* Macros to support TLS testing in times of missing compiler support. */ + +extern void *__tls_get_addr (void *); + +#define TLS_GD(x) \ + ({ \ + register void *__gp asm("$29"); \ + void *__result; \ + asm ("ldi %0, " #x "($gp) !tlsgd" : "=r"(__result) : "r"(__gp)); \ + __tls_get_addr (__result); \ + }) + +#define TLS_LD(x) \ + ({ \ + register void *__gp asm("$29"); \ + void *__result; \ + asm ("ldi %0, " #x "($gp) !tlsldm" : "=r"(__result) : "r"(__gp)); \ + __result = __tls_get_addr (__result); \ + asm ("ldi %0, " #x "(%0) !dtprel" : "+r"(__result)); \ + __result; \ + }) + +#define TLS_IE(x) \ + ({ \ + register void *__gp asm("$29"); \ + long ofs; \ + asm ("ldl %0, " #x "($gp) !gottprel" : "=r"(ofs) : "r"(__gp)); \ + __builtin_thread_pointer () + ofs; \ + }) + +#define TLS_LE(x) \ + ({ \ + void *__result = __builtin_thread_pointer (); \ + asm ("ldi %0, " #x "(%0) !tprel" : "+r"(__result)); \ + __result; \ + }) diff --git a/sysdeps/sw_64/tst-audit.h b/sysdeps/sw_64/tst-audit.h new file mode 100644 index 00000000..6f9633fd --- /dev/null +++ b/sysdeps/sw_64/tst-audit.h @@ -0,0 +1,24 @@ +/* Definitions for testing PLT entry/exit auditing. Sw_64 version. + Copyright (C) 2012-2023 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, see + . */ + +#define pltenter la_sw_64_gnu_pltenter +#define pltexit la_sw_64_gnu_pltexit +#define La_regs La_sw_64_regs +#define La_retval La_sw_64_retval +#define int_retval lrv_r0 diff --git a/sysdeps/sw_64/tst-file-align.h b/sysdeps/sw_64/tst-file-align.h new file mode 100644 index 00000000..2c4847f5 --- /dev/null +++ b/sysdeps/sw_64/tst-file-align.h @@ -0,0 +1,20 @@ +/* Check file alignment. Sw_64 version. + Copyright (C) 2021-2023 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, see + . */ + +/* This should cover all possible alignments we currently support. */ +#define ALIGN 0x10000 diff --git a/sysdeps/sw_64/unwind-arch.h b/sysdeps/sw_64/unwind-arch.h new file mode 100644 index 00000000..a64260bd --- /dev/null +++ b/sysdeps/sw_64/unwind-arch.h @@ -0,0 +1,28 @@ +/* Dynamic loading of the libgcc unwinder. sw_64 customization. + Copyright (C) 2023 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, see + . */ + +#ifndef _ARCH_UNWIND_LINK_H +#define _ARCH_UNWIND_LINK_H + +#define UNWIND_LINK_GETIP 1 +#define UNWIND_LINK_FRAME_STATE_FOR 1 +#define UNWIND_LINK_FRAME_ADJUSTMENT 0 +#define UNWIND_LINK_EXTRA_FIELDS +#define UNWIND_LINK_EXTRA_INIT + +#endif /* _ARCH_UNWIND_LINK_H */ diff --git a/sysdeps/unix/sysv/linux/sw_64/____longjmp_chk.S b/sysdeps/unix/sysv/linux/sw_64/____longjmp_chk.S new file mode 100644 index 00000000..b2c2b539 --- /dev/null +++ b/sysdeps/unix/sysv/linux/sw_64/____longjmp_chk.S @@ -0,0 +1,145 @@ +/* Copyright (C) 1992-2023 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, see + . */ + +#include +#include +#include + + + .section .rodata.str1.1,"aMS",@progbits,1 + .type longjmp_msg,@object +longjmp_msg: + .string "longjmp causes uninitialized stack frame" + .size longjmp_msg, .-longjmp_msg + + +/* Jump to the position specified by ENV, causing the + setjmp call there to return VAL, or 1 if VAL is 0. + void __longjmp (__jmp_buf env, int val). */ + .text + .align 4 + .globl ____longjmp_chk + .type ____longjmp_chk, @function + .usepv ____longjmp_chk, std + + cfi_startproc +____longjmp_chk: + ldgp gp, 0(pv) +#ifdef PROF + .set noat + ldi AT, _mcount + call AT, (AT), _mcount + .set at +#endif + + ldl s2, JB_PC*8(a0) + mov a0, s0 + ldl fp, JB_FP*8(a0) + mov a1, s1 + ldl s3, JB_SP*8(a0) + seleq s1, 1, s1, s1 + +#ifdef PTR_DEMANGLE + PTR_DEMANGLE (s2, t1) + PTR_DEMANGLE2 (s3, t1) + PTR_DEMANGLE2 (fp, t1) +#endif + /* ??? While this is a proper test for detecting a longjmp to an + invalid frame within any given stack, the main thread stack is + located *below* almost everything in the address space. Which + means that the test at Lfail vs the signal stack will almost + certainly never pass. We ought bounds check top and bottom of + the current thread's stack. */ + cmpule s3, sp, t1 + bne t1, $Lfail + + .align 4 +$Lok: + mov s0, a0 + mov s1, v0 + mov s3, t0 + mov s2, ra + cfi_remember_state + cfi_def_cfa (a0, 0) + cfi_register (sp, t0) + cfi_offset (s0, JB_S0*8) + cfi_offset (s1, JB_S1*8) + cfi_offset (s2, JB_S2*8) + cfi_offset (s3, JB_S3*8) + cfi_offset (s4, JB_S4*8) + cfi_offset (s5, JB_S5*8) + cfi_offset (s3, JB_S3*8) + cfi_offset ($f2, JB_F2*8) + cfi_offset ($f3, JB_F3*8) + cfi_offset ($f4, JB_F4*8) + cfi_offset ($f5, JB_F5*8) + cfi_offset ($f6, JB_F6*8) + cfi_offset ($f7, JB_F7*8) + cfi_offset ($f8, JB_F8*8) + cfi_offset ($f9, JB_F9*8) + ldl s0, JB_S0*8(a0) + ldl s1, JB_S1*8(a0) + ldl s2, JB_S2*8(a0) + ldl s3, JB_S3*8(a0) + ldl s4, JB_S4*8(a0) + ldl s5, JB_S5*8(a0) + fldd $f2, JB_F2*8(a0) + fldd $f3, JB_F3*8(a0) + fldd $f4, JB_F4*8(a0) + fldd $f5, JB_F5*8(a0) + fldd $f6, JB_F6*8(a0) + fldd $f7, JB_F7*8(a0) + fldd $f8, JB_F8*8(a0) + fldd $f9, JB_F9*8(a0) + mov t0, sp + ret + + .align 4 +$Lfail: + cfi_restore_state + ldi v0, __NR_sigaltstack + ldi a0, 0 + ldi a1, -32(sp) + ldi sp, -32(sp) + cfi_adjust_cfa_offset (32) + sys_call 0x83 + ldl t0, 0(sp) /* ss_sp */ + ldw t1, 8(sp) /* ss_flags */ + ldl t2, 16(sp) /* ss_size */ + ldi sp, 32(sp) + cfi_adjust_cfa_offset (-32) + + /* Without working sigaltstack we cannot perform the test. */ + bne a3, $Lok + + addl t0, t2, t0 /* t0 = ss_sp + ss_size */ + subl t0, s3, t0 /* t0 = (ss_sp + ss_size) - new_sp */ + cmpule t2, t0, t0 /* t0 = (t0 >= ss_size) */ + and t0, t1, t0 /* t0 = (t0 >= ss_size) & (ss_flags & SS_ONSTACK) */ + bne t0, $Lok + + ldih a0, longjmp_msg(gp) !gprelhigh + ldi a0, longjmp_msg(a0) !gprellow +#ifdef PIC + call ra, HIDDEN_JUMPTARGET (__fortify_fail) +#else + bsr ra, HIDDEN_JUMPTARGET (__fortify_fail) !samegp +#endif + sys_call 0x81 + + cfi_endproc + .size ____longjmp_chk, .-____longjmp_chk -- 2.25.1