Blame sysdeps/arm/sysdep.h

Packit 6c4009
/* Assembler macros for ARM.
Packit 6c4009
   Copyright (C) 1997-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/generic/sysdep.h>
Packit 6c4009
#include <features.h>
Packit 6c4009
Packit 6c4009
#ifndef __ASSEMBLER__
Packit 6c4009
# include <stdint.h>
Packit 6c4009
#else
Packit 6c4009
# include <arm-features.h>
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* The __ARM_ARCH define is provided by gcc 4.8.  Construct it otherwise.  */
Packit 6c4009
#ifndef __ARM_ARCH
Packit 6c4009
# ifdef __ARM_ARCH_2__
Packit 6c4009
#  define __ARM_ARCH 2
Packit 6c4009
# elif defined (__ARM_ARCH_3__) || defined (__ARM_ARCH_3M__)
Packit 6c4009
#  define __ARM_ARCH 3
Packit 6c4009
# elif defined (__ARM_ARCH_4__) || defined (__ARM_ARCH_4T__)
Packit 6c4009
#  define __ARM_ARCH 4
Packit 6c4009
# elif defined (__ARM_ARCH_5__) || defined (__ARM_ARCH_5E__) \
Packit 6c4009
       || defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_5TE__) \
Packit 6c4009
       || defined(__ARM_ARCH_5TEJ__)
Packit 6c4009
#  define __ARM_ARCH 5
Packit 6c4009
# elif defined (__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
Packit 6c4009
       || defined (__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) \
Packit 6c4009
       || defined (__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__)
Packit 6c4009
#  define __ARM_ARCH 6
Packit 6c4009
# elif defined (__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
Packit 6c4009
       || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
Packit 6c4009
       || defined(__ARM_ARCH_7EM__)
Packit 6c4009
#  define __ARM_ARCH 7
Packit 6c4009
# else
Packit 6c4009
#  error unknown arm architecture
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if __ARM_ARCH > 4 || defined (__ARM_ARCH_4T__)
Packit 6c4009
# define ARCH_HAS_BX
Packit 6c4009
#endif
Packit 6c4009
#if __ARM_ARCH > 4
Packit 6c4009
# define ARCH_HAS_BLX
Packit 6c4009
#endif
Packit 6c4009
#if __ARM_ARCH > 6 || defined (__ARM_ARCH_6K__) || defined (__ARM_ARCH_6ZK__)
Packit 6c4009
# define ARCH_HAS_HARD_TP
Packit 6c4009
#endif
Packit 6c4009
#if __ARM_ARCH > 6 || defined (__ARM_ARCH_6T2__)
Packit 6c4009
# define ARCH_HAS_T2
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef	__ASSEMBLER__
Packit 6c4009
Packit 6c4009
/* Syntactic details of assembler.  */
Packit 6c4009
Packit 6c4009
#define ALIGNARG(log2) log2
Packit 6c4009
#define ASM_SIZE_DIRECTIVE(name) .size name,.-name
Packit 6c4009
Packit 6c4009
#define PLTJMP(_x)	_x##(PLT)
Packit 6c4009
Packit 6c4009
#ifdef ARCH_HAS_BX
Packit 6c4009
# define BX(R)		bx	R
Packit 6c4009
# define BXC(C, R)	bx##C	R
Packit 6c4009
# ifdef ARCH_HAS_BLX
Packit 6c4009
#  define BLX(R)	blx	R
Packit 6c4009
# else
Packit 6c4009
#  define BLX(R)	mov	lr, pc; bx R
Packit 6c4009
# endif
Packit 6c4009
#else
Packit 6c4009
# define BX(R)		mov	pc, R
Packit 6c4009
# define BXC(C, R)	mov##C	pc, R
Packit 6c4009
# define BLX(R)		mov	lr, pc; mov pc, R
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define DO_RET(R)	BX(R)
Packit 6c4009
#define RETINSTR(C, R)	BXC(C, R)
Packit 6c4009
Packit 6c4009
/* Define an entry point visible from C.  */
Packit 6c4009
#define	ENTRY(name)					\
Packit 6c4009
	.globl	C_SYMBOL_NAME(name);			\
