arm: Use _dl_find_object on __gnu_Unwind_Find_exidx (BZ 31405)
[glibc.git] / sysdeps / powerpc / powerpc64 / sysdep.h
blobc363939e1aa8e73e7557a32d2e65acd644a42ae7
1 /* Assembly macros for 64-bit PowerPC.
2 Copyright (C) 2002-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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 <https://www.gnu.org/licenses/>. */
19 #include <sysdeps/powerpc/sysdep.h>
20 #include <tls.h>
22 #ifdef __ASSEMBLER__
24 /* Stack frame offsets. */
25 #define FRAME_BACKCHAIN 0
26 #define FRAME_CR_SAVE 8
27 #define FRAME_LR_SAVE 16
28 #if _CALL_ELF != 2
29 #define FRAME_MIN_SIZE 112
30 #define FRAME_MIN_SIZE_PARM 112
31 #define FRAME_TOC_SAVE 40
32 #define FRAME_PARM_SAVE 48
33 #else
34 #define FRAME_MIN_SIZE 32
35 #define FRAME_MIN_SIZE_PARM 96
36 #define FRAME_TOC_SAVE 24
37 #define FRAME_PARM_SAVE 32
38 #endif
40 /* Support macros for CALL_MCOUNT. */
41 .macro SAVE_ARG NARG
42 .if \NARG
43 SAVE_ARG \NARG-1
44 std 2+\NARG,-FRAME_MIN_SIZE_PARM+FRAME_PARM_SAVE-8+8*(\NARG)(1)
45 .endif
46 .endm
48 .macro REST_ARG NARG
49 .if \NARG
50 REST_ARG \NARG-1
51 ld 2+\NARG,FRAME_PARM_SAVE-8+8*(\NARG)(1)
52 .endif
53 .endm
55 .macro CFI_SAVE_ARG NARG
56 .if \NARG
57 CFI_SAVE_ARG \NARG-1
58 cfi_offset(2+\NARG,-FRAME_MIN_SIZE_PARM+FRAME_PARM_SAVE-8+8*(\NARG))
59 .endif
60 .endm
62 .macro CFI_REST_ARG NARG
63 .if \NARG
64 CFI_REST_ARG \NARG-1
65 cfi_restore(2+\NARG)
66 .endif
67 .endm
69 /* If compiled for profiling, call `_mcount' at the start of each function.
70 see ppc-mcount.S for more details. */
71 .macro CALL_MCOUNT NARG
72 #ifdef PROF
73 mflr r0
74 SAVE_ARG \NARG
75 std r0,FRAME_LR_SAVE(r1)
76 stdu r1,-FRAME_MIN_SIZE_PARM(r1)
77 cfi_adjust_cfa_offset(FRAME_MIN_SIZE_PARM)
78 cfi_offset(lr,FRAME_LR_SAVE)
79 CFI_SAVE_ARG \NARG
80 bl JUMPTARGET (_mcount)
81 #ifndef SHARED
82 nop
83 #endif
84 ld r0,FRAME_MIN_SIZE_PARM+FRAME_LR_SAVE(r1)
85 REST_ARG \NARG
86 mtlr r0
87 addi r1,r1,FRAME_MIN_SIZE_PARM
88 cfi_adjust_cfa_offset(-FRAME_MIN_SIZE_PARM)
89 cfi_restore(lr)
90 CFI_REST_ARG \NARG
91 #endif
92 .endm
94 #if _CALL_ELF != 2
96 /* Macro to prepare for calling via a function pointer. */
97 .macro PPC64_LOAD_FUNCPTR PTR
98 ld r12,0(\PTR)
99 ld r2,8(\PTR)
100 mtctr r12
101 ld r11,16(\PTR)
102 .endm
104 #ifdef USE_PPC64_OVERLAPPING_OPD
105 # define OPD_ENT(name) .quad BODY_LABEL (name), .TOC.@tocbase
106 #else
107 # define OPD_ENT(name) .quad BODY_LABEL (name), .TOC.@tocbase, 0
108 #endif
110 #define ENTRY_1(name) \
111 .type BODY_LABEL(name),@function; \
112 .globl name; \
113 .section ".opd","aw"; \
114 .p2align 3;FUNC_LABEL(name): \
115 OPD_ENT (name); \
116 .previous
118 #define FUNC_LABEL(X) X
119 #define BODY_LABEL(X) .LY##X
120 #define ENTRY_2(name) \
121 .type name,@function; \
122 ENTRY_1(name)
123 #define END_2(name) \
124 .size name,.-BODY_LABEL(name); \
125 .size BODY_LABEL(name),.-BODY_LABEL(name)
126 #define LOCALENTRY(name)
128 #else /* _CALL_ELF == 2 */
130 /* Macro to prepare for calling via a function pointer. */
131 .macro PPC64_LOAD_FUNCPTR PTR
132 mr r12,\PTR
133 mtctr r12
134 .endm
136 #define FUNC_LABEL(X) X
137 #define BODY_LABEL(X) X
138 #define ENTRY_2(name) \
139 .globl name; \
140 .type name,@function
141 #define END_2(name) \
142 .size name,.-name
143 #define LOCALENTRY(name) \
144 1: addis r2,r12,.TOC.-1b@ha; \
145 addi r2,r2,.TOC.-1b@l; \
146 .localentry name,.-name
148 #endif /* _CALL_ELF */
150 .macro NOPS NARG
151 .if \NARG
152 NOPS \NARG-1
154 .endif
155 .endm
157 .macro ENTRY_3 name, alignp2=2, nopwords=0
158 .text
159 ENTRY_2(\name)
160 .p2align \alignp2
161 NOPS \nopwords
162 BODY_LABEL(\name):
163 .endm
165 /* Use ENTRY_TOCLESS for functions that make no use of r2 and
166 guarantee r2 is unchanged on exit. Any function that has @toc or
167 @got relocs uses r2. Functions that call other functions via the
168 PLT use r2. Use ENTRY for functions that may use or change r2.
169 The first argument is the function name.
170 The optional second argument specifies alignment of the function's
171 code, as the logarithm base two of the byte alignment. For
172 example, a value of four aligns to a sixteen byte boundary.
173 The optional third argument specifies the number of NOPs to emit
174 before the start of the function's code. */
175 #ifndef PROF
176 #define ENTRY_TOCLESS(name, ...) \
177 ENTRY_3 name, ## __VA_ARGS__; \
178 cfi_startproc
180 #define ENTRY(name, ...) \
181 ENTRY_TOCLESS(name, ## __VA_ARGS__); \
182 LOCALENTRY(name)
183 #else
184 /* The call to _mcount is potentially via the plt, so profiling code
185 is never free of an r2 use. */
186 #define ENTRY_TOCLESS(name, ...) \
187 ENTRY_3 name, ## __VA_ARGS__; \
188 cfi_startproc; \
189 LOCALENTRY(name)
191 #define ENTRY(name, ...) \
192 ENTRY_TOCLESS(name, ## __VA_ARGS__)
193 #endif
195 /* Local labels stripped out by the linker. */
196 #undef L
197 #define L(x) .L##x
199 #define tostring(s) #s
200 #define stringify(s) tostring(s)
201 #define XGLUE(a,b) a##b
202 #define GLUE(a,b) XGLUE(a,b)
203 #define LT_LABEL(name) GLUE(.LT,name)
204 #define LT_LABELSUFFIX(name,suffix) GLUE(GLUE(.LT,name),suffix)
206 /* Support Traceback tables */
207 #define TB_ASM 0x000c000000000000
208 #define TB_GLOBALLINK 0x0000800000000000
209 #define TB_IS_EPROL 0x0000400000000000
210 #define TB_HAS_TBOFF 0x0000200000000000
211 #define TB_INT_PROC 0x0000100000000000
212 #define TB_HAS_CTL 0x0000080000000000
213 #define TB_TOCLESS 0x0000040000000000
214 #define TB_FP_PRESENT 0x0000020000000000
215 #define TB_LOG_ABORT 0x0000010000000000
216 #define TB_INT_HANDL 0x0000008000000000
217 #define TB_NAME_PRESENT 0x0000004000000000
218 #define TB_USES_ALLOCA 0x0000002000000000
219 #define TB_SAVES_CR 0x0000000200000000
220 #define TB_SAVES_LR 0x0000000100000000
221 #define TB_STORES_BC 0x0000000080000000
222 #define TB_FIXUP 0x0000000040000000
223 #define TB_FP_SAVED(fprs) (((fprs) & 0x3f) << 24)
224 #define TB_GPR_SAVED(gprs) (((fprs) & 0x3f) << 16)
225 #define TB_FIXEDPARMS(parms) (((parms) & 0xff) << 8)
226 #define TB_FLOATPARMS(parms) (((parms) & 0x7f) << 1)
227 #define TB_PARMSONSTK 0x0000000000000001
229 #define PPC_HIGHER(v) (((v) >> 32) & 0xffff)
230 #define TB_DEFAULT TB_ASM | TB_HAS_TBOFF | TB_NAME_PRESENT
232 #define TRACEBACK(name) \
233 LT_LABEL(name): ; \
234 .long 0 ; \
235 .quad TB_DEFAULT ; \
236 .long LT_LABEL(name)-BODY_LABEL(name) ; \
237 .short LT_LABELSUFFIX(name,_name_end)-LT_LABELSUFFIX(name,_name_start) ; \
238 LT_LABELSUFFIX(name,_name_start): ;\
239 .ascii stringify(name) ; \
240 LT_LABELSUFFIX(name,_name_end): ; \
241 .p2align 2
243 #define TRACEBACK_MASK(name,mask) \
244 LT_LABEL(name): ; \
245 .long 0 ; \
246 .quad TB_DEFAULT | mask ; \
247 .long LT_LABEL(name)-BODY_LABEL(name) ; \
248 .short LT_LABELSUFFIX(name,_name_end)-LT_LABELSUFFIX(name,_name_start) ; \
249 LT_LABELSUFFIX(name,_name_start): ;\
250 .ascii stringify(name) ; \
251 LT_LABELSUFFIX(name,_name_end): ; \
252 .p2align 2
254 /* END generates Traceback tables */
255 #undef END
256 #define END(name) \
257 cfi_endproc; \
258 TRACEBACK(name); \
259 END_2(name)
261 /* This form supports more informative traceback tables */
262 #define END_GEN_TB(name,mask) \
263 cfi_endproc; \
264 TRACEBACK_MASK(name,mask); \
265 END_2(name)
267 /* We will allocate a new frame to save LR and the non-volatile register used to
268 read the TCB when checking for scv support on syscall code. We actually just
269 need the minimum frame size plus room for 1 reg (8 bytes). But the ABI
270 mandates stack frames should be aligned at 16 Bytes, so we end up allocating
271 a bit more space then what will actually be used. */
272 #define SCV_FRAME_SIZE (FRAME_MIN_SIZE+16)
273 #define SCV_FRAME_NVOLREG_SAVE FRAME_MIN_SIZE
275 /* Allocate frame and save register */
276 #define NVOLREG_SAVE \
277 stdu r1,-SCV_FRAME_SIZE(r1); \
278 cfi_adjust_cfa_offset(SCV_FRAME_SIZE); \
279 std r31,SCV_FRAME_NVOLREG_SAVE(r1); \
280 cfi_rel_offset(r31,SCV_FRAME_NVOLREG_SAVE);
282 /* Restore register and destroy frame */
283 #define NVOLREG_RESTORE \
284 ld r31,SCV_FRAME_NVOLREG_SAVE(r1); \
285 cfi_restore(r31); \
286 addi r1,r1,SCV_FRAME_SIZE; \
287 cfi_adjust_cfa_offset(-SCV_FRAME_SIZE);
289 /* Check PPC_FEATURE2_SCV bit from hwcap2 in the TCB. If it is not set, scv is
290 not available, then go to JUMPFALSE (label given by the macro's caller). We
291 save the value we read from the TCB in a non-volatile register so we can
292 reuse it later when exiting from the syscall in PSEUDO_RET. Note that for
293 the static case we need an extra check to guarantee the thread pointer has
294 already been initialized, otherwise we may try to access an invalid address
295 if a syscall is called before the TLS has been setup. */
296 .macro CHECK_SCV_SUPPORT REG JUMPFALSE
298 #ifndef SHARED
299 /* Check if thread pointer has already been setup. */
300 cmpdi r13,0
301 beq \JUMPFALSE
302 #endif
304 /* Read PPC_FEATURE2_SCV from TCB and store it in REG */
305 ld \REG,TCB_HWCAP(PT_THREAD_POINTER)
306 andis. \REG,\REG,PPC_FEATURE2_SCV>>16
308 beq \JUMPFALSE
309 .endm
311 #if !defined(USE_PPC_SCV) || IS_IN(rtld)
312 # define DO_CALL(syscall) \
313 li r0,syscall; \
314 DO_CALL_SC
315 #else
316 /* Before doing the syscall, check if we can use scv. scv is supported by P9
317 and later with Linux v5.9 and later. If so, use it. Otherwise, fallback to
318 sc. We use a non-volatile register to save hwcap2 from the TCB, so we need
319 to save its content beforehand. */
320 # define DO_CALL(syscall) \
321 li r0,syscall; \
322 NVOLREG_SAVE; \
323 CHECK_SCV_SUPPORT r31 0f; \
324 DO_CALL_SCV; \
325 b 1f; \
326 0: DO_CALL_SC; \
328 #endif /* !defined(USE_PPC_SCV) || IS_IN(rtld) */
330 /* DO_CALL_SC and DO_CALL_SCV expect the syscall number to be in r0. */
331 #define DO_CALL_SC \
334 #define DO_CALL_SCV \
335 mflr r9; \
336 std r9,SCV_FRAME_SIZE+FRAME_LR_SAVE(r1); \
337 cfi_rel_offset(lr,SCV_FRAME_SIZE+FRAME_LR_SAVE); \
338 .machine "push"; \
339 .machine "power9"; \
340 scv 0; \
341 .machine "pop"; \
342 ld r9,SCV_FRAME_SIZE+FRAME_LR_SAVE(r1); \
343 mtlr r9; \
344 cfi_restore(lr);
346 /* ppc64 is always PIC */
347 #undef JUMPTARGET
348 #define JUMPTARGET(name) FUNC_LABEL(name)
350 #define PSEUDO(name, syscall_name, args) \
351 .section ".text"; \
352 ENTRY (name); \
353 DO_CALL (SYS_ify (syscall_name))
355 #ifdef SHARED
356 #define TAIL_CALL_SYSCALL_ERROR \
357 b JUMPTARGET (NOTOC (__syscall_error))
358 #else
359 /* Static version might be linked into a large app with a toc exceeding
360 64k. We can't put a toc adjusting stub on a plain branch, so can't
361 tail call __syscall_error. */
362 #define TAIL_CALL_SYSCALL_ERROR \
363 .ifdef .Local_syscall_error; \
364 b .Local_syscall_error; \
365 .else; \
366 .Local_syscall_error: \
367 mflr 0; \
368 std 0,FRAME_LR_SAVE(1); \
369 stdu 1,-FRAME_MIN_SIZE(1); \
370 cfi_adjust_cfa_offset(FRAME_MIN_SIZE); \
371 cfi_offset(lr,FRAME_LR_SAVE); \
372 bl JUMPTARGET(__syscall_error); \
373 nop; \
374 ld 0,FRAME_MIN_SIZE+FRAME_LR_SAVE(1); \
375 addi 1,1,FRAME_MIN_SIZE; \
376 cfi_adjust_cfa_offset(-FRAME_MIN_SIZE); \
377 mtlr 0; \
378 cfi_restore(lr); \
379 blr; \
380 .endif
381 #endif
383 #if !defined(USE_PPC_SCV) || IS_IN(rtld)
384 # define PSEUDO_RET \
385 RET_SC; \
386 TAIL_CALL_SYSCALL_ERROR
387 #else
388 /* This should only be called after a DO_CALL. In such cases, r31 contains the
389 value of PPC_FEATURE2_SCV read from hwcap2 by CHECK_SCV_SUPPORT. If it is
390 set, we know we have entered the kernel using scv, so handle the return code
391 accordingly. */
392 # define PSEUDO_RET \
393 cmpdi cr5,r31,0; \
394 NVOLREG_RESTORE; \
395 beq cr5,0f; \
396 RET_SCV; \
397 b 1f; \
398 0: RET_SC; \
399 1: TAIL_CALL_SYSCALL_ERROR
400 #endif /* !defined(USE_PPC_SCV) || IS_IN(rtld) */
402 #define RET_SCV \
403 li r9,-4095; \
404 cmpld r3,r9; \
405 bltlr+; \
406 neg r3,r3;
408 #define RET_SC \
409 bnslr+;
411 #define ret PSEUDO_RET
413 #undef PSEUDO_END
414 #define PSEUDO_END(name) \
415 END (name)
417 #define PSEUDO_NOERRNO(name, syscall_name, args) \
418 .section ".text"; \
419 ENTRY (name); \
420 DO_CALL (SYS_ify (syscall_name))
422 #if !defined(USE_PPC_SCV) || IS_IN(rtld)
423 # define PSEUDO_RET_NOERRNO \
425 #else
426 /* This should only be called after a DO_CALL. */
427 # define PSEUDO_RET_NOERRNO \
428 NVOLREG_RESTORE; \
430 #endif /* !defined(USE_PPC_SCV) || IS_IN(rtld) */
432 #define ret_NOERRNO PSEUDO_RET_NOERRNO
434 #undef PSEUDO_END_NOERRNO
435 #define PSEUDO_END_NOERRNO(name) \
436 END (name)
438 #define PSEUDO_ERRVAL(name, syscall_name, args) \
439 .section ".text"; \
440 ENTRY (name); \
441 DO_CALL (SYS_ify (syscall_name))
443 #if !defined(USE_PPC_SCV) || IS_IN(rtld)
444 # define PSEUDO_RET_ERRVAL \
446 #else
447 /* This should only be called after a DO_CALL. */
448 # define PSEUDO_RET_ERRVAL \
449 NVOLREG_RESTORE; \
451 #endif /* !defined(USE_PPC_SCV) || IS_IN(rtld) */
453 #define ret_ERRVAL PSEUDO_RET_ERRVAL
455 #undef PSEUDO_END_ERRVAL
456 #define PSEUDO_END_ERRVAL(name) \
457 END (name)
459 #ifdef SHARED
460 # if IS_IN (rtld)
461 /* Inside ld.so we use the local alias to avoid runtime GOT
462 relocations. */
463 # define __GLRO_DEF(var) \
464 .LC__ ## var: \
465 .tc _rtld_local_ro[TC],_rtld_local_ro
466 # else
467 # define __GLRO_DEF(var) \
468 .LC__ ## var: \
469 .tc _rtld_global_ro[TC],_rtld_global_ro
470 # endif
471 # define __GLRO(rOUT, var, offset) \
472 addis rOUT,r2,.LC__ ## var@toc@ha; \
473 ld rOUT,.LC__ ## var@toc@l(rOUT); \
474 lwz rOUT,offset(rOUT)
475 #else
476 # define __GLRO_DEF(var) \
477 .LC__ ## var: \
478 .tc _ ## var[TC],_ ## var
479 # define __GLRO(rOUT, var, offset) \
480 addis rOUT,r2,.LC__ ## var@toc@ha; \
481 ld rOUT,.LC__ ## var@toc@l(rOUT); \
482 lwz rOUT,0(rOUT)
483 #endif
485 #ifdef USE_PPC64_NOTOC
486 # define NOTOC(l) l@notoc
487 #else
488 # define NOTOC(l) l
489 #endif
491 #else /* !__ASSEMBLER__ */
493 #if _CALL_ELF != 2
495 #define PPC64_LOAD_FUNCPTR(ptr) \
496 "ld 12,0(" #ptr ")\n" \
497 "ld 2,8(" #ptr ")\n" \
498 "mtctr 12\n" \
499 "ld 11,16(" #ptr ")"
501 #ifdef USE_PPC64_OVERLAPPING_OPD
502 # define OPD_ENT(name) ".quad " BODY_PREFIX #name ", .TOC.@tocbase"
503 #else
504 # define OPD_ENT(name) ".quad " BODY_PREFIX #name ", .TOC.@tocbase, 0"
505 #endif
507 #define ENTRY_1(name) \
508 ".type " BODY_PREFIX #name ",@function\n" \
509 ".globl " #name "\n" \
510 ".pushsection \".opd\",\"aw\"\n" \
511 ".p2align 3\n" \
512 #name ":\n" \
513 OPD_ENT (name) "\n" \
514 ".popsection"
516 #define DOT_PREFIX ""
517 #define BODY_PREFIX ".LY"
518 #define ENTRY_2(name) \
519 ".type " #name ",@function\n" \
520 ENTRY_1(name)
521 #define END_2(name) \
522 ".size " #name ",.-" BODY_PREFIX #name "\n" \
523 ".size " BODY_PREFIX #name ",.-" BODY_PREFIX #name
524 #define LOCALENTRY(name)
526 #else /* _CALL_ELF */
528 #define PPC64_LOAD_FUNCPTR(ptr) \
529 "mr 12," #ptr "\n" \
530 "mtctr 12"
532 #define DOT_PREFIX ""
533 #define BODY_PREFIX ""
534 #define ENTRY_2(name) \
535 ".type " #name ",@function\n" \
536 ".globl " #name
537 #define END_2(name) \
538 ".size " #name ",.-" #name
539 #define LOCALENTRY(name) \
540 "1: addis 2,12,.TOC.-1b@ha\n" \
541 "addi 2,2,.TOC.-1b@l\n" \
542 ".localentry " #name ",.-" #name
544 #endif /* _CALL_ELF */
546 #endif /* __ASSEMBLER__ */