PageRenderTime 53ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/src/libffi/src/powerpc/ffi_linux64.c

https://gitlab.com/jlarocco/ecl
C | 943 lines | 733 code | 84 blank | 126 comment | 194 complexity | 7e40e8c0cc6e566f1090aca8dbfb62dc MD5 | raw file
Possible License(s): LGPL-2.0, JSON
  1. /* -----------------------------------------------------------------------
  2. ffi_linux64.c - Copyright (C) 2013 IBM
  3. Copyright (C) 2011 Anthony Green
  4. Copyright (C) 2011 Kyle Moffett
  5. Copyright (C) 2008 Red Hat, Inc
  6. Copyright (C) 2007, 2008 Free Software Foundation, Inc
  7. Copyright (c) 1998 Geoffrey Keating
  8. PowerPC Foreign Function Interface
  9. Permission is hereby granted, free of charge, to any person obtaining
  10. a copy of this software and associated documentation files (the
  11. ``Software''), to deal in the Software without restriction, including
  12. without limitation the rights to use, copy, modify, merge, publish,
  13. distribute, sublicense, and/or sell copies of the Software, and to
  14. permit persons to whom the Software is furnished to do so, subject to
  15. the following conditions:
  16. The above copyright notice and this permission notice shall be included
  17. in all copies or substantial portions of the Software.
  18. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
  19. OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  21. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
  22. OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  23. ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  24. OTHER DEALINGS IN THE SOFTWARE.
  25. ----------------------------------------------------------------------- */
  26. #include "ffi.h"
  27. #ifdef POWERPC64
  28. #include "ffi_common.h"
  29. #include "ffi_powerpc.h"
  30. /* About the LINUX64 ABI. */
  31. enum {
  32. NUM_GPR_ARG_REGISTERS64 = 8,
  33. NUM_FPR_ARG_REGISTERS64 = 13
  34. };
  35. enum { ASM_NEEDS_REGISTERS64 = 4 };
  36. #if HAVE_LONG_DOUBLE_VARIANT && FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
  37. /* Adjust size of ffi_type_longdouble. */
  38. void FFI_HIDDEN
  39. ffi_prep_types_linux64 (ffi_abi abi)
  40. {
  41. if ((abi & (FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128)) == FFI_LINUX)
  42. {
  43. ffi_type_longdouble.size = 8;
  44. ffi_type_longdouble.alignment = 8;
  45. }
  46. else
  47. {
  48. ffi_type_longdouble.size = 16;
  49. ffi_type_longdouble.alignment = 16;
  50. }
  51. }
  52. #endif
  53. #if _CALL_ELF == 2
  54. static unsigned int
  55. discover_homogeneous_aggregate (const ffi_type *t, unsigned int *elnum)
  56. {
  57. switch (t->type)
  58. {
  59. case FFI_TYPE_FLOAT:
  60. case FFI_TYPE_DOUBLE:
  61. *elnum = 1;
  62. return (int) t->type;
  63. case FFI_TYPE_STRUCT:;
  64. {
  65. unsigned int base_elt = 0, total_elnum = 0;
  66. ffi_type **el = t->elements;
  67. while (*el)
  68. {
  69. unsigned int el_elt, el_elnum = 0;
  70. el_elt = discover_homogeneous_aggregate (*el, &el_elnum);
  71. if (el_elt == 0
  72. || (base_elt && base_elt != el_elt))
  73. return 0;
  74. base_elt = el_elt;
  75. total_elnum += el_elnum;
  76. if (total_elnum > 8)
  77. return 0;
  78. el++;
  79. }
  80. *elnum = total_elnum;
  81. return base_elt;
  82. }
  83. default:
  84. return 0;
  85. }
  86. }
  87. #endif
  88. /* Perform machine dependent cif processing */
  89. static ffi_status
  90. ffi_prep_cif_linux64_core (ffi_cif *cif)
  91. {
  92. ffi_type **ptr;
  93. unsigned bytes;
  94. unsigned i, fparg_count = 0, intarg_count = 0;
  95. unsigned flags = cif->flags;
  96. #if _CALL_ELF == 2
  97. unsigned int elt, elnum;
  98. #endif
  99. #if FFI_TYPE_LONGDOUBLE == FFI_TYPE_DOUBLE
  100. /* If compiled without long double support.. */
  101. if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
  102. return FFI_BAD_ABI;
  103. #endif
  104. /* The machine-independent calculation of cif->bytes doesn't work
  105. for us. Redo the calculation. */
  106. #if _CALL_ELF == 2
  107. /* Space for backchain, CR, LR, TOC and the asm's temp regs. */
  108. bytes = (4 + ASM_NEEDS_REGISTERS64) * sizeof (long);
  109. /* Space for the general registers. */
  110. bytes += NUM_GPR_ARG_REGISTERS64 * sizeof (long);
  111. #else
  112. /* Space for backchain, CR, LR, cc/ld doubleword, TOC and the asm's temp
  113. regs. */
  114. bytes = (6 + ASM_NEEDS_REGISTERS64) * sizeof (long);
  115. /* Space for the mandatory parm save area and general registers. */
  116. bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof (long);
  117. #endif
  118. /* Return value handling. */
  119. switch (cif->rtype->type)
  120. {
  121. #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
  122. case FFI_TYPE_LONGDOUBLE:
  123. if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
  124. flags |= FLAG_RETURNS_128BITS;
  125. /* Fall through. */
  126. #endif
  127. case FFI_TYPE_DOUBLE:
  128. flags |= FLAG_RETURNS_64BITS;
  129. /* Fall through. */
  130. case FFI_TYPE_FLOAT:
  131. flags |= FLAG_RETURNS_FP;
  132. break;
  133. case FFI_TYPE_UINT128:
  134. flags |= FLAG_RETURNS_128BITS;
  135. /* Fall through. */
  136. case FFI_TYPE_UINT64:
  137. case FFI_TYPE_SINT64:
  138. flags |= FLAG_RETURNS_64BITS;
  139. break;
  140. case FFI_TYPE_STRUCT:
  141. #if _CALL_ELF == 2
  142. elt = discover_homogeneous_aggregate (cif->rtype, &elnum);
  143. if (elt)
  144. {
  145. if (elt == FFI_TYPE_DOUBLE)
  146. flags |= FLAG_RETURNS_64BITS;
  147. flags |= FLAG_RETURNS_FP | FLAG_RETURNS_SMST;
  148. break;
  149. }
  150. if (cif->rtype->size <= 16)
  151. {
  152. flags |= FLAG_RETURNS_SMST;
  153. break;
  154. }
  155. #endif
  156. intarg_count++;
  157. flags |= FLAG_RETVAL_REFERENCE;
  158. /* Fall through. */
  159. case FFI_TYPE_VOID:
  160. flags |= FLAG_RETURNS_NOTHING;
  161. break;
  162. default:
  163. /* Returns 32-bit integer, or similar. Nothing to do here. */
  164. break;
  165. }
  166. for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
  167. {
  168. unsigned int align;
  169. switch ((*ptr)->type)
  170. {
  171. #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
  172. case FFI_TYPE_LONGDOUBLE:
  173. if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
  174. {
  175. fparg_count++;
  176. intarg_count++;
  177. }
  178. /* Fall through. */
  179. #endif
  180. case FFI_TYPE_DOUBLE:
  181. case FFI_TYPE_FLOAT:
  182. fparg_count++;
  183. intarg_count++;
  184. if (fparg_count > NUM_FPR_ARG_REGISTERS64)
  185. flags |= FLAG_ARG_NEEDS_PSAVE;
  186. break;
  187. case FFI_TYPE_STRUCT:
  188. if ((cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0)
  189. {
  190. align = (*ptr)->alignment;
  191. if (align > 16)
  192. align = 16;
  193. align = align / 8;
  194. if (align > 1)
  195. intarg_count = ALIGN (intarg_count, align);
  196. }
  197. intarg_count += ((*ptr)->size + 7) / 8;
  198. #if _CALL_ELF == 2
  199. elt = discover_homogeneous_aggregate (*ptr, &elnum);
  200. if (elt)
  201. {
  202. fparg_count += elnum;
  203. if (fparg_count > NUM_FPR_ARG_REGISTERS64)
  204. flags |= FLAG_ARG_NEEDS_PSAVE;
  205. }
  206. else
  207. #endif
  208. {
  209. if (intarg_count > NUM_GPR_ARG_REGISTERS64)
  210. flags |= FLAG_ARG_NEEDS_PSAVE;
  211. }
  212. break;
  213. case FFI_TYPE_POINTER:
  214. case FFI_TYPE_UINT64:
  215. case FFI_TYPE_SINT64:
  216. case FFI_TYPE_INT:
  217. case FFI_TYPE_UINT32:
  218. case FFI_TYPE_SINT32:
  219. case FFI_TYPE_UINT16:
  220. case FFI_TYPE_SINT16:
  221. case FFI_TYPE_UINT8:
  222. case FFI_TYPE_SINT8:
  223. /* Everything else is passed as a 8-byte word in a GPR, either
  224. the object itself or a pointer to it. */
  225. intarg_count++;
  226. if (intarg_count > NUM_GPR_ARG_REGISTERS64)
  227. flags |= FLAG_ARG_NEEDS_PSAVE;
  228. break;
  229. default:
  230. FFI_ASSERT (0);
  231. }
  232. }
  233. if (fparg_count != 0)
  234. flags |= FLAG_FP_ARGUMENTS;
  235. if (intarg_count > 4)
  236. flags |= FLAG_4_GPR_ARGUMENTS;
  237. /* Space for the FPR registers, if needed. */
  238. if (fparg_count != 0)
  239. bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double);
  240. /* Stack space. */
  241. #if _CALL_ELF == 2
  242. if ((flags & FLAG_ARG_NEEDS_PSAVE) != 0)
  243. bytes += intarg_count * sizeof (long);
  244. #else
  245. if (intarg_count > NUM_GPR_ARG_REGISTERS64)
  246. bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof (long);
  247. #endif
  248. /* The stack space allocated needs to be a multiple of 16 bytes. */
  249. bytes = (bytes + 15) & ~0xF;
  250. cif->flags = flags;
  251. cif->bytes = bytes;
  252. return FFI_OK;
  253. }
  254. ffi_status FFI_HIDDEN
  255. ffi_prep_cif_linux64 (ffi_cif *cif)
  256. {
  257. if ((cif->abi & FFI_LINUX) != 0)
  258. cif->nfixedargs = cif->nargs;
  259. #if _CALL_ELF != 2
  260. else if (cif->abi == FFI_COMPAT_LINUX64)
  261. {
  262. /* This call is from old code. Don't touch cif->nfixedargs
  263. since old code will be using a smaller cif. */
  264. cif->flags |= FLAG_COMPAT;
  265. /* Translate to new abi value. */
  266. cif->abi = FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128;
  267. }
  268. #endif
  269. else
  270. return FFI_BAD_ABI;
  271. return ffi_prep_cif_linux64_core (cif);
  272. }
  273. ffi_status FFI_HIDDEN
  274. ffi_prep_cif_linux64_var (ffi_cif *cif,
  275. unsigned int nfixedargs,
  276. unsigned int ntotalargs MAYBE_UNUSED)
  277. {
  278. if ((cif->abi & FFI_LINUX) != 0)
  279. cif->nfixedargs = nfixedargs;
  280. #if _CALL_ELF != 2
  281. else if (cif->abi == FFI_COMPAT_LINUX64)
  282. {
  283. /* This call is from old code. Don't touch cif->nfixedargs
  284. since old code will be using a smaller cif. */
  285. cif->flags |= FLAG_COMPAT;
  286. /* Translate to new abi value. */
  287. cif->abi = FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128;
  288. }
  289. #endif
  290. else
  291. return FFI_BAD_ABI;
  292. #if _CALL_ELF == 2
  293. cif->flags |= FLAG_ARG_NEEDS_PSAVE;
  294. #endif
  295. return ffi_prep_cif_linux64_core (cif);
  296. }
  297. /* ffi_prep_args64 is called by the assembly routine once stack space
  298. has been allocated for the function's arguments.
  299. The stack layout we want looks like this:
  300. | Ret addr from ffi_call_LINUX64 8bytes | higher addresses
  301. |--------------------------------------------|
  302. | CR save area 8bytes |
  303. |--------------------------------------------|
  304. | Previous backchain pointer 8 | stack pointer here
  305. |--------------------------------------------|<+ <<< on entry to
  306. | Saved r28-r31 4*8 | | ffi_call_LINUX64
  307. |--------------------------------------------| |
  308. | GPR registers r3-r10 8*8 | |
  309. |--------------------------------------------| |
  310. | FPR registers f1-f13 (optional) 13*8 | |
  311. |--------------------------------------------| |
  312. | Parameter save area | |
  313. |--------------------------------------------| |
  314. | TOC save area 8 | |
  315. |--------------------------------------------| | stack |
  316. | Linker doubleword 8 | | grows |
  317. |--------------------------------------------| | down V
  318. | Compiler doubleword 8 | |
  319. |--------------------------------------------| | lower addresses
  320. | Space for callee's LR 8 | |
  321. |--------------------------------------------| |
  322. | CR save area 8 | |
  323. |--------------------------------------------| | stack pointer here
  324. | Current backchain pointer 8 |-/ during
  325. |--------------------------------------------| <<< ffi_call_LINUX64
  326. */
  327. void FFI_HIDDEN
  328. ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
  329. {
  330. const unsigned long bytes = ecif->cif->bytes;
  331. const unsigned long flags = ecif->cif->flags;
  332. typedef union
  333. {
  334. char *c;
  335. unsigned long *ul;
  336. float *f;
  337. double *d;
  338. size_t p;
  339. } valp;
  340. /* 'stacktop' points at the previous backchain pointer. */
  341. valp stacktop;
  342. /* 'next_arg' points at the space for gpr3, and grows upwards as
  343. we use GPR registers, then continues at rest. */
  344. valp gpr_base;
  345. valp gpr_end;
  346. valp rest;
  347. valp next_arg;
  348. /* 'fpr_base' points at the space for fpr3, and grows upwards as
  349. we use FPR registers. */
  350. valp fpr_base;
  351. unsigned int fparg_count;
  352. unsigned int i, words, nargs, nfixedargs;
  353. ffi_type **ptr;
  354. double double_tmp;
  355. union
  356. {
  357. void **v;
  358. char **c;
  359. signed char **sc;
  360. unsigned char **uc;
  361. signed short **ss;
  362. unsigned short **us;
  363. signed int **si;
  364. unsigned int **ui;
  365. unsigned long **ul;
  366. float **f;
  367. double **d;
  368. } p_argv;
  369. unsigned long gprvalue;
  370. unsigned long align;
  371. stacktop.c = (char *) stack + bytes;
  372. gpr_base.ul = stacktop.ul - ASM_NEEDS_REGISTERS64 - NUM_GPR_ARG_REGISTERS64;
  373. gpr_end.ul = gpr_base.ul + NUM_GPR_ARG_REGISTERS64;
  374. #if _CALL_ELF == 2
  375. rest.ul = stack + 4 + NUM_GPR_ARG_REGISTERS64;
  376. #else
  377. rest.ul = stack + 6 + NUM_GPR_ARG_REGISTERS64;
  378. #endif
  379. fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64;
  380. fparg_count = 0;
  381. next_arg.ul = gpr_base.ul;
  382. /* Check that everything starts aligned properly. */
  383. FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0);
  384. FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0);
  385. FFI_ASSERT ((bytes & 0xF) == 0);
  386. /* Deal with return values that are actually pass-by-reference. */
  387. if (flags & FLAG_RETVAL_REFERENCE)
  388. *next_arg.ul++ = (unsigned long) (char *) ecif->rvalue;
  389. /* Now for the arguments. */
  390. p_argv.v = ecif->avalue;
  391. nargs = ecif->cif->nargs;
  392. #if _CALL_ELF != 2
  393. nfixedargs = (unsigned) -1;
  394. if ((flags & FLAG_COMPAT) == 0)
  395. #endif
  396. nfixedargs = ecif->cif->nfixedargs;
  397. for (ptr = ecif->cif->arg_types, i = 0;
  398. i < nargs;
  399. i++, ptr++, p_argv.v++)
  400. {
  401. #if _CALL_ELF == 2
  402. unsigned int elt, elnum;
  403. #endif
  404. switch ((*ptr)->type)
  405. {
  406. #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
  407. case FFI_TYPE_LONGDOUBLE:
  408. if ((ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
  409. {
  410. double_tmp = (*p_argv.d)[0];
  411. if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
  412. {
  413. *fpr_base.d++ = double_tmp;
  414. # if _CALL_ELF != 2
  415. if ((flags & FLAG_COMPAT) != 0)
  416. *next_arg.d = double_tmp;
  417. # endif
  418. }
  419. else
  420. *next_arg.d = double_tmp;
  421. if (++next_arg.ul == gpr_end.ul)
  422. next_arg.ul = rest.ul;
  423. fparg_count++;
  424. double_tmp = (*p_argv.d)[1];
  425. if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
  426. {
  427. *fpr_base.d++ = double_tmp;
  428. # if _CALL_ELF != 2
  429. if ((flags & FLAG_COMPAT) != 0)
  430. *next_arg.d = double_tmp;
  431. # endif
  432. }
  433. else
  434. *next_arg.d = double_tmp;
  435. if (++next_arg.ul == gpr_end.ul)
  436. next_arg.ul = rest.ul;
  437. fparg_count++;
  438. FFI_ASSERT (__LDBL_MANT_DIG__ == 106);
  439. FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
  440. break;
  441. }
  442. /* Fall through. */
  443. #endif
  444. case FFI_TYPE_DOUBLE:
  445. double_tmp = **p_argv.d;
  446. if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
  447. {
  448. *fpr_base.d++ = double_tmp;
  449. #if _CALL_ELF != 2
  450. if ((flags & FLAG_COMPAT) != 0)
  451. *next_arg.d = double_tmp;
  452. #endif
  453. }
  454. else
  455. *next_arg.d = double_tmp;
  456. if (++next_arg.ul == gpr_end.ul)
  457. next_arg.ul = rest.ul;
  458. fparg_count++;
  459. FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
  460. break;
  461. case FFI_TYPE_FLOAT:
  462. double_tmp = **p_argv.f;
  463. if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
  464. {
  465. *fpr_base.d++ = double_tmp;
  466. #if _CALL_ELF != 2
  467. if ((flags & FLAG_COMPAT) != 0)
  468. *next_arg.f = (float) double_tmp;
  469. #endif
  470. }
  471. else
  472. *next_arg.f = (float) double_tmp;
  473. if (++next_arg.ul == gpr_end.ul)
  474. next_arg.ul = rest.ul;
  475. fparg_count++;
  476. FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
  477. break;
  478. case FFI_TYPE_STRUCT:
  479. if ((ecif->cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0)
  480. {
  481. align = (*ptr)->alignment;
  482. if (align > 16)
  483. align = 16;
  484. if (align > 1)
  485. next_arg.p = ALIGN (next_arg.p, align);
  486. }
  487. #if _CALL_ELF == 2
  488. elt = discover_homogeneous_aggregate (*ptr, &elnum);
  489. if (elt)
  490. {
  491. union {
  492. void *v;
  493. float *f;
  494. double *d;
  495. } arg;
  496. arg.v = *p_argv.v;
  497. if (elt == FFI_TYPE_FLOAT)
  498. {
  499. do
  500. {
  501. double_tmp = *arg.f++;
  502. if (fparg_count < NUM_FPR_ARG_REGISTERS64
  503. && i < nfixedargs)
  504. *fpr_base.d++ = double_tmp;
  505. else
  506. *next_arg.f = (float) double_tmp;
  507. if (++next_arg.f == gpr_end.f)
  508. next_arg.f = rest.f;
  509. fparg_count++;
  510. }
  511. while (--elnum != 0);
  512. if ((next_arg.p & 3) != 0)
  513. {
  514. if (++next_arg.f == gpr_end.f)
  515. next_arg.f = rest.f;
  516. }
  517. }
  518. else
  519. do
  520. {
  521. double_tmp = *arg.d++;
  522. if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
  523. *fpr_base.d++ = double_tmp;
  524. else
  525. *next_arg.d = double_tmp;
  526. if (++next_arg.d == gpr_end.d)
  527. next_arg.d = rest.d;
  528. fparg_count++;
  529. }
  530. while (--elnum != 0);
  531. }
  532. else
  533. #endif
  534. {
  535. words = ((*ptr)->size + 7) / 8;
  536. if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul)
  537. {
  538. size_t first = gpr_end.c - next_arg.c;
  539. memcpy (next_arg.c, *p_argv.c, first);
  540. memcpy (rest.c, *p_argv.c + first, (*ptr)->size - first);
  541. next_arg.c = rest.c + words * 8 - first;
  542. }
  543. else
  544. {
  545. char *where = next_arg.c;
  546. #ifndef __LITTLE_ENDIAN__
  547. /* Structures with size less than eight bytes are passed
  548. left-padded. */
  549. if ((*ptr)->size < 8)
  550. where += 8 - (*ptr)->size;
  551. #endif
  552. memcpy (where, *p_argv.c, (*ptr)->size);
  553. next_arg.ul += words;
  554. if (next_arg.ul == gpr_end.ul)
  555. next_arg.ul = rest.ul;
  556. }
  557. }
  558. break;
  559. case FFI_TYPE_UINT8:
  560. gprvalue = **p_argv.uc;
  561. goto putgpr;
  562. case FFI_TYPE_SINT8:
  563. gprvalue = **p_argv.sc;
  564. goto putgpr;
  565. case FFI_TYPE_UINT16:
  566. gprvalue = **p_argv.us;
  567. goto putgpr;
  568. case FFI_TYPE_SINT16:
  569. gprvalue = **p_argv.ss;
  570. goto putgpr;
  571. case FFI_TYPE_UINT32:
  572. gprvalue = **p_argv.ui;
  573. goto putgpr;
  574. case FFI_TYPE_INT:
  575. case FFI_TYPE_SINT32:
  576. gprvalue = **p_argv.si;
  577. goto putgpr;
  578. case FFI_TYPE_UINT64:
  579. case FFI_TYPE_SINT64:
  580. case FFI_TYPE_POINTER:
  581. gprvalue = **p_argv.ul;
  582. putgpr:
  583. *next_arg.ul++ = gprvalue;
  584. if (next_arg.ul == gpr_end.ul)
  585. next_arg.ul = rest.ul;
  586. break;
  587. }
  588. }
  589. FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS
  590. || (next_arg.ul >= gpr_base.ul
  591. && next_arg.ul <= gpr_base.ul + 4));
  592. }
  593. #if _CALL_ELF == 2
  594. #define MIN_CACHE_LINE_SIZE 8
  595. static void
  596. flush_icache (char *wraddr, char *xaddr, int size)
  597. {
  598. int i;
  599. for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE)
  600. __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;"
  601. : : "r" (xaddr + i), "r" (wraddr + i) : "memory");
  602. __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" "sync;" "isync;"
  603. : : "r"(xaddr + size - 1), "r"(wraddr + size - 1)
  604. : "memory");
  605. }
  606. #endif
  607. ffi_status
  608. ffi_prep_closure_loc_linux64 (ffi_closure *closure,
  609. ffi_cif *cif,
  610. void (*fun) (ffi_cif *, void *, void **, void *),
  611. void *user_data,
  612. void *codeloc)
  613. {
  614. #if _CALL_ELF == 2
  615. unsigned int *tramp = (unsigned int *) &closure->tramp[0];
  616. if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI)
  617. return FFI_BAD_ABI;
  618. tramp[0] = 0xe96c0018; /* 0: ld 11,2f-0b(12) */
  619. tramp[1] = 0xe98c0010; /* ld 12,1f-0b(12) */
  620. tramp[2] = 0x7d8903a6; /* mtctr 12 */
  621. tramp[3] = 0x4e800420; /* bctr */
  622. /* 1: .quad function_addr */
  623. /* 2: .quad context */
  624. *(void **) &tramp[4] = (void *) ffi_closure_LINUX64;
  625. *(void **) &tramp[6] = codeloc;
  626. flush_icache ((char *)tramp, (char *)codeloc, FFI_TRAMPOLINE_SIZE);
  627. #else
  628. void **tramp = (void **) &closure->tramp[0];
  629. if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI)
  630. return FFI_BAD_ABI;
  631. /* Copy function address and TOC from ffi_closure_LINUX64. */
  632. memcpy (tramp, (char *) ffi_closure_LINUX64, 16);
  633. tramp[2] = tramp[1];
  634. tramp[1] = codeloc;
  635. #endif
  636. closure->cif = cif;
  637. closure->fun = fun;
  638. closure->user_data = user_data;
  639. return FFI_OK;
  640. }
  641. int FFI_HIDDEN
  642. ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue,
  643. unsigned long *pst, ffi_dblfl *pfr)
  644. {
  645. /* rvalue is the pointer to space for return value in closure assembly */
  646. /* pst is the pointer to parameter save area
  647. (r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */
  648. /* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */
  649. void **avalue;
  650. ffi_type **arg_types;
  651. unsigned long i, avn, nfixedargs;
  652. ffi_cif *cif;
  653. ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64;
  654. unsigned long align;
  655. cif = closure->cif;
  656. avalue = alloca (cif->nargs * sizeof (void *));
  657. /* Copy the caller's structure return value address so that the
  658. closure returns the data directly to the caller. */
  659. if (cif->rtype->type == FFI_TYPE_STRUCT
  660. && (cif->flags & FLAG_RETURNS_SMST) == 0)
  661. {
  662. rvalue = (void *) *pst;
  663. pst++;
  664. }
  665. i = 0;
  666. avn = cif->nargs;
  667. #if _CALL_ELF != 2
  668. nfixedargs = (unsigned) -1;
  669. if ((cif->flags & FLAG_COMPAT) == 0)
  670. #endif
  671. nfixedargs = cif->nfixedargs;
  672. arg_types = cif->arg_types;
  673. /* Grab the addresses of the arguments from the stack frame. */
  674. while (i < avn)
  675. {
  676. unsigned int elt, elnum;
  677. switch (arg_types[i]->type)
  678. {
  679. case FFI_TYPE_SINT8:
  680. case FFI_TYPE_UINT8:
  681. #ifndef __LITTLE_ENDIAN__
  682. avalue[i] = (char *) pst + 7;
  683. pst++;
  684. break;
  685. #endif
  686. case FFI_TYPE_SINT16:
  687. case FFI_TYPE_UINT16:
  688. #ifndef __LITTLE_ENDIAN__
  689. avalue[i] = (char *) pst + 6;
  690. pst++;
  691. break;
  692. #endif
  693. case FFI_TYPE_SINT32:
  694. case FFI_TYPE_UINT32:
  695. #ifndef __LITTLE_ENDIAN__
  696. avalue[i] = (char *) pst + 4;
  697. pst++;
  698. break;
  699. #endif
  700. case FFI_TYPE_SINT64:
  701. case FFI_TYPE_UINT64:
  702. case FFI_TYPE_POINTER:
  703. avalue[i] = pst;
  704. pst++;
  705. break;
  706. case FFI_TYPE_STRUCT:
  707. if ((cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0)
  708. {
  709. align = arg_types[i]->alignment;
  710. if (align > 16)
  711. align = 16;
  712. if (align > 1)
  713. pst = (unsigned long *) ALIGN ((size_t) pst, align);
  714. }
  715. elt = 0;
  716. #if _CALL_ELF == 2
  717. elt = discover_homogeneous_aggregate (arg_types[i], &elnum);
  718. #endif
  719. if (elt)
  720. {
  721. union {
  722. void *v;
  723. unsigned long *ul;
  724. float *f;
  725. double *d;
  726. size_t p;
  727. } to, from;
  728. /* Repackage the aggregate from its parts. The
  729. aggregate size is not greater than the space taken by
  730. the registers so store back to the register/parameter
  731. save arrays. */
  732. if (pfr + elnum <= end_pfr)
  733. to.v = pfr;
  734. else
  735. to.v = pst;
  736. avalue[i] = to.v;
  737. from.ul = pst;
  738. if (elt == FFI_TYPE_FLOAT)
  739. {
  740. do
  741. {
  742. if (pfr < end_pfr && i < nfixedargs)
  743. {
  744. *to.f = (float) pfr->d;
  745. pfr++;
  746. }
  747. else
  748. *to.f = *from.f;
  749. to.f++;
  750. from.f++;
  751. }
  752. while (--elnum != 0);
  753. }
  754. else
  755. {
  756. do
  757. {
  758. if (pfr < end_pfr && i < nfixedargs)
  759. {
  760. *to.d = pfr->d;
  761. pfr++;
  762. }
  763. else
  764. *to.d = *from.d;
  765. to.d++;
  766. from.d++;
  767. }
  768. while (--elnum != 0);
  769. }
  770. }
  771. else
  772. {
  773. #ifndef __LITTLE_ENDIAN__
  774. /* Structures with size less than eight bytes are passed
  775. left-padded. */
  776. if (arg_types[i]->size < 8)
  777. avalue[i] = (char *) pst + 8 - arg_types[i]->size;
  778. else
  779. #endif
  780. avalue[i] = pst;
  781. }
  782. pst += (arg_types[i]->size + 7) / 8;
  783. break;
  784. #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
  785. case FFI_TYPE_LONGDOUBLE:
  786. if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
  787. {
  788. if (pfr + 1 < end_pfr && i + 1 < nfixedargs)
  789. {
  790. avalue[i] = pfr;
  791. pfr += 2;
  792. }
  793. else
  794. {
  795. if (pfr < end_pfr && i < nfixedargs)
  796. {
  797. /* Passed partly in f13 and partly on the stack.
  798. Move it all to the stack. */
  799. *pst = *(unsigned long *) pfr;
  800. pfr++;
  801. }
  802. avalue[i] = pst;
  803. }
  804. pst += 2;
  805. break;
  806. }
  807. /* Fall through. */
  808. #endif
  809. case FFI_TYPE_DOUBLE:
  810. /* On the outgoing stack all values are aligned to 8 */
  811. /* there are 13 64bit floating point registers */
  812. if (pfr < end_pfr && i < nfixedargs)
  813. {
  814. avalue[i] = pfr;
  815. pfr++;
  816. }
  817. else
  818. avalue[i] = pst;
  819. pst++;
  820. break;
  821. case FFI_TYPE_FLOAT:
  822. if (pfr < end_pfr && i < nfixedargs)
  823. {
  824. /* Float values are stored as doubles in the
  825. ffi_closure_LINUX64 code. Fix them here. */
  826. pfr->f = (float) pfr->d;
  827. avalue[i] = pfr;
  828. pfr++;
  829. }
  830. else
  831. avalue[i] = pst;
  832. pst++;
  833. break;
  834. default:
  835. FFI_ASSERT (0);
  836. }
  837. i++;
  838. }
  839. (closure->fun) (cif, rvalue, avalue, closure->user_data);
  840. /* Tell ffi_closure_LINUX64 how to perform return type promotions. */
  841. if ((cif->flags & FLAG_RETURNS_SMST) != 0)
  842. {
  843. if ((cif->flags & FLAG_RETURNS_FP) == 0)
  844. return FFI_V2_TYPE_SMALL_STRUCT + cif->rtype->size - 1;
  845. else if ((cif->flags & FLAG_RETURNS_64BITS) != 0)
  846. return FFI_V2_TYPE_DOUBLE_HOMOG;
  847. else
  848. return FFI_V2_TYPE_FLOAT_HOMOG;
  849. }
  850. return cif->rtype->type;
  851. }
  852. #endif