Packit 6c4009
	.type	C_SYMBOL_NAME(name),%function;		\
Packit 6c4009
	.align	ALIGNARG(4);				\
Packit 6c4009
  C_LABEL(name)						\
Packit 6c4009
	CFI_SECTIONS;					\
Packit 6c4009
	cfi_startproc;					\
Packit 6c4009
	CALL_MCOUNT
Packit 6c4009
Packit 6c4009
#define CFI_SECTIONS					\
Packit 6c4009
	.cfi_sections .debug_frame
Packit 6c4009
Packit 6c4009
#undef	END
Packit 6c4009
#define END(name)					\
Packit 6c4009
	cfi_endproc;					\
Packit 6c4009
	ASM_SIZE_DIRECTIVE(name)
Packit 6c4009
Packit 6c4009
/* If compiled for profiling, call `mcount' at the start of each function.  */
Packit 6c4009
#ifdef	PROF
Packit 6c4009
/* Call __gnu_mcount_nc (GCC >= 4.4).  */
Packit 6c4009
#define CALL_MCOUNT					\
Packit 6c4009
	push	{lr};					\
Packit 6c4009
	cfi_adjust_cfa_offset (4);			\
Packit 6c4009
	cfi_rel_offset (lr, 0);				\
Packit 6c4009
	bl	PLTJMP(mcount);				\
Packit 6c4009
	cfi_adjust_cfa_offset (-4);			\
Packit 6c4009
	cfi_restore (lr)
