diff options
Diffstat (limited to 'libc/sysdeps/linux/xtensa')
-rw-r--r-- | libc/sysdeps/linux/xtensa/Makefile.arch | 3 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/__start_context.S | 104 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/bits/elf-fdpic.h | 117 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/bits/fcntl.h | 2 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/bits/stat.h | 4 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/bits/uClibc_arch_features.h | 3 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/bits/xtensa-config.h | 20 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/clone.S | 6 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/crt1.S | 108 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/crti.S | 10 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/crtn.S | 6 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/crtreloc.c | 105 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/getcontext.S | 100 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/makecontext.c | 184 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/setcontext.S | 117 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/setjmp.S | 3 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/swapcontext.S | 174 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/sysdep.h | 55 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/ucontext_i.sym | 15 |
19 files changed, 1125 insertions, 11 deletions
diff --git a/libc/sysdeps/linux/xtensa/Makefile.arch b/libc/sysdeps/linux/xtensa/Makefile.arch index 23cd08ee5..f3a93caaa 100644 --- a/libc/sysdeps/linux/xtensa/Makefile.arch +++ b/libc/sysdeps/linux/xtensa/Makefile.arch @@ -10,3 +10,6 @@ SSRC-y := bsd-_setjmp.S bsd-setjmp.S setjmp.S clone.S \ sigrestorer.S syscall.S mmap.S windowspill.S __longjmp.S vfork.S CSRC-$(if $(UCLIBC_HAS_THREADS_NATIVE),,y) += fork.c + +CSRC-$(UCLIBC_HAS_CONTEXT_FUNCS) += makecontext.c +SSRC-$(UCLIBC_HAS_CONTEXT_FUNCS) += setcontext.S getcontext.S swapcontext.S __start_context.S diff --git a/libc/sysdeps/linux/xtensa/__start_context.S b/libc/sysdeps/linux/xtensa/__start_context.S new file mode 100644 index 000000000..e6ce93347 --- /dev/null +++ b/libc/sysdeps/linux/xtensa/__start_context.S @@ -0,0 +1,104 @@ +/* Copyright (C) 2018 - 2022 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 + <http://www.gnu.org/licenses/>. */ + +#include <sysdep.h> + +#if defined(__XTENSA_CALL0_ABI__) +/* + * There's no entry instruction, makecontext sets up ucontext_t as if + * getcontext was called above and is about to return here. + * Registers on entry to this function: + * a12: func to call (function descriptor in case of FDPIC) + * a13: ucp->uc_link, next context to activate if func returns + * a14: func argc + * a15: current GOT pointer (in case of FDPIC) + */ + .literal_position + +ENTRY_PREFIX(__start_context) + + beqz a14, 1f + + /* load func arguments 0..1 from stack and free that space */ + l32i a2, a1, 8 + l32i a3, a1, 12 + addi a1, a1, 16 + bltui a14, 3, 1f + + /* load func arguments 2..5 from stack and free that space */ + l32i a4, a1, 0 + l32i a5, a1, 4 + l32i a6, a1, 8 + l32i a7, a1, 12 + addi a1, a1, 16 + /* func arguments 6..argc - 1 are now at the top of the stack */ +1: + FDPIC_LOAD_FUNCDESC (a12, a12) + callx0 a12 + beqz a13, 1f + mov a2, a13 + movi a4, JUMPTARGET (setcontext) + FDPIC_LOAD_JUMPTARGET (a4, a15, a4) + callx0 a4 +1: + movi a4, JUMPTARGET (_exit) + movi a2, 0 + FDPIC_LOAD_JUMPTARGET (a4, a15, a4) + callx0 a4 + ill +END(__start_context) +#elif defined(__XTENSA_WINDOWED_ABI__) +/* + * There's no entry instruction, makecontext sets up ucontext_t as if + * getcontext was called above and is about to return here. + * Registers on entry to this function: + * a2: func to call + * a3: ucp->uc_link, next context to activate if func returns + * a4: func argc + * a5..a7: func arguments 0..2 + */ + .literal_position + +ENTRY_PREFIX(__start_context) + + mov a10, a5 + mov a11, a6 + mov a12, a7 + bltui a4, 4, 1f + + /* load func arguments 3..5 from stack and free that space */ + l32i a13, a1, 4 + l32i a14, a1, 8 + l32i a15, a1, 12 + addi a5, a1, 16 + movsp a1, a5 + /* func arguments 6..argc - 1 are now at the top of the stack */ +1: + callx8 a2 + beqz a3, 1f + mov a6, a3 + movi a4, JUMPTARGET (setcontext) + callx4 a4 +1: + movi a4, JUMPTARGET (_exit) + movi a6, 0 + callx4 a4 + ill +END(__start_context) +#else +#error Unsupported Xtensa ABI +#endif diff --git a/libc/sysdeps/linux/xtensa/bits/elf-fdpic.h b/libc/sysdeps/linux/xtensa/bits/elf-fdpic.h new file mode 100644 index 000000000..19bb247b8 --- /dev/null +++ b/libc/sysdeps/linux/xtensa/bits/elf-fdpic.h @@ -0,0 +1,117 @@ +/* Copyright 2003, 2004 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.) + +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 +Library 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; see the file COPYING.LIB. If +not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _BITS_ELF_FDPIC_H +#define _BITS_ELF_FDPIC_H + +/* These data structures are described in the FDPIC ABI extension. + The kernel passes a process a memory map, such that for every LOAD + segment there is an elf32_fdpic_loadseg entry. A pointer to an + elf32_fdpic_loadmap is passed in r7 at start-up, and a pointer to + an additional such map is passed in r8 for the interpreter, when + there is one. */ + +#include <elf.h> + +/* This data structure represents a PT_LOAD segment. */ +struct elf32_fdpic_loadseg +{ + /* Core address to which the segment is mapped. */ + Elf32_Addr addr; + /* VMA recorded in the program header. */ + Elf32_Addr p_vaddr; + /* Size of this segment in memory. */ + Elf32_Word p_memsz; +}; + +struct elf32_fdpic_loadmap { + /* Protocol version number, must be zero. */ + Elf32_Half version; + /* Number of segments in this map. */ + Elf32_Half nsegs; + /* The actual memory map. */ + struct elf32_fdpic_loadseg segs[/*nsegs*/]; +}; + +struct elf32_fdpic_loadaddr { + struct elf32_fdpic_loadmap *map; + void *got_value; +}; + +/* Map a pointer's VMA to its corresponding address according to the + load map. */ +static __always_inline void * +__reloc_pointer (void *p, + const struct elf32_fdpic_loadmap *map) +{ + int c; + +#if 0 + if (map->version != 0) + /* Crash. */ + ((void(*)())0)(); +#endif + + /* No special provision is made for NULL. We don't want NULL + addresses to go through relocation, so they shouldn't be in + .rofixup sections, and, if they're present in dynamic + relocations, they shall be mapped to the NULL address without + undergoing relocations. */ + + for (c = 0; + /* Take advantage of the fact that the loadmap is ordered by + virtual addresses. In general there will only be 2 entries, + so it's not profitable to do a binary search. */ + c < map->nsegs && p >= (void*)map->segs[c].p_vaddr; + c++) + { + /* This should be computed as part of the pointer comparison + above, but we want to use the carry in the comparison, so we + can't convert it to an integer type beforehand. */ + unsigned long offset = (char*)p - (char*)map->segs[c].p_vaddr; + /* We only check for one-past-the-end for the last segment, + assumed to be the data segment, because other cases are + ambiguous in the absence of padding between segments, and + rofixup already serves as padding between text and data. + Unfortunately, unless we special-case the last segment, we + fail to relocate the _end symbol. */ + if (offset < map->segs[c].p_memsz + || (offset == map->segs[c].p_memsz && c + 1 == map->nsegs)) + return (char*)map->segs[c].addr + offset; + } + + /* We might want to crash instead. */ + return (void*)-1; +} + +# define __RELOC_POINTER(ptr, loadaddr) \ + (__reloc_pointer ((void*)(ptr), \ + (loadaddr).map)) + +void* +__self_reloc (const struct elf32_fdpic_loadmap *map, void ***p, void ***e); + +#endif /* _BITS_ELF_FDPIC_H */ diff --git a/libc/sysdeps/linux/xtensa/bits/fcntl.h b/libc/sysdeps/linux/xtensa/bits/fcntl.h index 5af9d2124..9bc5fa893 100644 --- a/libc/sysdeps/linux/xtensa/bits/fcntl.h +++ b/libc/sysdeps/linux/xtensa/bits/fcntl.h @@ -245,3 +245,5 @@ extern ssize_t tee (int __fdin, int __fdout, size_t __len, #endif __END_DECLS +/* Include generic Linux declarations. */ +#include <bits/fcntl-linux.h> diff --git a/libc/sysdeps/linux/xtensa/bits/stat.h b/libc/sysdeps/linux/xtensa/bits/stat.h index 045a017fd..43af825ec 100644 --- a/libc/sysdeps/linux/xtensa/bits/stat.h +++ b/libc/sysdeps/linux/xtensa/bits/stat.h @@ -54,7 +54,7 @@ struct stat unsigned long __pad2; __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ #endif -#ifdef __USE_MISC +#if defined(__USE_MISC) || defined(__USE_XOPEN2K8) /* Nanosecond resolution timestamps are stored in a format equivalent to 'struct timespec'. This is the type used whenever possible but the Unix namespace rules do not allow the @@ -94,7 +94,7 @@ struct stat64 unsigned long __pad2; __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ -#ifdef __USE_MISC +#if defined(__USE_MISC) || defined(__USE_XOPEN2K8) /* Nanosecond resolution timestamps are stored in a format equivalent to 'struct timespec'. This is the type used whenever possible but the Unix namespace rules do not allow the diff --git a/libc/sysdeps/linux/xtensa/bits/uClibc_arch_features.h b/libc/sysdeps/linux/xtensa/bits/uClibc_arch_features.h index de9b38983..a15744c2f 100644 --- a/libc/sysdeps/linux/xtensa/bits/uClibc_arch_features.h +++ b/libc/sysdeps/linux/xtensa/bits/uClibc_arch_features.h @@ -11,9 +11,6 @@ /* can your target use syscall6() for mmap ? */ #define __UCLIBC_MMAP_HAS_6_ARGS__ -/* does your target use statx */ -#undef __UCLIBC_HAVE_STATX__ - /* does your target align 64bit values in register pairs ? (32bit arches only) */ #define __UCLIBC_SYSCALL_ALIGN_64BIT__ diff --git a/libc/sysdeps/linux/xtensa/bits/xtensa-config.h b/libc/sysdeps/linux/xtensa/bits/xtensa-config.h index b99928b1e..bfcd571d2 100644 --- a/libc/sysdeps/linux/xtensa/bits/xtensa-config.h +++ b/libc/sysdeps/linux/xtensa/bits/xtensa-config.h @@ -32,21 +32,41 @@ macros. */ #undef XCHAL_HAVE_NSA +#ifdef __XCHAL_HAVE_NSA +#define XCHAL_HAVE_NSA __XCHAL_HAVE_NSA +#else #define XCHAL_HAVE_NSA 1 +#endif #undef XCHAL_HAVE_LOOPS +#ifdef __XCHAL_HAVE_LOOPS +#define XCHAL_HAVE_LOOPS __XCHAL_HAVE_LOOPS +#else #define XCHAL_HAVE_LOOPS 1 +#endif /* Assume the maximum number of AR registers. This currently only affects the __window_spill function, and it is always safe to flush extra. */ #undef XCHAL_NUM_AREGS +#ifdef __XCHAL_NUM_AREGS +#define XCHAL_NUM_AREGS __XCHAL_NUM_AREGS +#else #define XCHAL_NUM_AREGS 64 +#endif #undef XCHAL_HAVE_S32C1I +#ifdef __XCHAL_HAVE_S32C1I +#define XCHAL_HAVE_S32C1I __XCHAL_HAVE_S32C1I +#else #define XCHAL_HAVE_S32C1I 1 +#endif #undef XCHAL_HAVE_EXCLUSIVE +#ifdef __XCHAL_HAVE_EXCLUSIVE +#define XCHAL_HAVE_EXCLUSIVE __XCHAL_HAVE_EXCLUSIVE +#else #define XCHAL_HAVE_EXCLUSIVE 0 +#endif #endif /* !XTENSA_CONFIG_H */ diff --git a/libc/sysdeps/linux/xtensa/clone.S b/libc/sysdeps/linux/xtensa/clone.S index ebfdcc1f6..a11044cd0 100644 --- a/libc/sysdeps/linux/xtensa/clone.S +++ b/libc/sysdeps/linux/xtensa/clone.S @@ -81,11 +81,17 @@ ENTRY (__clone) callx4 a2 #elif defined(__XTENSA_CALL0_ABI__) mov a2, a9 /* load up the 'arg' parameter */ +#ifdef __FDPIC__ + mov a12, a11 + l32i a11, a7, 4 + l32i a7, a7, 0 +#endif callx0 a7 /* call the user's function */ /* Call _exit. Note that any return parameter from the user's function in a2 is seen as inputs to _exit. */ movi a0, JUMPTARGET(_exit) + FDPIC_LOAD_JUMPTARGET(a0, a12, a0) callx0 a0 #else #error Unsupported Xtensa ABI diff --git a/libc/sysdeps/linux/xtensa/crt1.S b/libc/sysdeps/linux/xtensa/crt1.S index efbe264c0..a12f82dd6 100644 --- a/libc/sysdeps/linux/xtensa/crt1.S +++ b/libc/sysdeps/linux/xtensa/crt1.S @@ -35,6 +35,86 @@ #include <features.h> +#if defined(__FDPIC__) + +/* This is the canonical entry point, usually the first thing in the text + segment. When the entry point runs, most register values are unspecified, + except for: + + a6 Address of .dynamic section + a5 Interpreter map + a4 Executable map + + a2 Contains a function pointer to be registered with `atexit'. + This is how the dynamic linker arranges to have DT_FINI + functions called for shared libraries that have been loaded + before this code runs. + + a1 The stack (i.e., a1+16) contains the arguments and environment: + a1+0 argc + a1+4 argv[0] + ... + a1+(4*argc) NULL + a1+(4*(argc+1)) envp[0] + ... + NULL + */ + .text + .align 4 + .literal_position + .global _start + .type _start, @function +_start: +#if defined(__XTENSA_CALL0_ABI__) + + .begin no-transform + call0 1f +2: + .end no-transform + .align 4 + .literal_position +1: + movi a15, 2b + sub a15, a0, a15 + + mov a12, a4 + mov a13, a5 + mov a14, a6 + mov a2, a4 + movi a3, __ROFIXUP_LIST__ + add a3, a3, a15 + movi a4, __ROFIXUP_END__ + add a4, a4, a15 + movi a0, __self_reloc + add a0, a0, a15 + callx0 a0 + + mov a11, a2 + movi a2, main@GOTOFFFUNCDESC + add a2, a2, a11 + l32i a3, sp, 0 /* argc */ + addi a4, sp, 4 /* argv */ + /* a5 is either 0 when static or set by the RTLD to the rtld_fini */ + mov a7, a13 + /* unused stack_end argument is what used to be argc */ + movi a5, _init@GOTOFFFUNCDESC + add a5, a5, a11 + movi a6, _fini@GOTOFFFUNCDESC + add a6, a6, a11 + + movi a0, __uClibc_main@GOTOFFFUNCDESC + add a0, a0, a11 + l32i a11, a0, 4 + l32i a0, a0, 0 + callx0 a0 + ill + +#else +#error Unsupported Xtensa ABI +#endif + +#else /* defined(__FDPIC__) */ + #ifndef __UCLIBC_CTOR_DTOR__ .weak _init .weak _fini @@ -76,9 +156,26 @@ .global _start .type _start, @function _start: +#ifdef L_rcrt1 + .begin no-transform + call0 1f +.Lret_addr: + .end no-transform + .align 4 +1: +#endif #if defined(__XTENSA_WINDOWED_ABI__) +#ifdef L_rcrt1 + movi a6, .Lret_addr + sub a6, a0, a6 + movi a0, 0 + movi a4, reloc_static_pie + add a4, a4, a6 + callx4 a4 +#else /* Clear a0 to obviously mark the outermost frame. */ movi a0, 0 +#endif /* Load up the user's main function. */ movi a6, main @@ -106,8 +203,18 @@ _start: movi a4, __uClibc_main callx4 a4 #elif defined(__XTENSA_CALL0_ABI__) +#ifdef L_rcrt1 + mov a12, a2 + movi a2, .Lret_addr + sub a2, a0, a2 + movi a0, reloc_static_pie + add a0, a0, a2 + callx0 a0 + mov a7, a12 +#else /* Setup the shared library termination function. */ mov a7, a2 +#endif /* Load up the user's main function. */ movi a2, main @@ -146,3 +253,4 @@ __data_start: .long 0 .weak data_start data_start = __data_start +#endif /* defined(__FDPIC__) */ diff --git a/libc/sysdeps/linux/xtensa/crti.S b/libc/sysdeps/linux/xtensa/crti.S index ba804eb45..2923ff09d 100644 --- a/libc/sysdeps/linux/xtensa/crti.S +++ b/libc/sysdeps/linux/xtensa/crti.S @@ -3,6 +3,7 @@ .section .init .align 4 .global _init + .hidden _init .type _init, @function _init: #if defined(__XTENSA_WINDOWED_ABI__) @@ -10,6 +11,10 @@ _init: #elif defined(__XTENSA_CALL0_ABI__) addi sp, sp, -16 s32i a0, sp, 0 +#ifdef __FDPIC__ + s32i a12, sp, 4 + mov a12, a11 +#endif #else #error Unsupported Xtensa ABI #endif @@ -17,6 +22,7 @@ _init: .section .fini .align 4 .global _fini + .hidden _fini .type _fini, @function _fini: #if defined(__XTENSA_WINDOWED_ABI__) @@ -24,6 +30,10 @@ _fini: #elif defined(__XTENSA_CALL0_ABI__) addi sp, sp, -16 s32i a0, sp, 0 +#ifdef __FDPIC__ + s32i a12, sp, 4 + mov a12, a11 +#endif #else #error Unsupported Xtensa ABI #endif diff --git a/libc/sysdeps/linux/xtensa/crtn.S b/libc/sysdeps/linux/xtensa/crtn.S index a3598da1a..6f797e8bd 100644 --- a/libc/sysdeps/linux/xtensa/crtn.S +++ b/libc/sysdeps/linux/xtensa/crtn.S @@ -4,6 +4,9 @@ #if defined(__XTENSA_WINDOWED_ABI__) retw #elif defined(__XTENSA_CALL0_ABI__) +#ifdef __FDPIC__ + l32i a12, sp, 4 +#endif l32i a0, sp, 0 addi sp, sp, 16 ret @@ -15,6 +18,9 @@ #if defined(__XTENSA_WINDOWED_ABI__) retw #elif defined(__XTENSA_CALL0_ABI__) +#ifdef __FDPIC__ + l32i a12, sp, 4 +#endif l32i a0, sp, 0 addi sp, sp, 16 ret diff --git a/libc/sysdeps/linux/xtensa/crtreloc.c b/libc/sysdeps/linux/xtensa/crtreloc.c new file mode 100644 index 000000000..697ef91ab --- /dev/null +++ b/libc/sysdeps/linux/xtensa/crtreloc.c @@ -0,0 +1,105 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + written by Alexandre Oliva <aoliva@redhat.com> +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.) + +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 +Library 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; see the file COPYING.LIB. If +not, see <http://www.gnu.org/licenses/>. */ + +#ifdef __FDPIC__ + +#include <sys/types.h> +#include <link.h> + +/* This file is to be compiled into crt object files, to enable + executables to easily self-relocate. */ + +/* Compute the runtime address of pointer in the range [p,e), and then + map the pointer pointed by it. */ +static __always_inline void *** +reloc_range_indirect (void ***p, void ***e, + const struct elf32_fdpic_loadmap *map) +{ + while (p < e) + { + if (*p != (void **)-1) + { + void *ptr = __reloc_pointer (*p, map); + + if (ptr != (void *)-1) + { + unsigned long off = ((unsigned long)ptr & 3) * 8; + unsigned long *pa = (unsigned long *)((unsigned long)ptr & -4); + unsigned long v2; + void *pt; + + if (off) + { + unsigned long v0, v1; +#ifdef __XTENSA_EB__ + v0 = pa[1]; v1 = pa[0]; + v2 = (v1 >> (32 - off)) | (v0 << off); +#else /* __XTENSA_EL__ */ + v0 = pa[0]; v1 = pa[1]; + v2 = (v0 << (32 - off)) | (v1 >> off); +#endif + pt = (void *)((v1 << (32 - off)) | (v0 >> off)); + } + else + pt = *(void**)ptr; + pt = __reloc_pointer (pt, map); + if (off) + { + unsigned long v = (unsigned long)pt; +#ifdef __XTENSA_EB__ + pa[0] = (v2 << (32 - off)) | (v >> off); + pa[1] = (v << (32 - off)) | (v2 >> off); +#else /* __XTENSA_EL__ */ + pa[0] = (v2 >> (32 - off)) | (v << off); + pa[1] = (v >> (32 - off)) | (v2 << off); +#endif + } + else + *(void**)ptr = pt; + } + } + p++; + } + return p; +} + +/* Call __reloc_range_indirect for the given range except for the last + entry, whose contents are only relocated. It's expected to hold + the GOT value. */ +attribute_hidden void* +__self_reloc (const struct elf32_fdpic_loadmap *map, + void ***p, void ***e) +{ + p = reloc_range_indirect (p, e-1, map); + + if (p >= e) + return (void*)-1; + + return __reloc_pointer (*p, map); +} + +#endif /* __FDPIC__ */ diff --git a/libc/sysdeps/linux/xtensa/getcontext.S b/libc/sysdeps/linux/xtensa/getcontext.S new file mode 100644 index 000000000..4cc644552 --- /dev/null +++ b/libc/sysdeps/linux/xtensa/getcontext.S @@ -0,0 +1,100 @@ +/* Copyright (C) 2018 - 2022 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 + <http://www.gnu.org/licenses/>. */ + +#include <sysdep.h> +#include "ucontext_i.h" + +#if defined(__XTENSA_CALL0_ABI__) +ENTRY(__getcontext) + s32i a0, a2, MCONTEXT_SC_PC + s32i a1, a2, MCONTEXT_SC_A_0 + 4 + + /* save callee-saved registers in the context */ + s32i a12, a2, MCONTEXT_SC_A_0 + 48 + s32i a13, a2, MCONTEXT_SC_A_0 + 52 + s32i a14, a2, MCONTEXT_SC_A_0 + 56 + s32i a15, a2, MCONTEXT_SC_A_0 + 60 + + movi a3, 0 + addi a4, a2, UCONTEXT_SIGMASK + movi a2, SIG_BLOCK + movi a5, JUMPTARGET (sigprocmask) + FDPIC_LOAD_JUMPTARGET (a5, a11, a5) + jx a5 +END(__getcontext) +#elif defined(__XTENSA_WINDOWED_ABI__) +ENTRY(__getcontext) + movi a4, __window_spill + callx4 a4 + s32i a0, a2, MCONTEXT_SC_PC + + /* copy registers a0..a3 from spill area */ + addi a3, a1, -16 + l32i a4, a3, 0 + l32i a5, a3, 4 + l32i a6, a3, 8 + l32i a7, a3, 12 + s32i a4, a2, MCONTEXT_SC_A_0 + 0 + s32i a5, a2, MCONTEXT_SC_A_0 + 4 + s32i a6, a2, MCONTEXT_SC_A_0 + 8 + s32i a7, a2, MCONTEXT_SC_A_0 + 12 + + /* if it was call4 then register saving is done */ + extui a4, a0, 30, 2 + bltui a4, 2, 1f + + /* otherwise load spill overflow area address into a3 */ + addi a3, a5, -16 + l32i a3, a3, 4 + addi a3, a3, -32 + beqi a4, 2, 2f + + /* copy registers a8..a11 from spill overflow area */ + addi a3, a3, -16 + l32i a4, a3, 16 + l32i a5, a3, 20 + l32i a6, a3, 24 + l32i a7, a3, 28 + s32i a4, a2, MCONTEXT_SC_A_0 + 32 + s32i a5, a2, MCONTEXT_SC_A_0 + 36 + s32i a6, a2, MCONTEXT_SC_A_0 + 40 + s32i a7, a2, MCONTEXT_SC_A_0 + 44 + + /* copy registers a4..a7 from spill overflow area */ +2: + l32i a4, a3, 0 + l32i a5, a3, 4 + l32i a6, a3, 8 + l32i a7, a3, 12 + s32i a4, a2, MCONTEXT_SC_A_0 + 16 + s32i a5, a2, MCONTEXT_SC_A_0 + 20 + s32i a6, a2, MCONTEXT_SC_A_0 + 24 + s32i a7, a2, MCONTEXT_SC_A_0 + 28 +1: + movi a6, SIG_BLOCK + movi a7, 0 + addi a8, a2, UCONTEXT_SIGMASK + movi a4, JUMPTARGET (sigprocmask) + callx4 a4 + mov a2, a6 + retw +END(__getcontext) +#else +#error Unsupported Xtensa ABI +#endif + +weak_alias (__getcontext, getcontext) diff --git a/libc/sysdeps/linux/xtensa/makecontext.c b/libc/sysdeps/linux/xtensa/makecontext.c new file mode 100644 index 000000000..0a8f7116f --- /dev/null +++ b/libc/sysdeps/linux/xtensa/makecontext.c @@ -0,0 +1,184 @@ +/* Copyright (C) 2018 - 2022 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 + <http://www.gnu.org/licenses/>. */ + +#include <sysdep.h> +#include <stdarg.h> +#include <stdint.h> +#include <string.h> +#include <ucontext.h> + +extern void __start_context (void); + +#if defined(__XTENSA_CALL0_ABI__) +/* + * makecontext sets up new stack like this: + * + * +------------------ stack top (uc_stack.ss_sp + uc_stack.ss_size) + * | optional alignment + * +------------------ CFA of __start_context, initial sp points here + * | optional padding + * +------------------ Optional arguments 6..argc - 1 + * | func arg argc - 1 + * | func arg argc - 2 + * | ... + * | func arg 6 + * +------------------ Optional arguments 2..5 + * | func arg 5 + * 16 | func arg 4 + * | func arg 3 + * | func arg 2 + * +------------------ Optional arguments 0..1 + * | func arg 1 + * 16 | func arg 0 + * | padding + * | padding + * +------------------ CFA of pseudo getcontext + * | + * +------------------ stack bottom (uc_stack.ss_sp) + * + * When argc is 0 arguments areas are not allocated, + * when 1 <= argc < 3 only area for arguments 0..1 is allocated, + * when 3 <= argc < 7 areas for arguments 0..1 and 2..5 is allocated, + * when argc >= 7 all three arguments areas are allocated. + * Arguments 0..5 area is deallocated by the __start_context after + * arguments are loaded into registers. + * uc_mcontext registers are set as if __start_context made call0 + * to getcontext, sp points to that pseudo getcontext CFA. + * setcontext/swapcontext will arrange for restoring regiters + * a1, a12..a15 of __start_context. + */ + +void +__makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...) +{ + unsigned long sp = ((unsigned long) ucp->uc_stack.ss_sp + + ucp->uc_stack.ss_size) & -16; + int i; + + if (argc > 0) + sp -= 4 * (argc + 2); + sp &= -16; + +#ifdef __FDPIC__ + ucp->uc_mcontext.sc_pc = ((unsigned long *) __start_context)[0]; + ucp->uc_mcontext.sc_a[15] = ((unsigned long *) __start_context)[1]; +#else + ucp->uc_mcontext.sc_pc = (unsigned long) __start_context; +#endif + ucp->uc_mcontext.sc_a[1] = sp; + ucp->uc_mcontext.sc_a[12] = (unsigned long) func; + ucp->uc_mcontext.sc_a[13] = (unsigned long) ucp->uc_link; + ucp->uc_mcontext.sc_a[14] = argc; + + if (argc) + { + va_list ap; + + va_start (ap, argc); + for (i = 0; i < argc; ++i) + ((int *) sp)[i + 2] = va_arg (ap, int); + va_end (ap); + } +} +#elif defined(__XTENSA_WINDOWED_ABI__) +/* + * makecontext sets up new stack like this: + * + * +------------------ stack top (uc_stack.ss_sp + uc_stack.ss_size) + * | optional alignment + * +------------------ CFA of __start_context + * 16 | Outermost caller spill area + * +------------------ + * 16 | __start_context overflow area + * +------------------ initial sp points here + * | optional padding + * +------------------ Optional arguments 6..argc - 1 + * | func arg argc - 1 + * | func arg argc - 2 + * | ... + * | func arg 6 + * +------------------ Optional arguments 3..5 + * | func arg 5 + * 16 | func arg 4 + * | func arg 3 + * | padding + * +------------------ CFA of pseudo getcontext + * 16 | __start_context caller spill area + * +------------------ + * | + * +------------------ stack bottom (uc_stack.ss_sp) + * + * When argc < 4 both arguments areas are not allocated, + * when 4 <= argc < 7 only area for arguments 3..5 is allocated, + * when argc >= 7 both arguments areas are allocated. + * Arguments 3..5 area is deallocated by the __start_context after + * arguments are loaded into registers. + * uc_mcontext registers are set as if __start_context made call8 + * to getcontext, sp points to that pseudo getcontext CFA, spill + * area under that sp has a1 pointing to the __start_context CFA + * at the top of the stack. setcontext/swapcontext will arrange for + * restoring regiters a0..a7 of __start_context. + */ + +void +__makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...) +{ + unsigned long sp = ((unsigned long) ucp->uc_stack.ss_sp + + ucp->uc_stack.ss_size - 32) & -16; + unsigned long spill0[4] = + { + 0, sp + 32, 0, 0, + }; + int i; + + memset ((void *) sp, 0, 32); + + if (argc > 2) + sp -= 4 * (argc - 2); + sp &= -16; + + ucp->uc_mcontext.sc_pc = + ((unsigned long) __start_context & 0x3fffffff) + 0x80000000; + ucp->uc_mcontext.sc_a[0] = 0; + ucp->uc_mcontext.sc_a[1] = sp; + ucp->uc_mcontext.sc_a[2] = (unsigned long) func; + ucp->uc_mcontext.sc_a[3] = (unsigned long) ucp->uc_link; + ucp->uc_mcontext.sc_a[4] = argc; + + if (argc) + { + va_list ap; + + va_start (ap, argc); |