]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/powerpc/tst-tlsifunc.c
75cfb3e6567aab8229001c847045767dd799b35d
[thirdparty/glibc.git] / sysdeps / powerpc / tst-tlsifunc.c
1 /* Test if an executable can read from the TLS from an STT_GNU_IFUNC resolver.
2 Copyright (C) 2017-2018 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdint.h>
22 #include <inttypes.h>
23 #include <libc-symbols.h>
24 #include <tls-macros.h>
25
26 __thread int bar;
27 static int *bar_ptr = NULL;
28
29 static uint32_t resolver_platform = 0;
30
31 int foo (void);
32
33 int tcb_test (void);
34
35 /* Offsets copied from tcb-offsets.h. */
36 #ifdef __powerpc64__
37 # define __TPREG "r13"
38 # define __ATPLATOFF -28764
39 #else
40 # define __TPREG "r2"
41 # define __ATPLATOFF -28724
42 #endif
43
44 uint32_t
45 get_platform (void)
46 {
47 register unsigned long tp __asm__ (__TPREG);
48 uint32_t tmp;
49
50 __asm__ ("lwz %0,%1(%2)\n"
51 : "=r" (tmp)
52 : "i" (__ATPLATOFF), "b" (tp));
53
54 return tmp;
55 }
56
57 void
58 init_foo (void)
59 {
60 bar_ptr = TLS_GD (bar);
61 }
62
63 int
64 my_foo (void)
65 {
66 printf ("&bar = %p and bar_ptr = %p.\n", &bar, bar_ptr);
67 return bar_ptr != NULL;
68 }
69
70 __ifunc (foo, foo, my_foo, void, init_foo);
71
72 void
73 init_tcb_test (void)
74 {
75 resolver_platform = get_platform ();
76 }
77
78 int
79 my_tcb_test (void)
80 {
81 printf ("resolver_platform = 0x%"PRIx32
82 " and current platform = 0x%"PRIx32".\n",
83 resolver_platform, get_platform ());
84 return resolver_platform != 0;
85 }
86
87 __ifunc (tcb_test, tcb_test, my_tcb_test, void, init_tcb_test);
88
89 static int
90 do_test (void)
91 {
92 int ret = 0;
93
94 if (foo ())
95 printf ("PASS: foo IFUNC resolver called once.\n");
96 else
97 {
98 printf ("FAIL: foo IFUNC resolver not called once.\n");
99 ret = 1;
100 }
101
102 if (&bar == bar_ptr)
103 printf ("PASS: bar address read from IFUNC resolver is correct.\n");
104 else
105 {
106 printf ("FAIL: bar address read from IFUNC resolver is incorrect.\n");
107 ret = 1;
108 }
109
110 if (tcb_test ())
111 printf ("PASS: tcb_test IFUNC resolver called once.\n");
112 else
113 {
114 printf ("FAIL: tcb_test IFUNC resolver not called once.\n");
115 ret = 1;
116 }
117
118 if (resolver_platform == get_platform ())
119 printf ("PASS: platform read from IFUNC resolver is correct.\n");
120 else
121 {
122 printf ("FAIL: platform read from IFUNC resolver is incorrect.\n");
123 ret = 1;
124 }
125
126 return ret;
127 }
128
129 #include <support/test-driver.c>