sysdep.h 9.2 KB

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