1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
/* Copyright (C) 2014-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)
# if !IS_IN (librt) || !defined(PIC)
# define AC_STACK_SIZE 16 /* space for r15, async_cancel arg and 2 temp words */
# define AC_SET_GOT /* empty */
# define AC_RESTORE_GOT /* empty */
# else
# define AC_STACK_SIZE 20 /* extra 4 bytes for r20 */
# define AC_SET_GOT \
swi r20, r1, AC_STACK_SIZE-4; \
mfs r20, rpc; \
addik r20, r20, _GLOBAL_OFFSET_TABLE_+8;
# define AC_RESTORE_GOT \
lwi r20, r1, AC_STACK_SIZE-4;
# endif
# undef PSEUDO
# define PSEUDO(name, syscall_name, args) \
.text; \
ENTRY (name) \
SINGLE_THREAD_P(r12); \
bnei r12, L(pseudo_cancel); \
.globl __##syscall_name##_nocancel; \
.type __##syscall_name##_nocancel,@function; \
__##syscall_name##_nocancel: \
DO_CALL (syscall_name, args); \
addik r4, r0, -4095; \
cmpu r4, r4, r3; \
bgei r4, SYSCALL_ERROR_LABEL; \
rtsd r15, 8; \
nop; \
.size __##syscall_name##_nocancel, .-__##syscall_name##_nocancel; \
L(pseudo_cancel): \
addik r1, r1, -AC_STACK_SIZE; \
swi r15, r1, 0; \
AC_SET_GOT \
DOCARGS_##args \
CENABLE; \
swi r3, r1, 8; \
UNDOCARGS_##args \
DO_CALL (syscall_name, args); \
swi r3, r1, 12; \
lwi r5, r1, 8; \
CDISABLE; \
lwi r3, r1, 12; \
lwi r15, r1, 0; \
AC_RESTORE_GOT \
addik r1, r1, AC_STACK_SIZE; \
addik r4, r0, -4095; \
cmpu r4, r4, r3; \
bgei r4, SYSCALL_ERROR_LABEL; \
rtsd r15, 8; \
nop;
/*
* Macros to save/restore syscall arguments across CENABLE
* The arguments are saved into the caller's stack (original r1 + 4)
*/
# define DOCARGS_0
# define DOCARGS_1 swi r5, r1, AC_STACK_SIZE + 4;
# define DOCARGS_2 swi r6, r1, AC_STACK_SIZE + 8; DOCARGS_1
# define DOCARGS_3 swi r7, r1, AC_STACK_SIZE + 12; DOCARGS_2
# define DOCARGS_4 swi r8, r1, AC_STACK_SIZE + 16; DOCARGS_3
# define DOCARGS_5 swi r9, r1, AC_STACK_SIZE + 20; DOCARGS_4
# define DOCARGS_6 swi r10, r1, AC_STACK_SIZE + 24; DOCARGS_5
# define UNDOCARGS_0
# define UNDOCARGS_1 lwi r5, r1, AC_STACK_SIZE + 4;
# define UNDOCARGS_2 UNDOCARGS_1 lwi r6, r1, AC_STACK_SIZE + 8;
# define UNDOCARGS_3 UNDOCARGS_2 lwi r7, r1, AC_STACK_SIZE + 12;
# define UNDOCARGS_4 UNDOCARGS_3 lwi r8, r1, AC_STACK_SIZE + 16;
# define UNDOCARGS_5 UNDOCARGS_4 lwi r9, r1, AC_STACK_SIZE + 20;
# define UNDOCARGS_6 UNDOCARGS_5 lwi r10, r1, AC_STACK_SIZE + 24;
# ifdef PIC
# define PSEUDO_JMP(sym) brlid r15, sym##@PLTPC; addk r0, r0, r0
# else
# define PSEUDO_JMP(sym) brlid r15, sym; addk r0, r0, r0
# endif
# if IS_IN (libpthread)
# define CENABLE PSEUDO_JMP (__pthread_enable_asynccancel)
# define CDISABLE PSEUDO_JMP (__pthread_disable_asynccancel)
# define __local_multiple_threads __pthread_multiple_threads
# elif IS_IN (libc)
# define CENABLE PSEUDO_JMP (__libc_enable_asynccancel)
# define CDISABLE PSEUDO_JMP (__libc_disable_asynccancel)
# define __local_multiple_threads __libc_multiple_threads
# elif IS_IN (librt)
# define CENABLE PSEUDO_JMP (__librt_enable_asynccancel)
# define CDISABLE PSEUDO_JMP (__librt_disable_asynccancel)
# else
# error Unsupported library
# endif
# if IS_IN (libpthread) || IS_IN (libc)
# ifndef __ASSEMBLER__
extern int __local_multiple_threads attribute_hidden;
# define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1)
# else
# if !defined PIC
# define SINGLE_THREAD_P(reg) lwi reg, r0, __local_multiple_threads;
# else
# define SINGLE_THREAD_P(reg) \
mfs reg, rpc; \
addik reg, reg, _GLOBAL_OFFSET_TABLE_+8; \
lwi reg, reg, __local_multiple_threads@GOT; \
lwi reg, reg, 0;
# endif
# endif
# else
# ifndef __ASSEMBLER__
# define SINGLE_THREAD_P \
__builtin_expect (THREAD_GETMEM (THREAD_SELF, \
header.multiple_threads) == 0, 1)
# else
# define SINGLE_THREAD_P(reg) \
lwi reg, r0, MULTIPLE_THREADS_OFFSET(reg)
# endif
# 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
|