1 /* 2 * Macros for asm code. Arm version. 3 * 4 * Copyright (c) 2019-2022, Arm Limited. 5 * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception 6 */ 7 8 #ifndef _ASMDEFS_H 9 #define _ASMDEFS_H 10 11 /* Check whether leaf function PAC signing has been requested in the 12 -mbranch-protect compile-time option. */ 13 #define LEAF_PROTECT_BIT 2 14 15 #ifdef __ARM_FEATURE_PAC_DEFAULT 16 # define HAVE_PAC_LEAF \ 17 ((__ARM_FEATURE_PAC_DEFAULT & (1 << LEAF_PROTECT_BIT)) && 1) 18 #else 19 # define HAVE_PAC_LEAF 0 20 #endif 21 22 /* Provide default parameters for PAC-code handling in leaf-functions. */ 23 #if HAVE_PAC_LEAF 24 # ifndef PAC_LEAF_PUSH_IP 25 # define PAC_LEAF_PUSH_IP 1 26 # endif 27 #else /* !HAVE_PAC_LEAF */ 28 # undef PAC_LEAF_PUSH_IP 29 # define PAC_LEAF_PUSH_IP 0 30 #endif /* HAVE_PAC_LEAF */ 31 32 #define STACK_ALIGN_ENFORCE 0 33 34 /****************************************************************************** 35 * Implementation of the prologue and epilogue assembler macros and their 36 * associated helper functions. 37 * 38 * These functions add support for the following: 39 * 40 * - M-profile branch target identification (BTI) landing-pads when compiled 41 * with `-mbranch-protection=bti'. 42 * - PAC-signing and verification instructions, depending on hardware support 43 * and whether the PAC-signing of leaf functions has been requested via the 44 * `-mbranch-protection=pac-ret+leaf' compiler argument. 45 * - 8-byte stack alignment preservation at function entry, defaulting to the 46 * value of STACK_ALIGN_ENFORCE. 47 * 48 * Notes: 49 * - Prologue stack alignment is implemented by detecting a push with an odd 50 * number of registers and prepending a dummy register to the list. 51 * - If alignment is attempted on a list containing r0, compilation will result 52 * in an error. 53 * - If alignment is attempted in a list containing r1, r0 will be prepended to 54 * the register list and r0 will be restored prior to function return. for 55 * functions with non-void return types, this will result in the corruption of 56 * the result register. 57 * - Stack alignment is enforced via the following helper macro call-chain: 58 * 59 * {prologue|epilogue} ->_align8 -> _preprocess_reglist -> 60 * _preprocess_reglist1 -> {_prologue|_epilogue} 61 * 62 * - Debug CFI directives are automatically added to prologues and epilogues, 63 * assisted by `cfisavelist' and `cfirestorelist', respectively. 64 * 65 * Arguments: 66 * prologue 67 * -------- 68 * - first - If `last' specified, this serves as start of general-purpose 69 * register (GPR) range to push onto stack, otherwise represents 70 * single GPR to push onto stack. If omitted, no GPRs pushed 71 * onto stack at prologue. 72 * - last - If given, specifies inclusive upper-bound of GPR range. 73 * - push_ip - Determines whether IP register is to be pushed to stack at 74 * prologue. When pac-signing is requested, this holds the 75 * the pac-key. Either 1 or 0 to push or not push, respectively. 76 * Default behavior: Set to value of PAC_LEAF_PUSH_IP macro. 77 * - push_lr - Determines whether to push lr to the stack on function entry. 78 * Either 1 or 0 to push or not push, respectively. 79 * - align8 - Whether to enforce alignment. Either 1 or 0, with 1 requesting 80 * alignment. 81 * 82 * epilogue 83 * -------- 84 * The epilogue should be called passing the same arguments as those passed to 85 * the prologue to ensure the stack is not corrupted on function return. 86 * 87 * Usage examples: 88 * 89 * prologue push_ip=1 -> push {ip} 90 * epilogue push_ip=1, align8=1 -> pop {r2, ip} 91 * prologue push_ip=1, push_lr=1 -> push {ip, lr} 92 * epilogue 1 -> pop {r1} 93 * prologue 1, align8=1 -> push {r0, r1} 94 * epilogue 1, push_ip=1 -> pop {r1, ip} 95 * prologue 1, 4 -> push {r1-r4} 96 * epilogue 1, 4 push_ip=1 -> pop {r1-r4, ip} 97 * 98 ******************************************************************************/ 99 100 /* Emit .cfi_restore directives for a consecutive sequence of registers. */ 101 .macro cfirestorelist first, last 102 .cfi_restore \last 103 .if \last-\first 104 cfirestorelist \first, \last-1 105 .endif 106 .endm 107 108 /* Emit .cfi_offset directives for a consecutive sequence of registers. */ 109 .macro cfisavelist first, last, index=1 110 .cfi_offset \last, -4*(\index) 111 .if \last-\first 112 cfisavelist \first, \last-1, \index+1 113 .endif 114 .endm 115 116 .macro _prologue first=-1, last=-1, push_ip=PAC_LEAF_PUSH_IP, push_lr=0 117 .if \push_ip & 1 != \push_ip 118 .error "push_ip may be either 0 or 1" 119 .endif 120 .if \push_lr & 1 != \push_lr 121 .error "push_lr may be either 0 or 1" 122 .endif 123 .if \first != -1 124 .if \last == -1 125 /* Upper-bound not provided: Set upper = lower. */ 126 _prologue \first, \first, \push_ip, \push_lr 127 .exitm 128 .endif 129 .endif 130 #if HAVE_PAC_LEAF 131 # if __ARM_FEATURE_BTI_DEFAULT 132 pacbti ip, lr, sp 133 # else 134 pac ip, lr, sp 135 # endif /* __ARM_FEATURE_BTI_DEFAULT */ 136 .cfi_register 143, 12 137 #else 138 # if __ARM_FEATURE_BTI_DEFAULT 139 bti 140 # endif /* __ARM_FEATURE_BTI_DEFAULT */ 141 #endif /* HAVE_PAC_LEAF */ 142 .if \first != -1 143 .if \last != \first 144 .if \last >= 13 145 .error "SP cannot be in the save list" 146 .endif 147 .if \push_ip 148 .if \push_lr 149 /* Case 1: push register range, ip and lr registers. */ 150 push {r\first-r\last, ip, lr} 151 .cfi_adjust_cfa_offset ((\last-\first)+3)*4 152 .cfi_offset 14, -4 153 .cfi_offset 143, -8 154 cfisavelist \first, \last, 3 155 .else // !\push_lr 156 /* Case 2: push register range and ip register. */ 157 push {r\first-r\last, ip} 158 .cfi_adjust_cfa_offset ((\last-\first)+2)*4 159 .cfi_offset 143, -4 160 cfisavelist \first, \last, 2 161 .endif 162 .else // !\push_ip 163 .if \push_lr 164 /* Case 3: push register range and lr register. */ 165 push {r\first-r\last, lr} 166 .cfi_adjust_cfa_offset ((\last-\first)+2)*4 167 .cfi_offset 14, -4 168 cfisavelist \first, \last, 2 169 .else // !\push_lr 170 /* Case 4: push register range. */ 171 push {r\first-r\last} 172 .cfi_adjust_cfa_offset ((\last-\first)+1)*4 173 cfisavelist \first, \last, 1 174 .endif 175 .endif 176 .else // \last == \first 177 .if \push_ip 178 .if \push_lr 179 /* Case 5: push single GP register plus ip and lr registers. */ 180 push {r\first, ip, lr} 181 .cfi_adjust_cfa_offset 12 182 .cfi_offset 14, -4 183 .cfi_offset 143, -8 184 cfisavelist \first, \first, 3 185 .else // !\push_lr 186 /* Case 6: push single GP register plus ip register. */ 187 push {r\first, ip} 188 .cfi_adjust_cfa_offset 8 189 .cfi_offset 143, -4 190 cfisavelist \first, \first, 2 191 .endif 192 .else // !\push_ip 193 .if \push_lr 194 /* Case 7: push single GP register plus lr register. */ 195 push {r\first, lr} 196 .cfi_adjust_cfa_offset 8 197 .cfi_offset 14, -4 198 cfisavelist \first, \first, 2 199 .else // !\push_lr 200 /* Case 8: push single GP register. */ 201 push {r\first} 202 .cfi_adjust_cfa_offset 4 203 cfisavelist \first, \first, 1 204 .endif 205 .endif 206 .endif 207 .else // \first == -1 208 .if \push_ip 209 .if \push_lr 210 /* Case 9: push ip and lr registers. */ 211 push {ip, lr} 212 .cfi_adjust_cfa_offset 8 213 .cfi_offset 14, -4 214 .cfi_offset 143, -8 215 .else // !\push_lr 216 /* Case 10: push ip register. */ 217 push {ip} 218 .cfi_adjust_cfa_offset 4 219 .cfi_offset 143, -4 220 .endif 221 .else // !\push_ip 222 .if \push_lr 223 /* Case 11: push lr register. */ 224 push {lr} 225 .cfi_adjust_cfa_offset 4 226 .cfi_offset 14, -4 227 .endif 228 .endif 229 .endif 230 .endm 231 232 .macro _epilogue first=-1, last=-1, push_ip=PAC_LEAF_PUSH_IP, push_lr=0 233 .if \push_ip & 1 != \push_ip 234 .error "push_ip may be either 0 or 1" 235 .endif 236 .if \push_lr & 1 != \push_lr 237 .error "push_lr may be either 0 or 1" 238 .endif 239 .if \first != -1 240 .if \last == -1 241 /* Upper-bound not provided: Set upper = lower. */ 242 _epilogue \first, \first, \push_ip, \push_lr 243 .exitm 244 .endif 245 .if \last != \first 246 .if \last >= 13 247 .error "SP cannot be in the save list" 248 .endif 249 .if \push_ip 250 .if \push_lr 251 /* Case 1: pop register range, ip and lr registers. */ 252 pop {r\first-r\last, ip, lr} 253 .cfi_restore 14 254 .cfi_register 143, 12 255 cfirestorelist \first, \last 256 .else // !\push_lr 257 /* Case 2: pop register range and ip register. */ 258 pop {r\first-r\last, ip} 259 .cfi_register 143, 12 260 cfirestorelist \first, \last 261 .endif 262 .else // !\push_ip 263 .if \push_lr 264 /* Case 3: pop register range and lr register. */ 265 pop {r\first-r\last, lr} 266 .cfi_restore 14 267 cfirestorelist \first, \last 268 .else // !\push_lr 269 /* Case 4: pop register range. */ 270 pop {r\first-r\last} 271 cfirestorelist \first, \last 272 .endif 273 .endif 274 .else // \last == \first 275 .if \push_ip 276 .if \push_lr 277 /* Case 5: pop single GP register plus ip and lr registers. */ 278 pop {r\first, ip, lr} 279 .cfi_restore 14 280 .cfi_register 143, 12 281 cfirestorelist \first, \first 282 .else // !\push_lr 283 /* Case 6: pop single GP register plus ip register. */ 284 pop {r\first, ip} 285 .cfi_register 143, 12 286 cfirestorelist \first, \first 287 .endif 288 .else // !\push_ip 289 .if \push_lr 290 /* Case 7: pop single GP register plus lr register. */ 291 pop {r\first, lr} 292 .cfi_restore 14 293 cfirestorelist \first, \first 294 .else // !\push_lr 295 /* Case 8: pop single GP register. */ 296 pop {r\first} 297 cfirestorelist \first, \first 298 .endif 299 .endif 300 .endif 301 .else // \first == -1 302 .if \push_ip 303 .if \push_lr 304 /* Case 9: pop ip and lr registers. */ 305 pop {ip, lr} 306 .cfi_restore 14 307 .cfi_register 143, 12 308 .else // !\push_lr 309 /* Case 10: pop ip register. */ 310 pop {ip} 311 .cfi_register 143, 12 312 .endif 313 .else // !\push_ip 314 .if \push_lr 315 /* Case 11: pop lr register. */ 316 pop {lr} 317 .cfi_restore 14 318 .endif 319 .endif 320 .endif 321 #if HAVE_PAC_LEAF 322 aut ip, lr, sp 323 #endif /* HAVE_PAC_LEAF */ 324 bx lr 325 .endm 326 327 /* Clean up expressions in 'last'. */ 328 .macro _preprocess_reglist1 first:req, last:req, push_ip:req, push_lr:req, reglist_op:req 329 .if \last == 0 330 \reglist_op \first, 0, \push_ip, \push_lr 331 .elseif \last == 1 332 \reglist_op \first, 1, \push_ip, \push_lr 333 .elseif \last == 2 334 \reglist_op \first, 2, \push_ip, \push_lr 335 .elseif \last == 3 336 \reglist_op \first, 3, \push_ip, \push_lr 337 .elseif \last == 4 338 \reglist_op \first, 4, \push_ip, \push_lr 339 .elseif \last == 5 340 \reglist_op \first, 5, \push_ip, \push_lr 341 .elseif \last == 6 342 \reglist_op \first, 6, \push_ip, \push_lr 343 .elseif \last == 7 344 \reglist_op \first, 7, \push_ip, \push_lr 345 .elseif \last == 8 346 \reglist_op \first, 8, \push_ip, \push_lr 347 .elseif \last == 9 348 \reglist_op \first, 9, \push_ip, \push_lr 349 .elseif \last == 10 350 \reglist_op \first, 10, \push_ip, \push_lr 351 .elseif \last == 11 352 \reglist_op \first, 11, \push_ip, \push_lr 353 .else 354 .error "last (\last) out of range" 355 .endif 356 .endm 357 358 /* Clean up expressions in 'first'. */ 359 .macro _preprocess_reglist first:req, last, push_ip=0, push_lr=0, reglist_op:req 360 .ifb \last 361 _preprocess_reglist \first \first \push_ip \push_lr 362 .else 363 .if \first > \last 364 .error "last (\last) must be at least as great as first (\first)" 365 .endif 366 .if \first == 0 367 _preprocess_reglist1 0, \last, \push_ip, \push_lr, \reglist_op 368 .elseif \first == 1 369 _preprocess_reglist1 1, \last, \push_ip, \push_lr, \reglist_op 370 .elseif \first == 2 371 _preprocess_reglist1 2, \last, \push_ip, \push_lr, \reglist_op 372 .elseif \first == 3 373 _preprocess_reglist1 3, \last, \push_ip, \push_lr, \reglist_op 374 .elseif \first == 4 375 _preprocess_reglist1 4, \last, \push_ip, \push_lr, \reglist_op 376 .elseif \first == 5 377 _preprocess_reglist1 5, \last, \push_ip, \push_lr, \reglist_op 378 .elseif \first == 6 379 _preprocess_reglist1 6, \last, \push_ip, \push_lr, \reglist_op 380 .elseif \first == 7 381 _preprocess_reglist1 7, \last, \push_ip, \push_lr, \reglist_op 382 .elseif \first == 8 383 _preprocess_reglist1 8, \last, \push_ip, \push_lr, \reglist_op 384 .elseif \first == 9 385 _preprocess_reglist1 9, \last, \push_ip, \push_lr, \reglist_op 386 .elseif \first == 10 387 _preprocess_reglist1 10, \last, \push_ip, \push_lr, \reglist_op 388 .elseif \first == 11 389 _preprocess_reglist1 11, \last, \push_ip, \push_lr, \reglist_op 390 .else 391 .error "first (\first) out of range" 392 .endif 393 .endif 394 .endm 395 396 .macro _align8 first, last, push_ip=0, push_lr=0, reglist_op=_prologue 397 .ifb \first 398 .ifnb \last 399 .error "can't have last (\last) without specifying first" 400 .else // \last not blank 401 .if ((\push_ip + \push_lr) % 2) == 0 402 \reglist_op first=-1, last=-1, push_ip=\push_ip, push_lr=\push_lr 403 .exitm 404 .else // ((\push_ip + \push_lr) % 2) odd 405 _align8 2, 2, \push_ip, \push_lr, \reglist_op 406 .exitm 407 .endif // ((\push_ip + \push_lr) % 2) == 0 408 .endif // .ifnb \last 409 .endif // .ifb \first 410 411 .ifb \last 412 _align8 \first, \first, \push_ip, \push_lr, \reglist_op 413 .else 414 .if \push_ip & 1 <> \push_ip 415 .error "push_ip may be 0 or 1" 416 .endif 417 .if \push_lr & 1 <> \push_lr 418 .error "push_lr may be 0 or 1" 419 .endif 420 .ifeq (\last - \first + \push_ip + \push_lr) % 2 421 .if \first == 0 422 .error "Alignment required and first register is r0" 423 .exitm 424 .endif 425 _preprocess_reglist \first-1, \last, \push_ip, \push_lr, \reglist_op 426 .else 427 _preprocess_reglist \first \last, \push_ip, \push_lr, \reglist_op 428 .endif 429 .endif 430 .endm 431 432 .macro prologue first, last, push_ip=PAC_LEAF_PUSH_IP, push_lr=0, align8=STACK_ALIGN_ENFORCE 433 .if \align8 434 _align8 \first, \last, \push_ip, \push_lr, _prologue 435 .else 436 _prologue first=\first, last=\last, push_ip=\push_ip, push_lr=\push_lr 437 .endif 438 .endm 439 440 .macro epilogue first, last, push_ip=PAC_LEAF_PUSH_IP, push_lr=0, align8=STACK_ALIGN_ENFORCE 441 .if \align8 442 _align8 \first, \last, \push_ip, \push_lr, reglist_op=_epilogue 443 .else 444 _epilogue first=\first, last=\last, push_ip=\push_ip, push_lr=\push_lr 445 .endif 446 .endm 447 448 #define ENTRY_ALIGN(name, alignment) \ 449 .global name; \ 450 .type name,%function; \ 451 .align alignment; \ 452 name: \ 453 .fnstart; \ 454 .cfi_startproc; 455 456 #define ENTRY(name) ENTRY_ALIGN(name, 6) 457 458 #define ENTRY_ALIAS(name) \ 459 .global name; \ 460 .type name,%function; \ 461 name: 462 463 #if defined (IS_LEAF) 464 # define END_UNWIND .cantunwind; 465 #else 466 # define END_UNWIND 467 #endif 468 469 #define END(name) \ 470 .cfi_endproc; \ 471 END_UNWIND \ 472 .fnend; \ 473 .size name, .-name; 474 475 #define L(l) .L ## l 476 477 #endif 478