1/* ----------------------------------------------------------------------- 2 sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub@redhat.com> 3 Copyright (c) 2008 Red Hat, Inc. 4 5 PowerPC64 Assembly glue. 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 32#ifdef POWERPC64 33 .hidden ffi_call_LINUX64 34 .globl ffi_call_LINUX64 35 .text 36 .cfi_startproc 37# if _CALL_ELF == 2 38ffi_call_LINUX64: 39 addis %r2, %r12, .TOC.-ffi_call_LINUX64@ha 40 addi %r2, %r2, .TOC.-ffi_call_LINUX64@l 41 .localentry ffi_call_LINUX64, . - ffi_call_LINUX64 42# else 43 .section ".opd","aw" 44 .align 3 45ffi_call_LINUX64: 46# ifdef _CALL_LINUX 47 .quad .L.ffi_call_LINUX64,.TOC.@tocbase,0 48 .type ffi_call_LINUX64,@function 49 .text 50.L.ffi_call_LINUX64: 51# else 52 .hidden .ffi_call_LINUX64 53 .globl .ffi_call_LINUX64 54 .quad .ffi_call_LINUX64,.TOC.@tocbase,0 55 .size ffi_call_LINUX64,24 56 .type .ffi_call_LINUX64,@function 57 .text 58.ffi_call_LINUX64: 59# endif 60# endif 61 mflr %r0 62 std %r28, -32(%r1) 63 std %r29, -24(%r1) 64 std %r30, -16(%r1) 65 std %r31, -8(%r1) 66 std %r7, 8(%r1) /* closure, saved in cr field. */ 67 std %r0, 16(%r1) 68 69 mr %r28, %r1 /* our AP. */ 70 .cfi_def_cfa_register 28 71 .cfi_offset 65, 16 72 .cfi_offset 31, -8 73 .cfi_offset 30, -16 74 .cfi_offset 29, -24 75 .cfi_offset 28, -32 76 77 stdux %r1, %r1, %r8 78 mr %r31, %r6 /* flags, */ 79 mr %r30, %r5 /* rvalue, */ 80 mr %r29, %r4 /* function address. */ 81/* Save toc pointer, not for the ffi_prep_args64 call, but for the later 82 bctrl function call. */ 83# if _CALL_ELF == 2 84 std %r2, 24(%r1) 85# else 86 std %r2, 40(%r1) 87# endif 88 89 /* Call ffi_prep_args64. */ 90 mr %r4, %r1 91# if defined _CALL_LINUX || _CALL_ELF == 2 92 bl ffi_prep_args64 93# else 94 bl .ffi_prep_args64 95# endif 96 97# if _CALL_ELF == 2 98 mr %r12, %r29 99# else 100 ld %r12, 0(%r29) 101 ld %r2, 8(%r29) 102# endif 103 /* Now do the call. */ 104 /* Set up cr1 with bits 3-7 of the flags. */ 105 mtcrf 0xc0, %r31 106 107 /* Get the address to call into CTR. */ 108 mtctr %r12 109 /* Load all those argument registers. */ 110 addi %r29, %r28, -32-(8*8) 111 ld %r3, (0*8)(%r29) 112 ld %r4, (1*8)(%r29) 113 ld %r5, (2*8)(%r29) 114 ld %r6, (3*8)(%r29) 115 bf- 5, 1f 116 ld %r7, (4*8)(%r29) 117 ld %r8, (5*8)(%r29) 118 ld %r9, (6*8)(%r29) 119 ld %r10, (7*8)(%r29) 1201: 121 122 /* Load all the FP registers. */ 123 bf- 6, 2f 124 addi %r29, %r29, -(14*8) 125 lfd %f1, ( 1*8)(%r29) 126 lfd %f2, ( 2*8)(%r29) 127 lfd %f3, ( 3*8)(%r29) 128 lfd %f4, ( 4*8)(%r29) 129 lfd %f5, ( 5*8)(%r29) 130 lfd %f6, ( 6*8)(%r29) 131 lfd %f7, ( 7*8)(%r29) 132 lfd %f8, ( 8*8)(%r29) 133 lfd %f9, ( 9*8)(%r29) 134 lfd %f10, (10*8)(%r29) 135 lfd %f11, (11*8)(%r29) 136 lfd %f12, (12*8)(%r29) 137 lfd %f13, (13*8)(%r29) 1382: 139 140 /* Load all the vector registers. */ 141 bf- 3, 3f 142 addi %r29, %r29, -16 143 lvx %v13, 0, %r29 144 addi %r29, %r29, -16 145 lvx %v12, 0, %r29 146 addi %r29, %r29, -16 147 lvx %v11, 0, %r29 148 addi %r29, %r29, -16 149 lvx %v10, 0, %r29 150 addi %r29, %r29, -16 151 lvx %v9, 0, %r29 152 addi %r29, %r29, -16 153 lvx %v8, 0, %r29 154 addi %r29, %r29, -16 155 lvx %v7, 0, %r29 156 addi %r29, %r29, -16 157 lvx %v6, 0, %r29 158 addi %r29, %r29, -16 159 lvx %v5, 0, %r29 160 addi %r29, %r29, -16 161 lvx %v4, 0, %r29 162 addi %r29, %r29, -16 163 lvx %v3, 0, %r29 164 addi %r29, %r29, -16 165 lvx %v2, 0, %r29 1663: 167 168 /* Make the call. */ 169 ld %r11, 8(%r28) 170 bctrl 171 172 /* This must follow the call immediately, the unwinder 173 uses this to find out if r2 has been saved or not. */ 174# if _CALL_ELF == 2 175 ld %r2, 24(%r1) 176# else 177 ld %r2, 40(%r1) 178# endif 179 180 /* Now, deal with the return value. */ 181 mtcrf 0x01, %r31 182 bt 31, .Lstruct_return_value 183 bt 30, .Ldone_return_value 184 bt 29, .Lfp_return_value 185 bt 28, .Lvec_return_value 186 std %r3, 0(%r30) 187 /* Fall through... */ 188 189.Ldone_return_value: 190 /* Restore the registers we used and return. */ 191 mr %r1, %r28 192 .cfi_def_cfa_register 1 193 ld %r0, 16(%r28) 194 ld %r28, -32(%r28) 195 mtlr %r0 196 ld %r29, -24(%r1) 197 ld %r30, -16(%r1) 198 ld %r31, -8(%r1) 199 blr 200 201.Lvec_return_value: 202 stvx %v2, 0, %r30 203 b .Ldone_return_value 204 205.Lfp_return_value: 206 .cfi_def_cfa_register 28 207 mtcrf 0x02, %r31 /* cr6 */ 208 bf 27, .Lfloat_return_value 209 stfd %f1, 0(%r30) 210 bf 26, .Ldone_return_value 211 stfd %f2, 8(%r30) 212 b .Ldone_return_value 213.Lfloat_return_value: 214 stfs %f1, 0(%r30) 215 b .Ldone_return_value 216 217.Lstruct_return_value: 218 bf 29, .Lvec_homog_or_small_struct 219 mtcrf 0x02, %r31 /* cr6 */ 220 bf 27, .Lfloat_homog_return_value 221 stfd %f1, 0(%r30) 222 stfd %f2, 8(%r30) 223 stfd %f3, 16(%r30) 224 stfd %f4, 24(%r30) 225 stfd %f5, 32(%r30) 226 stfd %f6, 40(%r30) 227 stfd %f7, 48(%r30) 228 stfd %f8, 56(%r30) 229 b .Ldone_return_value 230 231.Lfloat_homog_return_value: 232 stfs %f1, 0(%r30) 233 stfs %f2, 4(%r30) 234 stfs %f3, 8(%r30) 235 stfs %f4, 12(%r30) 236 stfs %f5, 16(%r30) 237 stfs %f6, 20(%r30) 238 stfs %f7, 24(%r30) 239 stfs %f8, 28(%r30) 240 b .Ldone_return_value 241 242.Lvec_homog_or_small_struct: 243 bf 28, .Lsmall_struct 244 stvx %v2, 0, %r30 245 addi %r30, %r30, 16 246 stvx %v3, 0, %r30 247 addi %r30, %r30, 16 248 stvx %v4, 0, %r30 249 addi %r30, %r30, 16 250 stvx %v5, 0, %r30 251 addi %r30, %r30, 16 252 stvx %v6, 0, %r30 253 addi %r30, %r30, 16 254 stvx %v7, 0, %r30 255 addi %r30, %r30, 16 256 stvx %v8, 0, %r30 257 addi %r30, %r30, 16 258 stvx %v9, 0, %r30 259 b .Ldone_return_value 260 261.Lsmall_struct: 262 std %r3, 0(%r30) 263 std %r4, 8(%r30) 264 b .Ldone_return_value 265 266 .cfi_endproc 267# if _CALL_ELF == 2 268 .size ffi_call_LINUX64,.-ffi_call_LINUX64 269# else 270# ifdef _CALL_LINUX 271 .size ffi_call_LINUX64,.-.L.ffi_call_LINUX64 272# else 273 .long 0 274 .byte 0,12,0,1,128,4,0,0 275 .size .ffi_call_LINUX64,.-.ffi_call_LINUX64 276# endif 277# endif 278 279#endif 280 281#if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2 282 .section .note.GNU-stack,"",@progbits 283#endif 284