1 /* Copyright (C) 2003-2014 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library. If not, see
16 <http://www.gnu.org/licenses/>. */
19 #include <sysdeps/generic/sysdep.h>
22 # include <nptl/pthreadP.h>
26 /* Gas will put the initial save of $gp into the CIE, because it appears to
27 happen before any instructions. So we use cfi_same_value instead of
30 #if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
34 # define PSEUDO(name, syscall_name, args) \
38 cfi_adjust_cfa_offset (STKSPACE); \
39 cfi_rel_offset (gp, STKOFF_GP); \
40 99: PTR_LA t9,__syscall_error; \
41 /* manual cpreturn */ \
42 REG_L gp, STKOFF_GP(sp); \
43 cfi_same_value (gp); \
46 .type __##syscall_name##_nocancel, @function; \
47 .globl __##syscall_name##_nocancel; \
48 __##syscall_name##_nocancel: \
50 .cpsetup t9, STKOFF_GP, name; \
51 cfi_rel_offset (gp, STKOFF_GP); \
52 li v0, SYS_ify(syscall_name); \
54 bne a3, zero, SYSCALL_ERROR_LABEL; \
55 /* manual cpreturn */ \
56 REG_L gp, STKOFF_GP(sp); \
57 cfi_same_value (gp); \
61 .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \
64 .cpsetup t9, STKOFF_GP, name; \
65 cfi_rel_offset (gp, STKOFF_GP); \
66 SINGLE_THREAD_P(v1); \
67 bne zero, v1, L(pseudo_cancel); \
69 li v0, SYS_ify(syscall_name); \
72 bne a3, zero, SYSCALL_ERROR_LABEL; \
73 /* manual cpreturn */ \
74 REG_L gp, STKOFF_GP(sp); \
75 cfi_same_value (gp); \
79 cfi_adjust_cfa_offset (STKSPACE); \
80 cfi_rel_offset (gp, STKOFF_GP); \
81 REG_S ra, STKOFF_RA(sp); \
82 cfi_rel_offset (ra, STKOFF_RA); \
83 PUSHARGS_##args; /* save syscall args */ \
85 REG_S v0, STKOFF_SVMSK(sp); /* save mask */ \
86 POPARGS_##args; /* restore syscall args */ \
88 li v0, SYS_ify (syscall_name); \
91 REG_S v0, STKOFF_SC_V0(sp); /* save syscall result */ \
92 REG_S a3, STKOFF_SC_ERR(sp); /* save syscall error flag */ \
93 REG_L a0, STKOFF_SVMSK(sp); /* pass mask as arg1 */ \
95 REG_L a3, STKOFF_SC_ERR(sp); /* restore syscall error flag */ \
96 REG_L ra, STKOFF_RA(sp); /* restore return address */ \
97 REG_L v0, STKOFF_SC_V0(sp); /* restore syscall result */ \
98 bne a3, zero, SYSCALL_ERROR_LABEL; \
99 /* manual cpreturn */ \
100 REG_L gp, STKOFF_GP(sp); \
101 cfi_same_value (gp); \
106 # define PSEUDO(name, syscall_name, args) \
110 cfi_adjust_cfa_offset (STKSPACE); \
113 .type __##syscall_name##_nocancel, @function; \
114 .globl __##syscall_name##_nocancel; \
115 __##syscall_name##_nocancel: \
117 li v0, SYS_ify(syscall_name); \
119 bne a3, zero, SYSCALL_ERROR_LABEL; \
123 .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \
126 SINGLE_THREAD_P(v1); \
127 bne zero, v1, L(pseudo_cancel); \
129 li v0, SYS_ify(syscall_name); \
132 bne a3, zero, SYSCALL_ERROR_LABEL; \
136 cfi_adjust_cfa_offset (STKSPACE); \
137 REG_S ra, STKOFF_RA(sp); \
138 cfi_rel_offset (ra, STKOFF_RA); \
139 PUSHARGS_##args; /* save syscall args */ \
141 REG_S v0, STKOFF_SVMSK(sp); /* save mask */ \
142 POPARGS_##args; /* restore syscall args */ \
144 li v0, SYS_ify (syscall_name); \
147 REG_S v0, STKOFF_SC_V0(sp); /* save syscall result */ \
148 REG_S a3, STKOFF_SC_ERR(sp); /* save syscall error flag */ \
149 REG_L a0, STKOFF_SVMSK(sp); /* pass mask as arg1 */ \
151 REG_L a3, STKOFF_SC_ERR(sp); /* restore syscall error flag */ \
152 REG_L ra, STKOFF_RA(sp); /* restore return address */ \
153 REG_L v0, STKOFF_SC_V0(sp); /* restore syscall result */ \
154 bne a3, zero, SYSCALL_ERROR_LABEL; \
160 # define PSEUDO_END(sym) cfi_endproc; .end sym; .size sym,.-sym
162 # define PUSHARGS_0 /* nothing to do */
163 # define PUSHARGS_1 PUSHARGS_0 REG_S a0, STKOFF_A0(sp); cfi_rel_offset (a0, STKOFF_A0);
164 # define PUSHARGS_2 PUSHARGS_1 REG_S a1, STKOFF_A1(sp); cfi_rel_offset (a1, STKOFF_A1);
165 # define PUSHARGS_3 PUSHARGS_2 REG_S a2, STKOFF_A2(sp); cfi_rel_offset (a2, STKOFF_A2);
166 # define PUSHARGS_4 PUSHARGS_3 REG_S a3, STKOFF_A3(sp); cfi_rel_offset (a3, STKOFF_A3);
167 # define PUSHARGS_5 PUSHARGS_4 REG_S a4, STKOFF_A4(sp); cfi_rel_offset (a3, STKOFF_A4);
168 # define PUSHARGS_6 PUSHARGS_5 REG_S a5, STKOFF_A5(sp); cfi_rel_offset (a3, STKOFF_A5);
170 # define POPARGS_0 /* nothing to do */
171 # define POPARGS_1 POPARGS_0 REG_L a0, STKOFF_A0(sp);
172 # define POPARGS_2 POPARGS_1 REG_L a1, STKOFF_A1(sp);
173 # define POPARGS_3 POPARGS_2 REG_L a2, STKOFF_A2(sp);
174 # define POPARGS_4 POPARGS_3 REG_L a3, STKOFF_A3(sp);
175 # define POPARGS_5 POPARGS_4 REG_L a4, STKOFF_A4(sp);
176 # define POPARGS_6 POPARGS_5 REG_L a5, STKOFF_A5(sp);
178 /* Save an even number of slots. Should be 0 if an even number of slots
179 are used below, or SZREG if an odd number are used. */
181 # define STK_PAD SZREG
186 /* Place values that we are more likely to use later in this sequence, i.e.
187 closer to the SP at function entry. If you do that, the are more
188 likely to already be in your d-cache. */
189 # define STKOFF_A5 (STK_PAD)
190 # define STKOFF_A4 (STKOFF_A5 + SZREG)
191 # define STKOFF_A3 (STKOFF_A4 + SZREG)
192 # define STKOFF_A2 (STKOFF_A3 + SZREG) /* MT and more args. */
193 # define STKOFF_A1 (STKOFF_A2 + SZREG) /* MT and 2 args. */
194 # define STKOFF_A0 (STKOFF_A1 + SZREG) /* MT and 1 arg. */
195 # define STKOFF_RA (STKOFF_A0 + SZREG) /* Used if MT. */
196 # define STKOFF_SC_V0 (STKOFF_RA + SZREG) /* Used if MT. */
197 # define STKOFF_SC_ERR (STKOFF_SC_V0 + SZREG) /* Used if MT. */
198 # define STKOFF_SVMSK (STKOFF_SC_ERR + SZREG) /* Used if MT. */
201 # define STKOFF_GP (STKOFF_SVMSK + SZREG) /* Always used. */
202 # define STKSPACE (STKOFF_GP + SZREG)
204 # define STKSPACE (STKOFF_SVMSK + SZREG)
207 # define SAVESTK PTR_SUBU sp, STKSPACE; cfi_adjust_cfa_offset(STKSPACE)
208 # define RESTORESTK PTR_ADDU sp, STKSPACE; cfi_adjust_cfa_offset(-STKSPACE)
211 # define PSEUDO_JMP(sym) PTR_LA t9, sym; jalr t9
213 # define PSEUDO_JMP(sym) jal sym
216 # ifdef IS_IN_libpthread
217 # define CENABLE PSEUDO_JMP (__pthread_enable_asynccancel)
218 # define CDISABLE PSEUDO_JMP (__pthread_disable_asynccancel)
219 # elif defined IS_IN_librt
220 # define CENABLE PSEUDO_JMP (__librt_enable_asynccancel)
221 # define CDISABLE PSEUDO_JMP (__librt_disable_asynccancel)
223 # define CENABLE PSEUDO_JMP (__libc_enable_asynccancel)
224 # define CDISABLE PSEUDO_JMP (__libc_disable_asynccancel)
227 # ifndef __ASSEMBLER__
228 # define SINGLE_THREAD_P \
229 __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
230 header.multiple_threads) \
233 # define SINGLE_THREAD_P(reg) \
234 READ_THREAD_POINTER(reg); \
235 lw reg, MULTIPLE_THREADS_OFFSET(reg)
238 #elif !defined __ASSEMBLER__
240 # define SINGLE_THREAD_P 1
241 # define NO_CANCELLATION 1
245 #ifndef __ASSEMBLER__
246 # define RTLD_SINGLE_THREAD_P \
247 __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
248 header.multiple_threads) == 0, 1)