1 /* 2 * Copyright (c) 2009 ARM Ltd 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the company may not be used to endorse or promote 14 * products derived from this software without specific prior written 15 * permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 22 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #ifndef ARM_ASM__H 30 #define ARM_ASM__H 31 32 #include "machine/acle-compat.h" 33 34 #if __ARM_ARCH >= 7 && defined (__ARM_ARCH_ISA_ARM) 35 # define _ISA_ARM_7 36 #endif 37 38 #if __ARM_ARCH >= 6 && defined (__ARM_ARCH_ISA_ARM) 39 # define _ISA_ARM_6 40 #endif 41 42 #if __ARM_ARCH >= 5 43 # define _ISA_ARM_5 44 #endif 45 46 #if __ARM_ARCH >= 4 && __ARM_ARCH_ISA_THUMB >= 1 47 # define _ISA_ARM_4T 48 #endif 49 50 #if __ARM_ARCH >= 4 && __ARM_ARCH_ISA_THUMB == 0 51 # define _ISA_ARM_4 52 #endif 53 54 55 #if __ARM_ARCH_ISA_THUMB >= 2 56 # define _ISA_THUMB_2 57 #endif 58 59 #if __ARM_ARCH_ISA_THUMB >= 1 60 # define _ISA_THUMB_1 61 #endif 62 63 /* Check whether leaf function PAC signing has been requested in the 64 -mbranch-protect compile-time option. */ 65 #define LEAF_PROTECT_BIT 2 66 67 #ifdef __ARM_FEATURE_PAC_DEFAULT 68 # define HAVE_PAC_LEAF \ 69 ((__ARM_FEATURE_PAC_DEFAULT & (1 << LEAF_PROTECT_BIT)) && 1) 70 #else 71 # define HAVE_PAC_LEAF 0 72 #endif 73 74 /* Provide default parameters for PAC-code handling in leaf-functions. */ 75 #if HAVE_PAC_LEAF 76 # ifndef PAC_LEAF_PUSH_IP 77 # define PAC_LEAF_PUSH_IP 1 78 # endif 79 #else /* !HAVE_PAC_LEAF */ 80 # undef PAC_LEAF_PUSH_IP 81 # define PAC_LEAF_PUSH_IP 0 82 #endif /* HAVE_PAC_LEAF */ 83 84 #define STACK_ALIGN_ENFORCE 0 85 86 #ifdef __ASSEMBLER__ 87 88 /****************************************************************************** 89 * Implementation of the prologue and epilogue assembler macros and their 90 * associated helper functions. 91 * 92 * These functions add support for the following: 93 * 94 * - M-profile branch target identification (BTI) landing-pads when compiled 95 * with `-mbranch-protection=bti'. 96 * - PAC-signing and verification instructions, depending on hardware support 97 * and whether the PAC-signing of leaf functions has been requested via the 98 * `-mbranch-protection=pac-ret+leaf' compiler argument. 99 * - 8-byte stack alignment preservation at function entry, defaulting to the 100 * value of STACK_ALIGN_ENFORCE. 101 * 102 * Notes: 103 * - Prologue stack alignment is implemented by detecting a push with an odd 104 * number of registers and prepending a dummy register to the list. 105 * - If alignment is attempted on a list containing r0, compilation will result 106 * in an error. 107 * - If alignment is attempted in a list containing r1, r0 will be prepended to 108 * the register list and r0 will be restored prior to function return. for 109 * functions with non-void return types, this will result in the corruption of 110 * the result register. 111 * - Stack alignment is enforced via the following helper macro call-chain: 112 * 113 * {prologue|epilogue} ->_align8 -> _preprocess_reglist -> 114 * _preprocess_reglist1 -> {_prologue|_epilogue} 115 * 116 * - Debug CFI directives are automatically added to prologues and epilogues, 117 * assisted by `cfisavelist' and `cfirestorelist', respectively. 118 * 119 * Arguments: 120 * prologue 121 * -------- 122 * - first - If `last' specified, this serves as start of general-purpose 123 * register (GPR) range to push onto stack, otherwise represents 124 * single GPR to push onto stack. If omitted, no GPRs pushed 125 * onto stack at prologue. 126 * - last - If given, specifies inclusive upper-bound of GPR range. 127 * - push_ip - Determines whether IP register is to be pushed to stack at 128 * prologue. When pac-signing is requested, this holds the 129 * the pac-key. Either 1 or 0 to push or not push, respectively. 130 * Default behavior: Set to value of PAC_LEAF_PUSH_IP macro. 131 * - push_lr - Determines whether to push lr to the stack on function entry. 132 * Either 1 or 0 to push or not push, respectively. 133 * - align8 - Whether to enforce alignment. Either 1 or 0, with 1 requesting 134 * alignment. 135 * 136 * epilogue 137 * -------- 138 * The epilogue should be called passing the same arguments as those passed to 139 * the prologue to ensure the stack is not corrupted on function return. 140 * 141 * Usage examples: 142 * 143 * prologue push_ip=1 -> push {ip} 144 * epilogue push_ip=1, align8=1 -> pop {r2, ip} 145 * prologue push_ip=1, push_lr=1 -> push {ip, lr} 146 * epilogue 1 -> pop {r1} 147 * prologue 1, align8=1 -> push {r0, r1} 148 * epilogue 1, push_ip=1 -> pop {r1, ip} 149 * prologue 1, 4 -> push {r1-r4} 150 * epilogue 1, 4 push_ip=1 -> pop {r1-r4, ip} 151 * 152 ******************************************************************************/ 153 154 /* Emit .cfi_restore directives for a consecutive sequence of registers. */ 155 .macro cfirestorelist first, last 156 .cfi_restore \last 157 .if \last-\first 158 cfirestorelist \first, \last-1 159 .endif 160 .endm 161 162 /* Emit .cfi_offset directives for a consecutive sequence of registers. */ 163 .macro cfisavelist first, last, index=1 164 .cfi_offset \last, -4*(\index) 165 .if \last-\first 166 cfisavelist \first, \last-1, \index+1 167 .endif 168 .endm 169 170 .macro _prologue first=-1, last=-1, push_ip=PAC_LEAF_PUSH_IP, push_lr=0 171 .if \push_ip & 1 != \push_ip 172 .error "push_ip may be either 0 or 1" 173 .endif 174 .if \push_lr & 1 != \push_lr 175 .error "push_lr may be either 0 or 1" 176 .endif 177 .if \first != -1 178 .if \last == -1 179 /* Upper-bound not provided: Set upper = lower. */ 180 _prologue \first, \first, \push_ip, \push_lr 181 .exitm 182 .endif 183 .endif 184 #if HAVE_PAC_LEAF 185 #if __ARM_FEATURE_BTI_DEFAULT 186 pacbti ip, lr, sp 187 #else 188 pac ip, lr, sp 189 #endif /* __ARM_FEATURE_BTI_DEFAULT */ 190 .cfi_register 143, 12 191 #else 192 #if __ARM_FEATURE_BTI_DEFAULT 193 bti 194 #endif /* __ARM_FEATURE_BTI_DEFAULT */ 195 #endif /* HAVE_PAC_LEAF */ 196 .if \first != -1 197 .if \last != \first 198 .if \last >= 13 199 .error "SP cannot be in the save list" 200 .endif 201 .if \push_ip 202 .if \push_lr 203 /* Case 1: push register range, ip and lr registers. */ 204 push {r\first-r\last, ip, lr} 205 .cfi_adjust_cfa_offset ((\last-\first)+3)*4 206 .cfi_offset 14, -4 207 .cfi_offset 143, -8 208 cfisavelist \first, \last, 3 209 .else // !\push_lr 210 /* Case 2: push register range and ip register. */ 211 push {r\first-r\last, ip} 212 .cfi_adjust_cfa_offset ((\last-\first)+2)*4 213 .cfi_offset 143, -4 214 cfisavelist \first, \last, 2 215 .endif 216 .else // !\push_ip 217 .if \push_lr 218 /* Case 3: push register range and lr register. */ 219 push {r\first-r\last, lr} 220 .cfi_adjust_cfa_offset ((\last-\first)+2)*4 221 .cfi_offset 14, -4 222 cfisavelist \first, \last, 2 223 .else // !\push_lr 224 /* Case 4: push register range. */ 225 push {r\first-r\last} 226 .cfi_adjust_cfa_offset ((\last-\first)+1)*4 227 cfisavelist \first, \last, 1 228 .endif 229 .endif 230 .else // \last == \first 231 .if \push_ip 232 .if \push_lr 233 /* Case 5: push single GP register plus ip and lr registers. */ 234 push {r\first, ip, lr} 235 .cfi_adjust_cfa_offset 12 236 .cfi_offset 14, -4 237 .cfi_offset 143, -8 238 cfisavelist \first, \first, 3 239 .else // !\push_lr 240 /* Case 6: push single GP register plus ip register. */ 241 push {r\first, ip} 242 .cfi_adjust_cfa_offset 8 243 .cfi_offset 143, -4 244 cfisavelist \first, \first, 2 245 .endif 246 .else // !\push_ip 247 .if \push_lr 248 /* Case 7: push single GP register plus lr register. */ 249 push {r\first, lr} 250 .cfi_adjust_cfa_offset 8 251 .cfi_offset 14, -4 252 cfisavelist \first, \first, 2 253 .else // !\push_lr 254 /* Case 8: push single GP register. */ 255 push {r\first} 256 .cfi_adjust_cfa_offset 4 257 cfisavelist \first, \first, 1 258 .endif 259 .endif 260 .endif 261 .else // \first == -1 262 .if \push_ip 263 .if \push_lr 264 /* Case 9: push ip and lr registers. */ 265 push {ip, lr} 266 .cfi_adjust_cfa_offset 8 267 .cfi_offset 14, -4 268 .cfi_offset 143, -8 269 .else // !\push_lr 270 /* Case 10: push ip register. */ 271 push {ip} 272 .cfi_adjust_cfa_offset 4 273 .cfi_offset 143, -4 274 .endif 275 .else // !\push_ip 276 .if \push_lr 277 /* Case 11: push lr register. */ 278 push {lr} 279 .cfi_adjust_cfa_offset 4 280 .cfi_offset 14, -4 281 .endif 282 .endif 283 .endif 284 .endm 285 286 .macro _epilogue first=-1, last=-1, push_ip=PAC_LEAF_PUSH_IP, push_lr=0 287 .if \push_ip & 1 != \push_ip 288 .error "push_ip may be either 0 or 1" 289 .endif 290 .if \push_lr & 1 != \push_lr 291 .error "push_lr may be either 0 or 1" 292 .endif 293 .if \first != -1 294 .if \last == -1 295 /* Upper-bound not provided: Set upper = lower. */ 296 _epilogue \first, \first, \push_ip, \push_lr 297 .exitm 298 .endif 299 .if \last != \first 300 .if \last >= 13 301 .error "SP cannot be in the save list" 302 .endif 303 .if \push_ip 304 .if \push_lr 305 /* Case 1: pop register range, ip and lr registers. */ 306 pop {r\first-r\last, ip, lr} 307 .cfi_restore 14 308 .cfi_register 143, 12 309 cfirestorelist \first, \last 310 .else // !\push_lr 311 /* Case 2: pop register range and ip register. */ 312 pop {r\first-r\last, ip} 313 .cfi_register 143, 12 314 cfirestorelist \first, \last 315 .endif 316 .else // !\push_ip 317 .if \push_lr 318 /* Case 3: pop register range and lr register. */ 319 pop {r\first-r\last, lr} 320 .cfi_restore 14 321 cfirestorelist \first, \last 322 .else // !\push_lr 323 /* Case 4: pop register range. */ 324 pop {r\first-r\last} 325 cfirestorelist \first, \last 326 .endif 327 .endif 328 .else // \last == \first 329 .if \push_ip 330 .if \push_lr 331 /* Case 5: pop single GP register plus ip and lr registers. */ 332 pop {r\first, ip, lr} 333 .cfi_restore 14 334 .cfi_register 143, 12 335 cfirestorelist \first, \first 336 .else // !\push_lr 337 /* Case 6: pop single GP register plus ip register. */ 338 pop {r\first, ip} 339 .cfi_register 143, 12 340 cfirestorelist \first, \first 341 .endif 342 .else // !\push_ip 343 .if \push_lr 344 /* Case 7: pop single GP register plus lr register. */ 345 pop {r\first, lr} 346 .cfi_restore 14 347 cfirestorelist \first, \first 348 .else // !\push_lr 349 /* Case 8: pop single GP register. */ 350 pop {r\first} 351 cfirestorelist \first, \first 352 .endif 353 .endif 354 .endif 355 .else // \first == -1 356 .if \push_ip 357 .if \push_lr 358 /* Case 9: pop ip and lr registers. */ 359 pop {ip, lr} 360 .cfi_restore 14 361 .cfi_register 143, 12 362 .else // !\push_lr 363 /* Case 10: pop ip register. */ 364 pop {ip} 365 .cfi_register 143, 12 366 .endif 367 .else // !\push_ip 368 .if \push_lr 369 /* Case 11: pop lr register. */ 370 pop {lr} 371 .cfi_restore 14 372 .endif 373 .endif 374 .endif 375 #if HAVE_PAC_LEAF 376 aut ip, lr, sp 377 #endif /* HAVE_PAC_LEAF */ 378 bx lr 379 .endm 380 381 # clean up expressions in 'last' 382 .macro _preprocess_reglist1 first:req, last:req, push_ip:req, push_lr:req, reglist_op:req 383 .if \last == 0 384 \reglist_op \first, 0, \push_ip, \push_lr 385 .elseif \last == 1 386 \reglist_op \first, 1, \push_ip, \push_lr 387 .elseif \last == 2 388 \reglist_op \first, 2, \push_ip, \push_lr 389 .elseif \last == 3 390 \reglist_op \first, 3, \push_ip, \push_lr 391 .elseif \last == 4 392 \reglist_op \first, 4, \push_ip, \push_lr 393 .elseif \last == 5 394 \reglist_op \first, 5, \push_ip, \push_lr 395 .elseif \last == 6 396 \reglist_op \first, 6, \push_ip, \push_lr 397 .elseif \last == 7 398 \reglist_op \first, 7, \push_ip, \push_lr 399 .elseif \last == 8 400 \reglist_op \first, 8, \push_ip, \push_lr 401 .elseif \last == 9 402 \reglist_op \first, 9, \push_ip, \push_lr 403 .elseif \last == 10 404 \reglist_op \first, 10, \push_ip, \push_lr 405 .elseif \last == 11 406 \reglist_op \first, 11, \push_ip, \push_lr 407 .else 408 .error "last (\last) out of range" 409 .endif 410 .endm 411 412 # clean up expressions in 'first' 413 .macro _preprocess_reglist first:req, last, push_ip=0, push_lr=0, reglist_op:req 414 .ifb \last 415 _preprocess_reglist \first \first \push_ip \push_lr 416 .else 417 .if \first > \last 418 .error "last (\last) must be at least as great as first (\first)" 419 .endif 420 .if \first == 0 421 _preprocess_reglist1 0, \last, \push_ip, \push_lr, \reglist_op 422 .elseif \first == 1 423 _preprocess_reglist1 1, \last, \push_ip, \push_lr, \reglist_op 424 .elseif \first == 2 425 _preprocess_reglist1 2, \last, \push_ip, \push_lr, \reglist_op 426 .elseif \first == 3 427 _preprocess_reglist1 3, \last, \push_ip, \push_lr, \reglist_op 428 .elseif \first == 4 429 _preprocess_reglist1 4, \last, \push_ip, \push_lr, \reglist_op 430 .elseif \first == 5 431 _preprocess_reglist1 5, \last, \push_ip, \push_lr, \reglist_op 432 .elseif \first == 6 433 _preprocess_reglist1 6, \last, \push_ip, \push_lr, \reglist_op 434 .elseif \first == 7 435 _preprocess_reglist1 7, \last, \push_ip, \push_lr, \reglist_op 436 .elseif \first == 8 437 _preprocess_reglist1 8, \last, \push_ip, \push_lr, \reglist_op 438 .elseif \first == 9 439 _preprocess_reglist1 9, \last, \push_ip, \push_lr, \reglist_op 440 .elseif \first == 10 441 _preprocess_reglist1 10, \last, \push_ip, \push_lr, \reglist_op 442 .elseif \first == 11 443 _preprocess_reglist1 11, \last, \push_ip, \push_lr, \reglist_op 444 .else 445 .error "first (\first) out of range" 446 .endif 447 .endif 448 .endm 449 450 .macro _align8 first, last, push_ip=0, push_lr=0, reglist_op=_prologue 451 .ifb \first 452 .ifnb \last 453 .error "can't have last (\last) without specifying first" 454 .else // \last not blank 455 .if ((\push_ip + \push_lr) % 2) == 0 456 \reglist_op first=-1, last=-1, push_ip=\push_ip, push_lr=\push_lr 457 .exitm 458 .else // ((\push_ip + \push_lr) % 2) odd 459 _align8 2, 2, \push_ip, \push_lr, \reglist_op 460 .exitm 461 .endif // ((\push_ip + \push_lr) % 2) == 0 462 .endif // .ifnb \last 463 .endif // .ifb \first 464 465 .ifb \last 466 _align8 \first, \first, \push_ip, \push_lr, \reglist_op 467 .else 468 .if \push_ip & 1 <> \push_ip 469 .error "push_ip may be 0 or 1" 470 .endif 471 .if \push_lr & 1 <> \push_lr 472 .error "push_lr may be 0 or 1" 473 .endif 474 .ifeq (\last - \first + \push_ip + \push_lr) % 2 475 .if \first == 0 476 .error "Alignment required and first register is r0" 477 .exitm 478 .endif 479 _preprocess_reglist \first-1, \last, \push_ip, \push_lr, \reglist_op 480 .else 481 _preprocess_reglist \first \last, \push_ip, \push_lr, \reglist_op 482 .endif 483 .endif 484 .endm 485 486 .macro prologue first, last, push_ip=PAC_LEAF_PUSH_IP, push_lr=0, align8=STACK_ALIGN_ENFORCE 487 .if \align8 488 _align8 \first, \last, \push_ip, \push_lr, _prologue 489 .else 490 _prologue first=\first, last=\last, push_ip=\push_ip, push_lr=\push_lr 491 .endif 492 .endm 493 494 .macro epilogue first, last, push_ip=PAC_LEAF_PUSH_IP, push_lr=0, align8=STACK_ALIGN_ENFORCE 495 .if \align8 496 _align8 \first, \last, \push_ip, \push_lr, reglist_op=_epilogue 497 .else 498 _epilogue first=\first, last=\last, push_ip=\push_ip, push_lr=\push_lr 499 .endif 500 .endm 501 502 #endif /* __ASSEMBLER__ */ 503 504 #endif /* ARM_ASM__H */ 505