Blame sysdeps/powerpc/powerpc64/sysdep.h

Packit 6c4009
/* Assembly macros for 64-bit PowerPC.
Packit 6c4009
   Copyright (C) 2002-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <sysdeps/powerpc/sysdep.h>
Packit 6c4009
Packit 6c4009
#ifdef __ASSEMBLER__
Packit 6c4009
Packit 6c4009
/* Stack frame offsets.  */
Packit 6c4009
#define FRAME_BACKCHAIN		0
Packit 6c4009
#define FRAME_CR_SAVE		8
Packit 6c4009
#define FRAME_LR_SAVE		16
Packit 6c4009
#if _CALL_ELF != 2
Packit 6c4009
#define FRAME_MIN_SIZE		112
Packit 6c4009
#define FRAME_MIN_SIZE_PARM	112
Packit 6c4009
#define FRAME_TOC_SAVE		40
Packit 6c4009
#define FRAME_PARM_SAVE		48
Packit 6c4009
#else
Packit 6c4009
#define FRAME_MIN_SIZE		32
Packit 6c4009
#define FRAME_MIN_SIZE_PARM	96
Packit 6c4009
#define FRAME_TOC_SAVE		24
Packit 6c4009
#define FRAME_PARM_SAVE		32
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Support macros for CALL_MCOUNT.  */
Packit 6c4009
	.macro SAVE_ARG NARG
Packit 6c4009
	.if \NARG
Packit 6c4009
	SAVE_ARG \NARG-1
Packit 6c4009
	std	2+\NARG,-FRAME_MIN_SIZE_PARM+FRAME_PARM_SAVE-8+8*(\NARG)(1)
Packit 6c4009
	.endif
Packit 6c4009
	.endm
Packit 6c4009
Packit 6c4009
	.macro REST_ARG NARG
Packit 6c4009
	.if \NARG
Packit 6c4009
	REST_ARG \NARG-1
Packit 6c4009
	ld	2+\NARG,FRAME_PARM_SAVE-8+8*(\NARG)(1)
Packit 6c4009
	.endif
Packit 6c4009
	.endm
Packit 6c4009
Packit 6c4009
	.macro CFI_SAVE_ARG NARG
Packit 6c4009
	.if \NARG
Packit 6c4009
	CFI_SAVE_ARG \NARG-1
Packit 6c4009
	cfi_offset(2+\NARG,-FRAME_MIN_SIZE_PARM+FRAME_PARM_SAVE-8+8*(\NARG))
Packit 6c4009
	.endif
Packit 6c4009
	.endm
Packit 6c4009
Packit 6c4009
	.macro CFI_REST_ARG NARG
Packit 6c4009
	.if \NARG
Packit 6c4009
	CFI_REST_ARG \NARG-1
Packit 6c4009
	cfi_restore(2+\NARG)
Packit 6c4009
	.endif
Packit 6c4009
	.endm
Packit 6c4009
Packit 6c4009
/* If compiled for profiling, call `_mcount' at the start of each function.
Packit 6c4009
   see ppc-mcount.S for more details.  */
Packit 6c4009
	.macro CALL_MCOUNT NARG
Packit 6c4009
#ifdef	PROF
Packit 6c4009
	mflr	r0
Packit 6c4009
	SAVE_ARG \NARG
Packit 6c4009
	std	r0,FRAME_LR_SAVE(r1)
Packit 6c4009
	stdu	r1,-FRAME_MIN_SIZE_PARM(r1)
Packit 6c4009
	cfi_adjust_cfa_offset(FRAME_MIN_SIZE_PARM)
Packit 6c4009
	cfi_offset(lr,FRAME_LR_SAVE)
Packit 6c4009
	CFI_SAVE_ARG \NARG
Packit 6c4009
	bl	JUMPTARGET (_mcount)
Packit 6c4009
#ifndef SHARED
Packit 6c4009
	nop
Packit 6c4009
#endif
Packit 6c4009
	ld	r0,FRAME_MIN_SIZE_PARM+FRAME_LR_SAVE(r1)
Packit 6c4009
	REST_ARG \NARG
Packit 6c4009
	mtlr	r0
Packit 6c4009
	addi	r1,r1,FRAME_MIN_SIZE_PARM
Packit 6c4009
	cfi_adjust_cfa_offset(-FRAME_MIN_SIZE_PARM)
Packit 6c4009
	cfi_restore(lr)
Packit 6c4009
	CFI_REST_ARG \NARG
Packit 6c4009
#endif
Packit 6c4009
	.endm
