mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-26 15:00:06 +00:00
142 lines
5.9 KiB
C
142 lines
5.9 KiB
C
/* Assembler macros with cancellation support, Nios II version.
|
|
Copyright (C) 2003-2016 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 <tls.h>
|
|
#ifndef __ASSEMBLER__
|
|
# include <nptl/pthreadP.h>
|
|
#endif
|
|
|
|
#if IS_IN (libc) || IS_IN (libpthread) || IS_IN (librt)
|
|
|
|
# undef PSEUDO
|
|
# define PSEUDO(name, syscall_name, args) \
|
|
.type __##syscall_name##_nocancel, @function; \
|
|
.globl __##syscall_name##_nocancel; \
|
|
__##syscall_name##_nocancel: \
|
|
cfi_startproc; \
|
|
DO_CALL (syscall_name, args); \
|
|
bne r7, zero, SYSCALL_ERROR_LABEL; \
|
|
ret; \
|
|
cfi_endproc; \
|
|
.size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \
|
|
ENTRY (name) \
|
|
SINGLE_THREAD_P(r2); \
|
|
bne r2, zero, pseudo_cancel; \
|
|
DO_CALL (syscall_name, args); \
|
|
bne r7, zero, SYSCALL_ERROR_LABEL; \
|
|
ret; \
|
|
pseudo_cancel: \
|
|
SAVESTK_##args; /* save syscall args and adjust stack */ \
|
|
SAVEREG(ra, 0); /* save return address */ \
|
|
SAVEREG(r22, 4); /* save GOT pointer */ \
|
|
nextpc r22; \
|
|
1: movhi r2, %hiadj(_gp_got - 1b); \
|
|
addi r2, r2, %lo(_gp_got - 1b); \
|
|
add r22, r22, r2; \
|
|
CENABLE; \
|
|
callr r3; \
|
|
stw r2, 8(sp); /* save mask */ \
|
|
LOADARGS_##args; \
|
|
movi r2, SYS_ify(syscall_name); \
|
|
trap; \
|
|
stw r2, 12(sp); /* save syscall result */ \
|
|
stw r7, 16(sp); /* save syscall error flag */ \
|
|
ldw r4, 8(sp); /* pass mask as argument 1 */ \
|
|
CDISABLE; \
|
|
callr r3; \
|
|
ldw r7, 16(sp); /* restore syscall error flag */ \
|
|
ldw r2, 12(sp); /* restore syscall result */ \
|
|
ldw ra, 0(sp); /* restore return address */ \
|
|
ldw r22, 4(sp); /* restore GOT pointer */ \
|
|
RESTORESTK_##args; \
|
|
bne r7, zero, SYSCALL_ERROR_LABEL;
|
|
|
|
|
|
# undef PSEUDO_END
|
|
# define PSEUDO_END(sym) \
|
|
SYSCALL_ERROR_HANDLER \
|
|
END (sym)
|
|
|
|
#define SAVEREG(REG, LOC) stw REG, LOC(sp); cfi_rel_offset (REG, LOC)
|
|
#define SAVESTK(X) subi sp, sp, X; cfi_adjust_cfa_offset(X)
|
|
#define SAVESTK_0 SAVESTK(20)
|
|
#define SAVEARG_1 SAVEREG(r4, 20)
|
|
#define SAVESTK_1 SAVESTK(24); SAVEARG_1
|
|
#define SAVEARG_2 SAVEREG(r5, 24); SAVEARG_1
|
|
#define SAVESTK_2 SAVESTK(28); SAVEARG_2
|
|
#define SAVEARG_3 SAVEREG(r6, 28); SAVEARG_2
|
|
#define SAVESTK_3 SAVESTK(32); SAVEARG_3
|
|
#define SAVEARG_4 SAVEREG(r7, 32); SAVEARG_3
|
|
#define SAVESTK_4 SAVESTK(36); SAVEARG_4
|
|
#define SAVESTK_5 SAVESTK_4
|
|
#define SAVESTK_6 SAVESTK_5
|
|
|
|
#define LOADARGS_0
|
|
#define LOADARGS_1 ldw r4, 20(sp)
|
|
#define LOADARGS_2 LOADARGS_1; ldw r5, 24(sp)
|
|
#define LOADARGS_3 LOADARGS_2; ldw r6, 28(sp)
|
|
#define LOADARGS_4 LOADARGS_3; ldw r7, 32(sp)
|
|
#define LOADARGS_5 LOADARGS_4; ldw r8, 36(sp)
|
|
#define LOADARGS_6 LOADARGS_5; ldw r9, 40(sp)
|
|
|
|
#define RESTORESTK(X) addi sp, sp, X; cfi_adjust_cfa_offset(-X)
|
|
#define RESTORESTK_0 RESTORESTK(20)
|
|
#define RESTORESTK_1 RESTORESTK(24)
|
|
#define RESTORESTK_2 RESTORESTK(28)
|
|
#define RESTORESTK_3 RESTORESTK(32)
|
|
#define RESTORESTK_4 RESTORESTK(36)
|
|
#define RESTORESTK_5 RESTORESTK(36)
|
|
#define RESTORESTK_6 RESTORESTK(36)
|
|
|
|
# if IS_IN (libpthread)
|
|
# define CENABLE ldw r3, %call(__pthread_enable_asynccancel)(r22)
|
|
# define CDISABLE ldw r3, %call(__pthread_disable_asynccancel)(r22)
|
|
# elif IS_IN (librt)
|
|
# define CENABLE ldw r3, %call(__librt_enable_asynccancel)(r22)
|
|
# define CDISABLE ldw r3, %call(__librt_disable_asynccancel)(r22)
|
|
# elif IS_IN (libc)
|
|
# define CENABLE ldw r3, %call(__libc_enable_asynccancel)(r22)
|
|
# define CDISABLE ldw r3, %call(__libc_disable_asynccancel)(r22)
|
|
# else
|
|
# error Unsupported library
|
|
# endif
|
|
|
|
# ifndef __ASSEMBLER__
|
|
# define SINGLE_THREAD_P \
|
|
__builtin_expect (THREAD_GETMEM (THREAD_SELF, \
|
|
header.multiple_threads) \
|
|
== 0, 1)
|
|
# else
|
|
# define SINGLE_THREAD_P(reg) \
|
|
ldw reg, MULTIPLE_THREADS_OFFSET(r23)
|
|
#endif
|
|
|
|
#elif !defined __ASSEMBLER__
|
|
|
|
# define SINGLE_THREAD_P 1
|
|
# define NO_CANCELLATION 1
|
|
|
|
#endif
|
|
|
|
#ifndef __ASSEMBLER__
|
|
# define RTLD_SINGLE_THREAD_P \
|
|
__builtin_expect (THREAD_GETMEM (THREAD_SELF, \
|
|
header.multiple_threads) == 0, 1)
|
|
#endif
|