master
  1/* Assembler macros for ARM.
  2   Copyright (C) 1997-2025 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;					\
17798:	.word	EXPR - 99f - PC_OFS;			\
178	.previous;					\
17999:	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;	\
18599:	LDST_PC_INDEXED (OP, R, T, T)
186# else
187#  define LDST_PCREL(OP, R, T, EXPR) \
188	ldr	T, 98f;					\
189	.subsection 2;					\
19098:	.word	EXPR - 99f - PC_OFS;			\
191	.previous;					\
19299:	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;							\
20999:	.word	SYMBOL##(GOT);						\
210	.popsection;							\
21197:	add	R, R, pc;						\
21298:	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;				\
21998:	add	T, T, pc;				\
220	ldr	T, [T, R];				\
221	.subsection 2;					\
22299:	.word	_GLOBAL_OFFSET_TABLE_ - 98b - PC_OFS;	\
223100:	.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