Packit 6c4009
Packit 6c4009
#if _CALL_ELF != 2
Packit 6c4009
Packit 6c4009
/* Macro to prepare for calling via a function pointer.  */
Packit 6c4009
	.macro PPC64_LOAD_FUNCPTR PTR
Packit 6c4009
	ld      r12,0(\PTR)
Packit 6c4009
	ld      r2,8(\PTR)
Packit 6c4009
	mtctr   r12
Packit 6c4009
	ld      r11,16(\PTR)
Packit 6c4009
	.endm
Packit 6c4009
Packit 6c4009
#ifdef USE_PPC64_OVERLAPPING_OPD
Packit 6c4009
# define OPD_ENT(name)	.quad BODY_LABEL (name), .TOC.@tocbase
Packit 6c4009
#else
Packit 6c4009
# define OPD_ENT(name)	.quad BODY_LABEL (name), .TOC.@tocbase, 0
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define ENTRY_1(name)				\
Packit 6c4009
	.type BODY_LABEL(name),@function;	\
Packit 6c4009
	.globl name;				\
Packit 6c4009
	.section ".opd","aw";			\
Packit 6c4009
	.p2align 3;FUNC_LABEL(name):		\
Packit 6c4009
	OPD_ENT (name);				\
Packit 6c4009
	.previous
Packit 6c4009
Packit 6c4009
#define FUNC_LABEL(X) X
Packit 6c4009
#define BODY_LABEL(X) .LY##X
Packit 6c4009
#define ENTRY_2(name)				\
Packit 6c4009
	.type name,@function;			\
Packit 6c4009
	ENTRY_1(name)
Packit 6c4009
#define END_2(name)				\
Packit 6c4009
	.size name,.-BODY_LABEL(name);		\
Packit 6c4009
	.size BODY_LABEL(name),.-BODY_LABEL(name)
Packit 6c4009
#define LOCALENTRY(name)
Packit 6c4009
Packit 6c4009
#else /* _CALL_ELF == 2 */
Packit 6c4009
Packit 6c4009
/* Macro to prepare for calling via a function pointer.  */
Packit 6c4009
	.macro PPC64_LOAD_FUNCPTR PTR
Packit 6c4009
	mr	r12,\PTR
Packit 6c4009
	mtctr   r12
Packit 6c4009
	.endm
Packit 6c4009
Packit 6c4009
#define FUNC_LABEL(X) X
Packit 6c4009
#define BODY_LABEL(X) X
Packit 6c4009
#define ENTRY_2(name)				\
Packit 6c4009
	.globl name;				\
Packit 6c4009
	.type name,@function
Packit 6c4009
#define END_2(name)				\
Packit 6c4009
	.size name,.-name
Packit 6c4009
#define LOCALENTRY(name)			\
Packit 6c4009
1:      addis	r2,r12,.TOC.-1b@ha;		\
Packit 6c4009
        addi	r2,r2,.TOC.-1b@l;		\
Packit 6c4009
	.localentry name,.-name
Packit 6c4009
Packit 6c4009
#endif /* _CALL_ELF */
Packit 6c4009
Packit 6c4009
	.macro NOPS NARG
Packit 6c4009
	.if \NARG
Packit 6c4009
	NOPS \NARG-1
Packit 6c4009
	nop
Packit 6c4009
	.endif
Packit 6c4009
	.endm
Packit 6c4009
Packit 6c4009
	.macro ENTRY_3 name, alignp2=2, nopwords=0
Packit 6c4009
	.text
Packit 6c4009
	ENTRY_2(\name)
Packit 6c4009
	.p2align \alignp2
Packit 6c4009
	NOPS \nopwords
Packit 6c4009
BODY_LABEL(\name):
Packit 6c4009
	.endm
Packit 6c4009
Packit 6c4009
/* Use ENTRY_TOCLESS for functions that make no use of r2 and
Packit 6c4009
   guarantee r2 is unchanged on exit.  Any function that has @toc or
Packit 6c4009
   @got relocs uses r2.  Functions that call other functions via the
Packit 6c4009
   PLT use r2.  Use ENTRY for functions that may use or change r2.
Packit 6c4009
   The first argument is the function name.
Packit 6c4009
   The optional second argument specifies alignment of the function's
Packit 6c4009
   code, as the logarithm base two of the byte alignment.  For
Packit 6c4009
   example, a value of four aligns to a sixteen byte boundary.
Packit 6c4009
   The optional third argument specifies the number of NOPs to emit
Packit 6c4009
   before the start of the function's code.   */
