blob: 8b3c68220f17b4be670bcdcdb3fd977f9eb5e433 [file] [log] [blame]
yuezonghe824eb0c2024-06-27 02:32:26 -07001/* Assembler macros for SH.
2 Copyright (C) 1999, 2000, 2005 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
19
20#include <common/sysdep.h>
21
22#include <features.h>
23#include <libc-internal.h>
24
25#ifdef __ASSEMBLER__
26
27/* Syntactic details of assembler. */
28
29#define LOCAL(X) .L_##X
30#define ALIGNARG(log2) log2
31/* For ELF we need the `.type' directive to make shared libs work right. */
32#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,@##typearg;
33#define ASM_SIZE_DIRECTIVE(name) .size name,.-name
34
35#ifdef SHARED
36#define PLTJMP(_x) _x##@PLT
37#else
38#define PLTJMP(_x) _x
39#endif
40
41/* Define an entry point visible from C. */
42#define ENTRY(name) \
43 ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \
44 ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),function) \
45 .align ALIGNARG(5); \
46 C_LABEL(name) \
47 cfi_startproc; \
48 CALL_MCOUNT
49
50#undef END
51#define END(name) \
52 cfi_endproc; \
53 ASM_SIZE_DIRECTIVE(C_SYMBOL_NAME(name))
54
55/* If compiled for profiling, call `mcount' at the start of each function. */
56#ifdef PROF
57#define CALL_MCOUNT \
58 mov.l 1f,r1; \
59 sts.l pr,@-r15; \
60 cfi_adjust_cfa_offset (4); \
61 cfi_rel_offset (pr, 0); \
62 mova 2f,r0; \
63 jmp @r1; \
64 lds r0,pr; \
65 .align 2; \
661: .long mcount; \
672: lds.l @r15+,pr; \
68 cfi_adjust_cfa_offset (-4); \
69 cfi_restore (pr)
70
71#else
72#define CALL_MCOUNT /* Do nothing. */
73#endif
74
75#ifdef __UCLIBC_UNDERSCORES__
76/* Since C identifiers are not normally prefixed with an underscore
77 on this system, the asm identifier `syscall_error' intrudes on the
78 C name space. Make sure we use an innocuous name. */
79#define syscall_error __syscall_error
80#define mcount _mcount
81#endif
82
83/* For Linux we can use the system call table in the header file
84 /usr/include/asm/unistd.h
85 of the kernel. But these symbols do not follow the SYS_* syntax
86 so we have to redefine the `SYS_ify' macro here. */
87#undef SYS_ify
88#define SYS_ify(syscall_name) (__NR_##syscall_name)
89
90#define ret rts ; nop
91/* The sh move insn is s, d. */
92#define MOVE(x,y) mov x , y
93
94/* Linux uses a negative return value to indicate syscall errors,
95 unlike most Unices, which use the condition codes' carry flag.
96
97 Since version 2.1 the return value of a system call might be
98 negative even if the call succeeded. E.g., the `lseek' system call
99 might return a large offset. Therefore we must not anymore test
100 for < 0, but test for a real error by making sure the value in R0
101 is a real error number. Linus said he will make sure the no syscall
102 returns a value in -1 .. -4095 as a valid result so we can savely
103 test with -4095. */
104
105#define _IMM1 #-1
106#define _IMM12 #-12
107#undef PSEUDO
108#define PSEUDO(name, syscall_name, args) \
109 .text; \
110 ENTRY (name); \
111 DO_CALL (syscall_name, args); \
112 mov r0,r1; \
113 mov _IMM12,r2; \
114 shad r2,r1; \
115 not r1,r1; \
116 tst r1,r1; \
117 bf .Lpseudo_end; \
118 SYSCALL_ERROR_HANDLER; \
119 .Lpseudo_end:
120
121#undef PSEUDO_END
122#define PSEUDO_END(name) \
123 END (name)
124
125#undef PSEUDO_NOERRNO
126#define PSEUDO_NOERRNO(name, syscall_name, args) \
127 .text; \
128 ENTRY (name); \
129 DO_CALL (syscall_name, args)
130
131#undef PSEUDO_END_NOERRNO
132#define PSEUDO_END_NOERRNO(name) \
133 END (name)
134
135#define ret_NOERRNO ret
136
137#define PSEUDO_ERRVAL(name, syscall_name, args) \
138 .text; \
139 ENTRY (name); \
140 DO_CALL (syscall_name, args);
141
142#undef PSEUDO_END_ERRVAL
143#define PSEUDO_END_ERRVAL(name) \
144 END (name)
145
146#define ret_ERRVAL ret
147
148#ifndef __PIC__
149# define SYSCALL_ERROR_HANDLER \
150 mov.l 0f,r1; \
151 jmp @r1; \
152 mov r0,r4; \
153 .align 2; \
154 0: .long __syscall_error
155
156#include <libc/sysdeps/linux/sh/syscall_error.S>
157#else
158# ifdef RTLD_PRIVATE_ERRNO
159
160# define SYSCALL_ERROR_HANDLER \
161 neg r0,r1; \
162 mov.l 0f,r12; \
163 mova 0f,r0; \
164 add r0,r12; \
165 mov.l 1f,r0; \
166 mov.l r1,@(r0,r12)
167 bra .Lpseudo_end; \
168 mov _IMM1,r0; \
169 .align 2; \
170 0: .long _GLOBAL_OFFSET_TABLE_; \
171 1: .long rtld_errno@GOTOFF
172
173# elif defined _LIBC_REENTRANT
174
175# if defined USE___THREAD
176
177# ifndef NOT_IN_libc
178# define SYSCALL_ERROR_ERRNO __libc_errno
179# else
180# define SYSCALL_ERROR_ERRNO errno
181# endif
182# define SYSCALL_ERROR_HANDLER \
183 neg r0,r1; \
184 mov r12,r2; \
185 mov.l 0f,r12; \
186 mova 0f,r0; \
187 add r0,r12; \
188 mov.l 1f,r0; \
189 stc gbr, r4; \
190 mov.l @(r0,r12),r0; \
191 bra .Lskip; \
192 add r4,r0; \
193 .align 2; \
194 1: .long SYSCALL_ERROR_ERRNO@GOTTPOFF; \
195 .Lskip: \
196 mov r2,r12; \
197 mov.l r1,@r0; \
198 bra .Lpseudo_end; \
199 mov _IMM1,r0; \
200 .align 2; \
201 0: .long _GLOBAL_OFFSET_TABLE_
202# else
203
204# define SYSCALL_ERROR_HANDLER \
205 neg r0,r1; \
206 mov.l r14,@-r15; \
207 mov.l r12,@-r15; \
208 mov.l r1,@-r15; \
209 mov.l 0f,r12; \
210 mova 0f,r0; \
211 add r0,r12; \
212 sts.l pr,@-r15; \
213 mov r15,r14; \
214 mov.l 1f,r1; \
215 bsrf r1; \
216 nop; \
217 2: mov r14,r15; \
218 lds.l @r15+,pr; \
219 mov.l @r15+,r1; \
220 mov.l r1,@r0; \
221 mov.l @r15+,r12; \
222 mov.l @r15+,r14; \
223 bra .Lpseudo_end; \
224 mov _IMM1,r0; \
225 .align 2; \
226 0: .long _GLOBAL_OFFSET_TABLE_; \
227 1: .long PLTJMP(C_SYMBOL_NAME(__errno_location))-(2b-.)
228/* A quick note: it is assumed that the call to `__errno_location' does
229 not modify the stack! */
230# endif
231# else
232
233/* Store (-r0) into errno through the GOT. */
234# define SYSCALL_ERROR_HANDLER \
235 neg r0,r1; \
236 mov r12,r2; \
237 mov.l 0f,r12; \
238 mova 0f,r0; \
239 add r0,r12; \
240 mov.l 1f,r0; \
241 mov.l @(r0,r12),r0; \
242 mov r2,r12; \
243 mov.l r1,@r0; \
244 bra .Lpseudo_end; \
245 mov _IMM1,r0; \
246 .align 2; \
247 0: .long _GLOBAL_OFFSET_TABLE_; \
248 1: .long errno@GOT
249# endif /* _LIBC_REENTRANT */
250#endif /* __PIC__ */
251
252# ifdef __SH4__
253# define SYSCALL_INST_PAD \
254 or r0,r0; or r0,r0; or r0,r0; or r0,r0; or r0,r0
255# else
256# define SYSCALL_INST_PAD
257# endif
258
259#define SYSCALL_INST0 trapa #0x10
260#define SYSCALL_INST1 trapa #0x11
261#define SYSCALL_INST2 trapa #0x12
262#define SYSCALL_INST3 trapa #0x13
263#define SYSCALL_INST4 trapa #0x14
264#define SYSCALL_INST5 mov.l @(0,r15),r0; trapa #0x15
265#define SYSCALL_INST6 mov.l @(0,r15),r0; mov.l @(4,r15),r1; trapa #0x16
266
267#undef DO_CALL
268#define DO_CALL(syscall_name, args) \
269 mov.l 1f,r3; \
270 SYSCALL_INST##args; \
271 SYSCALL_INST_PAD; \
272 bra 2f; \
273 nop; \
274 .align 2; \
275 1: .long SYS_ify (syscall_name); \
276 2:
277#endif /* __ASSEMBLER__ */
278
279/* Pointer mangling support. */
280#if defined NOT_IN_libc && defined IS_IN_rtld
281/* We cannot use the thread descriptor because in ld.so we use setjmp
282 earlier than the descriptor is initialized. Using a global variable
283 is too complicated here since we have no PC-relative addressing mode. */
284#else
285# ifdef __ASSEMBLER__
286# define PTR_MANGLE(reg, tmp) \
287 stc gbr,tmp; mov.l @(POINTER_GUARD,tmp),tmp; xor tmp,reg
288# define PTR_MANGLE2(reg, tmp) xor tmp,reg
289# define PTR_DEMANGLE(reg, tmp) PTR_MANGLE (reg, tmp)
290# define PTR_DEMANGLE2(reg, tmp) PTR_MANGLE2 (reg, tmp)
291# else
292# define PTR_MANGLE(var) \
293 (var) = (void *) ((uintptr_t) (var) ^ THREAD_GET_POINTER_GUARD ())
294# define PTR_DEMANGLE(var) PTR_MANGLE (var)
295# endif
296#endif
297