1a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* ----------------------------------------------------------------------- 2a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project ffi.c - Copyright (c) 2002, 2007 Bo Thorsen <bo@suse.de> 3a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project Copyright (c) 2008 Red Hat, Inc. 4a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 5a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project x86-64 Foreign Function Interface 6a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 7a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project Permission is hereby granted, free of charge, to any person obtaining 8a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project a copy of this software and associated documentation files (the 9a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project ``Software''), to deal in the Software without restriction, including 10a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project without limitation the rights to use, copy, modify, merge, publish, 11a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project distribute, sublicense, and/or sell copies of the Software, and to 12a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project permit persons to whom the Software is furnished to do so, subject to 13a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project the following conditions: 14a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 15a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project The above copyright notice and this permission notice shall be included 16a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project in all copies or substantial portions of the Software. 17a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 18a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 19a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project DEALINGS IN THE SOFTWARE. 26a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project ----------------------------------------------------------------------- */ 27a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 28a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <ffi.h> 29a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <ffi_common.h> 30a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 31a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <stdlib.h> 32a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <stdarg.h> 33a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 34a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#ifdef __x86_64__ 35a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 36a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define MAX_GPR_REGS 6 37a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define MAX_SSE_REGS 8 38a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 39a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstruct register_args 40a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{ 41a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Registers for argument passing. */ 42a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project UINT64 gpr[MAX_GPR_REGS]; 43a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project __int128_t sse[MAX_SSE_REGS]; 44a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}; 45a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 46a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectextern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags, 47a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project void *raddr, void (*fnaddr)(void), unsigned ssecount); 48a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 49a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* All reference to register classes here is identical to the code in 50a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project gcc/config/i386/i386.c. Do *not* change one without the other. */ 51a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 52a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Register class used for passing given 64bit part of the argument. 53a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project These represent classes as documented by the PS ABI, with the exception 54a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project of SSESF, SSEDF classes, that are basically SSE class, just gcc will 55a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project use SF or DFmode move instead of DImode to avoid reformating penalties. 56a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 57a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves 58a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project whenever possible (upper half does contain padding). */ 59a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectenum x86_64_reg_class 60a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 61a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project X86_64_NO_CLASS, 62a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project X86_64_INTEGER_CLASS, 63a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project X86_64_INTEGERSI_CLASS, 64a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project X86_64_SSE_CLASS, 65a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project X86_64_SSESF_CLASS, 66a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project X86_64_SSEDF_CLASS, 67a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project X86_64_SSEUP_CLASS, 68a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project X86_64_X87_CLASS, 69a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project X86_64_X87UP_CLASS, 70a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project X86_64_COMPLEX_X87_CLASS, 71a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project X86_64_MEMORY_CLASS 72a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project }; 73a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 74a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define MAX_CLASSES 4 75a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 76a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define SSE_CLASS_P(X) ((X) >= X86_64_SSE_CLASS && X <= X86_64_SSEUP_CLASS) 77a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 78a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* x86-64 register passing implementation. See x86-64 ABI for details. Goal 79a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project of this code is to classify each 8bytes of incoming argument by the register 80a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project class and assign registers accordingly. */ 81a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 82a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Return the union class of CLASS1 and CLASS2. 83a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project See the x86-64 PS ABI for details. */ 84a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 85a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic enum x86_64_reg_class 86a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectmerge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2) 87a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{ 88a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Rule #1: If both classes are equal, this is the resulting class. */ 89a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (class1 == class2) 90a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return class1; 91a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 92a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Rule #2: If one of the classes is NO_CLASS, the resulting class is 93a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project the other class. */ 94a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (class1 == X86_64_NO_CLASS) 95a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return class2; 96a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (class2 == X86_64_NO_CLASS) 97a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return class1; 98a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 99a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */ 100a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS) 101a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return X86_64_MEMORY_CLASS; 102a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 103a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */ 104a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS) 105a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS)) 106a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return X86_64_INTEGERSI_CLASS; 107a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS 108a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS) 109a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return X86_64_INTEGER_CLASS; 110a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 111a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Rule #5: If one of the classes is X87, X87UP, or COMPLEX_X87 class, 112a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project MEMORY is used. */ 113a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (class1 == X86_64_X87_CLASS 114a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project || class1 == X86_64_X87UP_CLASS 115a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project || class1 == X86_64_COMPLEX_X87_CLASS 116a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project || class2 == X86_64_X87_CLASS 117a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project || class2 == X86_64_X87UP_CLASS 118a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project || class2 == X86_64_COMPLEX_X87_CLASS) 119a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return X86_64_MEMORY_CLASS; 120a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 121a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Rule #6: Otherwise class SSE is used. */ 122a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return X86_64_SSE_CLASS; 123a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project} 124a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 125a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Classify the argument of type TYPE and mode MODE. 126a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project CLASSES will be filled by the register class used to pass each word 127a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project of the operand. The number of words is returned. In case the parameter 128a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project should be passed in memory, 0 is returned. As a special case for zero 129a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project sized containers, classes[0] will be NO_CLASS and 1 is returned. 130a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 131a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project See the x86-64 PS ABI for details. 132a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project*/ 133a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic int 134a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectclassify_argument (ffi_type *type, enum x86_64_reg_class classes[], 135a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project size_t byte_offset) 136a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{ 137a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project switch (type->type) 138a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 139a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case FFI_TYPE_UINT8: 140a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case FFI_TYPE_SINT8: 141a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case FFI_TYPE_UINT16: 142a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case FFI_TYPE_SINT16: 143a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case FFI_TYPE_UINT32: 144a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case FFI_TYPE_SINT32: 145a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case FFI_TYPE_UINT64: 146a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case FFI_TYPE_SINT64: 147a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case FFI_TYPE_POINTER: 148a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (byte_offset + type->size <= 4) 149a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project classes[0] = X86_64_INTEGERSI_CLASS; 150a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project else 151a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project classes[0] = X86_64_INTEGER_CLASS; 152a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return 1; 153a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case FFI_TYPE_FLOAT: 154a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (byte_offset == 0) 155a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project classes[0] = X86_64_SSESF_CLASS; 156a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project else 157a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project classes[0] = X86_64_SSE_CLASS; 158a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return 1; 159a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case FFI_TYPE_DOUBLE: 160a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project classes[0] = X86_64_SSEDF_CLASS; 161a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return 1; 162a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case FFI_TYPE_LONGDOUBLE: 163a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project classes[0] = X86_64_X87_CLASS; 164a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project classes[1] = X86_64_X87UP_CLASS; 165a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return 2; 166a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case FFI_TYPE_STRUCT: 167a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 168a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project const int UNITS_PER_WORD = 8; 169a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project int words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; 170a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project ffi_type **ptr; 171a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project int i; 172a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project enum x86_64_reg_class subclasses[MAX_CLASSES]; 173a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 174a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* If the struct is larger than 16 bytes, pass it on the stack. */ 175a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (type->size > 16) 176a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return 0; 177a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 178a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project for (i = 0; i < words; i++) 179a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project classes[i] = X86_64_NO_CLASS; 180a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 181a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Merge the fields of structure. */ 182a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project for (ptr = type->elements; *ptr != NULL; ptr++) 183a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 184a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project int num; 185a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 186a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project byte_offset = ALIGN (byte_offset, (*ptr)->alignment); 187a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 188a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project num = classify_argument (*ptr, subclasses, byte_offset % 8); 189a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (num == 0) 190a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return 0; 191a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project for (i = 0; i < num; i++) 192a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 193a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project int pos = byte_offset / 8; 194a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project classes[i + pos] = 195a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project merge_classes (subclasses[i], classes[i + pos]); 196a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 197a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 198a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project byte_offset += (*ptr)->size; 199a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 200a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 201a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Final merger cleanup. */ 202a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project for (i = 0; i < words; i++) 203a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 204a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* If one class is MEMORY, everything should be passed in 205a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project memory. */ 206a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (classes[i] == X86_64_MEMORY_CLASS) 207a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return 0; 208a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 209a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* The X86_64_SSEUP_CLASS should be always preceded by 210a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project X86_64_SSE_CLASS. */ 211a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (classes[i] == X86_64_SSEUP_CLASS 212a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project && (i == 0 || classes[i - 1] != X86_64_SSE_CLASS)) 213a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project classes[i] = X86_64_SSE_CLASS; 214a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 215a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS. */ 216a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (classes[i] == X86_64_X87UP_CLASS 217a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project && (i == 0 || classes[i - 1] != X86_64_X87_CLASS)) 218a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project classes[i] = X86_64_SSE_CLASS; 219a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 220a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return words; 221a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 222a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 223a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project default: 224a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project FFI_ASSERT(0); 225a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 226a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return 0; /* Never reached. */ 227a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project} 228a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 229a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Examine the argument and return set number of register required in each 230a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project class. Return zero iff parameter should be passed in memory, otherwise 231a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project the number of registers. */ 232a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 233a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic int 234a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectexamine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES], 235a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project _Bool in_return, int *pngpr, int *pnsse) 236a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{ 237a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project int i, n, ngpr, nsse; 238a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 239a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project n = classify_argument (type, classes, 0); 240a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (n == 0) 241a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return 0; 242a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 243a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project ngpr = nsse = 0; 244a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project for (i = 0; i < n; ++i) 245a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project switch (classes[i]) 246a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 247a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case X86_64_INTEGER_CLASS: 248a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case X86_64_INTEGERSI_CLASS: 249a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project ngpr++; 250a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project break; 251a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case X86_64_SSE_CLASS: 252a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case X86_64_SSESF_CLASS: 253a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case X86_64_SSEDF_CLASS: 254a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project nsse++; 255a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project break; 256a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case X86_64_NO_CLASS: 257a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case X86_64_SSEUP_CLASS: 258a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project break; 259a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case X86_64_X87_CLASS: 260a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case X86_64_X87UP_CLASS: 261a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case X86_64_COMPLEX_X87_CLASS: 262a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return in_return != 0; 263a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project default: 264a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project abort (); 265a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 266a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 267a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project *pngpr = ngpr; 268a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project *pnsse = nsse; 269a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 270a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return n; 271a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project} 272a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 273a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Perform machine dependent cif processing. */ 274a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 275a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectffi_status 276a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectffi_prep_cif_machdep (ffi_cif *cif) 277a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{ 278a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project int gprcount, ssecount, i, avn, n, ngpr, nsse, flags; 279a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project enum x86_64_reg_class classes[MAX_CLASSES]; 280a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project size_t bytes; 281a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 282a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project gprcount = ssecount = 0; 283a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 284a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project flags = cif->rtype->type; 285a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (flags != FFI_TYPE_VOID) 286a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 287a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse); 288a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (n == 0) 289a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 290a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* The return value is passed in memory. A pointer to that 291a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project memory is the first argument. Allocate a register for it. */ 292a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project gprcount++; 293a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* We don't have to do anything in asm for the return. */ 294a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project flags = FFI_TYPE_VOID; 295a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 296a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project else if (flags == FFI_TYPE_STRUCT) 297a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 298a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Mark which registers the result appears in. */ 299a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project _Bool sse0 = SSE_CLASS_P (classes[0]); 300a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project _Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]); 301a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (sse0 && !sse1) 302a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project flags |= 1 << 8; 303a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project else if (!sse0 && sse1) 304a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project flags |= 1 << 9; 305a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project else if (sse0 && sse1) 306a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project flags |= 1 << 10; 307a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Mark the true size of the structure. */ 308a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project flags |= cif->rtype->size << 12; 309a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 310a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 311a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 312a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Go over all arguments and determine the way they should be passed. 313a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project If it's in a register and there is space for it, let that be so. If 314a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project not, add it's size to the stack byte count. */ 315a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project for (bytes = 0, i = 0, avn = cif->nargs; i < avn; i++) 316a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 317a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (examine_argument (cif->arg_types[i], classes, 0, &ngpr, &nsse) == 0 318a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project || gprcount + ngpr > MAX_GPR_REGS 319a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project || ssecount + nsse > MAX_SSE_REGS) 320a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 321a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project long align = cif->arg_types[i]->alignment; 322a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 323a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (align < 8) 324a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project align = 8; 325a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 326a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project bytes = ALIGN(bytes, align); 327a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project bytes += cif->arg_types[i]->size; 328a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 329a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project else 330a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 331a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project gprcount += ngpr; 332a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project ssecount += nsse; 333a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 334a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 335a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (ssecount) 336a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project flags |= 1 << 11; 337a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project cif->flags = flags; 338a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project cif->bytes = bytes; 339a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 340a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return FFI_OK; 341a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project} 342a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 343a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectvoid 344a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) 345a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{ 346a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project enum x86_64_reg_class classes[MAX_CLASSES]; 347a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project char *stack, *argp; 348a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project ffi_type **arg_types; 349a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project int gprcount, ssecount, ngpr, nsse, i, avn; 350a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project _Bool ret_in_memory; 351a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project struct register_args *reg_args; 352a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 353a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Can't call 32-bit mode from 64-bit mode. */ 354a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project FFI_ASSERT (cif->abi == FFI_UNIX64); 355a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 356a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* If the return value is a struct and we don't have a return value 357a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project address then we need to make one. Note the setting of flags to 358a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project VOID above in ffi_prep_cif_machdep. */ 359a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project ret_in_memory = (cif->rtype->type == FFI_TYPE_STRUCT 360a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project && (cif->flags & 0xff) == FFI_TYPE_VOID); 361a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (rvalue == NULL && ret_in_memory) 362a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project rvalue = alloca (cif->rtype->size); 363a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 364a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Allocate the space for the arguments, plus 4 words of temp space. */ 365a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8); 366a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project reg_args = (struct register_args *) stack; 367a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project argp = stack + sizeof (struct register_args); 368a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 369a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project gprcount = ssecount = 0; 370a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 371a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* If the return value is passed in memory, add the pointer as the 372a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project first integer argument. */ 373a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (ret_in_memory) 374a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project reg_args->gpr[gprcount++] = (long) rvalue; 375a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 376a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project avn = cif->nargs; 377a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project arg_types = cif->arg_types; 378a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 379a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project for (i = 0; i < avn; ++i) 380a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 381a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project size_t size = arg_types[i]->size; 382a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project int n; 383a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 384a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse); 385a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (n == 0 386a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project || gprcount + ngpr > MAX_GPR_REGS 387a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project || ssecount + nsse > MAX_SSE_REGS) 388a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 389a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project long align = arg_types[i]->alignment; 390a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 391a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Stack arguments are *always* at least 8 byte aligned. */ 392a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (align < 8) 393a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project align = 8; 394a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 395a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Pass this argument in memory. */ 396a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project argp = (void *) ALIGN (argp, align); 397a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project memcpy (argp, avalue[i], size); 398a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project argp += size; 399a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 400a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project else 401a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 402a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* The argument is passed entirely in registers. */ 403a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project char *a = (char *) avalue[i]; 404a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project int j; 405a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 406a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project for (j = 0; j < n; j++, a += 8, size -= 8) 407a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 408a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project switch (classes[j]) 409a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 410a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case X86_64_INTEGER_CLASS: 411a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case X86_64_INTEGERSI_CLASS: 412a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project reg_args->gpr[gprcount] = 0; 413a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project memcpy (®_args->gpr[gprcount], a, size < 8 ? size : 8); 414a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project gprcount++; 415a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project break; 416a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case X86_64_SSE_CLASS: 417a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case X86_64_SSEDF_CLASS: 418a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project reg_args->sse[ssecount++] = *(UINT64 *) a; 419a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project break; 420a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project case X86_64_SSESF_CLASS: 421a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project reg_args->sse[ssecount++] = *(UINT32 *) a; 422a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project break; 423a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project default: 424a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project abort(); 425a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 426a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 427a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 428a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 429a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 430a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args), 431a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project cif->flags, rvalue, fn, ssecount); 432a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project} 433a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 434a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 435a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectextern void ffi_closure_unix64(void); 436a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 437a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectffi_status 438a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectffi_prep_closure_loc (ffi_closure* closure, 439a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project ffi_cif* cif, 440a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project void (*fun)(ffi_cif*, void*, void**, void*), 441a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project void *user_data, 442a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project void *codeloc) 443a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{ 444a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project volatile unsigned short *tramp; 445a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 446a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project tramp = (volatile unsigned short *) &closure->tramp[0]; 447a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 448a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project tramp[0] = 0xbb49; /* mov <code>, %r11 */ 449a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project *(void * volatile *) &tramp[1] = ffi_closure_unix64; 450a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project tramp[5] = 0xba49; /* mov <data>, %r10 */ 451a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project *(void * volatile *) &tramp[6] = codeloc; 452a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 453a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Set the carry bit iff the function uses any sse registers. 454a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project This is clc or stc, together with the first byte of the jmp. */ 455a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project tramp[10] = cif->flags & (1 << 11) ? 0x49f9 : 0x49f8; 456a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 457a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project tramp[11] = 0xe3ff; /* jmp *%r11 */ 458a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 459a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project closure->cif = cif; 460a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project closure->fun = fun; 461a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project closure->user_data = user_data; 462a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 463a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return FFI_OK; 464a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project} 465a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 466a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectint 467a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectffi_closure_unix64_inner(ffi_closure *closure, void *rvalue, 468a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project struct register_args *reg_args, char *argp) 469a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{ 470a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project ffi_cif *cif; 471a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project void **avalue; 472a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project ffi_type **arg_types; 473a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project long i, avn; 474a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project int gprcount, ssecount, ngpr, nsse; 475a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project int ret; 476a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 477a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project cif = closure->cif; 478a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project avalue = alloca(cif->nargs * sizeof(void *)); 479a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project gprcount = ssecount = 0; 480a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 481a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project ret = cif->rtype->type; 482a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (ret != FFI_TYPE_VOID) 483a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 484a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project enum x86_64_reg_class classes[MAX_CLASSES]; 485a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project int n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse); 486a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (n == 0) 487a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 488a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* The return value goes in memory. Arrange for the closure 489a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return value to go directly back to the original caller. */ 490a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project rvalue = (void *) reg_args->gpr[gprcount++]; 491a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* We don't have to do anything in asm for the return. */ 492a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project ret = FFI_TYPE_VOID; 493a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 494a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project else if (ret == FFI_TYPE_STRUCT && n == 2) 495a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 496a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Mark which register the second word of the structure goes in. */ 497a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project _Bool sse0 = SSE_CLASS_P (classes[0]); 498a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project _Bool sse1 = SSE_CLASS_P (classes[1]); 499a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (!sse0 && sse1) 500a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project ret |= 1 << 8; 501a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project else if (sse0 && !sse1) 502a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project ret |= 1 << 9; 503a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 504a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 505a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 506a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project avn = cif->nargs; 507a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project arg_types = cif->arg_types; 508a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 509a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project for (i = 0; i < avn; ++i) 510a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 511a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project enum x86_64_reg_class classes[MAX_CLASSES]; 512a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project int n; 513a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 514a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse); 515a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (n == 0 516a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project || gprcount + ngpr > MAX_GPR_REGS 517a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project || ssecount + nsse > MAX_SSE_REGS) 518a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 519a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project long align = arg_types[i]->alignment; 520a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 521a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Stack arguments are *always* at least 8 byte aligned. */ 522a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (align < 8) 523a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project align = 8; 524a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 525a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Pass this argument in memory. */ 526a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project argp = (void *) ALIGN (argp, align); 527a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project avalue[i] = argp; 528a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project argp += arg_types[i]->size; 529a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 530a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* If the argument is in a single register, or two consecutive 531a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project registers, then we can use that address directly. */ 532a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project else if (n == 1 533a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project || (n == 2 534a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project && SSE_CLASS_P (classes[0]) == SSE_CLASS_P (classes[1]))) 535a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 536a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* The argument is in a single register. */ 537a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (SSE_CLASS_P (classes[0])) 538a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 539a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project avalue[i] = ®_args->sse[ssecount]; 540a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project ssecount += n; 541a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 542a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project else 543a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 544a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project avalue[i] = ®_args->gpr[gprcount]; 545a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project gprcount += n; 546a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 547a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 548a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Otherwise, allocate space to make them consecutive. */ 549a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project else 550a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 551a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project char *a = alloca (16); 552a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project int j; 553a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 554a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project avalue[i] = a; 555a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project for (j = 0; j < n; j++, a += 8) 556a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project { 557a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project if (SSE_CLASS_P (classes[j])) 558a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project memcpy (a, ®_args->sse[ssecount++], 8); 559a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project else 560a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project memcpy (a, ®_args->gpr[gprcount++], 8); 561a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 562a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 563a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project } 564a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 565a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Invoke the closure. */ 566a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project closure->fun (cif, rvalue, avalue, closure->user_data); 567a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 568a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project /* Tell assembly how to perform return type promotions. */ 569a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project return ret; 570a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project} 571a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project 572a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#endif /* __x86_64__ */ 573