ifunc-sel.h 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. /* Used by the elf ifunc tests. */
  2. #ifndef ELF_IFUNC_SEL_H
  3. #define ELF_IFUNC_SEL_H 1
  4. extern int global;
  5. static inline __attribute__ ((always_inline)) void *
  6. ifunc_sel (int (*f1) (void), int (*f2) (void), int (*f3) (void))
  7. {
  8. #ifdef __powerpc__
  9. /* When generating PIC, powerpc gcc loads the address of "global"
  10. from the GOT, but the GOT may not have been relocated.
  11. Similarly, "f1", "f2" and "f3" may be loaded from non-relocated
  12. GOT entries.
  13. There is NO WAY to make this ill conceived IFUNC misfeature
  14. reliably work on targets that use a GOT for function or variable
  15. addresses, short of implementing two passes over relocations in
  16. ld.so, with ifunc relocations being applied after all other
  17. relocations, globally.
  18. Cheat. Don't use the GOT. Rely on this function being inlined
  19. and calculate all variable and function addresses relative to pc.
  20. Using the 'X' constraint is risky, but that's the only way to
  21. make the asm here see the function names for %4, %5 and %6.
  22. Sadly, powerpc64 gcc doesn't accept use of %3 here with 'X' for
  23. some reason, so we expand it ourselves. */
  24. register void *ret __asm__ ("r3");
  25. void *temp1, *temp2;
  26. __asm__ ("mflr %1\n\t"
  27. "bcl 20,31,1f\n"
  28. "1:\tmflr %2\n\t"
  29. "mtlr %1\n\t"
  30. "addis %1,%2,global-1b@ha\n\t"
  31. "lwz %1,global-1b@l(%1)\n\t"
  32. "addis %0,%2,%4-1b@ha\n\t"
  33. "addi %0,%0,%4-1b@l\n\t"
  34. "cmpwi %1,1\n\t"
  35. "beqlr\n\t"
  36. "addis %0,%2,%5-1b@ha\n\t"
  37. "addi %0,%0,%5-1b@l\n\t"
  38. "cmpwi %1,-1\n\t"
  39. "beqlr\n\t"
  40. "addis %0,%2,%6-1b@ha\n\t"
  41. "addi %0,%0,%6-1b@l"
  42. : "=&b" (ret), "=&b" (temp1), "=&b" (temp2)
  43. : "X" (&global), "X" (f1), "X" (f2), "X" (f3));
  44. return ret;
  45. #else
  46. switch (global)
  47. {
  48. case 1:
  49. return f1;
  50. case -1:
  51. return f2;
  52. default:
  53. return f3;
  54. }
  55. #endif
  56. }
  57. static inline __attribute__ ((always_inline)) void *
  58. ifunc_one (int (*f1) (void))
  59. {
  60. #ifdef __powerpc__
  61. /* As above, PIC may use an unrelocated GOT entry for f1.
  62. Case study: ifuncmain6pie's shared library, ifuncmod6.so, wants
  63. the address of "foo" in function get_foo(). So there is a GOT
  64. entry for "foo" in ifuncmod6.so. ld.so relocates ifuncmod6.so
  65. *before* ifuncmain6pie, and on finding "foo" to be STT_GNU_IFUNC,
  66. calls this function with f1 set to "one". But the address of
  67. "one" is loaded from ifuncmain6pie's GOT, which hasn't been
  68. relocated yet.
  69. Cheat as for ifunc-sel. */
  70. register void *ret __asm__ ("r3");
  71. void *temp;
  72. __asm__ ("mflr %1\n\t"
  73. "bcl 20,31,1f\n"
  74. "1:\tmflr %0\n\t"
  75. "mtlr %1\n\t"
  76. "addis %0,%0,%2-1b@ha\n\t"
  77. "addi %0,%0,%2-1b@l"
  78. : "=&b" (ret), "=&r" (temp)
  79. : "X" (f1));
  80. return ret;
  81. #else
  82. return f1;
  83. #endif
  84. }
  85. #endif