]>
Commit | Line | Data |
---|---|---|
f7a9f785 | 1 | /* Copyright (C) 2003-2016 Free Software Foundation, Inc. |
5400aba6 UD |
2 | This file is part of the GNU C Library. |
3 | ||
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. | |
8 | ||
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. | |
13 | ||
14 | You should have received a copy of the GNU Lesser General Public | |
ab84e3ff PE |
15 | License along with the GNU C Library. If not, see |
16 | <http://www.gnu.org/licenses/>. */ | |
5400aba6 UD |
17 | |
18 | #include <sysdep.h> | |
19 | #include <tls.h> | |
20 | #ifndef __ASSEMBLER__ | |
21 | # include <nptl/pthreadP.h> | |
22 | #endif | |
23 | ||
4f41c682 | 24 | #if IS_IN (libc) || IS_IN (libpthread) || IS_IN (librt) |
5400aba6 | 25 | |
5400aba6 UD |
26 | /* ??? Assumes that nothing comes between PSEUDO and PSEUDO_END |
27 | besides "ret". */ | |
28 | ||
29 | # undef PSEUDO | |
30 | # define PSEUDO(name, syscall_name, args) \ | |
e184a918 RH |
31 | .globl __##syscall_name##_nocancel; \ |
32 | .type __##syscall_name##_nocancel, @function; \ | |
33 | .usepv __##syscall_name##_nocancel, std; \ | |
5400aba6 | 34 | .align 4; \ |
5400aba6 | 35 | cfi_startproc; \ |
e184a918 | 36 | __LABEL(__##syscall_name##_nocancel) \ |
5400aba6 UD |
37 | ldgp gp, 0(pv); \ |
38 | PSEUDO_PROF; \ | |
e184a918 RH |
39 | __LABEL($pseudo_nocancel) \ |
40 | PSEUDO_PREPARE_ARGS; \ | |
5400aba6 UD |
41 | lda v0, SYS_ify(syscall_name); \ |
42 | call_pal PAL_callsys; \ | |
43 | bne a3, SYSCALL_ERROR_LABEL; \ | |
44 | __LABEL($pseudo_ret) \ | |
45 | .subsection 2; \ | |
e184a918 RH |
46 | .size __##syscall_name##_nocancel, .-__##syscall_name##_nocancel; \ |
47 | .globl name; \ | |
48 | .type name, @function; \ | |
49 | .usepv name, std; \ | |
50 | .align 4; \ | |
0c3c8450 | 51 | cfi_startproc; \ |
e184a918 RH |
52 | __LABEL(name) \ |
53 | ldgp gp, 0(pv); \ | |
54 | PSEUDO_PROF; \ | |
55 | SINGLE_THREAD_P(t0); \ | |
56 | beq t0, $pseudo_nocancel; \ | |
5400aba6 UD |
57 | subq sp, 64, sp; \ |
58 | cfi_def_cfa_offset(64); \ | |
59 | stq ra, 0(sp); \ | |
60 | cfi_offset(ra, -64); \ | |
61 | SAVE_ARGS_##args; \ | |
62 | CENABLE; \ | |
63 | LOAD_ARGS_##args; \ | |
a5e72ef8 RH |
64 | /* Save the CENABLE return value in RA. That register \ |
65 | is preserved across syscall and the real return \ | |
66 | address is saved on the stack. */ \ | |
67 | mov v0, ra; \ | |
5400aba6 UD |
68 | lda v0, SYS_ify(syscall_name); \ |
69 | call_pal PAL_callsys; \ | |
70 | stq v0, 8(sp); \ | |
a5e72ef8 | 71 | mov ra, a0; \ |
5400aba6 UD |
72 | bne a3, $multi_error; \ |
73 | CDISABLE; \ | |
74 | ldq ra, 0(sp); \ | |
75 | ldq v0, 8(sp); \ | |
76 | addq sp, 64, sp; \ | |
77 | cfi_remember_state; \ | |
78 | cfi_restore(ra); \ | |
79 | cfi_def_cfa_offset(0); \ | |
80 | ret; \ | |
81 | cfi_restore_state; \ | |
82 | __LABEL($multi_error) \ | |
83 | CDISABLE; \ | |
84 | ldq ra, 0(sp); \ | |
85 | ldq v0, 8(sp); \ | |
86 | addq sp, 64, sp; \ | |
87 | cfi_restore(ra); \ | |
88 | cfi_def_cfa_offset(0); \ | |
c18b7473 | 89 | SYSCALL_ERROR_FALLTHRU; \ |
5400aba6 | 90 | SYSCALL_ERROR_HANDLER; \ |
0c3c8450 | 91 | cfi_endproc; \ |
5400aba6 UD |
92 | .previous |
93 | ||
94 | # undef PSEUDO_END | |
95 | # define PSEUDO_END(sym) \ | |
5400aba6 | 96 | cfi_endproc; \ |
0c3c8450 | 97 | .subsection 2; \ |
5400aba6 UD |
98 | .size sym, .-sym |
99 | ||
100 | # define SAVE_ARGS_0 /* Nothing. */ | |
101 | # define SAVE_ARGS_1 SAVE_ARGS_0; stq a0, 8(sp) | |
102 | # define SAVE_ARGS_2 SAVE_ARGS_1; stq a1, 16(sp) | |
103 | # define SAVE_ARGS_3 SAVE_ARGS_2; stq a2, 24(sp) | |
104 | # define SAVE_ARGS_4 SAVE_ARGS_3; stq a3, 32(sp) | |
105 | # define SAVE_ARGS_5 SAVE_ARGS_4; stq a4, 40(sp) | |
106 | # define SAVE_ARGS_6 SAVE_ARGS_5; stq a5, 48(sp) | |
107 | ||
108 | # define LOAD_ARGS_0 /* Nothing. */ | |
109 | # define LOAD_ARGS_1 LOAD_ARGS_0; ldq a0, 8(sp) | |
110 | # define LOAD_ARGS_2 LOAD_ARGS_1; ldq a1, 16(sp) | |
111 | # define LOAD_ARGS_3 LOAD_ARGS_2; ldq a2, 24(sp) | |
112 | # define LOAD_ARGS_4 LOAD_ARGS_3; ldq a3, 32(sp) | |
113 | # define LOAD_ARGS_5 LOAD_ARGS_4; ldq a4, 40(sp) | |
114 | # define LOAD_ARGS_6 LOAD_ARGS_5; ldq a5, 48(sp) | |
115 | ||
ce9f10f7 | 116 | # if IS_IN (libpthread) |
5400aba6 UD |
117 | # define __local_enable_asynccancel __pthread_enable_asynccancel |
118 | # define __local_disable_asynccancel __pthread_disable_asynccancel | |
119 | # define __local_multiple_threads __pthread_multiple_threads | |
4f41c682 | 120 | # elif IS_IN (libc) |
5400aba6 UD |
121 | # define __local_enable_asynccancel __libc_enable_asynccancel |
122 | # define __local_disable_asynccancel __libc_disable_asynccancel | |
123 | # define __local_multiple_threads __libc_multiple_threads | |
016afc75 | 124 | # elif IS_IN (librt) |
5400aba6 UD |
125 | # define __local_enable_asynccancel __librt_enable_asynccancel |
126 | # define __local_disable_asynccancel __librt_disable_asynccancel | |
127 | # else | |
128 | # error Unsupported library | |
129 | # endif | |
130 | ||
131 | # ifdef PIC | |
132 | # define CENABLE bsr ra, __local_enable_asynccancel !samegp | |
133 | # define CDISABLE bsr ra, __local_disable_asynccancel !samegp | |
134 | # else | |
135 | # define CENABLE jsr ra, __local_enable_asynccancel; ldgp ra, 0(gp) | |
136 | # define CDISABLE jsr ra, __local_disable_asynccancel; ldgp ra, 0(gp) | |
137 | # endif | |
138 | ||
4f41c682 | 139 | # if IS_IN (libpthread) || IS_IN (libc) |
df8419fe | 140 | # ifndef __ASSEMBLER__ |
5400aba6 | 141 | extern int __local_multiple_threads attribute_hidden; |
df8419fe | 142 | # define SINGLE_THREAD_P \ |
5400aba6 | 143 | __builtin_expect (__local_multiple_threads == 0, 1) |
df8419fe RH |
144 | # elif defined(PIC) |
145 | # define SINGLE_THREAD_P(reg) ldl reg, __local_multiple_threads(gp) !gprel | |
146 | # else | |
147 | # define SINGLE_THREAD_P(reg) \ | |
5400aba6 UD |
148 | ldah reg, __local_multiple_threads(gp) !gprelhigh; \ |
149 | ldl reg, __local_multiple_threads(reg) !gprellow | |
df8419fe RH |
150 | # endif |
151 | # else | |
152 | # ifndef __ASSEMBLER__ | |
153 | # define SINGLE_THREAD_P \ | |
5400aba6 UD |
154 | __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ |
155 | header.multiple_threads) == 0, 1) | |
df8419fe RH |
156 | # else |
157 | # define SINGLE_THREAD_P(reg) \ | |
b17d80b1 RH |
158 | call_pal PAL_rduniq; \ |
159 | ldl reg, MULTIPLE_THREADS_OFFSET($0) | |
df8419fe | 160 | # endif |
5400aba6 | 161 | # endif |
df8419fe RH |
162 | |
163 | #else | |
164 | ||
cf0494f3 | 165 | # define SINGLE_THREAD_P (1) |
df8419fe RH |
166 | # define NO_CANCELLATION 1 |
167 | ||
5400aba6 | 168 | #endif |
cf0494f3 UD |
169 | |
170 | #ifndef __ASSEMBLER__ | |
171 | # define RTLD_SINGLE_THREAD_P \ | |
172 | __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ | |
173 | header.multiple_threads) == 0, 1) | |
174 | #endif |