Packit 6c4009
#else
Packit 6c4009
#define CALL_MCOUNT		/* Do nothing.  */
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Since C identifiers are not normally prefixed with an underscore
Packit 6c4009
   on this system, the asm identifier `syscall_error' intrudes on the
Packit 6c4009
   C name space.  Make sure we use an innocuous name.  */
Packit 6c4009
#define	syscall_error	__syscall_error
Packit 6c4009
#define mcount		__gnu_mcount_nc
Packit 6c4009
Packit 6c4009
/* Tag_ABI_align8_preserved: This code preserves 8-byte
Packit 6c4009
   alignment in any callee.  */
Packit 6c4009
	.eabi_attribute 25, 1
Packit 6c4009
/* Tag_ABI_align8_needed: This code may require 8-byte alignment from
Packit 6c4009
   the caller.  */
Packit 6c4009
	.eabi_attribute 24, 1
Packit 6c4009
Packit 6c4009
/* The thumb2 encoding is reasonably complete.  Unless suppressed, use it.  */
Packit 6c4009
	.syntax unified
Packit 6c4009
# if defined(__thumb2__) && !defined(NO_THUMB)
Packit 6c4009
	.thumb
Packit 6c4009
#else
Packit 6c4009
#  undef __thumb__
Packit 6c4009
#  undef __thumb2__
Packit 6c4009
	.arm
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
/* Load or store to/from address X + Y into/from R, (maybe) using T.
Packit 6c4009
   X or Y can use T freely; T can be R if OP is a load.  The first
Packit 6c4009
   version eschews the two-register addressing mode, while the
Packit 6c4009
   second version uses it.  */
Packit 6c4009
# define LDST_INDEXED_NOINDEX(OP, R, T, X, Y)		\
Packit 6c4009
	add	T, X, Y;				\
Packit 6c4009
	OP	R, [T]
Packit 6c4009
# define LDST_INDEXED_INDEX(OP, R, X, Y)		\
Packit 6c4009
	OP	R, [X, Y]
Packit 6c4009
Packit 6c4009
# ifdef ARM_NO_INDEX_REGISTER
Packit 6c4009
/* We're never using the two-register addressing mode, so this
Packit 6c4009
   always uses an intermediate add.  */
Packit 6c4009
#  define LDST_INDEXED(OP, R, T, X, Y)	LDST_INDEXED_NOINDEX (OP, R, T, X, Y)
Packit 6c4009
#  define LDST_PC_INDEXED(OP, R, T, X)	LDST_INDEXED_NOINDEX (OP, R, T, pc, X)
Packit 6c4009
# else
Packit 6c4009
/* The two-register addressing mode is OK, except on Thumb with pc.  */
Packit 6c4009
#  define LDST_INDEXED(OP, R, T, X, Y)	LDST_INDEXED_INDEX (OP, R, X, Y)
Packit 6c4009
#  ifdef __thumb2__
Packit 6c4009
#   define LDST_PC_INDEXED(OP, R, T, X)	LDST_INDEXED_NOINDEX (OP, R, T, pc, X)
Packit 6c4009
#  else
Packit 6c4009
#   define LDST_PC_INDEXED(OP, R, T, X)	LDST_INDEXED_INDEX (OP, R, pc, X)
Packit 6c4009
#  endif
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
/* Load or store to/from a pc-relative EXPR into/from R, using T.  */
Packit 6c4009
# ifdef __thumb2__
Packit 6c4009
#  define LDST_PCREL(OP, R, T, EXPR) \
Packit 6c4009
	ldr	T, 98f;					\
Packit 6c4009
	.subsection 2;					\
Packit 6c4009
98:	.word	EXPR - 99f - PC_OFS;			\
Packit 6c4009
	.previous;					\
Packit 6c4009
99:	add	T, T, pc;				\
Packit 6c4009
	OP	R, [T]
Packit 6c4009
# elif defined (ARCH_HAS_T2) && ARM_PCREL_MOVW_OK
Packit 6c4009
#  define LDST_PCREL(OP, R, T, EXPR)			\
Packit 6c4009
	movw	T, #:lower16:EXPR - 99f - PC_OFS;	\
Packit 6c4009
	movt	T, #:upper16:EXPR - 99f - PC_OFS;	\
Packit 6c4009
99:	LDST_PC_INDEXED (OP, R, T, T)
Packit 6c4009
# else
Packit 6c4009
#  define LDST_PCREL(OP, R, T, EXPR) \
Packit 6c4009
	ldr	T, 98f;					\
Packit 6c4009
	.subsection 2;					\
Packit 6c4009
98:	.word	EXPR - 99f - PC_OFS;			\
Packit 6c4009
	.previous;					\
Packit 6c4009
99:	OP	R, [pc, T]
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
/* Load from a global SYMBOL + CONSTANT into R, using T.  */
Packit 6c4009
# if defined (ARCH_HAS_T2) && !defined (PIC)
Packit 6c4009
#  define LDR_GLOBAL(R, T, SYMBOL, CONSTANT)				\
Packit 6c4009
	movw	T, #:lower16:SYMBOL;					\
Packit 6c4009
	movt	T, #:upper16:SYMBOL;					\
Packit 6c4009
	ldr	R, [T, $CONSTANT]
Packit 6c4009
# elif defined (ARCH_HAS_T2) && defined (PIC) && ARM_PCREL_MOVW_OK
Packit 6c4009
#  define LDR_GLOBAL(R, T, SYMBOL, CONSTANT)				\
Packit 6c4009
	movw	R, #:lower16:_GLOBAL_OFFSET_TABLE_ - 97f - PC_OFS;	\
Packit 6c4009
	movw	T, #:lower16:99f - 98f - PC_OFS;			\
Packit 6c4009
	movt	R, #:upper16:_GLOBAL_OFFSET_TABLE_ - 97f - PC_OFS;	\
Packit 6c4009
	movt	T, #:upper16:99f - 98f - PC_OFS;			\
Packit 6c4009
	.pushsection .rodata.cst4, "aM", %progbits, 4;			\
Packit 6c4009
	.balign 4;							\
Packit 6c4009
99:	.word	SYMBOL##(GOT);						\
Packit 6c4009
	.popsection;							\
Packit 6c4009
97:	add	R, R, pc;						\
Packit 6c4009
98:	LDST_PC_INDEXED (ldr, T, T, T);					\
Packit 6c4009
	LDST_INDEXED (ldr, R, T, R, T);					\
Packit 6c4009
	ldr	R, [R, $CONSTANT]
Packit 6c4009
# else
Packit 6c4009
#  define LDR_GLOBAL(R, T, SYMBOL, CONSTANT)		\
Packit 6c4009
	ldr	T, 99f;					\
Packit 6c4009
	ldr	R, 100f;				\
Packit 6c4009
98:	add	T, T, pc;				\
Packit 6c4009
	ldr	T, [T, R];				\
Packit 6c4009
	.subsection 2;					\
Packit 6c4009
99:	.word	_GLOBAL_OFFSET_TABLE_ - 98b - PC_OFS;	\
Packit 6c4009
100:	.word	SYMBOL##(GOT);				\
Packit 6c4009
	.previous;					\
Packit 6c4009
	ldr	R, [T, $CONSTANT]
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
/* This is the same as LDR_GLOBAL, but for a SYMBOL that is known to
Packit 6c4009
   be in the same linked object (as for one with hidden visibility).
Packit 6c4009
   We can avoid the GOT indirection in the PIC case.  For the pure
Packit 6c4009
   static case, LDR_GLOBAL is already optimal.  */
Packit 6c4009
# ifdef PIC
Packit 6c4009
#  define LDR_HIDDEN(R, T, SYMBOL, CONSTANT) \
Packit 6c4009
  LDST_PCREL (ldr, R, T, SYMBOL + CONSTANT)
Packit 6c4009
# else
Packit 6c4009
#  define LDR_HIDDEN(R, T, SYMBOL, CONSTANT) \
Packit 6c4009
  LDR_GLOBAL (R, T, SYMBOL, CONSTANT)
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
/* Cope with negative memory offsets, which thumb can't encode.
Packit 6c4009
   Use NEGOFF_ADJ_BASE to (conditionally) alter the base register,
Packit 6c4009
   and then NEGOFF_OFF1 to use 0 for thumb and the offset for arm,
Packit 6c4009
   or NEGOFF_OFF2 to use A-B for thumb and A for arm.  */
Packit 6c4009
# ifdef __thumb2__
Packit 6c4009
#  define NEGOFF_ADJ_BASE(R, OFF)	add R, R, $OFF
Packit 6c4009
#  define NEGOFF_ADJ_BASE2(D, S, OFF)	add D, S, $OFF
Packit 6c4009
#  define NEGOFF_OFF1(R, OFF)		[R]
Packit 6c4009
#  define NEGOFF_OFF2(R, OFFA, OFFB)	[R, $((OFFA) - (OFFB))]
Packit 6c4009
# else
Packit 6c4009
#  define NEGOFF_ADJ_BASE(R, OFF)
Packit 6c4009
#  define NEGOFF_ADJ_BASE2(D, S, OFF)	mov D, S
Packit 6c4009
#  define NEGOFF_OFF1(R, OFF)		[R, $OFF]
Packit 6c4009
#  define NEGOFF_OFF2(R, OFFA, OFFB)	[R, $OFFA]
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
/* Helper to get the TLS base pointer.  The interface is that TMP is a
Packit 6c4009
   register that may be used to hold the LR, if necessary.  TMP may be
Packit 6c4009
   LR itself to indicate that LR need not be saved.  The base pointer
Packit 6c4009
   is returned in R0.  Only R0 and TMP are modified.  */
Packit 6c4009
Packit 6c4009
# ifdef ARCH_HAS_HARD_TP
Packit 6c4009
/* If the cpu has cp15 available, use it.  */
Packit 6c4009
#  define GET_TLS(TMP)		mrc p15, 0, r0, c13, c0, 3
Packit 6c4009
# else
Packit 6c4009
/* At this generic level we have no tricks to pull.  Call the ABI routine.  */
Packit 6c4009
#  define GET_TLS(TMP)					\
Packit 6c4009
	push	{ r1, r2, r3, lr };			\
Packit 6c4009
	cfi_remember_state;				\
Packit 6c4009
	cfi_adjust_cfa_offset (16);			\
Packit 6c4009
	cfi_rel_offset (r1, 0);				\
Packit 6c4009
	cfi_rel_offset (r2, 4);				\
Packit 6c4009
	cfi_rel_offset (r3, 8);				\
Packit 6c4009
	cfi_rel_offset (lr, 12);			\
Packit 6c4009
	bl	__aeabi_read_tp;			\
Packit 6c4009
	pop	{ r1, r2, r3, lr };			\
Packit 6c4009
	cfi_restore_state
Packit 6c4009
# endif /* ARCH_HAS_HARD_TP */
Packit 6c4009
Packit 6c4009
/* These are the directives used for EABI unwind info.
Packit 6c4009
   Wrap them in macros so another configuration's sysdep.h
Packit 6c4009
   file can define them away if it doesn't use EABI unwind info.  */
Packit 6c4009
# define eabi_fnstart		.fnstart
Packit 6c4009
# define eabi_fnend		.fnend
Packit 6c4009
# define eabi_save(...)		.save __VA_ARGS__
Packit 6c4009
# define eabi_cantunwind	.cantunwind
Packit 6c4009
# define eabi_pad(n)		.pad n
Packit 6c4009
Packit 6c4009
#endif	/* __ASSEMBLER__ */
Packit 6c4009
Packit 6c4009
/* This number is the offset from the pc at the current location.  */
Packit 6c4009
#ifdef __thumb__
Packit 6c4009
# define PC_OFS  4
Packit 6c4009
#else
Packit 6c4009
# define PC_OFS  8
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Pointer mangling support.  */
Packit 6c4009
#if (IS_IN (rtld) || \
Packit 6c4009
     (!defined SHARED && (IS_IN (libc) || IS_IN (libpthread))))
Packit 6c4009
# ifdef __ASSEMBLER__
Packit 6c4009
#  define PTR_MANGLE_LOAD(guard, tmp)					\
Packit 6c4009
  LDR_HIDDEN (guard, tmp, C_SYMBOL_NAME(__pointer_chk_guard_local), 0)
Packit 6c4009
#  define PTR_MANGLE(dst, src, guard, tmp)				\
Packit 6c4009
  PTR_MANGLE_LOAD(guard, tmp);						\
Packit 6c4009
  PTR_MANGLE2(dst, src, guard)
Packit 6c4009
/* Use PTR_MANGLE2 for efficiency if guard is already loaded.  */
Packit 6c4009
#  define PTR_MANGLE2(dst, src, guard)		\
Packit 6c4009
  eor dst, src, guard
Packit 6c4009
#  define PTR_DEMANGLE(dst, src, guard, tmp)	\
Packit 6c4009
  PTR_MANGLE (dst, src, guard, tmp)
Packit 6c4009
#  define PTR_DEMANGLE2(dst, src, guard)	\
Packit 6c4009
  PTR_MANGLE2 (dst, src, guard)
Packit 6c4009
# else
Packit 6c4009
extern uintptr_t __pointer_chk_guard_local attribute_relro attribute_hidden;
Packit 6c4009
#  define PTR_MANGLE(var) \
Packit 6c4009
  (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard_local)
Packit 6c4009
#  define PTR_DEMANGLE(var)     PTR_MANGLE (var)
Packit 6c4009
# endif
Packit 6c4009
#else
Packit 6c4009
# ifdef __ASSEMBLER__
Packit 6c4009
#  define PTR_MANGLE_LOAD(guard, tmp)					\
Packit 6c4009
  LDR_GLOBAL (guard, tmp, C_SYMBOL_NAME(__pointer_chk_guard), 0);
Packit 6c4009
#  define PTR_MANGLE(dst, src, guard, tmp)				\
Packit 6c4009
  PTR_MANGLE_LOAD(guard, tmp);						\
Packit 6c4009
  PTR_MANGLE2(dst, src, guard)
Packit 6c4009
/* Use PTR_MANGLE2 for efficiency if guard is already loaded.  */
Packit 6c4009
#  define PTR_MANGLE2(dst, src, guard)		\
Packit 6c4009
  eor dst, src, guard
Packit 6c4009
#  define PTR_DEMANGLE(dst, src, guard, tmp)	\
Packit 6c4009
  PTR_MANGLE (dst, src, guard, tmp)
Packit 6c4009
#  define PTR_DEMANGLE2(dst, src, guard)	\
Packit 6c4009
  PTR_MANGLE2 (dst, src, guard)
Packit 6c4009
# else
Packit 6c4009
extern uintptr_t __pointer_chk_guard attribute_relro;
Packit 6c4009
#  define PTR_MANGLE(var) \
Packit 6c4009
  (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard)
Packit 6c4009
#  define PTR_DEMANGLE(var)     PTR_MANGLE (var)
Packit 6c4009
# endif
Packit 6c4009
#endif