1/* ----------------------------------------------------------------------- 2 v8.S - Copyright (c) 2013 The Written Word, Inc. 3 Copyright (c) 1996, 1997, 2003, 2004, 2008 Red Hat, Inc. 4 5 SPARC Foreign Function Interface 6 7 Permission is hereby granted, free of charge, to any person obtaining 8 a copy of this software and associated documentation files (the 9 ``Software''), to deal in the Software without restriction, including 10 without limitation the rights to use, copy, modify, merge, publish, 11 distribute, sublicense, and/or sell copies of the Software, and to 12 permit persons to whom the Software is furnished to do so, subject to 13 the following conditions: 14 15 The above copyright notice and this permission notice shall be included 16 in all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 ----------------------------------------------------------------------- */ 27 28#define LIBFFI_ASM 29#include <fficonfig.h> 30#include <ffi.h> 31#include "internal.h" 32 33#ifndef SPARC64 34 35#define C2(X, Y) X ## Y 36#define C1(X, Y) C2(X, Y) 37 38#ifdef __USER_LABEL_PREFIX__ 39# define C(Y) C1(__USER_LABEL_PREFIX__, Y) 40#else 41# define C(Y) Y 42#endif 43#define L(Y) C1(.L, Y) 44 45 .text 46 47#ifndef __GNUC__ 48 .align 8 49 .globl C(ffi_flush_icache) 50 .type C(ffi_flush_icache),#function 51 FFI_HIDDEN(C(ffi_flush_icache)) 52 53C(ffi_flush_icache): 541: iflush %o0 55 iflush %o+8 56 nop 57 nop 58 nop 59 nop 60 nop 61 retl 62 nop 63 .size C(ffi_flush_icache), . - C(ffi_flush_icache) 64#endif 65 66#if defined(__sun__) && defined(__svr4__) 67# define E(INDEX) .align 16 68#else 69# define E(INDEX) .align 16; .org 2b + INDEX * 16 70#endif 71 72 .align 8 73 .globl C(ffi_call_v8) 74 .type C(ffi_call_v8),#function 75 FFI_HIDDEN(C(ffi_call_v8)) 76 77C(ffi_call_v8): 78.LUW0: 79 ! Allocate a stack frame sized by ffi_call. 80 save %sp, %o4, %sp 81.LUW1: 82 mov %i0, %o0 ! copy cif 83 add %sp, 64+32, %o1 ! load args area 84 mov %i2, %o2 ! copy rvalue 85 call C(ffi_prep_args_v8) 86 mov %i3, %o3 ! copy avalue 87 88 add %sp, 32, %sp ! deallocate prep frame 89 and %o0, SPARC_FLAG_RET_MASK, %l0 ! save return type 90 srl %o0, SPARC_SIZEMASK_SHIFT, %l1 ! save return size 91 ld [%sp+64+4], %o0 ! load all argument registers 92 ld [%sp+64+8], %o1 93 ld [%sp+64+12], %o2 94 ld [%sp+64+16], %o3 95 cmp %l0, SPARC_RET_STRUCT ! struct return needs an unimp 4 96 ld [%sp+64+20], %o4 97 be 8f 98 ld [%sp+64+24], %o5 99 100 ! Call foreign function 101 call %i1 102 mov %i5, %g2 ! load static chain 103 1040: call 1f ! load pc in %o7 105 sll %l0, 4, %l0 1061: add %o7, %l0, %o7 ! o7 = 0b + ret_type*16 107 jmp %o7+(2f-0b) 108 nop 109 110 ! Note that each entry is 4 insns, enforced by the E macro. 111 .align 16 1122: 113E(SPARC_RET_VOID) 114 ret 115 restore 116E(SPARC_RET_STRUCT) 117 unimp 118E(SPARC_RET_UINT8) 119 and %o0, 0xff, %o0 120 st %o0, [%i2] 121 ret 122 restore 123E(SPARC_RET_SINT8) 124 sll %o0, 24, %o0 125 b 7f 126 sra %o0, 24, %o0 127E(SPARC_RET_UINT16) 128 sll %o0, 16, %o0 129 b 7f 130 srl %o0, 16, %o0 131E(SPARC_RET_SINT16) 132 sll %o0, 16, %o0 133 b 7f 134 sra %o0, 16, %o0 135E(SPARC_RET_UINT32) 1367: st %o0, [%i2] 137 ret 138 restore 139E(SP_V8_RET_CPLX16) 140 sth %o0, [%i2+2] 141 b 9f 142 srl %o0, 16, %o0 143E(SPARC_RET_INT64) 144 st %o0, [%i2] 145 st %o1, [%i2+4] 146 ret 147 restore 148E(SPARC_RET_INT128) 149 std %o0, [%i2] 150 std %o2, [%i2+8] 151 ret 152 restore 153E(SPARC_RET_F_8) 154 st %f7, [%i2+7*4] 155 nop 156 st %f6, [%i2+6*4] 157 nop 158E(SPARC_RET_F_6) 159 st %f5, [%i2+5*4] 160 nop 161 st %f4, [%i2+4*4] 162 nop 163E(SPARC_RET_F_4) 164 st %f3, [%i2+3*4] 165 nop 166 st %f2, [%i2+2*4] 167 nop 168E(SPARC_RET_F_2) 169 st %f1, [%i2+4] 170 st %f0, [%i2] 171 ret 172 restore 173E(SP_V8_RET_CPLX8) 174 stb %o0, [%i2+1] 175 b 0f 176 srl %o0, 8, %o0 177E(SPARC_RET_F_1) 178 st %f0, [%i2] 179 ret 180 restore 181 182 .align 8 1839: sth %o0, [%i2] 184 ret 185 restore 186 .align 8 1870: stb %o0, [%i2] 188 ret 189 restore 190 191 ! Struct returning functions expect and skip the unimp here. 192 ! To make it worse, conforming callees examine the unimp and 193 ! make sure the low 12 bits of the unimp match the size of 194 ! the struct being returned. 195 .align 8 1968: call 1f ! load pc in %o7 197 sll %l1, 2, %l0 ! size * 4 1981: sll %l1, 4, %l1 ! size * 16 199 add %l0, %l1, %l0 ! size * 20 200 add %o7, %l0, %o7 ! o7 = 8b + size*20 201 jmp %o7+(2f-8b) 202 mov %i5, %g2 ! load static chain 2032: 204 205/* The Sun assembler doesn't understand .rept 0x1000. */ 206#define rept1 \ 207 call %i1; \ 208 nop; \ 209 unimp (. - 2b) / 20; \ 210 ret; \ 211 restore 212 213#define rept16 \ 214 rept1; rept1; rept1; rept1; \ 215 rept1; rept1; rept1; rept1; \ 216 rept1; rept1; rept1; rept1; \ 217 rept1; rept1; rept1; rept1 218 219#define rept256 \ 220 rept16; rept16; rept16; rept16; \ 221 rept16; rept16; rept16; rept16; \ 222 rept16; rept16; rept16; rept16; \ 223 rept16; rept16; rept16; rept16 224 225 rept256; rept256; rept256; rept256 226 rept256; rept256; rept256; rept256 227 rept256; rept256; rept256; rept256 228 rept256; rept256; rept256; rept256 229 230.LUW2: 231 .size C(ffi_call_v8),. - C(ffi_call_v8) 232 233 234/* 16*4 register window + 1*4 struct return + 6*4 args backing store 235 + 8*4 return storage + 1*4 alignment. */ 236#define STACKFRAME (16*4 + 4 + 6*4 + 8*4 + 4) 237 238/* ffi_closure_v8(...) 239 240 Receives the closure argument in %g2. */ 241 242#ifdef HAVE_AS_REGISTER_PSEUDO_OP 243 .register %g2, #scratch 244#endif 245 246 .align 8 247 .globl C(ffi_go_closure_v8) 248 .type C(ffi_go_closure_v8),#function 249 FFI_HIDDEN(C(ffi_go_closure_v8)) 250 251C(ffi_go_closure_v8): 252.LUW3: 253 save %sp, -STACKFRAME, %sp 254.LUW4: 255 ld [%g2+4], %o0 ! load cif 256 ld [%g2+8], %o1 ! load fun 257 b 0f 258 mov %g2, %o2 ! load user_data 259.LUW5: 260 .size C(ffi_go_closure_v8), . - C(ffi_go_closure_v8) 261 262 .align 8 263 .globl C(ffi_closure_v8) 264 .type C(ffi_closure_v8),#function 265 FFI_HIDDEN(C(ffi_closure_v8)) 266 267C(ffi_closure_v8): 268.LUW6: 269 save %sp, -STACKFRAME, %sp 270.LUW7: 271 ld [%g2+FFI_TRAMPOLINE_SIZE], %o0 ! load cif 272 ld [%g2+FFI_TRAMPOLINE_SIZE+4], %o1 ! load fun 273 ld [%g2+FFI_TRAMPOLINE_SIZE+8], %o2 ! load user_data 2740: 275 ! Store all of the potential argument registers in va_list format. 276 st %i0, [%fp+68+0] 277 st %i1, [%fp+68+4] 278 st %i2, [%fp+68+8] 279 st %i3, [%fp+68+12] 280 st %i4, [%fp+68+16] 281 st %i5, [%fp+68+20] 282 283 ! Call ffi_closure_sparc_inner to do the bulk of the work. 284 add %fp, -8*4, %o3 285 call ffi_closure_sparc_inner_v8 286 add %fp, 64, %o4 287 2880: call 1f 289 and %o0, SPARC_FLAG_RET_MASK, %o0 2901: sll %o0, 4, %o0 ! o0 = o0 * 16 291 add %o7, %o0, %o7 ! o7 = 0b + o0*16 292 jmp %o7+(2f-0b) 293 add %fp, -8*4, %i2 294 295 ! Note that each entry is 4 insns, enforced by the E macro. 296 .align 16 2972: 298E(SPARC_RET_VOID) 299 ret 300 restore 301E(SPARC_RET_STRUCT) 302 ld [%i2], %i0 303 jmp %i7+12 304 restore 305E(SPARC_RET_UINT8) 306 ldub [%i2+3], %i0 307 ret 308 restore 309E(SPARC_RET_SINT8) 310 ldsb [%i2+3], %i0 311 ret 312 restore 313E(SPARC_RET_UINT16) 314 lduh [%i2+2], %i0 315 ret 316 restore 317E(SPARC_RET_SINT16) 318 ldsh [%i2+2], %i0 319 ret 320 restore 321E(SPARC_RET_UINT32) 322 ld [%i2], %i0 323 ret 324 restore 325E(SP_V8_RET_CPLX16) 326 ld [%i2], %i0 327 ret 328 restore 329E(SPARC_RET_INT64) 330 ldd [%i2], %i0 331 ret 332 restore 333E(SPARC_RET_INT128) 334 ldd [%i2], %i0 335 ldd [%i2+8], %i2 336 ret 337 restore 338E(SPARC_RET_F_8) 339 ld [%i2+7*4], %f7 340 nop 341 ld [%i2+6*4], %f6 342 nop 343E(SPARC_RET_F_6) 344 ld [%i2+5*4], %f5 345 nop 346 ld [%i2+4*4], %f4 347 nop 348E(SPARC_RET_F_4) 349 ld [%i2+3*4], %f3 350 nop 351 ld [%i2+2*4], %f2 352 nop 353E(SPARC_RET_F_2) 354 ldd [%i2], %f0 355 ret 356 restore 357E(SP_V8_RET_CPLX8) 358 lduh [%i2], %i0 359 ret 360 restore 361E(SPARC_RET_F_1) 362 ld [%i2], %f0 363 ret 364 restore 365 366.LUW8: 367 .size C(ffi_closure_v8), . - C(ffi_closure_v8) 368 369#ifdef HAVE_RO_EH_FRAME 370 .section ".eh_frame",#alloc 371#else 372 .section ".eh_frame",#alloc,#write 373#endif 374 375#ifdef HAVE_AS_SPARC_UA_PCREL 376# define FDE_ADDR(X) %r_disp32(X) 377#else 378# define FDE_ADDR(X) X 379#endif 380 381 .align 4 382.LCIE: 383 .long .LECIE - .LSCIE ! CIE Length 384.LSCIE: 385 .long 0 ! CIE Identifier Tag 386 .byte 1 ! CIE Version 387 .ascii "zR\0" ! CIE Augmentation 388 .byte 4 ! CIE Code Alignment Factor 389 .byte 0x7c ! CIE Data Alignment Factor 390 .byte 15 ! CIE RA Column 391 .byte 1 ! Augmentation size 392#ifdef HAVE_AS_SPARC_UA_PCREL 393 .byte 0x1b ! FDE Encoding (pcrel sdata4) 394#else 395 .byte 0x50 ! FDE Encoding (aligned absolute) 396#endif 397 .byte 0xc, 14, 0 ! DW_CFA_def_cfa, %o6, offset 0 398 .align 4 399.LECIE: 400 401 .long .LEFDE1 - .LSFDE1 ! FDE Length 402.LSFDE1: 403 .long .LSFDE1 - .LCIE ! FDE CIE offset 404 .long FDE_ADDR(.LUW0) ! Initial location 405 .long .LUW2 - .LUW0 ! Address range 406 .byte 0 ! Augmentation size 407 .byte 0x40+1 ! DW_CFA_advance_loc 4 408 .byte 0xd, 30 ! DW_CFA_def_cfa_register, %i6 409 .byte 0x2d ! DW_CFA_GNU_window_save 410 .byte 0x9, 15, 31 ! DW_CFA_register, %o7, %i7 411 .align 4 412.LEFDE1: 413 414 .long .LEFDE2 - .LSFDE2 ! FDE Length 415.LSFDE2: 416 .long .LSFDE2 - .LCIE ! FDE CIE offset 417 .long FDE_ADDR(.LUW3) ! Initial location 418 .long .LUW5 - .LUW3 ! Address range 419 .byte 0 ! Augmentation size 420 .byte 0x40+1 ! DW_CFA_advance_loc 4 421 .byte 0xd, 30 ! DW_CFA_def_cfa_register, %i6 422 .byte 0x2d ! DW_CFA_GNU_window_save 423 .byte 0x9, 15, 31 ! DW_CFA_register, %o7, %i7 424 .align 4 425.LEFDE2: 426 427 .long .LEFDE3 - .LSFDE3 ! FDE Length 428.LSFDE3: 429 .long .LSFDE3 - .LCIE ! FDE CIE offset 430 .long FDE_ADDR(.LUW6) ! Initial location 431 .long .LUW8 - .LUW6 ! Address range 432 .byte 0 ! Augmentation size 433 .byte 0x40+1 ! DW_CFA_advance_loc 4 434 .byte 0xd, 30 ! DW_CFA_def_cfa_register, %i6 435 .byte 0x2d ! DW_CFA_GNU_window_save 436 .byte 0x9, 15, 31 ! DW_CFA_register, %o7, %i7 437 .align 4 438.LEFDE3: 439 440#endif /* !SPARC64 */ 441#if defined __ELF__ && defined __linux__ 442 .section .note.GNU-stack,"",@progbits 443#endif 444