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