1/* ----------------------------------------------------------------------- 2 unix.S - Copyright (c) 1998, 2008 Red Hat, Inc. 3 Copyright (c) 2000 Hewlett Packard Company 4 5 IA64/unix Foreign Function Interface 6 7 Primary author: Hans Boehm, HP Labs 8 9 Loosely modeled on Cygnus code for other platforms. 10 11 Permission is hereby granted, free of charge, to any person obtaining 12 a copy of this software and associated documentation files (the 13 ``Software''), to deal in the Software without restriction, including 14 without limitation the rights to use, copy, modify, merge, publish, 15 distribute, sublicense, and/or sell copies of the Software, and to 16 permit persons to whom the Software is furnished to do so, subject to 17 the following conditions: 18 19 The above copyright notice and this permission notice shall be included 20 in all copies or substantial portions of the Software. 21 22 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 26 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 27 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 29 DEALINGS IN THE SOFTWARE. 30 ----------------------------------------------------------------------- */ 31 32#define LIBFFI_ASM 33#include <fficonfig.h> 34#include <ffi.h> 35#include "ia64_flags.h" 36 37 .pred.safe_across_calls p1-p5,p16-p63 38.text 39 40/* int ffi_call_unix (struct ia64_args *stack, PTR64 rvalue, 41 void (*fn)(void), int flags); 42 */ 43 44 .align 16 45 .global ffi_call_unix 46 .proc ffi_call_unix 47ffi_call_unix: 48 .prologue 49 /* Bit o trickiness. We actually share a stack frame with ffi_call. 50 Rely on the fact that ffi_call uses a vframe and don't bother 51 tracking one here at all. */ 52 .fframe 0 53 .save ar.pfs, r36 // loc0 54 alloc loc0 = ar.pfs, 4, 3, 8, 0 55 .save rp, loc1 56 mov loc1 = b0 57 .body 58 add r16 = 16, in0 59 mov loc2 = gp 60 mov r8 = in1 61 ;; 62 63 /* Load up all of the argument registers. */ 64 ldf.fill f8 = [in0], 32 65 ldf.fill f9 = [r16], 32 66 ;; 67 ldf.fill f10 = [in0], 32 68 ldf.fill f11 = [r16], 32 69 ;; 70 ldf.fill f12 = [in0], 32 71 ldf.fill f13 = [r16], 32 72 ;; 73 ldf.fill f14 = [in0], 32 74 ldf.fill f15 = [r16], 24 75 ;; 76 ld8 out0 = [in0], 16 77 ld8 out1 = [r16], 16 78 ;; 79 ld8 out2 = [in0], 16 80 ld8 out3 = [r16], 16 81 ;; 82 ld8 out4 = [in0], 16 83 ld8 out5 = [r16], 16 84 ;; 85 ld8 out6 = [in0] 86 ld8 out7 = [r16] 87 ;; 88 89 /* Deallocate the register save area from the stack frame. */ 90 mov sp = in0 91 92 /* Call the target function. */ 93 ld8 r16 = [in2], 8 94 ;; 95 ld8 gp = [in2] 96 mov b6 = r16 97 br.call.sptk.many b0 = b6 98 ;; 99 100 /* Dispatch to handle return value. */ 101 mov gp = loc2 102 zxt1 r16 = in3 103 ;; 104 mov ar.pfs = loc0 105 addl r18 = @ltoffx(.Lst_table), gp 106 ;; 107 ld8.mov r18 = [r18], .Lst_table 108 mov b0 = loc1 109 ;; 110 shladd r18 = r16, 3, r18 111 ;; 112 ld8 r17 = [r18] 113 shr in3 = in3, 8 114 ;; 115 add r17 = r17, r18 116 ;; 117 mov b6 = r17 118 br b6 119 ;; 120 121.Lst_void: 122 br.ret.sptk.many b0 123 ;; 124.Lst_uint8: 125 zxt1 r8 = r8 126 ;; 127 st8 [in1] = r8 128 br.ret.sptk.many b0 129 ;; 130.Lst_sint8: 131 sxt1 r8 = r8 132 ;; 133 st8 [in1] = r8 134 br.ret.sptk.many b0 135 ;; 136.Lst_uint16: 137 zxt2 r8 = r8 138 ;; 139 st8 [in1] = r8 140 br.ret.sptk.many b0 141 ;; 142.Lst_sint16: 143 sxt2 r8 = r8 144 ;; 145 st8 [in1] = r8 146 br.ret.sptk.many b0 147 ;; 148.Lst_uint32: 149 zxt4 r8 = r8 150 ;; 151 st8 [in1] = r8 152 br.ret.sptk.many b0 153 ;; 154.Lst_sint32: 155 sxt4 r8 = r8 156 ;; 157 st8 [in1] = r8 158 br.ret.sptk.many b0 159 ;; 160.Lst_int64: 161 st8 [in1] = r8 162 br.ret.sptk.many b0 163 ;; 164.Lst_float: 165 stfs [in1] = f8 166 br.ret.sptk.many b0 167 ;; 168.Lst_double: 169 stfd [in1] = f8 170 br.ret.sptk.many b0 171 ;; 172.Lst_ldouble: 173 stfe [in1] = f8 174 br.ret.sptk.many b0 175 ;; 176 177.Lst_small_struct: 178 cmp.lt p6, p0 = 8, in3 179 cmp.lt p7, p0 = 16, in3 180 cmp.lt p8, p0 = 24, in3 181 ;; 182 add r16 = 8, sp 183 add r17 = 16, sp 184 add r18 = 24, sp 185 ;; 186 st8 [sp] = r8 187(p6) st8 [r16] = r9 188 mov out0 = in1 189(p7) st8 [r17] = r10 190(p8) st8 [r18] = r11 191 mov out1 = sp 192 mov out2 = in3 193 ;; 194 // ia64 software calling convention requires 195 // top 16 bytes of stack to be scratch space 196 // PLT resolver uses that scratch space at 197 // 'memcpy' symbol reolution time 198 add sp = -16, sp 199 br.call.sptk.many b0 = memcpy# 200 ;; 201 mov ar.pfs = loc0 202 mov b0 = loc1 203 mov gp = loc2 204 br.ret.sptk.many b0 205 206.Lst_hfa_float: 207 add r16 = 4, in1 208 cmp.lt p6, p0 = 4, in3 209 ;; 210 stfs [in1] = f8, 8 211(p6) stfs [r16] = f9, 8 212 cmp.lt p7, p0 = 8, in3 213 cmp.lt p8, p0 = 12, in3 214 ;; 215(p7) stfs [in1] = f10, 8 216(p8) stfs [r16] = f11, 8 217 cmp.lt p9, p0 = 16, in3 218 cmp.lt p10, p0 = 20, in3 219 ;; 220(p9) stfs [in1] = f12, 8 221(p10) stfs [r16] = f13, 8 222 cmp.lt p6, p0 = 24, in3 223 cmp.lt p7, p0 = 28, in3 224 ;; 225(p6) stfs [in1] = f14 226(p7) stfs [r16] = f15 227 br.ret.sptk.many b0 228 ;; 229 230.Lst_hfa_double: 231 add r16 = 8, in1 232 cmp.lt p6, p0 = 8, in3 233 ;; 234 stfd [in1] = f8, 16 235(p6) stfd [r16] = f9, 16 236 cmp.lt p7, p0 = 16, in3 237 cmp.lt p8, p0 = 24, in3 238 ;; 239(p7) stfd [in1] = f10, 16 240(p8) stfd [r16] = f11, 16 241 cmp.lt p9, p0 = 32, in3 242 cmp.lt p10, p0 = 40, in3 243 ;; 244(p9) stfd [in1] = f12, 16 245(p10) stfd [r16] = f13, 16 246 cmp.lt p6, p0 = 48, in3 247 cmp.lt p7, p0 = 56, in3 248 ;; 249(p6) stfd [in1] = f14 250(p7) stfd [r16] = f15 251 br.ret.sptk.many b0 252 ;; 253 254.Lst_hfa_ldouble: 255 add r16 = 16, in1 256 cmp.lt p6, p0 = 16, in3 257 ;; 258 stfe [in1] = f8, 32 259(p6) stfe [r16] = f9, 32 260 cmp.lt p7, p0 = 32, in3 261 cmp.lt p8, p0 = 48, in3 262 ;; 263(p7) stfe [in1] = f10, 32 264(p8) stfe [r16] = f11, 32 265 cmp.lt p9, p0 = 64, in3 266 cmp.lt p10, p0 = 80, in3 267 ;; 268(p9) stfe [in1] = f12, 32 269(p10) stfe [r16] = f13, 32 270 cmp.lt p6, p0 = 96, in3 271 cmp.lt p7, p0 = 112, in3 272 ;; 273(p6) stfe [in1] = f14 274(p7) stfe [r16] = f15 275 br.ret.sptk.many b0 276 ;; 277 278 .endp ffi_call_unix 279 280 .align 16 281 .global ffi_closure_unix 282 .proc ffi_closure_unix 283 284#define FRAME_SIZE (8*16 + 8*8 + 8*16) 285 286ffi_closure_unix: 287 .prologue 288 .save ar.pfs, r40 // loc0 289 alloc loc0 = ar.pfs, 8, 4, 4, 0 290 .fframe FRAME_SIZE 291 add r12 = -FRAME_SIZE, r12 292 .save rp, loc1 293 mov loc1 = b0 294 .save ar.unat, loc2 295 mov loc2 = ar.unat 296 .body 297 298 /* Retrieve closure pointer and real gp. */ 299#ifdef _ILP32 300 addp4 out0 = 0, gp 301 addp4 gp = 16, gp 302#else 303 mov out0 = gp 304 add gp = 16, gp 305#endif 306 ;; 307 ld8 gp = [gp] 308 309 /* Spill all of the possible argument registers. */ 310 add r16 = 16 + 8*16, sp 311 add r17 = 16 + 8*16 + 16, sp 312 ;; 313 stf.spill [r16] = f8, 32 314 stf.spill [r17] = f9, 32 315 mov loc3 = gp 316 ;; 317 stf.spill [r16] = f10, 32 318 stf.spill [r17] = f11, 32 319 ;; 320 stf.spill [r16] = f12, 32 321 stf.spill [r17] = f13, 32 322 ;; 323 stf.spill [r16] = f14, 32 324 stf.spill [r17] = f15, 24 325 ;; 326 .mem.offset 0, 0 327 st8.spill [r16] = in0, 16 328 .mem.offset 8, 0 329 st8.spill [r17] = in1, 16 330 add out1 = 16 + 8*16, sp 331 ;; 332 .mem.offset 0, 0 333 st8.spill [r16] = in2, 16 334 .mem.offset 8, 0 335 st8.spill [r17] = in3, 16 336 add out2 = 16, sp 337 ;; 338 .mem.offset 0, 0 339 st8.spill [r16] = in4, 16 340 .mem.offset 8, 0 341 st8.spill [r17] = in5, 16 342 mov out3 = r8 343 ;; 344 .mem.offset 0, 0 345 st8.spill [r16] = in6 346 .mem.offset 8, 0 347 st8.spill [r17] = in7 348 349 /* Invoke ffi_closure_unix_inner for the hard work. */ 350 br.call.sptk.many b0 = ffi_closure_unix_inner 351 ;; 352 353 /* Dispatch to handle return value. */ 354 mov gp = loc3 355 zxt1 r16 = r8 356 ;; 357 addl r18 = @ltoffx(.Lld_table), gp 358 mov ar.pfs = loc0 359 ;; 360 ld8.mov r18 = [r18], .Lld_table 361 mov b0 = loc1 362 ;; 363 shladd r18 = r16, 3, r18 364 mov ar.unat = loc2 365 ;; 366 ld8 r17 = [r18] 367 shr r8 = r8, 8 368 ;; 369 add r17 = r17, r18 370 add r16 = 16, sp 371 ;; 372 mov b6 = r17 373 br b6 374 ;; 375 .label_state 1 376 377.Lld_void: 378 .restore sp 379 add sp = FRAME_SIZE, sp 380 br.ret.sptk.many b0 381 ;; 382.Lld_int: 383 .body 384 .copy_state 1 385 ld8 r8 = [r16] 386 .restore sp 387 add sp = FRAME_SIZE, sp 388 br.ret.sptk.many b0 389 ;; 390.Lld_float: 391 .body 392 .copy_state 1 393 ldfs f8 = [r16] 394 .restore sp 395 add sp = FRAME_SIZE, sp 396 br.ret.sptk.many b0 397 ;; 398.Lld_double: 399 .body 400 .copy_state 1 401 ldfd f8 = [r16] 402 .restore sp 403 add sp = FRAME_SIZE, sp 404 br.ret.sptk.many b0 405 ;; 406.Lld_ldouble: 407 .body 408 .copy_state 1 409 ldfe f8 = [r16] 410 .restore sp 411 add sp = FRAME_SIZE, sp 412 br.ret.sptk.many b0 413 ;; 414 415.Lld_small_struct: 416 .body 417 .copy_state 1 418 add r17 = 8, r16 419 cmp.lt p6, p0 = 8, r8 420 cmp.lt p7, p0 = 16, r8 421 cmp.lt p8, p0 = 24, r8 422 ;; 423 ld8 r8 = [r16], 16 424(p6) ld8 r9 = [r17], 16 425 ;; 426(p7) ld8 r10 = [r16] 427(p8) ld8 r11 = [r17] 428 .restore sp 429 add sp = FRAME_SIZE, sp 430 br.ret.sptk.many b0 431 ;; 432 433.Lld_hfa_float: 434 .body 435 .copy_state 1 436 add r17 = 4, r16 437 cmp.lt p6, p0 = 4, r8 438 ;; 439 ldfs f8 = [r16], 8 440(p6) ldfs f9 = [r17], 8 441 cmp.lt p7, p0 = 8, r8 442 cmp.lt p8, p0 = 12, r8 443 ;; 444(p7) ldfs f10 = [r16], 8 445(p8) ldfs f11 = [r17], 8 446 cmp.lt p9, p0 = 16, r8 447 cmp.lt p10, p0 = 20, r8 448 ;; 449(p9) ldfs f12 = [r16], 8 450(p10) ldfs f13 = [r17], 8 451 cmp.lt p6, p0 = 24, r8 452 cmp.lt p7, p0 = 28, r8 453 ;; 454(p6) ldfs f14 = [r16] 455(p7) ldfs f15 = [r17] 456 .restore sp 457 add sp = FRAME_SIZE, sp 458 br.ret.sptk.many b0 459 ;; 460 461.Lld_hfa_double: 462 .body 463 .copy_state 1 464 add r17 = 8, r16 465 cmp.lt p6, p0 = 8, r8 466 ;; 467 ldfd f8 = [r16], 16 468(p6) ldfd f9 = [r17], 16 469 cmp.lt p7, p0 = 16, r8 470 cmp.lt p8, p0 = 24, r8 471 ;; 472(p7) ldfd f10 = [r16], 16 473(p8) ldfd f11 = [r17], 16 474 cmp.lt p9, p0 = 32, r8 475 cmp.lt p10, p0 = 40, r8 476 ;; 477(p9) ldfd f12 = [r16], 16 478(p10) ldfd f13 = [r17], 16 479 cmp.lt p6, p0 = 48, r8 480 cmp.lt p7, p0 = 56, r8 481 ;; 482(p6) ldfd f14 = [r16] 483(p7) ldfd f15 = [r17] 484 .restore sp 485 add sp = FRAME_SIZE, sp 486 br.ret.sptk.many b0 487 ;; 488 489.Lld_hfa_ldouble: 490 .body 491 .copy_state 1 492 add r17 = 16, r16 493 cmp.lt p6, p0 = 16, r8 494 ;; 495 ldfe f8 = [r16], 32 496(p6) ldfe f9 = [r17], 32 497 cmp.lt p7, p0 = 32, r8 498 cmp.lt p8, p0 = 48, r8 499 ;; 500(p7) ldfe f10 = [r16], 32 501(p8) ldfe f11 = [r17], 32 502 cmp.lt p9, p0 = 64, r8 503 cmp.lt p10, p0 = 80, r8 504 ;; 505(p9) ldfe f12 = [r16], 32 506(p10) ldfe f13 = [r17], 32 507 cmp.lt p6, p0 = 96, r8 508 cmp.lt p7, p0 = 112, r8 509 ;; 510(p6) ldfe f14 = [r16] 511(p7) ldfe f15 = [r17] 512 .restore sp 513 add sp = FRAME_SIZE, sp 514 br.ret.sptk.many b0 515 ;; 516 517 .endp ffi_closure_unix 518 519 .section .rodata 520 .align 8 521.Lst_table: 522 data8 @pcrel(.Lst_void) // FFI_TYPE_VOID 523 data8 @pcrel(.Lst_sint32) // FFI_TYPE_INT 524 data8 @pcrel(.Lst_float) // FFI_TYPE_FLOAT 525 data8 @pcrel(.Lst_double) // FFI_TYPE_DOUBLE 526 data8 @pcrel(.Lst_ldouble) // FFI_TYPE_LONGDOUBLE 527 data8 @pcrel(.Lst_uint8) // FFI_TYPE_UINT8 528 data8 @pcrel(.Lst_sint8) // FFI_TYPE_SINT8 529 data8 @pcrel(.Lst_uint16) // FFI_TYPE_UINT16 530 data8 @pcrel(.Lst_sint16) // FFI_TYPE_SINT16 531 data8 @pcrel(.Lst_uint32) // FFI_TYPE_UINT32 532 data8 @pcrel(.Lst_sint32) // FFI_TYPE_SINT32 533 data8 @pcrel(.Lst_int64) // FFI_TYPE_UINT64 534 data8 @pcrel(.Lst_int64) // FFI_TYPE_SINT64 535 data8 @pcrel(.Lst_void) // FFI_TYPE_STRUCT 536 data8 @pcrel(.Lst_int64) // FFI_TYPE_POINTER 537 data8 @pcrel(.Lst_void) // FFI_TYPE_COMPLEX (not implemented) 538 data8 @pcrel(.Lst_small_struct) // FFI_IA64_TYPE_SMALL_STRUCT 539 data8 @pcrel(.Lst_hfa_float) // FFI_IA64_TYPE_HFA_FLOAT 540 data8 @pcrel(.Lst_hfa_double) // FFI_IA64_TYPE_HFA_DOUBLE 541 data8 @pcrel(.Lst_hfa_ldouble) // FFI_IA64_TYPE_HFA_LDOUBLE 542 543.Lld_table: 544 data8 @pcrel(.Lld_void) // FFI_TYPE_VOID 545 data8 @pcrel(.Lld_int) // FFI_TYPE_INT 546 data8 @pcrel(.Lld_float) // FFI_TYPE_FLOAT 547 data8 @pcrel(.Lld_double) // FFI_TYPE_DOUBLE 548 data8 @pcrel(.Lld_ldouble) // FFI_TYPE_LONGDOUBLE 549 data8 @pcrel(.Lld_int) // FFI_TYPE_UINT8 550 data8 @pcrel(.Lld_int) // FFI_TYPE_SINT8 551 data8 @pcrel(.Lld_int) // FFI_TYPE_UINT16 552 data8 @pcrel(.Lld_int) // FFI_TYPE_SINT16 553 data8 @pcrel(.Lld_int) // FFI_TYPE_UINT32 554 data8 @pcrel(.Lld_int) // FFI_TYPE_SINT32 555 data8 @pcrel(.Lld_int) // FFI_TYPE_UINT64 556 data8 @pcrel(.Lld_int) // FFI_TYPE_SINT64 557 data8 @pcrel(.Lld_void) // FFI_TYPE_STRUCT 558 data8 @pcrel(.Lld_int) // FFI_TYPE_POINTER 559 data8 @pcrel(.Lld_void) // FFI_TYPE_COMPLEX (not implemented) 560 data8 @pcrel(.Lld_small_struct) // FFI_IA64_TYPE_SMALL_STRUCT 561 data8 @pcrel(.Lld_hfa_float) // FFI_IA64_TYPE_HFA_FLOAT 562 data8 @pcrel(.Lld_hfa_double) // FFI_IA64_TYPE_HFA_DOUBLE 563 data8 @pcrel(.Lld_hfa_ldouble) // FFI_IA64_TYPE_HFA_LDOUBLE 564 565#if defined __ELF__ && defined __linux__ 566 .section .note.GNU-stack,"",@progbits 567#endif 568