1  /* Assembler macros for ARM.
       2     Copyright (C) 1997-2023 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     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <sysdeps/generic/sysdep.h>
      20  #include <features.h>
      21  
      22  #ifndef __ASSEMBLER__
      23  # include <stdint.h>
      24  #else
      25  # include <arm-features.h>
      26  #endif
      27  
      28  /* The __ARM_ARCH define is provided by gcc 4.8.  Construct it otherwise.  */
      29  #ifndef __ARM_ARCH
      30  # ifdef __ARM_ARCH_2__
      31  #  define __ARM_ARCH 2
      32  # elif defined (__ARM_ARCH_3__) || defined (__ARM_ARCH_3M__)
      33  #  define __ARM_ARCH 3
      34  # elif defined (__ARM_ARCH_4__) || defined (__ARM_ARCH_4T__)
      35  #  define __ARM_ARCH 4
      36  # elif defined (__ARM_ARCH_5__) || defined (__ARM_ARCH_5E__) \
      37         || defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_5TE__) \
      38         || defined(__ARM_ARCH_5TEJ__)
      39  #  define __ARM_ARCH 5
      40  # elif defined (__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
      41         || defined (__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) \
      42         || defined (__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__)
      43  #  define __ARM_ARCH 6
      44  # elif defined (__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
      45         || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
      46         || defined(__ARM_ARCH_7EM__)
      47  #  define __ARM_ARCH 7
      48  # else
      49  #  error unknown arm architecture
      50  # endif
      51  #endif
      52  
      53  #if __ARM_ARCH > 4 || defined (__ARM_ARCH_4T__)
      54  # define ARCH_HAS_BX
      55  #endif
      56  #if __ARM_ARCH > 4
      57  # define ARCH_HAS_BLX
      58  #endif
      59  #if __ARM_ARCH > 6 || defined (__ARM_ARCH_6K__) || defined (__ARM_ARCH_6ZK__)
      60  # define ARCH_HAS_HARD_TP
      61  #endif
      62  #if __ARM_ARCH > 6 || defined (__ARM_ARCH_6T2__)
      63  # define ARCH_HAS_T2
      64  #endif
      65  
      66  #ifdef	__ASSEMBLER__
      67  
      68  /* Syntactic details of assembler.  */
      69  
      70  #define ALIGNARG(log2) log2
      71  #define ASM_SIZE_DIRECTIVE(name) .size name,.-name
      72  
      73  #define PLTJMP(_x)	_x##(PLT)
      74  
      75  #ifdef ARCH_HAS_BX
      76  # define BX(R)		bx	R
      77  # define BXC(C, R)	bx##C	R
      78  # ifdef ARCH_HAS_BLX
      79  #  define BLX(R)	blx	R
      80  # else
      81  #  define BLX(R)	mov	lr, pc; bx R
      82  # endif
      83  #else
      84  # define BX(R)		mov	pc, R
      85  # define BXC(C, R)	mov##C	pc, R
      86  # define BLX(R)		mov	lr, pc; mov pc, R
      87  #endif
      88  
      89  #define DO_RET(R)	BX(R)
      90  #define RETINSTR(C, R)	BXC(C, R)
      91  
      92  /* Define an entry point visible from C.  */
      93  #define	ENTRY(name)					\
      94  	.globl	C_SYMBOL_NAME(name);			\
      95  	.type	C_SYMBOL_NAME(name),%function;		\
      96  	.align	ALIGNARG(4);				\
      97    C_LABEL(name)						\
      98  	CFI_SECTIONS;					\
      99  	cfi_startproc;					\
     100  	CALL_MCOUNT
     101  
     102  #define CFI_SECTIONS					\
     103  	.cfi_sections .debug_frame
     104  
     105  #undef	END
     106  #define END(name)					\
     107  	cfi_endproc;					\
     108  	ASM_SIZE_DIRECTIVE(name)
     109  
     110  /* If compiled for profiling, call `mcount' at the start of each function.  */
     111  #ifdef	PROF
     112  /* Call __gnu_mcount_nc (GCC >= 4.4).  */
     113  #define CALL_MCOUNT					\
     114  	push	{lr};					\
     115  	cfi_adjust_cfa_offset (4);			\
     116  	cfi_rel_offset (lr, 0);				\
     117  	bl	PLTJMP(mcount);				\
     118  	cfi_adjust_cfa_offset (-4);			\
     119  	cfi_restore (lr)
     120  #else
     121  #define CALL_MCOUNT		/* Do nothing.  */
     122  #endif
     123  
     124  /* Since C identifiers are not normally prefixed with an underscore
     125     on this system, the asm identifier `syscall_error' intrudes on the
     126     C name space.  Make sure we use an innocuous name.  */
     127  #define	syscall_error	__syscall_error
     128  #define mcount		__gnu_mcount_nc
     129  
     130  /* Tag_ABI_align8_preserved: This code preserves 8-byte
     131     alignment in any callee.  */
     132  	.eabi_attribute 25, 1
     133  /* Tag_ABI_align8_needed: This code may require 8-byte alignment from
     134     the caller.  */
     135  	.eabi_attribute 24, 1
     136  
     137  /* The thumb2 encoding is reasonably complete.  Unless suppressed, use it.  */
     138  	.syntax unified
     139  # if defined(__thumb2__) && !defined(NO_THUMB)
     140  	.thumb
     141  #else
     142  #  undef __thumb__
     143  #  undef __thumb2__
     144  	.arm
     145  # endif
     146  
     147  /* Load or store to/from address X + Y into/from R, (maybe) using T.
     148     X or Y can use T freely; T can be R if OP is a load.  The first
     149     version eschews the two-register addressing mode, while the
     150     second version uses it.  */
     151  # define LDST_INDEXED_NOINDEX(OP, R, T, X, Y)		\
     152  	add	T, X, Y;				\
     153  	OP	R, [T]
     154  # define LDST_INDEXED_INDEX(OP, R, X, Y)		\
     155  	OP	R, [X, Y]
     156  
     157  # ifdef ARM_NO_INDEX_REGISTER
     158  /* We're never using the two-register addressing mode, so this
     159     always uses an intermediate add.  */
     160  #  define LDST_INDEXED(OP, R, T, X, Y)	LDST_INDEXED_NOINDEX (OP, R, T, X, Y)
     161  #  define LDST_PC_INDEXED(OP, R, T, X)	LDST_INDEXED_NOINDEX (OP, R, T, pc, X)
     162  # else
     163  /* The two-register addressing mode is OK, except on Thumb with pc.  */
     164  #  define LDST_INDEXED(OP, R, T, X, Y)	LDST_INDEXED_INDEX (OP, R, X, Y)
     165  #  ifdef __thumb2__
     166  #   define LDST_PC_INDEXED(OP, R, T, X)	LDST_INDEXED_NOINDEX (OP, R, T, pc, X)
     167  #  else
     168  #   define LDST_PC_INDEXED(OP, R, T, X)	LDST_INDEXED_INDEX (OP, R, pc, X)
     169  #  endif
     170  # endif
     171  
     172  /* Load or store to/from a pc-relative EXPR into/from R, using T.  */
     173  # ifdef __thumb2__
     174  #  define LDST_PCREL(OP, R, T, EXPR) \
     175  	ldr	T, 98f;					\
     176  	.subsection 2;					\
     177  98:	.word	EXPR - 99f - PC_OFS;			\
     178  	.previous;					\
     179  99:	add	T, T, pc;				\
     180  	OP	R, [T]
     181  # elif defined (ARCH_HAS_T2) && ARM_PCREL_MOVW_OK
     182  #  define LDST_PCREL(OP, R, T, EXPR)			\
     183  	movw	T, #:lower16:EXPR - 99f - PC_OFS;	\
     184  	movt	T, #:upper16:EXPR - 99f - PC_OFS;	\
     185  99:	LDST_PC_INDEXED (OP, R, T, T)
     186  # else
     187  #  define LDST_PCREL(OP, R, T, EXPR) \
     188  	ldr	T, 98f;					\
     189  	.subsection 2;					\
     190  98:	.word	EXPR - 99f - PC_OFS;			\
     191  	.previous;					\
     192  99:	OP	R, [pc, T]
     193  # endif
     194  
     195  /* Load from a global SYMBOL + CONSTANT into R, using T.  */
     196  # if defined (ARCH_HAS_T2) && !defined (PIC)
     197  #  define LDR_GLOBAL(R, T, SYMBOL, CONSTANT)				\
     198  	movw	T, #:lower16:SYMBOL;					\
     199  	movt	T, #:upper16:SYMBOL;					\
     200  	ldr	R, [T, $CONSTANT]
     201  # elif defined (ARCH_HAS_T2) && defined (PIC) && ARM_PCREL_MOVW_OK
     202  #  define LDR_GLOBAL(R, T, SYMBOL, CONSTANT)				\
     203  	movw	R, #:lower16:_GLOBAL_OFFSET_TABLE_ - 97f - PC_OFS;	\
     204  	movw	T, #:lower16:99f - 98f - PC_OFS;			\
     205  	movt	R, #:upper16:_GLOBAL_OFFSET_TABLE_ - 97f - PC_OFS;	\
     206  	movt	T, #:upper16:99f - 98f - PC_OFS;			\
     207  	.pushsection .rodata.cst4, "aM", %progbits, 4;			\
     208  	.balign 4;							\
     209  99:	.word	SYMBOL##(GOT);						\
     210  	.popsection;							\
     211  97:	add	R, R, pc;						\
     212  98:	LDST_PC_INDEXED (ldr, T, T, T);					\
     213  	LDST_INDEXED (ldr, R, T, R, T);					\
     214  	ldr	R, [R, $CONSTANT]
     215  # else
     216  #  define LDR_GLOBAL(R, T, SYMBOL, CONSTANT)		\
     217  	ldr	T, 99f;					\
     218  	ldr	R, 100f;				\
     219  98:	add	T, T, pc;				\
     220  	ldr	T, [T, R];				\
     221  	.subsection 2;					\
     222  99:	.word	_GLOBAL_OFFSET_TABLE_ - 98b - PC_OFS;	\
     223  100:	.word	SYMBOL##(GOT);				\
     224  	.previous;					\
     225  	ldr	R, [T, $CONSTANT]
     226  # endif
     227  
     228  /* This is the same as LDR_GLOBAL, but for a SYMBOL that is known to
     229     be in the same linked object (as for one with hidden visibility).
     230     We can avoid the GOT indirection in the PIC case.  For the pure
     231     static case, LDR_GLOBAL is already optimal.  */
     232  # ifdef PIC
     233  #  define LDR_HIDDEN(R, T, SYMBOL, CONSTANT) \
     234    LDST_PCREL (ldr, R, T, SYMBOL + CONSTANT)
     235  # else
     236  #  define LDR_HIDDEN(R, T, SYMBOL, CONSTANT) \
     237    LDR_GLOBAL (R, T, SYMBOL, CONSTANT)
     238  # endif
     239  
     240  /* Cope with negative memory offsets, which thumb can't encode.
     241     Use NEGOFF_ADJ_BASE to (conditionally) alter the base register,
     242     and then NEGOFF_OFF1 to use 0 for thumb and the offset for arm,
     243     or NEGOFF_OFF2 to use A-B for thumb and A for arm.  */
     244  # ifdef __thumb2__
     245  #  define NEGOFF_ADJ_BASE(R, OFF)	add R, R, $OFF
     246  #  define NEGOFF_ADJ_BASE2(D, S, OFF)	add D, S, $OFF
     247  #  define NEGOFF_OFF1(R, OFF)		[R]
     248  #  define NEGOFF_OFF2(R, OFFA, OFFB)	[R, $((OFFA) - (OFFB))]
     249  # else
     250  #  define NEGOFF_ADJ_BASE(R, OFF)
     251  #  define NEGOFF_ADJ_BASE2(D, S, OFF)	mov D, S
     252  #  define NEGOFF_OFF1(R, OFF)		[R, $OFF]
     253  #  define NEGOFF_OFF2(R, OFFA, OFFB)	[R, $OFFA]
     254  # endif
     255  
     256  /* Helper to get the TLS base pointer.  The interface is that TMP is a
     257     register that may be used to hold the LR, if necessary.  TMP may be
     258     LR itself to indicate that LR need not be saved.  The base pointer
     259     is returned in R0.  Only R0 and TMP are modified.  */
     260  
     261  # ifdef ARCH_HAS_HARD_TP
     262  /* If the cpu has cp15 available, use it.  */
     263  #  define GET_TLS(TMP)		mrc p15, 0, r0, c13, c0, 3
     264  # else
     265  /* At this generic level we have no tricks to pull.  Call the ABI routine.  */
     266  #  define GET_TLS(TMP)					\
     267  	push	{ r1, r2, r3, lr };			\
     268  	cfi_remember_state;				\
     269  	cfi_adjust_cfa_offset (16);			\
     270  	cfi_rel_offset (r1, 0);				\
     271  	cfi_rel_offset (r2, 4);				\
     272  	cfi_rel_offset (r3, 8);				\
     273  	cfi_rel_offset (lr, 12);			\
     274  	bl	__aeabi_read_tp;			\
     275  	pop	{ r1, r2, r3, lr };			\
     276  	cfi_restore_state
     277  # endif /* ARCH_HAS_HARD_TP */
     278  
     279  /* These are the directives used for EABI unwind info.
     280     Wrap them in macros so another configuration's sysdep.h
     281     file can define them away if it doesn't use EABI unwind info.  */
     282  # define eabi_fnstart		.fnstart
     283  # define eabi_fnend		.fnend
     284  # define eabi_save(...)		.save __VA_ARGS__
     285  # define eabi_cantunwind	.cantunwind
     286  # define eabi_pad(n)		.pad n
     287  
     288  #endif	/* __ASSEMBLER__ */
     289  
     290  /* This number is the offset from the pc at the current location.  */
     291  #ifdef __thumb__
     292  # define PC_OFS  4
     293  #else
     294  # define PC_OFS  8
     295  #endif