Packit 6c4009
#ifndef PROF
Packit 6c4009
#define ENTRY_TOCLESS(name, ...)		\
Packit 6c4009
	ENTRY_3 name, ## __VA_ARGS__;		\
Packit 6c4009
	cfi_startproc
Packit 6c4009
Packit 6c4009
#define ENTRY(name, ...)			\
Packit 6c4009
	ENTRY_TOCLESS(name, ## __VA_ARGS__);	\
Packit 6c4009
	LOCALENTRY(name)
Packit 6c4009
#else
Packit 6c4009
/* The call to _mcount is potentially via the plt, so profiling code
Packit 6c4009
   is never free of an r2 use.  */
Packit 6c4009
#define ENTRY_TOCLESS(name, ...)		\
Packit 6c4009
	ENTRY_3 name, ## __VA_ARGS__;		\
Packit 6c4009
	cfi_startproc;				\
Packit 6c4009
	LOCALENTRY(name)
Packit 6c4009
Packit 6c4009
#define ENTRY(name, ...)			\
Packit 6c4009
	ENTRY_TOCLESS(name, ## __VA_ARGS__)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Local labels stripped out by the linker.  */
Packit 6c4009
#undef L
Packit 6c4009
#define L(x) .L##x
Packit 6c4009
Packit 6c4009
#define tostring(s) #s
Packit 6c4009
#define stringify(s) tostring(s)
Packit 6c4009
#define XGLUE(a,b) a##b
Packit 6c4009
#define GLUE(a,b) XGLUE(a,b)
Packit 6c4009
#define LT_LABEL(name) GLUE(.LT,name)
Packit 6c4009
#define LT_LABELSUFFIX(name,suffix) GLUE(GLUE(.LT,name),suffix)
Packit 6c4009
Packit 6c4009
/* Support Traceback tables */
Packit 6c4009
#define TB_ASM			0x000c000000000000
Packit 6c4009
#define TB_GLOBALLINK		0x0000800000000000
Packit 6c4009
#define TB_IS_EPROL		0x0000400000000000
Packit 6c4009
#define TB_HAS_TBOFF		0x0000200000000000
Packit 6c4009
#define TB_INT_PROC		0x0000100000000000
Packit 6c4009
#define TB_HAS_CTL		0x0000080000000000
Packit 6c4009
#define TB_TOCLESS		0x0000040000000000
Packit 6c4009
#define TB_FP_PRESENT		0x0000020000000000
Packit 6c4009
#define TB_LOG_ABORT		0x0000010000000000
Packit 6c4009
#define TB_INT_HANDL		0x0000008000000000
Packit 6c4009
#define TB_NAME_PRESENT		0x0000004000000000
Packit 6c4009
#define TB_USES_ALLOCA		0x0000002000000000
Packit 6c4009
#define TB_SAVES_CR		0x0000000200000000
Packit 6c4009
#define TB_SAVES_LR		0x0000000100000000
Packit 6c4009
#define TB_STORES_BC		0x0000000080000000
Packit 6c4009
#define TB_FIXUP		0x0000000040000000
Packit 6c4009
#define TB_FP_SAVED(fprs)	(((fprs) & 0x3f) << 24)
Packit 6c4009
#define TB_GPR_SAVED(gprs)	(((fprs) & 0x3f) << 16)
Packit 6c4009
#define TB_FIXEDPARMS(parms)	(((parms) & 0xff) << 8)
Packit 6c4009
#define TB_FLOATPARMS(parms)	(((parms) & 0x7f) << 1)
Packit 6c4009
#define TB_PARMSONSTK		0x0000000000000001
Packit 6c4009
Packit 6c4009
#define PPC_HIGHER(v) 		(((v) >> 32) & 0xffff)
Packit 6c4009
#define TB_DEFAULT		TB_ASM | TB_HAS_TBOFF | TB_NAME_PRESENT
Packit 6c4009
Packit 6c4009
#define TRACEBACK(name) \
Packit 6c4009
LT_LABEL(name): ; \
Packit 6c4009
	.long	0 ; \
Packit 6c4009
	.quad	TB_DEFAULT ; \
Packit 6c4009
	.long	LT_LABEL(name)-BODY_LABEL(name) ; \
Packit 6c4009
	.short	LT_LABELSUFFIX(name,_name_end)-LT_LABELSUFFIX(name,_name_start) ; \
Packit 6c4009
LT_LABELSUFFIX(name,_name_start): ;\
Packit 6c4009
	.ascii	stringify(name) ; \
Packit 6c4009
LT_LABELSUFFIX(name,_name_end): ; \
Packit 6c4009
	.p2align 2
Packit 6c4009
Packit 6c4009
#define TRACEBACK_MASK(name,mask) \
Packit 6c4009
LT_LABEL(name): ; \
Packit 6c4009
	.long	0 ; \
Packit 6c4009
	.quad	TB_DEFAULT | mask ; \
Packit 6c4009
	.long	LT_LABEL(name)-BODY_LABEL(name) ; \
Packit 6c4009
	.short	LT_LABELSUFFIX(name,_name_end)-LT_LABELSUFFIX(name,_name_start) ; \
Packit 6c4009
LT_LABELSUFFIX(name,_name_start): ;\
Packit 6c4009
	.ascii	stringify(name) ; \
Packit 6c4009
LT_LABELSUFFIX(name,_name_end): ; \
Packit 6c4009
	.p2align 2
Packit 6c4009
Packit 6c4009
/* END generates Traceback tables */
Packit 6c4009
#undef	END
Packit 6c4009
#define END(name) \
Packit 6c4009
  cfi_endproc;			\
Packit 6c4009
  TRACEBACK(name);		\
Packit 6c4009
  END_2(name)
Packit 6c4009
Packit 6c4009
/* This form supports more informative traceback tables */
Packit 6c4009
#define END_GEN_TB(name,mask)	\
Packit 6c4009
  cfi_endproc;			\
Packit 6c4009
  TRACEBACK_MASK(name,mask);	\
Packit 6c4009
  END_2(name)
Packit 6c4009
Packit 6c4009
#define DO_CALL(syscall) \
Packit 6c4009
    li 0,syscall; \
Packit 6c4009
    sc
Packit 6c4009
Packit 6c4009
/* ppc64 is always PIC */
Packit 6c4009
#undef JUMPTARGET
Packit 6c4009
#define JUMPTARGET(name) FUNC_LABEL(name)
Packit 6c4009
Packit 6c4009
#define PSEUDO(name, syscall_name, args) \
Packit 6c4009
  .section ".text";				\
Packit 6c4009
  ENTRY (name);					\
Packit 6c4009
  DO_CALL (SYS_ify (syscall_name))
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
#define TAIL_CALL_SYSCALL_ERROR \
Packit 6c4009
    b JUMPTARGET(__syscall_error)
Packit 6c4009
#else
Packit 6c4009
/* Static version might be linked into a large app with a toc exceeding
Packit 6c4009
   64k.  We can't put a toc adjusting stub on a plain branch, so can't
Packit 6c4009
   tail call __syscall_error.  */
Packit 6c4009
#define TAIL_CALL_SYSCALL_ERROR \
Packit 6c4009
    .ifdef .Local_syscall_error; \
Packit 6c4009
    b .Local_syscall_error; \
Packit 6c4009
    .else; \
Packit 6c4009
.Local_syscall_error: \
Packit 6c4009
    mflr 0; \
Packit 6c4009
    std 0,FRAME_LR_SAVE(1); \
Packit 6c4009
    stdu 1,-FRAME_MIN_SIZE(1); \
Packit 6c4009
    cfi_adjust_cfa_offset(FRAME_MIN_SIZE); \
Packit 6c4009
    cfi_offset(lr,FRAME_LR_SAVE); \
Packit 6c4009
    bl JUMPTARGET(__syscall_error); \
Packit 6c4009
    nop; \
Packit 6c4009
    ld 0,FRAME_MIN_SIZE+FRAME_LR_SAVE(1); \
Packit 6c4009
    addi 1,1,FRAME_MIN_SIZE; \
Packit 6c4009
    cfi_adjust_cfa_offset(-FRAME_MIN_SIZE); \
Packit 6c4009
    mtlr 0; \
Packit 6c4009
    cfi_restore(lr); \
Packit 6c4009
    blr; \
Packit 6c4009
    .endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define PSEUDO_RET \
Packit 6c4009
    bnslr+; \
Packit 6c4009
    TAIL_CALL_SYSCALL_ERROR
Packit 6c4009
Packit 6c4009
#define ret PSEUDO_RET
Packit 6c4009
Packit 6c4009
#undef	PSEUDO_END
Packit 6c4009
#define	PSEUDO_END(name) \
Packit 6c4009
  END (name)
Packit 6c4009
Packit 6c4009
#define PSEUDO_NOERRNO(name, syscall_name, args) \
Packit 6c4009
  .section ".text";					\
Packit 6c4009
  ENTRY (name);						\
Packit 6c4009
  DO_CALL (SYS_ify (syscall_name))
Packit 6c4009
Packit 6c4009
#define PSEUDO_RET_NOERRNO \
Packit 6c4009
    blr
Packit 6c4009
Packit 6c4009
#define ret_NOERRNO PSEUDO_RET_NOERRNO
Packit 6c4009
Packit 6c4009
#undef	PSEUDO_END_NOERRNO
Packit 6c4009
#define	PSEUDO_END_NOERRNO(name) \
Packit 6c4009
  END (name)
Packit 6c4009
Packit 6c4009
#define PSEUDO_ERRVAL(name, syscall_name, args) \
Packit 6c4009
  .section ".text";					\
Packit 6c4009
  ENTRY (name);						\
Packit 6c4009
  DO_CALL (SYS_ify (syscall_name))
Packit 6c4009
Packit 6c4009
#define PSEUDO_RET_ERRVAL \
Packit 6c4009
    blr
Packit 6c4009
Packit 6c4009
#define ret_ERRVAL PSEUDO_RET_ERRVAL
Packit 6c4009
Packit 6c4009
#undef	PSEUDO_END_ERRVAL
Packit 6c4009
#define	PSEUDO_END_ERRVAL(name) \
Packit 6c4009
  END (name)
Packit 6c4009
Packit 6c4009
#else /* !__ASSEMBLER__ */
Packit 6c4009
Packit 6c4009
#if _CALL_ELF != 2
Packit 6c4009
Packit 6c4009
#define PPC64_LOAD_FUNCPTR(ptr) \
Packit 6c4009
	"ld 	12,0(" #ptr ")\n"					\
Packit 6c4009
	"ld	2,8(" #ptr ")\n"					\
Packit 6c4009
	"mtctr	12\n"							\
Packit 6c4009
	"ld	11,16(" #ptr ")"
Packit 6c4009
Packit 6c4009
#ifdef USE_PPC64_OVERLAPPING_OPD
Packit 6c4009
# define OPD_ENT(name)	".quad " BODY_PREFIX #name ", .TOC.@tocbase"
Packit 6c4009
#else
Packit 6c4009
# define OPD_ENT(name)	".quad " BODY_PREFIX #name ", .TOC.@tocbase, 0"
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define ENTRY_1(name)	\
Packit 6c4009
	".type   " BODY_PREFIX #name ",@function\n"			\
Packit 6c4009
	".globl " #name "\n"						\
Packit 6c4009
	".pushsection \".opd\",\"aw\"\n"				\
Packit 6c4009
	".p2align 3\n"							\
Packit 6c4009
#name ":\n"								\
Packit 6c4009
	OPD_ENT (name) "\n"						\
Packit 6c4009
	".popsection"
Packit 6c4009
Packit 6c4009
#define DOT_PREFIX ""
Packit 6c4009
#define BODY_PREFIX ".LY"
Packit 6c4009
#define ENTRY_2(name)	\
Packit 6c4009
	".type " #name ",@function\n"					\
Packit 6c4009
	ENTRY_1(name)
Packit 6c4009
#define END_2(name)	\
Packit 6c4009
	".size " #name ",.-" BODY_PREFIX #name "\n"			\
Packit 6c4009
	".size " BODY_PREFIX #name ",.-" BODY_PREFIX #name
Packit 6c4009
#define LOCALENTRY(name)
Packit 6c4009
Packit 6c4009
#else /* _CALL_ELF */
Packit 6c4009
Packit 6c4009
#define PPC64_LOAD_FUNCPTR(ptr) \
Packit 6c4009
	"mr	12," #ptr "\n"						\
Packit 6c4009
	"mtctr 	12"
Packit 6c4009
Packit 6c4009
#define DOT_PREFIX ""
Packit 6c4009
#define BODY_PREFIX ""
Packit 6c4009
#define ENTRY_2(name)	\
Packit 6c4009
	".type " #name ",@function\n"					\
Packit 6c4009
	".globl " #name
Packit 6c4009
#define END_2(name)	\
Packit 6c4009
	".size " #name ",.-" #name
Packit 6c4009
#define LOCALENTRY(name)	\
Packit 6c4009
	"1: addis 2,12,.TOC.-1b@ha\n"					\
Packit 6c4009
	"addi	2,2,.TOC.-1b@l\n"					\
Packit 6c4009
	".localentry " #name ",.-" #name
Packit 6c4009
Packit 6c4009
#endif /* _CALL_ELF */
Packit 6c4009
Packit 6c4009
#endif	/* __ASSEMBLER__ */