1/* libunwind - a platform-independent unwind library 2 Copyright (C) 2004-2005 Hewlett-Packard Co 3 Contributed by David Mosberger-Tang <davidm@hpl.hp.com> 4 5This file is part of libunwind. 6 7Permission is hereby granted, free of charge, to any person obtaining 8a copy of this software and associated documentation files (the 9"Software"), to deal in the Software without restriction, including 10without limitation the rights to use, copy, modify, merge, publish, 11distribute, sublicense, and/or sell copies of the Software, and to 12permit persons to whom the Software is furnished to do so, subject to 13the following conditions: 14 15The above copyright notice and this permission notice shall be 16included in all copies or substantial portions of the Software. 17 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 25 26 .text 27 28#define CALL_NEXT_PTR(gp_save_reg, arg0, arg1) \ 29 ld8 r2 = [arg0], 8;; /* read the next function pointer */ \ 30 ld8 r3 = [r2], 8;; /* read the function's entry-point */ \ 31 ld8 r2 = [r2];; /* read the function's gp */ \ 32 mov b6 = r3; \ 33 mov gp_save_reg = gp; \ 34 mov out0 = arg0; \ 35 mov out1 = arg1; \ 36 mov gp = r2; \ 37 br.call.sptk.many rp = b6;; \ 38 mov gp = gp_save_reg 39 40#define CALL_NEXT(gp_save_reg) CALL_NEXT_PTR(gp_save_reg, in0, in1) 41 42#define LOAD_VAL(reg) \ 43 ld8 reg = [in1], 8;; \ 44 tbit.nz p15, p0 = reg, 0;; \ 45(p15) ld8.s reg = [r0] 46 47 48 .global flushrs 49 .proc flushrs 50flushrs: 51 flushrs;; 52 br.ret.sptk.many rp 53 .endp flushrs 54 55 /* Save r4-r7 into stacked registers, load them up with the 56 values passed via the pointer in in1 and then call the 57 function passed via the pointer in in0. */ 58 59 .global save_static_to_stacked 60 .proc save_static_to_stacked 61save_static_to_stacked: 62 .prologue 63 .regstk 2, 7, 2, 0 64 .save ar.pfs, loc0 65 alloc loc0 = ar.pfs, 2, 7, 2, 0 66 .save rp, loc1 67 mov loc1 = rp 68 .spillreg r4, loc2 69 mov loc2 = r4 70 .spillreg r5, loc3 71 mov loc3 = r5 72 .spillreg r6, loc4 73 mov loc4 = r6 74 .spillreg r7, loc5 75 mov loc5 = r7 76 .body 77 LOAD_VAL(r4) 78 LOAD_VAL(r5) 79 LOAD_VAL(r6) 80 LOAD_VAL(r7) 81 CALL_NEXT(loc6) 82 83 mov r4 = loc2 84 mov r5 = loc3 85 mov r6 = loc4 86 mov r7 = loc5 87 88 mov ar.pfs = loc0 89 mov rp = loc1 90 br.ret.sptk.many rp 91 .endp save_static_to_stacked 92 93 /* Save f2 to the memory stack, save r4 to f2, then load 94 r4 with the value passed via in1 and call the function 95 passed via in0. */ 96 97 .global save_static_to_fr 98 .proc save_static_to_fr 99save_static_to_fr: 100 .prologue 101 .regstk 2, 3, 2, 0 102 .save ar.pfs, loc0 103 alloc loc0 = ar.pfs, 2, 3, 2, 0 104 .save rp, loc1 105 mov loc1 = rp 106 .fframe 16 107 .spillpsp f2, 0 108 stf.spill [sp] = f2, -16 109 .spillreg r4, f2 110 setf.sig f2 = r4 111 112 .body 113 114 ld8 r4 = [in1], 8;; 115 tbit.nz p6, p0 = r4, 0;; 116(p6) ld8.s r4 = [r0] 117 118 CALL_NEXT(loc2) 119 120 getf.sig r4 = f2 // restore r4 121 .restore sp 122 add sp = 16, sp;; 123 ldf.fill f2 = [sp] // restore r2 124 125 mov ar.pfs = loc0 126 mov rp = loc1 127 br.ret.sptk.many rp 128 .endp save_static_to_fr 129 130 /* If r4 is not a NaT, save b3 to a stacked register and 131 then save r4 in b3. The non-NaTness of r4 is saved in 132 p1. */ 133 134 .global save_static_to_br 135 .proc save_static_to_br 136save_static_to_br: 137 .prologue 138 .regstk 2, 6, 2, 0 139 .save ar.pfs, loc0 140 alloc loc0 = ar.pfs, 2, 6, 2, 0 141 .save rp, loc1 142 mov loc1 = rp 143 144 .save pr, loc2 145 mov loc2 = pr // save predicates 146 147 .spillreg b3, loc3 148 mov loc3 = b3 149 150 tnat.z p1, p2 = r4;; 151 .spillreg.p p1, r4, b3 152(p1) mov b3 = r4 153 .spillreg.p p2, r4, loc4 154(p2) mov loc4 = r4 155 156 .body 157 158 LOAD_VAL(r4) 159 CALL_NEXT(loc5) 160 161 .pred.rel.mutex p1, p2 162(p1) mov r4 = b3 // restore r4 163(p2) mov r4 = loc4 164 165 mov ar.pfs = loc0 166 mov rp = loc1 167 mov pr = loc2, -1 168 mov b3 = loc3 // restore b3 169 br.ret.sptk.many rp 170 .endp save_static_to_br 171 172 /* Spill r4 into memory and then save r5 in r4. */ 173 174 .global save_static_to_mem 175 .proc save_static_to_mem 176save_static_to_mem: 177 .prologue 178 .regstk 2, 4, 2, 0 179 .save ar.pfs, loc0 180 alloc loc0 = ar.pfs, 2, 4, 2, 0 181 .save rp, loc1 182 mov loc1 = rp 183 .save ar.unat, loc2 184 mov loc2 = ar.unat 185 186 .fframe 16 187 .spillpsp r4, 0 188 st8.spill [sp] = r4, -16 189 190 .spillreg r5, r4 191 mov r4 = r5 192 193 .body 194 195 LOAD_VAL(r5) 196 CALL_NEXT(loc3) 197 198 mov r5 = r4 // restore r5 199 .restore sp 200 add sp = 16, sp;; 201 ld8.fill r4 = [sp] // restore r4 202 203 mov ar.pfs = loc0 204 mov rp = loc1 205 mov ar.unat = loc2 // restore ar.unat 206 br.ret.sptk.many rp 207 .endp save_static_to_mem 208 209 /* Spill r6 into memory and save primary ar.unat in a register. */ 210 211 .global save_static_to_mem2 212 .proc save_static_to_mem2 213save_static_to_mem2: 214 .prologue 215 .regstk 2, 5, 2, 0 216 .save ar.pfs, loc0 217 alloc loc0 = ar.pfs, 2, 5, 2, 0 218 .save rp, loc1 219 mov loc1 = rp 220 .save ar.unat, loc2 221 mov loc2 = ar.unat 222 223 .fframe 16 224 .spillpsp r6, 0 225 st8.spill [sp] = r6, -16;; 226 .save @priunat, loc3 227 mov loc3 = ar.unat 228 mov ar.unat = 0 // trash ar.unat 229 230 .body 231 232 LOAD_VAL(r6) 233 CALL_NEXT(loc4) 234 235 mov ar.unat = loc3 // restore primary UNaT 236 .restore sp 237 add sp = 16, sp;; 238 ld8.fill r6 = [sp] // restore r6 239 240 mov ar.pfs = loc0 241 mov rp = loc1 242 mov ar.unat = loc2 // restore ar.unat 243 br.ret.sptk.many rp 244 .endp save_static_to_mem2 245 246 /* Spill r6 into memory and save primary ar.unat in memory. */ 247 248 .global save_static_to_mem3 249 .proc save_static_to_mem3 250save_static_to_mem3: 251 .prologue 252 .regstk 2, 5, 2, 0 253 .save ar.pfs, loc0 254 alloc loc0 = ar.pfs, 2, 5, 2, 0 255 .save rp, loc1 256 mov loc1 = rp 257 .save ar.unat, loc2 258 mov loc2 = ar.unat 259 260 add r2 = 8, sp 261 .fframe 16 262 .spillpsp r6, 0 263 st8.spill [sp] = r6, -16;; 264 mov r3 = ar.unat;; 265 .savepsp @priunat, -8 266 st8 [r2] = r3 267 mov ar.unat = 0 // trash ar.unat 268 269 .body 270 271 LOAD_VAL(r6) 272 CALL_NEXT(loc4) 273 274 add r2 = 24, sp;; 275 ld8 r3 = [r2];; 276 mov ar.unat = r3 // restore primary UNaT 277 .restore sp 278 add sp = 16, sp;; 279 ld8.fill r6 = [sp] // restore r6 280 281 mov ar.pfs = loc0 282 mov rp = loc1 283 mov ar.unat = loc2 // restore ar.unat 284 br.ret.sptk.many rp 285 .endp save_static_to_mem3 286 287 /* Spill r6 into memory and save primary ar.unat in register, 288 then in memory. */ 289 290 .global save_static_to_mem4 291 .proc save_static_to_mem4 292save_static_to_mem4: 293 .prologue 294 .regstk 2, 5, 2, 0 295 .save ar.pfs, loc0 296 alloc loc0 = ar.pfs, 2, 5, 2, 0 297 .save rp, loc1 298 mov loc1 = rp 299 .save ar.unat, loc2 300 mov loc2 = ar.unat 301 302 add r2 = 8, sp 303 .fframe 16 304 .spillpsp r6, 0 305 st8.spill [sp] = r6, -16;; 306 .save @priunat, r3 307 mov r3 = ar.unat;; 308 mov ar.unat = 0 // trash ar.unat 309 .savepsp @priunat, -8 310 st8 [r2] = r3 311 mov r3 = r0 // trash register pri UNaT location 312 .body 313 314 LOAD_VAL(r6) 315 CALL_NEXT(loc4) 316 317 add r2 = 24, sp;; 318 ld8 r3 = [r2];; 319 mov ar.unat = r3 // restore primary UNaT 320 .restore sp 321 add sp = 16, sp;; 322 ld8.fill r6 = [sp] // restore r6 323 324 mov ar.pfs = loc0 325 mov rp = loc1 326 mov ar.unat = loc2 // restore ar.unat 327 br.ret.sptk.many rp 328 .endp save_static_to_mem4 329 330 /* Spill r6 into memory and save primary ar.unat in register, 331 then in memory. */ 332 333 .global save_static_to_mem5 334 .proc save_static_to_mem5 335save_static_to_mem5: 336 .prologue 337 .regstk 2, 5, 2, 0 338 .save ar.pfs, loc0 339 alloc loc0 = ar.pfs, 2, 5, 2, 0 340 .save rp, loc1 341 mov loc1 = rp 342 .save ar.unat, loc2 343 mov loc2 = ar.unat 344 345 add r2 = 8, sp 346 .fframe 16 347 .spillpsp r6, 0 348 st8.spill [sp] = r6, -16;; 349 mov r3 = ar.unat;; 350 mov ar.unat = 0 // trash ar.unat 351 .savepsp @priunat, -8 352 st8 [r2] = r3 353 .save @priunat, loc3 354 mov loc3 = r3 355 st8 [r2] = r0 // trash memory pri UNaT location 356 .body 357 358 LOAD_VAL(r6) 359 CALL_NEXT(loc4) 360 361 add r2 = 24, sp;; 362 ld8 r3 = [r2];; 363 mov ar.unat = loc3 // restore primary UNaT 364 .restore sp 365 add sp = 16, sp;; 366 ld8.fill r6 = [sp] // restore r6 367 368 mov ar.pfs = loc0 369 mov rp = loc1 370 mov ar.unat = loc2 // restore ar.unat 371 br.ret.sptk.many rp 372 .endp save_static_to_mem5 373 374 /* Save r4-r7 to various scratch registers, then trigger 375 a segfault. */ 376 377 .global save_static_to_scratch 378 .proc save_static_to_scratch 379save_static_to_scratch: 380 .prologue 381 382 .spillreg r4, r16 383 mov r16 = r4 // save r4 in r16 384 tnat.nz p6, p7 = r5;; 385 .spillreg.p p6, r5, f31 386(p6) setf.sig f31 = r5 // save r5 in f31 if it's a NaT 387 .spillreg.p p7, r5, b6 388(p7) mov b6 = r5 // in b6 if it not 389 .spillreg r6, f32 390 setf.sig f32 = r6 // save r6 in f32 (fph partition) 391 .spillsp r7, 0 392 st8.spill [sp] = r7 // save r7 in the scratch stack space 393 .spillreg f4, f6 394 mov f6 = f4;; 395 .body 396 397 ld8 r2 = [in1] 398 ;; 399 mov ar.ec = r2 400 401 LOAD_VAL(r4) 402 LOAD_VAL(r5) 403 LOAD_VAL(r6) 404 LOAD_VAL(r7) 405 setf.sig f4 = r4 406 407 /* Now force a SIGSEGV. Make sure the ld8 is at the beginning of a 408 bundle, so the signal-handler can skip over it simply by 409 incrementing the IP. */ 410 { 411 .mmi 412 ld8 r2 = [r0] 413 nop.m 0 414 nop.i 0 ;; 415 } 416 417 mov f4 = f6 418 mov r4 = r16 419 .pred.rel.mutex p6, p7 420(p6) getf.sig r5 = f31 421(p7) mov r5 = b6 422 getf.sig r6 = f32 423 ld8.fill r7 = [sp] 424 425 br.ret.sptk.many rp 426 .endp save_static_to_scratch 427 428 /* Rotate registers a bit in a vain attempt to sow some confusion. 429 Care must be taken not to write any rotating general register 430 after rotation, because we keep the preserved state 431 there... */ 432 433 .global rotate_regs 434 .proc rotate_regs 435rotate_regs: 436 .prologue 437 .regstk 2, 14, 2, 16 438 .save ar.pfs, loc0 439 alloc loc0 = ar.pfs, 2, 14, 2, 16 440 .save rp, loc1 441 mov loc1 = rp 442 .save pr, loc2 443 mov loc2 = pr 444 .save ar.lc, loc3 445 mov loc3 = ar.lc 446 .spillreg r4, loc4 447 mov loc4 = r4 448 449 ld8 r2 = [in1], 8;; 450 mov pr = r2, -1 451 452 ld8 r2 = [in1], 8;; 453 mov r8 = in0 454 mov r9 = in1 455 and r2 = 127, r2;; 456 mov ar.ec = 0 457 mov ar.lc = r2;; 458 459 // use p6 to preserve p63 as it gets rotated into p16: 460(p16) cmp.eq.unc p6,p0 = r0,r0;; 4611: 462(p6) cmp.eq.unc p16,p0 = r0,r0 463(p63) cmp.eq.unc p6,p0 = r0,r0 464 br.ctop.dptk.few 1b;; 465 466(p6) cmp.eq.unc p63,p0 = r0,r0 467 468 CALL_NEXT_PTR(r4, r8, r9) 469 470 clrrrb 471 472 mov ar.pfs = loc0 473 mov rp = loc1 474 mov pr = loc2, -1 475 mov ar.lc = loc3 476 mov r4 = loc4 477 br.ret.sptk.many rp 478 479 .endp rotate_regs 480 481 .global save_pr 482 .proc save_pr 483save_pr: 484 .prologue 485 .regstk 2, 4, 2, 0 486 .save ar.pfs, loc0 487 alloc loc0 = ar.pfs, 2, 4, 2, 0 488 .save rp, loc1 489 mov loc1 = rp 490 .save pr, loc2 491 mov loc2 = pr 492 493 ld8 r2 = [in1], 8;; 494 mov pr = r2, -1 495 496 CALL_NEXT(loc3) 497 498 mov ar.pfs = loc0 499 mov rp = loc1 500 mov pr = loc2, -1 501 br.ret.sptk.many rp 502 503 .endp save_pr 504 505#ifdef __linux__ 506 /* We do not need executable stack. */ 507 .section .note.GNU-stack,"",@progbits 508#endif 509