1 /* 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, see
17    <http://www.gnu.org/licenses/>.  */
18 
19 #include <common/sysdep.h>
20 
21 #include <features.h>
22 
23 #ifdef	__ASSEMBLER__
24 
25 /* Syntactic details of assembler.  */
26 
27 #define LOCAL(X)	.L_##X
28 #define ALIGNARG(log2) log2
29 /* For ELF we need the `.type' directive to make shared libs work right.  */
30 #define ASM_TYPE_DIRECTIVE(name,typearg) .type name,@##typearg;
31 #define ASM_SIZE_DIRECTIVE(name) .size name,.-name
32 
33 #ifdef SHARED
34 #define PLTJMP(_x)	_x##@PLT
35 #else
36 #define PLTJMP(_x)	_x
37 #endif
38 
39 /* Define an entry point visible from C.  */
40 #define	ENTRY(name)							      \
41   .globl C_SYMBOL_NAME(name);				      \
42   ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),function)			      \
43   .align ALIGNARG(5);							      \
44   C_LABEL(name)								      \
45   cfi_startproc;
46 
47 #undef	END
48 #define END(name)							      \
49   cfi_endproc;								      \
50   ASM_SIZE_DIRECTIVE(C_SYMBOL_NAME(name))
51 
52 #ifdef	__UCLIBC_UNDERSCORES__
53 /* Since C identifiers are not normally prefixed with an underscore
54    on this system, the asm identifier `syscall_error' intrudes on the
55    C name space.  Make sure we use an innocuous name.  */
56 #define	syscall_error	__syscall_error
57 #define mcount		_mcount
58 #endif
59 
60 /* For Linux we can use the system call table in the header file
61 	/usr/include/asm/unistd.h
62    of the kernel.  But these symbols do not follow the SYS_* syntax
63    so we have to redefine the `SYS_ify' macro here.  */
64 #undef SYS_ify
65 #define SYS_ify(syscall_name)	(__NR_##syscall_name)
66 
67 #define ret	rts ; nop
68 /* The sh move insn is s, d.  */
69 #define MOVE(x,y)	mov x , y
70 
71 /* Linux uses a negative return value to indicate syscall errors,
72    unlike most Unices, which use the condition codes' carry flag.
73 
74    Since version 2.1 the return value of a system call might be
75    negative even if the call succeeded.  E.g., the `lseek' system call
76    might return a large offset.  Therefore we must not anymore test
77    for < 0, but test for a real error by making sure the value in R0
78    is a real error number.  Linus said he will make sure the no syscall
79    returns a value in -1 .. -4095 as a valid result so we can savely
80    test with -4095.  */
81 
82 #define _IMM1 #-1
83 #define _IMM12 #-12
84 #undef	PSEUDO
85 #define	PSEUDO(name, syscall_name, args) \
86  .text; \
87  ENTRY (name); \
88     DO_CALL (syscall_name, args); \
89     mov r0,r1; \
90     mov _IMM12,r2; \
91     shad r2,r1; \
92     not r1,r1; \
93     tst r1,r1; \
94     bf .Lpseudo_end; \
95     SYSCALL_ERROR_HANDLER; \
96  .Lpseudo_end:
97 
98 #undef	PSEUDO_END
99 #define	PSEUDO_END(name) \
100   END (name)
101 
102 #undef	PSEUDO_NOERRNO
103 #define	PSEUDO_NOERRNO(name, syscall_name, args) \
104  .text; \
105  ENTRY (name); \
106     DO_CALL (syscall_name, args)
107 
108 #undef	PSEUDO_END_NOERRNO
109 #define	PSEUDO_END_NOERRNO(name) \
110   END (name)
111 
112 #define ret_NOERRNO ret
113 
114 #define	PSEUDO_ERRVAL(name, syscall_name, args) \
115  .text; \
116  ENTRY (name); \
117     DO_CALL (syscall_name, args);
118 
119 #undef	PSEUDO_END_ERRVAL
120 #define	PSEUDO_END_ERRVAL(name) \
121   END (name)
122 
123 #ifndef __PIC__
124 # define SYSCALL_ERROR_HANDLER	\
125 	mov.l 0f,r1; \
126 	jmp @r1; \
127 	 mov r0,r4; \
128 	.align 2; \
129      0: .long __syscall_error
130 
131 #include <libc/sysdeps/linux/sh/syscall_error.S>
132 #else
133 # if defined _LIBC_REENTRANT
134 
135 #  if defined USE___THREAD
136 
137 #    define SYSCALL_ERROR_ERRNO errno
138 #   define SYSCALL_ERROR_HANDLER \
139 	neg r0,r1; \
140 	mov r12,r2; \
141 	mov.l 0f,r12; \
142 	mova 0f,r0; \
143 	add r0,r12; \
144 	mov.l 1f,r0; \
145 	stc gbr, r4; \
146 	mov.l @(r0,r12),r0; \
147 	bra .Lskip; \
148 	add r4,r0; \
149 	.align 2; \
150 	1: .long SYSCALL_ERROR_ERRNO@GOTTPOFF; \
151 	.Lskip: \
152 	mov r2,r12; \
153 	mov.l r1,@r0; \
154 	bra .Lpseudo_end; \
155 	mov _IMM1,r0; \
156 	.align 2; \
157 	0: .long _GLOBAL_OFFSET_TABLE_
158 #  else
159 
160 #   define SYSCALL_ERROR_HANDLER \
161 	neg r0,r1; \
162 	mov.l r14,@-r15; \
163 	mov.l r12,@-r15; \
164 	mov.l r1,@-r15; \
165 	mov.l 0f,r12; \
166 	mova 0f,r0; \
167 	add r0,r12; \
168 	sts.l pr,@-r15; \
169 	mov r15,r14; \
170 	mov.l 1f,r1; \
171 	bsrf r1; \
172          nop; \
173      2: mov r14,r15; \
174 	lds.l @r15+,pr; \
175 	mov.l @r15+,r1; \
176 	mov.l r1,@r0; \
177 	mov.l @r15+,r12; \
178 	mov.l @r15+,r14; \
179 	bra .Lpseudo_end; \
180 	 mov _IMM1,r0; \
181 	.align 2; \
182      0: .long _GLOBAL_OFFSET_TABLE_; \
183      1: .long PLTJMP(C_SYMBOL_NAME(__errno_location))-(2b-.)
184 /* A quick note: it is assumed that the call to `__errno_location' does
185    not modify the stack!  */
186 #  endif
187 # else
188 
189 /* Store (-r0) into errno through the GOT.  */
190 #  define SYSCALL_ERROR_HANDLER						      \
191 	neg r0,r1; \
192 	mov r12,r2; \
193 	mov.l 0f,r12; \
194 	mova 0f,r0; \
195 	add r0,r12; \
196 	mov.l 1f,r0; \
197 	mov.l @(r0,r12),r0; \
198 	mov r2,r12; \
199 	mov.l r1,@r0; \
200 	bra .Lpseudo_end; \
201 	 mov _IMM1,r0; \
202 	.align 2; \
203      0: .long _GLOBAL_OFFSET_TABLE_; \
204      1: .long errno@GOT
205 # endif	/* _LIBC_REENTRANT */
206 #endif	/* __PIC__ */
207 
208 # ifdef __SH4__
209 #  define SYSCALL_INST_PAD \
210 	or r0,r0; or r0,r0; or r0,r0; or r0,r0; or r0,r0
211 # else
212 #  define SYSCALL_INST_PAD
213 # endif
214 
215 #define SYSCALL_INST0	trapa #0x10
216 #define SYSCALL_INST1	trapa #0x11
217 #define SYSCALL_INST2	trapa #0x12
218 #define SYSCALL_INST3	trapa #0x13
219 #define SYSCALL_INST4	trapa #0x14
220 #define SYSCALL_INST5	mov.l @(0,r15),r0; trapa #0x15
221 #define SYSCALL_INST6	mov.l @(0,r15),r0; mov.l @(4,r15),r1; trapa #0x16
222 
223 #undef	DO_CALL
224 #define DO_CALL(syscall_name, args)	\
225     mov.l 1f,r3;			\
226     SYSCALL_INST##args;			\
227     SYSCALL_INST_PAD;			\
228     bra 2f;				\
229      nop;				\
230     .align 2;				\
231  1: .long SYS_ify (syscall_name);	\
232  2:
233 #endif	/* __ASSEMBLER__ */
234